mirror of
https://github.com/demostf/demo.js
synced 2026-06-04 00:54:14 +02:00
initial version
This commit is contained in:
commit
011625257d
10 changed files with 576 additions and 0 deletions
14
consolecmd.js
Normal file
14
consolecmd.js
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
var ConsoleCmd = function (type, tick, stream, length) {
|
||||||
|
this.type = type;
|
||||||
|
this.tick = tick;
|
||||||
|
this.stream = stream;
|
||||||
|
this.length = length;//length in bytes
|
||||||
|
};
|
||||||
|
|
||||||
|
ConsoleCmd.prototype.parse = function () {
|
||||||
|
var cmd = this.stream.readASCIIString();
|
||||||
|
console.log("cmd " + cmd);
|
||||||
|
return cmd;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = ConsoleCmd;
|
||||||
30
demo.js
Normal file
30
demo.js
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
var BitStream = require('bit-buffer').BitStream;
|
||||||
|
var Parser = require('./parser');
|
||||||
|
|
||||||
|
var Demo = function (arrayBuffer) {
|
||||||
|
this.stream = new BitStream(arrayBuffer);
|
||||||
|
};
|
||||||
|
|
||||||
|
Demo.prototype.getParser = function () {
|
||||||
|
return new Parser(this.stream);
|
||||||
|
};
|
||||||
|
|
||||||
|
Demo.fromNodeBuffer = function (nodeBuffer) {
|
||||||
|
var arrayBuffer = new ArrayBuffer(nodeBuffer.length);
|
||||||
|
var view = new Uint8Array(arrayBuffer);
|
||||||
|
for (var i = 0; i < nodeBuffer.length; ++i) {
|
||||||
|
view[i] = nodeBuffer[i];
|
||||||
|
}
|
||||||
|
return new Demo(arrayBuffer);
|
||||||
|
};
|
||||||
|
|
||||||
|
Demo.fromPath = function (path) {
|
||||||
|
var arrayBuffer = new ArrayBuffer(nodeBuffer.length);
|
||||||
|
var view = new Uint8Array(arrayBuffer);
|
||||||
|
for (var i = 0; i < nodeBuffer.length; ++i) {
|
||||||
|
view[i] = nodeBuffer[i];
|
||||||
|
}
|
||||||
|
return new Demo(arrayBuffer);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = Demo;
|
||||||
BIN
gully.dem
Normal file
BIN
gully.dem
Normal file
Binary file not shown.
6
package.json
Normal file
6
package.json
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"bit-buffer": "0.0.3",
|
||||||
|
"buffer": "^3.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
334
packet.js
Normal file
334
packet.js
Normal file
|
|
@ -0,0 +1,334 @@
|
||||||
|
var ParserGenerator = require('./parsergenerator');
|
||||||
|
|
||||||
|
function logBase2(num) {
|
||||||
|
var result = 0;
|
||||||
|
while ((num >>= 1) != 0) {
|
||||||
|
result++;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
var Packet = function (type, tick, stream, length) {
|
||||||
|
this.type = type;
|
||||||
|
this.tick = tick;
|
||||||
|
this.stream = stream;
|
||||||
|
this.length = length;//length in bytes
|
||||||
|
};
|
||||||
|
|
||||||
|
Packet.gameEventMap = {};
|
||||||
|
|
||||||
|
Object.defineProperty(Packet.prototype, 'bitsLeft', {
|
||||||
|
get: function () {
|
||||||
|
return (this.length * 8) - this.stream._index;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Packet.prototype.parse = function () {
|
||||||
|
var packets = [];
|
||||||
|
while (this.bitsLeft > 6) { // last 6 bits for NOOP
|
||||||
|
var type = this.stream.readBits(6);
|
||||||
|
if (Packet.parsers[type]) {
|
||||||
|
var packet = Packet.parsers[type](this.stream);
|
||||||
|
console.log(packet);
|
||||||
|
packets.push(packet);
|
||||||
|
} else {
|
||||||
|
throw 'Unknown packet type ' + type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return packets;
|
||||||
|
};
|
||||||
|
|
||||||
|
Packet.parseGameEvent = function (eventId, stream) {
|
||||||
|
if (!Packet.gameEventMap[eventId]) {
|
||||||
|
return 'unknown';
|
||||||
|
}
|
||||||
|
var eventDescription = this.gameEventMap[eventId];
|
||||||
|
//console.log(eventDescription);
|
||||||
|
var values = {};
|
||||||
|
for (var i = 0; i < eventDescription.entries.length; i++) {
|
||||||
|
var entry = eventDescription.entries[i];
|
||||||
|
values[entry.name] = Packet.getGameEventValue(stream, entry);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
name : eventDescription.name,
|
||||||
|
type : eventDescription.type,
|
||||||
|
values: values
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
Packet.getGameEventValue = function (stream, entry) {
|
||||||
|
switch (entry.type) {
|
||||||
|
case 1:
|
||||||
|
return stream.readASCIIString();
|
||||||
|
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'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Packet.parsers = {
|
||||||
|
0 : function () {
|
||||||
|
},
|
||||||
|
3 : ParserGenerator.make('netTick', 'tick{32}frameTime{16}stdDev{16}'),
|
||||||
|
6 : ParserGenerator.make('sigOnState', 'state{8}count{32}'),
|
||||||
|
8 : ParserGenerator.make('serverInfo',
|
||||||
|
'version{16}serverCount{32}stv{b}dedicated{b}maxCrc{32}maxClasses{16}' +
|
||||||
|
'mapHash{128}playerCount{8}maxPlayerCount{8}intervalPerTick{f32}platform{s1}' +
|
||||||
|
'game{s}map{s}skybox{s}serverName{s}replay{b}'),
|
||||||
|
10: function (stream) {
|
||||||
|
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}'),
|
||||||
|
12: function (stream) {
|
||||||
|
//todo
|
||||||
|
// https://coldemoplayer.googlecode.com/svn/branches/2.0/code/plugins/CDP.Source/Messages/SvcCreateStringTable.cs
|
||||||
|
var name = stream.readASCIIString();
|
||||||
|
var maxEntries = stream.readBits(16);
|
||||||
|
var bits = Math.log(maxEntries) / Math.LN2;
|
||||||
|
var numEntries = stream.readBits(bits + 1);
|
||||||
|
var length = stream.readBits(20);
|
||||||
|
var userDataFixedSize = stream.readBits(1);
|
||||||
|
if (userDataFixedSize) {
|
||||||
|
var userSize = stream.readBits(12);
|
||||||
|
var userDataBits = stream.readBits(4);
|
||||||
|
}
|
||||||
|
var data = [];
|
||||||
|
var end = stream._index + length;
|
||||||
|
|
||||||
|
|
||||||
|
for (var i = 0; i < numEntries; i++) {
|
||||||
|
//data.push(stream.readASCIIString());
|
||||||
|
//stream.readBits(7);
|
||||||
|
//data.push(stream.readASCIIString());
|
||||||
|
//console.log(stream.readBits(bits + 1));
|
||||||
|
//stream.readBits(1);
|
||||||
|
//data.push(stream.readASCIIString());
|
||||||
|
}
|
||||||
|
stream._index = end;
|
||||||
|
return {packetType: 'createStringTable'};
|
||||||
|
//return {
|
||||||
|
// packetType: 'createStringTable',
|
||||||
|
// name : name,
|
||||||
|
// entries : numEntries,
|
||||||
|
// data : data
|
||||||
|
//}
|
||||||
|
},
|
||||||
|
13: function (stream) {
|
||||||
|
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 = [];
|
||||||
|
//for (var i = 0; i < changeEntries; i++) {
|
||||||
|
// // todo cleanup the 8/16 bits that get read in the string here
|
||||||
|
// strings.push(stream.readASCIIString());
|
||||||
|
//}
|
||||||
|
stream._index = end;
|
||||||
|
//throw false;
|
||||||
|
return {
|
||||||
|
packetType : 'updateStringTables',
|
||||||
|
tableId : tableId,
|
||||||
|
changedEntries: changeEntries,
|
||||||
|
length : length,
|
||||||
|
strings : strings
|
||||||
|
}
|
||||||
|
},
|
||||||
|
14: ParserGenerator.make('voiceInit', 'coded{s}quality{8}'),
|
||||||
|
15: ParserGenerator.make('voiceData', 'client{8}proximity{8}length{16}data{$length}'),
|
||||||
|
17: function (stream) {
|
||||||
|
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}'),
|
||||||
|
19: ParserGenerator.make('fixAngle', 'relative{b}x{16}y{16}z{16}'),
|
||||||
|
23: function (stream) {
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stream._index = pos + length;
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
24: ParserGenerator.make('entityMessage', 'index{11}id{9}length{11}data{$length}'),
|
||||||
|
25: function (stream) {
|
||||||
|
var length = stream.readBits(11);
|
||||||
|
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) {
|
||||||
|
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}data{$length}'),
|
||||||
|
28: ParserGenerator.make('preFetch', 'index{14}'),
|
||||||
|
30: function (stream) {
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Packet.userMessageParsers = {
|
||||||
|
4: ParserGenerator.make('sayText2', 'client{8}raw{8}kind{s}from{s}text{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;
|
||||||
90
parser.js
Normal file
90
parser.js
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
var Packet = require('./packet');
|
||||||
|
var ConsoleCmd = require('./consolecmd');
|
||||||
|
var StringTable = require('./stringtable');
|
||||||
|
var BitStream = require('bit-buffer').BitStream;
|
||||||
|
|
||||||
|
var Parser = function (steam) {
|
||||||
|
this.stream = steam;
|
||||||
|
};
|
||||||
|
|
||||||
|
Parser.MessageType = {
|
||||||
|
Sigon : 1,
|
||||||
|
Packet : 2,
|
||||||
|
SyncTick : 3,
|
||||||
|
ConsoleCmd : 4,
|
||||||
|
UserCmd : 5,
|
||||||
|
DataTables : 6,
|
||||||
|
Stop : 7,
|
||||||
|
StringTables: 8
|
||||||
|
};
|
||||||
|
|
||||||
|
Parser.prototype.readHeader = function () {
|
||||||
|
return {
|
||||||
|
'type' : this.stream.readASCIIString(8),
|
||||||
|
'version' : this.stream.readInt32(),
|
||||||
|
'protocol': this.stream.readInt32(),
|
||||||
|
'server' : this.stream.readASCIIString(260),
|
||||||
|
'nick' : this.stream.readASCIIString(260),
|
||||||
|
'map' : this.stream.readASCIIString(260),
|
||||||
|
'game' : this.stream.readASCIIString(260),
|
||||||
|
'duration': this.stream.readFloat32(),
|
||||||
|
'ticks' : this.stream.readInt32(),
|
||||||
|
'frames' : this.stream.readInt32(),
|
||||||
|
'sigon' : this.stream.readInt32()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Parser.prototype.readMessage = function () {
|
||||||
|
console.log();
|
||||||
|
console.log('start message');
|
||||||
|
console.log(this.stream.byteIndex);
|
||||||
|
var type = this.stream.readBits(8);
|
||||||
|
console.log(type);
|
||||||
|
if (type === Parser.MessageType.Stop) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var tick = this.stream.readInt32();
|
||||||
|
var data, start, length, buffer;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case Parser.MessageType.Sigon:
|
||||||
|
case Parser.MessageType.Packet:
|
||||||
|
this.stream.byteIndex += 0x54; // command/sequence info
|
||||||
|
break;
|
||||||
|
case Parser.MessageType.UserCmd:
|
||||||
|
this.stream.byteIndex += 0x04; // unknown / outgoing sequence
|
||||||
|
break;
|
||||||
|
case Parser.MessageType.Stop:
|
||||||
|
return false;
|
||||||
|
case Parser.MessageType.SyncTick:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
length = this.stream.readInt32();
|
||||||
|
console.log('message length: ' + length + ' byte');
|
||||||
|
start = this.stream.byteIndex;
|
||||||
|
buffer = this.stream.buffer.slice(start, start + length);
|
||||||
|
this.stream.byteIndex += length;
|
||||||
|
data = new BitStream(buffer);
|
||||||
|
//console.log(this.stream.buffer);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case Parser.MessageType.Sigon:
|
||||||
|
case Parser.MessageType.Packet:
|
||||||
|
return new Packet(type, tick, data, length);
|
||||||
|
case Parser.MessageType.ConsoleCmd:
|
||||||
|
return new ConsoleCmd(type, tick, data, length);
|
||||||
|
case Parser.MessageType.UserCmd:
|
||||||
|
return true;
|
||||||
|
case Parser.MessageType.DataTables:
|
||||||
|
console.log('datatable');
|
||||||
|
return true;
|
||||||
|
case Parser.MessageType.StringTables:
|
||||||
|
return new StringTable(type, tick, data, length);
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
//throw 'Unknown message type: ' + type;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = Parser;
|
||||||
47
parsergenerator.js
Normal file
47
parsergenerator.js
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
var Generator = {};
|
||||||
|
|
||||||
|
Generator.make = function (name, string) {
|
||||||
|
var parts = string.substr(0, string.length - 1).split('}');//remove leading } to prevent empty part
|
||||||
|
var items = parts.map(function (part) {
|
||||||
|
return part.split('{');
|
||||||
|
});
|
||||||
|
return function (stream) {
|
||||||
|
var result = {
|
||||||
|
'packetType': name
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
for (var i = 0; i < items.length; i++) {
|
||||||
|
result[items[i][0]] = Generator.readItem(stream, items[i][1], result);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
throw 'Failed reading pattern ' + string;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Generator.readItem = function (stream, description, data) {
|
||||||
|
var length;
|
||||||
|
if (description[0] === 'b') {
|
||||||
|
return !!stream.readBits(1);
|
||||||
|
} else if (description[0] === 's') {
|
||||||
|
if (description.length === 1) {
|
||||||
|
return stream.readASCIIString();
|
||||||
|
} else {
|
||||||
|
length = parseInt(description.substr(1), 10);
|
||||||
|
return stream.readASCIIString(length);
|
||||||
|
}
|
||||||
|
} else if (description === 'f32') {
|
||||||
|
return stream.readFloat32();
|
||||||
|
} else if (description[0] === 'u') {
|
||||||
|
length = parseInt(description.substr(1), 10);
|
||||||
|
return stream.readBits(length);
|
||||||
|
} else if (description[0] === '$') {
|
||||||
|
var variable = description.substr(1);
|
||||||
|
return stream.readBits(variable);
|
||||||
|
} else {
|
||||||
|
return stream.readBits(parseInt(description, 10), true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = Generator;
|
||||||
BIN
snakewater.dem
Normal file
BIN
snakewater.dem
Normal file
Binary file not shown.
39
stringtable.js
Normal file
39
stringtable.js
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
var StringTable = function (type, tick, stream, length) {
|
||||||
|
this.type = type;
|
||||||
|
this.tick = tick;
|
||||||
|
this.stream = stream;
|
||||||
|
this.length = length;//length in bytes
|
||||||
|
};
|
||||||
|
|
||||||
|
StringTable.prototype.parse = function () {
|
||||||
|
var tableCount = this.stream.readBits(8);
|
||||||
|
var tables = {};
|
||||||
|
for (var i = 0; i < tableCount; i++) {
|
||||||
|
var entries = [];
|
||||||
|
var tableName = this.stream.readASCIIString();
|
||||||
|
var entryCount = this.stream.readBits(16);
|
||||||
|
for (var j = 0; j < entryCount; j++) {
|
||||||
|
var entry = {
|
||||||
|
text: this.stream.readASCIIString()
|
||||||
|
};
|
||||||
|
if (this.stream.readBits(1)) {
|
||||||
|
var extraDataLength = this.stream.readBits(16);
|
||||||
|
entry.extraData = this.stream.readASCIIString(extraDataLength);
|
||||||
|
}
|
||||||
|
entries.push(entry);
|
||||||
|
}
|
||||||
|
tables[tableName] = entries;
|
||||||
|
if (this.stream.readBits(1)) {
|
||||||
|
console.log(this.stream.readASCIIString());
|
||||||
|
if (this.stream.readBits(1)) {
|
||||||
|
throw 'more extra data not implemted';
|
||||||
|
var extraDataLength = this.stream.readBits(16);
|
||||||
|
this.stream.readBits(extraDataLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//console.log(tables);
|
||||||
|
return tables;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = StringTable;
|
||||||
16
test.js
Normal file
16
test.js
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
var Demo = require('./demo');
|
||||||
|
var fs = require('fs');
|
||||||
|
|
||||||
|
fs.readFile("snakewater.dem", function (err, data) {
|
||||||
|
if (err) throw err;
|
||||||
|
var demo = Demo.fromNodeBuffer(data);
|
||||||
|
var parser = demo.getParser();
|
||||||
|
var head = parser.readHeader();
|
||||||
|
//console.log(parser.readHeader());
|
||||||
|
var message;
|
||||||
|
while (message = parser.readMessage()) {
|
||||||
|
if (message.parse) {
|
||||||
|
message.parse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
Loading…
Add table
Add a link
Reference in a new issue