1
0
Fork 0
mirror of https://github.com/demostf/demo.js synced 2026-06-04 00:54:14 +02:00

add explicit tick function to step trough demos

This commit is contained in:
Robin Appelman 2017-02-11 17:47:42 +01:00
commit 58852ffac7
3 changed files with 58 additions and 22 deletions

View file

@ -5,10 +5,11 @@ import {StringTable} from "./StringTable";
import {SendProp} from "./SendProp"; import {SendProp} from "./SendProp";
import {GameEventDefinitionMap} from "./GameEvent"; import {GameEventDefinitionMap} from "./GameEvent";
import {BitStream} from "bit-buffer"; import {BitStream} from "bit-buffer";
import {UserInfo} from "./UserInfo";
export class Match { export class Match {
tick: number; tick: number;
chat: any[]; chat: any[];
users: any; users: UserInfo[];
deaths: any[]; deaths: any[];
rounds: any[]; rounds: any[];
startTick: number; startTick: number;
@ -24,7 +25,7 @@ export class Match {
constructor() { constructor() {
this.tick = 0; this.tick = 0;
this.chat = []; this.chat = [];
this.users = {}; this.users = [];
this.deaths = []; this.deaths = [];
this.rounds = []; this.rounds = [];
this.startTick = 0; this.startTick = 0;
@ -69,9 +70,16 @@ export class Match {
} }
handlePacket(packet) { handlePacket(packet) {
var userState;
switch (packet.packetType) { switch (packet.packetType) {
case 'packetEntities': case 'packetEntities':
for (const entity of this.entities) {
if (entity && entity.serverClass.name === 'CTFPlayer') {
// console.log(entity.props.map((prop: SendProp) => {
// return prop.definition.ownerTableName + '.' + prop.definition.name;
// }));
// console.log(this.getUserInfoForEntity(entity).name);
}
}
break; break;
case 'netTick': case 'netTick':
if (this.startTick === 0) { if (this.startTick === 0) {
@ -98,9 +106,10 @@ export class Match {
const name = userData.extraData.readUTF8String(32); const name = userData.extraData.readUTF8String(32);
const userId = userData.extraData.readUint32(); const userId = userData.extraData.readUint32();
const steamId = userData.extraData.readUTF8String(); const steamId = userData.extraData.readUTF8String();
userState = this.getUserState(userId); const userState = this.getUserInfo(userId);
userState.name = name; userState.name = name;
userState.steamId = steamId; userState.steamId = steamId;
userState.entityId = parseInt(userData.text, 10) + 1;
} }
} }
} }
@ -112,8 +121,8 @@ export class Match {
while (packet.event.values.assister > 256 && packet.event.values.assister < (1024 * 16)) { while (packet.event.values.assister > 256 && packet.event.values.assister < (1024 * 16)) {
packet.event.values.assister -= 256; packet.event.values.assister -= 256;
} }
var assister = packet.event.values.assister < 256 ? packet.event.values.assister : null; const assister = packet.event.values.assister < 256 ? packet.event.values.assister : null;
// todo get player names, not same id as the name string table // todo get player names, not same id as the name string table (entity id)
while (packet.event.values.attacker > 256) { while (packet.event.values.attacker > 256) {
packet.event.values.attacker -= 256; packet.event.values.attacker -= 256;
} }
@ -139,7 +148,7 @@ export class Match {
break; break;
case 'player_spawn': case 'player_spawn':
const userId = packet.event.values.userid; const userId = packet.event.values.userid;
userState = this.getUserState(userId); const userState = this.getUserInfo(userId);
if (!userState.team) { //only register first spawn if (!userState.team) { //only register first spawn
userState.team = packet.event.values.team === 2 ? 'red' : 'blue' userState.team = packet.event.values.team === 2 ? 'red' : 'blue'
} }
@ -154,7 +163,7 @@ export class Match {
} }
} }
getUserState(userId) { getUserInfo(userId: number): UserInfo {
// no clue why it does this // no clue why it does this
// only seems to be the case with per user ready // only seems to be the case with per user ready
while (userId > 256) { while (userId > 256) {
@ -162,15 +171,26 @@ export class Match {
} }
if (!this.users[userId]) { if (!this.users[userId]) {
this.users[userId] = { this.users[userId] = {
name: null, name: '',
userId: userId, userId: userId,
steamId: null, steamId: '',
classes: {} classes: {},
entityId: 0,
team: ''
} }
} }
return this.users[userId]; return this.users[userId];
} }
getUserInfoForEntity(entity: Entity): UserInfo {
for (const user of this.users) {
if (user && user.entityId === entity.entityIndex) {
return user;
}
}
throw new Error('User not found for entity ' + entity.entityIndex);
}
get classBits() { get classBits() {
return Math.ceil(Math.log(this.serverClasses.length) * Math.LOG2E) return Math.ceil(Math.log(this.serverClasses.length) * Math.LOG2E)
} }

8
src/Data/UserInfo.ts Normal file
View file

@ -0,0 +1,8 @@
export interface UserInfo {
name: string
userId: number;
steamId: string;
entityId: number;
classes: any;
team: string;
}

View file

@ -46,16 +46,24 @@ export class Parser extends EventEmitter {
} }
parseBody() { parseBody() {
let message; let hasNext = true;
while (message = this.readMessage(this.stream, this.match)) { while (hasNext) {
if (message instanceof MessageParser) { hasNext = this.tick();
this.handleMessage(message);
}
} }
this.emit('done', this.match); this.emit('done', this.match);
return this.match; return this.match;
} }
tick() {
const message = this.readMessage(this.stream, this.match);
if (message instanceof MessageParser) {
this.handleMessage(message);
return true;
} else {
return false;
}
}
parseMessage(data: BitStream, type: MessageType, tick: number, length: number, match: Match): MessageParser { parseMessage(data: BitStream, type: MessageType, tick: number, length: number, match: Match): MessageParser {
switch (type) { switch (type) {