mirror of
https://github.com/demostf/demo.js
synced 2026-06-03 16:44:12 +02:00
packetentities wip
This commit is contained in:
parent
a619cd1404
commit
8e286a17b1
7 changed files with 410 additions and 74 deletions
244
datatable.js
244
datatable.js
|
|
@ -25,13 +25,13 @@ DataTableParser.prototype.parse = function () {
|
|||
var propName = this.stream.readASCIIString();
|
||||
var nFlagsBits = 16; // might be 11 (old?), 13 (new?), 16(networked) or 17(??)
|
||||
var flags = this.stream.readBits(nFlagsBits);
|
||||
var prop = new SendProp(propType, propName, flags);
|
||||
if (propType === SendProp.types.DPT_DataTable) {
|
||||
var prop = new SendPropDefinition(propType, propName, flags);
|
||||
if (propType === SendPropDefinition.types.DPT_DataTable) {
|
||||
prop.excludeDTName = this.stream.readASCIIString();
|
||||
} else {
|
||||
if (prop.isExcludeProp()) {
|
||||
prop.excludeDTName = this.stream.readASCIIString();
|
||||
} else if (prop.type === SendProp.types.DPT_Array) {
|
||||
} else if (prop.type === SendPropDefinition.types.DPT_Array) {
|
||||
prop.numElements = this.stream.readBits(10);
|
||||
} else {
|
||||
prop.lowValue = this.stream.readFloat32();
|
||||
|
|
@ -40,25 +40,25 @@ DataTableParser.prototype.parse = function () {
|
|||
}
|
||||
}
|
||||
|
||||
if (prop.hasFlag(SendProp.flags.SPROP_NOSCALE)) {
|
||||
if (prop.type === SendProp.types.DPT_Float) {
|
||||
if (prop.hasFlag(SendPropDefinition.flags.SPROP_NOSCALE)) {
|
||||
if (prop.type === SendPropDefinition.types.DPT_Float) {
|
||||
prop.bitCount = 32;
|
||||
} else if (prop.type === SendProp.types.DPT_Vector) {
|
||||
if (!prop.hasFlag(SendProp.flags.SPROP_NORMAL)) {
|
||||
} else if (prop.type === SendPropDefinition.types.DPT_Vector) {
|
||||
if (!prop.hasFlag(SendPropDefinition.flags.SPROP_NORMAL)) {
|
||||
prop.bitCount = 32 * 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (arrayElementProp) {
|
||||
if (!prop.type === SendProp.types.DPT_Array) {
|
||||
if (!prop.type === SendPropDefinition.types.DPT_Array) {
|
||||
throw "expected prop of type array";
|
||||
}
|
||||
prop.arrayProperty = arrayElementProp;
|
||||
arrayElementProp = null;
|
||||
}
|
||||
|
||||
if (prop.hasFlag(SendProp.flags.SPROP_INSIDEARRAY)) {
|
||||
if (prop.hasFlag(SendPropDefinition.flags.SPROP_INSIDEARRAY)) {
|
||||
arrayElementProp = prop;
|
||||
} else {
|
||||
table.addProp(prop);
|
||||
|
|
@ -71,7 +71,7 @@ DataTableParser.prototype.parse = function () {
|
|||
// link referenced tables
|
||||
for (i = 0; i < tables.length; i++) {
|
||||
for (j = 0; j < tables[i].props.length; j++) {
|
||||
if (tables[i].props[j].type === SendProp.types.DPT_DataTable) {
|
||||
if (tables[i].props[j].type === SendPropDefinition.types.DPT_DataTable) {
|
||||
tables[i].props[j].table = this.match.getSendTable(tables[i].props[j].excludeDTName);
|
||||
tables[i].props[j].excludeDTName = null;
|
||||
}
|
||||
|
|
@ -104,30 +104,87 @@ DataTableParser.prototype.parse = function () {
|
|||
var SentTable = function (name) {
|
||||
this.name = name;
|
||||
this.props = [];
|
||||
this._flattenedProps = [];
|
||||
};
|
||||
|
||||
Object.defineProperty(SentTable.prototype, 'flattenedProps', {
|
||||
get: function () {
|
||||
if (this._flattenedProps.length === 0) {
|
||||
this.flatten();
|
||||
}
|
||||
return this._flattenedProps;
|
||||
}
|
||||
});
|
||||
|
||||
SentTable.prototype.addProp = function (prop) {
|
||||
this.props.push(prop);
|
||||
};
|
||||
SentTable.prototype.flatten = function () {
|
||||
var excludes = [];
|
||||
var props = [];
|
||||
this.getAllProps(excludes, props);
|
||||
|
||||
var SendProp = function (type, name, flags) {
|
||||
// sort often changed props before the others
|
||||
var start = 0;
|
||||
for (var i = 0; i < props.length; i++) {
|
||||
if (props[i].hasFlag(SendPropDefinition.flags.SPROP_CHANGES_OFTEN)) {
|
||||
if (i != start) {
|
||||
var temp = props[i];
|
||||
props[i] = props[start];
|
||||
props[start] = temp;
|
||||
}
|
||||
start++;
|
||||
}
|
||||
}
|
||||
this._flattenedProps = props;
|
||||
};
|
||||
SentTable.prototype.getAllProps = function (excludes, props) {
|
||||
var localProps = [];
|
||||
this.getAllPropsIteratorProps(excludes, localProps, props);
|
||||
for (var i = 0; i < localProps.length; i++) {
|
||||
props.push(localProps[i]);
|
||||
}
|
||||
};
|
||||
SentTable.prototype.getAllPropsIteratorProps = function (excludes, props, childProps) {
|
||||
for (var i = 0; i < this.props.length; i++) {
|
||||
var prop = this.props[i];
|
||||
if (prop.type === SendPropDefinition.types.DPT_DataTable) {
|
||||
if (prop.hasFlag(SendPropDefinition.flags.SPROP_EXCLUDE)) {
|
||||
excludes.push(prop.table);
|
||||
} else if (excludes.indexOf(this) === -1) {
|
||||
if (prop.hasFlag(SendPropDefinition.flags.SPROP_COLLAPSIBLE)) {
|
||||
prop.table.getAllPropsIteratorProps(excludes, props, childProps);
|
||||
} else {
|
||||
prop.table.getAllProps(excludes, childProps);
|
||||
}
|
||||
}
|
||||
} else if (!prop.hasFlag(SendPropDefinition.flags.SPROP_EXCLUDE)) {
|
||||
props.push(prop);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var SendPropDefinition = function (type, name, flags) {
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
this.flags = flags;
|
||||
this.excludeDTName = null;
|
||||
this.lowValue = 0;
|
||||
this.highValue = 0;
|
||||
this.bits = 0;
|
||||
this.bitCount = 0;
|
||||
this.table = null;
|
||||
this.numElements = null;
|
||||
this.arrayProperty = null;
|
||||
};
|
||||
|
||||
SendProp.prototype.hasFlag = function (flag) {
|
||||
SendPropDefinition.prototype.hasFlag = function (flag) {
|
||||
return (this.flags & flag) != 0;
|
||||
};
|
||||
SendProp.prototype.isExcludeProp = function () {
|
||||
return this.hasFlag(SendProp.flags.SPROP_EXCLUDE);
|
||||
SendPropDefinition.prototype.isExcludeProp = function () {
|
||||
return this.hasFlag(SendPropDefinition.flags.SPROP_EXCLUDE);
|
||||
};
|
||||
|
||||
SendProp.types = {
|
||||
SendPropDefinition.types = {
|
||||
DPT_Int : 0,
|
||||
DPT_Float : 1,
|
||||
DPT_Vector : 2,
|
||||
|
|
@ -138,7 +195,7 @@ SendProp.types = {
|
|||
DPT_NUMSendPropTypes: 7
|
||||
};
|
||||
|
||||
SendProp.flags = {
|
||||
SendPropDefinition.flags = {
|
||||
SPROP_UNSIGNED : (1 << 0),// Unsigned integer data.
|
||||
SPROP_COORD : (1 << 1),// If this is set, the float/vector is treated like a world coordinate.
|
||||
// Note that the bit count is ignored in this case.
|
||||
|
|
@ -160,14 +217,15 @@ SendProp.flags = {
|
|||
// trouble of walking the hierarchy more than necessary.
|
||||
SPROP_COORD_MP : (1 << 13),// Like SPROP_COORD, but special handling for multiplayer games
|
||||
SPROP_COORD_MP_LOWPRECISION: (1 << 14),// Like SPROP_COORD, but special handling for multiplayer games where the fractional component only gets a 3 bits instead of 5
|
||||
SPROP_COORD_MP_INTEGRAL : (1 << 15)// SPROP_COORD_MP, but coordinates are rounded to integral boundaries
|
||||
SPROP_COORD_MP_INTEGRAL : (1 << 15),// SPROP_COORD_MP, but coordinates are rounded to integral boundaries
|
||||
SPROP_VARINT : (1 << 5) //reuse normal
|
||||
};
|
||||
|
||||
SendProp.formatFlags = function (flags) {
|
||||
SendPropDefinition.formatFlags = function (flags) {
|
||||
var names = [];
|
||||
for (var name in SendProp.flags) {
|
||||
if (SendProp.flags.hasOwnProperty(name)) {
|
||||
if (flags & SendProp.flags[name]) {
|
||||
for (var name in SendPropDefinition.flags) {
|
||||
if (SendPropDefinition.flags.hasOwnProperty(name)) {
|
||||
if (flags & SendPropDefinition.flags[name]) {
|
||||
names.push(name);
|
||||
}
|
||||
}
|
||||
|
|
@ -175,14 +233,150 @@ SendProp.formatFlags = function (flags) {
|
|||
return names;
|
||||
};
|
||||
|
||||
SendPropDefinition.prototype.decode = function (stream) {
|
||||
switch (this.type) {
|
||||
case SendPropDefinition.types.DPT_Int:
|
||||
return this.readInt(stream);
|
||||
case SendPropDefinition.types.DPT_Vector:
|
||||
return this.readVector(stream);
|
||||
case SendPropDefinition.types.DPT_VectorXY:
|
||||
return this.readVectorXY(stream);
|
||||
case SendPropDefinition.types.DPT_Float:
|
||||
return this.readFloat(stream);
|
||||
case SendPropDefinition.types.DPT_String:
|
||||
return this.readString(stream);
|
||||
case SendPropDefinition.types.DPT_Array:
|
||||
return this.readArray(stream);
|
||||
}
|
||||
};
|
||||
|
||||
SendPropDefinition.prototype.readInt = function (stream) {
|
||||
if (this.hasFlag(SendPropDefinition.flags.SPROP_VARINT)) {
|
||||
return readBitVar(stream, !this.hasFlag(SendPropDefinition.flags.SPROP_UNSIGNED));
|
||||
} else {
|
||||
return stream.readBits(this.bitCount, !this.hasFlag(SendPropDefinition.flags.SPROP_UNSIGNED));
|
||||
}
|
||||
};
|
||||
|
||||
SendPropDefinition.prototype.readArray = function (stream) {
|
||||
var maxElements = this.numElements;
|
||||
var numBits = 1;
|
||||
while ((maxElements >>= 1) != 0)
|
||||
numBits++;
|
||||
|
||||
var count = stream.readBits(numBits);
|
||||
var values = [];
|
||||
for (var i = 0; i < count; i++) {
|
||||
values.push(this.arrayProperty.decode(stream));
|
||||
}
|
||||
return values;
|
||||
};
|
||||
|
||||
SendPropDefinition.prototype.readString = function (stream) {
|
||||
var length = stream.readBits(9);
|
||||
return stream.readASCIIString(length);
|
||||
};
|
||||
|
||||
SendPropDefinition.prototype.readVector = function (stream) {
|
||||
var x = this.readFloat(stream);
|
||||
var y = this.readFloat(stream);
|
||||
if (this.hasFlag(SendPropDefinition.flags.SPROP_NORMAL)) {
|
||||
var z = this.readFloat(stream);
|
||||
} else {
|
||||
z = 0; //guess
|
||||
}
|
||||
return new Vector(x, y, z);
|
||||
};
|
||||
|
||||
SendPropDefinition.prototype.readVectorXY = function (stream) {
|
||||
var x = this.readFloat(stream);
|
||||
var y = this.readFloat(stream);
|
||||
return new Vector(x, y, 0);
|
||||
};
|
||||
|
||||
var Vector = function (x, y, z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
};
|
||||
|
||||
SendPropDefinition.prototype.readFloat = function (stream) {
|
||||
if (this.hasFlag(SendPropDefinition.flags.SPROP_COORD)) {
|
||||
throw new Error("not implemented");
|
||||
} else if (this.hasFlag(SendPropDefinition.flags.SPROP_COORD_MP)) {
|
||||
return this.readBitCoord(stream, false, false);
|
||||
} else if (this.hasFlag(SendPropDefinition.flags.SPROP_COORD_MP_LOWPRECISION)) {
|
||||
return this.readBitCoord(stream, false, true);
|
||||
} else if (this.hasFlag(SendPropDefinition.flags.SPROP_COORD_MP_INTEGRAL)) {
|
||||
return this.readBitCoord(stream, true, false);
|
||||
} else if (this.hasFlag(SendPropDefinition.flags.SPROP_NOSCALE)) {
|
||||
return stream.readFloat32();
|
||||
} else if (this.hasFlag(SendPropDefinition.flags.SPROP_NORMAL)) {
|
||||
throw new Error("not implemented");
|
||||
} else {
|
||||
var raw = stream.readBits(this.bitCount);
|
||||
var percentage = raw / ((1 << this.bitCount) - 1);
|
||||
return this.lowValue + (this.highValue - this.lowValue) * percentage;
|
||||
}
|
||||
};
|
||||
|
||||
SendPropDefinition.prototype.readBitCoord = function (stream, isIntegral, isLowPercision) {
|
||||
var value = 0;
|
||||
var isNegative = false;
|
||||
var inBounds = stream.readBoolean();
|
||||
|
||||
var hasIntVal = stream.readBoolean();
|
||||
if (isIntegral) {
|
||||
if (hasIntVal) {
|
||||
isNegative = stream.readBoolean();
|
||||
|
||||
if (inBounds) {
|
||||
value = stream.readBitVar(11) + 1;
|
||||
} else {
|
||||
value = stream.readBitVar(14) + 1;
|
||||
if (value < (1 << 11)) {
|
||||
throw new Error("Something's fishy...");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
isNegative = stream.readBoolean();
|
||||
if (hasIntVal) {
|
||||
if (inBounds) {
|
||||
value = stream.readBitVar(11) + 1;
|
||||
} else {
|
||||
value = stream.readBitVar(14) + 1;
|
||||
if (value < (1 << 11)) {
|
||||
throw new Error("Something's fishy...");
|
||||
}
|
||||
}
|
||||
}
|
||||
var fractalVal = stream.readBits(isLowPercision ? 3 : 5);
|
||||
value += fractalVal * (1 / (1 << (isLowPercision ? 3 : 5)));
|
||||
}
|
||||
if (isNegative) {
|
||||
value = -value;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
var ServerClass = function (id, name, dataTable) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.dataTable = dataTable;
|
||||
};
|
||||
|
||||
function recvClassInfos(stream, needsDecoder) {
|
||||
|
||||
}
|
||||
var readBitVar = function (stream, signed) {
|
||||
switch (stream.readBits(2)) {
|
||||
case 0:
|
||||
return stream.readBits(4, signed);
|
||||
case 1:
|
||||
return stream.readBits(8, signed);
|
||||
case 2:
|
||||
return stream.readBits(12, signed);
|
||||
case 3:
|
||||
return stream.readBits(32, signed);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = DataTableParser;
|
||||
|
|
|
|||
|
|
@ -1,23 +1,12 @@
|
|||
var clone = require('clone');
|
||||
|
||||
var PVS = {
|
||||
PRESERVE: 0,
|
||||
ENTER : 1,
|
||||
LEAVE : 2,
|
||||
DELETE : 3
|
||||
DELETE : 4
|
||||
};
|
||||
|
||||
|
||||
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 readPVSType(stream) {
|
||||
// https://github.com/skadistats/smoke/blob/a2954fbe2fa3936d64aee5b5567be294fef228e6/smoke/io/stream/entity.pyx#L24
|
||||
var pvs;
|
||||
|
|
@ -35,14 +24,44 @@ function readPVSType(stream) {
|
|||
return pvs;
|
||||
}
|
||||
|
||||
function readEnterPVS(stream, entityId) {
|
||||
function readEnterPVS(stream, entityId, match, baseLine) {
|
||||
// https://github.com/PazerOP/DemoLib/blob/5f9467650f942a4a70f9ec689eadcd3e0a051956/TF2Net/NetMessages/NetPacketEntitiesMessage.cs#L198
|
||||
var serverClass = match.serverClasses[stream.readBits(match.classBits)];
|
||||
var sendTable = match.getSendTable(serverClass.dataTable);
|
||||
var serialNumber = stream.readBits(10);
|
||||
|
||||
var entity = (match.entities[entityId]) ? match.entities[entityId] : new Entity(match, serverClass, sendTable, entityId, serialNumber);
|
||||
|
||||
var decodedBaseLine = match.instanceBaselines[baseLine][entityId];
|
||||
if (decodedBaseLine) {
|
||||
for (var i = 0; i < decodedBaseLine.length; i++) {
|
||||
var newProp = decodedBaseLine[i];
|
||||
if (!entity.getPropByDefinition(newProp.definition)) {
|
||||
entity.props.push(newProp.clone(entity));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var staticBaseLine = match.staticBaseLines[serverClass.id];
|
||||
if (staticBaseLine) {
|
||||
var streamStart = staticBaseLine._index;
|
||||
applyEntityUpdate(entity, staticBaseLine);
|
||||
staticBaseLine._index = streamStart;
|
||||
}
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
module.exports = function (stream, events, entities) { //26: packetEntities
|
||||
function readLeavePVS(match, entityId, shouldDelete) {
|
||||
if (shouldDelete) {
|
||||
match.entities[entityId] = null;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = function (stream, events, entities, match) { //26: packetEntities
|
||||
// https://github.com/skadistats/smoke/blob/master/smoke/replay/handler/svc_packetentities.pyx
|
||||
// https://github.com/StatsHelix/demoinfo/blob/3d28ea917c3d44d987b98bb8f976f1a3fcc19821/DemoInfo/DP/Handler/PacketEntitesHandler.cs
|
||||
// https://github.com/StatsHelix/demoinfo/blob/3d28ea917c3d44d987b98bb8f976f1a3fcc19821/DemoInfo/DP/Entity.cs
|
||||
// https://github.com/PazerOP/DemoLib/blob/5f9467650f942a4a70f9ec689eadcd3e0a051956/TF2Net/NetMessages/NetPacketEntitiesMessage.cs
|
||||
// todo
|
||||
var maxEntries = stream.readBits(11);
|
||||
var isDelta = !!stream.readBits(1);
|
||||
|
|
@ -51,31 +70,68 @@ module.exports = function (stream, events, entities) { //26: packetEntities
|
|||
} else {
|
||||
delta = null;
|
||||
}
|
||||
var baseLink = !!stream.readBits(1);
|
||||
var baseLine = stream.readBits(1);
|
||||
var updatedEntries = stream.readBits(11);
|
||||
var length = stream.readBits(20);
|
||||
var updatedBaseLink = !!stream.readBits(1);
|
||||
var updatedBaseLine = stream.readBoolean();
|
||||
var end = stream._index + length;
|
||||
//console.log('max: ' + maxEntries);
|
||||
var entityId = -1;
|
||||
|
||||
for (var i = 0; i < updatedEntries; i++) {
|
||||
entityId = readIndex(stream, entityId);
|
||||
var pvs = readPVSType(stream);
|
||||
if (pvs = PVS.PRESERVE) {
|
||||
var entity = readEnterPVS(stream, entityId)
|
||||
if (updatedBaseLine) {
|
||||
if (baseLine === 0) {
|
||||
match.instanceBaselines[1] = match.instanceBaselines[0];
|
||||
match.instanceBaselines[0] = new Array((1 << 11)); // array of SendPropDefinition with size MAX_EDICTS
|
||||
} else {
|
||||
match.instanceBaselines[0] = match.instanceBaselines[1];
|
||||
match.instanceBaselines[1] = new Array((1 << 11)); // array of SendPropDefinition with size MAX_EDICTS
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < updatedEntries; i++) {
|
||||
entityId+= 1 + readUBitVar(stream);
|
||||
var pvs = readPVSType(stream);
|
||||
if (pvs === PVS.ENTER) {
|
||||
var entity = readEnterPVS(stream, entityId, match, baseLine);
|
||||
applyEntityUpdate(entity, stream);
|
||||
match.entities[entityId] = entity;
|
||||
|
||||
if (updatedBaseLine) {
|
||||
match.instanceBaselines[baseLine][entityId] = [].concat(entity.props);
|
||||
}
|
||||
entity.inPVS = true;
|
||||
} else if (pvs === PVS.PRESERVE) {
|
||||
entity = match.entities[entityId];
|
||||
if (!entity) {
|
||||
console.log(entityId, match.entities.length);
|
||||
throw new Error("unknown entity");
|
||||
}
|
||||
applyEntityUpdate(entity, stream);
|
||||
} else {
|
||||
entity = match.entities[entityId];
|
||||
if (entity) {
|
||||
entity.inPVS = false;
|
||||
}
|
||||
readLeavePVS(match, entityId, pvs === PVS.DELETE);
|
||||
}
|
||||
}
|
||||
|
||||
if (isDelta) {
|
||||
while (stream.readBoolean()) {
|
||||
var ent = stream.readBits(11);
|
||||
match.entities[ent] = null;
|
||||
}
|
||||
}
|
||||
|
||||
stream._index = end;
|
||||
//var ent = {
|
||||
// packetType : 'packetEntities',
|
||||
// maxEntries : maxEntries,
|
||||
// isDelta : isDelta,
|
||||
// delta : delta,
|
||||
// baseLink : baseLink,
|
||||
// baseLine : baseLine,
|
||||
// updatedEntries : updatedEntries,
|
||||
// length : length,
|
||||
// updatedBaseLink: updatedBaseLink
|
||||
// updatedBaseLine: updatedBaseLine
|
||||
//};
|
||||
//console.log(ent);
|
||||
//console.log(entities);
|
||||
|
|
@ -85,3 +141,78 @@ module.exports = function (stream, events, entities) { //26: packetEntities
|
|||
entities : entities
|
||||
};
|
||||
};
|
||||
|
||||
var readFieldIndex = function (stream, lastIndex) {
|
||||
if (!stream.readBoolean()) {
|
||||
return -1;
|
||||
}
|
||||
var diff = readUBitVar(stream);
|
||||
return lastIndex + diff + 1;
|
||||
};
|
||||
|
||||
var applyEntityUpdate = function (entity, stream) {
|
||||
var index = -1;
|
||||
var allProps = entity.sendTable.flattenedProps;
|
||||
while ((index = readFieldIndex(stream, index)) != -1) {
|
||||
if (index > 4096) {
|
||||
throw new Error('prop index out of bounds');
|
||||
}
|
||||
var propDefinition = allProps[index];
|
||||
var existingProp = entity.getPropByDefinition(propDefinition);
|
||||
var prop;
|
||||
if (existingProp) {
|
||||
prop = existingProp;
|
||||
} else {
|
||||
prop = new SentProp(propDefinition);
|
||||
}
|
||||
prop.value = propDefinition.decode(stream);
|
||||
|
||||
if (!existingProp) {
|
||||
entity.props.push(prop);
|
||||
}
|
||||
}
|
||||
return entity;
|
||||
};
|
||||
|
||||
var readUBitVar = function (stream) {
|
||||
switch (stream.readBits(2)) {
|
||||
case 0:
|
||||
return stream.readBits(4);
|
||||
case 1:
|
||||
return stream.readBits(8);
|
||||
case 2:
|
||||
return stream.readBits(12);
|
||||
case 3:
|
||||
return stream.readBits(32);
|
||||
}
|
||||
};
|
||||
|
||||
var Entity = function (match, serverClass, sentTable, entityIndex, serialNumber) {
|
||||
this.match = match;
|
||||
this.serverClass = serverClass;
|
||||
this.sendTable = sentTable;
|
||||
this.entityIndex = entityIndex;
|
||||
this.serialNumber = serialNumber;
|
||||
this.props = [];
|
||||
this.inPVS = false;
|
||||
};
|
||||
|
||||
Entity.prototype.getPropByDefinition = function (definition) {
|
||||
for (var i = 0; i < this.props; i++) {
|
||||
if (this.props[i].definition === definition) {
|
||||
return this.props[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
var SentProp = function (definition) {
|
||||
this.definition = definition;
|
||||
this.value = null;
|
||||
};
|
||||
|
||||
SentProp.prototype.clone = function () {
|
||||
var prop = new SentProp(this.definition);
|
||||
prop.value = clone(this.value);
|
||||
return prop;
|
||||
};
|
||||
|
|
|
|||
18
match.js
18
match.js
|
|
@ -10,6 +10,9 @@ var Match = function () {
|
|||
this.stringTables = [];
|
||||
this.sendTables = [];
|
||||
this.serverClasses = [];
|
||||
this.entities = [];
|
||||
this.instanceBaselines = [[],[]];
|
||||
this.staticBaseLines = [];
|
||||
};
|
||||
|
||||
Match.prototype.getSendTable = function (name) {
|
||||
|
|
@ -21,6 +24,15 @@ Match.prototype.getSendTable = function (name) {
|
|||
return null;
|
||||
};
|
||||
|
||||
Match.prototype.getStringTable = function (name) {
|
||||
for (var i = 0; i < this.stringTables.length; i++) {
|
||||
if (this.stringTables[i].name === name) {
|
||||
return this.stringTables[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
Match.prototype.getState = function () {
|
||||
return {
|
||||
'chat' : this.chat,
|
||||
|
|
@ -131,4 +143,10 @@ Match.prototype.getUserState = function (userId) {
|
|||
return this.users[userId];
|
||||
};
|
||||
|
||||
Object.defineProperty(Match.prototype, 'classBits', {
|
||||
get: function () {
|
||||
return Math.ceil(Math.log(this.serverClasses.length) * Math.LOG2E)
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Match;
|
||||
|
|
|
|||
|
|
@ -7,8 +7,10 @@
|
|||
},
|
||||
"main": "demo.js",
|
||||
"dependencies": {
|
||||
"bit-buffer": "icewind1991/bit-buffer",
|
||||
"bit-buffer": "icewind1991/bit-buffer#readBitStream",
|
||||
"clone": "^2.1.0",
|
||||
"minimist": "1.1.x",
|
||||
"smart-buffer": "^1.0.1"
|
||||
"smart-buffer": "^1.0.1",
|
||||
"typedarray-to-buffer": "^3.1.2"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ Packet.prototype.parse = function () {
|
|||
while (this.bitsLeft > 6) { // last 6 bits for NOOP
|
||||
var type = this.stream.readBits(6);
|
||||
if (Packet.parsers[type]) {
|
||||
var packet = Packet.parsers[type].call(this, this.stream, Packet.gameEventMap, entities);
|
||||
var packet = Packet.parsers[type].call(this, this.stream, Packet.gameEventMap, entities, this.match);
|
||||
if (packet) {
|
||||
packet.viewOrigin = this.viewOrigin;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
var toBuffer = require('typedarray-to-buffer')
|
||||
var util = require('util');
|
||||
var Packet = require('./packet');
|
||||
var ConsoleCmd = require('./consolecmd');
|
||||
|
|
@ -134,7 +135,7 @@ Parser.prototype.readMessage = function (stream, match) {
|
|||
|
||||
length = stream.readInt32();
|
||||
start = stream.byteIndex;
|
||||
buffer = stream.buffer.slice(start, start + length);
|
||||
buffer = toBuffer(stream._view._view.slice(start, start + length));
|
||||
stream.byteIndex += length;
|
||||
return this.parseMessage(buffer, type, tick, length, viewOrigin, match);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
var BitStream = require('bit-buffer').BitStream;
|
||||
|
||||
var StringTable = function (type, tick, stream, length, match) {
|
||||
this.type = type;
|
||||
this.tick = tick;
|
||||
|
|
@ -7,13 +9,14 @@ var StringTable = function (type, tick, stream, length, match) {
|
|||
};
|
||||
|
||||
StringTable.prototype.parse = function () {
|
||||
var tableCount = this.stream.readBits(8);
|
||||
// https://github.com/StatsHelix/demoinfo/blob/3d28ea917c3d44d987b98bb8f976f1a3fcc19821/DemoInfo/ST/StringTableParser.cs
|
||||
var tableCount = this.stream.readUint8();
|
||||
var tables = {};
|
||||
var extraDataLength;
|
||||
for (var i = 0; i < tableCount; i++) {
|
||||
var entries = [];
|
||||
var tableName = this.stream.readASCIIString();
|
||||
var entryCount = this.stream.readBits(16);
|
||||
var entryCount = this.stream.readUint16();
|
||||
for (var j = 0; j < entryCount; j++) {
|
||||
try {
|
||||
var entry = {
|
||||
|
|
@ -26,8 +29,12 @@ StringTable.prototype.parse = function () {
|
|||
}];
|
||||
}
|
||||
if (this.stream.readBits(1)) {
|
||||
extraDataLength = this.stream.readBits(16);
|
||||
entry.extraData = this.readExtraData(extraDataLength);
|
||||
extraDataLength = this.stream.readUint16();
|
||||
if (tableName === 'instancebaseline') {
|
||||
this.match.staticBaseLines[parseInt(entry.text, 10)] = this.stream.readBitStream(8 * extraDataLength);
|
||||
} else {
|
||||
entry.extraData = this.readExtraData(extraDataLength);
|
||||
}
|
||||
}
|
||||
entries.push(entry);
|
||||
}
|
||||
|
|
@ -52,23 +59,6 @@ StringTable.prototype.parse = function () {
|
|||
}];
|
||||
};
|
||||
|
||||
StringTable.prototype.parsePlayerInfo = function (length) {
|
||||
var pos = this.stream._index;
|
||||
var name = this.stream.readUTF8String(128);
|
||||
console.log(length);
|
||||
//if (name === 'Icewind') {
|
||||
console.log(name);
|
||||
var userId = this.stream.readBits(32);
|
||||
console.log(userId);
|
||||
var guid = this.stream.readASCIIString(33);
|
||||
console.log('guid: ' + guid);
|
||||
//console.log(this.stream.readASCIIString(33));
|
||||
//console.log(this.stream.readASCIIString());
|
||||
//throw false;
|
||||
//}
|
||||
this.stream._index = pos + (length * 8);
|
||||
};
|
||||
|
||||
StringTable.prototype.readExtraData = function (length) {
|
||||
var end = this.stream._index + (length * 8);
|
||||
var data = [];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue