mirror of
https://codeberg.org/demostf/inspector.git
synced 2026-06-03 18:14:08 +02:00
usercmd button
This commit is contained in:
parent
eb629acd5b
commit
69d1318a43
3 changed files with 173 additions and 120 deletions
94
www/src/packets/message.tsx
Normal file
94
www/src/packets/message.tsx
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
import {GameEventDefinition, Message, PacketEntity, SendPropValue} from "../parser";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export interface MessageInfoProps {
|
||||||
|
msg: Message,
|
||||||
|
prop_names: Map<number, { table: String, prop: String }>,
|
||||||
|
class_names: Map<number, String>
|
||||||
|
}
|
||||||
|
|
||||||
|
export function MessageInfo({msg, prop_names, class_names}: MessageInfoProps) {
|
||||||
|
switch (msg.type) {
|
||||||
|
case "Print":
|
||||||
|
return <>{msg.value}</>
|
||||||
|
case "ServerInfo":
|
||||||
|
return <>stv: {msg.stv ? 'true' : 'false'}, map: {msg.map}, player count: {msg.player_count},
|
||||||
|
map: {msg.map}</>
|
||||||
|
case "NetTick":
|
||||||
|
return <>Tick {msg.tick}, frame time: {msg.frame_time}, std_dev: {msg.std_dev}</>
|
||||||
|
case "ParseSounds":
|
||||||
|
return <>{msg.reliable ? 'reliable' : 'unreliable'} {msg.num} sounds: {msg.length} bits</>
|
||||||
|
case "VoiceInit":
|
||||||
|
return <>{msg.codec} at quality {msg.quality} and sampling rage {msg.sampling_rate}</>
|
||||||
|
case "SigOnState":
|
||||||
|
return <>state: {msg.state}, count: {msg.count}</>
|
||||||
|
case "SetConVar":
|
||||||
|
return <>{msg.vars.map(cvar => `${cvar.key}=${cvar.value}`).join(', ')}</>
|
||||||
|
case "SetView":
|
||||||
|
return <>set view to entity {msg.index}</>
|
||||||
|
case "GameEventList":
|
||||||
|
return <>{msg.event_list.map(formatEventDefinition).map((str, i) => (<p key={i}>{str}</p>))}</>
|
||||||
|
case "PacketEntities":
|
||||||
|
let entities = msg.entities.map(entity => formatEntity(entity, prop_names, class_names)).map((str, i) => <p
|
||||||
|
key={i}>{str}</p>);
|
||||||
|
let deleted = <></>
|
||||||
|
if (msg.removed_entities.length > 0) {
|
||||||
|
deleted = <>deleted: {msg.removed_entities.join(', ')}</>
|
||||||
|
}
|
||||||
|
return <>
|
||||||
|
<p>delta: {JSON.stringify(msg.delta)}</p>
|
||||||
|
<p>baseline: {JSON.stringify(msg.base_line)}</p>
|
||||||
|
<p>max: {JSON.stringify(msg.max_entries)}</p>
|
||||||
|
<p>updated base line: {JSON.stringify(msg.updated_base_line)}</p>
|
||||||
|
{entities}
|
||||||
|
{deleted}
|
||||||
|
</>
|
||||||
|
case "TempEntities":
|
||||||
|
let events = msg.events.map(event => {
|
||||||
|
let class_name = class_names.get(event.class_id);
|
||||||
|
let props = event.props.map(prop => {
|
||||||
|
let names = prop_names.get(prop.identifier);
|
||||||
|
if (names) {
|
||||||
|
return `${names.table}.${names.prop}=${formatPropValue(prop.value)}`;
|
||||||
|
} else {
|
||||||
|
return `[unknown prop]=${prop.value}`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return `temp entity ${class_name}(delay: ${event.fire_delay}, reliable:${JSON.stringify(event.reliable)}): ` + props.join(', ');
|
||||||
|
})
|
||||||
|
return <>{events.map(event => <p>{event}</p>)}</>
|
||||||
|
default:
|
||||||
|
let json = msg;
|
||||||
|
delete json.type;
|
||||||
|
return <>{JSON.stringify(json)}</>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function formatPropValue(value: SendPropValue): string {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
return '[' + value.map(formatPropValue).join(',') + ']'
|
||||||
|
} else if (typeof value === "number" || typeof value === "string") {
|
||||||
|
return `${value}`
|
||||||
|
} else {
|
||||||
|
return JSON.stringify(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatEntity(entity: PacketEntity, prop_names: Map<number, { table: String, prop: String }>, class_names: Map<number, String>,): string {
|
||||||
|
let class_name = class_names.get(entity.server_class);
|
||||||
|
let props = entity.props.map(prop => {
|
||||||
|
let names = prop_names.get(prop.identifier);
|
||||||
|
if (names) {
|
||||||
|
return `${names.table}.${names.prop}=${formatPropValue(prop.value)}`;
|
||||||
|
} else {
|
||||||
|
return `[unknown prop]=${prop.value}`;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return `entity ${entity.entity_index}(${class_name}) ${entity.pvs}: ` + props.join(', ');
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatEventDefinition(event: GameEventDefinition): string {
|
||||||
|
let values = event.entries.map(entry => `${entry.name}: ${entry.kind}`);
|
||||||
|
return `${event.event_type}{${values.join(', ')}}`;
|
||||||
|
}
|
||||||
75
www/src/packets/usercmd.tsx
Normal file
75
www/src/packets/usercmd.tsx
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
import {UserCmd} from "../parser";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
enum Button {
|
||||||
|
ATTACK = (1 << 0),
|
||||||
|
JUMP = (1 << 1),
|
||||||
|
DUCK = (1 << 2),
|
||||||
|
FORWARD = (1 << 3),
|
||||||
|
BACK = (1 << 4),
|
||||||
|
USE = (1 << 5),
|
||||||
|
CANCEL = (1 << 6),
|
||||||
|
LEFT = (1 << 7),
|
||||||
|
RIGHT = (1 << 8),
|
||||||
|
MOVELEFT = (1 << 9),
|
||||||
|
MOVERIGHT = (1 << 10),
|
||||||
|
ATTACK2 = (1 << 11),
|
||||||
|
RUN = (1 << 12),
|
||||||
|
RELOAD = (1 << 13),
|
||||||
|
ALT1 = (1 << 14),
|
||||||
|
ALT2 = (1 << 15),
|
||||||
|
SCORE = (1 << 16),
|
||||||
|
SPEED = (1 << 17),
|
||||||
|
WALK = (1 << 18),
|
||||||
|
ZOOM = (1 << 19),
|
||||||
|
WEAPON1 = (1 << 20),
|
||||||
|
WEAPON2 = (1 << 21),
|
||||||
|
BULLRUSH = (1 << 22),
|
||||||
|
GRENADE1 = (1 << 23),
|
||||||
|
GRENADE2 = (1 << 24),
|
||||||
|
ATTACK3 = (1 << 25),
|
||||||
|
}
|
||||||
|
namespace Button {
|
||||||
|
export function toValues(n: Button) {
|
||||||
|
const values: string[] = [];
|
||||||
|
while (n) {
|
||||||
|
const bit = n & (~n+1);
|
||||||
|
values.push(Button[bit]);
|
||||||
|
n ^= bit;
|
||||||
|
}
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function UserCmdDetails({cmd}: { cmd: UserCmd }) {
|
||||||
|
let out = `${cmd.command_number} - tick ${cmd.tick_count}: `;
|
||||||
|
|
||||||
|
const formatOptionNum = (x: number | null) => x === null ? 0 : x;
|
||||||
|
const anyNonNull = (xs: (number | null)[]) => xs.findIndex(x => x !== null) != -1;
|
||||||
|
|
||||||
|
let parts = [];
|
||||||
|
|
||||||
|
if (anyNonNull(cmd.view_angles)) {
|
||||||
|
parts.push(`view angles: ${cmd.view_angles.map(formatOptionNum).join(',')}`);
|
||||||
|
}
|
||||||
|
if (anyNonNull(cmd.movement)) {
|
||||||
|
parts.push(`movement: ${cmd.movement.map(formatOptionNum).join(',')}`);
|
||||||
|
}
|
||||||
|
if (cmd.mouse_dx !== null || cmd.mouse_dy !== null) {
|
||||||
|
parts.push(`mouse: ${[cmd.mouse_dx, cmd.mouse_dy].map(formatOptionNum).join(',')}`);
|
||||||
|
}
|
||||||
|
if (cmd.impulse) {
|
||||||
|
parts.push(`impulse ${cmd.impulse}`)
|
||||||
|
}
|
||||||
|
if (cmd.buttons) {
|
||||||
|
parts.push(`buttons ${Button.toValues(cmd.buttons as Button)}`)
|
||||||
|
}
|
||||||
|
if (cmd.weapon_select) {
|
||||||
|
parts.push(`weapon ${cmd.weapon_select.select}(${cmd.weapon_select.subtype})`)
|
||||||
|
}
|
||||||
|
if (parts.length == 0) {
|
||||||
|
parts.push(`no data`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return <>{out + parts.join(', ')}</>
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
import React, {CSSProperties, JSXElementConstructor, ReactElement} from 'react';
|
import React, {CSSProperties, JSXElementConstructor, ReactElement} from 'react';
|
||||||
import {GameEventDefinition, Message, Packet, PacketEntity, SendPropValue, UserCmd} from "./parser";
|
import {GameEventDefinition, Message, Packet, PacketEntity, SendPropValue, UserCmd} from "./parser";
|
||||||
import {FixedSizeList as List} from 'react-window';
|
import {FixedSizeList as List} from 'react-window';
|
||||||
|
import {MessageInfo} from "./packets/message";
|
||||||
|
import {UserCmdDetails} from "./packets/usercmd";
|
||||||
|
|
||||||
interface TableProps {
|
interface TableProps {
|
||||||
packets: Packet[],
|
packets: Packet[],
|
||||||
|
|
@ -85,7 +87,7 @@ export function PacketDetails({packet, prop_names, class_names}: DetailProps) {
|
||||||
case "Message":
|
case "Message":
|
||||||
let rows = packet.messages.map((message, y) => <tr key={y}>
|
let rows = packet.messages.map((message, y) => <tr key={y}>
|
||||||
<td className="type">{message.type}</td>
|
<td className="type">{message.type}</td>
|
||||||
<td>{messageInfoText(message, prop_names, class_names)}</td>
|
<td><MessageInfo msg={message} prop_names={prop_names} class_names={class_names}/></td>
|
||||||
</tr>)
|
</tr>)
|
||||||
return (
|
return (
|
||||||
<table>
|
<table>
|
||||||
|
|
@ -99,7 +101,7 @@ export function PacketDetails({packet, prop_names, class_names}: DetailProps) {
|
||||||
case "ConsoleCmd":
|
case "ConsoleCmd":
|
||||||
return <>{packet.command}</>
|
return <>{packet.command}</>
|
||||||
case "UserCmd":
|
case "UserCmd":
|
||||||
return <>{formatUserCmd(packet.cmd)}</>
|
return <UserCmdDetails cmd={packet.cmd}/>
|
||||||
case "DataTables":
|
case "DataTables":
|
||||||
return <>{packet.tables.length}</>
|
return <>{packet.tables.length}</>
|
||||||
case "Stop":
|
case "Stop":
|
||||||
|
|
@ -108,121 +110,3 @@ export function PacketDetails({packet, prop_names, class_names}: DetailProps) {
|
||||||
return <>{packet.tables.length}</>
|
return <>{packet.tables.length}</>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function messageInfoText(msg: Message, prop_names: Map<number, { table: String, prop: String }>, class_names: Map<number, String>) {
|
|
||||||
switch (msg.type) {
|
|
||||||
case "Print":
|
|
||||||
return <>{msg.value}</>
|
|
||||||
case "ServerInfo":
|
|
||||||
return <>stv: {msg.stv ? 'true' : 'false'}, map: {msg.map}, player count: {msg.player_count},
|
|
||||||
map: {msg.map}</>
|
|
||||||
case "NetTick":
|
|
||||||
return <>Tick {msg.tick}, frame time: {msg.frame_time}, std_dev: {msg.std_dev}</>
|
|
||||||
case "ParseSounds":
|
|
||||||
return <>{msg.reliable ? 'reliable' : 'unreliable'} {msg.num} sounds: {msg.length} bits</>
|
|
||||||
case "VoiceInit":
|
|
||||||
return <>{msg.codec} at quality {msg.quality} and sampling rage {msg.sampling_rate}</>
|
|
||||||
case "SigOnState":
|
|
||||||
return <>state: {msg.state}, count: {msg.count}</>
|
|
||||||
case "SetConVar":
|
|
||||||
return <>{msg.vars.map(cvar => `${cvar.key}=${cvar.value}`).join(', ')}</>
|
|
||||||
case "SetView":
|
|
||||||
return <>set view to entity {msg.index}</>
|
|
||||||
case "GameEventList":
|
|
||||||
return <>{msg.event_list.map(formatEventDefinition).map((str, i) => (<p key={i}>{str}</p>))}</>
|
|
||||||
case "PacketEntities":
|
|
||||||
let entities = msg.entities.map(entity => formatEntity(entity, prop_names, class_names)).map((str, i) => <p
|
|
||||||
key={i}>{str}</p>);
|
|
||||||
let deleted = <></>
|
|
||||||
if (msg.removed_entities.length > 0) {
|
|
||||||
deleted = <>deleted: {msg.removed_entities.join(', ')}</>
|
|
||||||
}
|
|
||||||
return <>
|
|
||||||
<p>delta: {JSON.stringify(msg.delta)}</p>
|
|
||||||
<p>baseline: {JSON.stringify(msg.base_line)}</p>
|
|
||||||
<p>max: {JSON.stringify(msg.max_entries)}</p>
|
|
||||||
<p>updated base line: {JSON.stringify(msg.updated_base_line)}</p>
|
|
||||||
{entities}
|
|
||||||
{deleted}
|
|
||||||
</>
|
|
||||||
case "TempEntities":
|
|
||||||
let events = msg.events.map(event => {
|
|
||||||
let class_name = class_names.get(event.class_id);
|
|
||||||
let props = event.props.map(prop => {
|
|
||||||
let names = prop_names.get(prop.identifier);
|
|
||||||
if (names) {
|
|
||||||
return `${names.table}.${names.prop}=${formatPropValue(prop.value)}`;
|
|
||||||
} else {
|
|
||||||
return `[unknown prop]=${prop.value}`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return `temp entity ${class_name}(delay: ${event.fire_delay}, reliable:${JSON.stringify(event.reliable)}): ` + props.join(', ');
|
|
||||||
})
|
|
||||||
return <>{events.map(event => <p>{event}</p>)}</>
|
|
||||||
default:
|
|
||||||
let json = msg;
|
|
||||||
delete json.type;
|
|
||||||
return <>{JSON.stringify(json)}</>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatUserCmd(cmd: UserCmd): string {
|
|
||||||
let out = `${cmd.command_number} - tick ${cmd.tick_count}: `;
|
|
||||||
|
|
||||||
const formatOptionNum = (x: number | null) => x === null ? 0 : x;
|
|
||||||
const anyNonNull = (xs: (number | null)[]) => xs.findIndex(x => x !== null) != -1;
|
|
||||||
|
|
||||||
let parts = [];
|
|
||||||
|
|
||||||
if (anyNonNull(cmd.view_angles)) {
|
|
||||||
parts.push(`view angles: ${cmd.view_angles.map(formatOptionNum).join(',')}`);
|
|
||||||
}
|
|
||||||
if (anyNonNull(cmd.movement)) {
|
|
||||||
parts.push(`movement: ${cmd.movement.map(formatOptionNum).join(',')}`);
|
|
||||||
}
|
|
||||||
if (cmd.mouse_dx !== null || cmd.mouse_dy !== null) {
|
|
||||||
parts.push(`mouse: ${[cmd.mouse_dx, cmd.mouse_dy].map(formatOptionNum).join(',')}`);
|
|
||||||
}
|
|
||||||
if (cmd.impulse) {
|
|
||||||
parts.push(`impulse ${cmd.impulse}`)
|
|
||||||
}
|
|
||||||
if (cmd.buttons) {
|
|
||||||
parts.push(`buttons ${cmd.buttons}`)
|
|
||||||
}
|
|
||||||
if (cmd.weapon_select) {
|
|
||||||
parts.push(`weapon ${cmd.weapon_select.select}(${cmd.weapon_select.subtype})`)
|
|
||||||
}
|
|
||||||
if (parts.length == 0) {
|
|
||||||
parts.push(`no data`)
|
|
||||||
}
|
|
||||||
|
|
||||||
return out + parts.join(', ');
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatPropValue(value: SendPropValue): string {
|
|
||||||
if (Array.isArray(value)) {
|
|
||||||
return '[' + value.map(formatPropValue).join(',') + ']'
|
|
||||||
} else if (typeof value === "number" || typeof value === "string") {
|
|
||||||
return `${value}`
|
|
||||||
} else {
|
|
||||||
return JSON.stringify(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatEntity(entity: PacketEntity, prop_names: Map<number, { table: String, prop: String }>, class_names: Map<number, String>,): string {
|
|
||||||
let class_name = class_names.get(entity.server_class);
|
|
||||||
let props = entity.props.map(prop => {
|
|
||||||
let names = prop_names.get(prop.identifier);
|
|
||||||
if (names) {
|
|
||||||
return `${names.table}.${names.prop}=${formatPropValue(prop.value)}`;
|
|
||||||
} else {
|
|
||||||
return `[unknown prop]=${prop.value}`;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return `entity ${entity.entity_index}(${class_name}) ${entity.pvs}: ` + props.join(', ');
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatEventDefinition(event: GameEventDefinition): string {
|
|
||||||
let values = event.entries.map(entry => `${entry.name}: ${entry.kind}`);
|
|
||||||
return `${event.event_type}{${values.join(', ')}}`;
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue