mirror of
https://github.com/demostf/demo.js
synced 2026-06-03 16:44:12 +02:00
extract team and weapon data
This commit is contained in:
parent
6ce96e0e52
commit
5488b14e63
7 changed files with 200 additions and 41 deletions
|
|
@ -14,6 +14,8 @@ import {handleGameEvent} from "../PacketHandler/GameEvent";
|
|||
import {handlePacketEntities} from "../PacketHandler/PacketEntities";
|
||||
import {handleGameEventList} from "../PacketHandler/GameEventList";
|
||||
import {handleDataTable} from "../PacketHandler/DataTable";
|
||||
import {Weapon} from "./Weapon";
|
||||
import {Team} from "./Team";
|
||||
|
||||
export class Match {
|
||||
tick: number;
|
||||
|
|
@ -34,6 +36,10 @@ export class Match {
|
|||
entityClasses: {[entityId: string]: ServerClass};
|
||||
sendTableMap: {[name: string]: SendTable};
|
||||
baseLineCache: {[serverClass: string]: PacketEntity};
|
||||
weaponMap: {[entityId: string]: Weapon};
|
||||
outerMap: {[outer: number]: number};
|
||||
teams: Team[];
|
||||
teamMap: {[entityId: string]: Team};
|
||||
|
||||
constructor() {
|
||||
this.tick = 0;
|
||||
|
|
@ -57,6 +63,10 @@ export class Match {
|
|||
this.entityClasses = {};
|
||||
this.sendTableMap = {};
|
||||
this.baseLineCache = {};
|
||||
this.weaponMap = {};
|
||||
this.outerMap = {};
|
||||
this.teams = [];
|
||||
this.teamMap = {};
|
||||
}
|
||||
|
||||
getSendTable(name) {
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ export class PacketEntity {
|
|||
return prop;
|
||||
}
|
||||
}
|
||||
throw new Error('Property not found in entity');
|
||||
throw new Error(`Property not found in entity (${originTable}.${name})`);
|
||||
}
|
||||
|
||||
clone(): PacketEntity {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,14 @@
|
|||
import {UserInfo} from "./UserInfo";
|
||||
import {Vector} from "./Vector";
|
||||
import {PlayerCondition} from "./PlayerCondition";
|
||||
|
||||
export enum LifeState {
|
||||
ALIVE = 0,
|
||||
DYING = 1,
|
||||
DEATH = 2,
|
||||
RESPAWNABLE = 3
|
||||
}
|
||||
|
||||
export interface Player {
|
||||
user: UserInfo;
|
||||
position: Vector;
|
||||
|
|
@ -9,4 +17,7 @@ export interface Player {
|
|||
classId: number;
|
||||
team: number;
|
||||
viewAngle: number;
|
||||
weapons: number[];
|
||||
ammo: number[];
|
||||
lifeState: LifeState
|
||||
}
|
||||
|
|
|
|||
7
src/Data/Team.ts
Normal file
7
src/Data/Team.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
export interface Team {
|
||||
teamNumber: number;
|
||||
name: string;
|
||||
score: number;
|
||||
roundsWon: number;
|
||||
players: number[];
|
||||
}
|
||||
13
src/Data/Weapon.ts
Normal file
13
src/Data/Weapon.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
export interface BaseCombatWeapon {
|
||||
className: string;
|
||||
owner: number;
|
||||
}
|
||||
|
||||
export interface CWeaponMedigun {
|
||||
className: 'CWeaponMedigun';
|
||||
healTarget: number;
|
||||
chargeLevel: number;
|
||||
}
|
||||
|
||||
export type Weapon = BaseCombatWeapon|
|
||||
CWeaponMedigun;
|
||||
|
|
@ -2,7 +2,8 @@ import {PacketEntitiesPacket} from "../Data/Packet";
|
|||
import {Match} from "../Data/Match";
|
||||
import {PacketEntity, PVS} from "../Data/PacketEntity";
|
||||
import {Vector} from "../Data/Vector";
|
||||
import {Player} from "../Data/Player";
|
||||
import {Player, LifeState} from "../Data/Player";
|
||||
import {CWeaponMedigun, Weapon} from "../Data/Weapon";
|
||||
|
||||
export function handlePacketEntities(packet: PacketEntitiesPacket, match: Match) {
|
||||
for (const removedEntityId of packet.removedEntities) {
|
||||
|
|
@ -24,13 +25,59 @@ function saveEntity(packetEntity: PacketEntity, match: Match) {
|
|||
}
|
||||
|
||||
function handleEntity(entity: PacketEntity, match: Match) {
|
||||
for (const prop of entity.props) {
|
||||
if (prop.definition.ownerTableName === 'DT_AttributeContainer' && prop.definition.name === 'm_hOuter') {
|
||||
if (!match.outerMap[<number>prop.value]) {
|
||||
match.outerMap[<number>prop.value] = entity.entityIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const prop of entity.props) {
|
||||
if (prop.definition.ownerTableName === 'DT_BaseCombatWeapon' && prop.definition.name === 'm_hOwner') {
|
||||
if (!match.weaponMap[entity.entityIndex]) {
|
||||
match.weaponMap[entity.entityIndex] = {
|
||||
className: entity.serverClass.name,
|
||||
owner: <number>prop.value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (entity.serverClass.name) {
|
||||
case 'CWorld':
|
||||
match.world.boundaryMin = <Vector>entity.getProperty('DT_WORLD', 'm_WorldMins').value;
|
||||
match.world.boundaryMax = <Vector>entity.getProperty('DT_WORLD', 'm_WorldMaxs').value;
|
||||
break;
|
||||
case 'CTFPlayer':
|
||||
try {
|
||||
/**
|
||||
"DT_TFPlayerScoringDataExclusive.m_iCaptures": 0,
|
||||
"DT_TFPlayerScoringDataExclusive.m_iDefenses": 0,
|
||||
"DT_TFPlayerScoringDataExclusive.m_iKills": 5,
|
||||
"DT_TFPlayerScoringDataExclusive.m_iDeaths": 17,
|
||||
"DT_TFPlayerScoringDataExclusive.m_iSuicides": 7,
|
||||
"DT_TFPlayerScoringDataExclusive.m_iDominations": 0,
|
||||
"DT_TFPlayerScoringDataExclusive.m_iRevenge": 0,
|
||||
"DT_TFPlayerScoringDataExclusive.m_iBuildingsBuilt": 0,
|
||||
"DT_TFPlayerScoringDataExclusive.m_iBuildingsDestroyed": 0,
|
||||
"DT_TFPlayerScoringDataExclusive.m_iHeadshots": 0,
|
||||
"DT_TFPlayerScoringDataExclusive.m_iBackstabs": 0,
|
||||
"DT_TFPlayerScoringDataExclusive.m_iHealPoints": 0,
|
||||
"DT_TFPlayerScoringDataExclusive.m_iInvulns": 0,
|
||||
"DT_TFPlayerScoringDataExclusive.m_iTeleports": 0,
|
||||
"DT_TFPlayerScoringDataExclusive.m_iDamageDone": 847,
|
||||
"DT_TFPlayerScoringDataExclusive.m_iCrits": 0,
|
||||
"DT_TFPlayerScoringDataExclusive.m_iResupplyPoints": 0,
|
||||
"DT_TFPlayerScoringDataExclusive.m_iKillAssists": 0,
|
||||
"DT_TFPlayerScoringDataExclusive.m_iBonusPoints": 0,
|
||||
"DT_TFPlayerScoringDataExclusive.m_iPoints": 6,
|
||||
"DT_TFPlayerSharedLocal.m_nDesiredDisguiseTeam": 0,
|
||||
"DT_TFPlayerSharedLocal.m_nDesiredDisguiseClass": 0,
|
||||
"DT_TFPlayerShared.m_iKillStreak": 0,
|
||||
"DT_BaseCombatCharacter.m_hActiveWeapon": 2097151,
|
||||
"DT_TFPlayerShared.m_flCloakMeter": 100,
|
||||
*/
|
||||
|
||||
const player: Player = (match.playerMap[entity.entityIndex]) ? match.playerMap[entity.entityIndex] : {
|
||||
user: match.getUserInfoForEntity(entity),
|
||||
position: new Vector(0, 0, 0),
|
||||
|
|
@ -38,7 +85,10 @@ function handleEntity(entity: PacketEntity, match: Match) {
|
|||
health: 0,
|
||||
classId: 0,
|
||||
team: 0,
|
||||
viewAngle: 0
|
||||
viewAngle: 0,
|
||||
weapons: [],
|
||||
ammo: [],
|
||||
lifeState: LifeState.DEATH
|
||||
};
|
||||
if (!match.playerMap[entity.entityIndex]) {
|
||||
match.playerMap[entity.entityIndex] = player;
|
||||
|
|
@ -46,6 +96,16 @@ function handleEntity(entity: PacketEntity, match: Match) {
|
|||
}
|
||||
|
||||
for (const prop of entity.props) {
|
||||
if (prop.definition.ownerTableName === 'm_hMyWeapons') {
|
||||
if (prop.value !== 2097151) {
|
||||
player.weapons[parseInt(prop.definition.name, 10)] = <number>prop.value;
|
||||
}
|
||||
}
|
||||
if (prop.definition.ownerTableName === 'm_iAmmo') {
|
||||
if (prop.value > 0) {
|
||||
player.ammo[parseInt(prop.definition.name, 10)] = <number>prop.value;
|
||||
}
|
||||
}
|
||||
const propName = prop.definition.ownerTableName + '.' + prop.definition.name;
|
||||
switch (propName) {
|
||||
case 'DT_BasePlayer.m_iHealth':
|
||||
|
|
@ -74,12 +134,70 @@ function handleEntity(entity: PacketEntity, match: Match) {
|
|||
case 'DT_TFLocalPlayerExclusive.m_angEyeAngles[1]':
|
||||
player.viewAngle = <number>prop.value;
|
||||
break;
|
||||
case 'DT_BasePlayer.m_lifeState':
|
||||
player.lifeState = <number>prop.value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case 'CWeaponMedigun':
|
||||
const weapon = <CWeaponMedigun>match.weaponMap[entity.entityIndex];
|
||||
for (const prop of entity.props) {
|
||||
const propName = prop.definition.ownerTableName + '.' + prop.definition.name;
|
||||
switch (propName) {
|
||||
case 'DT_WeaponMedigun.m_hHealingTarget':
|
||||
weapon.healTarget = <number>prop.value;
|
||||
break;
|
||||
case 'DT_TFWeaponMedigunDataNonLocal.m_flChargeLevel':
|
||||
weapon.chargeLevel = <number>prop.value;
|
||||
break;
|
||||
case 'DT_LocalTFWeaponMedigunData.m_flChargeLevel':
|
||||
weapon.chargeLevel = <number>prop.value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case'CTFTeam':
|
||||
try {
|
||||
const teamId = <number>entity.getProperty('DT_Team', 'm_iTeamNum').value;
|
||||
if (!match.teams[teamId]) {
|
||||
match.teams[teamId] = {
|
||||
name: <string>entity.getProperty('DT_Team', 'm_szTeamname').value,
|
||||
score: <number>entity.getProperty('DT_Team', 'm_iScore').value,
|
||||
roundsWon: <number>entity.getProperty('DT_Team', 'm_iRoundsWon').value,
|
||||
players: <number[]>entity.getProperty('DT_Team', '"player_array"').value,
|
||||
teamNumber: <number>teamId
|
||||
};
|
||||
match.teamMap[entity.entityIndex] = match.teams[teamId];
|
||||
}
|
||||
} catch (e) {
|
||||
const team = match.teamMap[entity.entityIndex];
|
||||
for (const prop of entity.props) {
|
||||
const propName = prop.definition.ownerTableName + '.' + prop.definition.name;
|
||||
switch (propName) {
|
||||
case 'DT_Team.m_iScore':
|
||||
team.score = <number>prop.value;
|
||||
break;
|
||||
case 'DT_Team.m_szTeamname':
|
||||
team.name = <string>prop.value;
|
||||
break;
|
||||
case 'DT_Team.m_iRoundsWon':
|
||||
team.roundsWon = <number>prop.value;
|
||||
break;
|
||||
case 'DT_Team."player_array"':
|
||||
team.players = <number[]>prop.value;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
// process.exit();
|
||||
}
|
||||
break;
|
||||
case 'CTFPlayerResource':
|
||||
break;
|
||||
case 'CObjectSentrygun':
|
||||
break;
|
||||
case 'CTeamRoundTimer':
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ export class SendPropParser {
|
|||
if (value instanceof Array) {
|
||||
throw new Error('Nested arrays not supported');
|
||||
}
|
||||
values.push();
|
||||
values.push(value);
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue