1
0
Fork 0
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:
Robin Appelman 2017-02-14 22:12:06 +01:00
commit afa0451a66
6 changed files with 56 additions and 49 deletions

View file

@ -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) {

View file

@ -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 {

View file

@ -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) {

View file

@ -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':

View file

@ -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 { } else {
console.log(entityId, match.packetEntities.length); const packetEntity = getPacketEntityForExisting(entityId, match, pvs);
throw new Error("unknown entity"); receivedEntities.push(packetEntity);
}
} else {
const entity = match.packetEntities[entityId];
if (entity) {
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
}; };
} }

View file

@ -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");
} }