mirror of
https://github.com/demostf/demo.js
synced 2026-06-04 00:54:14 +02:00
more building data
This commit is contained in:
parent
eebc2e15cd
commit
dea2d2e790
7 changed files with 370 additions and 6 deletions
40
src/Data/Building.ts
Normal file
40
src/Data/Building.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import {Vector} from "./Vector";
|
||||
|
||||
export interface BaseBuilding {
|
||||
builder: number;
|
||||
position: Vector;
|
||||
level: number;
|
||||
maxHealth: number;
|
||||
health: number;
|
||||
isBuilding: boolean;
|
||||
isSapped: boolean;
|
||||
team: number;
|
||||
}
|
||||
|
||||
export interface Sentry extends BaseBuilding {
|
||||
type: 'sentry';
|
||||
shieldLevel: number;
|
||||
playerControlled: boolean;
|
||||
autoAimTarget: number;
|
||||
ammoShells: number;
|
||||
ammoRockets: number;
|
||||
isMini: boolean;
|
||||
}
|
||||
|
||||
export interface Dispenser extends BaseBuilding {
|
||||
type: 'dispenser';
|
||||
healing: number[];
|
||||
metal: number;
|
||||
}
|
||||
|
||||
export interface Teleporter extends BaseBuilding {
|
||||
type: 'teleporter';
|
||||
isEntrance: boolean;
|
||||
otherEnd: number;
|
||||
rechargeTime: number;
|
||||
rechargeDuration: number;
|
||||
timesUsed: number;
|
||||
yawToExit: number;
|
||||
}
|
||||
|
||||
export type Building = Sentry | Dispenser | Teleporter;
|
||||
|
|
@ -43,6 +43,15 @@ export interface PlayerSpawnEventValues {
|
|||
'class': number
|
||||
}
|
||||
|
||||
export interface ObjectDestroyedValues {
|
||||
userid: number;
|
||||
attacker: number;
|
||||
weapon: string;
|
||||
weapinid: number;
|
||||
objecttype: number;
|
||||
index: number;
|
||||
}
|
||||
|
||||
export type GameEventValue = string|number|boolean;
|
||||
|
||||
export type GameEventValueMap = {
|
||||
|
|
@ -52,7 +61,8 @@ export type GameEventValueMap = {
|
|||
export type GameEventValues = GameEventValueMap |
|
||||
DeathEventValues |
|
||||
RoundWinEventValues |
|
||||
PlayerSpawnEventValues;
|
||||
PlayerSpawnEventValues |
|
||||
ObjectDestroyedValues;
|
||||
|
||||
export type GameEventDefinitionMap = {
|
||||
[id: number]: GameEventDefinition;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ import {handleGameEventList} from "../PacketHandler/GameEventList";
|
|||
import {handleDataTable} from "../PacketHandler/DataTable";
|
||||
import {Weapon} from "./Weapon";
|
||||
import {Team} from "./Team";
|
||||
import {Building} from "./Building";
|
||||
import {PlayerResource} from "./PlayerResource";
|
||||
|
||||
export class Match {
|
||||
tick: number;
|
||||
|
|
@ -40,6 +42,9 @@ export class Match {
|
|||
outerMap: {[outer: number]: number};
|
||||
teams: Team[];
|
||||
teamMap: {[entityId: string]: Team};
|
||||
version: number;
|
||||
buildings: {[entityId: string]: Building} = {};
|
||||
playerResources: PlayerResource[] = [];
|
||||
|
||||
constructor() {
|
||||
this.tick = 0;
|
||||
|
|
@ -67,6 +72,7 @@ export class Match {
|
|||
this.outerMap = {};
|
||||
this.teams = [];
|
||||
this.teamMap = {};
|
||||
this.version = 0;
|
||||
}
|
||||
|
||||
getSendTable(name) {
|
||||
|
|
@ -131,6 +137,7 @@ export class Match {
|
|||
break;
|
||||
case 'serverInfo':
|
||||
this.intervalPerTick = packet.intervalPerTick;
|
||||
this.version = packet.version;
|
||||
break;
|
||||
case 'sayText2':
|
||||
handleSayText2(packet, this);
|
||||
|
|
|
|||
25
src/Data/PlayerResource.ts
Normal file
25
src/Data/PlayerResource.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
export interface PlayerResource {
|
||||
ping: number;
|
||||
score: number;
|
||||
deaths: number;
|
||||
connected: boolean;
|
||||
team: number;
|
||||
alive: boolean;
|
||||
health: number;
|
||||
totalScore: number;
|
||||
maxHealth: number;
|
||||
maxBuffedHealth: number;
|
||||
playerClass: number;
|
||||
arenaSpectator: boolean;
|
||||
dominations: number;
|
||||
nextRespawn: number;
|
||||
chargeLevel: number;
|
||||
damage: number;
|
||||
damageAssists: number;
|
||||
healing: number;
|
||||
healingAssist: number;
|
||||
damageBlocked: number;
|
||||
bonusPoints: number;
|
||||
playerLevel: number;
|
||||
killStreak: number;
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import {GameEventPacket} from "../Data/Packet";
|
||||
import {Match} from "../Data/Match";
|
||||
import {DeathEventValues, RoundWinEventValues, PlayerSpawnEventValues} from "../Data/GameEvent";
|
||||
import {DeathEventValues, RoundWinEventValues, PlayerSpawnEventValues, ObjectDestroyedValues} from "../Data/GameEvent";
|
||||
|
||||
export function handleGameEvent(packet: GameEventPacket, match: Match) {
|
||||
switch (packet.event.name) {
|
||||
|
|
@ -54,5 +54,9 @@ export function handleGameEvent(packet: GameEventPacket, match: Match) {
|
|||
userState.classes[classId]++;
|
||||
}
|
||||
break;
|
||||
case 'object_destroyed':{
|
||||
const values = <ObjectDestroyedValues>packet.event.values;
|
||||
delete match.buildings[values.index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ import {PacketEntity, PVS} from "../Data/PacketEntity";
|
|||
import {Vector} from "../Data/Vector";
|
||||
import {Player, LifeState} from "../Data/Player";
|
||||
import {CWeaponMedigun, Weapon} from "../Data/Weapon";
|
||||
import {Building, Sentry, Dispenser, Teleporter} from "../Data/Building";
|
||||
import {SendProp} from "../Data/SendProp";
|
||||
|
||||
export function handlePacketEntities(packet: PacketEntitiesPacket, match: Match) {
|
||||
for (const removedEntityId of packet.removedEntities) {
|
||||
|
|
@ -189,11 +191,285 @@ function handleEntity(entity: PacketEntity, match: Match) {
|
|||
// process.exit();
|
||||
}
|
||||
break;
|
||||
case 'CTFPlayerResource':
|
||||
break;
|
||||
case 'CObjectSentrygun':
|
||||
if (!match.buildings[entity.entityIndex]) {
|
||||
match.buildings[entity.entityIndex] = {
|
||||
type: 'sentry',
|
||||
ammoRockets: 0,
|
||||
ammoShells: 0,
|
||||
autoAimTarget: 0,
|
||||
builder: 0,
|
||||
health: 0,
|
||||
isBuilding: false,
|
||||
isSapped: false,
|
||||
level: 0,
|
||||
maxHealth: 0,
|
||||
playerControlled: false,
|
||||
position: new Vector(0, 0, 0),
|
||||
shieldLevel: 0,
|
||||
isMini: false,
|
||||
team: 0
|
||||
};
|
||||
}
|
||||
const sentry = <Sentry>match.buildings[entity.entityIndex];
|
||||
for (const prop of entity.props) {
|
||||
const propName = prop.definition.ownerTableName + '.' + prop.definition.name;
|
||||
applyBuildingProp(sentry, prop, propName);
|
||||
switch (propName) {
|
||||
case 'DT_ObjectSentrygun.m_bPlayerControlled':
|
||||
sentry.playerControlled = <number>prop.value > 0;
|
||||
break;
|
||||
case 'DT_ObjectSentrygun.m_hAutoAimTarget':
|
||||
sentry.autoAimTarget = <number>prop.value;
|
||||
break;
|
||||
case 'DT_ObjectSentrygun.m_nShieldLevel':
|
||||
sentry.shieldLevel = <number>prop.value;
|
||||
break;
|
||||
case 'DT_ObjectSentrygun.m_iAmmoShells':
|
||||
sentry.ammoShells = <number>prop.value;
|
||||
break;
|
||||
case 'DT_ObjectSentrygun.m_iAmmoRockets':
|
||||
sentry.ammoRockets = <number>prop.value;
|
||||
break;
|
||||
case 'DT_BaseObject.m_bMiniBuilding':
|
||||
sentry.isMini = <number>prop.value > 1;
|
||||
}
|
||||
}
|
||||
if (entity.pvs & PVS.LEAVE) {
|
||||
delete match.buildings[entity.entityIndex];
|
||||
}
|
||||
break;
|
||||
case 'CObjectDispenser':
|
||||
if (!match.buildings[entity.entityIndex]) {
|
||||
match.buildings[entity.entityIndex] = {
|
||||
type: 'dispenser',
|
||||
builder: 0,
|
||||
health: 0,
|
||||
isBuilding: false,
|
||||
isSapped: false,
|
||||
level: 0,
|
||||
maxHealth: 0,
|
||||
position: new Vector(0, 0, 0),
|
||||
team: 0,
|
||||
healing: [],
|
||||
metal: 0
|
||||
};
|
||||
}
|
||||
const dispenser = <Dispenser>match.buildings[entity.entityIndex];
|
||||
for (const prop of entity.props) {
|
||||
const propName = prop.definition.ownerTableName + '.' + prop.definition.name;
|
||||
applyBuildingProp(dispenser, prop, propName);
|
||||
switch (propName) {
|
||||
case 'DT_ObjectDispenser.m_iAmmoMetal':
|
||||
dispenser.metal = <number>prop.value;
|
||||
break;
|
||||
case 'DT_ObjectDispenser."healing_array"':
|
||||
dispenser.healing = <number[]>prop.value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (entity.pvs & PVS.LEAVE) {
|
||||
delete match.buildings[entity.entityIndex];
|
||||
}
|
||||
break;
|
||||
case 'CObjectTeleporter':
|
||||
if (!match.buildings[entity.entityIndex]) {
|
||||
match.buildings[entity.entityIndex] = {
|
||||
type: 'teleporter',
|
||||
builder: 0,
|
||||
health: 0,
|
||||
isBuilding: false,
|
||||
isSapped: false,
|
||||
level: 0,
|
||||
maxHealth: 0,
|
||||
position: new Vector(0, 0, 0),
|
||||
team: 0,
|
||||
isEntrance: false,
|
||||
otherEnd: 0,
|
||||
rechargeTime: 0,
|
||||
rechargeDuration: 0,
|
||||
timesUsed: 0,
|
||||
yawToExit: 0
|
||||
};
|
||||
}
|
||||
const teleporter = <Teleporter>match.buildings[entity.entityIndex];
|
||||
for (const prop of entity.props) {
|
||||
const propName = prop.definition.ownerTableName + '.' + prop.definition.name;
|
||||
applyBuildingProp(teleporter, prop, propName);
|
||||
switch (propName) {
|
||||
case 'DT_ObjectTeleporter.m_flRechargeTime':
|
||||
teleporter.rechargeTime = <number>prop.value;
|
||||
break;
|
||||
case 'DT_ObjectTeleporter.m_flCurrentRechargeDuration':
|
||||
teleporter.rechargeDuration = <number>prop.value;
|
||||
break;
|
||||
case 'DT_ObjectTeleporter.m_iTimesUsed':
|
||||
teleporter.timesUsed = <number>prop.value;
|
||||
break;
|
||||
case 'DT_ObjectTeleporter.m_bMatchBuilding':
|
||||
teleporter.otherEnd = <number>prop.value;
|
||||
break;
|
||||
case 'DT_ObjectTeleporter.m_flYawToExit':
|
||||
if (prop.value) {
|
||||
teleporter.isEntrance = true;
|
||||
teleporter.yawToExit = <number>prop.value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (entity.pvs & PVS.LEAVE) {
|
||||
delete match.buildings[entity.entityIndex];
|
||||
}
|
||||
break;
|
||||
case 'CTFPlayerResource':
|
||||
for (const prop of entity.props) {
|
||||
const playerId = parseInt(prop.definition.name, 10);
|
||||
const value = <number>prop.value;
|
||||
if (!match.playerResources[playerId]) {
|
||||
match.playerResources[playerId] = {
|
||||
alive: false,
|
||||
arenaSpectator: false,
|
||||
bonusPoints: 0,
|
||||
chargeLevel: 0,
|
||||
connected: false,
|
||||
damageAssists: 0,
|
||||
damageBlocked: 0,
|
||||
deaths: 0,
|
||||
dominations: 0,
|
||||
healing: 0,
|
||||
healingAssist: 0,
|
||||
health: 0,
|
||||
killStreak: 0,
|
||||
maxBuffedHealth: 0,
|
||||
maxHealth: 0,
|
||||
nextRespawn: 0,
|
||||
ping: 0,
|
||||
playerClass: 0,
|
||||
playerLevel: 0,
|
||||
score: 0,
|
||||
team: 0,
|
||||
totalScore: 0,
|
||||
damage: 0
|
||||
};
|
||||
}
|
||||
const playerResource = match.playerResources[playerId];
|
||||
switch (prop.definition.ownerTableName) {
|
||||
case 'm_iPing':
|
||||
playerResource.ping = value;
|
||||
break;
|
||||
case 'm_iScore':
|
||||
playerResource.score = value;
|
||||
break;
|
||||
case 'm_iDeaths':
|
||||
playerResource.deaths = value;
|
||||
break;
|
||||
case 'm_bConnected':
|
||||
playerResource.connected = value > 0;
|
||||
break;
|
||||
case 'm_iTeam':
|
||||
playerResource.team = value;
|
||||
break;
|
||||
case'm_bAlive':
|
||||
playerResource.alive = value > 0;
|
||||
break;
|
||||
case 'm_iHealth':
|
||||
playerResource.health = value;
|
||||
break;
|
||||
case 'm_iTotalScore':
|
||||
playerResource.totalScore = value;
|
||||
break;
|
||||
case 'm_iMaxHealth':
|
||||
playerResource.maxHealth = value;
|
||||
break;
|
||||
case 'm_iMaxBuffedHealth':
|
||||
playerResource.maxBuffedHealth = value;
|
||||
break;
|
||||
case 'm_iPlayerClass':
|
||||
playerResource.playerClass = value;
|
||||
break;
|
||||
case 'm_bArenaSpectator':
|
||||
playerResource.arenaSpectator = value > 0;
|
||||
break;
|
||||
case 'm_iActiveDominations':
|
||||
playerResource.dominations = value;
|
||||
break;
|
||||
case 'm_flNextRespawnTime':
|
||||
playerResource.nextRespawn = value;
|
||||
break;
|
||||
case 'm_iChargeLevel':
|
||||
playerResource.chargeLevel = value;
|
||||
break;
|
||||
case 'm_iDamage':
|
||||
playerResource.damage = value;
|
||||
break;
|
||||
case 'm_iDamageAssist':
|
||||
playerResource.damageAssists = value;
|
||||
break;
|
||||
case 'm_iHealing':
|
||||
playerResource.healing = value;
|
||||
break;
|
||||
case 'm_iHealingAssist':
|
||||
playerResource.healingAssist = value;
|
||||
break;
|
||||
case 'm_iDamageBlocked':
|
||||
playerResource.damageBlocked = value;
|
||||
break;
|
||||
case 'm_iBonusPoints':
|
||||
playerResource.bonusPoints = value;
|
||||
break;
|
||||
case 'm_iPlayerLevel':
|
||||
playerResource.playerLevel = value;
|
||||
break;
|
||||
case 'm_iKillstreak':
|
||||
playerResource.killStreak = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'CTeamRoundTimer':
|
||||
break;
|
||||
case 'CLaserDot':
|
||||
// for (const prop of entity.props) {
|
||||
// const propName = prop.definition.ownerTableName + '.' + prop.definition.name;
|
||||
// switch (propName) {
|
||||
// case 'DT_BaseEntity.m_iParentAttachment':
|
||||
// console.log(prop.value);
|
||||
// process.exit();
|
||||
// break;
|
||||
//
|
||||
// }
|
||||
// }
|
||||
// console.log(match.getSendTable(entity.serverClass.dataTable).flattenedProps);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function applyBuildingProp(building: Building, prop: SendProp, propName: string) {
|
||||
switch (propName) {
|
||||
case 'DT_BaseObject.m_iUpgradeLevel':
|
||||
building.level = <number>prop.value;
|
||||
break;
|
||||
case 'DT_BaseObject.m_hBuilder':
|
||||
building.builder = <number>prop.value;
|
||||
break;
|
||||
case 'DT_BaseObject.m_iMaxHealth':
|
||||
building.maxHealth = <number>prop.value;
|
||||
break;
|
||||
case 'DT_BaseObject.m_iHealth':
|
||||
building.health = <number>prop.value;
|
||||
break;
|
||||
case 'DT_BaseObject.m_bBuilding':
|
||||
building.isBuilding = <number>prop.value > 0;
|
||||
break;
|
||||
case 'DT_BaseObject.m_bHasSapper':
|
||||
building.isSapped = <number>prop.value > 0;
|
||||
break;
|
||||
case 'DT_BaseEntity.m_vecOrigin':
|
||||
building.position = <Vector>prop.value;
|
||||
break;
|
||||
case 'DT_BaseEntity.m_iTeamNum':
|
||||
building.team = <number>prop.value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,11 @@ import {make} from './ParserGenerator';
|
|||
|
||||
import {EntityMessagePacket} from "../../Data/Packet";
|
||||
import {BitStream} from 'bit-buffer';
|
||||
import {Match} from "../../Data/Match";
|
||||
|
||||
const baseParser = make('entityMessage', 'index{11}classId{9}length{11}data{$length}');
|
||||
|
||||
export function EntityMessage(stream: BitStream): EntityMessagePacket { // 24: entityMessage
|
||||
return <EntityMessagePacket>baseParser(stream); //todo parse data further?
|
||||
export function EntityMessage(stream: BitStream, match: Match): EntityMessagePacket { // 24: entityMessage
|
||||
const result = <EntityMessagePacket>baseParser(stream); //todo parse data further?
|
||||
return result;
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue