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 {GameEventDefinition, Message, Packet, PacketEntity, SendPropValue, UserCmd} from "./parser";
|
||||
import {FixedSizeList as List} from 'react-window';
|
||||
import {MessageInfo} from "./packets/message";
|
||||
import {UserCmdDetails} from "./packets/usercmd";
|
||||
|
||||
interface TableProps {
|
||||
packets: Packet[],
|
||||
|
|
@ -85,7 +87,7 @@ export function PacketDetails({packet, prop_names, class_names}: DetailProps) {
|
|||
case "Message":
|
||||
let rows = packet.messages.map((message, y) => <tr key={y}>
|
||||
<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>)
|
||||
return (
|
||||
<table>
|
||||
|
|
@ -99,7 +101,7 @@ export function PacketDetails({packet, prop_names, class_names}: DetailProps) {
|
|||
case "ConsoleCmd":
|
||||
return <>{packet.command}</>
|
||||
case "UserCmd":
|
||||
return <>{formatUserCmd(packet.cmd)}</>
|
||||
return <UserCmdDetails cmd={packet.cmd}/>
|
||||
case "DataTables":
|
||||
return <>{packet.tables.length}</>
|
||||
case "Stop":
|
||||
|
|
@ -108,121 +110,3 @@ export function PacketDetails({packet, prop_names, class_names}: DetailProps) {
|
|||
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