mirror of
https://github.com/demostf/demo.js
synced 2026-06-04 00:54:14 +02:00
parse deaths and strictly type packet types
This commit is contained in:
parent
1a71b65f12
commit
cb02fdee9b
18 changed files with 217 additions and 119 deletions
7
src/Data/Death.ts
Normal file
7
src/Data/Death.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
export interface Death {
|
||||
weapon: string;
|
||||
victim: number;
|
||||
assister: number;
|
||||
killer: number;
|
||||
tick: number;
|
||||
}
|
||||
|
|
@ -9,11 +9,13 @@ import {UserInfo} from "./UserInfo";
|
|||
import {World} from "./World";
|
||||
import {Vector} from "./Vector";
|
||||
import {Player} from "./Player";
|
||||
import {Death} from "./Death";
|
||||
import {HandlerMap} from "../PacketHandler/Handler";
|
||||
export class Match {
|
||||
tick: number;
|
||||
chat: any[];
|
||||
users: UserInfo[];
|
||||
deaths: any[];
|
||||
deaths: Death[];
|
||||
rounds: any[];
|
||||
startTick: number;
|
||||
intervalPerTick: number;
|
||||
|
|
@ -53,18 +55,18 @@ export class Match {
|
|||
}
|
||||
|
||||
getSendTable(name) {
|
||||
for (var i = 0; i < this.sendTables.length; i++) {
|
||||
if (this.sendTables[i].name === name) {
|
||||
return this.sendTables[i];
|
||||
for (const table of this.sendTables) {
|
||||
if (table.name === name) {
|
||||
return table;
|
||||
}
|
||||
}
|
||||
throw new Error("unknown SendTable " + name);
|
||||
}
|
||||
|
||||
getStringTable(name) {
|
||||
for (var i = 0; i < this.stringTables.length; i++) {
|
||||
if (this.stringTables[i].name === name) {
|
||||
return this.stringTables[i];
|
||||
for (const table of this.stringTables) {
|
||||
if (table.name === name) {
|
||||
return table;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
|
@ -112,10 +114,10 @@ export class Match {
|
|||
if (table.name === 'userinfo') {
|
||||
for (const userData of table.entries) {
|
||||
if (userData.extraData) {
|
||||
if (userData.extraData.bitsLeft > (32*8)) {
|
||||
const name = userData.extraData.readUTF8String(32);
|
||||
const userId = userData.extraData.readUint32();
|
||||
const steamId = userData.extraData.readUTF8String();
|
||||
if (userData.extraData.bitsLeft > (32 * 8)) {
|
||||
const name = userData.extraData.readUTF8String(32);
|
||||
const userId = userData.extraData.readUint32();
|
||||
const steamId = userData.extraData.readUTF8String();
|
||||
if (steamId) {
|
||||
const userState = this.getUserInfo(userId);
|
||||
userState.name = name;
|
||||
|
|
@ -163,13 +165,12 @@ export class Match {
|
|||
case 'player_spawn':
|
||||
const userId = packet.event.values.userid;
|
||||
const userState = this.getUserInfo(userId);
|
||||
const player = this.playerMap[userState.entityId];
|
||||
if (!userState.team) { //only register first spawn
|
||||
userState.team = packet.event.values.team === 2 ? 'red' : 'blue'
|
||||
}
|
||||
const classId = packet.event.values.class;
|
||||
const player = this.playerMap[userState.entityId];
|
||||
userState.team = packet.event.values.team === 2 ? 'red' : 'blue';
|
||||
const classId = packet.event.values.class;
|
||||
if (player) {
|
||||
player.classId = classId;
|
||||
player.team = packet.event.values.team;
|
||||
}
|
||||
if (!userState.classes[classId]) {
|
||||
userState.classes[classId] = 0;
|
||||
|
|
@ -209,6 +210,15 @@ export class Match {
|
|||
throw new Error('User not found for entity ' + entity.entityIndex);
|
||||
}
|
||||
|
||||
getPlayerByUserId(userId: number): Player {
|
||||
for (const player of this.players) {
|
||||
if (player.user.userId === userId) {
|
||||
return player;
|
||||
}
|
||||
}
|
||||
throw new Error('player not found for user id');
|
||||
}
|
||||
|
||||
get classBits() {
|
||||
return Math.ceil(Math.log(this.serverClasses.length) * Math.LOG2E)
|
||||
}
|
||||
|
|
@ -220,42 +230,48 @@ export class Match {
|
|||
this.world.boundaryMax = <Vector>entity.getProperty('DT_WORLD', 'm_WorldMaxs').value;
|
||||
break;
|
||||
case 'CTFPlayer':
|
||||
const player: Player = (this.playerMap[entity.entityIndex]) ? this.playerMap[entity.entityIndex] : {
|
||||
user: this.getUserInfoForEntity(entity),
|
||||
position: new Vector(0, 0, 0),
|
||||
maxHealth: 0,
|
||||
health: 0,
|
||||
};
|
||||
if (!this.playerMap[entity.entityIndex]) {
|
||||
this.playerMap[entity.entityIndex] = player;
|
||||
this.players.push(player);
|
||||
}
|
||||
|
||||
for (const prop of entity.updatedProps) {
|
||||
const propName = prop.definition.ownerTableName + '.' + prop.definition.name;
|
||||
// console.log(propName, prop.value);
|
||||
switch (propName) {
|
||||
case 'DT_BasePlayer.m_iHealth':
|
||||
player.health = <number>prop.value;
|
||||
break;
|
||||
case 'DT_BasePlayer.m_iMaxHealth':
|
||||
player.maxHealth = <number>prop.value;
|
||||
break;
|
||||
case 'DT_TFLocalPlayerExclusive.m_vecOrigin':
|
||||
player.position.x = (<Vector>prop.value).x;
|
||||
player.position.y = (<Vector>prop.value).y;
|
||||
break;
|
||||
case 'DT_TFNonLocalPlayerExclusive.m_vecOrigin':
|
||||
player.position.x = (<Vector>prop.value).x;
|
||||
player.position.y = (<Vector>prop.value).y;
|
||||
break;
|
||||
case 'DT_TFLocalPlayerExclusive.m_vecOrigin[2]':
|
||||
player.position.z = <number>prop.value;
|
||||
break;
|
||||
case 'DT_TFNonLocalPlayerExclusive.m_vecOrigin[2]':
|
||||
player.position.z = <number>prop.value;
|
||||
break;
|
||||
try {
|
||||
const player: Player = (this.playerMap[entity.entityIndex]) ? this.playerMap[entity.entityIndex] : {
|
||||
user: this.getUserInfoForEntity(entity),
|
||||
position: new Vector(0, 0, 0),
|
||||
maxHealth: 0,
|
||||
health: 0,
|
||||
classId: 0,
|
||||
team: 0
|
||||
};
|
||||
if (!this.playerMap[entity.entityIndex]) {
|
||||
this.playerMap[entity.entityIndex] = player;
|
||||
this.players.push(player);
|
||||
}
|
||||
|
||||
for (const prop of entity.updatedProps) {
|
||||
const propName = prop.definition.ownerTableName + '.' + prop.definition.name;
|
||||
// console.log(propName, prop.value);
|
||||
switch (propName) {
|
||||
case 'DT_BasePlayer.m_iHealth':
|
||||
player.health = <number>prop.value;
|
||||
break;
|
||||
case 'DT_BasePlayer.m_iMaxHealth':
|
||||
player.maxHealth = <number>prop.value;
|
||||
break;
|
||||
case 'DT_TFLocalPlayerExclusive.m_vecOrigin':
|
||||
player.position.x = (<Vector>prop.value).x;
|
||||
player.position.y = (<Vector>prop.value).y;
|
||||
break;
|
||||
case 'DT_TFNonLocalPlayerExclusive.m_vecOrigin':
|
||||
player.position.x = (<Vector>prop.value).x;
|
||||
player.position.y = (<Vector>prop.value).y;
|
||||
break;
|
||||
case 'DT_TFLocalPlayerExclusive.m_vecOrigin[2]':
|
||||
player.position.z = <number>prop.value;
|
||||
break;
|
||||
case 'DT_TFNonLocalPlayerExclusive.m_vecOrigin[2]':
|
||||
player.position.z = <number>prop.value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,93 @@
|
|||
export interface Packet {
|
||||
packetType: string;
|
||||
[name: string]: any;
|
||||
import {StringTable} from "./StringTable";
|
||||
import {Vector} from "./Vector";
|
||||
import {GameEvent} from "./GameEvent";
|
||||
|
||||
export interface StringTablePacket {
|
||||
packetType: 'stringTable';
|
||||
tables: StringTable[];
|
||||
}
|
||||
|
||||
export interface BSPDecalPacket {
|
||||
packetType: 'bspDecal';
|
||||
position: Vector;
|
||||
textureIndex: number;
|
||||
entIndex: number;
|
||||
modelIndex: number;
|
||||
lowPriority: boolean;
|
||||
}
|
||||
|
||||
export interface ClassInfoPacket {
|
||||
packetType: 'classInfo';
|
||||
number: number;
|
||||
create: boolean;
|
||||
entries: {
|
||||
classId: number;
|
||||
className: string;
|
||||
dataTableName: string;
|
||||
}[]
|
||||
}
|
||||
|
||||
export interface EntityMessagePacket {
|
||||
packetType: 'entityMessage';
|
||||
classId: number;
|
||||
length: number;
|
||||
data: string;
|
||||
}
|
||||
|
||||
export interface GameEventPacket {
|
||||
packetType: 'gameEvent';
|
||||
event: GameEvent;
|
||||
}
|
||||
|
||||
export interface GameEventListPacket {
|
||||
packetType: 'gameEventList';
|
||||
}
|
||||
|
||||
export interface PacketEntitiesPacket {
|
||||
packetType: 'packetEntities';
|
||||
}
|
||||
|
||||
export interface ParseSoundsPacket {
|
||||
packetType: 'parseSounds';
|
||||
reliable: boolean;
|
||||
num: number;
|
||||
length: number;
|
||||
}
|
||||
|
||||
export interface SetConVarPacket {
|
||||
packetType: 'setConVar';
|
||||
vars: {[key: string]: string};
|
||||
}
|
||||
|
||||
export interface SayText2Packet {
|
||||
packetType: 'sayText2';
|
||||
client: number;
|
||||
raw: number;
|
||||
kind: string;
|
||||
from: string;
|
||||
text: string;
|
||||
}
|
||||
|
||||
export interface TextMessagePacket {
|
||||
packetType: 'textMsg';
|
||||
destType: number;
|
||||
text: string;
|
||||
}
|
||||
|
||||
export interface UnknownUserMessagePacket {
|
||||
packetType: 'unknownUserMessage';
|
||||
type: number;
|
||||
}
|
||||
|
||||
export type UserMessagePacket = SayText2Packet | TextMessagePacket | UnknownUserMessagePacket;
|
||||
|
||||
export type Packet = BSPDecalPacket |
|
||||
StringTablePacket |
|
||||
ClassInfoPacket |
|
||||
EntityMessagePacket |
|
||||
GameEventPacket |
|
||||
GameEventListPacket |
|
||||
PacketEntitiesPacket |
|
||||
ParseSoundsPacket |
|
||||
SetConVarPacket |
|
||||
UserMessagePacket;
|
||||
|
|
|
|||
|
|
@ -6,4 +6,5 @@ export interface Player {
|
|||
health: number;
|
||||
maxHealth: number;
|
||||
classId: number;
|
||||
team: number;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue