1
0
Fork 0
mirror of https://github.com/demostf/demo.js synced 2026-06-04 00:54:14 +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

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;