mirror of
https://github.com/demostf/demo.js
synced 2026-06-04 00:54:14 +02:00
only apply updates for entities from the current packet
This commit is contained in:
parent
641f5419df
commit
7cb74d93de
8 changed files with 46 additions and 50 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
import {Entity} from "./Entity";
|
import {PacketEntity} from "./PacketEntity";
|
||||||
import {ServerClass} from "./ServerClass";
|
import {ServerClass} from "./ServerClass";
|
||||||
import {SendTable} from "./SendTable";
|
import {SendTable} from "./SendTable";
|
||||||
import {StringTable} from "./StringTable";
|
import {StringTable} from "./StringTable";
|
||||||
|
|
@ -22,7 +22,7 @@ export class Match {
|
||||||
rounds: any[];
|
rounds: any[];
|
||||||
startTick: number;
|
startTick: number;
|
||||||
intervalPerTick: number;
|
intervalPerTick: number;
|
||||||
entities: (Entity|null)[];
|
packetEntities: (PacketEntity|null)[];
|
||||||
stringTables: StringTable[];
|
stringTables: StringTable[];
|
||||||
serverClasses: ServerClass[];
|
serverClasses: ServerClass[];
|
||||||
sendTables: SendTable[];
|
sendTables: SendTable[];
|
||||||
|
|
@ -41,11 +41,11 @@ export class Match {
|
||||||
this.rounds = [];
|
this.rounds = [];
|
||||||
this.startTick = 0;
|
this.startTick = 0;
|
||||||
this.intervalPerTick = 0;
|
this.intervalPerTick = 0;
|
||||||
this.entities = [];
|
this.packetEntities = [];
|
||||||
this.stringTables = [];
|
this.stringTables = [];
|
||||||
this.sendTables = [];
|
this.sendTables = [];
|
||||||
this.serverClasses = [];
|
this.serverClasses = [];
|
||||||
this.entities = [];
|
this.packetEntities = [];
|
||||||
this.instanceBaselines = [[], []];
|
this.instanceBaselines = [[], []];
|
||||||
this.staticBaseLines = [];
|
this.staticBaseLines = [];
|
||||||
this.eventDefinitions = {};
|
this.eventDefinitions = {};
|
||||||
|
|
@ -147,7 +147,7 @@ export class Match {
|
||||||
return this.users[userId];
|
return this.users[userId];
|
||||||
}
|
}
|
||||||
|
|
||||||
getUserInfoForEntity(entity: Entity): UserInfo {
|
getUserInfoForEntity(entity: PacketEntity): UserInfo {
|
||||||
for (const id of Object.keys(this.users)) {
|
for (const id of Object.keys(this.users)) {
|
||||||
const user = this.users[id];
|
const user = this.users[id];
|
||||||
if (user && user.entityId === entity.entityIndex) {
|
if (user && user.entityId === entity.entityIndex) {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import {StringTable} from "./StringTable";
|
import {StringTable} from "./StringTable";
|
||||||
import {Vector} from "./Vector";
|
import {Vector} from "./Vector";
|
||||||
import {GameEvent} from "./GameEvent";
|
import {GameEvent} from "./GameEvent";
|
||||||
import {Entity} from "./Entity";
|
import {PacketEntity} from "./PacketEntity";
|
||||||
|
|
||||||
export interface StringTablePacket {
|
export interface StringTablePacket {
|
||||||
packetType: 'stringTable';
|
packetType: 'stringTable';
|
||||||
|
|
@ -46,6 +46,7 @@ export interface GameEventListPacket {
|
||||||
|
|
||||||
export interface PacketEntitiesPacket {
|
export interface PacketEntitiesPacket {
|
||||||
packetType: 'packetEntities';
|
packetType: 'packetEntities';
|
||||||
|
entities: PacketEntity[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ParseSoundsPacket {
|
export interface ParseSoundsPacket {
|
||||||
|
|
@ -62,7 +63,7 @@ export interface SetConVarPacket {
|
||||||
|
|
||||||
export interface TempEntitiesPacket {
|
export interface TempEntitiesPacket {
|
||||||
packetType: 'tempEntities';
|
packetType: 'tempEntities';
|
||||||
entities: Entity[];
|
entities: PacketEntity[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SayText2Packet {
|
export interface SayText2Packet {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import {ServerClass} from "./ServerClass";
|
||||||
import {SendTable} from "./SendTable";
|
import {SendTable} from "./SendTable";
|
||||||
import {SendProp} from "./SendProp";
|
import {SendProp} from "./SendProp";
|
||||||
import {SendPropDefinition} from "./SendPropDefinition";
|
import {SendPropDefinition} from "./SendPropDefinition";
|
||||||
export class Entity {
|
export class PacketEntity {
|
||||||
serverClass: ServerClass;
|
serverClass: ServerClass;
|
||||||
sendTable: SendTable;
|
sendTable: SendTable;
|
||||||
entityIndex: number;
|
entityIndex: number;
|
||||||
|
|
@ -1,18 +1,16 @@
|
||||||
import {PacketEntitiesPacket} from "../Data/Packet";
|
import {PacketEntitiesPacket} from "../Data/Packet";
|
||||||
import {Match} from "../Data/Match";
|
import {Match} from "../Data/Match";
|
||||||
import {Entity} from "../Data/Entity";
|
import {PacketEntity} from "../Data/PacketEntity";
|
||||||
import {Vector} from "../Data/Vector";
|
import {Vector} from "../Data/Vector";
|
||||||
import {Player} from "../Data/Player";
|
import {Player} from "../Data/Player";
|
||||||
|
|
||||||
export function handlePacketEntities(packet: PacketEntitiesPacket, match: Match) {
|
export function handlePacketEntities(packet: PacketEntitiesPacket, match: Match) {
|
||||||
for (const entity of match.entities) {
|
for (const entity of packet.entities) {
|
||||||
if (entity) {
|
handleEntity(entity, match);
|
||||||
handleEntity(entity, match);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleEntity(entity: Entity, match: Match) {
|
function handleEntity(entity: PacketEntity, match: Match) {
|
||||||
switch (entity.serverClass.name) {
|
switch (entity.serverClass.name) {
|
||||||
case 'CWorld':
|
case 'CWorld':
|
||||||
match.world.boundaryMin = <Vector>entity.getProperty('DT_WORLD', 'm_WorldMins').value;
|
match.world.boundaryMin = <Vector>entity.getProperty('DT_WORLD', 'm_WorldMins').value;
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,11 @@
|
||||||
import {Entity} from "../Data/Entity";
|
import {PacketEntity} from "../Data/PacketEntity";
|
||||||
import {BitStream} from "bit-buffer";
|
import {BitStream} from "bit-buffer";
|
||||||
import {SendProp} from "../Data/SendProp";
|
import {SendProp} from "../Data/SendProp";
|
||||||
import {SendPropParser} from "./SendPropParser";
|
import {SendPropParser} from "./SendPropParser";
|
||||||
import {readUBitVar} from "./readBitVar";
|
import {readUBitVar} from "./readBitVar";
|
||||||
import {SendTable} from "../Data/SendTable";
|
import {SendTable} from "../Data/SendTable";
|
||||||
|
|
||||||
export function applyEntityUpdate(entity: Entity, stream: BitStream, sendTable?: SendTable): Entity {
|
export function applyEntityUpdate(entity: PacketEntity, sendTable: SendTable, stream: BitStream): PacketEntity {
|
||||||
if (!sendTable) {
|
|
||||||
sendTable = entity.sendTable;
|
|
||||||
}
|
|
||||||
let index = -1;
|
let index = -1;
|
||||||
const allProps = sendTable.flattenedProps;
|
const allProps = sendTable.flattenedProps;
|
||||||
let lastProps:SendProp[] = [];
|
let lastProps:SendProp[] = [];
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import {Entity} from '../../Data/Entity';
|
import {PacketEntity} from '../../Data/PacketEntity';
|
||||||
import {SendProp} from '../../Data/SendProp';
|
import {SendProp} from '../../Data/SendProp';
|
||||||
import {PacketEntitiesPacket} from "../../Data/Packet";
|
import {PacketEntitiesPacket} from "../../Data/Packet";
|
||||||
import {BitStream} from 'bit-buffer';
|
import {BitStream} from 'bit-buffer';
|
||||||
|
|
@ -30,19 +30,16 @@ function readPVSType(stream: BitStream): PVS {
|
||||||
return pvs;
|
return pvs;
|
||||||
}
|
}
|
||||||
|
|
||||||
function readEnterPVS(stream: BitStream, entityId: number, match: Match, baseLine: number): Entity {
|
function readEnterPVS(stream: BitStream, entityId: number, match: Match, baseLine: number): PacketEntity {
|
||||||
// https://github.com/PazerOP/DemoLib/blob/5f9467650f942a4a70f9ec689eadcd3e0a051956/TF2Net/NetMessages/NetPacketEntitiesMessage.cs#L198
|
// https://github.com/PazerOP/DemoLib/blob/5f9467650f942a4a70f9ec689eadcd3e0a051956/TF2Net/NetMessages/NetPacketEntitiesMessage.cs#L198
|
||||||
const serverClass = match.serverClasses[stream.readBits(match.classBits)];
|
const serverClass = match.serverClasses[stream.readBits(match.classBits)];
|
||||||
const sendTable = match.getSendTable(serverClass.dataTable);
|
const sendTable = match.getSendTable(serverClass.dataTable);
|
||||||
const serialNumber = stream.readBits(10);
|
const serialNumber = stream.readBits(10);
|
||||||
if (!sendTable) {
|
if (!sendTable) {
|
||||||
throw new Error('Unknown SendTable for serverclass');
|
throw new Error('Unknown SendTable for serverclass');
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (match.entities[entityId]) {
|
const entity = new PacketEntity(serverClass, sendTable, entityId, serialNumber);
|
||||||
// console.log('overwriting entity');
|
|
||||||
// }
|
|
||||||
const entity = new Entity(serverClass, sendTable, entityId, serialNumber);
|
|
||||||
|
|
||||||
const decodedBaseLine = match.instanceBaselines[baseLine][entityId];
|
const decodedBaseLine = match.instanceBaselines[baseLine][entityId];
|
||||||
if (decodedBaseLine) {
|
if (decodedBaseLine) {
|
||||||
|
|
@ -56,7 +53,7 @@ function readEnterPVS(stream: BitStream, entityId: number, match: Match, baseLin
|
||||||
const staticBaseLine = match.staticBaseLines[serverClass.id];
|
const staticBaseLine = match.staticBaseLines[serverClass.id];
|
||||||
if (staticBaseLine) {
|
if (staticBaseLine) {
|
||||||
staticBaseLine.index = 0;
|
staticBaseLine.index = 0;
|
||||||
applyEntityUpdate(entity, staticBaseLine, sendTable);
|
applyEntityUpdate(entity, sendTable, staticBaseLine);
|
||||||
if (staticBaseLine.bitsLeft > 7) {
|
if (staticBaseLine.bitsLeft > 7) {
|
||||||
// console.log(staticBaseLine.length, staticBaseLine.index);
|
// console.log(staticBaseLine.length, staticBaseLine.index);
|
||||||
// throw new Error('Unexpected data left at the end of staticBaseline, ' + staticBaseLine.bitsLeft + ' bits left');
|
// throw new Error('Unexpected data left at the end of staticBaseline, ' + staticBaseLine.bitsLeft + ' bits left');
|
||||||
|
|
@ -68,7 +65,7 @@ function readEnterPVS(stream: BitStream, entityId: number, match: Match, baseLin
|
||||||
|
|
||||||
function readLeavePVS(match, entityId, shouldDelete) {
|
function readLeavePVS(match, entityId, shouldDelete) {
|
||||||
if (shouldDelete) {
|
if (shouldDelete) {
|
||||||
match.entities[entityId] = null;
|
match.packetEntities[entityId] = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -97,14 +94,15 @@ export function PacketEntities(stream: BitStream, match: Match): PacketEntitiesP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const receivedEntities: PacketEntity[] = [];
|
||||||
for (let i = 0; i < updatedEntries; i++) {
|
for (let i = 0; i < updatedEntries; i++) {
|
||||||
const diff = readUBitVar(stream);
|
const diff = readUBitVar(stream);
|
||||||
entityId += 1 + diff;
|
entityId += 1 + diff;
|
||||||
const pvs = readPVSType(stream);
|
const pvs = readPVSType(stream);
|
||||||
if (pvs === PVS.ENTER) {
|
if (pvs === PVS.ENTER) {
|
||||||
const entity = readEnterPVS(stream, entityId, match, baseLine);
|
const entity = readEnterPVS(stream, entityId, match, baseLine);
|
||||||
applyEntityUpdate(entity, stream);
|
applyEntityUpdate(entity, entity.sendTable, stream);
|
||||||
match.entities[entityId] = entity;
|
match.packetEntities[entityId] = entity;
|
||||||
|
|
||||||
if (updatedBaseLine) {
|
if (updatedBaseLine) {
|
||||||
const newBaseLine: SendProp[] = [];
|
const newBaseLine: SendProp[] = [];
|
||||||
|
|
@ -112,16 +110,18 @@ export function PacketEntities(stream: BitStream, match: Match): PacketEntitiesP
|
||||||
match.instanceBaselines[baseLine][entityId] = newBaseLine;
|
match.instanceBaselines[baseLine][entityId] = newBaseLine;
|
||||||
}
|
}
|
||||||
entity.inPVS = true;
|
entity.inPVS = true;
|
||||||
|
receivedEntities.push(entity);
|
||||||
} else if (pvs === PVS.PRESERVE) {
|
} else if (pvs === PVS.PRESERVE) {
|
||||||
const entity = match.entities[entityId];
|
const entity = match.packetEntities[entityId];
|
||||||
if (entity) {
|
if (entity) {
|
||||||
applyEntityUpdate(entity, stream);
|
applyEntityUpdate(entity, entity.sendTable, stream);
|
||||||
|
receivedEntities.push(entity);
|
||||||
} else {
|
} else {
|
||||||
console.log(entityId, match.entities.length);
|
console.log(entityId, match.packetEntities.length);
|
||||||
throw new Error("unknown entity");
|
throw new Error("unknown entity");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const entity = match.entities[entityId];
|
const entity = match.packetEntities[entityId];
|
||||||
if (entity) {
|
if (entity) {
|
||||||
entity.inPVS = false;
|
entity.inPVS = false;
|
||||||
}
|
}
|
||||||
|
|
@ -131,13 +131,14 @@ export function PacketEntities(stream: BitStream, match: Match): PacketEntitiesP
|
||||||
|
|
||||||
if (isDelta) {
|
if (isDelta) {
|
||||||
while (stream.readBoolean()) {
|
while (stream.readBoolean()) {
|
||||||
const ent = stream.readBits(11);
|
const ent = stream.readBits(11);
|
||||||
match.entities[ent] = null;
|
match.packetEntities[ent] = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stream.index = end;
|
stream.index = end;
|
||||||
return {
|
return {
|
||||||
packetType: 'packetEntities'
|
packetType: 'packetEntities',
|
||||||
|
entities: receivedEntities
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
import {Packet} from "../../Data/Packet";
|
import {Packet} from "../../Data/Packet";
|
||||||
import {BitStream} from 'bit-buffer';
|
import {BitStream} from 'bit-buffer';
|
||||||
import {GameEventDefinitionMap} from "../../Data/GameEvent";
|
|
||||||
import {Match} from "../../Data/Match";
|
import {Match} from "../../Data/Match";
|
||||||
import {Entity} from "../../Data/Entity";
|
|
||||||
|
|
||||||
export type Parser = (stream: BitStream, match?: Match) => Packet;
|
export type Parser = (stream: BitStream, match?: Match) => Packet;
|
||||||
export type PacketParserMap = {[id: number]: Parser};
|
export type PacketParserMap = {[id: number]: Parser};
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import {TempEntitiesPacket} from "../../Data/Packet";
|
import {TempEntitiesPacket} from "../../Data/Packet";
|
||||||
import {BitStream} from 'bit-buffer';
|
import {BitStream} from 'bit-buffer';
|
||||||
import {Match} from "../../Data/Match";
|
import {Match} from "../../Data/Match";
|
||||||
import {Entity} from "../../Data/Entity";
|
import {PacketEntity} from "../../Data/PacketEntity";
|
||||||
import {applyEntityUpdate} from "../EntityDecoder";
|
import {applyEntityUpdate} from "../EntityDecoder";
|
||||||
|
|
||||||
export function TempEntities(stream: BitStream, match: Match): TempEntitiesPacket { // 10: classInfo
|
export function TempEntities(stream: BitStream, match: Match): TempEntitiesPacket { // 10: classInfo
|
||||||
|
|
@ -9,22 +9,23 @@ export function TempEntities(stream: BitStream, match: Match): TempEntitiesPacke
|
||||||
const length = readVarInt(stream);
|
const length = readVarInt(stream);
|
||||||
const end = stream.index + length;
|
const end = stream.index + length;
|
||||||
|
|
||||||
let entity: Entity|null = null;
|
let entity: PacketEntity|null = null;
|
||||||
let entities: Entity[] = [];
|
let entities: PacketEntity[] = [];
|
||||||
for (let i = 0; i < entityCount; i++) {
|
for (let i = 0; i < entityCount; i++) {
|
||||||
const delay = (stream.readBoolean()) ? stream.readUint8() / 100 : 0; //unused it seems
|
const delay = (stream.readBoolean()) ? stream.readUint8() / 100 : 0; //unused it seems
|
||||||
if (stream.readBoolean()) {
|
if (stream.readBoolean()) {
|
||||||
const classId = stream.readBits(match.classBits);
|
const classId = stream.readBits(match.classBits);
|
||||||
const serverClass = match.serverClasses[classId - 1]; // no clue why the -1 but it works
|
const serverClass = match.serverClasses[classId - 1];
|
||||||
// maybe because world (id=0) can never be tem
|
// no clue why the -1 but it works
|
||||||
// but it's not like the -1 saves any space
|
// maybe because world (id=0) can never be temp
|
||||||
const sendTable = match.getSendTable(serverClass.dataTable);
|
// but it's not like the -1 saves any space
|
||||||
entity = new Entity(serverClass, sendTable, 0, 0);
|
const sendTable = match.getSendTable(serverClass.dataTable);
|
||||||
applyEntityUpdate(entity, stream);
|
entity = new PacketEntity(serverClass, sendTable, 0, 0);
|
||||||
|
applyEntityUpdate(entity, sendTable, stream);
|
||||||
entities.push(entity);
|
entities.push(entity);
|
||||||
} else {
|
} else {
|
||||||
if (entity) {
|
if (entity) {
|
||||||
applyEntityUpdate(entity, stream);
|
applyEntityUpdate(entity, entity.sendTable, stream);
|
||||||
} else {
|
} else {
|
||||||
throw new Error("no entity set to update");
|
throw new Error("no entity set to update");
|
||||||
}
|
}
|
||||||
|
|
@ -37,7 +38,7 @@ export function TempEntities(stream: BitStream, match: Match): TempEntitiesPacke
|
||||||
stream.index = end;
|
stream.index = end;
|
||||||
return {
|
return {
|
||||||
packetType: 'tempEntities',
|
packetType: 'tempEntities',
|
||||||
entities: entities
|
entities: entities
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue