mirror of
https://github.com/demostf/demo.js
synced 2026-06-04 00:54:14 +02:00
stricter packet handler types
This commit is contained in:
parent
70bdf0257e
commit
df1aac6575
9 changed files with 262 additions and 145 deletions
|
|
@ -6,34 +6,37 @@ import {ServerClass} from './ServerClass';
|
||||||
import {StringTable, StringTableEntry} from './StringTable';
|
import {StringTable, StringTableEntry} from './StringTable';
|
||||||
import {Vector} from './Vector';
|
import {Vector} from './Vector';
|
||||||
|
|
||||||
export interface StringTablePacket {
|
export interface BasePacket {
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StringTablePacket extends BasePacket {
|
||||||
packetType: 'stringTable';
|
packetType: 'stringTable';
|
||||||
tables: StringTable[];
|
tables: StringTable[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CreateStringTablePacket {
|
export interface CreateStringTablePacket extends BasePacket {
|
||||||
packetType: 'createStringTable';
|
packetType: 'createStringTable';
|
||||||
table: StringTable;
|
table: StringTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UpdateStringTablePacket {
|
export interface UpdateStringTablePacket extends BasePacket {
|
||||||
packetType: 'updateStringTable';
|
packetType: 'updateStringTable';
|
||||||
entries: StringTableEntry[];
|
entries: StringTableEntry[];
|
||||||
tableId: number;
|
tableId: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ConsoleCmdPacket {
|
export interface ConsoleCmdPacket extends BasePacket {
|
||||||
packetType: 'consoleCmd';
|
packetType: 'consoleCmd';
|
||||||
command: string;
|
command: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DataTablePacket {
|
export interface DataTablePacket extends BasePacket {
|
||||||
packetType: 'dataTable';
|
packetType: 'dataTable';
|
||||||
tables: SendTable[];
|
tables: SendTable[];
|
||||||
serverClasses: ServerClass[];
|
serverClasses: ServerClass[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BSPDecalPacket {
|
export interface BSPDecalPacket extends BasePacket {
|
||||||
packetType: 'bspDecal';
|
packetType: 'bspDecal';
|
||||||
position: Vector;
|
position: Vector;
|
||||||
textureIndex: number;
|
textureIndex: number;
|
||||||
|
|
@ -42,7 +45,7 @@ export interface BSPDecalPacket {
|
||||||
lowPriority: boolean;
|
lowPriority: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ClassInfoPacket {
|
export interface ClassInfoPacket extends BasePacket {
|
||||||
packetType: 'classInfo';
|
packetType: 'classInfo';
|
||||||
number: number;
|
number: number;
|
||||||
create: boolean;
|
create: boolean;
|
||||||
|
|
@ -53,24 +56,24 @@ export interface ClassInfoPacket {
|
||||||
}[];
|
}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EntityMessagePacket {
|
export interface EntityMessagePacket extends BasePacket {
|
||||||
packetType: 'entityMessage';
|
packetType: 'entityMessage';
|
||||||
classId: number;
|
classId: number;
|
||||||
length: number;
|
length: number;
|
||||||
data: string;
|
data: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GameEventPacket {
|
export interface GameEventPacket extends BasePacket {
|
||||||
packetType: 'gameEvent';
|
packetType: 'gameEvent';
|
||||||
event: GameEvent;
|
event: GameEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GameEventListPacket {
|
export interface GameEventListPacket extends BasePacket {
|
||||||
packetType: 'gameEventList';
|
packetType: 'gameEventList';
|
||||||
eventList: GameEventDefinitionMap;
|
eventList: GameEventDefinitionMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PacketEntitiesPacket {
|
export interface PacketEntitiesPacket extends BasePacket {
|
||||||
packetType: 'packetEntities';
|
packetType: 'packetEntities';
|
||||||
entities: PacketEntity[];
|
entities: PacketEntity[];
|
||||||
removedEntities: number[];
|
removedEntities: number[];
|
||||||
|
|
@ -83,7 +86,7 @@ export interface PacketEntitiesPacket {
|
||||||
updatedBaseLine: boolean;
|
updatedBaseLine: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ParseSoundsPacket {
|
export interface ParseSoundsPacket extends BasePacket {
|
||||||
packetType: 'parseSounds';
|
packetType: 'parseSounds';
|
||||||
reliable: boolean;
|
reliable: boolean;
|
||||||
num: number;
|
num: number;
|
||||||
|
|
@ -91,17 +94,17 @@ export interface ParseSoundsPacket {
|
||||||
data: BitStream;
|
data: BitStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SetConVarPacket {
|
export interface SetConVarPacket extends BasePacket {
|
||||||
packetType: 'setConVar';
|
packetType: 'setConVar';
|
||||||
vars: { [key: string]: string };
|
vars: {[key: string]: string};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TempEntitiesPacket {
|
export interface TempEntitiesPacket extends BasePacket {
|
||||||
packetType: 'tempEntities';
|
packetType: 'tempEntities';
|
||||||
entities: PacketEntity[];
|
entities: PacketEntity[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SayText2Packet {
|
export interface SayText2Packet extends BasePacket {
|
||||||
packetType: 'sayText2';
|
packetType: 'sayText2';
|
||||||
client: number;
|
client: number;
|
||||||
raw: number;
|
raw: number;
|
||||||
|
|
@ -110,26 +113,26 @@ export interface SayText2Packet {
|
||||||
text: string;
|
text: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TextMessagePacket {
|
export interface TextMessagePacket extends BasePacket {
|
||||||
packetType: 'textMsg';
|
packetType: 'textMsg';
|
||||||
destType: number;
|
destType: number;
|
||||||
text: string;
|
text: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UnknownUserMessagePacket {
|
export interface UnknownUserMessagePacket extends BasePacket {
|
||||||
packetType: 'unknownUserMessage';
|
packetType: 'unknownUserMessage';
|
||||||
type: number;
|
type: number;
|
||||||
data: BitStream;
|
data: BitStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface VoiceInitPacket {
|
export interface VoiceInitPacket extends BasePacket {
|
||||||
packetType: 'voiceInit';
|
packetType: 'voiceInit';
|
||||||
codec: string;
|
codec: string;
|
||||||
quality: number;
|
quality: number;
|
||||||
extraData: number;
|
extraData: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface VoiceDataPacket {
|
export interface VoiceDataPacket extends BasePacket {
|
||||||
packetType: 'voiceData';
|
packetType: 'voiceData';
|
||||||
client: number;
|
client: number;
|
||||||
proximity: number;
|
proximity: number;
|
||||||
|
|
@ -137,19 +140,101 @@ export interface VoiceDataPacket {
|
||||||
data: BitStream;
|
data: BitStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MenuPacket {
|
export interface MenuPacket extends BasePacket {
|
||||||
packetType: 'menu';
|
packetType: 'menu';
|
||||||
type: number;
|
type: number;
|
||||||
length: number;
|
length: number;
|
||||||
data: BitStream;
|
data: BitStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CmdKeyValuesPacket {
|
export interface CmdKeyValuesPacket extends BasePacket {
|
||||||
packetType: 'cmdKeyValues';
|
packetType: 'cmdKeyValues';
|
||||||
length: number;
|
length: number;
|
||||||
data: BitStream;
|
data: BitStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface VoidPacket extends BasePacket {
|
||||||
|
packetType: 'void';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FilePacket extends BasePacket {
|
||||||
|
packetType: 'file';
|
||||||
|
transferId: number;
|
||||||
|
fileName: string;
|
||||||
|
requested: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NetTickPacket extends BasePacket {
|
||||||
|
packetType: 'netTick';
|
||||||
|
tick: number;
|
||||||
|
frameTime: number;
|
||||||
|
stdDev: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StringCmdPacket extends BasePacket {
|
||||||
|
packetType: 'stringCmd';
|
||||||
|
command: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SigOnStatePacket extends BasePacket {
|
||||||
|
packetType: 'sigOnState';
|
||||||
|
state: number;
|
||||||
|
count: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PrintPacket extends BasePacket {
|
||||||
|
packetType: 'print';
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ServerInfoPacket extends BasePacket {
|
||||||
|
packetType: 'serverInfo';
|
||||||
|
version: number;
|
||||||
|
serverCount: number;
|
||||||
|
stv: boolean;
|
||||||
|
dedicated: boolean;
|
||||||
|
maxCrc: number;
|
||||||
|
maxClasses: number;
|
||||||
|
mapHash: number;
|
||||||
|
playerCount: number;
|
||||||
|
maxPlayerCount: number;
|
||||||
|
intervalPerTick: number;
|
||||||
|
platform: string;
|
||||||
|
game: string;
|
||||||
|
skybox: string;
|
||||||
|
serverName: string;
|
||||||
|
replay: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SetPausePacket extends BasePacket {
|
||||||
|
packetType: 'setPause';
|
||||||
|
paused: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SetViewPacket extends BasePacket {
|
||||||
|
packetType: 'setView';
|
||||||
|
index: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FixAnglePacket extends BasePacket {
|
||||||
|
packetType: 'fixAngle';
|
||||||
|
relative: boolean;
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
z: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PreFetchPacket {
|
||||||
|
packetType: 'preFetch';
|
||||||
|
index: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GetCvarValuePacket {
|
||||||
|
packetType: 'getCvarValue';
|
||||||
|
cookie: number;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
export type UserMessagePacket = SayText2Packet | TextMessagePacket | UnknownUserMessagePacket;
|
export type UserMessagePacket = SayText2Packet | TextMessagePacket | UnknownUserMessagePacket;
|
||||||
|
|
||||||
export type Packet = BSPDecalPacket |
|
export type Packet = BSPDecalPacket |
|
||||||
|
|
@ -170,4 +255,46 @@ export type Packet = BSPDecalPacket |
|
||||||
VoiceDataPacket |
|
VoiceDataPacket |
|
||||||
MenuPacket |
|
MenuPacket |
|
||||||
ConsoleCmdPacket |
|
ConsoleCmdPacket |
|
||||||
CmdKeyValuesPacket;
|
CmdKeyValuesPacket |
|
||||||
|
VoidPacket |
|
||||||
|
FilePacket |
|
||||||
|
NetTickPacket |
|
||||||
|
StringCmdPacket |
|
||||||
|
SigOnStatePacket |
|
||||||
|
PrintPacket |
|
||||||
|
ServerInfoPacket |
|
||||||
|
SetPausePacket |
|
||||||
|
SetViewPacket |
|
||||||
|
FixAnglePacket |
|
||||||
|
PreFetchPacket |
|
||||||
|
GetCvarValuePacket;
|
||||||
|
|
||||||
|
export enum PacketType {
|
||||||
|
file = 2,
|
||||||
|
netTick = 3,
|
||||||
|
stringCmd = 4,
|
||||||
|
setConVar = 5,
|
||||||
|
sigOnState = 6,
|
||||||
|
print = 7,
|
||||||
|
serverInfo = 8,
|
||||||
|
classInfo = 10,
|
||||||
|
setPause = 11,
|
||||||
|
createStringTable = 12,
|
||||||
|
updateStringTable = 13,
|
||||||
|
voiceInit = 14,
|
||||||
|
voiceData = 15,
|
||||||
|
parseSounds = 17,
|
||||||
|
setView = 18,
|
||||||
|
fixAngle = 19,
|
||||||
|
bspDecal = 21,
|
||||||
|
userMessage = 23,
|
||||||
|
entityMessage = 24,
|
||||||
|
gameEvent = 25,
|
||||||
|
packetEntities = 26,
|
||||||
|
tempEntities = 27,
|
||||||
|
preFetch = 28,
|
||||||
|
menu = 29,
|
||||||
|
gameEventList = 30,
|
||||||
|
getCvarValue = 31,
|
||||||
|
cmdKeyValues = 32,
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import {BitStream} from 'bit-buffer';
|
import {BitStream} from 'bit-buffer';
|
||||||
import {Parser} from './Parser';
|
import {Parser} from './Parser';
|
||||||
import {PacketType} from './Parser/Message/Packet';
|
|
||||||
import {StreamDemo} from './StreamDemo';
|
import {StreamDemo} from './StreamDemo';
|
||||||
|
import {PacketType} from './Data/Packet';
|
||||||
|
|
||||||
export {StreamDemo} from './StreamDemo';
|
export {StreamDemo} from './StreamDemo';
|
||||||
|
|
||||||
|
|
@ -20,6 +20,7 @@ export class Demo {
|
||||||
}
|
}
|
||||||
|
|
||||||
public stream: BitStream;
|
public stream: BitStream;
|
||||||
|
|
||||||
public parser: Parser | null;
|
public parser: Parser | null;
|
||||||
|
|
||||||
constructor(arrayBuffer: ArrayBuffer) {
|
constructor(arrayBuffer: ArrayBuffer) {
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,11 @@ import {Header} from './Data/Header';
|
||||||
import {Match} from './Data/Match';
|
import {Match} from './Data/Match';
|
||||||
import {ConsoleCmd} from './Parser/Message/ConsoleCmd';
|
import {ConsoleCmd} from './Parser/Message/ConsoleCmd';
|
||||||
import {DataTable} from './Parser/Message/DataTable';
|
import {DataTable} from './Parser/Message/DataTable';
|
||||||
import {Packet, PacketType} from './Parser/Message/Packet';
|
import {Packet} from './Parser/Message/Packet';
|
||||||
import {Parser as MessageParser} from './Parser/Message/Parser';
|
import {Parser as MessageParser} from './Parser/Message/Parser';
|
||||||
import {StringTable} from './Parser/Message/StringTable';
|
import {StringTable} from './Parser/Message/StringTable';
|
||||||
import {UserCmd} from './Parser/Message/UserCmd';
|
import {UserCmd} from './Parser/Message/UserCmd';
|
||||||
|
import {PacketType} from './Data/Packet';
|
||||||
|
|
||||||
export class Parser extends EventEmitter {
|
export class Parser extends EventEmitter {
|
||||||
public stream: BitStream;
|
public stream: BitStream;
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
import {make} from '../Packet/ParserGenerator';
|
import {make} from '../Packet/ParserGenerator';
|
||||||
|
|
||||||
import {EncodeBSPDecal, ParseBSPDecal} from '../Packet/BSPDecal';
|
import {EncodeBSPDecal, ParseBSPDecal} from '../Packet/BSPDecal';
|
||||||
import {EncodeClassInfo, ParseClassInfo} from '../Packet/ClassInfo';
|
import {EncodeClassInfo, ParseClassInfo} from '../Packet/ClassInfo';
|
||||||
import {EncodeCreateStringTable, ParseCreateStringTable} from '../Packet/CreateStringTable';
|
import {EncodeCreateStringTable, ParseCreateStringTable} from '../Packet/CreateStringTable';
|
||||||
import {ParseGameEvent} from '../Packet/GameEvent';
|
import {ParseGameEvent} from '../Packet/GameEvent';
|
||||||
import {EncodeGameEventList, ParseGameEventList} from '../Packet/GameEventList';
|
import {EncodeGameEventList, ParseGameEventList} from '../Packet/GameEventList';
|
||||||
import {ParsePacketEntities} from '../Packet/PacketEntities';
|
import {ParsePacketEntities} from '../Packet/PacketEntities';
|
||||||
import {PacketParserMap, voidEncoder} from '../Packet/Parser';
|
import {PacketHandler, voidEncoder} from '../Packet/Parser';
|
||||||
import {EncodeParseSounds, ParseParseSounds} from '../Packet/ParseSounds';
|
import {EncodeParseSounds, ParseParseSounds} from '../Packet/ParseSounds';
|
||||||
import {EncodeSetConVar, ParseSetConVar} from '../Packet/SetConVar';
|
import {EncodeSetConVar, ParseSetConVar} from '../Packet/SetConVar';
|
||||||
import {ParseTempEntities} from '../Packet/TempEntities';
|
import {ParseTempEntities} from '../Packet/TempEntities';
|
||||||
|
|
@ -16,60 +15,82 @@ import {EncodeVoiceData, ParseVoiceData} from '../Packet/VoiceData';
|
||||||
import {EncodeVoiceInit, ParseVoiceInit} from '../Packet/VoiceInit';
|
import {EncodeVoiceInit, ParseVoiceInit} from '../Packet/VoiceInit';
|
||||||
import {Parser} from './Parser';
|
import {Parser} from './Parser';
|
||||||
|
|
||||||
import {Packet as IPacket} from '../../Data/Packet';
|
import {Packet as IPacket, PacketType} from '../../Data/Packet';
|
||||||
|
|
||||||
// https://code.google.com/p/coldemoplayer/source/browse/branches/2.0/compLexity+Demo+Player/CDP.Source/Messages/?r=219
|
|
||||||
// https://github.com/TimePath/hl2-toolkit/tree/master/src/main/java/com/timepath/hl2/io/demo
|
|
||||||
// https://github.com/stgn/netdecode/blob/master/Packet.cs
|
|
||||||
// https://github.com/LestaD/SourceEngine2007/blob/master/src_main/common/netmessages.cpp
|
|
||||||
|
|
||||||
|
|
||||||
export class Packet extends Parser {
|
export class Packet extends Parser {
|
||||||
private static parsers: PacketParserMap = {
|
private static parsers: Map<PacketType, PacketHandler<IPacket>> = new Map([
|
||||||
2: make('file', 'transferId{32}fileName{s}requested{b}'),
|
[PacketType.file,
|
||||||
3: make('netTick', 'tick{32}frameTime{16}stdDev{16}'),
|
make('file', 'transferId{32}fileName{s}requested{b}')],
|
||||||
4: make('stringCmd', 'command{s}'),
|
[PacketType.netTick,
|
||||||
5: {parser: ParseSetConVar, encoder: EncodeSetConVar},
|
make('netTick', 'tick{32}frameTime{16}stdDev{16}')],
|
||||||
6: make('sigOnState', 'state{8}count{32}'),
|
[PacketType.stringCmd,
|
||||||
7: make('print', 'value{s}'),
|
make('stringCmd', 'command{s}')],
|
||||||
8: make('serverInfo',
|
[PacketType.setConVar,
|
||||||
'version{16}serverCount{32}stv{b}dedicated{b}maxCrc{32}maxClasses{16}' +
|
{parser: ParseSetConVar, encoder: EncodeSetConVar}],
|
||||||
'mapHash{128}playerCount{8}maxPlayerCount{8}intervalPerTick{f32}platform{s1}' +
|
[PacketType.sigOnState,
|
||||||
'game{s}map{s}skybox{s}serverName{s}replay{b}'),
|
make('sigOnState', 'state{8}count{32}')],
|
||||||
10: {parser: ParseClassInfo, encoder: EncodeClassInfo},
|
[PacketType.print,
|
||||||
11: make('setPause', 'paused{b}'),
|
make('print', 'value{s}')],
|
||||||
12: {parser: ParseCreateStringTable, encoder: EncodeCreateStringTable},
|
[PacketType.serverInfo,
|
||||||
13: {parser: ParseUpdateStringTable, encoder: EncodeUpdateStringTable},
|
make('serverInfo',
|
||||||
14: {parser: ParseVoiceInit, encoder: EncodeVoiceInit},
|
'version{16}serverCount{32}stv{b}dedicated{b}maxCrc{32}maxClasses{16}' +
|
||||||
15: {parser: ParseVoiceData, encoder: EncodeVoiceData},
|
'mapHash{128}playerCount{8}maxPlayerCount{8}intervalPerTick{f32}platform{s1}' +
|
||||||
17: {parser: ParseParseSounds, encoder: EncodeParseSounds},
|
'game{s}map{s}skybox{s}serverName{s}replay{b}')],
|
||||||
18: make('setView', 'index{11}'),
|
[PacketType.classInfo,
|
||||||
19: make('fixAngle', 'relative{b}x{16}y{16}z{16}'),
|
{parser: ParseClassInfo, encoder: EncodeClassInfo}],
|
||||||
21: {parser: ParseBSPDecal, encoder: EncodeBSPDecal},
|
[PacketType.setPause,
|
||||||
23: {parser: ParseUserMessage, encoder: voidEncoder},
|
make('setPause', 'paused{b}')],
|
||||||
24: make('entityMessage', 'index{11}classId{9}length{11}data{$length}'),
|
[PacketType.createStringTable,
|
||||||
25: {parser: ParseGameEvent, encoder: voidEncoder},
|
{parser: ParseCreateStringTable, encoder: EncodeCreateStringTable}],
|
||||||
26: {parser: ParsePacketEntities, encoder: voidEncoder},
|
[PacketType.updateStringTable,
|
||||||
27: {parser: ParseTempEntities, encoder: voidEncoder},
|
{parser: ParseUpdateStringTable, encoder: EncodeUpdateStringTable}],
|
||||||
28: make('preFetch', 'index{14}'),
|
[PacketType.voiceInit,
|
||||||
29: make('menu', 'type{u16}length{u16}data{$length*8}'),
|
{parser: ParseVoiceInit, encoder: EncodeVoiceInit}],
|
||||||
30: {parser: ParseGameEventList, encoder: EncodeGameEventList},
|
[PacketType.voiceData,
|
||||||
31: make('getCvarValue', 'cookie{32}value{s}'),
|
{parser: ParseVoiceData, encoder: EncodeVoiceData}],
|
||||||
32: make('cmdKeyValues', 'length{32}data{$length}'),
|
[PacketType.parseSounds,
|
||||||
};
|
{parser: ParseParseSounds, encoder: EncodeParseSounds}],
|
||||||
|
[PacketType.setView,
|
||||||
|
make('setView', 'index{11}')],
|
||||||
|
[PacketType.fixAngle,
|
||||||
|
make('fixAngle', 'relative{b}x{16}y{16}z{16}')],
|
||||||
|
[PacketType.bspDecal,
|
||||||
|
{parser: ParseBSPDecal, encoder: EncodeBSPDecal}],
|
||||||
|
[PacketType.userMessage,
|
||||||
|
{parser: ParseUserMessage, encoder: voidEncoder}],
|
||||||
|
[PacketType.entityMessage,
|
||||||
|
make('entityMessage', 'index{11}classId{9}length{11}data{$length}')],
|
||||||
|
[PacketType.gameEvent,
|
||||||
|
{parser: ParseGameEvent, encoder: voidEncoder}],
|
||||||
|
[PacketType.packetEntities,
|
||||||
|
{parser: ParsePacketEntities, encoder: voidEncoder}],
|
||||||
|
[PacketType.tempEntities,
|
||||||
|
{parser: ParseTempEntities, encoder: voidEncoder}],
|
||||||
|
[PacketType.preFetch,
|
||||||
|
make('preFetch', 'index{14}')],
|
||||||
|
[PacketType.menu,
|
||||||
|
make('menu', 'type{u16}length{u16}data{$length*8}')],
|
||||||
|
[PacketType.gameEventList,
|
||||||
|
{parser: ParseGameEventList, encoder: EncodeGameEventList}],
|
||||||
|
[PacketType.getCvarValue,
|
||||||
|
make('getCvarValue', 'cookie{32}value{s}')],
|
||||||
|
[PacketType.cmdKeyValues,
|
||||||
|
make('cmdKeyValues', 'length{32}data{$length}')],
|
||||||
|
]);
|
||||||
|
|
||||||
public parse() {
|
public parse() {
|
||||||
const packets: IPacket[] = [];
|
const packets: IPacket[] = [];
|
||||||
let lastPacketType = 0;
|
let lastPacketType = 0;
|
||||||
while (this.bitsLeft > 6) { // last 6 bits for NOOP
|
while (this.bitsLeft > 6) { // last 6 bits for NOOP
|
||||||
const type = this.stream.readBits(6);
|
const type = this.stream.readBits(6) as PacketType;
|
||||||
if (type !== 0) {
|
if (type !== 0) {
|
||||||
if (Packet.parsers[type]) {
|
const parser = Packet.parsers.get(type);
|
||||||
|
if (parser) {
|
||||||
const skip = this.skippedPackets.indexOf(type) !== -1;
|
const skip = this.skippedPackets.indexOf(type) !== -1;
|
||||||
const packet = Packet.parsers[type].parser.call(this, this.stream, this.match, skip);
|
const packet = parser.parser(this.stream, this.match, skip);
|
||||||
packets.push(packet);
|
packets.push(packet);
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Unknown packet type ' + type + ' just parsed a ' + PacketType[lastPacketType]);
|
throw new Error(`Unknown packet type ${type} just parsed a ${PacketType[lastPacketType]}`);
|
||||||
}
|
}
|
||||||
lastPacketType = type;
|
lastPacketType = type;
|
||||||
}
|
}
|
||||||
|
|
@ -81,33 +102,3 @@ export class Packet extends Parser {
|
||||||
return (this.length * 8) - this.stream.index;
|
return (this.length * 8) - this.stream.index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum PacketType {
|
|
||||||
file = 2,
|
|
||||||
netTick = 3,
|
|
||||||
stringCmd = 4,
|
|
||||||
setConVar = 5,
|
|
||||||
sigOnState = 6,
|
|
||||||
print = 7,
|
|
||||||
serverInfo = 8,
|
|
||||||
classInfo = 10,
|
|
||||||
setPause = 11,
|
|
||||||
createStringTable = 12,
|
|
||||||
updateStringTable = 13,
|
|
||||||
voiceInit = 14,
|
|
||||||
voiceData = 15,
|
|
||||||
parseSounds = 17,
|
|
||||||
setView = 18,
|
|
||||||
fixAngle = 19,
|
|
||||||
bspDecal = 21,
|
|
||||||
userMessage = 23,
|
|
||||||
entityMessage = 24,
|
|
||||||
gameEvent = 25,
|
|
||||||
packetEntities = 26,
|
|
||||||
tempEntities = 27,
|
|
||||||
preFetch = 28,
|
|
||||||
menu = 29,
|
|
||||||
gameEventList = 30,
|
|
||||||
getCvarValue = 30,
|
|
||||||
cmdKeyValues = 32,
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
import {BitStream} from 'bit-buffer';
|
import {BitStream} from 'bit-buffer';
|
||||||
import {Match} from '../../Data/Match';
|
import {Match} from '../../Data/Match';
|
||||||
import {Packet} from '../../Data/Packet';
|
import {Packet, PacketType} from '../../Data/Packet';
|
||||||
import {MessageType} from '../../Parser';
|
import {MessageType} from '../../Parser';
|
||||||
import {PacketType} from './Packet';
|
|
||||||
|
|
||||||
export abstract class Parser {
|
export abstract class Parser {
|
||||||
protected type: any;
|
protected type: any;
|
||||||
|
|
@ -13,11 +12,11 @@ export abstract class Parser {
|
||||||
protected skippedPackets: PacketType[];
|
protected skippedPackets: PacketType[];
|
||||||
|
|
||||||
constructor(type: MessageType, tick: number, stream: BitStream, length: number, match: Match, skippedPacket: PacketType[] = []) {
|
constructor(type: MessageType, tick: number, stream: BitStream, length: number, match: Match, skippedPacket: PacketType[] = []) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.tick = tick;
|
this.tick = tick;
|
||||||
this.stream = stream;
|
this.stream = stream;
|
||||||
this.length = length; // length in bytes
|
this.length = length; // length in bytes
|
||||||
this.match = match;
|
this.match = match;
|
||||||
this.skippedPackets = skippedPacket;
|
this.skippedPackets = skippedPacket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,17 @@
|
||||||
import {BitStream} from 'bit-buffer';
|
import {BitStream} from 'bit-buffer';
|
||||||
import {Match} from '../../Data/Match';
|
import {Match} from '../../Data/Match';
|
||||||
import {Packet} from '../../Data/Packet';
|
import {Packet, PacketType, VoidPacket} from '../../Data/Packet';
|
||||||
|
|
||||||
export type Parser = (stream: BitStream, match?: Match, skip?: boolean) => Packet;
|
export type Parser<P extends Packet> = (stream: BitStream, match?: Match, skip?: boolean) => P;
|
||||||
export type Encoder = (packet: Packet, stream: BitStream, match?: Match) => void;
|
export type Encoder<P extends Packet> = (packet: P, stream: BitStream, match?: Match) => void;
|
||||||
|
|
||||||
export interface PacketHandler {
|
export interface PacketHandler<P extends Packet> {
|
||||||
parser: Parser,
|
parser: Parser<P>,
|
||||||
encoder: Encoder
|
encoder: Encoder<P>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const voidEncoder: Encoder<VoidPacket> = () => {
|
||||||
export const voidEncoder: Encoder = () => {
|
return {
|
||||||
|
type: 'void'
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface PacketParserMap {
|
|
||||||
[id: number]: PacketHandler;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,34 @@
|
||||||
import {Packet} from '../../Data/Packet';
|
import {Packet} from '../../Data/Packet';
|
||||||
import {PacketHandler} from './Parser';
|
import {Encoder, PacketHandler, Parser} from './Parser';
|
||||||
import {BitStream} from 'bit-buffer';
|
import {BitStream} from 'bit-buffer';
|
||||||
|
|
||||||
export function make(name: string, definition: string): PacketHandler {
|
export function make<P extends Packet>(name: P['packetType'], definition: string): PacketHandler<P> {
|
||||||
const parts = definition.split('}');
|
const parts = definition.split('}');
|
||||||
const items = parts.map((part) => {
|
const items = parts.map((part) => {
|
||||||
return part.split('{');
|
return part.split('{');
|
||||||
}).filter(part => part[0]);
|
}).filter(part => part[0]);
|
||||||
return {
|
const parser: Parser<P> = (stream: BitStream) => {
|
||||||
parser: (stream) => {
|
const result = {
|
||||||
const result = {
|
packetType: name,
|
||||||
packetType: name,
|
};
|
||||||
};
|
try {
|
||||||
try {
|
|
||||||
for (const group of items) {
|
|
||||||
const value = readItem(stream, group[1], result);
|
|
||||||
if (group[0] !== '_') {
|
|
||||||
result[group[0]] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
throw new Error('Failed reading pattern ' + definition + '. ' + e);
|
|
||||||
}
|
|
||||||
return result as Packet;
|
|
||||||
},
|
|
||||||
encoder: (packet, stream) => {
|
|
||||||
for (const group of items) {
|
for (const group of items) {
|
||||||
writeItem(stream, group[1], packet, packet[group[0]]);
|
const value = readItem(stream, group[1], result);
|
||||||
|
if (group[0] !== '_') {
|
||||||
|
result[group[0]] = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error('Failed reading pattern ' + definition + '. ' + e);
|
||||||
|
}
|
||||||
|
return result as P;
|
||||||
|
};
|
||||||
|
const encoder: Encoder<P> = (packet: P, stream: BitStream) => {
|
||||||
|
for (const group of items) {
|
||||||
|
writeItem(stream, group[1], packet, packet[group[0]]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
return {parser, encoder};
|
||||||
}
|
}
|
||||||
|
|
||||||
function readItem(stream: BitStream, description: string, data) {
|
function readItem(stream: BitStream, description: string, data) {
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,14 @@ import {BitStream} from 'bit-buffer';
|
||||||
import {assertEncoder, assertParser, getStream} from './PacketTest';
|
import {assertEncoder, assertParser, getStream} from './PacketTest';
|
||||||
|
|
||||||
function assertGeneratedParser(definition: string, stream: BitStream, expected: any, length: number) {
|
function assertGeneratedParser(definition: string, stream: BitStream, expected: any, length: number) {
|
||||||
expected.packetType = 'packetName';
|
expected.packetType = 'void';
|
||||||
const {parser} = make('packetName', definition);
|
const {parser} = make('void', definition);
|
||||||
return assertParser(parser, stream, expected, length);
|
return assertParser(parser, stream, expected, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
function assertGeneratedEncoder(definition: string, data: any, length: number = 0) {
|
function assertGeneratedEncoder(definition: string, data: any, length: number = 0) {
|
||||||
data.packetType = 'packetName';
|
data.packetType = 'void';
|
||||||
const {parser, encoder} = make('packetName', definition);
|
const {parser, encoder} = make('void', definition);
|
||||||
return assertEncoder(parser, encoder, data, length);
|
return assertEncoder(parser, encoder, data, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,8 @@
|
||||||
"lib": [
|
"lib": [
|
||||||
"dom",
|
"dom",
|
||||||
"es2015.promise",
|
"es2015.promise",
|
||||||
"es5"
|
"es5",
|
||||||
|
"ES2017"
|
||||||
],
|
],
|
||||||
"module": "ES6",
|
"module": "ES6",
|
||||||
"target": "ES5",
|
"target": "ES5",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue