1
0
Fork 0
mirror of https://github.com/demostf/demo.js synced 2026-06-03 16:44:12 +02:00

entity encoder wip

This commit is contained in:
Robin Appelman 2017-09-09 02:50:51 +02:00
commit 206facfa8d
17 changed files with 733 additions and 174 deletions

View file

@ -12,7 +12,7 @@ import {EntityId, PacketEntity} from './PacketEntity';
import {Player} from './Player';
import {PlayerResource} from './PlayerResource';
import {SendTable, SendTableName} from './SendTable';
import {ServerClass} from './ServerClass';
import {ServerClass, ServerClassId} from './ServerClass';
import {StringTable} from './StringTable';
import {Team, TeamNumber} from './Team';
import {UserInfo} from './UserInfo';
@ -31,7 +31,7 @@ export class Match {
public rounds: Round[] = [];
public startTick: number = 0;
public intervalPerTick: number = 0;
public staticBaseLines: BitStream[] = [];
public staticBaseLines: Map<ServerClassId, BitStream> = new Map();
public eventDefinitions: Map<number, GameEventDefinition<GameEventType>> = new Map();
public world: World = {
boundaryMin: {x: 0, y: 0, z: 0},

View file

@ -1,6 +1,6 @@
import {BitStream} from 'bit-buffer';
import {GameEventDefinition} from './GameEvent';
import {PacketEntity} from './PacketEntity';
import {EntityId, PacketEntity} from './PacketEntity';
import {SendTable} from './SendTable';
import {ServerClass} from './ServerClass';
import {StringTable, StringTableEntry} from './StringTable';
@ -82,13 +82,10 @@ export interface GameEventListPacket extends BasePacket {
export interface PacketEntitiesPacket extends BasePacket {
packetType: 'packetEntities';
entities: PacketEntity[];
removedEntities: number[];
removedEntities: EntityId[];
maxEntries: number;
isDelta: boolean;
delta: number;
baseLine: number;
updatedEntries: number;
length: number;
updatedBaseLine: boolean;
}

View file

@ -64,4 +64,11 @@ export class PacketEntity {
}
}
}
public diffFromBaseLine(baseline: PacketEntity): SendProp[] {
return this.props.filter(prop => {
const baseProp = baseline.getPropByDefinition(prop.definition);
return (!baseProp || prop.value !== baseProp.value);
});
}
}

View file

