mirror of
https://github.com/demostf/demo.js
synced 2026-06-03 16:44:12 +02:00
cleanup packet parser signature
This commit is contained in:
parent
1fbb61f252
commit
e83ca71f6d
10 changed files with 106 additions and 78 deletions
|
|
@ -3,6 +3,7 @@ import {ServerClass} from "./ServerClass";
|
|||
import {SendTable} from "./SendTable";
|
||||
import {StringTable} from "./StringTable";
|
||||
import {SendProp} from "./SendProp";
|
||||
import {GameEventDefinitionMap} from "./GameEvent";
|
||||
export class Match {
|
||||
tick: number;
|
||||
chat: any[];
|
||||
|
|
@ -17,7 +18,7 @@ export class Match {
|
|||
sendTables: SendTable[];
|
||||
instanceBaselines: SendProp[][][];
|
||||
staticBaseLines: any[];
|
||||
_classBits: number = 0
|
||||
eventDefinitions: GameEventDefinitionMap;
|
||||
|
||||
constructor() {
|
||||
this.tick = 0;
|
||||
|
|
@ -34,6 +35,7 @@ export class Match {
|
|||
this.entities = [];
|
||||
this.instanceBaselines = [[], []];
|
||||
this.staticBaseLines = [];
|
||||
this.eventDefinitions = {};
|
||||
}
|
||||
|
||||
getSendTable(name) {
|
||||
|
|
@ -42,7 +44,7 @@ export class Match {
|
|||
return this.sendTables[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
throw new Error("unknown SendTable " + name);
|
||||
}
|
||||
|
||||
getStringTable(name) {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ export class SendTable {
|
|||
this.props.push(prop);
|
||||
}
|
||||
|
||||
flatten() {
|
||||
private flatten() {
|
||||
let excludes: SendPropDefinition[] = [];
|
||||
let props: SendPropDefinition[] = [];
|
||||
this.getAllProps(excludes, props);
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
import {SendTable} from "./SendTable";
|
||||
|
||||
export class ServerClass {
|
||||
id: number;
|
||||
name: string;
|
||||
dataTable: SendTable;
|
||||
dataTable: string;
|
||||
|
||||
constructor(id, name, dataTable) {
|
||||
constructor(id:number, name:string, dataTable:string) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.dataTable = dataTable;
|
||||
|
|
|
|||
44
src/Parser/EntityDecoder.ts
Normal file
44
src/Parser/EntityDecoder.ts
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import {Entity} from "../Data/Entity";
|
||||
import {BitStream} from "bit-buffer";
|
||||
import {SendProp} from "../Data/SendProp";
|
||||
import {SendPropParser} from "./SendPropParser";
|
||||
import {readUBitVar} from "./readBitVar";
|
||||
export function applyEntityUpdate(entity: Entity, stream: BitStream): Entity {
|
||||
let index = -1;
|
||||
const allProps = entity.sendTable.flattenedProps;
|
||||
let changedProps: SendProp[] = [];
|
||||
while ((index = readFieldIndex(stream, index)) != -1) {
|
||||
if (index > 4096) {
|
||||
throw new Error('prop index out of bounds while applying update for ' + entity.sendTable.name+ ' got ' + index);
|
||||
}
|
||||
const propDefinition = allProps[index];
|
||||
const existingProp = entity.getPropByDefinition(propDefinition);
|
||||
let prop;
|
||||
if (existingProp) {
|
||||
prop = existingProp;
|
||||
} else {
|
||||
prop = new SendProp(propDefinition);
|
||||
}
|
||||
// prop.value = SendPropParser.decode(propDefinition, stream);
|
||||
// console.log(prop);
|
||||
changedProps.push(prop);
|
||||
|
||||
if (!existingProp) {
|
||||
entity.props.push(prop);
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < changedProps.length; i++) {
|
||||
const prop = changedProps[i];
|
||||
prop.value = SendPropParser.decode(prop.definition, stream);
|
||||
console.log(prop);
|
||||
}
|
||||
return entity;
|
||||
};
|
||||
|
||||
const readFieldIndex = function (stream: BitStream, lastIndex: number): number {
|
||||
if (!stream.readBoolean()) {
|
||||
return -1;
|
||||
}
|
||||
const diff = readUBitVar(stream);
|
||||
return lastIndex + diff + 1;
|
||||
};
|
||||
|
|
@ -28,13 +28,12 @@ import {Packet as IPacket} from '../../Data/Packet';
|
|||
export class Packet extends Parser {
|
||||
parse() {
|
||||
let packets: IPacket[] = [];
|
||||
let entities = [];
|
||||
let lastPacketType = 0;
|
||||
while (this.bitsLeft > 6) { // last 6 bits for NOOP
|
||||
const type = this.stream.readBits(6);
|
||||
if (type !== 0) {
|
||||
if (Packet.parsers[type]) {
|
||||
let packet = Packet.parsers[type].call(this, this.stream, Packet.gameEventMap, entities, this.match);
|
||||
let packet = Packet.parsers[type].call(this, this.stream, this.match);
|
||||
packets.push(packet);
|
||||
} else {
|
||||
throw new Error('Unknown packet type ' + type + " just parsed a " + PacketType[lastPacketType]);
|
||||
|
|
@ -81,8 +80,6 @@ export class Packet extends Parser {
|
|||
31: ParserGenerator.make('getCvarValue', 'cookie{32}value{s}'),
|
||||
32: ParserGenerator.make('cmdKeyValues', 'length{32}data{$length}')
|
||||
};
|
||||
|
||||
static gameEventMap: GameEventDefinitionMap = {};
|
||||
}
|
||||
|
||||
enum PacketType {
|
||||
|
|
|
|||
|
|
@ -4,22 +4,23 @@ import {
|
|||
GameEventType, GameEventValue, GameEventEntry, GameEventDefinition, GameEvent as IGameEvent,
|
||||
GameEventValueMap, GameEventDefinitionMap
|
||||
} from "../../Data/GameEvent";
|
||||
import {Match} from "../../Data/Match";
|
||||
|
||||
const parseGameEvent = function (eventId: number, stream: BitStream, events: GameEventDefinitionMap): IGameEvent|null {
|
||||
if (!events[eventId]) {
|
||||
return null;
|
||||
}
|
||||
const eventDescription: GameEventDefinition = events[eventId];
|
||||
const values: GameEventValueMap = {};
|
||||
const values: GameEventValueMap = {};
|
||||
for (let i = 0; i < eventDescription.entries.length; i++) {
|
||||
const entry: GameEventEntry = eventDescription.entries[i];
|
||||
const value = getGameEventValue(stream, entry);
|
||||
const value = getGameEventValue(stream, entry);
|
||||
if (value) {
|
||||
values[entry.name] = value;
|
||||
}
|
||||
}
|
||||
return {
|
||||
name: eventDescription.name,
|
||||
name: eventDescription.name,
|
||||
values: values
|
||||
};
|
||||
};
|
||||
|
|
@ -46,14 +47,14 @@ const getGameEventValue = function (stream: BitStream, entry: GameEventEntry): G
|
|||
};
|
||||
|
||||
|
||||
export function GameEvent(stream: BitStream, events: GameEventDefinitionMap): Packet { // 25: game event
|
||||
const length = stream.readBits(11);
|
||||
const end = stream._index + length;
|
||||
export function GameEvent(stream: BitStream, match: Match): Packet { // 25: game event
|
||||
const length = stream.readBits(11);
|
||||
const end = stream._index + length;
|
||||
const eventId = stream.readBits(9);
|
||||
const event = parseGameEvent(eventId, stream, events);
|
||||
const event = parseGameEvent(eventId, stream, match.eventDefinitions);
|
||||
stream._index = end;
|
||||
return {
|
||||
packetType: 'gameEvent',
|
||||
event: event
|
||||
event: event
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
import {Packet} from "../../Data/Packet";
|
||||
import {BitStream} from 'bit-buffer';
|
||||
import {GameEventEntry, GameEventDefinitionMap} from "../../Data/GameEvent";
|
||||
import {Match} from "../../Data/Match";
|
||||
|
||||
export function GameEventList(stream: BitStream, events: GameEventDefinitionMap): Packet { // 30: gameEventList
|
||||
export function GameEventList(stream: BitStream, match: Match): Packet { // 30: gameEventList
|
||||
// list of game events and parameters
|
||||
const numEvents = stream.readBits(9);
|
||||
const length = stream.readBits(20);
|
||||
const length = stream.readBits(20);
|
||||
for (let i = 0; i < numEvents; i++) {
|
||||
const id = stream.readBits(9);
|
||||
const name = stream.readASCIIString();
|
||||
let type = stream.readBits(3);
|
||||
const id = stream.readBits(9);
|
||||
const name = stream.readASCIIString();
|
||||
let type = stream.readBits(3);
|
||||
const entries: GameEventEntry[] = [];
|
||||
while (type !== 0) {
|
||||
entries.push({
|
||||
|
|
@ -18,14 +19,13 @@ export function GameEventList(stream: BitStream, events: GameEventDefinitionMap)
|
|||
});
|
||||
type = stream.readBits(3);
|
||||
}
|
||||
events[id] = {
|
||||
id: id,
|
||||
name: name,
|
||||
match.eventDefinitions[id] = {
|
||||
id: id,
|
||||
name: name,
|
||||
entries: entries
|
||||
};
|
||||
}
|
||||
return {
|
||||
packetType: 'gameEventList',
|
||||
events: events
|
||||
packetType: 'gameEventList'
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import {BitStream} from 'bit-buffer';
|
|||
import {GameEventDefinition} from "../../Data/GameEvent";
|
||||
import {Match} from "../../Data/Match";
|
||||
import {readUBitVar} from "../readBitVar";
|
||||
import {applyEntityUpdate} from "../EntityDecoder";
|
||||
|
||||
enum PVS {
|
||||
PRESERVE = 0,
|
||||
|
|
@ -71,7 +72,7 @@ function readLeavePVS(match, entityId, shouldDelete) {
|
|||
}
|
||||
}
|
||||
|
||||
export function PacketEntities(stream: BitStream, events: GameEventDefinition[], entities: Entity[], match: Match): Packet { //26: packetEntities
|
||||
export function PacketEntities(stream: BitStream, match: Match): Packet { //26: packetEntities
|
||||
// https://github.com/skadistats/smoke/blob/master/smoke/replay/handler/svc_packetentities.pyx
|
||||
// https://github.com/StatsHelix/demoinfo/blob/3d28ea917c3d44d987b98bb8f976f1a3fcc19821/DemoInfo/DP/Handler/PacketEntitesHandler.cs
|
||||
// https://github.com/StatsHelix/demoinfo/blob/3d28ea917c3d44d987b98bb8f976f1a3fcc19821/DemoInfo/DP/Entity.cs
|
||||
|
|
@ -89,8 +90,7 @@ export function PacketEntities(stream: BitStream, events: GameEventDefinition[],
|
|||
|
||||
stream._index = end;
|
||||
return {
|
||||
packetType: 'packetEntities',
|
||||
entities: entities
|
||||
packetType: 'packetEntities'
|
||||
};
|
||||
|
||||
if (updatedBaseLine) {
|
||||
|
|
@ -146,47 +146,6 @@ export function PacketEntities(stream: BitStream, events: GameEventDefinition[],
|
|||
|
||||
stream._index = end;
|
||||
return {
|
||||
packetType: 'packetEntities',
|
||||
entities: entities
|
||||
packetType: 'packetEntities'
|
||||
};
|
||||
}
|
||||
|
||||
const readFieldIndex = function (stream: BitStream, lastIndex: number): number {
|
||||
if (!stream.readBoolean()) {
|
||||
return -1;
|
||||
}
|
||||
const diff = readUBitVar(stream);
|
||||
return lastIndex + diff + 1;
|
||||
};
|
||||
|
||||
const applyEntityUpdate = function (entity: Entity, stream: BitStream): Entity {
|
||||
let index = -1;
|
||||
const allProps = entity.sendTable.flattenedProps;
|
||||
let changedProps: SendProp[] = [];
|
||||
while ((index = readFieldIndex(stream, index)) != -1) {
|
||||
if (index > 4096) {
|
||||
throw new Error('prop index out of bounds');
|
||||
}
|
||||
const propDefinition = allProps[index];
|
||||
const existingProp = entity.getPropByDefinition(propDefinition);
|
||||
let prop;
|
||||
if (existingProp) {
|
||||
prop = existingProp;
|
||||
} else {
|
||||
prop = new SendProp(propDefinition);
|
||||
}
|
||||
// prop.value = SendPropParser.decode(propDefinition, stream);
|
||||
// console.log(prop);
|
||||
changedProps.push(prop);
|
||||
|
||||
if (!existingProp) {
|
||||
entity.props.push(prop);
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < changedProps.length; i++) {
|
||||
const prop = changedProps[i];
|
||||
prop.value = SendPropParser.decode(prop.definition, stream);
|
||||
console.log(prop);
|
||||
}
|
||||
return entity;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,5 +4,5 @@ import {GameEventDefinitionMap} from "../../Data/GameEvent";
|
|||
import {Match} from "../../Data/Match";
|
||||
import {Entity} from "../../Data/Entity";
|
||||
|
||||
export type Parser = (stream: BitStream, gameEventMap?: GameEventDefinitionMap, entities?: Entity[], match?: Match) => Packet;
|
||||
export type Parser = (stream: BitStream, match?: Match) => Packet;
|
||||
export type PacketParserMap = {[id: number]: Parser};
|
||||
|
|
|
|||
|
|
@ -1,12 +1,39 @@
|
|||
import {Packet} from "../../Data/Packet";
|
||||
import {BitStream} from 'bit-buffer';
|
||||
import {Match} from "../../Data/Match";
|
||||
import {Entity} from "../../Data/Entity";
|
||||
import {applyEntityUpdate} from "../EntityDecoder";
|
||||
|
||||
export function TempEntities(stream: BitStream): Packet { // 10: classInfo
|
||||
export function TempEntities(stream: BitStream, match: Match): Packet { // 10: classInfo
|
||||
const entityCount = stream.readBits(8);
|
||||
const length = readVarInt(stream);
|
||||
console.log(length);
|
||||
stream._index += length;
|
||||
const end = stream._index + length;
|
||||
|
||||
// let entity: Entity|null = null;
|
||||
// let entities: Entity[] = [];
|
||||
// for (let i = 0; i < entityCount; i++) {
|
||||
// const delay = (stream.readBoolean()) ? stream.readUint8() / 100 : 0; //unused it seems
|
||||
// if (stream.readBoolean()) {
|
||||
// const classId = stream.readBits(match.classBits);
|
||||
// const serverClass = match.serverClasses[classId];
|
||||
// const sendTable = match.getSendTable(serverClass.dataTable);
|
||||
// entity = new Entity(serverClass, sendTable, 0, 0);
|
||||
// applyEntityUpdate(entity, stream);
|
||||
// entities.push(entity);
|
||||
// } else {
|
||||
// if (entity) {
|
||||
// applyEntityUpdate(entity, stream);
|
||||
// } else {
|
||||
// throw new Error("no entity set to update");
|
||||
// }
|
||||
// }
|
||||
// console.log(entity);
|
||||
// }
|
||||
// if (end - stream._index > 8) {
|
||||
// throw new Error("unexpected content after TempEntities");
|
||||
// }
|
||||
|
||||
stream._index = end;
|
||||
return {
|
||||
'packetType': 'tempEntities'
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue