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

better handling of user messages

This commit is contained in:
Robin Appelman 2017-09-27 01:26:27 +02:00
commit 171b5c4049
6 changed files with 86 additions and 45 deletions

View file

@ -85,8 +85,12 @@ export class Match {
this.calculateUserInfo();
}
break;
case 'sayText2':
handleSayText2(packet, this);
case 'userMessage':
switch (packet.userMessageType) {
case 'sayText2':
handleSayText2(packet, this);
break;
}
break;
case 'gameEvent':
handleGameEvent(packet, this);

View file

@ -18,11 +18,11 @@ export enum MessageType {
}
export interface BaseMessage {
tick: number;
rawData: BitStream;
}
export interface PacketMessage extends BaseMessage {
tick: number;
type: MessageType.Packet;
packets: Packet[];
viewOrigin: [Vector, Vector];
@ -36,30 +36,35 @@ export interface PacketMessage extends BaseMessage {
export type SigonMessage = PacketMessage;
export interface SyncTickMessage extends BaseMessage {
tick: number;
type: MessageType.SyncTick;
}
export interface ConsoleCmdMessage extends BaseMessage {
type: MessageType.ConsoleCmd;
command: string;
}
export interface UserCmdMessage extends BaseMessage {
type: MessageType.UserCmd;
sequenceOut: number;
}
export interface DataTablesMessage extends BaseMessage {
type: MessageType.DataTables;
tables: SendTable[];
serverClasses: ServerClass[];
}
export interface StopMessage extends BaseMessage {
type: MessageType.Stop;
}
export interface ConsoleCmdMessage extends BaseMessage {
tick: number;
type: MessageType.ConsoleCmd;
command: string;
}
export interface UserCmdMessage extends BaseMessage {
tick: number;
type: MessageType.UserCmd;
sequenceOut: number;
}
export interface DataTablesMessage extends BaseMessage {
tick: number;
type: MessageType.DataTables;
tables: SendTable[];
serverClasses: ServerClass[];
}
export interface StringTablesMessage extends BaseMessage {
tick: number;
type: MessageType.StringTables;
tables: StringTable[];
}

View file

@ -66,7 +66,8 @@ export interface BaseDataUserPacket {
}
export interface SayText2Packet {
packetType: 'sayText2';
packetType: 'userMessage',
userMessageType: 'sayText2';
client: number;
raw: number;
kind: 'TF_Chat_All' | 'TF_Chat_Team' | 'TF_Chat_AllDead';
@ -82,28 +83,33 @@ export enum HudTextLocation {
}
export interface TextMessagePacket {
packetType: 'textMsg';
packetType: 'userMessage',
userMessageType: 'textMsg';
destType: HudTextLocation;
text: string;
}
export interface ResetHUDPacket extends BaseDataUserPacket {
packetType: 'resetHUD';
packetType: 'userMessage',
userMessageType: 'resetHUD';
}
export interface TrainPacket extends BaseDataUserPacket {
packetType: 'train';
packetType: 'userMessage',
userMessageType: 'train';
}
export interface VoiceSubtitlePacket {
packetType: 'voiceSubtitle';
packetType: 'userMessage',
userMessageType: 'voiceSubtitle';
client: number;
menu: number;
item: number;
}
export interface ShakePacket {
packetType: 'shake';
packetType: 'userMessage',
userMessageType: 'shake';
command: number;
amplitude: number;
frequency: number;
@ -116,11 +122,13 @@ export interface UnknownUserMessageBasePacket {
}
export interface BreakModelPumpkinPacket extends UnknownUserMessageBasePacket {
packetType: 'breakModelPumpkin';
packetType: 'userMessage',
userMessageType: 'breakModelPumpkin';
}
export interface GenericUnknownUserMessagePacket extends UnknownUserMessageBasePacket {
packetType: 'unknownUserMessage';
packetType: 'userMessage',
userMessageType: 'unknownUserMessage';
}
export type UnknownUserMessagePacket = GenericUnknownUserMessagePacket |
@ -135,6 +143,8 @@ export type UserMessagePacket = SayText2Packet
| BreakModelPumpkinPacket
| ShakePacket;
export type UserMessagePacketType = UserMessagePacket['userMessageType'];
export interface UserMessageTypeMap {
sayText2: SayText2Packet;
textMsg: TextMessagePacket;
@ -146,13 +156,14 @@ export interface UserMessageTypeMap {
shake: ShakePacket;
}
export const UserMessagePacketTypeMap: Map<UserMessagePacket['packetType'], UserMessageType> =
new Map<UserMessagePacket['packetType'], UserMessageType>([
export const UserMessagePacketTypeMap: Map<UserMessagePacketType, UserMessageType> =
new Map<UserMessagePacketType, UserMessageType>([
['sayText2', UserMessageType.SayText2],
['textMsg', UserMessageType.TextMsg],
['train', UserMessageType.Train],
['voiceSubtitle', UserMessageType.VoiceSubtitle],
['breakModelPumpkin', UserMessageType.BreakModel_Pumpkin],
['resetHUD', UserMessageType.ResetHUD],
['shake', UserMessageType.Shake]
['shake', UserMessageType.Shake],
['unknownUserMessage', -1]
]);

View file

@ -1,16 +1,20 @@
import {BitStream} from 'bit-buffer';
import {PacketMapType, PacketType} from '../../Data/Packet';
import {Packet, PacketMapType, PacketType} from '../../Data/Packet';
import {Encoder, PacketHandler, Parser} from './Parser';
import {UserMessagePacketType} from '../../Data/UserMessage';
export function make<T extends PacketType>(name: T, definition: string): PacketHandler<PacketMapType[T]> {
export interface NamedPacketHandler<P extends Packet, N extends PacketType | UserMessagePacketType> extends PacketHandler<P> {
name: N;
}
export function make<T extends PacketType | UserMessagePacketType>(name: T, definition: string, nameKey: string = 'packetType', extraData: any = {}): NamedPacketHandler<PacketMapType[T], T> {
const parts = definition.split('}');
const items = parts.map((part) => {
return part.split('{');
}).filter((part) => part[0]);
const parser: Parser<PacketMapType[T]> = (stream: BitStream) => {
const result = {
packetType: name
};
const result = Object.assign({}, extraData);
result[nameKey] = name;
try {
for (const group of items) {
const value = readItem(stream, group[1], result);
@ -28,7 +32,7 @@ export function make<T extends PacketType>(name: T, definition: string): PacketH
writeItem(stream, group[1], packet, packet[group[0]]);
}
};
return {parser, encoder};
return {parser, encoder, name};
}
function readItem(stream: BitStream, description: string, data) {

View file

@ -2,21 +2,21 @@ import {BitStream} from 'bit-buffer';
import {
UnknownUserMessageBasePacket,
UnknownUserMessagePacket,
UserMessagePacket,
UserMessagePacket, UserMessagePacketType,
UserMessagePacketTypeMap,
UserMessageType,
UserMessageTypeMap
} from '../../Data/UserMessage';
import {EncodeSayText2, ParseSayText2} from '../UserMessage/SayText2';
import {PacketHandler} from './Parser';
import {make} from './ParserGenerator';
import {make, NamedPacketHandler} from './ParserGenerator';
function unknownPacketHandler<T extends UnknownUserMessagePacket['packetType']>(packetType: T): PacketHandler<UserMessageTypeMap[T]> {
function unknownPacketHandler<T extends UnknownUserMessagePacket['userMessageType']>(userMessageType: T): NamedPacketHandler<UserMessageTypeMap[T], UserMessagePacketType> {
return {
parser: (data: BitStream) => {
return {
packetType,
type: UserMessagePacketTypeMap.get(packetType),
packetType: 'userMessage',
userMessageType,
type: UserMessagePacketTypeMap.get(userMessageType),
data
} as UserMessageTypeMap[T];
},
@ -24,23 +24,38 @@ function unknownPacketHandler<T extends UnknownUserMessagePacket['packetType']>(
packet.data.index = 0;
data.writeBitStream(packet.data);
packet.data.index = 0;
}
},
name: userMessageType
};
}
const userMessageParsers: Map<UserMessageType, PacketHandler<UserMessagePacket>> =
new Map<UserMessageType, PacketHandler<UserMessagePacket>>([
[UserMessageType.SayText2, {parser: ParseSayText2, encoder: EncodeSayText2}],
[UserMessageType.TextMsg, make('textMsg', 'destType{8}text{s}substitute1{s}substitute2{s}substitute3{s}substitute4{s}')],
[UserMessageType.ResetHUD, make('resetHUD', 'data{8}')],
[UserMessageType.Train, make('train', 'data{8}')],
[UserMessageType.VoiceSubtitle, make('voiceSubtitle', 'client{8}menu{8}item{8}')],
const userMessageParsers: Map<UserMessageType, NamedPacketHandler<UserMessagePacket, UserMessagePacketType>> =
new Map<UserMessageType, NamedPacketHandler<UserMessagePacket, UserMessagePacketType>>([
[UserMessageType.SayText2, {parser: ParseSayText2, encoder: EncodeSayText2, name: 'sayText2'}],
[UserMessageType.TextMsg,
make('textMsg', 'destType{8}text{s}substitute1{s}substitute2{s}substitute3{s}substitute4{s}', 'userMessageType', {
packetType: 'userMessage'
})],
[UserMessageType.ResetHUD,
make('resetHUD', 'data{8}', 'userMessageType', {
packetType: 'userMessage'
})],
[UserMessageType.Train,
make('train', 'data{8}', 'userMessageType', {
packetType: 'userMessage'
})],
[UserMessageType.VoiceSubtitle,
make('voiceSubtitle', 'client{8}menu{8}item{8}', 'userMessageType', {
packetType: 'userMessage'
})],
[UserMessageType.BreakModel_Pumpkin, unknownPacketHandler('breakModelPumpkin')],
[UserMessageType.Shake, make('shake', 'command{8}amplitude{f32}frequency{f32}duration{f32}')]
[UserMessageType.Shake,
make('shake', 'command{8}amplitude{f32}frequency{f32}duration{f32}', 'userMessageType', {
packetType: 'userMessage'
})]
]);
export function ParseUserMessage(stream: BitStream): UserMessagePacket { // 23: user message
const s = stream.index;
const type = stream.readUint8();
const length = stream.readBits(11);
const messageData = stream.readBitStream(length);
@ -49,7 +64,8 @@ export function ParseUserMessage(stream: BitStream): UserMessagePacket { // 23:
if (!handler) {
return {
packetType: 'unknownUserMessage',
packetType: 'userMessage',
userMessageType: 'unknownUserMessage',
type,
data: messageData
};
@ -59,14 +75,14 @@ export function ParseUserMessage(stream: BitStream): UserMessagePacket { // 23:
}
export function EncodeUserMessage(packet: UserMessagePacket, stream: BitStream) {
if (packet.packetType === 'unknownUserMessage') {
if (packet.userMessageType === 'unknownUserMessage') {
stream.writeUint8(packet.type);
stream.writeBits(packet.data.length, 11);
packet.data.index = 0;
stream.writeBitStream(packet.data);
packet.data.index = 0;
} else {
const messageType = UserMessagePacketTypeMap.get(packet.packetType);
const messageType = UserMessagePacketTypeMap.get(packet.userMessageType);
if (!messageType) {
throw new Error(`Unknown userMessage type ${messageType}`);
}
@ -78,7 +94,7 @@ export function EncodeUserMessage(packet: UserMessagePacket, stream: BitStream)
const handler = userMessageParsers.get(messageType);
if (!handler) {
throw new Error(`No encoder for userMessage ${packet.packetType}(${messageType})`);
throw new Error(`No encoder for userMessage ${packet.userMessageType}(${messageType})`);
}
handler.encoder(packet, stream);

View file

@ -44,7 +44,8 @@ export function ParseSayText2(stream: BitStream): SayText2Packet { // 4: ParseSa
}
return {
packetType: 'sayText2',
packetType: 'userMessage',
userMessageType: 'sayText2',
client,
raw,
kind,