1
0
Fork 0
mirror of https://github.com/demostf/demo.js synced 2026-06-03 16:44:12 +02:00

more building data

This commit is contained in:
Robin Appelman 2017-03-04 21:56:23 +01:00
commit dea2d2e790
7 changed files with 370 additions and 6 deletions

40
src/Data/Building.ts Normal file
View 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;

View file

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

View file

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

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

View file

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

View file

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

View file

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