@ -1,9 +1,11 @@
export type ServerClassId = number;
export class ServerClass {
public id: number;
public id: ServerClassId;
public name: string;
public dataTable: string;
constructor(id: number, name: string, dataTable: string) {
constructor(id: ServerClassId, name: string, dataTable: string) {
this.id = id;
this.name = name;
this.dataTable = dataTable;

View file

@ -59,7 +59,7 @@ function saveUserData(userData: StringTableEntry, match: Match) {
function saveInstanceBaseLine(entry: StringTableEntry, match: Match) {
if (entry.extraData) {
match.staticBaseLines[parseInt(entry.text, 10)] = entry.extraData;
match.staticBaseLines.set(parseInt(entry.text, 10), entry.extraData);
} else {
throw new Error('Missing baseline');
}

View file

@ -3,20 +3,38 @@ import {Match} from '../../Data/Match';
import {PacketEntitiesPacket} from '../../Data/Packet';
import {EntityId, PacketEntity, PVS} from '../../Data/PacketEntity';
import {SendProp} from '../../Data/SendProp';
import {getEntityUpdate} from '../EntityDecoder';
import {readUBitVar} from '../readBitVar';
import {encodeEntityUpdate, getEntityUpdate} from '../EntityDecoder';
import {readUBitVar, writeBitVar} from '../readBitVar';
import {isDate} from 'util';
import {ServerClass} from '../../Data/ServerClass';
import {SendTable} from '../../Data/SendTable';
const pvsMap = {
0: PVS.PRESERVE,
2: PVS.ENTER,
1: PVS.LEAVE,
3: PVS.LEAVE + PVS.DELETE,
};
const pvsMap = new Map([
[0, PVS.PRESERVE],
[2, PVS.ENTER],
[1, PVS.LEAVE],
[3, PVS.LEAVE + PVS.DELETE],
]);
const pvsReverseMap = new Map([
[PVS.PRESERVE, 0],
[PVS.ENTER, 2],
[PVS.LEAVE, 1],
[PVS.LEAVE + PVS.DELETE, 3],
]);
function readPVSType(stream: BitStream): PVS {
const pvs = stream.readBits(2);
// console.log(pvs);
return pvsMap[pvs];
return pvsMap.get(pvs) as number;
}
function writePVSType(pvs: PVS, stream: BitStream) {
const raw = pvsReverseMap.get(pvs);
if (!raw) {
throw new Error(`Unknown pvs ${pvs}`);
}
stream.writeBits(raw, 2);
}
function readEnterPVS(stream: BitStream, entityId: EntityId, match: Match): PacketEntity {
@ -36,7 +54,7 @@ function readEnterPVS(stream: BitStream, entityId: EntityId, match: Match): Pack
if (!sendTable) {
throw new Error('Unknown SendTable for serverclass');
}
const staticBaseLine = match.staticBaseLines[serverClass.id];
const staticBaseLine = match.staticBaseLines.get(serverClass.id);
if (staticBaseLine) {
staticBaseLine.index = 0;
const props = getEntityUpdate(sendTable, staticBaseLine);
@ -52,6 +70,30 @@ function readEnterPVS(stream: BitStream, entityId: EntityId, match: Match): Pack
}
}
/**
* @param {PacketEntity} entity
* @param {BitStream} stream
* @param {Match} match
* @returns {SendProp[]} the entities to be encoded
*/
function writeEnterPVS(entity: PacketEntity, stream: BitStream, match: Match) {
const serverClassId = match.serverClasses.findIndex(serverClass => serverClass && entity.serverClass.id === serverClass.id);
if (serverClassId === -1) {
throw new Error(`Unknown server class ${entity.serverClass.name}(${entity.serverClass.id})`);
}
// get the instance from the match, not the entity
const serverClass = match.serverClasses[serverClassId];
stream.writeBits(serverClassId, match.classBits);
stream.writeBits(entity.serialNumber || 0, 10);
const cachedBaseLine = match.baseLineCache.get(serverClass);
const propsToEncode = cachedBaseLine ? entity.diffFromBaseLine(cachedBaseLine) : entity.props;
encodeEntityUpdate(propsToEncode, match.getSendTable(serverClass.dataTable), stream);
}
function getPacketEntityForExisting(entityId: EntityId, match: Match, pvs: PVS) {
const serverClass = match.entityClasses.get(entityId);
if (!serverClass) {
@ -62,6 +104,7 @@ function getPacketEntityForExisting(entityId: EntityId, match: Match, pvs: PVS)
}
export function ParsePacketEntities(stream: BitStream, match: Match, skip: boolean = false): PacketEntitiesPacket { // 26: packetEntities
const s = stream.index;
// 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
@ -104,6 +147,8 @@ export function ParsePacketEntities(stream: BitStream, match: Match, skip: boole
} else if (match.entityClasses.has(entityId)) {
const packetEntity = getPacketEntityForExisting(entityId, match, pvs);
receivedEntities.push(packetEntity);
} else {
throw new Error(`No existing entity to update with id ${entityId}`);
}
}
@ -120,11 +165,52 @@ export function ParsePacketEntities(stream: BitStream, match: Match, skip: boole
entities: receivedEntities,
removedEntities: removedEntityIds,
maxEntries,
isDelta,
delta,
baseLine,
updatedEntries,
length,
updatedBaseLine,
};
}
export function EncodePacketEntities(packet: PacketEntitiesPacket, stream: BitStream, match: Match) {
stream.writeBits(packet.maxEntries, 11);
const isDelta = packet.removedEntities.length > 0;
stream.writeBoolean(isDelta);
if (isDelta) {
stream.writeInt32(packet.delta);
}
stream.writeBits(packet.baseLine, 1);
stream.writeBits(packet.entities.length, 11);
const lengthStart = stream.index;
stream.index += 20;
const packetDataStart = stream.index;
stream.writeBoolean(packet.updatedBaseLine);
let lastEntityId = -1;
for (const entity of packet.entities) {
const diff = entity.entityIndex - lastEntityId;
lastEntityId = entity.entityIndex;
writeBitVar(diff - 1, stream);
writePVSType(entity.pvs, stream);
if (entity.pvs === PVS.ENTER) {
writeEnterPVS(entity, stream, match);
} else if (entity.pvs === PVS.PRESERVE) {
encodeEntityUpdate(entity.props, match.getSendTable(entity.serverClass.dataTable), stream);
}
for (const removedEntity of packet.removedEntities) {
stream.writeBoolean(true);
stream.writeBits(removedEntity, 11);
}
stream.writeBoolean(false);
}
const packetDataEnd = stream.index;
stream.index = lengthStart;
stream.writeBits(packetDataEnd - packetDataStart, 20);
stream.index = packetDataEnd;
}

View file

@ -27,6 +27,9 @@ export class SendPropParser {
}
public static readInt(propDefinition: SendPropDefinition, stream: BitStream) {
if (!propDefinition.hasFlag) {
console.log(propDefinition, propDefinition.hasFlag);
}
if (propDefinition.hasFlag(SendPropFlag.SPROP_VARINT)) {
return readVarInt(stream, !propDefinition.hasFlag(SendPropFlag.SPROP_UNSIGNED));
} else {

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,337 @@
[
{
"id": 338,
"name": "CWorld",
"dataTable": "DT_WORLD"
},
{
"id": 241,
"name": "CTFPlayer",
"dataTable": "DT_TFPlayer"
},
{
"id": 306,
"name": "CTFTeam",
"dataTable": "DT_TFTeam"
},
{
"id": 243,
"name": "CTFPlayerResource",
"dataTable": "DT_TFPlayerResource"
},
{
"id": 229,
"name": "CTFObjectiveResource",
"dataTable": "DT_TFObjectiveResource"
},
{
"id": 84,
"name": "CMonsterResource",
"dataTable": "DT_MonsterResource"
},
{
"id": 80,
"name": "CMannVsMachineStats",
"dataTable": "DT_MannVsMachineStats"
},
{
"id": 331,
"name": "CVoteController",
"dataTable": "DT_VoteController"
},
{
"id": 33,
"name": "CDynamicProp",
"dataTable": "DT_DynamicProp"
},
{
"id": 79,
"name": "CLightGlow",
"dataTable": "DT_LightGlow"
},
{
"id": 119,
"name": "CSprite",
"dataTable": "DT_Sprite"
},
{
"id": 7,
"name": "CBaseEntity",
"dataTable": "DT_BaseEntity"
},
{
"id": 126,
"name": "CTeamRoundTimer",
"dataTable": "DT_TeamRoundTimer"
},
{
"id": 127,
"name": "CTeamTrainWatcher",
"dataTable": "DT_TeamTrainWatcher"
},
{
"id": 1,
"name": "CBaseAnimating",
"dataTable": "DT_BaseAnimating"
},
{
"id": 92,
"name": "CParticleSystem",
"dataTable": "DT_ParticleSystem"
},
{
"id": 85,
"name": "CObjectCartDispenser",
"dataTable": "DT_ObjectCartDispenser"
},
{
"id": 67,
"name": "CFuncTrackTrain",
"dataTable": "DT_FuncTrackTrain"
},
{
"id": 97,
"name": "CPhysicsProp",
"dataTable": "DT_PhysicsProp"
},
{
"id": 207,
"name": "CTFGameRulesProxy",
"dataTable": "DT_TFGameRulesProxy"
},
{
"id": 123,
"name": "CSun",
"dataTable": "DT_Sun"
},
{
"id": 52,
"name": "CFogController",
"dataTable": "DT_FogController"
},
{
"id": 114,
"name": "CShadowControl",
"dataTable": "DT_ShadowControl"
},
{
"id": 46,
"name": "CEnvTonemapController",
"dataTable": "DT_EnvTonemapController"
},
{
"id": 6,
"name": "CBaseDoor",
"dataTable": "DT_BaseDoor"
},
{
"id": 113,
"name": "CSceneEntity",
"dataTable": "DT_SceneEntity"
},
{
"id": 217,
"name": "CTFJar",
"dataTable": "DT_TFWeaponJar"
},
{
"id": 64,
"name": "CFuncRespawnRoomVisualizer",
"dataTable": "DT_FuncRespawnRoomVisualizer"
},
{
"id": 289,
"name": "CTFShotgun_Pyro",
"dataTable": "DT_TFShotgun_Pyro"
},
{
"id": 292,
"name": "CTFShotgunBuildingRescue",
"dataTable": "DT_TFShotgunBuildingRescue"
},
{
"id": 308,
"name": "CTFViewModel",
"dataTable": "DT_TFViewModel"
},
{
"id": 212,
"name": "CTFGrenadePipebombProjectile",
"dataTable": "DT_TFProjectile_Pipebomb"
},
{
"id": 228,
"name": "CTFMinigun",
"dataTable": "DT_WeaponMinigun"
},
{
"id": 112,
"name": "CRopeKeyframe",
"dataTable": "DT_RopeKeyframe"
},
{
"id": 60,
"name": "CFuncOccluder",
"dataTable": "DT_FuncOccluder"
},
{
"id": 54,
"name": "CFunc_LOD",
"dataTable": "DT_Func_LOD"
},
{
"id": 198,
"name": "CTFCrossbow",
"dataTable": "DT_Crossbow"
},
{
"id": 323,
"name": "CTFWearable",
"dataTable": "DT_TFWearable"
},
{
"id": 295,
"name": "CTFSniperRifle",
"dataTable": "DT_TFSniperRifle"
},
{
"id": 189,
"name": "CTFBonesaw",
"dataTable": "DT_TFWeaponBonesaw"
},
{
"id": 196,
"name": "CTFClub",
"dataTable": "DT_TFWeaponClub"
},
{
"id": 293,
"name": "CTFShovel",
"dataTable": "DT_TFWeaponShovel"
},
{
"id": 337,
"name": "CWeaponMedigun",
"dataTable": "DT_WeaponMedigun"
},
{
"id": 282,
"name": "CTFRocketLauncher",
"dataTable": "DT_WeaponRocketLauncher"
},
{
"id": 244,
"name": "CTFPowerupBottle",
"dataTable": "DT_TFPowerupBottle"
},
{
"id": 118,
"name": "CSpotlightEnd",
"dataTable": "DT_SpotlightEnd"
},
{
"id": 19,
"name": "CBeam",
"dataTable": "DT_Beam"
},
{
"id": 221,
"name": "CTFLaserPointer",
"dataTable": "DT_TFLaserPointer"
},
{
"id": 222,
"name": "CTFLunchBox",
"dataTable": "DT_WeaponLunchBox"
},
{
"id": 202,
"name": "CTFFists",
"dataTable": "DT_TFWeaponFists"
},
{
"id": 180,
"name": "CTFAmmoPack",
"dataTable": "DT_AmmoPack"
},
{
"id": 273,
"name": "CTFRagdoll",
"dataTable": "DT_TFRagdoll"
},
{
"id": 86,
"name": "CObjectDispenser",
"dataTable": "DT_ObjectDispenser"
},
{
"id": 204,
"name": "CTFFlameThrower",
"dataTable": "DT_WeaponFlameThrower"
},
{
"id": 201,
"name": "CTFFireAxe",
"dataTable": "DT_TFWeaponFireAxe"
},
{
"id": 276,
"name": "CTFRevolver",
"dataTable": "DT_WeaponRevolver"
},
{
"id": 314,
"name": "CTFWeaponBuilder",
"dataTable": "DT_TFWeaponBuilder"
},
{
"id": 89,
"name": "CObjectTeleporter",
"dataTable": "DT_ObjectTeleporter"
},
{
"id": 317,
"name": "CTFWeaponPDA_Engineer_Build",
"dataTable": "DT_TFWeaponPDA_Engineer_Build"
},
{
"id": 318,
"name": "CTFWeaponPDA_Engineer_Destroy",
"dataTable": "DT_TFWeaponPDA_Engineer_Destroy"
},
{
"id": 319,
"name": "CTFWeaponPDA_Spy",
"dataTable": "DT_TFWeaponPDA_Spy"
},
{
"id": 330,
"name": "CVGuiScreen",
"dataTable": "DT_VGuiScreen"
},
{
"id": 192,
"name": "CTFBuffItem",
"dataTable": "DT_TFWeaponBuffItem"
},
{
"id": 88,
"name": "CObjectSentrygun",
"dataTable": "DT_ObjectSentrygun"
},
{
"id": 329,
"name": "CTFWrench",
"dataTable": "DT_TFWeaponWrench"
},
{
"id": 315,
"name": "CTFWeaponInvis",
"dataTable": "DT_TFWeaponInvis"
},
{
"id": 220,
"name": "CTFKnife",
"dataTable": "DT_TFWeaponKnife"
}
]

View file

@ -0,0 +1,124 @@
[
{
"serverClass": {
"id": 164,
"name": "CTEPlayerAnimEvent",
"dataTable": "DT_TEPlayerAnimEvent"
},
"entityIndex": 0,
"props": [
{
"definition": {
"type": 0,
"name": "m_iPlayerIndex",
"flags": 1,
"excludeDTName": null,
"lowValue": 0,
"highValue": 0,
"bitCount": 7,
"table": null,
"numElements": 0,
"arrayProperty": null,
"ownerTableName": "DT_TEPlayerAnimEvent"
},
"value": 17
}
],
"inPVS": false,
"pvs": 1,
"delay": 0
},
{
"serverClass": {
"id": 178,
"name": "CTETFParticleEffect",
"dataTable": "DT_TETFParticleEffect"
},
"entityIndex": 0,
"props": [
{
"definition": {
"type": 1,
"name": "m_vecOrigin[0]",
"flags": 32772,
"excludeDTName": null,
"lowValue": 0,
"highValue": 0,
"bitCount": 32,
"table": null,
"numElements": 0,
"arrayProperty": null,
"ownerTableName": "DT_TETFParticleEffect"
},
"value": 1004
},
{
"definition": {
"type": 1,
"name": "m_vecOrigin[1]",
"flags": 32772,
"excludeDTName": null,
"lowValue": 0,
"highValue": 0,
"bitCount": 32,
"table": null,
"numElements": 0,
"arrayProperty": null,
"ownerTableName": "DT_TETFParticleEffect"
},
"value": -2016
},
{
"definition": {
"type": 1,
"name": "m_vecOrigin[2]",
"flags": 32772,
"excludeDTName": null,
"lowValue": 0,
"highValue": 0,
"bitCount": 32,
"table": null,
"numElements": 0,
"arrayProperty": null,
"ownerTableName": "DT_TETFParticleEffect"
},
"value": 561
},
{
"definition": {
"type": 0,
"name": "m_iParticleSystemIndex",
"flags": 1,
"excludeDTName": null,
"lowValue": 0,
"highValue": 0,
"bitCount": 16,
"table": null,
"numElements": 0,
"arrayProperty": null,
"ownerTableName": "DT_TETFParticleEffect"
},
"value": 472
},
{
"definition": {
"type": 0,
"name": "entindex",
"flags": 1,
"excludeDTName": null,
"lowValue": 0,
"highValue": 0,
"bitCount": 11,
"table": null,
"numElements": 0,
"arrayProperty": null,
"ownerTableName": "DT_TETFParticleEffect"
},
"value": 2047
}
],
"inPVS": false,
"pvs": 1,
"delay": 0
}
]

View file

@ -15,32 +15,6 @@ function testDemo(name: string, fastMode: boolean = false) {
assert.deepEqual(JSON.parse(JSON.stringify(parsed)), target);
}
function testPackets() {
const target = JSON.parse(readFileSync(`${__dirname}/../data/${name}_packets.json`, 'utf8'));
const source = readFileSync(`${__dirname}/../data/${name}.dem`);
const demo = Demo.fromNodeBuffer(source);
const parser = demo.getParser(false);
parser.readHeader();
const match = parser.match;
const packets: {[tick: string]: Partial<Packet>[]} = {};
parser.on('packet', (packet: Packet) => {
if (!packets[match.tick]) {
packets[match.tick] = [];
}
const packetData = {};
for (const key in packet) {
if (packet.hasOwnProperty(key) && !(packet[key] instanceof BitStream)) {
packetData[key] = packet[key];
}
}
packets[match.tick].push(packetData);
});
assert.deepEqual(JSON.parse(JSON.stringify(packets)), target);
}
suite('Parse basic demo info', () => {
test('Fast mode', () => {
testDemo('snakewater', true);

View file

@ -0,0 +1,145 @@
import {BitStream} from 'bit-buffer';
import {assertEncoder, assertParser, getStream} from './PacketTest';
import {Match} from '../../../../Data/Match';
import {hydrateEntity, hydrateTable} from './hydrate';
import {ServerClass} from '../../../../Data/ServerClass';
import {PacketEntitiesPacket} from '../../../../Data/Packet';
import {readFileSync} from 'fs';
import {gunzipSync} from 'zlib';
import {EncodePacketEntities, ParsePacketEntities} from '../../../../Parser/Packet/PacketEntities';
import * as assert from 'assert';
const data = JSON.parse(readFileSync(__dirname + '/../../../data/packetEntitiesData.json', 'utf8'));
const packetData = JSON.parse(gunzipSync(readFileSync(__dirname + '/../../../data/packetEntitiesResult.json.gz')).toString('utf8'));
const sendTableData = JSON.parse(gunzipSync(readFileSync(__dirname + '/../../../data/packetEntitiesSendTables.json.gz')).toString('utf8'));
const serverClassesData = JSON.parse(readFileSync(__dirname + '/../../../data/packetEntitiesServerClasses.json', 'utf8'));
const expected: PacketEntitiesPacket = {
packetType: 'packetEntities',
removedEntities: packetData.removedEntities,
updatedBaseLine: packetData.updatedBaseLine,
baseLine: packetData.baseLine,
delta: packetData.delta,
maxEntries: packetData.maxEntries,
entities: packetData.entities.map(hydrateEntity)
};
const match = new Match();
match.serverClasses.length = 348;
for (const serverClass of serverClassesData) {
match.serverClasses[serverClass.id] = new ServerClass(serverClass.id, serverClass.name, serverClass.dataTable);
}
for (const sendTable of sendTableData) {
const table = hydrateTable(sendTable);
match.sendTables.set(table.name, table);
}
for (const entity of expected.entities) {
match.entityClasses.set(entity.entityIndex, entity.serverClass);
}
function parse(stream: BitStream) {
return ParsePacketEntities(stream, match);
}
function encode(value: PacketEntitiesPacket, stream: BitStream) {
EncodePacketEntities(value, stream, match);
}
const sunEntityData = {
'serverClass': {
'id': 123,
'name': 'CSun',
'dataTable': 'DT_Sun'
},
'entityIndex': 403,
'props': [
{
'definition': {
'type': 0,
'name': 'm_clrRender',
'flags': 1,
'excludeDTName': null,
'lowValue': 0,
'highValue': 0,
'bitCount': 32,
'table': null,
'numElements': 0,
'arrayProperty': null,
'ownerTableName': 'DT_Sun'
},
'value': 4276271871
},
{
'definition': {
'type': 0,
'name': 'm_clrOverlay',
'flags': 1,
'excludeDTName': null,
'lowValue': 0,
'highValue': 0,
'bitCount': 32,
'table': null,
'numElements': 0,
'arrayProperty': null,
'ownerTableName': 'DT_Sun'
},
'value': 0
},
{
'definition': {
'type': 2,
'name': 'm_vDirection',
'flags': 32,
'excludeDTName': null,
'lowValue': 0,
'highValue': -121121.125,
'bitCount': 0,
'table': null,
'numElements': 0,
'arrayProperty': null,
'ownerTableName': 'DT_Sun'
},
'value': {
'x': -0.6453346360527601,
'y': -0.504152418172936,
'z': 0.1880801172447484
}
}
],
'inPVS': true,
'pvs': 1,
'serialNumber': 664
};
suite('PacketEntities', () => {
test('Parse packetEntities', () => {
const length = 130435;
const stream = getStream(data);
const start = stream.index;
const resultPacket = parse(stream);
assert.equal(stream.index - start, length, 'Unexpected number of bits consumed from stream');
for (let i = 0; i < resultPacket.entities.length; i++) {
const resultEntity = resultPacket.entities[i];
const expectedEntity = expected.entities[i];
assert.deepEqual(resultEntity, expectedEntity);
}
});
// test('Encode packetEntities', () => {
// assertEncoder(parse, encode, expected, Math.ceil(data.length / 8));
// });
//
// test('Encode small packetEntities', () => {
// assertEncoder(parse, encode, {
// packetType: 'packetEntities',
// removedEntities: [10, 11],
// updatedBaseLine: false,
// baseLine: 0,
// delta: 0,
// maxEntries: 16,
// entities: [hydrateEntity(sunEntityData)]
// }, 259);
// });
});

View file

@ -5,6 +5,7 @@ import {Match} from '../../../../Data/Match';
import {hydrateEntity, hydrateTable} from './hydrate';
import {ServerClass} from '../../../../Data/ServerClass';
import {TempEntitiesPacket} from '../../../../Data/Packet';
import {readFileSync} from 'fs';
const data = [
2,
@ -29,130 +30,7 @@ const data = [
252,
95];
const entityData = [
{
'serverClass': {
'id': 164,
'name': 'CTEPlayerAnimEvent',
'dataTable': 'DT_TEPlayerAnimEvent'
},
'entityIndex': 0,
'props': [
{
'definition': {
'type': 0,
'name': 'm_iPlayerIndex',
'flags': 1,
'excludeDTName': null,
'lowValue': 0,
'highValue': 0,
'bitCount': 7,
'table': null,
'numElements': 0,
'arrayProperty': null,
'ownerTableName': 'DT_TEPlayerAnimEvent'
},
'value': 17
}
],
'inPVS': false,
'pvs': 1,
'delay': 0
},
{
'serverClass': {
'id': 178,
'name': 'CTETFParticleEffect',
'dataTable': 'DT_TETFParticleEffect'
},
'entityIndex': 0,
'props': [
{
'definition': {
'type': 1,
'name': 'm_vecOrigin[0]',
'flags': 32772,
'excludeDTName': null,
'lowValue': 0,
'highValue': 0,
'bitCount': 32,
'table': null,
'numElements': 0,
'arrayProperty': null,
'ownerTableName': 'DT_TETFParticleEffect'
},
'value': 1004
},
{
'definition': {
'type': 1,
'name': 'm_vecOrigin[1]',
'flags': 32772,
'excludeDTName': null,
'lowValue': 0,
'highValue': 0,
'bitCount': 32,
'table': null,
'numElements': 0,
'arrayProperty': null,
'ownerTableName': 'DT_TETFParticleEffect'
},
'value': -2016
},
{
'definition': {
'type': 1,
'name': 'm_vecOrigin[2]',
'flags': 32772,
'excludeDTName': null,
'lowValue': 0,
'highValue': 0,
'bitCount': 32,
'table': null,
'numElements': 0,
'arrayProperty': null,
'ownerTableName': 'DT_TETFParticleEffect'
},
'value': 561
},
{
'definition': {
'type': 0,
'name': 'm_iParticleSystemIndex',
'flags': 1,
'excludeDTName': null,
'lowValue': 0,
'highValue': 0,
'bitCount': 16,
'table': null,
'numElements': 0,
'arrayProperty': null,
'ownerTableName': 'DT_TETFParticleEffect'
},
'value': 472
},
{
'definition': {
'type': 0,
'name': 'entindex',
'flags': 1,
'excludeDTName': null,
'lowValue': 0,
'highValue': 0,
'bitCount': 11,
'table': null,
'numElements': 0,
'arrayProperty': null,
'ownerTableName': 'DT_TETFParticleEffect'
},
'value': 2047
}
],
'inPVS': false,
'pvs': 1,
'delay': 0
}
];
const entityData = JSON.parse(readFileSync(__dirname + '/../../../data/tempEntitiesResult.json', 'utf8'));
const sendTableData = {
'name': 'DT_TEPlayerAnimEvent',
'props': [

View file

@ -15,15 +15,19 @@ export function hydrateEntity(entityData): PacketEntity {
}
return prop;
});
entity.inPVS = entityData.inPVS;
if (typeof entityData.delay !== 'undefined') {
entity.delay = entityData.delay;
}
if (typeof entityData.serialNumber !== 'undefined') {
entity.serialNumber = entityData.serialNumber;
}
return entity;
}
export function propDataDefinition(propData): SendPropDefinition {
const prop = new SendPropDefinition(propData.type, propData.name, propData.flags, propData.ownerTableName);
prop.arrayProperty = propData.arrayProperty;
prop.arrayProperty = propData.arrayProperty ? propDataDefinition(propData.arrayProperty) : null;
prop.numElements = propData.numElements;
prop.bitCount = propData.bitCount;
prop.excludeDTName = propData.excludeDTName;

View file

@ -1,4 +1,5 @@
import {BitStream} from 'bit-buffer';
import * as assert from 'assert';
export interface EqualOpts {
strict?: boolean;