mirror of
https://github.com/demostf/demo.js
synced 2026-06-03 16:44:12 +02:00
add encoder for packet message
This commit is contained in:
parent
d54f639633
commit
5241059fd2
8 changed files with 180 additions and 22 deletions
|
|
@ -38,7 +38,7 @@ export class Parser {
|
|||
return this.header;
|
||||
}
|
||||
|
||||
public * getPackets(): Iterable<Packet> {
|
||||
public * getPackets(): IterableIterator<Packet> {
|
||||
// ensure that we are past the header
|
||||
this.getHeader();
|
||||
const messages = this.getMessages();
|
||||
|
|
@ -48,13 +48,12 @@ export class Parser {
|
|||
}
|
||||
|
||||
private * getMessages(): Iterable<Message> {
|
||||
let hasNext: boolean = true;
|
||||
while (hasNext) {
|
||||
while (true) {
|
||||
const message = this.readMessage(this.stream, this.parserState);
|
||||
if (!message) {
|
||||
hasNext = false;
|
||||
} else {
|
||||
if (message) {
|
||||
yield message;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ import {EncodeClassInfo, ParseClassInfo} from '../Packet/ClassInfo';
|
|||
import {EncodeCreateStringTable, ParseCreateStringTable} from '../Packet/CreateStringTable';
|
||||
import {EncodeGameEvent, ParseGameEvent} from '../Packet/GameEvent';
|
||||
import {EncodeGameEventList, ParseGameEventList} from '../Packet/GameEventList';
|
||||
import {ParsePacketEntities} from '../Packet/PacketEntities';
|
||||
import {PacketHandler, voidEncoder} from '../Packet/Parser';
|
||||
import {EncodePacketEntities, ParsePacketEntities} from '../Packet/PacketEntities';
|
||||
import {PacketHandler} from '../Packet/Parser';
|
||||
import {EncodeParseSounds, ParseParseSounds} from '../Packet/ParseSounds';
|
||||
import {EncodeSetConVar, ParseSetConVar} from '../Packet/SetConVar';
|
||||
import {EncodeTempEntities, ParseTempEntities} from '../Packet/TempEntities';
|
||||
|
|
@ -67,7 +67,7 @@ const handlers: PacketHandlerMap = new Map<PacketTypeId, PacketHandler<IPacket>>
|
|||
[PacketTypeId.gameEvent,
|
||||
{parser: ParseGameEvent, encoder: EncodeGameEvent}],
|
||||
[PacketTypeId.packetEntities,
|
||||
{parser: ParsePacketEntities, encoder: voidEncoder}],
|
||||
{parser: ParsePacketEntities, encoder: EncodePacketEntities}],
|
||||
[PacketTypeId.tempEntities,
|
||||
{parser: ParseTempEntities, encoder: EncodeTempEntities}],
|
||||
[PacketTypeId.preFetch,
|
||||
|
|
@ -107,10 +107,10 @@ export const PacketMessageHandler: MessageHandler<PacketMessage> = {
|
|||
while (messageStream.bitsLeft > 6) { // last 6 bits for NOOP
|
||||
const type = messageStream.readBits(6) as PacketTypeId;
|
||||
if (type !== 0) {
|
||||
const parser = handlers.get(type);
|
||||
if (parser) {
|
||||
const handler = handlers.get(type);
|
||||
if (handler) {
|
||||
const skip = state.skippedPackets.indexOf(type) !== -1;
|
||||
const packet = parser.parser(messageStream, state, skip);
|
||||
const packet = handler.parser(messageStream, state, skip);
|
||||
packets.push(packet);
|
||||
} else {
|
||||
throw new Error(`Unknown packet type ${type} just parsed a ${PacketTypeId[lastPacketType]}`);
|
||||
|
|
@ -131,7 +131,55 @@ export const PacketMessageHandler: MessageHandler<PacketMessage> = {
|
|||
sequenceOut
|
||||
};
|
||||
},
|
||||
encodeMessage: (message, stream) => {
|
||||
throw new Error('Not implemented');
|
||||
encodeMessage: (message: PacketMessage, stream: BitStream, state: ParserState) => {
|
||||
stream.writeUint32(message.tick);
|
||||
stream.writeUint32(message.flags);
|
||||
|
||||
for (let j = 0; j < 2; j++) {
|
||||
stream.writeFloat32(message.viewOrigin[j].x);
|
||||
stream.writeFloat32(message.viewOrigin[j].y);
|
||||
stream.writeFloat32(message.viewOrigin[j].z);
|
||||
|
||||
stream.writeFloat32(message.viewAngles[j].x);
|
||||
stream.writeFloat32(message.viewAngles[j].y);
|
||||
stream.writeFloat32(message.viewAngles[j].z);
|
||||
|
||||
stream.writeFloat32(message.localViewAngles[j].x);
|
||||
stream.writeFloat32(message.localViewAngles[j].y);
|
||||
stream.writeFloat32(message.localViewAngles[j].z);
|
||||
}
|
||||
|
||||
stream.writeUint32(message.sequenceIn);
|
||||
stream.writeUint32(message.sequenceOut);
|
||||
|
||||
const lengthStart = stream.index;
|
||||
|
||||
stream.index += 32;
|
||||
|
||||
const dataStart = stream.index;
|
||||
|
||||
for (const packet of message.packets) {
|
||||
const type = PacketTypeId[packet.packetType];
|
||||
stream.writeBits(type, 6);
|
||||
|
||||
const handler = handlers.get(type);
|
||||
if (handler) {
|
||||
handler.encoder(packet, stream, state);
|
||||
} else {
|
||||
throw new Error(`No handler for packet type ${packet.packetType}`);
|
||||
}
|
||||
}
|
||||
|
||||
stream.writeBits(0, 6);
|
||||
|
||||
const dataEnd = stream.index;
|
||||
|
||||
stream.index = lengthStart;
|
||||
|
||||
const byteLength = Math.ceil((dataEnd - dataStart) / 8);
|
||||
stream.writeUint32(byteLength);
|
||||
|
||||
// align to byte;
|
||||
stream.index = dataStart + byteLength * 8;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -192,7 +192,7 @@ export function ParsePacketEntities(stream: BitStream, state: ParserState, skip:
|
|||
|
||||
export function EncodePacketEntities(packet: PacketEntitiesPacket, stream: BitStream, state: ParserState) {
|
||||
stream.writeBits(packet.maxEntries, 11);
|
||||
const isDelta = packet.removedEntities.length > 0;
|
||||
const isDelta = packet.delta > 0;
|
||||
stream.writeBoolean(isDelta);
|
||||
if (isDelta) {
|
||||
stream.writeInt32(packet.delta);
|
||||
|
|
|
|||
|
|
@ -76,5 +76,7 @@ export function EncodeTempEntities(packet: TempEntitiesPacket, stream: BitStream
|
|||
|
||||
writeVarInt(entityDataLength, stream);
|
||||
|
||||
stream.writeBitStream(entityStream, entityDataLength);
|
||||
if (entityDataLength > 0) {
|
||||
stream.writeBitStream(entityStream, entityDataLength);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
1
src/tests/data/packetMessageData.json
Normal file
1
src/tests/data/packetMessageData.json
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"0":8,"1":85,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0,"50":0,"51":0,"52":0,"53":0,"54":0,"55":0,"56":0,"57":0,"58":0,"59":0,"60":0,"61":0,"62":0,"63":0,"64":0,"65":0,"66":0,"67":0,"68":0,"69":0,"70":0,"71":0,"72":0,"73":0,"74":0,"75":0,"76":0,"77":0,"78":0,"79":0,"80":50,"81":21,"82":0,"83":0,"84":50,"85":21,"86":0,"87":0,"88":185,"89":1,"90":0,"91":0,"92":67,"93":148,"94":42,"95":0,"96":64,"97":121,"98":1,"99":88,"100":128,"101":118,"102":193,"103":77,"104":170,"105":0,"106":0,"107":78,"108":192,"109":206,"110":0,"111":8,"112":194,"113":59,"114":103,"115":31,"116":99,"117":7,"118":22,"119":142,"120":5,"121":26,"122":3,"123":246,"124":7,"125":2,"126":0,"127":132,"128":162,"129":84,"130":1,"131":0,"132":0,"133":132,"134":231,"135":87,"136":249,"137":255,"138":96,"139":96,"140":188,"141":64,"142":64,"143":51,"144":240,"145":127,"146":0,"147":13,"148":65,"149":120,"150":172,"151":197,"152":89,"153":158,"154":192,"155":198,"156":161,"157":136,"158":89,"159":199,"160":227,"161":129,"162":3,"163":8,"164":207,"165":195,"166":152,"167":26,"168":30,"169":24,"170":35,"171":18,"172":57,"173":3,"174":16,"175":158,"176":120,"177":235,"178":222,"179":132,"180":129,"181":105,"182":70,"183":137,"184":85,"185":2,"186":106,"187":0,"188":194,"189":155,"190":116,"191":175,"192":97,"193":6,"194":166,"195":13,"196":6,"197":184,"198":2,"199":118,"200":5,"201":208,"202":0,"203":132,"204":103,"205":127,"206":159,"207":45,"208":13,"209":172,"210":27,"211":15,"212":116,"213":38,"214":212,"215":0,"216":132,"217":165,"218":160,"219":236,"220":117,"221":117,"222":130,"223":49,"224":144,"225":82,"226":32,"227":13,"228":64,"229":88,"230":10,"231":202,"232":94,"233":87,"234":39,"235":44,"236":3,"237":128,"238":5,"239":202,"240":186,"241":26,"242":203,"243":8,"244":149,"245":66,"246":0,"247":194,"248":178,"249":78,"250":120,"251":253,"252":62,"253":131,"254":6,"255":32,"256":44,"257":176,"258":5,"259":47,"260":162,"261":35,"262":223,"263":7,"264":210,"265":0,"266":132,"267":151,"268":255,"269":61,"270":105,"271":78,"272":180,"273":6,"274":214,"275":13,"276":156,"277":1,"278":8,"279":235,"280":40,"281":241,"282":183,"283":154,"284":140,"285":90,"286":192,"287":82,"288":0,"289":64,"290":88,"291":46,"292":200,"293":159,"294":52,"295":102,"296":212,"297":0,"298":196,"299":99,"300":3,"301":62,"302":7,"303":202,"304":0,"305":132,"306":5,"307":182,"308":224,"309":69,"310":116,"311":196,"312":254,"313":64,"314":90,"315":87,"316":99,"317":127,"318":229,"319":22,"320":8,"321":64,"322":88,"323":79,"324":202,"325":111,"326":101,"327":38,"328":22,"329":3,"330":94,"331":5,"332":206,"333":0,"334":132,"335":181,"336":157,"337":236,"338":150,"339":108,"340":228,"341":224,"342":64,"343":26,"344":148,"345":28,"346":17,"347":145,"348":20,"349":66,"350":46,"351":68,"352":250,"353":88,"354":48,"355":161,"356":64,"357":162,"358":58,"359":32,"360":180,"361":24,"362":16,"363":56,"364":15,"365":192,"366":144,"367":99,"368":132,"369":1,"370":42,"371":159,"372":72,"373":89,"374":96,"375":88,"376":14,"377":167,"378":29,"379":91,"380":120,"381":112,"382":160,"383":243,"384":207,"385":171,"386":76,"387":169,"388":56,"389":34,"390":40,"391":154,"392":237,"393":62,"394":122,"395":67,"396":101,"397":170,"398":1,"399":40,"400":1,"401":129,"402":164,"403":243,"404":88,"405":0,"406":67,"407":164,"408":44,"409":48,"410":3,"411":147,"412":7,"413":213,"414":239,"415":50,"416":49,"417":0,"418":81,"419":12,"420":145,"421":178,"422":192,"423":232,"424":249,"425":60,"426":175,"427":27,"428":168,"429":139,"430":32,"431":82,"432":22,"433":24,"434":223,"435":159,"436":195,"437":109,"438":7,"439":70,"440":164,"441":44,"442":48,"443":48,"444":255,"445":195,"446":27,"447":140,"448":244,"449":136,"450":197,"451":30,"452":23,"453":0,"454":76,"455":206,"456":17,"457":7,"458":12,"459":71,"460":34,"461":100,"462":22,"463":50,"464":136,"465":32,"466":0,"467":101,"468":16,"469":201,"470":220,"471":36,"472":230,"473":1,"474":16,"475":41,"476":11,"477":108,"478":20,"479":229,"480":4,"481":241,"482":131,"483":130,"484":10,"485":8,"486":68,"487":68,"488":164,"489":44,"490":48,"491":78,"492":184,"493":91,"494":100,"495":141,"496":12,"497":5,"498":64,"499":164,"500":44,"501":176,"502":88,"503":144,"504":243,"505":195,"506":12,"507":14,"508":60,"509":48,"510":0,"511":17,"512":41,"513":11,"514":44,"515":19,"516":241,"517":26,"518":241,"519":91,"520":195,"521":48,"522":125,"523":213,"524":103,"525":11,"526":56,"527":209,"528":83,"529":64,"530":17,"531":184,"532":0}
|
||||
64
src/tests/data/packetMessageResult.json
Normal file
64
src/tests/data/packetMessageResult.json
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
{
|
||||
"type": 2,
|
||||
"packets": [
|
||||
{
|
||||
"packetType": "netTick",
|
||||
"tick": 43601,
|
||||
"frameTime": 1509,
|
||||
"stdDev": 352
|
||||
},
|
||||
{
|
||||
"packetType": "packetEntities",
|
||||
"entities": [],
|
||||
"removedEntities": [],
|
||||
"maxEntries": 1047,
|
||||
"delta": 43597,
|
||||
"baseLine": 0,
|
||||
"updatedBaseLine": false
|
||||
},
|
||||
{
|
||||
"packetType": "tempEntities",
|
||||
"entities": []
|
||||
}
|
||||
],
|
||||
"tick": 21768,
|
||||
"flags": 0,
|
||||
"viewOrigin": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
}
|
||||
],
|
||||
"viewAngles": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
}
|
||||
],
|
||||
"localViewAngles": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
}
|
||||
],
|
||||
"sequenceIn": 5426,
|
||||
"sequenceOut": 5426
|
||||
}
|
||||
43
src/tests/unit/Parser/Message/PacketTest.ts
Normal file
43
src/tests/unit/Parser/Message/PacketTest.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import {BitStream} from 'bit-buffer';
|
||||
import {assertEncoder, assertParser, getStream} from '../Packet/PacketTest';
|
||||
import {readFileSync} from 'fs';
|
||||
import {PacketMessageHandler} from '../../../../Parser/Message/Packet';
|
||||
import {ParserState} from '../../../../Data/ParserState';
|
||||
import {PacketTypeId} from '../../../../Data/Packet';
|
||||
|
||||
const data = Object.values(JSON.parse(readFileSync(__dirname + '/../../../data/packetMessageData.json', 'utf8')));
|
||||
const expected = JSON.parse(readFileSync(__dirname + '/../../../data/packetMessageResult.json', 'utf8'));
|
||||
|
||||
const getParserState = (fastMode) => {
|
||||
const state = new ParserState();
|
||||
// fast mode allows us not to bother with complicated entity parser state
|
||||
state.skippedPackets = fastMode ? [
|
||||
PacketTypeId.packetEntities,
|
||||
PacketTypeId.tempEntities,
|
||||
PacketTypeId.entityMessage,
|
||||
] : [];
|
||||
return state;
|
||||
};
|
||||
|
||||
const handler = PacketMessageHandler;
|
||||
|
||||
function parser(stream) {
|
||||
const result = handler.parseMessage(stream, getParserState(true));
|
||||
delete result.rawData;
|
||||
return result;
|
||||
}
|
||||
|
||||
function encoder(message, stream) {
|
||||
handler.encodeMessage(message, stream, getParserState(false));
|
||||
}
|
||||
|
||||
suite('Packet', () => {
|
||||
test('Parse packet message', () => {
|
||||
assertParser(parser, getStream(data), expected, 4264);
|
||||
});
|
||||
|
||||
test('Encode packet message', () => {
|
||||
// shorted since empty entity list encoded, instead of skipping over entities
|
||||
assertEncoder(parser, encoder, expected, 920, '');
|
||||
});
|
||||
});
|
||||
|
|
@ -3,6 +3,7 @@ import {BitStream} from 'bit-buffer';
|
|||
import {Packet} from '../../../../Data/Packet';
|
||||
import {deepEqual} from '../../deepEqual';
|
||||
import {isObject} from 'util';
|
||||
import {ParserState} from '../../../../Data/ParserState';
|
||||
|
||||
export function getStream(data: string | number[]) {
|
||||
if (typeof data === 'string') {
|
||||
|
|
@ -14,12 +15,12 @@ export function getStream(data: string | number[]) {
|
|||
}
|
||||
}
|
||||
|
||||
export type Encoder = (data: any, stream: BitStream) => void;
|
||||
export type Encoder = (data: any, stream: BitStream, state?) => void;
|
||||
|
||||
export function assertEncoder(parser: Parser, encoder: Encoder, data: any, length: number = 0, message: string = '') {
|
||||
export function assertEncoder(parser: Parser, encoder: Encoder, data: any, length: number = 0, message: string = '', state?: ParserState) {
|
||||
const stream = new BitStream(new ArrayBuffer(length + 64000));
|
||||
|
||||
encoder(data as Packet, stream);
|
||||
encoder(data as Packet, stream, state);
|
||||
|
||||
const pos = stream.index;
|
||||
|
||||
|
|
@ -37,11 +38,11 @@ export function assertEncoder(parser: Parser, encoder: Encoder, data: any, lengt
|
|||
assert.equal(stream.index, pos, 'Number of bits used for encoding and parsing not equal' + message);
|
||||
}
|
||||
|
||||
export type Parser = (stream: BitStream, match?) => any;
|
||||
export type Parser = (stream: BitStream, state?) => any;
|
||||
|
||||
export function assertParser(parser: Parser, stream: BitStream, expected: any, length: number) {
|
||||
export function assertParser(parser: Parser, stream: BitStream, expected: any, length: number, state?: ParserState) {
|
||||
const start = stream.index;
|
||||
const result = parser(stream);
|
||||
const result = parser(stream, state);
|
||||
if (!deepEqual(result, expected)) {
|
||||
assert.deepEqual(result, expected);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue