1
0
Fork 0
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:
Robin Appelman 2017-02-22 23:28:18 +01:00
commit 5488b14e63
7 changed files with 200 additions and 41 deletions

View file

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

View file

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

View file

@ -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
View 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
View 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;

View file

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

View file

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