1
0
Fork 0
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:
Robin Appelman 2016-12-19 00:45:22 +01:00
commit e83ca71f6d
10 changed files with 106 additions and 78 deletions

View file

@ -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) {

View file

@ -15,7 +15,7 @@ export class SendTable {
this.props.push(prop);
}
flatten() {
private flatten() {
let excludes: SendPropDefinition[] = [];
let props: SendPropDefinition[] = [];
this.getAllProps(excludes, props);

View file

@ -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;

View 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;
};

View file

@ -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 {

View file

@ -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
}
}

View file

@ -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'
}
}

View file

@ -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;
};

View file

@ -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};

View file

@ -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'
}