Skip to content
This repository was archived by the owner on Jul 2, 2024. It is now read-only.

Commit a5a1642

Browse files
committed
encoder wip
1 parent 5b2665b commit a5a1642

13 files changed

+876
-35
lines changed

src/Data/ParserState.ts

+4
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,13 @@ export class ParserState {
2828
public instanceBaselines: [Map<EntityId, SendProp[]>, Map<EntityId, SendProp[]>] = [new Map(), new Map()];
2929
public skippedPackets: PacketTypeId[] = [];
3030
public userInfoEntries: Map<string, BitStream> = new Map();
31+
public tick: number = 0;
3132

3233
public handlePacket(packet: Packet) {
3334
switch (packet.packetType) {
35+
case 'netTick':
36+
this.tick = packet.tick;
37+
break;
3438
case 'serverInfo':
3539
this.version = packet.version;
3640
break;

src/Demo.ts

+2-7
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,8 @@ import {PacketTypeId} from './Data/Packet';
44
import {Parser} from './Parser';
55

66
export class Demo {
7-
public static fromNodeBuffer(nodeBuffer) {
8-
const arrayBuffer = new ArrayBuffer(nodeBuffer.length);
9-
const view = new Uint8Array(arrayBuffer);
10-
for (let i = 0; i < nodeBuffer.length; ++i) {
11-
view[i] = nodeBuffer[i];
12-
}
13-
return new Demo(arrayBuffer);
7+
public static fromNodeBuffer(nodeBuffer: Buffer) {
8+
return new Demo(nodeBuffer.buffer as ArrayBuffer);
149
}
1510

1611
public stream: BitStream;

src/Encoder.ts

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import {BitStream} from 'bit-buffer';
2+
import {Header} from './Data/Header';
3+
import {Message, MessageType} from './Data/Message';
4+
import {ParserState} from './Data/ParserState';
5+
import {messageHandlers} from './Parser';
6+
7+
export class Encoder {
8+
public readonly stream: BitStream;
9+
public readonly parserState: ParserState;
10+
11+
constructor(stream: BitStream) {
12+
this.stream = stream;
13+
this.parserState = new ParserState();
14+
}
15+
16+
public encodeHeader(header: Header) {
17+
this.stream.writeASCIIString(header.type, 8);
18+
this.stream.writeUint32(header.version);
19+
this.stream.writeUint32(header.protocol);
20+
this.stream.writeASCIIString(header.server, 260);
21+
this.stream.writeASCIIString(header.nick, 260);
22+
this.stream.writeASCIIString(header.map, 260);
23+
this.stream.writeASCIIString(header.game, 260);
24+
this.stream.writeFloat32(header.duration);
25+
this.stream.writeUint32(header.ticks);
26+
this.stream.writeUint32(header.frames);
27+
this.stream.writeUint32(header.sigon);
28+
}
29+
30+
public writeMessage(message: Message) {
31+
this.stream.writeUint8(message.type);
32+
const handler = messageHandlers.get(message.type);
33+
if (!handler) {
34+
throw new Error(`No handler for message of type ${MessageType[message.type]}`);
35+
}
36+
handler.encodeMessage(message, this.stream, this.parserState);
37+
this.handleMessage(message);
38+
}
39+
40+
protected handleMessage(message: Message) {
41+
this.parserState.handleMessage(message);
42+
if (message.type === MessageType.Packet) {
43+
for (const packet of message.packets) {
44+
this.parserState.handlePacket(packet);
45+
}
46+
}
47+
}
48+
}

src/Parser.ts

+19-20
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,20 @@ import {ParserState} from './Data/ParserState';
66
import {ConsoleCmdHandler} from './Parser/Message/ConsoleCmd';
77
import {DataTableHandler} from './Parser/Message/DataTable';
88
import {PacketMessageHandler} from './Parser/Message/Packet';
9+
import {StopHandler} from './Parser/Message/Stop';
910
import {StringTableHandler} from './Parser/Message/StringTable';
1011
import {SyncTickHandler} from './Parser/Message/SyncTick';
1112
import {UserCmdHandler} from './Parser/Message/UserCmd';
1213

13-
const messageHandlers: Map<MessageType, MessageHandler<Message>> = new Map<MessageType, MessageHandler<Message>>([
14+
export const messageHandlers: Map<MessageType, MessageHandler<Message>> = new Map<MessageType, MessageHandler<Message>>([
1415
[MessageType.Sigon, PacketMessageHandler],
1516
[MessageType.Packet, PacketMessageHandler],
1617
[MessageType.ConsoleCmd, ConsoleCmdHandler],
1718
[MessageType.UserCmd, UserCmdHandler],
1819
[MessageType.DataTables, DataTableHandler],
1920
[MessageType.StringTables, StringTableHandler],
20-
[MessageType.SyncTick, SyncTickHandler]
21+
[MessageType.SyncTick, SyncTickHandler],
22+
[MessageType.Stop, StopHandler]
2123
]);
2224

2325
export class Parser {
@@ -50,22 +52,13 @@ export class Parser {
5052
protected * getMessages(): Iterable<Message> {
5153
while (true) {
5254
const message = this.readMessage(this.stream, this.parserState);
53-
if (message) {
54-
yield message;
55-
} else {
55+
yield message;
56+
if (message.type === MessageType.Stop) {
5657
return;
5758
}
5859
}
5960
}
6061

61-
protected parseMessage(data: BitStream, type: MessageType, state: ParserState): Message {
62-
const handler = messageHandlers.get(type);
63-
if (!handler) {
64-
throw new Error(`No handler for message of type ${MessageType[type]}`);
65-
}
66-
return handler.parseMessage(data, state);
67-
}
68-
6962
protected parseHeader(stream): Header {
7063
return {
7164
type: stream.readASCIIString(8),
@@ -85,22 +78,28 @@ export class Parser {
8578
protected * handleMessage(message: Message): Iterable<Packet> {
8679
this.parserState.handleMessage(message);
8780
if (message.type === MessageType.Packet) {
88-
for (const packet of (message as PacketMessage).packets) {
81+
for (const packet of message.packets) {
8982
this.parserState.handlePacket(packet);
9083
yield packet;
9184
}
9285
}
9386
}
9487

95-
protected readMessage(stream: BitStream, state: ParserState): Message | false {
88+
protected readMessage(stream: BitStream, state: ParserState): Message {
9689
if (stream.bitsLeft < 8) {
97-
return false;
90+
throw new Error('Stream ended without stop packet');
9891
}
9992
const type: MessageType = stream.readUint8();
100-
if (type === MessageType.Stop) {
101-
return false;
93+
if (type === 0) {
94+
return {
95+
type: MessageType.Stop,
96+
rawData: stream.readBitStream(0)
97+
};
10298
}
103-
104-
return this.parseMessage(stream, type, state);
99+
const handler = messageHandlers.get(type);
100+
if (!handler) {
101+
throw new Error(`No handler for message of type ${MessageType[type]}(${type})`);
102+
}
103+
return handler.parseMessage(this.stream, state);
105104
}
106105
}

src/Parser/EntityDecoder.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@ export function getEntityUpdate(sendTable: SendTable, stream: BitStream): SendPr
99
let index = -1;
1010
const allProps = sendTable.flattenedProps;
1111
const props: Map<string, SendProp> = new Map();
12+
let lastIndex = -1;
1213
while (stream.readBoolean()) {
14+
lastIndex = index;
1315
index = readFieldIndex(stream, index);
1416
if (index >= 4096 || index > allProps.length) {
15-
throw new Error('prop index out of bounds while applying update for ' + sendTable.name + ' got ' + index
16-
+ ' property only has ' + allProps.length + ' properties');
17+
throw new Error(`prop index out of bounds while applying update for ${sendTable.name}
18+
got ${index} property only has ${allProps.length} properties (lastProp: ${lastIndex})`);
1719
}
1820

1921
const propDefinition = allProps[index];
@@ -42,8 +44,8 @@ export function encodeEntityUpdate(props: SendProp[], sendTable: SendTable, stre
4244
}
4345

4446
if (index < lastIndex) {
45-
throw new Error(`Property index not incremental while encoding` +
46-
`${prop.definition.fullName} after ${allProps[lastIndex].fullName}` +
47+
throw new Error(`Property index not incremental while encoding ` +
48+
`${prop.definition.fullName} after ${allProps[lastIndex].fullName} ` +
4749
`in ${sendTable.name} (current: ${index}, last: ${lastIndex})`);
4850
}
4951
writeFieldIndex(index, stream, lastIndex);

src/Parser/Message/Stop.ts

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import {BitStream} from 'bit-buffer';
2+
import {MessageHandler, MessageType, StopMessage, SyncTickMessage} from '../../Data/Message';
3+
4+
export const StopHandler: MessageHandler<StopMessage> = {
5+
parseMessage: (stream: BitStream) => {
6+
return {
7+
type: MessageType.Stop,
8+
rawData: stream.readBitStream(0)
9+
};
10+
},
11+
encodeMessage: (message, stream) => {
12+
// noop
13+
}
14+
};

src/Parser/Packet/GameEventList.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ import {GameEvent, GameEventType} from '../../Data/GameEventTypes';
44
import {GameEventListPacket} from '../../Data/Packet';
55

66
export function ParseGameEventList(stream: BitStream): GameEventListPacket { // 30: gameEventList
7-
const s = stream.index;
8-
97
// list of game events and parameters
108
const numEvents = stream.readBits(9);
119
const length = stream.readBits(20);
@@ -28,6 +26,7 @@ export function ParseGameEventList(stream: BitStream): GameEventListPacket { //
2826
entries
2927
});
3028
}
29+
3130
return {
3231
packetType: 'gameEventList',
3332
eventList

src/Parser/Packet/PacketEntities.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ export function ParsePacketEntities(
133133
const updatedEntries = stream.readBits(11);
134134
const length = stream.readBits(20);
135135
const updatedBaseLine = stream.readBoolean();
136+
const start = stream.index;
136137
const end = stream.index + length;
137138
let entityId = -1;
138139

@@ -166,14 +167,18 @@ export function ParsePacketEntities(
166167
if (!sendTable) {
167168
throw new Error(`Unknown sendTable ${packetEntity.serverClass.dataTable}`);
168169
}
170+
if (entityId === 55) {
171+
console.log(`decode preserve: ${entityId} = ${sendTable.name}, ${receivedEntities.length}/${i} ${stream.index} ${end} tick ${state.tick}`);
172+
console.log(receivedEntities[receivedEntities.length - 1], start, entityId, diff);
173+
}
169174
const updatedProps = getEntityUpdate(sendTable, stream);
170175
packetEntity.applyPropUpdate(updatedProps);
171176
receivedEntities.push(packetEntity);
172177
} else if (state.entityClasses.has(entityId)) {
173178
const packetEntity = getPacketEntityForExisting(entityId, state, pvs);
174179
receivedEntities.push(packetEntity);
175180
} else {
176-
// throw new Error(`No existing entity to update with id ${entityId}`);
181+
throw new Error(`No existing entity to update with id ${entityId}`);
177182
}
178183
}
179184

@@ -233,6 +238,9 @@ export function EncodePacketEntities(packet: PacketEntitiesPacket, stream: BitSt
233238
writeEnterPVS(entity, stream, state, packet.baseLine);
234239
} else if (entity.pvs === PVS.PRESERVE) {
235240
const sendTable = getSendTable(state, entity.serverClass.dataTable);
241+
if (entity.entityIndex === 55) {
242+
console.log(`encode preserve: ${entity.entityIndex} = ${entity.serverClass.dataTable}`);
243+
}
236244
encodeEntityUpdate(entity.props, sendTable, stream);
237245
}
238246
}

src/Parser/readBitVar.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export const readUBitVar = readBitVar;
5252
export function readVarInt(stream: BitStream, signed: boolean = false) {
5353
let result = 0;
5454
for (let i = 0; i < 35; i += 7) {
55-
const byte = stream.readBits(8);
55+
const byte = stream.readUint8();
5656
result |= ((byte & 0x7F) << i);
5757

5858
if ((byte >> 7) === 0) {

src/Transformer.ts

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import {BitStream} from 'bit-buffer';
2+
import {Parser} from './Parser';
3+
import {Encoder} from './Encoder';
4+
import {Packet} from './Data/Packet';
5+
import {Message, MessageType} from './Data/Message';
6+
7+
export type PacketTransform = (packet: Packet) => Packet;
8+
9+
export type MessageTransform = (message: Message) => Message;
10+
11+
export function nullTransform<T extends Packet | Message>(input: T): T {
12+
return input;
13+
}
14+
15+
export class Transformer extends Parser {
16+
private readonly encoder: Encoder;
17+
18+
constructor(sourceStream: BitStream, targetStream: BitStream) {
19+
super(sourceStream);
20+
this.encoder = new Encoder(targetStream);
21+
}
22+
23+
public transform(packetTransform: PacketTransform, messageTransform: MessageTransform) {
24+
this.encoder.encodeHeader(this.getHeader());
25+
26+
for (const message of this.getMessages()) {
27+
this.parserState.handleMessage(message);
28+
if (message.type === MessageType.Packet) {
29+
for (const packet of message.packets) {
30+
this.parserState.handlePacket(packet);
31+
}
32+
message.packets = message.packets.map(packetTransform);
33+
}
34+
35+
this.encoder.writeMessage(messageTransform(message));
36+
}
37+
}
38+
}

src/tests/data/short.dem

9.55 MB
Binary file not shown.

0 commit comments

Comments
 (0)