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

add encoder for gameEvent

This commit is contained in:
Robin Appelman 2017-09-04 00:42:11 +02:00
commit 2e43f5bb7f
9 changed files with 802 additions and 118 deletions

View file

@ -30,7 +30,9 @@ fs.readFile(argv._[0], function (err, data) {
.map(createEventDefinition)
.join('\n\n')
+ '\n\n' + createEventDefinitionUnion(definitions) + '\n\n'
+ createEventTpeMap(definitions) + '\n';
+ 'export type GameEventType = GameEvent[\'name\'];\n\n'
+ createEventTypeMap(definitions) + '\n\n'
+ createEventTypeIdMap(parser.match.eventDefinitions) + '\n';
console.log(definition);
} else if (argv['event-list']) {
echo(Array.from(parser.match.eventDefinitions.values()));
@ -108,12 +110,21 @@ function createEventDefinitionUnion(definitions) {
+ ';';
}
function createEventTpeMap(definitions) {
function createEventTypeMap(definitions) {
return `export type GameEventTypeMap = {
${definitions.map(definition => ` ${definition.name}: ${getEventTypeName(definition.name)}Event;`).join('\n')}
${definitions.map(definition => ` ${definition.name}: ${getEventTypeName(definition.name)}Event;`).join('\n')}
};`;
}
function createEventTypeIdMap(definitionMap) {
const definitionEntries = Array.from(definitionMap.entries());
return `export type GameEventTypeId = number;
export const GameEventTypeIdMap: Map<GameEventType, GameEventTypeId> = new Map<GameEventType, GameEventTypeId>([
${definitionEntries.map(([typeId, definition]) => ` ['${definition.name}', ${typeId}],`).join('\n')}
]);`;
}
const EventNameReplace = new Map([
['ReplayReplaysavailable', 'ReplayReplaysAvailable'],
['ServerAddban', 'ServerAddBan'],

View file

@ -1,6 +1,6 @@
import {GameEvent} from './GameEventTypes';
import {GameEventType} from './GameEventTypes';
export interface GameEventDefinition<T extends GameEvent['name']> {
export interface GameEventDefinition<T extends GameEventType> {
id: number;
name: T;
entries: GameEventEntry[];

File diff suppressed because it is too large Load diff

View file

@ -20,8 +20,8 @@ import {Weapon} from './Weapon';
import {World} from './World';
import {Round} from './Round';
import {Chat} from './Chat';
import {GameEvent} from './GameEventTypes';
import {Packet} from './Packet';
import {GameEventType} from './GameEventTypes';
export class Match {
public tick: number = 0;
@ -32,7 +32,7 @@ export class Match {
public startTick: number = 0;
public intervalPerTick: number = 0;
public staticBaseLines: BitStream[] = [];
public eventDefinitions: Map<number, GameEventDefinition<GameEvent['name']>> = new Map();
public eventDefinitions: Map<number, GameEventDefinition<GameEventType>> = new Map();
public world: World = {
boundaryMin: {x: 0, y: 0, z: 0},
boundaryMax: {x: 0, y: 0, z: 0},

View file

@ -2,7 +2,7 @@ import {make} from '../Packet/ParserGenerator';
import {EncodeBSPDecal, ParseBSPDecal} from '../Packet/BSPDecal';
import {EncodeClassInfo, ParseClassInfo} from '../Packet/ClassInfo';
import {EncodeCreateStringTable, ParseCreateStringTable} from '../Packet/CreateStringTable';
import {ParseGameEvent} from '../Packet/GameEvent';
import {EncodeGameEvent, ParseGameEvent} from '../Packet/GameEvent';
import {EncodeGameEventList, ParseGameEventList} from '../Packet/GameEventList';
import {ParsePacketEntities} from '../Packet/PacketEntities';
import {PacketHandler, voidEncoder} from '../Packet/Parser';
@ -63,7 +63,7 @@ export class Packet extends Parser {
[PacketTypeId.entityMessage,
make('entityMessage', 'index{11}classId{9}length{11}data{$length}')],
[PacketTypeId.gameEvent,
{parser: ParseGameEvent, encoder: voidEncoder}],
{parser: ParseGameEvent, encoder: EncodeGameEvent}],
[PacketTypeId.packetEntities,
{parser: ParsePacketEntities, encoder: voidEncoder}],
[PacketTypeId.tempEntities,

View file

@ -3,23 +3,19 @@ import {
GameEventDefinition, GameEventEntry,
GameEventValue, GameEventValueType,
} from '../../Data/GameEvent';
import {GameEvent, GameEventType} from '../../Data/GameEventTypes';
import {GameEvent, GameEventType, GameEventTypeIdMap, GameEventTypeMap} from '../../Data/GameEventTypes';
import {Match} from '../../Data/Match';
import {GameEventPacket} from '../../Data/Packet';
function parseGameEvent(eventId: number, stream: BitStream, events: Map<number, GameEventDefinition<GameEventType>>) {
const eventDescription = events.get(eventId);
if (!eventDescription) {
throw new Error('unknown event type');
}
const values: GameEvent['values'] = {};
for (const entry of eventDescription.entries) {
function parseGameEvent<T extends GameEventType>(definition: GameEventDefinition<T>, stream: BitStream) {
const values: GameEventTypeMap[T]['values'] = {};
for (const entry of definition.entries) {
const value = getGameEventValue(stream, entry);
if (value) {
values[entry.name] = value;
}
}
const name = eventDescription.name;
const name = definition.name as T;
return {
name,
@ -27,6 +23,15 @@ function parseGameEvent(eventId: number, stream: BitStream, events: Map<number,
};
}
function encodeGameEvent<T extends GameEventType>(event: GameEventTypeMap[T], definition: GameEventDefinition<T>, stream: BitStream) {
for (const entry of definition.entries) {
const value = event.values[entry.name];
if (value !== null) {
encodeGameEventValue(value, stream, entry);
}
}
}
function getGameEventValue(stream: BitStream, entry: GameEventEntry): GameEventValue | null {
switch (entry.type) {
case GameEventValueType.STRING:
@ -46,14 +51,77 @@ function getGameEventValue(stream: BitStream, entry: GameEventEntry): GameEventV
}
}
function encodeGameEventValue(value: GameEventValue | null, stream: BitStream, entry: GameEventEntry) {
switch (entry.type) {
case GameEventValueType.STRING:
if (typeof value !== 'string') {
throw new Error('Invalid value for game event');
}
return stream.writeASCIIString(value);
case GameEventValueType.FLOAT:
if (typeof value !== 'number') {
throw new Error('Invalid value for game event');
}
return stream.writeFloat32(value);
case GameEventValueType.LONG:
if (typeof value !== 'number') {
throw new Error('Invalid value for game event');
}
return stream.writeUint32(value);
case GameEventValueType.SHORT:
if (typeof value !== 'number') {
throw new Error('Invalid value for game event');
}
return stream.writeUint16(value);
case GameEventValueType.BYTE:
if (typeof value !== 'number') {
throw new Error('Invalid value for game event');
}
return stream.writeUint8(value);
case GameEventValueType.BOOLEAN:
if (typeof value !== 'boolean') {
throw new Error('Invalid value for game event');
}
return stream.writeBoolean(value);
}
}
export function ParseGameEvent(stream: BitStream, match: Match): GameEventPacket { // 25: game event
const length = stream.readBits(11);
const end = stream.index + length;
const eventId = stream.readBits(9);
const event = parseGameEvent(eventId, stream, match.eventDefinitions);
stream.index = end;
const eventData = stream.readBitStream(length);
const eventType = eventData.readBits(9);
const definition = match.eventDefinitions.get(eventType);
if (!definition) {
throw new Error(`Unknown game event type ${eventType}`);
}
const event = parseGameEvent(definition, eventData);
return {
packetType: 'gameEvent',
event: event as GameEvent,
};
}
export function EncodeGameEvent(packet: GameEventPacket, stream: BitStream, match: Match) {
const lengthStart = stream.index;
stream.index += 11;
const eventId = GameEventTypeIdMap.get(packet.event.name);
if (typeof eventId === 'undefined') {
throw new Error(`Unknown game event type ${packet.event.name}`);
}
const eventDataStart = stream.index;
stream.writeBits(eventId, 9);
const definition = match.eventDefinitions.get(eventId);
if (typeof definition === 'undefined') {
throw new Error(`Unknown game event type ${packet.event.name}`);
}
encodeGameEvent(packet.event, definition, stream);
const eventDataEnd = stream.index;
stream.index = lengthStart;
stream.writeBits(eventDataEnd - eventDataStart, 11);
stream.index = eventDataEnd;
}

View file

@ -1,7 +1,7 @@
import {BitStream} from 'bit-buffer';
import {GameEventDefinition, GameEventEntry} from '../../Data/GameEvent';
import {GameEventListPacket} from '../../Data/Packet';
import {GameEvent} from '../../Data/GameEventTypes';
import {GameEvent, GameEventType} from '../../Data/GameEventTypes';
export function ParseGameEventList(stream: BitStream): GameEventListPacket { // 30: gameEventList
const s = stream.index;
@ -9,7 +9,7 @@ export function ParseGameEventList(stream: BitStream): GameEventListPacket { //
// list of game events and parameters
const numEvents = stream.readBits(9);
const length = stream.readBits(20);
const eventList: Map<number, GameEventDefinition<GameEvent['name']>> = new Map();
const eventList: Map<number, GameEventDefinition<GameEventType>> = new Map();
for (let i = 0; i < numEvents; i++) {
const id = stream.readBits(9);
const name = stream.readASCIIString() as GameEvent['name'];
@ -58,8 +58,8 @@ export function EncodeGameEventList(packet: GameEventListPacket, stream: BitStre
stream.writeBitStream(eventListStream);
}
function getEventListLength(eventList: GameEventDefinition<GameEvent['name']>[]) {
return eventList.reduce((length: number, entry: GameEventDefinition<GameEvent['name']>) => {
function getEventListLength(eventList: GameEventDefinition<GameEventType>[]) {
return eventList.reduce((length: number, entry: GameEventDefinition<GameEventType>) => {
return length +
9 +
(entry.name.length + 1) * 8 +

View file

@ -0,0 +1,45 @@
import {BitStream} from 'bit-buffer';
import {assertEncoder, assertParser, getStream} from './PacketTest';
import {EncodeClassInfo, ParseClassInfo} from '../../../../Parser/Packet/ClassInfo';
import {EncodeGameEvent, ParseGameEvent} from '../../../../Parser/Packet/GameEvent';
import {GameEventPacket} from '../../../../Data/Packet';
import {Match} from '../../../../Data/Match';
import {GameEventTypeIdMap} from '../../../../Data/GameEventTypes';
import {GameEventValueType} from '../../../../Data/GameEvent';
const data = [25, 240, 149, 0, 0];
const expected = {
packetType: 'gameEvent',
event: {
name: 'post_inventory_application',
values: {userid: 9}
}
};
const match = new Match();
match.eventDefinitions.set(190, {
id: 190,
name: 'post_inventory_application',
entries: [{
name: 'userid',
type: GameEventValueType.SHORT
}]
});
const parseEvent = (stream: BitStream) => {
return ParseGameEvent(stream, match);
};
const encodeEvent = (packet: GameEventPacket, stream: BitStream) => {
EncodeGameEvent(packet, stream, match);
};
suite('GameEvent', () => {
test('Parse gameEvent', () => {
assertParser(parseEvent, getStream(data), expected, 36);
});
test('Encode gameEvent', () => {
assertEncoder(parseEvent, encodeEvent, expected, 36);
});
});

View file

@ -43,12 +43,12 @@ const expected = {
substitute4: '',
};
suite('SayText2', () => {
test('Parse sayText2', () => {
suite('UserMessage', () => {
test('Parse userMessage', () => {
assertParser(ParseUserMessage, getStream(data), expected, 219);
});
test('Encode sayText2', () => {
test('Encode userMessage', () => {
assertEncoder(ParseUserMessage, EncodeUserMessage, expected, 219);
});
});