mirror of
https://github.com/demostf/demo.js
synced 2026-06-04 00:54:14 +02:00
move handlers for each packet to their own file
This commit is contained in:
parent
197dbb9fa5
commit
9d5e599f89
13 changed files with 431 additions and 392 deletions
47
handlers/packet/bspDecal.js
Normal file
47
handlers/packet/bspDecal.js
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
var getCoord = function (stream) {
|
||||||
|
var hasInt = !!stream.readBits(1);
|
||||||
|
var hasFract = !!stream.readBits(1);
|
||||||
|
var value = 0;
|
||||||
|
if (hasInt || hasFract) {
|
||||||
|
var sign = !!stream.readBits(1);
|
||||||
|
if (hasInt) {
|
||||||
|
value += stream.readBits(14) + 1;
|
||||||
|
}
|
||||||
|
if (hasFract) {
|
||||||
|
value += stream.readBits(5) * (1 / 32);
|
||||||
|
}
|
||||||
|
if (sign) {
|
||||||
|
value = -value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
var getVecCoord = function (stream) {
|
||||||
|
var hasX = !!stream.readBits(1);
|
||||||
|
var hasY = !!stream.readBits(1);
|
||||||
|
var hasZ = !!stream.readBits(1);
|
||||||
|
return {
|
||||||
|
x: hasX ? getCoord(stream) : 0,
|
||||||
|
y: hasY ? getCoord(stream) : 0,
|
||||||
|
z: hasZ ? getCoord(stream) : 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = function (stream) { // 21: BSPDecal
|
||||||
|
var position = getVecCoord(stream);
|
||||||
|
var textureIndex = stream.readBits(9);
|
||||||
|
if (stream.readBits(1)) {
|
||||||
|
var entIndex = stream.readBits(11);
|
||||||
|
var modelIndex = stream.readBits(12);
|
||||||
|
}
|
||||||
|
var lowPriority = !!stream.readBits(1);
|
||||||
|
return {
|
||||||
|
packetType : 'BSPDecal',
|
||||||
|
position : position,
|
||||||
|
textureIndex: textureIndex,
|
||||||
|
entIndex : entIndex,
|
||||||
|
modelIndex : modelIndex,
|
||||||
|
lowPriority : lowPriority
|
||||||
|
}
|
||||||
|
};
|
||||||
30
handlers/packet/classInfo.js
Normal file
30
handlers/packet/classInfo.js
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
function logBase2(num) {
|
||||||
|
var result = 0;
|
||||||
|
while ((num >>= 1) != 0) {
|
||||||
|
result++;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function (stream) { // 10: classInfo
|
||||||
|
var number = stream.readBits(16);
|
||||||
|
var create = !!stream.readBits(1);
|
||||||
|
var entries = [];
|
||||||
|
if (!create) {
|
||||||
|
var bits = logBase2(number) + 1;
|
||||||
|
for (var i = 0; i < number; i++) {
|
||||||
|
var entry = {
|
||||||
|
'classId' : stream.readBits(bits),
|
||||||
|
'className' : stream.readASCIIString(),
|
||||||
|
'dataTableName': stream.readASCIIString()
|
||||||
|
};
|
||||||
|
entries.push(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
'packetType': 'classInfo',
|
||||||
|
number : number,
|
||||||
|
create : create,
|
||||||
|
entries : entries
|
||||||
|
}
|
||||||
|
};
|
||||||
10
handlers/packet/createStringTable.js
Normal file
10
handlers/packet/createStringTable.js
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
var PacketStringTable = require('../../packetstringtable');
|
||||||
|
|
||||||
|
module.exports = function (stream) { // 12: createStringTable
|
||||||
|
var stringTable = new PacketStringTable(stream);
|
||||||
|
var tables = stringTable.parse();
|
||||||
|
return {
|
||||||
|
packetType: 'createStringTable',
|
||||||
|
table : tables
|
||||||
|
};
|
||||||
|
};
|
||||||
50
handlers/packet/gameEvent.js
Normal file
50
handlers/packet/gameEvent.js
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
var parseGameEvent = function (eventId, stream, events) {
|
||||||
|
if (!events[eventId]) {
|
||||||
|
return 'unknown';
|
||||||
|
}
|
||||||
|
var eventDescription = events[eventId];
|
||||||
|
var values = {};
|
||||||
|
for (var i = 0; i < eventDescription.entries.length; i++) {
|
||||||
|
var entry = eventDescription.entries[i];
|
||||||
|
values[entry.name] = getGameEventValue(stream, entry);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
name : eventDescription.name,
|
||||||
|
type : eventDescription.type,
|
||||||
|
values: values
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
var getGameEventValue = function (stream, entry) {
|
||||||
|
switch (entry.type) {
|
||||||
|
case 1:
|
||||||
|
return stream.readUTF8String();
|
||||||
|
case 2:
|
||||||
|
return stream.readFloat32();
|
||||||
|
case 3:
|
||||||
|
return stream.readInt32();
|
||||||
|
case 4:
|
||||||
|
return stream.readBits(16);
|
||||||
|
case 5:
|
||||||
|
return stream.readBits(8);
|
||||||
|
case 6:
|
||||||
|
return !!stream.readBits(1);
|
||||||
|
case 7:
|
||||||
|
return 'local value';
|
||||||
|
default:
|
||||||
|
throw 'invalid game event type';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = function (stream, events) { // 25: game event
|
||||||
|
var length = stream.readBits(11);
|
||||||
|
var end = stream._index + length;
|
||||||
|
var eventId = stream.readBits(9);
|
||||||
|
var event = parseGameEvent(eventId, stream, events);
|
||||||
|
stream._index = end;
|
||||||
|
return {
|
||||||
|
packetType: 'gameEvent',
|
||||||
|
event : event
|
||||||
|
}
|
||||||
|
};
|
||||||
29
handlers/packet/gameEventList.js
Normal file
29
handlers/packet/gameEventList.js
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
module.exports = function (stream, events) { // 30: gameEventList
|
||||||
|
// list of game events and parameters
|
||||||
|
var numEvents = stream.readBits(9);
|
||||||
|
var length = stream.readBits(20);
|
||||||
|
for (var i = 0; i < numEvents; i++) {
|
||||||
|
var id = stream.readBits(9);
|
||||||
|
var name = stream.readASCIIString();
|
||||||
|
var type = stream.readBits(3);
|
||||||
|
var entries = [];
|
||||||
|
while (type !== 0) {
|
||||||
|
var entryName = stream.readASCIIString();
|
||||||
|
entries.push({
|
||||||
|
type: type,
|
||||||
|
name: entryName
|
||||||
|
});
|
||||||
|
type = stream.readBits(3);
|
||||||
|
}
|
||||||
|
events[id] = {
|
||||||
|
id : id,
|
||||||
|
name : name,
|
||||||
|
type : type,
|
||||||
|
entries: entries
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
packetType: 'gameEventList',
|
||||||
|
events : events
|
||||||
|
}
|
||||||
|
};
|
||||||
81
handlers/packet/packetEntities.js
Normal file
81
handlers/packet/packetEntities.js
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
var PVS = {
|
||||||
|
PRESERVE: 0,
|
||||||
|
ENTER : 1,
|
||||||
|
LEAVE : 2,
|
||||||
|
DELETE : 3
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function readIndex(stream, baseIndex) {
|
||||||
|
// https://github.com/skadistats/smoke/blob/a2954fbe2fa3936d64aee5b5567be294fef228e6/smoke/io/stream/entity.pyx#L15
|
||||||
|
var encodedIndex = stream.readBits(6);
|
||||||
|
if (encodedIndex & 0x30) {
|
||||||
|
var a = (encodedIndex >> 4) & 3;
|
||||||
|
var b = (a == 3) ? 16 : 0;
|
||||||
|
var i = stream.readBits(4 * a + b) << 4;
|
||||||
|
encodedIndex = i | (encodedIndex & 0x0f);
|
||||||
|
}
|
||||||
|
return baseIndex + encodedIndex + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function readPVS(stream) {
|
||||||
|
// https://github.com/skadistats/smoke/blob/a2954fbe2fa3936d64aee5b5567be294fef228e6/smoke/io/stream/entity.pyx#L24
|
||||||
|
var pvs;
|
||||||
|
var hi = stream.readBoolean();
|
||||||
|
var low = stream.readBoolean();
|
||||||
|
if (low && !hi) {
|
||||||
|
pvs = PVS.ENTER;
|
||||||
|
} else if (!(hi || low)) {
|
||||||
|
pvs = PVS.PRESERVE;
|
||||||
|
} else if (hi) {
|
||||||
|
pvs = (low) ? (PVS.LEAVE | PVS.DELETE) : PVS.LEAVE;
|
||||||
|
} else {
|
||||||
|
pvs = -1;
|
||||||
|
}
|
||||||
|
return pvs;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function (stream) { //26: packetEntities
|
||||||
|
// todo
|
||||||
|
var maxEntries = stream.readBits(11);
|
||||||
|
var isDelta = !!stream.readBits(1);
|
||||||
|
if (isDelta) {
|
||||||
|
var delta = stream.readInt32();
|
||||||
|
} else {
|
||||||
|
delta = null;
|
||||||
|
}
|
||||||
|
var baseLink = !!stream.readBits(1);
|
||||||
|
var updatedEntries = stream.readBits(11);
|
||||||
|
var length = stream.readBits(20);
|
||||||
|
var updatedBaseLink = !!stream.readBits(1);
|
||||||
|
var end = stream._index + length;
|
||||||
|
var entities = [];
|
||||||
|
//console.log('max: ' + maxEntries);
|
||||||
|
//var entityId = -1;
|
||||||
|
//
|
||||||
|
//for (var i = 0; i < updatedEntries; i++) {
|
||||||
|
// entityId = readIndex(stream, entityId);
|
||||||
|
// var pvs = readPVS(stream);
|
||||||
|
// if (pvs = PVS.PRESERVE) {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
stream._index = end;
|
||||||
|
//var ent = {
|
||||||
|
// packetType : 'packetEntities',
|
||||||
|
// maxEntries : maxEntries,
|
||||||
|
// isDelta : isDelta,
|
||||||
|
// delta : delta,
|
||||||
|
// baseLink : baseLink,
|
||||||
|
// updatedEntries : updatedEntries,
|
||||||
|
// length : length,
|
||||||
|
// updatedBaseLink: updatedBaseLink
|
||||||
|
//};
|
||||||
|
//console.log(ent);
|
||||||
|
//console.log(entities);
|
||||||
|
//process.exit();
|
||||||
|
return {
|
||||||
|
packetType: 'packetEntities',
|
||||||
|
entities : entities
|
||||||
|
};
|
||||||
|
}
|
||||||
12
handlers/packet/parseSounds.js
Normal file
12
handlers/packet/parseSounds.js
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
module.exports = function (stream) { // 17: parseSounds
|
||||||
|
var reliable = !!stream.readBits(1);
|
||||||
|
var num = (reliable) ? 1 : stream.readBits(8);
|
||||||
|
var length = (reliable) ? stream.readBits(8) : stream.readBits(16);
|
||||||
|
stream._index += length;
|
||||||
|
return {
|
||||||
|
packetType: 'parseSounds',
|
||||||
|
reliable : reliable,
|
||||||
|
num : num,
|
||||||
|
length : length
|
||||||
|
}
|
||||||
|
};
|
||||||
11
handlers/packet/setConVar.js
Normal file
11
handlers/packet/setConVar.js
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
module.exports= function (stream) { // 5: setconvar
|
||||||
|
var count = stream.readBits(8);
|
||||||
|
var vars = {};
|
||||||
|
for (var i = 0; i < count; i++) {
|
||||||
|
vars[stream.readUTF8String()] = stream.readUTF8String();
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
packetType: 'setConVar',
|
||||||
|
vars : vars
|
||||||
|
}
|
||||||
|
};
|
||||||
10
handlers/packet/updateStringTable.js
Normal file
10
handlers/packet/updateStringTable.js
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
var PacketStringTable = require('../../packetstringtable');
|
||||||
|
|
||||||
|
module.exports = function (stream) { // 12: updateStringTable
|
||||||
|
var stringTable = new PacketStringTable(stream);
|
||||||
|
var tables = stringTable.parse();
|
||||||
|
return {
|
||||||
|
packetType: 'updateStringTable',
|
||||||
|
table : tables
|
||||||
|
};
|
||||||
|
};
|
||||||
83
handlers/packet/userMessage.js
Normal file
83
handlers/packet/userMessage.js
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
var ParserGenerator = require('../../parsergenerator');
|
||||||
|
|
||||||
|
var userMessageParsers = {
|
||||||
|
4: require('../userMessage/SayText2'),
|
||||||
|
5: ParserGenerator.make('textMsg', 'destType{8}text{s}')
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = function (stream) { // 23: user message
|
||||||
|
var type = stream.readBits(8);
|
||||||
|
var length = stream.readBits(11);
|
||||||
|
var pos = stream._index;
|
||||||
|
if (userMessageParsers[type]) {
|
||||||
|
var result = userMessageParsers[type](stream);
|
||||||
|
} else {
|
||||||
|
result = {
|
||||||
|
packetType: 'unknownUserMessage',
|
||||||
|
type : type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stream._index = pos + length;
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
var UserMessageType = {
|
||||||
|
Geiger : 0,
|
||||||
|
Train : 1,
|
||||||
|
HudText : 2,
|
||||||
|
SayText : 3,
|
||||||
|
SayText2 : 4,
|
||||||
|
TextMsg : 5,
|
||||||
|
ResetHUD : 6,
|
||||||
|
GameTitle : 7,
|
||||||
|
ItemPickup : 8,
|
||||||
|
ShowMenu : 9,
|
||||||
|
Shake : 10,
|
||||||
|
Fade : 11,
|
||||||
|
VGUIMenu : 12,
|
||||||
|
Rumble : 13,
|
||||||
|
CloseCaption : 14,
|
||||||
|
SendAudio : 15,
|
||||||
|
VoiceMask : 16,
|
||||||
|
RequestState : 17,
|
||||||
|
Damage : 18,
|
||||||
|
HintText : 19,
|
||||||
|
KeyHintText : 20,
|
||||||
|
HudMsg : 21,
|
||||||
|
AmmoDenied : 22,
|
||||||
|
AchievementEvent : 23,
|
||||||
|
UpdateRadar : 24,
|
||||||
|
VoiceSubtitle : 25,
|
||||||
|
HudNotify : 26,
|
||||||
|
HudNotifyCustom : 27,
|
||||||
|
PlayerStatsUpdate : 28,
|
||||||
|
PlayerIgnited : 29,
|
||||||
|
PlayerIgnitedInv : 30,
|
||||||
|
HudArenaNotify : 31,
|
||||||
|
UpdateAchievement : 32,
|
||||||
|
TrainingMsg : 33,
|
||||||
|
TrainingObjective : 34,
|
||||||
|
DamageDodged : 35,
|
||||||
|
PlayerJarated : 36,
|
||||||
|
PlayerExtinguished : 37,
|
||||||
|
PlayerJaratedFade : 38,
|
||||||
|
PlayerShieldBlocked: 39,
|
||||||
|
BreakModel : 40,
|
||||||
|
CheapBreakModel : 41,
|
||||||
|
BreakModel_Pumpkin : 42,
|
||||||
|
BreakModelRocketDud: 43,
|
||||||
|
CallVoteFailed : 44,
|
||||||
|
VoteStart : 45,
|
||||||
|
VotePass : 46,
|
||||||
|
VoteFailed : 47,
|
||||||
|
VoteSetup : 48,
|
||||||
|
PlayerBonusPoints : 49,
|
||||||
|
SpawnFlyingBird : 50,
|
||||||
|
PlayerGodRayEffect : 51,
|
||||||
|
SPHapWeapEvent : 52,
|
||||||
|
HapDmg : 53,
|
||||||
|
HapPunch : 54,
|
||||||
|
HapSetDrag : 55,
|
||||||
|
HapSet : 56,
|
||||||
|
HapMeleeContact : 57
|
||||||
|
};
|
||||||
44
handlers/userMessage/SayText2.js
Normal file
44
handlers/userMessage/SayText2.js
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
module.exports = function (stream) { // 4: SayText2
|
||||||
|
var client = stream.readBits(8);
|
||||||
|
var raw = stream.readBits(8);
|
||||||
|
var pos = stream._index;
|
||||||
|
var from, text, kind, arg1, arg2;
|
||||||
|
if (stream.readBits(8) === 1) {
|
||||||
|
var first = stream.readBits(8);
|
||||||
|
if (first === 7) {
|
||||||
|
var color = stream.readUTF8String(6);
|
||||||
|
} else {
|
||||||
|
stream._index = pos + 8;
|
||||||
|
}
|
||||||
|
text = stream.readUTF8String();
|
||||||
|
if (text.substr(0, 6) === '*DEAD*') {
|
||||||
|
// grave talk is in the format '*DEAD* \u0003$from\u0001: $text'
|
||||||
|
var start = text.indexOf('\u0003');
|
||||||
|
var end = text.indexOf('\u0001');
|
||||||
|
from = text.substr(start + 1, end - start - 1);
|
||||||
|
text = text.substr(end + 5);
|
||||||
|
kind = 'TF_Chat_AllDead';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
stream._index = pos;
|
||||||
|
kind = stream.readUTF8String();
|
||||||
|
from = stream.readUTF8String();
|
||||||
|
text = stream.readUTF8String();
|
||||||
|
stream.readASCIIString();
|
||||||
|
stream.readASCIIString();
|
||||||
|
}
|
||||||
|
// cleanup color codes
|
||||||
|
text = text.replace(/\u0001/g, '');
|
||||||
|
text = text.replace(/\u0003/g, '');
|
||||||
|
while ((pos = text.indexOf('\u0007')) !== -1) {
|
||||||
|
text = text.slice(0, pos) + text.slice(pos + 7);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
packetType: 'sayText2',
|
||||||
|
client : client,
|
||||||
|
raw : raw,
|
||||||
|
kind : kind,
|
||||||
|
from : from,
|
||||||
|
text : text
|
||||||
|
}
|
||||||
|
};
|
||||||
23
package.json
23
package.json
|
|
@ -1,13 +1,14 @@
|
||||||
{
|
{
|
||||||
"name": "tf2-demo",
|
"name": "tf2-demo",
|
||||||
"description": "A parser for TF2 demo files",
|
"description": "A parser for TF2 demo files",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"bin": {
|
"bin": {
|
||||||
"demo-analyse": "./bin/analyse.js"
|
"demo-analyse": "./bin/analyse.js"
|
||||||
},
|
},
|
||||||
"main": "demo.js",
|
"main": "demo.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bit-buffer": "icewind1991/bit-buffer",
|
"bit-buffer": "icewind1991/bit-buffer",
|
||||||
"minimist": "1.1.x"
|
"buffertools": "^2.1.2",
|
||||||
}
|
"minimist": "1.1.x"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
393
packet.js
393
packet.js
|
|
@ -1,20 +1,10 @@
|
||||||
var ParserGenerator = require('./parsergenerator');
|
var ParserGenerator = require('./parsergenerator');
|
||||||
var StringTable = require('./stringtable');
|
|
||||||
var PacketStringTable = require('./packetstringtable');
|
|
||||||
|
|
||||||
// https://code.google.com/p/coldemoplayer/source/browse/branches/2.0/compLexity+Demo+Player/CDP.Source/Messages/?r=219
|
// 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/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/stgn/netdecode/blob/master/Packet.cs
|
||||||
// https://github.com/LestaD/SourceEngine2007/blob/master/src_main/common/netmessages.cpp
|
// https://github.com/LestaD/SourceEngine2007/blob/master/src_main/common/netmessages.cpp
|
||||||
|
|
||||||
function logBase2(num) {
|
|
||||||
var result = 0;
|
|
||||||
while ((num >>= 1) != 0) {
|
|
||||||
result++;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
var Packet = function (type, tick, stream, length) {
|
var Packet = function (type, tick, stream, length) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.tick = tick;
|
this.tick = tick;
|
||||||
|
|
@ -39,7 +29,7 @@ Packet.prototype.parse = function () {
|
||||||
while (this.bitsLeft > 6) { // last 6 bits for NOOP
|
while (this.bitsLeft > 6) { // last 6 bits for NOOP
|
||||||
var type = this.stream.readBits(6);
|
var type = this.stream.readBits(6);
|
||||||
if (Packet.parsers[type]) {
|
if (Packet.parsers[type]) {
|
||||||
var packet = Packet.parsers[type].call(this, this.stream);
|
var packet = Packet.parsers[type].call(this, this.stream, Packet.gameEventMap);
|
||||||
//console.log(packet);
|
//console.log(packet);
|
||||||
packets.push(packet);
|
packets.push(packet);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -49,398 +39,39 @@ Packet.prototype.parse = function () {
|
||||||
return packets;
|
return packets;
|
||||||
};
|
};
|
||||||
|
|
||||||
Packet.parseGameEvent = function (eventId, stream) {
|
|
||||||
if (!Packet.gameEventMap[eventId]) {
|
|
||||||
return 'unknown';
|
|
||||||
}
|
|
||||||
var eventDescription = this.gameEventMap[eventId];
|
|
||||||
var values = {};
|
|
||||||
for (var i = 0; i < eventDescription.entries.length; i++) {
|
|
||||||
var entry = eventDescription.entries[i];
|
|
||||||
values[entry.name] = Packet.getGameEventValue(stream, entry);
|
|
||||||
}
|
|
||||||
//console.log(eventDescription.name);
|
|
||||||
return {
|
|
||||||
name : eventDescription.name,
|
|
||||||
type : eventDescription.type,
|
|
||||||
values: values
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
Packet.getGameEventValue = function (stream, entry) {
|
|
||||||
switch (entry.type) {
|
|
||||||
case 1:
|
|
||||||
return stream.readUTF8String();
|
|
||||||
case 2:
|
|
||||||
return stream.readFloat32();
|
|
||||||
case 3:
|
|
||||||
return stream.readInt32();
|
|
||||||
case 4:
|
|
||||||
return stream.readBits(16);
|
|
||||||
case 5:
|
|
||||||
return stream.readBits(8);
|
|
||||||
case 6:
|
|
||||||
return !!stream.readBits(1);
|
|
||||||
case 7:
|
|
||||||
return 'local value';
|
|
||||||
default:
|
|
||||||
throw 'invalid game event type';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Packet.parsers = {
|
Packet.parsers = {
|
||||||
0 : function () {
|
0 : function () {//NOOP
|
||||||
},
|
},
|
||||||
2 : ParserGenerator.make('file', 'transferId{32}fileName{s}requested{b}'),
|
2 : ParserGenerator.make('file', 'transferId{32}fileName{s}requested{b}'),
|
||||||
3 : ParserGenerator.make('netTick', 'tick{32}frameTime{16}stdDev{16}'),
|
3 : ParserGenerator.make('netTick', 'tick{32}frameTime{16}stdDev{16}'),
|
||||||
4 : ParserGenerator.make('stringCmd', 'command{s}'),
|
4 : ParserGenerator.make('stringCmd', 'command{s}'),
|
||||||
5 : function (stream) { // setconvar
|
5 : require('./handlers/packet/setConVar'),
|
||||||
var count = stream.readBits(8);
|
|
||||||
var vars = {};
|
|
||||||
for (var i = 0; i < count; i++) {
|
|
||||||
vars[stream.readUTF8String()] = stream.readUTF8String();
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
packetType: 'setConVar',
|
|
||||||
vars : vars
|
|
||||||
}
|
|
||||||
},
|
|
||||||
6 : ParserGenerator.make('sigOnState', 'state{8}count{32}'),
|
6 : ParserGenerator.make('sigOnState', 'state{8}count{32}'),
|
||||||
7 : ParserGenerator.make('print', 'value{s}'),
|
7 : ParserGenerator.make('print', 'value{s}'),
|
||||||
8 : ParserGenerator.make('serverInfo',
|
8 : ParserGenerator.make('serverInfo',
|
||||||
'version{16}serverCount{32}stv{b}dedicated{b}maxCrc{32}maxClasses{16}' +
|
'version{16}serverCount{32}stv{b}dedicated{b}maxCrc{32}maxClasses{16}' +
|
||||||
'mapHash{128}playerCount{8}maxPlayerCount{8}intervalPerTick{f32}platform{s1}' +
|
'mapHash{128}playerCount{8}maxPlayerCount{8}intervalPerTick{f32}platform{s1}' +
|
||||||
'game{s}map{s}skybox{s}serverName{s}replay{b}'),
|
'game{s}map{s}skybox{s}serverName{s}replay{b}'),
|
||||||
10: function (stream) { //classInfo
|
10: require('./handlers/packet/classInfo'),
|
||||||
var number = stream.readBits(16);
|
|
||||||
var create = !!stream.readBits(1);
|
|
||||||
var entries = [];
|
|
||||||
if (!create) {
|
|
||||||
var bits = logBase2(number) + 1;
|
|
||||||
for (var i = 0; i < number; i++) {
|
|
||||||
var entry = {
|
|
||||||
'classId' : stream.readBits(bits),
|
|
||||||
'className' : stream.readASCIIString(),
|
|
||||||
'dataTableName': stream.readASCIIString()
|
|
||||||
};
|
|
||||||
entries.push(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
'packetType': 'classInfo',
|
|
||||||
number : number,
|
|
||||||
create : create,
|
|
||||||
entries : entries
|
|
||||||
}
|
|
||||||
},
|
|
||||||
11: ParserGenerator.make('setPause', 'paused{b}'),
|
11: ParserGenerator.make('setPause', 'paused{b}'),
|
||||||
12: function (stream) {
|
12: require('./handlers/packet/createStringTable'),
|
||||||
var stringTable = new PacketStringTable(stream);
|
13: require('./handlers/packet/updateStringTable'),
|
||||||
var tables = stringTable.parse();
|
|
||||||
return {
|
|
||||||
packetType: 'createStringTable',
|
|
||||||
table : tables
|
|
||||||
};
|
|
||||||
},
|
|
||||||
13: function (stream) { //updatestringTable
|
|
||||||
var stringTable = new PacketStringTable(stream);
|
|
||||||
var tables = stringTable.parse();
|
|
||||||
return {
|
|
||||||
packetType: 'updateStringTable',
|
|
||||||
table : tables
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
var tableId = stream.readBits(5);
|
|
||||||
var changeEntries = stream.readBits(1) ? stream.readBits(16) : 1;
|
|
||||||
var length = stream.readBits(20);
|
|
||||||
var end = stream._index + length;
|
|
||||||
stream.readBits(7);
|
|
||||||
var strings = {};
|
|
||||||
//var table = StringTable.tables[tableId];
|
|
||||||
|
|
||||||
// no idea why but it mostly works
|
|
||||||
var a = stream.readBits(1);
|
|
||||||
var b = stream.readBits(1);
|
|
||||||
if (a && !b) {
|
|
||||||
stream.readBits(12);
|
|
||||||
} else if (!b) {
|
|
||||||
stream.readBits(16);
|
|
||||||
} else {
|
|
||||||
stream.readBits(6);
|
|
||||||
}
|
|
||||||
stream._index = end;
|
|
||||||
//throw false;
|
|
||||||
return {
|
|
||||||
packetType : 'updateStringTables',
|
|
||||||
tableId : tableId,
|
|
||||||
changedEntries: changeEntries,
|
|
||||||
length : length,
|
|
||||||
strings : strings
|
|
||||||
}
|
|
||||||
},
|
|
||||||
14: ParserGenerator.make('voiceInit', 'codec{s}quality{8}'),
|
14: ParserGenerator.make('voiceInit', 'codec{s}quality{8}'),
|
||||||
15: ParserGenerator.make('voiceData', 'client{8}proximity{8}length{16}_{$length}'),
|
15: ParserGenerator.make('voiceData', 'client{8}proximity{8}length{16}_{$length}'),
|
||||||
17: function (stream) { //parseSounds
|
17: require('./handlers/packet/parseSounds'),
|
||||||
var reliable = !!stream.readBits(1);
|
|
||||||
var num = (reliable) ? 1 : stream.readBits(8);
|
|
||||||
var length = (reliable) ? stream.readBits(8) : stream.readBits(16);
|
|
||||||
stream._index += length;
|
|
||||||
return {
|
|
||||||
packetType: 'parseSounds',
|
|
||||||
reliable : reliable,
|
|
||||||
num : num,
|
|
||||||
length : length
|
|
||||||
}
|
|
||||||
},
|
|
||||||
18: ParserGenerator.make('setView', 'index{11}'),
|
18: ParserGenerator.make('setView', 'index{11}'),
|
||||||
19: ParserGenerator.make('fixAngle', 'relative{b}x{16}y{16}z{16}'),
|
19: ParserGenerator.make('fixAngle', 'relative{b}x{16}y{16}z{16}'),
|
||||||
21: function (stream) { //BSPDecal
|
21: require('./handlers/packet/bspDecal'),
|
||||||
var getCoord = function (stream) {
|
23: require('./handlers/packet/userMessage'),
|
||||||
var hasInt = !!stream.readBits(1);
|
|
||||||
var hasFract = !!stream.readBits(1);
|
|
||||||
var value = 0;
|
|
||||||
if (hasInt || hasFract) {
|
|
||||||
var sign = !!stream.readBits(1);
|
|
||||||
if (hasInt) {
|
|
||||||
value += stream.readBits(14) + 1;
|
|
||||||
}
|
|
||||||
if (hasFract) {
|
|
||||||
value += stream.readBits(5) * (1 / 32);
|
|
||||||
}
|
|
||||||
if (sign) {
|
|
||||||
value = -value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
};
|
|
||||||
var getVecCoord = function (stream) {
|
|
||||||
var hasX = !!stream.readBits(1);
|
|
||||||
var hasY = !!stream.readBits(1);
|
|
||||||
var hasZ = !!stream.readBits(1);
|
|
||||||
return {
|
|
||||||
x: hasX ? getCoord(stream) : 0,
|
|
||||||
y: hasY ? getCoord(stream) : 0,
|
|
||||||
z: hasZ ? getCoord(stream) : 0
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var position = getVecCoord(stream);
|
|
||||||
var textureIndex = stream.readBits(9);
|
|
||||||
if (stream.readBits(1)) {
|
|
||||||
var entIndex = stream.readBits(11);
|
|
||||||
var modelIndex = stream.readBits(12);
|
|
||||||
}
|
|
||||||
var lowPriority = !!stream.readBits(1);
|
|
||||||
return {
|
|
||||||
packetType : 'BSPDecal',
|
|
||||||
position : position,
|
|
||||||
textureIndex: textureIndex,
|
|
||||||
entIndex : entIndex,
|
|
||||||
modelIndex : modelIndex,
|
|
||||||
lowPriority : lowPriority
|
|
||||||
}
|
|
||||||
},
|
|
||||||
23: function (stream) { // user message
|
|
||||||
// user message
|
|
||||||
var type = stream.readBits(8);
|
|
||||||
var length = stream.readBits(11);
|
|
||||||
var pos = stream._index;
|
|
||||||
if (Packet.userMessageParsers[type]) {
|
|
||||||
var result = Packet.userMessageParsers[type](stream);
|
|
||||||
} else {
|
|
||||||
result = {
|
|
||||||
packetType: 'unknownUserMessage',
|
|
||||||
type : type
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//console.log(result);
|
|
||||||
//console.log(((pos + length) - stream._index) + ' bits left');
|
|
||||||
stream._index = pos + length;
|
|
||||||
return result;
|
|
||||||
},
|
|
||||||
24: ParserGenerator.make('entityMessage', 'index{11}id{9}length{11}data{$length}'),
|
24: ParserGenerator.make('entityMessage', 'index{11}id{9}length{11}data{$length}'),
|
||||||
25: function (stream) { //game event
|
25: require('./handlers/packet/gameEvent'),
|
||||||
var length = stream.readBits(11);
|
26: require('./handlers/packet/packetEntities'),
|
||||||
var end = stream._index + length;
|
|
||||||
var eventId = stream.readBits(9);
|
|
||||||
var event = Packet.parseGameEvent(eventId, stream);
|
|
||||||
stream._index = end;
|
|
||||||
return {
|
|
||||||
packetType: 'gameEvent',
|
|
||||||
event : event
|
|
||||||
}
|
|
||||||
},
|
|
||||||
26: function (stream) { //packetEntities
|
|
||||||
// todo
|
|
||||||
var maxEntries = stream.readBits(11);
|
|
||||||
var isDelta = !!stream.readBits(1);
|
|
||||||
if (isDelta) {
|
|
||||||
var delta = stream.readInt32();
|
|
||||||
} else {
|
|
||||||
delta = null;
|
|
||||||
}
|
|
||||||
var baseLink = !!stream.readBits(1);
|
|
||||||
var updatedEntries = stream.readBits(11);
|
|
||||||
var length = stream.readBits(20);
|
|
||||||
var updatedBaseLink = !!stream.readBits(1);
|
|
||||||
stream._index += length;
|
|
||||||
return {
|
|
||||||
packetType : 'packetEntities',
|
|
||||||
maxEntries : maxEntries,
|
|
||||||
isDelta : isDelta,
|
|
||||||
delta : delta,
|
|
||||||
baseLink : baseLink,
|
|
||||||
updatedEntries : updatedEntries,
|
|
||||||
length : length,
|
|
||||||
updatedBaseLink: updatedBaseLink
|
|
||||||
}
|
|
||||||
},
|
|
||||||
27: ParserGenerator.make('tempEntities', 'count{8}length{17}_{$length}'),
|
27: ParserGenerator.make('tempEntities', 'count{8}length{17}_{$length}'),
|
||||||
28: ParserGenerator.make('preFetch', 'index{14}'),
|
28: ParserGenerator.make('preFetch', 'index{14}'),
|
||||||
29: ParserGenerator.make('menu', 'type{16}length{16}_{$length}_{$length}_{$length}_{$length}_{$length}_{$length}_{$length}'),//length*8
|
29: ParserGenerator.make('menu', 'type{16}length{16}_{$length}_{$length}_{$length}_{$length}_{$length}_{$length}_{$length}'),//length*8
|
||||||
30: function (stream) { //gameEventList
|
30: require('./handlers/packet/gameEventList'),
|
||||||
// list of game events and parameters
|
|
||||||
var numEvents = stream.readBits(9);
|
|
||||||
var length = stream.readBits(20);
|
|
||||||
var events = {};
|
|
||||||
for (var i = 0; i < numEvents; i++) {
|
|
||||||
var id = stream.readBits(9);
|
|
||||||
var name = stream.readASCIIString();
|
|
||||||
var type = stream.readBits(3);
|
|
||||||
var entries = [];
|
|
||||||
while (type !== 0) {
|
|
||||||
var entryName = stream.readASCIIString();
|
|
||||||
entries.push({
|
|
||||||
type: type,
|
|
||||||
name: entryName
|
|
||||||
});
|
|
||||||
type = stream.readBits(3);
|
|
||||||
}
|
|
||||||
events[id] = {
|
|
||||||
id : id,
|
|
||||||
name : name,
|
|
||||||
type : type,
|
|
||||||
entries: entries
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Packet.gameEventMap = events;
|
|
||||||
return {
|
|
||||||
packetType: 'gameEventList',
|
|
||||||
events : events
|
|
||||||
}
|
|
||||||
},
|
|
||||||
31: ParserGenerator.make('getCvarValue', 'cookie{32}value{s}'),
|
31: ParserGenerator.make('getCvarValue', 'cookie{32}value{s}'),
|
||||||
32: ParserGenerator.make('cmdKeyValues', 'length{32}data{$length}')
|
32: ParserGenerator.make('cmdKeyValues', 'length{32}data{$length}')
|
||||||
};
|
};
|
||||||
|
|
||||||
Packet.userMessageParsers = {
|
|
||||||
4: function (stream) {
|
|
||||||
var client = stream.readBits(8);
|
|
||||||
var raw = stream.readBits(8);
|
|
||||||
var pos = stream._index;
|
|
||||||
var from, text, kind, arg1, arg2;
|
|
||||||
if (stream.readBits(8) === 1) {
|
|
||||||
var first = stream.readBits(8);
|
|
||||||
if (first === 7) {
|
|
||||||
var color = stream.readUTF8String(6);
|
|
||||||
} else {
|
|
||||||
stream._index = pos + 8;
|
|
||||||
}
|
|
||||||
text = stream.readUTF8String();
|
|
||||||
if (text.substr(0, 6) === '*DEAD*') {
|
|
||||||
// grave talk is in the format '*DEAD* \u0003$from\u0001: $text'
|
|
||||||
var start = text.indexOf('\u0003');
|
|
||||||
var end = text.indexOf('\u0001');
|
|
||||||
from = text.substr(start + 1, end - start - 1);
|
|
||||||
text = text.substr(end + 5);
|
|
||||||
kind = 'TF_Chat_AllDead';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
stream._index = pos;
|
|
||||||
kind = stream.readUTF8String();
|
|
||||||
from = stream.readUTF8String();
|
|
||||||
text = stream.readUTF8String();
|
|
||||||
stream.readASCIIString();
|
|
||||||
stream.readASCIIString();
|
|
||||||
}
|
|
||||||
// cleanup color codes
|
|
||||||
text = text.replace(/\u0001/g, '');
|
|
||||||
text = text.replace(/\u0003/g, '');
|
|
||||||
while ((pos = text.indexOf('\u0007')) !== -1) {
|
|
||||||
text = text.slice(0, pos) + text.slice(pos + 7);
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
packetType: 'sayText2',
|
|
||||||
client : client,
|
|
||||||
raw : raw,
|
|
||||||
kind : kind,
|
|
||||||
from : from,
|
|
||||||
text : text
|
|
||||||
}
|
|
||||||
},
|
|
||||||
//4: ParserGenerator.make('sayText2', 'client{8}raw{8}kind{s}from{s}text{s}arg1{s}arg2{s}'),
|
|
||||||
5: ParserGenerator.make('textMsg', 'destType{8}text{s}')
|
|
||||||
};
|
|
||||||
|
|
||||||
var UserMessageType = {
|
|
||||||
Geiger : 0,
|
|
||||||
Train : 1,
|
|
||||||
HudText : 2,
|
|
||||||
SayText : 3,
|
|
||||||
SayText2 : 4,
|
|
||||||
TextMsg : 5,
|
|
||||||
ResetHUD : 6,
|
|
||||||
GameTitle : 7,
|
|
||||||
ItemPickup : 8,
|
|
||||||
ShowMenu : 9,
|
|
||||||
Shake : 10,
|
|
||||||
Fade : 11,
|
|
||||||
VGUIMenu : 12,
|
|
||||||
Rumble : 13,
|
|
||||||
CloseCaption : 14,
|
|
||||||
SendAudio : 15,
|
|
||||||
VoiceMask : 16,
|
|
||||||
RequestState : 17,
|
|
||||||
Damage : 18,
|
|
||||||
HintText : 19,
|
|
||||||
KeyHintText : 20,
|
|
||||||
HudMsg : 21,
|
|
||||||
AmmoDenied : 22,
|
|
||||||
AchievementEvent : 23,
|
|
||||||
UpdateRadar : 24,
|
|
||||||
VoiceSubtitle : 25,
|
|
||||||
HudNotify : 26,
|
|
||||||
HudNotifyCustom : 27,
|
|
||||||
PlayerStatsUpdate : 28,
|
|
||||||
PlayerIgnited : 29,
|
|
||||||
PlayerIgnitedInv : 30,
|
|
||||||
HudArenaNotify : 31,
|
|
||||||
UpdateAchievement : 32,
|
|
||||||
TrainingMsg : 33,
|
|
||||||
TrainingObjective : 34,
|
|
||||||
DamageDodged : 35,
|
|
||||||
PlayerJarated : 36,
|
|
||||||
PlayerExtinguished : 37,
|
|
||||||
PlayerJaratedFade : 38,
|
|
||||||
PlayerShieldBlocked: 39,
|
|
||||||
BreakModel : 40,
|
|
||||||
CheapBreakModel : 41,
|
|
||||||
BreakModel_Pumpkin : 42,
|
|
||||||
BreakModelRocketDud: 43,
|
|
||||||
CallVoteFailed : 44,
|
|
||||||
VoteStart : 45,
|
|
||||||
VotePass : 46,
|
|
||||||
VoteFailed : 47,
|
|
||||||
VoteSetup : 48,
|
|
||||||
PlayerBonusPoints : 49,
|
|
||||||
SpawnFlyingBird : 50,
|
|
||||||
PlayerGodRayEffect : 51,
|
|
||||||
SPHapWeapEvent : 52,
|
|
||||||
HapDmg : 53,
|
|
||||||
HapPunch : 54,
|
|
||||||
HapSetDrag : 55,
|
|
||||||
HapSet : 56,
|
|
||||||
HapMeleeContact : 57
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = Packet;
|
module.exports = Packet;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue