teeworlds 2.5.3 → 2.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -3
- package/docs/documentation.md +3 -0
- package/index.js +24 -24
- package/lib/MsgPacker.js +46 -55
- package/lib/MsgUnpacker.js +52 -53
- package/lib/UUIDManager.js +44 -50
- package/lib/client.js +761 -845
- package/lib/client.ts +124 -214
- package/lib/components/game.js +103 -143
- package/lib/components/game.ts +12 -13
- package/lib/components/movement.js +74 -82
- package/lib/components/rcon.js +91 -0
- package/lib/components/rcon.ts +114 -0
- package/lib/components/snapshot.js +143 -258
- package/lib/components/snapshot.ts +68 -100
- package/lib/enums_types/protocol.js +13 -0
- package/lib/enums_types/protocol.ts +145 -0
- package/lib/enums_types/types.d.ts +236 -0
- package/lib/huffman.js +186 -192
- package/lib/snapshot.js +598 -610
- package/lib/snapshot.ts +36 -38
- package/package.json +4 -3
- package/tsconfig.json +1 -1
- package/lib/snapshots.d.ts +0 -233
package/lib/client.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
3
|
import { randomBytes } from "crypto";
|
|
4
|
-
|
|
4
|
+
import { lookup as dnsLookup } from 'dns';
|
|
5
5
|
import net from 'dgram';
|
|
6
6
|
import { EventEmitter } from 'stream';
|
|
7
7
|
|
|
@@ -9,146 +9,20 @@ import { unpackString, MsgUnpacker } from "./MsgUnpacker";
|
|
|
9
9
|
let { version } = require('../package.json');
|
|
10
10
|
|
|
11
11
|
import Movement from './components/movement';
|
|
12
|
-
import {
|
|
12
|
+
import { _Packet, Chunk, DeltaItem, SnapshotItemTypes } from './enums_types/types';
|
|
13
13
|
|
|
14
14
|
import { MsgPacker } from './MsgPacker';
|
|
15
|
-
import {
|
|
15
|
+
import { Snapshot } from './snapshot';
|
|
16
16
|
import { Huffman } from "./huffman";
|
|
17
17
|
import { Game } from "./components/game";
|
|
18
18
|
import { SnapshotWrapper } from "./components/snapshot";
|
|
19
19
|
|
|
20
20
|
import { UUIDManager } from "./UUIDManager";
|
|
21
|
+
import { NETMSG, States } from "./enums_types/protocol";
|
|
22
|
+
import { Rcon } from "./components/rcon";
|
|
21
23
|
|
|
22
24
|
const huff = new Huffman();
|
|
23
25
|
|
|
24
|
-
enum States {
|
|
25
|
-
STATE_OFFLINE = 0,
|
|
26
|
-
STATE_CONNECTING,
|
|
27
|
-
STATE_LOADING,
|
|
28
|
-
STATE_ONLINE,
|
|
29
|
-
STATE_DEMOPLAYBACK,
|
|
30
|
-
STATE_QUITTING,
|
|
31
|
-
STATE_RESTARTING
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
enum NETMSG_Game {
|
|
36
|
-
EX,
|
|
37
|
-
SV_MOTD,
|
|
38
|
-
SV_BROADCAST,
|
|
39
|
-
SV_CHAT,
|
|
40
|
-
SV_KILLMSG,
|
|
41
|
-
SV_SOUNDGLOBAL,
|
|
42
|
-
SV_TUNEPARAMS,
|
|
43
|
-
SV_EXTRAPROJECTILE,
|
|
44
|
-
SV_READYTOENTER,
|
|
45
|
-
SV_WEAPONPICKUP,
|
|
46
|
-
SV_EMOTICON,
|
|
47
|
-
SV_VOTECLEAROPTIONS,
|
|
48
|
-
SV_VOTEOPTIONLISTADD,
|
|
49
|
-
SV_VOTEOPTIONADD,
|
|
50
|
-
SV_VOTEOPTIONREMOVE,
|
|
51
|
-
SV_VOTESET,
|
|
52
|
-
SV_VOTESTATUS,
|
|
53
|
-
CL_SAY,
|
|
54
|
-
CL_SETTEAM,
|
|
55
|
-
CL_SETSPECTATORMODE,
|
|
56
|
-
CL_STARTINFO,
|
|
57
|
-
CL_CHANGEINFO,
|
|
58
|
-
CL_KILL,
|
|
59
|
-
CL_EMOTICON,
|
|
60
|
-
CL_VOTE,
|
|
61
|
-
CL_CALLVOTE,
|
|
62
|
-
CL_ISDDNETLEGACY,
|
|
63
|
-
SV_DDRACETIMELEGACY,
|
|
64
|
-
SV_RECORDLEGACY,
|
|
65
|
-
UNUSED,
|
|
66
|
-
SV_TEAMSSTATELEGACY,
|
|
67
|
-
CL_SHOWOTHERSLEGACY,
|
|
68
|
-
NUM
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
enum NETMSG_Sys {
|
|
72
|
-
NETMSG_EX = 0,
|
|
73
|
-
|
|
74
|
-
// the first thing sent by the client
|
|
75
|
-
// contains the version info for the client
|
|
76
|
-
NETMSG_INFO = 1,
|
|
77
|
-
|
|
78
|
-
// sent by server
|
|
79
|
-
NETMSG_MAP_CHANGE, // sent when client should switch map
|
|
80
|
-
NETMSG_MAP_DATA, // map transfer, contains a chunk of the map file
|
|
81
|
-
NETMSG_CON_READY, // connection is ready, client should send start info
|
|
82
|
-
NETMSG_SNAP, // normal snapshot, multiple parts
|
|
83
|
-
NETMSG_SNAPEMPTY, // empty snapshot
|
|
84
|
-
NETMSG_SNAPSINGLE, // ?
|
|
85
|
-
NETMSG_SNAPSMALL, //
|
|
86
|
-
NETMSG_INPUTTIMING, // reports how off the input was
|
|
87
|
-
NETMSG_RCON_AUTH_STATUS, // result of the authentication
|
|
88
|
-
NETMSG_RCON_LINE, // line that should be printed to the remote console
|
|
89
|
-
|
|
90
|
-
NETMSG_AUTH_CHALLANGE, //
|
|
91
|
-
NETMSG_AUTH_RESULT, //
|
|
92
|
-
|
|
93
|
-
// sent by client
|
|
94
|
-
NETMSG_READY, //
|
|
95
|
-
NETMSG_ENTERGAME,
|
|
96
|
-
NETMSG_INPUT, // contains the inputdata from the client
|
|
97
|
-
NETMSG_RCON_CMD, //
|
|
98
|
-
NETMSG_RCON_AUTH, //
|
|
99
|
-
NETMSG_REQUEST_MAP_DATA, //
|
|
100
|
-
|
|
101
|
-
NETMSG_AUTH_START, //
|
|
102
|
-
NETMSG_AUTH_RESPONSE, //
|
|
103
|
-
|
|
104
|
-
// sent by both
|
|
105
|
-
NETMSG_PING,
|
|
106
|
-
NETMSG_PING_REPLY,
|
|
107
|
-
NETMSG_ERROR,
|
|
108
|
-
|
|
109
|
-
// sent by server (todo: move it up)
|
|
110
|
-
NETMSG_RCON_CMD_ADD,
|
|
111
|
-
NETMSG_RCON_CMD_REM,
|
|
112
|
-
|
|
113
|
-
NUM_NETMSGS,
|
|
114
|
-
|
|
115
|
-
NETMSG_WHATIS = 65536,
|
|
116
|
-
NETMSG_ITIS,
|
|
117
|
-
NETMSG_IDONTKNOW,
|
|
118
|
-
|
|
119
|
-
NETMSG_RCONTYPE,
|
|
120
|
-
NETMSG_MAP_DETAILS,
|
|
121
|
-
NETMSG_CAPABILITIES,
|
|
122
|
-
NETMSG_CLIENTVER,
|
|
123
|
-
NETMSG_PINGEX,
|
|
124
|
-
NETMSG_PONGEX,
|
|
125
|
-
NETMSG_CHECKSUM_REQUEST,
|
|
126
|
-
NETMSG_CHECKSUM_RESPONSE,
|
|
127
|
-
NETMSG_CHECKSUM_ERROR,
|
|
128
|
-
|
|
129
|
-
NETMSG_REDIRECT,
|
|
130
|
-
|
|
131
|
-
NETMSG_I_AM_NPM_PACKAGE
|
|
132
|
-
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
interface chunk {
|
|
136
|
-
bytes: number,
|
|
137
|
-
flags: number,
|
|
138
|
-
seq?: number,
|
|
139
|
-
// type: 'sys' | 'game',
|
|
140
|
-
sys: Boolean,
|
|
141
|
-
msgid: number,
|
|
142
|
-
msg: string,
|
|
143
|
-
raw: Buffer,
|
|
144
|
-
extended_msgid?: Buffer;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
interface _packet {
|
|
148
|
-
twprotocol: { flags: number, ack: number, chunkAmount: number, size: number },
|
|
149
|
-
chunks: chunk[]
|
|
150
|
-
}
|
|
151
|
-
|
|
152
26
|
var messageTypes = [
|
|
153
27
|
["none, starts at 1", "SV_MOTD", "SV_BROADCAST", "SV_CHAT", "SV_KILL_MSG", "SV_SOUND_GLOBAL", "SV_TUNE_PARAMS", "SV_EXTRA_PROJECTILE", "SV_READY_TO_ENTER", "SV_WEAPON_PICKUP", "SV_EMOTICON", "SV_VOTE_CLEAR_OPTIONS", "SV_VOTE_OPTION_LIST_ADD", "SV_VOTE_OPTION_ADD", "SV_VOTE_OPTION_REMOVE", "SV_VOTE_SET", "SV_VOTE_STATUS", "CL_SAY", "CL_SET_TEAM", "CL_SET_SPECTATOR_MODE", "CL_START_INFO", "CL_CHANGE_INFO", "CL_KILL", "CL_EMOTICON", "CL_VOTE", "CL_CALL_VOTE", "CL_IS_DDNET", "SV_DDRACE_TIME", "SV_RECORD", "UNUSED", "SV_TEAMS_STATE", "CL_SHOW_OTHERS_LEGACY"],
|
|
154
28
|
["none, starts at 1", "INFO", "MAP_CHANGE", "MAP_DATA", "CON_READY", "SNAP", "SNAP_EMPTY", "SNAP_SINGLE", "INPUT_TIMING", "RCON_AUTH_STATUS", "RCON_LINE", "READY", "ENTER_GAME", "INPUT", "RCON_CMD", "RCON_AUTH", "REQUEST_MAP_DATA", "PING", "PING_REPLY", "RCON_CMD_ADD", "RCON_CMD_REMOVE"]
|
|
@@ -158,27 +32,27 @@ var messageTypes = [
|
|
|
158
32
|
declare interface iMessage {
|
|
159
33
|
team: number,
|
|
160
34
|
client_id: number,
|
|
161
|
-
author?: { ClientInfo?: ClientInfo, PlayerInfo?: PlayerInfo },
|
|
35
|
+
author?: { ClientInfo?: SnapshotItemTypes.ClientInfo, PlayerInfo?: SnapshotItemTypes.PlayerInfo },
|
|
162
36
|
message: string
|
|
163
37
|
}
|
|
164
38
|
|
|
165
39
|
declare interface iEmoticon {
|
|
166
40
|
client_id: number,
|
|
167
41
|
emoticon: number,
|
|
168
|
-
author?: { ClientInfo?: ClientInfo, PlayerInfo?: PlayerInfo }
|
|
42
|
+
author?: { ClientInfo?: SnapshotItemTypes.ClientInfo, PlayerInfo?: SnapshotItemTypes.PlayerInfo }
|
|
169
43
|
}
|
|
170
44
|
|
|
171
45
|
declare interface iKillMsg {
|
|
172
46
|
killer_id: number,
|
|
173
|
-
killer?: { ClientInfo?: ClientInfo, PlayerInfo?: PlayerInfo },
|
|
47
|
+
killer?: { ClientInfo?: SnapshotItemTypes.ClientInfo, PlayerInfo?: SnapshotItemTypes.PlayerInfo },
|
|
174
48
|
victim_id: number,
|
|
175
|
-
victim?: { ClientInfo?: ClientInfo, PlayerInfo?: PlayerInfo },
|
|
49
|
+
victim?: { ClientInfo?: SnapshotItemTypes.ClientInfo, PlayerInfo?: SnapshotItemTypes.PlayerInfo },
|
|
176
50
|
weapon: number,
|
|
177
51
|
special_mode: number
|
|
178
52
|
}
|
|
179
53
|
|
|
180
54
|
declare interface iOptions {
|
|
181
|
-
identity?: ClientInfo,
|
|
55
|
+
identity?: SnapshotItemTypes.ClientInfo,
|
|
182
56
|
password?: string,
|
|
183
57
|
ddnet_version?: {version: number, release_version: string},
|
|
184
58
|
timeout?: number, // in ms
|
|
@@ -186,26 +60,30 @@ declare interface iOptions {
|
|
|
186
60
|
lightweight?: boolean // experimental, only sends keepalive's (sendinput has to be called manually)
|
|
187
61
|
}
|
|
188
62
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
on(event: 'map_details', listener: (message: {map_name: string, map_sha256: Buffer, map_crc: number, map_size: number, map_url: string}) => void): this;
|
|
202
|
-
on(event: 'capabilities', listener: (message: {ChatTimeoutCode: boolean, AnyPlayerFlag: boolean, PingEx: boolean, AllowDummy: boolean, SyncWeaponInput: boolean}) => void): this;
|
|
203
|
-
|
|
204
|
-
on(event: 'snapshot', listener: (items: Item[]) => void): this;
|
|
63
|
+
interface ClientEvents {
|
|
64
|
+
connected: () => void;
|
|
65
|
+
disconnect: (reason: string) => void;
|
|
66
|
+
emote: (message: iEmoticon) => void;
|
|
67
|
+
message: (message: iMessage) => void;
|
|
68
|
+
broadcast: (message: string) => void;
|
|
69
|
+
kill: (kill: iKillMsg) => void;
|
|
70
|
+
motd: (message: string) => void;
|
|
71
|
+
map_details: (message: { map_name: string, map_sha256: Buffer, map_crc: number, map_size: number, map_url: string }) => void;
|
|
72
|
+
capabilities: (message: { ChatTimeoutCode: boolean, AnyPlayerFlag: boolean, PingEx: boolean, AllowDummy: boolean, SyncWeaponInput: boolean }) => void;
|
|
73
|
+
snapshot: (items: DeltaItem[]) => void;
|
|
74
|
+
rcon_line: (line: string) => void;
|
|
205
75
|
}
|
|
206
76
|
|
|
207
77
|
export class Client extends EventEmitter {
|
|
208
|
-
|
|
78
|
+
on<K extends keyof ClientEvents>(event: K, listener: ClientEvents[K]): this {
|
|
79
|
+
return super.on(event, listener);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
emit<K extends keyof ClientEvents>(event: K, ...args: Parameters<ClientEvents[K]>): boolean {
|
|
83
|
+
return super.emit(event, ...args);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
public rcon: Rcon;
|
|
209
87
|
private host: string;
|
|
210
88
|
private port: number;
|
|
211
89
|
private name: string;
|
|
@@ -260,7 +138,7 @@ export class Client extends EventEmitter {
|
|
|
260
138
|
this.currentSnapshotGameTick = 0;
|
|
261
139
|
|
|
262
140
|
this.SnapshotParts = 0;
|
|
263
|
-
|
|
141
|
+
this.rcon = new Rcon(this);
|
|
264
142
|
this.SnapUnpacker = new Snapshot(this);
|
|
265
143
|
// this.eSnapHolder = [];
|
|
266
144
|
this.requestResend = false;
|
|
@@ -298,22 +176,32 @@ export class Client extends EventEmitter {
|
|
|
298
176
|
|
|
299
177
|
this.UUIDManager = new UUIDManager();
|
|
300
178
|
|
|
301
|
-
this.UUIDManager.RegisterName("what-is@ddnet.tw",
|
|
302
|
-
this.UUIDManager.RegisterName("it-is@ddnet.tw",
|
|
303
|
-
this.UUIDManager.RegisterName("i-dont-know@ddnet.tw",
|
|
304
|
-
|
|
305
|
-
this.UUIDManager.RegisterName("rcon-type@ddnet.tw",
|
|
306
|
-
this.UUIDManager.RegisterName("map-details@ddnet.tw",
|
|
307
|
-
this.UUIDManager.RegisterName("capabilities@ddnet.tw",
|
|
308
|
-
this.UUIDManager.RegisterName("clientver@ddnet.tw",
|
|
309
|
-
this.UUIDManager.RegisterName("ping@ddnet.tw",
|
|
310
|
-
this.UUIDManager.RegisterName("pong@ddnet.tw",
|
|
311
|
-
this.UUIDManager.RegisterName("checksum-request@ddnet.tw",
|
|
312
|
-
this.UUIDManager.RegisterName("checksum-response@ddnet.tw",
|
|
313
|
-
this.UUIDManager.RegisterName("checksum-error@ddnet.tw",
|
|
314
|
-
this.UUIDManager.RegisterName("redirect@ddnet.org",
|
|
315
|
-
|
|
316
|
-
|
|
179
|
+
this.UUIDManager.RegisterName("what-is@ddnet.tw", NETMSG.System.NETMSG_WHATIS);
|
|
180
|
+
this.UUIDManager.RegisterName("it-is@ddnet.tw", NETMSG.System.NETMSG_ITIS);
|
|
181
|
+
this.UUIDManager.RegisterName("i-dont-know@ddnet.tw", NETMSG.System.NETMSG_IDONTKNOW);
|
|
182
|
+
|
|
183
|
+
this.UUIDManager.RegisterName("rcon-type@ddnet.tw", NETMSG.System.NETMSG_RCONTYPE);
|
|
184
|
+
this.UUIDManager.RegisterName("map-details@ddnet.tw", NETMSG.System.NETMSG_MAP_DETAILS);
|
|
185
|
+
this.UUIDManager.RegisterName("capabilities@ddnet.tw", NETMSG.System.NETMSG_CAPABILITIES);
|
|
186
|
+
this.UUIDManager.RegisterName("clientver@ddnet.tw", NETMSG.System.NETMSG_CLIENTVER);
|
|
187
|
+
this.UUIDManager.RegisterName("ping@ddnet.tw", NETMSG.System.NETMSG_PING);
|
|
188
|
+
this.UUIDManager.RegisterName("pong@ddnet.tw", NETMSG.System.NETMSG_PONGEX);
|
|
189
|
+
this.UUIDManager.RegisterName("checksum-request@ddnet.tw", NETMSG.System.NETMSG_CHECKSUM_REQUEST);
|
|
190
|
+
this.UUIDManager.RegisterName("checksum-response@ddnet.tw", NETMSG.System.NETMSG_CHECKSUM_RESPONSE);
|
|
191
|
+
this.UUIDManager.RegisterName("checksum-error@ddnet.tw", NETMSG.System.NETMSG_CHECKSUM_ERROR);
|
|
192
|
+
this.UUIDManager.RegisterName("redirect@ddnet.org", NETMSG.System.NETMSG_REDIRECT);
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
this.UUIDManager.RegisterName("rcon-cmd-group-start@ddnet.org", NETMSG.System.NETMSG_RCON_CMD_GROUP_START) // not implemented
|
|
196
|
+
this.UUIDManager.RegisterName("rcon-cmd-group-end@ddnet.org", NETMSG.System.NETMSG_RCON_CMD_GROUP_END) // not implemented
|
|
197
|
+
this.UUIDManager.RegisterName("map-reload@ddnet.org", NETMSG.System.NETMSG_MAP_RELOAD) // not implemented
|
|
198
|
+
this.UUIDManager.RegisterName("reconnect@ddnet.org", NETMSG.System.NETMSG_RECONNECT) // implemented
|
|
199
|
+
this.UUIDManager.RegisterName("sv-maplist-add@ddnet.org", NETMSG.System.NETMSG_MAPLIST_ADD) // not implemented
|
|
200
|
+
this.UUIDManager.RegisterName("sv-maplist-start@ddnet.org", NETMSG.System.NETMSG_MAPLIST_GROUP_START) // not implemented
|
|
201
|
+
this.UUIDManager.RegisterName("sv-maplist-end@ddnet.org", NETMSG.System.NETMSG_MAPLIST_GROUP_END) // not implemented
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
this.UUIDManager.RegisterName("i-am-npm-package@swarfey.gitlab.io", NETMSG.System.NETMSG_I_AM_NPM_PACKAGE);
|
|
317
205
|
|
|
318
206
|
}
|
|
319
207
|
|
|
@@ -340,8 +228,8 @@ export class Client extends EventEmitter {
|
|
|
340
228
|
this.SendMsgEx(toResend);
|
|
341
229
|
}
|
|
342
230
|
|
|
343
|
-
private Unpack(packet: Buffer):
|
|
344
|
-
var unpacked:
|
|
231
|
+
private Unpack(packet: Buffer): _Packet {
|
|
232
|
+
var unpacked: _Packet = { twprotocol: { flags: packet[0] >> 4, ack: ((packet[0]&0xf)<<8) | packet[1], chunkAmount: packet[2], size: packet.byteLength - 3 }, chunks: [] }
|
|
345
233
|
|
|
346
234
|
|
|
347
235
|
if (packet.indexOf(Buffer.from([0xff, 0xff, 0xff, 0xff])) == 0 )// !(unpacked.twprotocol.flags & 8) || unpacked.twprotocol.flags == 255) // flags == 255 is connectionless (used for sending usernames)
|
|
@@ -359,7 +247,7 @@ export class Client extends EventEmitter {
|
|
|
359
247
|
|
|
360
248
|
|
|
361
249
|
for (let i = 0; i < unpacked.twprotocol.chunkAmount; i++) {
|
|
362
|
-
var chunk:
|
|
250
|
+
var chunk: Chunk = {} as Chunk;
|
|
363
251
|
chunk.bytes = ((packet[0] & 0x3f) << 4) | (packet[1] & ((1 << 4) - 1));
|
|
364
252
|
chunk.flags = (packet[0] >> 6) & 3;
|
|
365
253
|
|
|
@@ -472,7 +360,12 @@ export class Client extends EventEmitter {
|
|
|
472
360
|
}
|
|
473
361
|
|
|
474
362
|
/** Queue a chunk (instantly sent if flush flag is set - otherwise it will be sent in the next packet). */
|
|
475
|
-
QueueChunkEx(Msg: MsgPacker) {
|
|
363
|
+
QueueChunkEx(Msg: MsgPacker | MsgPacker[]) {
|
|
364
|
+
if (Msg instanceof Array) {
|
|
365
|
+
for (let chunk of Msg)
|
|
366
|
+
this.QueueChunkEx(chunk);
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
476
369
|
if (this.queueChunkEx.length > 0) {
|
|
477
370
|
let total_size = 0;
|
|
478
371
|
for (let chunk of this.queueChunkEx)
|
|
@@ -503,7 +396,7 @@ export class Client extends EventEmitter {
|
|
|
503
396
|
}
|
|
504
397
|
|
|
505
398
|
private MsgToChunk(packet: Buffer) {
|
|
506
|
-
var chunk:
|
|
399
|
+
var chunk: Chunk = {} as Chunk;
|
|
507
400
|
chunk.bytes = ((packet[0] & 0x3f) << 4) | (packet[1] & ((1 << 4) - 1));
|
|
508
401
|
chunk.flags = (packet[0] >> 6) & 3;
|
|
509
402
|
|
|
@@ -539,7 +432,16 @@ export class Client extends EventEmitter {
|
|
|
539
432
|
}
|
|
540
433
|
|
|
541
434
|
/** Connect the client to the server. */
|
|
542
|
-
connect() {
|
|
435
|
+
async connect() {
|
|
436
|
+
// test via regex whether or not this.host is a domain or an ip
|
|
437
|
+
// if not, resolve it
|
|
438
|
+
if (!this.host.match(/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/)) {
|
|
439
|
+
dnsLookup(this.host, 4, (err, address, family) => {
|
|
440
|
+
if (err) throw err;
|
|
441
|
+
this.host = address;
|
|
442
|
+
})
|
|
443
|
+
}
|
|
444
|
+
|
|
543
445
|
this.State = States.STATE_CONNECTING;
|
|
544
446
|
|
|
545
447
|
let predTimer = setInterval(() => {
|
|
@@ -558,11 +460,12 @@ export class Client extends EventEmitter {
|
|
|
558
460
|
else
|
|
559
461
|
clearInterval(connectInterval)
|
|
560
462
|
}, 500);
|
|
463
|
+
let inputInterval: NodeJS.Timeout;
|
|
561
464
|
if (!this.options?.lightweight) {
|
|
562
|
-
|
|
465
|
+
inputInterval = setInterval(() => {
|
|
563
466
|
if (this.State == States.STATE_OFFLINE) {
|
|
564
467
|
clearInterval(inputInterval)
|
|
565
|
-
console.log("???");
|
|
468
|
+
// console.log("???");
|
|
566
469
|
}
|
|
567
470
|
if (this.State != States.STATE_ONLINE)
|
|
568
471
|
return;
|
|
@@ -584,7 +487,6 @@ export class Client extends EventEmitter {
|
|
|
584
487
|
let timeoutTime = this.options?.timeout ? this.options.timeout : 15000;
|
|
585
488
|
if ((new Date().getTime() - this.lastRecvTime) > timeoutTime) {
|
|
586
489
|
this.State = States.STATE_OFFLINE;
|
|
587
|
-
this.emit("timeout");
|
|
588
490
|
this.emit("disconnect", "Timed Out. (no packets received for " + (new Date().getTime() - this.lastRecvTime) + "ms)");
|
|
589
491
|
clearInterval(Timeout);
|
|
590
492
|
}
|
|
@@ -624,7 +526,7 @@ export class Client extends EventEmitter {
|
|
|
624
526
|
}
|
|
625
527
|
|
|
626
528
|
var i_am_npm_package = new MsgPacker(0, true, 1);
|
|
627
|
-
i_am_npm_package.AddBuffer(this.UUIDManager.LookupType(
|
|
529
|
+
i_am_npm_package.AddBuffer(this.UUIDManager.LookupType(NETMSG.System.NETMSG_I_AM_NPM_PACKAGE)!.hash);
|
|
628
530
|
|
|
629
531
|
i_am_npm_package.AddString(`https://www.npmjs.com/package/teeworlds/v/${version}`);
|
|
630
532
|
|
|
@@ -643,7 +545,7 @@ export class Client extends EventEmitter {
|
|
|
643
545
|
this.lastRecvTime = new Date().getTime();
|
|
644
546
|
}
|
|
645
547
|
|
|
646
|
-
var unpacked:
|
|
548
|
+
var unpacked: _Packet = this.Unpack(packet);
|
|
647
549
|
// unpacked.chunks = unpacked.chunks.filter(chunk => ((chunk.flags & 2) && (chunk.flags & 1)) ? chunk.seq! > this.ack : true); // filter out already received chunks
|
|
648
550
|
this.sentChunkQueue.forEach((buff, i) => {
|
|
649
551
|
let chunkFlags = (buff[0] >> 6) & 3;
|
|
@@ -680,23 +582,22 @@ export class Client extends EventEmitter {
|
|
|
680
582
|
|
|
681
583
|
if (chunk.sys) {
|
|
682
584
|
// system messages
|
|
683
|
-
if (chunk.msgid ==
|
|
684
|
-
let packer = new MsgPacker(
|
|
585
|
+
if (chunk.msgid == NETMSG.System.NETMSG_PING) { // ping
|
|
586
|
+
let packer = new MsgPacker(NETMSG.System.NETMSG_PING_REPLY, true, 0);
|
|
685
587
|
|
|
686
588
|
this.SendMsgEx(packer); // send ping reply
|
|
687
|
-
} else if (chunk.msgid ==
|
|
589
|
+
} else if (chunk.msgid == NETMSG.System.NETMSG_PING_REPLY) { // Ping reply
|
|
688
590
|
this.game._ping_resolve(new Date().getTime())
|
|
689
|
-
}
|
|
690
|
-
|
|
591
|
+
} else if (this.rcon._checkChunks(chunk)) {}
|
|
691
592
|
// packets neccessary for connection
|
|
692
593
|
// https://ddnet.org/docs/libtw2/connection/
|
|
693
594
|
|
|
694
|
-
if (chunk.msgid ==
|
|
595
|
+
if (chunk.msgid == NETMSG.System.NETMSG_MAP_CHANGE) {
|
|
695
596
|
this.Flush();
|
|
696
|
-
var Msg = new MsgPacker(
|
|
597
|
+
var Msg = new MsgPacker(NETMSG.System.NETMSG_READY, true, 1); /* ready */
|
|
697
598
|
this.SendMsgEx(Msg);
|
|
698
|
-
} else if (chunk.msgid ==
|
|
699
|
-
var info = new MsgPacker(
|
|
599
|
+
} else if (chunk.msgid == NETMSG.System.NETMSG_CON_READY) {
|
|
600
|
+
var info = new MsgPacker(NETMSG.Game.CL_STARTINFO, false, 1);
|
|
700
601
|
if (this.options?.identity) {
|
|
701
602
|
info.AddString(this.options.identity.name);
|
|
702
603
|
info.AddString(this.options.identity.clan);
|
|
@@ -720,7 +621,7 @@ export class Client extends EventEmitter {
|
|
|
720
621
|
this.SendMsgEx([info, crashmeplx]);
|
|
721
622
|
}
|
|
722
623
|
|
|
723
|
-
if (chunk.msgid >=
|
|
624
|
+
if (chunk.msgid >= NETMSG.System.NETMSG_SNAP && chunk.msgid <= NETMSG.System.NETMSG_SNAPSINGLE) {
|
|
724
625
|
this.receivedSnaps++; /* wait for 2 ss before seeing self as connected */
|
|
725
626
|
if (this.receivedSnaps == 2) {
|
|
726
627
|
if (this.State != States.STATE_ONLINE)
|
|
@@ -741,12 +642,12 @@ export class Client extends EventEmitter {
|
|
|
741
642
|
let Crc = 0;
|
|
742
643
|
let CompleteSize = 0;
|
|
743
644
|
|
|
744
|
-
if (chunk.msgid ==
|
|
645
|
+
if (chunk.msgid == NETMSG.System.NETMSG_SNAP) {
|
|
745
646
|
NumParts = unpacker.unpackInt();
|
|
746
647
|
Part = unpacker.unpackInt();
|
|
747
648
|
}
|
|
748
649
|
|
|
749
|
-
if (chunk.msgid !=
|
|
650
|
+
if (chunk.msgid != NETMSG.System.NETMSG_SNAPEMPTY) {
|
|
750
651
|
Crc = unpacker.unpackInt();
|
|
751
652
|
PartSize = unpacker.unpackInt();
|
|
752
653
|
}
|
|
@@ -789,28 +690,28 @@ export class Client extends EventEmitter {
|
|
|
789
690
|
|
|
790
691
|
}
|
|
791
692
|
|
|
792
|
-
if (chunk.msgid >=
|
|
793
|
-
if (chunk.msgid ==
|
|
693
|
+
if (chunk.msgid >= NETMSG.System.NETMSG_WHATIS && chunk.msgid <= NETMSG.System.NETMSG_CHECKSUM_ERROR) {
|
|
694
|
+
if (chunk.msgid == NETMSG.System.NETMSG_WHATIS) {
|
|
794
695
|
let Uuid = chunk.raw.slice(0, 16);
|
|
795
696
|
|
|
796
697
|
let uuid = this.UUIDManager.LookupUUID(Uuid);
|
|
797
698
|
let packer = new MsgPacker(0, true, 1);
|
|
798
699
|
if (uuid !== undefined) {
|
|
799
700
|
// IT_IS msg
|
|
800
|
-
packer.AddBuffer(this.UUIDManager.LookupType(
|
|
701
|
+
packer.AddBuffer(this.UUIDManager.LookupType(NETMSG.System.NETMSG_ITIS)!.hash);
|
|
801
702
|
|
|
802
703
|
packer.AddBuffer(Uuid);
|
|
803
704
|
packer.AddString(uuid.name);
|
|
804
705
|
} else {
|
|
805
706
|
// dont_know msg
|
|
806
|
-
packer.AddBuffer(this.UUIDManager.LookupType(
|
|
707
|
+
packer.AddBuffer(this.UUIDManager.LookupType(NETMSG.System.NETMSG_IDONTKNOW)!.hash);
|
|
807
708
|
|
|
808
709
|
packer.AddBuffer(Uuid);
|
|
809
710
|
}
|
|
810
711
|
this.QueueChunkEx(packer)
|
|
811
712
|
}
|
|
812
713
|
|
|
813
|
-
if (chunk.msgid ==
|
|
714
|
+
if (chunk.msgid == NETMSG.System.NETMSG_MAP_DETAILS) { // TODO: option for downloading maps
|
|
814
715
|
let unpacker = new MsgUnpacker(chunk.raw);
|
|
815
716
|
|
|
816
717
|
let map_name = unpacker.unpackString();
|
|
@@ -827,7 +728,7 @@ export class Client extends EventEmitter {
|
|
|
827
728
|
this.emit("map_details", {map_name, map_sha256, map_crc, map_size, map_url})
|
|
828
729
|
// unpacker.unpack
|
|
829
730
|
|
|
830
|
-
} else if (chunk.msgid ==
|
|
731
|
+
} else if (chunk.msgid == NETMSG.System.NETMSG_CAPABILITIES) {
|
|
831
732
|
let unpacker = new MsgUnpacker(chunk.raw);
|
|
832
733
|
let Version = unpacker.unpackInt();
|
|
833
734
|
let Flags = unpacker.unpackInt();
|
|
@@ -865,11 +766,22 @@ export class Client extends EventEmitter {
|
|
|
865
766
|
}
|
|
866
767
|
this.emit("capabilities", {ChatTimeoutCode, AnyPlayerFlag, PingEx, AllowDummy, SyncWeaponInput});
|
|
867
768
|
// https://github.com/ddnet/ddnet/blob/06e3eb564150e9ab81b3a5595c48e9fe5952ed32/src/engine/client/client.cpp#L1565
|
|
868
|
-
} else if (chunk.msgid ==
|
|
769
|
+
} else if (chunk.msgid == NETMSG.System.NETMSG_PINGEX) {
|
|
869
770
|
let packer = new MsgPacker(0, true, 2);
|
|
870
|
-
packer.AddBuffer(this.UUIDManager.LookupType(
|
|
771
|
+
packer.AddBuffer(this.UUIDManager.LookupType(NETMSG.System.NETMSG_PONGEX)!.hash);
|
|
871
772
|
|
|
872
773
|
this.SendMsgEx(packer, 2);
|
|
774
|
+
} else if (chunk.msgid == NETMSG.System.NETMSG_RECONNECT) {
|
|
775
|
+
this.SendControlMsg(4) // sends disconnect packet
|
|
776
|
+
clearInterval(predTimer);
|
|
777
|
+
clearInterval(inputInterval);
|
|
778
|
+
clearInterval(resendTimeout);
|
|
779
|
+
clearInterval(Timeout);
|
|
780
|
+
this.socket?.removeAllListeners("message");
|
|
781
|
+
this.connect();
|
|
782
|
+
|
|
783
|
+
|
|
784
|
+
return;
|
|
873
785
|
}
|
|
874
786
|
|
|
875
787
|
}
|
|
@@ -878,9 +790,9 @@ export class Client extends EventEmitter {
|
|
|
878
790
|
// game messages
|
|
879
791
|
|
|
880
792
|
// vote list:
|
|
881
|
-
if (chunk.msgid ==
|
|
793
|
+
if (chunk.msgid == NETMSG.Game.SV_VOTECLEAROPTIONS) {
|
|
882
794
|
this.VoteList = [];
|
|
883
|
-
} else if (chunk.msgid ==
|
|
795
|
+
} else if (chunk.msgid == NETMSG.Game.SV_VOTEOPTIONLISTADD) {
|
|
884
796
|
let unpacker = new MsgUnpacker(chunk.raw)
|
|
885
797
|
let NumOptions = unpacker.unpackInt()
|
|
886
798
|
let list: string[] = [];
|
|
@@ -890,11 +802,11 @@ export class Client extends EventEmitter {
|
|
|
890
802
|
list = list.slice(0, NumOptions);
|
|
891
803
|
|
|
892
804
|
this.VoteList.push(...list);
|
|
893
|
-
} else if (chunk.msgid ==
|
|
805
|
+
} else if (chunk.msgid == NETMSG.Game.SV_VOTEOPTIONADD) {
|
|
894
806
|
let unpacker = new MsgUnpacker(chunk.raw)
|
|
895
807
|
|
|
896
808
|
this.VoteList.push(unpacker.unpackString());
|
|
897
|
-
} else if (chunk.msgid ==
|
|
809
|
+
} else if (chunk.msgid == NETMSG.Game.SV_VOTEOPTIONREMOVE) {
|
|
898
810
|
let unpacker = new MsgUnpacker(chunk.raw)
|
|
899
811
|
|
|
900
812
|
let index = this.VoteList.indexOf(unpacker.unpackString());
|
|
@@ -905,7 +817,7 @@ export class Client extends EventEmitter {
|
|
|
905
817
|
}
|
|
906
818
|
|
|
907
819
|
// events
|
|
908
|
-
if (chunk.msgid ==
|
|
820
|
+
if (chunk.msgid == NETMSG.Game.SV_EMOTICON) {
|
|
909
821
|
let unpacker = new MsgUnpacker(chunk.raw);
|
|
910
822
|
let unpacked = {
|
|
911
823
|
client_id: unpacker.unpackInt(),
|
|
@@ -922,11 +834,11 @@ export class Client extends EventEmitter {
|
|
|
922
834
|
|
|
923
835
|
|
|
924
836
|
|
|
925
|
-
} else if (chunk.msgid ==
|
|
837
|
+
} else if (chunk.msgid == NETMSG.Game.SV_BROADCAST) {
|
|
926
838
|
let unpacker = new MsgUnpacker(chunk.raw);
|
|
927
839
|
|
|
928
840
|
this.emit("broadcast", unpacker.unpackString());
|
|
929
|
-
} if (chunk.msgid ==
|
|
841
|
+
} if (chunk.msgid == NETMSG.Game.SV_CHAT) {
|
|
930
842
|
let unpacker = new MsgUnpacker(chunk.raw);
|
|
931
843
|
let unpacked: iMessage = {
|
|
932
844
|
team: unpacker.unpackInt(),
|
|
@@ -941,7 +853,7 @@ export class Client extends EventEmitter {
|
|
|
941
853
|
}
|
|
942
854
|
}
|
|
943
855
|
this.emit("message", unpacked)
|
|
944
|
-
} else if (chunk.msgid ==
|
|
856
|
+
} else if (chunk.msgid == NETMSG.Game.SV_KILLMSG) {
|
|
945
857
|
let unpacked: iKillMsg = {} as iKillMsg;
|
|
946
858
|
let unpacker = new MsgUnpacker(chunk.raw);
|
|
947
859
|
unpacked.killer_id = unpacker.unpackInt();
|
|
@@ -955,7 +867,7 @@ export class Client extends EventEmitter {
|
|
|
955
867
|
if (unpacked.killer_id != -1 && unpacked.killer_id < 64)
|
|
956
868
|
unpacked.killer = { ClientInfo: this.SnapshotUnpacker.getObjClientInfo(unpacked.killer_id), PlayerInfo: this.SnapshotUnpacker.getObjPlayerInfo(unpacked.killer_id) }
|
|
957
869
|
this.emit("kill", unpacked)
|
|
958
|
-
} else if (chunk.msgid ==
|
|
870
|
+
} else if (chunk.msgid == NETMSG.Game.SV_MOTD) {
|
|
959
871
|
let unpacker = new MsgUnpacker(chunk.raw);
|
|
960
872
|
let message = unpacker.unpackString();
|
|
961
873
|
this.emit("motd", message);
|
|
@@ -963,8 +875,8 @@ export class Client extends EventEmitter {
|
|
|
963
875
|
|
|
964
876
|
// packets neccessary for connection
|
|
965
877
|
// https://ddnet.org/docs/libtw2/connection/
|
|
966
|
-
if (chunk.msgid ==
|
|
967
|
-
var Msg = new MsgPacker(
|
|
878
|
+
if (chunk.msgid == NETMSG.Game.SV_READYTOENTER) {
|
|
879
|
+
var Msg = new MsgPacker(NETMSG.System.NETMSG_ENTERGAME, true, 1); /* entergame */
|
|
968
880
|
this.SendMsgEx(Msg);
|
|
969
881
|
this.OnEnterGame();
|
|
970
882
|
}
|
|
@@ -983,8 +895,6 @@ export class Client extends EventEmitter {
|
|
|
983
895
|
}
|
|
984
896
|
})
|
|
985
897
|
}
|
|
986
|
-
|
|
987
|
-
|
|
988
898
|
/** Sending the input. (automatically done unless options.lightweight is on) */
|
|
989
899
|
sendInput(input = this.movement.input) {
|
|
990
900
|
if (this.State != States.STATE_ONLINE)
|