mirror of
https://github.com/demostf/demo.js
synced 2026-06-04 00:54:14 +02:00
add encoder for tempEntities
This commit is contained in:
parent
c064439b4e
commit
450300c1b0
12 changed files with 667 additions and 68 deletions
6
package-lock.json
generated
6
package-lock.json
generated
|
|
@ -229,9 +229,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"bit-buffer": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/bit-buffer/-/bit-buffer-0.2.0.tgz",
|
||||
"integrity": "sha512-et8MIvMW4fqwgseIq0SLjyjbhmypVSBcb+4Zd/+2CkYTDsh/yWXEosXrHaCvrTdYzkeeBJraypggmE3XKPlUAw=="
|
||||
"version": "0.2.3",
|
||||
"resolved": "https://registry.npmjs.org/bit-buffer/-/bit-buffer-0.2.3.tgz",
|
||||
"integrity": "sha512-Ugsj2ZD23YKb4cCasdBD4l1Oy4eI/752hnCMAmZO62P+oS1emCqNMlkex02ppGWgKHTS6sfzFeUbPD6VWd+s1w=="
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.6.tgz",
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
"jsnext:main": "build/es6/index.js",
|
||||
"module": "build/es6/index.js",
|
||||
"dependencies": {
|
||||
"bit-buffer": "^0.2.0",
|
||||
"bit-buffer": "^0.2.3",
|
||||
"clone": "^2.1.0",
|
||||
"minimist": "1.1.x",
|
||||
"snappyjs": "^0.5.0"
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ export class SendPropDefinition {
|
|||
|
||||
public inspect() {
|
||||
const data: any = {
|
||||
fromTable: this.ownerTableName,
|
||||
ownerTableName: this.ownerTableName,
|
||||
name: this.name,
|
||||
type: SendPropType[this.type],
|
||||
flags: this.flags,
|
||||
|
|
|
|||
30
src/DynamicBitStream.ts
Normal file
30
src/DynamicBitStream.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import {BitStream, BitView} from 'bit-buffer';
|
||||
|
||||
class DynamicBitView extends BitView {
|
||||
protected _view: Uint8Array;
|
||||
|
||||
setBits(offset: number, value: number, bits: number) {
|
||||
const available = (this.byteLength * 8 - offset);
|
||||
|
||||
if (bits > available) {
|
||||
this.grow();
|
||||
}
|
||||
return super.setBits(offset, value, bits);
|
||||
}
|
||||
|
||||
grow() {
|
||||
const newView = new Uint8Array(this.byteLength * 2);
|
||||
newView.set(this._view);
|
||||
this._view = newView;
|
||||
}
|
||||
}
|
||||
|
||||
export class DynamicBitStream extends BitStream {
|
||||
constructor(initialByteSize: number = 16 * 1024) {
|
||||
super(new DynamicBitView(new ArrayBuffer(initialByteSize)));
|
||||
}
|
||||
|
||||
get length() {
|
||||
return this.view.byteLength * 8;
|
||||
}
|
||||
}
|
||||
|
|
@ -31,7 +31,7 @@ export function encodeEntityUpdate(props: SendProp[], sendTable: SendTable, stre
|
|||
stream.writeBoolean(true);
|
||||
const index = allProps.findIndex(propDef => propDef.fullName === prop.definition.fullName);
|
||||
if (index === -1) {
|
||||
throw new Error('Unknown definition for property');
|
||||
throw new Error(`Unknown definition for property ${prop.definition.fullName} in ${sendTable.name}`);
|
||||
}
|
||||
writeFieldIndex(index, stream, lastIndex);
|
||||
lastIndex = index;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import {ParsePacketEntities} from '../Packet/PacketEntities';
|
|||
import {PacketHandler, voidEncoder} from '../Packet/Parser';
|
||||
import {EncodeParseSounds, ParseParseSounds} from '../Packet/ParseSounds';
|
||||
import {EncodeSetConVar, ParseSetConVar} from '../Packet/SetConVar';
|
||||
import {ParseTempEntities} from '../Packet/TempEntities';
|
||||
import {EncodeTempEntities, ParseTempEntities} from '../Packet/TempEntities';
|
||||
import {EncodeUpdateStringTable, ParseUpdateStringTable} from '../Packet/UpdateStringTable';
|
||||
import {EncodeUserMessage, ParseUserMessage} from '../Packet/UserMessage';
|
||||
import {EncodeVoiceData, ParseVoiceData} from '../Packet/VoiceData';
|
||||
|
|
@ -67,7 +67,7 @@ export class Packet extends Parser {
|
|||
[PacketTypeId.packetEntities,
|
||||
{parser: ParsePacketEntities, encoder: voidEncoder}],
|
||||
[PacketTypeId.tempEntities,
|
||||
{parser: ParseTempEntities, encoder: voidEncoder}],
|
||||
{parser: ParseTempEntities, encoder: EncodeTempEntities}],
|
||||
[PacketTypeId.preFetch,
|
||||
make('preFetch', 'index{14}')],
|
||||
[PacketTypeId.menu,
|
||||
|
|
|
|||
|
|
@ -2,47 +2,78 @@ import {BitStream} from 'bit-buffer';
|
|||
import {Match} from '../../Data/Match';
|
||||
import {TempEntitiesPacket} from '../../Data/Packet';
|
||||
import {PacketEntity, PVS} from '../../Data/PacketEntity';
|
||||
import {getEntityUpdate} from '../EntityDecoder';
|
||||
import {readVarInt} from '../readBitVar';
|
||||
import {encodeEntityUpdate, getEntityUpdate} from '../EntityDecoder';
|
||||
import {readVarInt, writeVarInt} from '../readBitVar';
|
||||
import {DynamicBitStream} from '../../DynamicBitStream';
|
||||
|
||||
export function ParseTempEntities(stream: BitStream, match: Match, skip: boolean = false): TempEntitiesPacket { // 10: classInfo
|
||||
const entityCount = stream.readBits(8);
|
||||
const entityCount = stream.readUint8();
|
||||
const length = readVarInt(stream);
|
||||
const end = stream.index + length;
|
||||
const entityData = stream.readBitStream(length);
|
||||
|
||||
let entity: PacketEntity | null = null;
|
||||
const entities: PacketEntity[] = [];
|
||||
if (!skip) {
|
||||
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 delay = (entityData.readBoolean()) ? entityData.readUint8() / 100 : 0; // unused it seems
|
||||
if (entityData.readBoolean()) {
|
||||
const classId = entityData.readBits(match.classBits);
|
||||
const serverClass = match.serverClasses[classId - 1];
|
||||
if (!serverClass) {
|
||||
throw new Error(`Unknown serverClass ${classId}`);
|
||||
}
|
||||
// no clue why the -1 but it works
|
||||
// maybe because world (id=0) can never be temp
|
||||
// but it's not like the -1 saves any space
|
||||
const sendTable = match.getSendTable(serverClass.dataTable);
|
||||
entity = new PacketEntity(serverClass, 0, PVS.ENTER);
|
||||
entity.delay = delay;
|
||||
entity.props = getEntityUpdate(sendTable, stream);
|
||||
entity.props = getEntityUpdate(sendTable, entityData);
|
||||
entities.push(entity);
|
||||
} else {
|
||||
if (entity) {
|
||||
const updatedProps = getEntityUpdate(match.getSendTable(entity.serverClass.dataTable), stream);
|
||||
const updatedProps = getEntityUpdate(match.getSendTable(entity.serverClass.dataTable), entityData);
|
||||
entity.applyPropUpdate(updatedProps);
|
||||
} else {
|
||||
throw new Error('no entity set to update');
|
||||
}
|
||||
}
|
||||
}
|
||||
if (end - stream.index > 8) {
|
||||
throw new Error('unexpected content after TempEntities');
|
||||
if (entityData.bitsLeft > 8) {
|
||||
throw new Error(`unexpected content after TempEntities ${entityData.bitsLeft} bits`);
|
||||
}
|
||||
}
|
||||
|
||||
stream.index = end;
|
||||
return {
|
||||
packetType: 'tempEntities',
|
||||
entities,
|
||||
};
|
||||
}
|
||||
|
||||
export function EncodeTempEntities(packet: TempEntitiesPacket, stream: BitStream, match: Match) {
|
||||
stream.writeUint8(packet.entities.length);
|
||||
|
||||
const entityStream = new DynamicBitStream();
|
||||
for (const entity of packet.entities) {
|
||||
if (entity.delay) {
|
||||
entityStream.writeBoolean(true);
|
||||
entityStream.writeUint8(Math.round(entity.delay * 100));
|
||||
} else {
|
||||
entityStream.writeBoolean(false);
|
||||
}
|
||||
|
||||
entityStream.writeBoolean(true);
|
||||
|
||||
const classId = match.serverClasses.findIndex(serverClass => serverClass && serverClass.name === entity.serverClass.name) + 1;
|
||||
entityStream.writeBits(classId, match.classBits);
|
||||
|
||||
const sendTable = match.getSendTable(entity.serverClass.dataTable);
|
||||
|
||||
encodeEntityUpdate(entity.props, sendTable, entityStream);
|
||||
}
|
||||
|
||||
const entityDataLength = entityStream.index;
|
||||
entityStream.index = 0;
|
||||
|
||||
writeVarInt(entityDataLength, stream);
|
||||
|
||||
stream.writeBitStream(entityStream, entityDataLength);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ export class SendPropParser {
|
|||
case SendPropType.DPT_Array:
|
||||
return SendPropParser.readArray(propDefinition, stream);
|
||||
}
|
||||
throw new Error('Unknown property type');
|
||||
throw new Error(`Unknown property type ${propDefinition.type}`);
|
||||
}
|
||||
|
||||
public static readInt(propDefinition: SendPropDefinition, stream: BitStream) {
|
||||
|
|
|
|||
17
src/tests/unit/DynamicBitStreamTest.ts
Normal file
17
src/tests/unit/DynamicBitStreamTest.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import * as assert from 'assert';
|
||||
import {DynamicBitStream} from '../../DynamicBitStream';
|
||||
|
||||
suite('DynamitcBitStream', () => {
|
||||
test('write grow', () => {
|
||||
const stream = new DynamicBitStream(2);
|
||||
stream.writeBits(0, 15);
|
||||
stream.writeBits(17, 16);
|
||||
|
||||
assert.equal(stream.length, 32);
|
||||
assert.equal(stream.index, 31);
|
||||
|
||||
stream.index = 18;
|
||||
|
||||
assert.equal(stream.readBits(2), 2);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,14 +1,12 @@
|
|||
import {BitStream} from 'bit-buffer';
|
||||
import {assertEncoder, assertParser, getStream} from './PacketTest';
|
||||
import {readFileSync} from 'fs';
|
||||
import {SendTable} from '../../../../Data/SendTable';
|
||||
import {encodeEntityUpdate, getEntityUpdate} from '../../../../Parser/EntityDecoder';
|
||||
import {SendProp, SendPropValue} from '../../../../Data/SendProp';
|
||||
import {SendPropDefinition, SendPropType} from '../../../../Data/SendPropDefinition';
|
||||
import {PacketEntity} from '../../../../Data/PacketEntity';
|
||||
import {Vector} from '../../../../Data/Vector';
|
||||
import {SendPropType} from '../../../../Data/SendPropDefinition';
|
||||
import {SendPropEncoder} from '../../../../Parser/SendPropEncoder';
|
||||
import {SendPropParser} from '../../../../Parser/SendPropParser';
|
||||
import {hydrateEntity, hydrateTable} from './hydrate';
|
||||
|
||||
const data = [
|
||||
9, 128, 64, 64, 64, 64, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 36, 0, 64, 0, 1, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 0, 128, 0, 0, 8, 0, 128, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 2, 64, 0, 32, 0, 16, 0, 32, 240, 255, 255, 255, 31, 0, 2, 32, 48, 0, 128, 0, 0, 4, 254, 255, 127, 224, 255, 255, 7, 254, 255, 127, 0, 8, 64, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 64, 64, 64, 64, 0, 32, 224, 136, 10, 248, 91, 2, 63, 18, 8, 40, 38, 3, 250, 163, 192, 126, 7, 2, 2, 0, 0, 0, 0, 1, 0, 0, 0, 128, 0, 0, 0, 224, 111, 0, 0, 0, 0, 32, 192, 129, 172, 140, 46, 44, 141, 237, 133, 172, 140, 46, 44, 141, 109, 14, 78, 46, 141, 174, 108, 238, 107, 46, 236, 174, 45, 141, 141, 45, 0];
|
||||
|
|
@ -18,46 +16,15 @@ const sendTableData = JSON.parse(readFileSync(__dirname + '/../../../data/sendTa
|
|||
const sendTable = hydrateTable(sendTableData);
|
||||
const entity = hydrateEntity(entityData);
|
||||
|
||||
function hydrateEntity(entityData): PacketEntity {
|
||||
const entity = new PacketEntity(entityData.serverClass, entityData.entityIndex, entityData.pvs);
|
||||
entity.props = entityData.props.map(propData => {
|
||||
const prop = new SendProp(propDataDefinition(propData.definition));
|
||||
if (prop.definition.type === SendPropType.DPT_Vector || prop.definition.type === SendPropType.DPT_VectorXY) {
|
||||
prop.value = new Vector(propData.value.x, propData.value.y, propData.value.z);
|
||||
} else {
|
||||
prop.value = propData.value;
|
||||
}
|
||||
return prop;
|
||||
});
|
||||
return entity;
|
||||
}
|
||||
|
||||
function propDataDefinition(propData): SendPropDefinition {
|
||||
const prop = new SendPropDefinition(propData.type, propData.name, propData.flags, propData.ownerTableName);
|
||||
prop.arrayProperty = propData.arrayProperty;
|
||||
prop.numElements = propData.numElements;
|
||||
prop.bitCount = propData.bitCount;
|
||||
prop.excludeDTName = propData.excludeDTName;
|
||||
prop.lowValue = propData.lowValue;
|
||||
prop.highValue = propData.highValue;
|
||||
prop.table = propData.table ? hydrateTable(propData.table) : null;
|
||||
return prop;
|
||||
}
|
||||
|
||||
function hydrateTable(tableData): SendTable {
|
||||
const table = new SendTable(tableData.name);
|
||||
table.props = tableData.props.map(propDataDefinition);
|
||||
return table;
|
||||
}
|
||||
|
||||
function decodeUpdate(stream: BitStream) {
|
||||
export function decodeUpdate(stream: BitStream) {
|
||||
return getEntityUpdate(sendTable, stream);
|
||||
}
|
||||
|
||||
function encodeUpdate(props: SendProp[], stream: BitStream) {
|
||||
export function encodeUpdate(props: SendProp[], stream: BitStream) {
|
||||
encodeEntityUpdate(props, sendTable, stream);
|
||||
}
|
||||
|
||||
|
||||
function encodeProp(prop: SendProp) {
|
||||
return function (value: SendPropValue, stream: BitStream) {
|
||||
return SendPropEncoder.encode(value, prop.definition, stream);
|
||||
|
|
|
|||
514
src/tests/unit/Parser/Packet/TempEntitiesTest.ts
Normal file
514
src/tests/unit/Parser/Packet/TempEntitiesTest.ts
Normal file
|
|
@ -0,0 +1,514 @@
|
|||
import {BitStream} from 'bit-buffer';
|
||||
import {assertEncoder, assertParser, getStream} from './PacketTest';
|
||||
import {EncodeTempEntities, ParseTempEntities} from '../../../../Parser/Packet/TempEntities';
|
||||
import {Match} from '../../../../Data/Match';
|
||||
import {hydrateEntity, hydrateTable} from './hydrate';
|
||||
import {ServerClass} from '../../../../Data/ServerClass';
|
||||
import {TempEntitiesPacket} from '../../../../Data/Packet';
|
||||
|
||||
const data = [
|
||||
2,
|
||||
142,
|
||||
1,
|
||||
150,
|
||||
10,
|
||||
68,
|
||||
56,
|
||||
43,
|
||||
176,
|
||||
245,
|
||||
5,
|
||||
254,
|
||||
253,
|
||||
192,
|
||||
96,
|
||||
20,
|
||||
194,
|
||||
14,
|
||||
8,
|
||||
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 sendTableData = {
|
||||
'name': 'DT_TEPlayerAnimEvent',
|
||||
'props': [
|
||||
{
|
||||
'type': 0,
|
||||
'name': 'm_iPlayerIndex',
|
||||
'flags': 1,
|
||||
'excludeDTName': null,
|
||||
'lowValue': 0,
|
||||
'highValue': 0,
|
||||
'bitCount': 7,
|
||||
'table': null,
|
||||
'numElements': 0,
|
||||
'arrayProperty': null,
|
||||
'ownerTableName': 'DT_TEPlayerAnimEvent'
|
||||
},
|
||||
{
|
||||
'type': 0,
|
||||
'name': 'm_iEvent',
|
||||
'flags': 1,
|
||||
'excludeDTName': null,
|
||||
'lowValue': 0,
|
||||
'highValue': 0,
|
||||
'bitCount': 6,
|
||||
'table': null,
|
||||
'numElements': 0,
|
||||
'arrayProperty': null,
|
||||
'ownerTableName': 'DT_TEPlayerAnimEvent'
|
||||
},
|
||||
{
|
||||
'type': 0,
|
||||
'name': 'm_nData',
|
||||
'flags': 0,
|
||||
'excludeDTName': null,
|
||||
'lowValue': 0,
|
||||
'highValue': 0,
|
||||
'bitCount': 12,
|
||||
'table': null,
|
||||
'numElements': 0,
|
||||
'arrayProperty': null,
|
||||
'ownerTableName': 'DT_TEPlayerAnimEvent'
|
||||
}
|
||||
],
|
||||
'cachedFlattenedProps': []
|
||||
};
|
||||
const sendTableData2 = {
|
||||
'name': 'DT_TETFParticleEffect',
|
||||
'props': [
|
||||
{
|
||||
'type': 6,
|
||||
'name': 'baseclass',
|
||||
'flags': 4096,
|
||||
'excludeDTName': null,
|
||||
'lowValue': 0,
|
||||
'highValue': 0,
|
||||
'bitCount': 0,
|
||||
'table': {
|
||||
'name': 'DT_BaseTempEntity',
|
||||
'props': [],
|
||||
'cachedFlattenedProps': []
|
||||
},
|
||||
'numElements': 0,
|
||||
'arrayProperty': null,
|
||||
'ownerTableName': 'DT_TETFParticleEffect'
|
||||
},
|
||||
{
|
||||
'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'
|
||||
},
|
||||
{
|
||||
'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'
|
||||
},
|
||||
{
|
||||
'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'
|
||||
},
|
||||
{
|
||||
'type': 1,
|
||||
'name': 'm_vecStart[0]',
|
||||
'flags': 32772,
|
||||
'excludeDTName': null,
|
||||
'lowValue': 0,
|
||||
'highValue': 0,
|
||||
'bitCount': 32,
|
||||
'table': null,
|
||||
'numElements': 0,
|
||||
'arrayProperty': null,
|
||||
'ownerTableName': 'DT_TETFParticleEffect'
|
||||
},
|
||||
{
|
||||
'type': 1,
|
||||
'name': 'm_vecStart[1]',
|
||||
'flags': 32772,
|
||||
'excludeDTName': null,
|
||||
'lowValue': 0,
|
||||
'highValue': 0,
|
||||
'bitCount': 32,
|
||||
'table': null,
|
||||
'numElements': 0,
|
||||
'arrayProperty': null,
|
||||
'ownerTableName': 'DT_TETFParticleEffect'
|
||||
},
|
||||
{
|
||||
'type': 1,
|
||||
'name': 'm_vecStart[2]',
|
||||
'flags': 32772,
|
||||
'excludeDTName': null,
|
||||
'lowValue': 0,
|
||||
'highValue': 0,
|
||||
'bitCount': 32,
|
||||
'table': null,
|
||||
'numElements': 0,
|
||||
'arrayProperty': null,
|
||||
'ownerTableName': 'DT_TETFParticleEffect'
|
||||
},
|
||||
{
|
||||
'type': 2,
|
||||
'name': 'm_vecAngles',
|
||||
'flags': 0,
|
||||
'excludeDTName': null,
|
||||
'lowValue': 0,
|
||||
'highValue': 360,
|
||||
'bitCount': 7,
|
||||
'table': null,
|
||||
'numElements': 0,
|
||||
'arrayProperty': null,
|
||||
'ownerTableName': 'DT_TETFParticleEffect'
|
||||
},
|
||||
{
|
||||
'type': 0,
|
||||
'name': 'm_iParticleSystemIndex',
|
||||
'flags': 1,
|
||||
'excludeDTName': null,
|
||||
'lowValue': 0,
|
||||
'highValue': 0,
|
||||
'bitCount': 16,
|
||||
'table': null,
|
||||
'numElements': 0,
|
||||
'arrayProperty': null,
|
||||
'ownerTableName': 'DT_TETFParticleEffect'
|
||||
},
|
||||
{
|
||||
'type': 0,
|
||||
'name': 'entindex',
|
||||
'flags': 1,
|
||||
'excludeDTName': null,
|
||||
'lowValue': 0,
|
||||
'highValue': 0,
|
||||
'bitCount': 11,
|
||||
'table': null,
|
||||
'numElements': 0,
|
||||
'arrayProperty': null,
|
||||
'ownerTableName': 'DT_TETFParticleEffect'
|
||||
},
|
||||
{
|
||||
'type': 0,
|
||||
'name': 'm_iAttachType',
|
||||
'flags': 1,
|
||||
'excludeDTName': null,
|
||||
'lowValue': 0,
|
||||
'highValue': 0,
|
||||
'bitCount': 5,
|
||||
'table': null,
|
||||
'numElements': 0,
|
||||
'arrayProperty': null,
|
||||
'ownerTableName': 'DT_TETFParticleEffect'
|
||||
},
|
||||
{
|
||||
'type': 0,
|
||||
'name': 'm_iAttachmentPointIndex',
|
||||
'flags': 0,
|
||||
'excludeDTName': null,
|
||||
'lowValue': 0,
|
||||
'highValue': 0,
|
||||
'bitCount': 32,
|
||||
'table': null,
|
||||
'numElements': 0,
|
||||
'arrayProperty': null,
|
||||
'ownerTableName': 'DT_TETFParticleEffect'
|
||||
},
|
||||
{
|
||||
'type': 0,
|
||||
'name': 'm_bResetParticles',
|
||||
'flags': 1,
|
||||
'excludeDTName': null,
|
||||
'lowValue': 0,
|
||||
'highValue': 0,
|
||||
'bitCount': 1,
|
||||
'table': null,
|
||||
'numElements': 0,
|
||||
'arrayProperty': null,
|
||||
'ownerTableName': 'DT_TETFParticleEffect'
|
||||
},
|
||||
{
|
||||
'type': 0,
|
||||
'name': 'm_bCustomColors',
|
||||
'flags': 1,
|
||||
'excludeDTName': null,
|
||||
'lowValue': 0,
|
||||
'highValue': 0,
|
||||
'bitCount': 1,
|
||||
'table': null,
|
||||
'numElements': 0,
|
||||
'arrayProperty': null,
|
||||
'ownerTableName': 'DT_TETFParticleEffect'
|
||||
},
|
||||
{
|
||||
'type': 2,
|
||||
'name': 'm_CustomColors.m_vecColor1',
|
||||
'flags': 0,
|
||||
'excludeDTName': null,
|
||||
'lowValue': 0,
|
||||
'highValue': 1,
|
||||
'bitCount': 8,
|
||||
'table': null,
|
||||
'numElements': 0,
|
||||
'arrayProperty': null,
|
||||
'ownerTableName': 'DT_TETFParticleEffect'
|
||||
},
|
||||
{
|
||||
'type': 2,
|
||||
'name': 'm_CustomColors.m_vecColor2',
|
||||
'flags': 0,
|
||||
'excludeDTName': null,
|
||||
'lowValue': 0,
|
||||
'highValue': 1,
|
||||
'bitCount': 8,
|
||||
'table': null,
|
||||
'numElements': 0,
|
||||
'arrayProperty': null,
|
||||
'ownerTableName': 'DT_TETFParticleEffect'
|
||||
},
|
||||
{
|
||||
'type': 0,
|
||||
'name': 'm_bControlPoint1',
|
||||
'flags': 1,
|
||||
'excludeDTName': null,
|
||||
'lowValue': 0,
|
||||
'highValue': 0,
|
||||
'bitCount': 1,
|
||||
'table': null,
|
||||
'numElements': 0,
|
||||
'arrayProperty': null,
|
||||
'ownerTableName': 'DT_TETFParticleEffect'
|
||||
},
|
||||
{
|
||||
'type': 0,
|
||||
'name': 'm_ControlPoint1.m_eParticleAttachment',
|
||||
'flags': 1,
|
||||
'excludeDTName': null,
|
||||
'lowValue': 0,
|
||||
'highValue': 0,
|
||||
'bitCount': 5,
|
||||
'table': null,
|
||||
'numElements': 0,
|
||||
'arrayProperty': null,
|
||||
'ownerTableName': 'DT_TETFParticleEffect'
|
||||
},
|
||||
{
|
||||
'type': 1,
|
||||
'name': 'm_ControlPoint1.m_vecOffset[0]',
|
||||
'flags': 8196,
|
||||
'excludeDTName': null,
|
||||
'lowValue': 0,
|
||||
'highValue': 0,
|
||||
'bitCount': 32,
|
||||
'table': null,
|
||||
'numElements': 0,
|
||||
'arrayProperty': null,
|
||||
'ownerTableName': 'DT_TETFParticleEffect'
|
||||
},
|
||||
{
|
||||
'type': 1,
|
||||
'name': 'm_ControlPoint1.m_vecOffset[1]',
|
||||
'flags': 8196,
|
||||
'excludeDTName': null,
|
||||
'lowValue': 0,
|
||||
'highValue': 0,
|
||||
'bitCount': 32,
|
||||
'table': null,
|
||||
'numElements': 0,
|
||||
'arrayProperty': null,
|
||||
'ownerTableName': 'DT_TETFParticleEffect'
|
||||
},
|
||||
{
|
||||
'type': 1,
|
||||
'name': 'm_ControlPoint1.m_vecOffset[2]',
|
||||
'flags': 8196,
|
||||
'excludeDTName': null,
|
||||
'lowValue': 0,
|
||||
'highValue': 0,
|
||||
'bitCount': 32,
|
||||
'table': null,
|
||||
'numElements': 0,
|
||||
'arrayProperty': null,
|
||||
'ownerTableName': 'DT_TETFParticleEffect'
|
||||
}
|
||||
],
|
||||
'cachedFlattenedProps': []
|
||||
};
|
||||
const sendTable = hydrateTable(sendTableData);
|
||||
const sendTable2 = hydrateTable(sendTableData2);
|
||||
const expected = {
|
||||
packetType: 'tempEntities',
|
||||
entities: entityData.map(hydrateEntity)
|
||||
};
|
||||
|
||||
const match = new Match();
|
||||
match.serverClasses.length = 348;
|
||||
match.serverClasses[164] = new ServerClass(164, 'CTEPlayerAnimEvent', 'DT_TEPlayerAnimEvent');
|
||||
match.serverClasses[178] = new ServerClass(178, 'CTETFParticleEffect', 'DT_TETFParticleEffect');
|
||||
match.sendTables.set(sendTable.name, sendTable);
|
||||
match.sendTables.set(sendTable2.name, sendTable2);
|
||||
|
||||
function parse(stream: BitStream) {
|
||||
return ParseTempEntities(stream, match);
|
||||
}
|
||||
|
||||
function encode(value: TempEntitiesPacket, stream: BitStream) {
|
||||
EncodeTempEntities(value, stream, match);
|
||||
}
|
||||
|
||||
suite('TempEntities', () => {
|
||||
test('Parse tempEntities', () => {
|
||||
assertParser(parse, getStream(data), expected, 166);
|
||||
});
|
||||
|
||||
test('Encode tempEntities', () => {
|
||||
assertEncoder(parse, encode, expected, 166);
|
||||
});
|
||||
});
|
||||
40
src/tests/unit/Parser/Packet/hydrate.ts
Normal file
40
src/tests/unit/Parser/Packet/hydrate.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import {SendProp} from '../../../../Data/SendProp';
|
||||
import {PacketEntity} from '../../../../Data/PacketEntity';
|
||||
import {SendPropDefinition, SendPropType} from '../../../../Data/SendPropDefinition';
|
||||
import {Vector} from '../../../../Data/Vector';
|
||||
import {SendTable} from '../../../../Data/SendTable';
|
||||
|
||||
export function hydrateEntity(entityData): PacketEntity {
|
||||
const entity = new PacketEntity(entityData.serverClass, entityData.entityIndex, entityData.pvs);
|
||||
entity.props = entityData.props.map(propData => {
|
||||
const prop = new SendProp(propDataDefinition(propData.definition));
|
||||
if (prop.definition.type === SendPropType.DPT_Vector || prop.definition.type === SendPropType.DPT_VectorXY) {
|
||||
prop.value = new Vector(propData.value.x, propData.value.y, propData.value.z);
|
||||
} else {
|
||||
prop.value = propData.value;
|
||||
}
|
||||
return prop;
|
||||
});
|
||||
if (typeof entityData.delay !== 'undefined') {
|
||||
entity.delay = entityData.delay;
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
export function propDataDefinition(propData): SendPropDefinition {
|
||||
const prop = new SendPropDefinition(propData.type, propData.name, propData.flags, propData.ownerTableName);
|
||||
prop.arrayProperty = propData.arrayProperty;
|
||||
prop.numElements = propData.numElements;
|
||||
prop.bitCount = propData.bitCount;
|
||||
prop.excludeDTName = propData.excludeDTName;
|
||||
prop.lowValue = propData.lowValue;
|
||||
prop.highValue = propData.highValue;
|
||||
prop.table = propData.table ? hydrateTable(propData.table) : null;
|
||||
return prop;
|
||||
}
|
||||
|
||||
export function hydrateTable(tableData): SendTable {
|
||||
const table = new SendTable(tableData.name);
|
||||
table.props = tableData.props.map(propDataDefinition);
|
||||
return table;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue