mirror of
https://github.com/demostf/demo.js
synced 2026-06-04 00:54:14 +02:00
per packet entities
This commit is contained in:
parent
95b9fb55c7
commit
afa0451a66
6 changed files with 56 additions and 49 deletions
|
|
@ -23,7 +23,6 @@ export class Match {
|
||||||
rounds: any[];
|
rounds: any[];
|
||||||
startTick: number;
|
startTick: number;
|
||||||
intervalPerTick: number;
|
intervalPerTick: number;
|
||||||
packetEntities: (PacketEntity|null)[];
|
|
||||||
stringTables: StringTable[];
|
stringTables: StringTable[];
|
||||||
serverClasses: ServerClass[];
|
serverClasses: ServerClass[];
|
||||||
sendTables: SendTable[];
|
sendTables: SendTable[];
|
||||||
|
|
@ -33,6 +32,7 @@ export class Match {
|
||||||
world: World;
|
world: World;
|
||||||
players: Player[];
|
players: Player[];
|
||||||
playerMap: {[entityId: number]: Player};
|
playerMap: {[entityId: number]: Player};
|
||||||
|
entityClasses: {[entityId: string]: ServerClass};
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.tick = 0;
|
this.tick = 0;
|
||||||
|
|
@ -42,11 +42,9 @@ export class Match {
|
||||||
this.rounds = [];
|
this.rounds = [];
|
||||||
this.startTick = 0;
|
this.startTick = 0;
|
||||||
this.intervalPerTick = 0;
|
this.intervalPerTick = 0;
|
||||||
this.packetEntities = [];
|
|
||||||
this.stringTables = [];
|
this.stringTables = [];
|
||||||
this.sendTables = [];
|
this.sendTables = [];
|
||||||
this.serverClasses = [];
|
this.serverClasses = [];
|
||||||
this.packetEntities = [];
|
|
||||||
this.instanceBaselines = [[], []];
|
this.instanceBaselines = [[], []];
|
||||||
this.staticBaseLines = [];
|
this.staticBaseLines = [];
|
||||||
this.eventDefinitions = {};
|
this.eventDefinitions = {};
|
||||||
|
|
@ -55,7 +53,8 @@ export class Match {
|
||||||
this.world = {
|
this.world = {
|
||||||
boundaryMin: {x: 0, y: 0, z: 0},
|
boundaryMin: {x: 0, y: 0, z: 0},
|
||||||
boundaryMax: {x: 0, y: 0, z: 0}
|
boundaryMax: {x: 0, y: 0, z: 0}
|
||||||
}
|
};
|
||||||
|
this.entityClasses = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
getSendTable(name) {
|
getSendTable(name) {
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@ export interface GameEventListPacket {
|
||||||
export interface PacketEntitiesPacket {
|
export interface PacketEntitiesPacket {
|
||||||
packetType: 'packetEntities';
|
packetType: 'packetEntities';
|
||||||
entities: PacketEntity[];
|
entities: PacketEntity[];
|
||||||
|
removedEntities: number[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ParseSoundsPacket {
|
export interface ParseSoundsPacket {
|
||||||
|
|
|
||||||
|
|
@ -2,23 +2,29 @@ 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 enum PVS {
|
||||||
|
PRESERVE = 0,
|
||||||
|
ENTER = 1,
|
||||||
|
LEAVE = 2,
|
||||||
|
DELETE = 4
|
||||||
|
}
|
||||||
|
|
||||||
export class PacketEntity {
|
export class PacketEntity {
|
||||||
|
pvs: PVS;
|
||||||
serverClass: ServerClass;
|
serverClass: ServerClass;
|
||||||
sendTable: SendTable;
|
|
||||||
entityIndex: number;
|
entityIndex: number;
|
||||||
serialNumber: number;
|
|
||||||
props: SendProp[];
|
props: SendProp[];
|
||||||
inPVS: boolean;
|
inPVS: boolean;
|
||||||
updatedProps: SendProp[];
|
updatedProps: SendProp[];
|
||||||
|
|
||||||
constructor(serverClass: ServerClass, sendTable: SendTable, entityIndex: number, serialNumber: number) {
|
constructor(serverClass: ServerClass, entityIndex: number, pvs: PVS) {
|
||||||
this.serverClass = serverClass;
|
this.serverClass = serverClass;
|
||||||
this.sendTable = sendTable;
|
|
||||||
this.entityIndex = entityIndex;
|
this.entityIndex = entityIndex;
|
||||||
this.serialNumber = serialNumber;
|
|
||||||
this.props = [];
|
this.props = [];
|
||||||
this.inPVS = false;
|
this.inPVS = false;
|
||||||
this.updatedProps = [];
|
this.updatedProps = [];
|
||||||
|
this.pvs = pvs;
|
||||||
}
|
}
|
||||||
|
|
||||||
getPropByDefinition(definition: SendPropDefinition) {
|
getPropByDefinition(definition: SendPropDefinition) {
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,28 @@
|
||||||
import {PacketEntitiesPacket} from "../Data/Packet";
|
import {PacketEntitiesPacket} from "../Data/Packet";
|
||||||
import {Match} from "../Data/Match";
|
import {Match} from "../Data/Match";
|
||||||
import {PacketEntity} from "../Data/PacketEntity";
|
import {PacketEntity, PVS} 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 removedEntityId of packet.removedEntities) {
|
||||||
|
delete match.entityClasses[removedEntityId];
|
||||||
|
}
|
||||||
|
|
||||||
for (const entity of packet.entities) {
|
for (const entity of packet.entities) {
|
||||||
|
saveEntity(entity, match);
|
||||||
handleEntity(entity, match);
|
handleEntity(entity, match);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function saveEntity(packetEntity: PacketEntity, match: Match) {
|
||||||
|
if (packetEntity.pvs === PVS.DELETE) {
|
||||||
|
delete match.entityClasses[packetEntity.entityIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
match.entityClasses[packetEntity.entityIndex] = packetEntity.serverClass;
|
||||||
|
}
|
||||||
|
|
||||||
function handleEntity(entity: PacketEntity, match: Match) {
|
function handleEntity(entity: PacketEntity, match: Match) {
|
||||||
switch (entity.serverClass.name) {
|
switch (entity.serverClass.name) {
|
||||||
case 'CWorld':
|
case 'CWorld':
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import {PacketEntity} from '../../Data/PacketEntity';
|
import {PacketEntity, PVS} 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';
|
||||||
|
|
@ -6,13 +6,6 @@ import {Match} from "../../Data/Match";
|
||||||
import {readUBitVar} from "../readBitVar";
|
import {readUBitVar} from "../readBitVar";
|
||||||
import {applyEntityUpdate} from "../EntityDecoder";
|
import {applyEntityUpdate} from "../EntityDecoder";
|
||||||
|
|
||||||
enum PVS {
|
|
||||||
PRESERVE = 0,
|
|
||||||
ENTER = 1,
|
|
||||||
LEAVE = 2,
|
|
||||||
DELETE = 4
|
|
||||||
}
|
|
||||||
|
|
||||||
function readPVSType(stream: BitStream): PVS {
|
function readPVSType(stream: BitStream): PVS {
|
||||||
// https://github.com/skadistats/smoke/blob/a2954fbe2fa3936d64aee5b5567be294fef228e6/smoke/io/stream/entity.pyx#L24
|
// https://github.com/skadistats/smoke/blob/a2954fbe2fa3936d64aee5b5567be294fef228e6/smoke/io/stream/entity.pyx#L24
|
||||||
let pvs;
|
let pvs;
|
||||||
|
|
@ -34,12 +27,12 @@ function readEnterPVS(stream: BitStream, entityId: number, match: Match, baseLin
|
||||||
// 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); // unused it seems
|
||||||
if (!sendTable) {
|
if (!sendTable) {
|
||||||
throw new Error('Unknown SendTable for serverclass');
|
throw new Error('Unknown SendTable for serverclass');
|
||||||
}
|
}
|
||||||
|
|
||||||
const entity = new PacketEntity(serverClass, sendTable, entityId, serialNumber);
|
const entity = new PacketEntity(serverClass, entityId, PVS.ENTER);
|
||||||
|
|
||||||
const decodedBaseLine = match.instanceBaselines[baseLine][entityId];
|
const decodedBaseLine = match.instanceBaselines[baseLine][entityId];
|
||||||
if (decodedBaseLine) {
|
if (decodedBaseLine) {
|
||||||
|
|
@ -63,10 +56,12 @@ function readEnterPVS(stream: BitStream, entityId: number, match: Match, baseLin
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
function readLeavePVS(match, entityId, shouldDelete) {
|
function getPacketEntityForExisting(entityId: number, match: Match, pvs: PVS) {
|
||||||
if (shouldDelete) {
|
if (!match.entityClasses[entityId]) {
|
||||||
match.packetEntities[entityId] = null;
|
throw new Error("unknown entity");
|
||||||
}
|
}
|
||||||
|
const serverClass = match.entityClasses[entityId];
|
||||||
|
return new PacketEntity(serverClass, entityId, pvs);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PacketEntities(stream: BitStream, match: Match): PacketEntitiesPacket { //26: packetEntities
|
export function PacketEntities(stream: BitStream, match: Match): PacketEntitiesPacket { //26: packetEntities
|
||||||
|
|
@ -100,45 +95,38 @@ export function PacketEntities(stream: BitStream, match: Match): PacketEntitiesP
|
||||||
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 packetEntity = readEnterPVS(stream, entityId, match, baseLine);
|
||||||
applyEntityUpdate(entity, entity.sendTable, stream);
|
applyEntityUpdate(packetEntity, match.getSendTable(packetEntity.serverClass.dataTable), stream);
|
||||||
match.packetEntities[entityId] = entity;
|
|
||||||
|
|
||||||
if (updatedBaseLine) {
|
if (updatedBaseLine) {
|
||||||
const newBaseLine: SendProp[] = [];
|
const newBaseLine: SendProp[] = [];
|
||||||
newBaseLine.concat(entity.props);
|
newBaseLine.concat(packetEntity.props);
|
||||||
match.instanceBaselines[baseLine][entityId] = newBaseLine;
|
match.instanceBaselines[baseLine][entityId] = newBaseLine;
|
||||||
}
|
}
|
||||||
entity.inPVS = true;
|
packetEntity.inPVS = true;
|
||||||
receivedEntities.push(entity);
|
receivedEntities.push(packetEntity);
|
||||||
} else if (pvs === PVS.PRESERVE) {
|
} else if (pvs === PVS.PRESERVE) {
|
||||||
const entity = match.packetEntities[entityId];
|
const packetEntity = getPacketEntityForExisting(entityId, match, pvs);
|
||||||
if (entity) {
|
applyEntityUpdate(packetEntity, match.getSendTable(packetEntity.serverClass.dataTable), stream);
|
||||||
applyEntityUpdate(entity, entity.sendTable, stream);
|
receivedEntities.push(packetEntity);
|
||||||
receivedEntities.push(entity);
|
|
||||||
} else {
|
|
||||||
console.log(entityId, match.packetEntities.length);
|
|
||||||
throw new Error("unknown entity");
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
const entity = match.packetEntities[entityId];
|
const packetEntity = getPacketEntityForExisting(entityId, match, pvs);
|
||||||
if (entity) {
|
receivedEntities.push(packetEntity);
|
||||||
entity.inPVS = false;
|
|
||||||
}
|
|
||||||
readLeavePVS(match, entityId, pvs === PVS.DELETE);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const removedEntityIds: number[] = [];
|
||||||
if (isDelta) {
|
if (isDelta) {
|
||||||
while (stream.readBoolean()) {
|
while (stream.readBoolean()) {
|
||||||
const ent = stream.readBits(11);
|
const entityId = stream.readBits(11);
|
||||||
match.packetEntities[ent] = null;
|
removedEntityIds.push(entityId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stream.index = end;
|
stream.index = end;
|
||||||
return {
|
return {
|
||||||
packetType: 'packetEntities',
|
packetType: 'packetEntities',
|
||||||
entities: receivedEntities
|
entities: receivedEntities,
|
||||||
|
removedEntities: removedEntityIds
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {PacketEntity} from "../../Data/PacketEntity";
|
import {PacketEntity, PVS} 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
|
||||||
|
|
@ -20,12 +20,12 @@ export function TempEntities(stream: BitStream, match: Match): TempEntitiesPacke
|
||||||
// maybe because world (id=0) can never be temp
|
// maybe because world (id=0) can never be temp
|
||||||
// but it's not like the -1 saves any space
|
// but it's not like the -1 saves any space
|
||||||
const sendTable = match.getSendTable(serverClass.dataTable);
|
const sendTable = match.getSendTable(serverClass.dataTable);
|
||||||
entity = new PacketEntity(serverClass, sendTable, 0, 0);
|
entity = new PacketEntity(serverClass, 0, PVS.ENTER);
|
||||||
applyEntityUpdate(entity, sendTable, stream);
|
applyEntityUpdate(entity, sendTable, stream);
|
||||||
entities.push(entity);
|
entities.push(entity);
|
||||||
} else {
|
} else {
|
||||||
if (entity) {
|
if (entity) {
|
||||||
applyEntityUpdate(entity, entity.sendTable, stream);
|
applyEntityUpdate(entity, match.getSendTable(entity.serverClass.dataTable), stream);
|
||||||
} else {
|
} else {
|
||||||
throw new Error("no entity set to update");
|
throw new Error("no entity set to update");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue