teeworlds 2.5.2 → 2.5.4

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/lib/client.ts CHANGED
@@ -1,5 +1,7 @@
1
- import { randomBytes } from "crypto";
2
1
 
2
+
3
+ import { randomBytes } from "crypto";
4
+ import { lookup as dnsLookup } from 'dns';
3
5
  import net from 'dgram';
4
6
  import { EventEmitter } from 'stream';
5
7
 
@@ -7,147 +9,20 @@ import { unpackString, MsgUnpacker } from "./MsgUnpacker";
7
9
  let { version } = require('../package.json');
8
10
 
9
11
  import Movement from './components/movement';
10
- import { PlayerInput, PlayerInfo, Projectile, Laser, Pickup, Flag, GameInfo, GameData, CharacterCore, Character, ClientInfo, SpectatorInfo, Common, Explosion, Spawn, HammerHit, Death, SoundGlobal, SoundWorld, DamageInd } from "./snapshots";
12
+ import { _Packet, Chunk, DeltaItem, SnapshotItemTypes } from './enums_types/types';
11
13
 
12
14
  import { MsgPacker } from './MsgPacker';
13
- import { Item, Snapshot } from './snapshot';
15
+ import { Snapshot } from './snapshot';
14
16
  import { Huffman } from "./huffman";
15
17
  import { Game } from "./components/game";
16
18
  import { SnapshotWrapper } from "./components/snapshot";
17
19
 
18
20
  import { UUIDManager } from "./UUIDManager";
21
+ import { NETMSG, States } from "./enums_types/protocol";
22
+ import { Rcon } from "./components/rcon";
19
23
 
20
24
  const huff = new Huffman();
21
25
 
22
- enum States {
23
- STATE_OFFLINE = 0,
24
- STATE_CONNECTING,
25
- STATE_LOADING,
26
- STATE_ONLINE,
27
- STATE_DEMOPLAYBACK,
28
- STATE_QUITTING,
29
- STATE_RESTARTING
30
- }
31
-
32
-
33
- enum NETMSG_Game {
34
- EX,
35
- SV_MOTD,
36
- SV_BROADCAST,
37
- SV_CHAT,
38
- SV_KILLMSG,
39
- SV_SOUNDGLOBAL,
40
- SV_TUNEPARAMS,
41
- SV_EXTRAPROJECTILE,
42
- SV_READYTOENTER,
43
- SV_WEAPONPICKUP,
44
- SV_EMOTICON,
45
- SV_VOTECLEAROPTIONS,
46
- SV_VOTEOPTIONLISTADD,
47
- SV_VOTEOPTIONADD,
48
- SV_VOTEOPTIONREMOVE,
49
- SV_VOTESET,
50
- SV_VOTESTATUS,
51
- CL_SAY,
52
- CL_SETTEAM,
53
- CL_SETSPECTATORMODE,
54
- CL_STARTINFO,
55
- CL_CHANGEINFO,
56
- CL_KILL,
57
- CL_EMOTICON,
58
- CL_VOTE,
59
- CL_CALLVOTE,
60
- CL_ISDDNETLEGACY,
61
- SV_DDRACETIMELEGACY,
62
- SV_RECORDLEGACY,
63
- UNUSED,
64
- SV_TEAMSSTATELEGACY,
65
- CL_SHOWOTHERSLEGACY,
66
- NUM
67
- }
68
-
69
- enum NETMSG_Sys {
70
- NETMSG_EX = 0,
71
-
72
- // the first thing sent by the client
73
- // contains the version info for the client
74
- NETMSG_INFO = 1,
75
-
76
- // sent by server
77
- NETMSG_MAP_CHANGE, // sent when client should switch map
78
- NETMSG_MAP_DATA, // map transfer, contains a chunk of the map file
79
- NETMSG_CON_READY, // connection is ready, client should send start info
80
- NETMSG_SNAP, // normal snapshot, multiple parts
81
- NETMSG_SNAPEMPTY, // empty snapshot
82
- NETMSG_SNAPSINGLE, // ?
83
- NETMSG_SNAPSMALL, //
84
- NETMSG_INPUTTIMING, // reports how off the input was
85
- NETMSG_RCON_AUTH_STATUS, // result of the authentication
86
- NETMSG_RCON_LINE, // line that should be printed to the remote console
87
-
88
- NETMSG_AUTH_CHALLANGE, //
89
- NETMSG_AUTH_RESULT, //
90
-
91
- // sent by client
92
- NETMSG_READY, //
93
- NETMSG_ENTERGAME,
94
- NETMSG_INPUT, // contains the inputdata from the client
95
- NETMSG_RCON_CMD, //
96
- NETMSG_RCON_AUTH, //
97
- NETMSG_REQUEST_MAP_DATA, //
98
-
99
- NETMSG_AUTH_START, //
100
- NETMSG_AUTH_RESPONSE, //
101
-
102
- // sent by both
103
- NETMSG_PING,
104
- NETMSG_PING_REPLY,
105
- NETMSG_ERROR,
106
-
107
- // sent by server (todo: move it up)
108
- NETMSG_RCON_CMD_ADD,
109
- NETMSG_RCON_CMD_REM,
110
-
111
- NUM_NETMSGS,
112
-
113
- NETMSG_WHATIS = 65536,
114
- NETMSG_ITIS,
115
- NETMSG_IDONTKNOW,
116
-
117
- NETMSG_RCONTYPE,
118
- NETMSG_MAP_DETAILS,
119
- NETMSG_CAPABILITIES,
120
- NETMSG_CLIENTVER,
121
- NETMSG_PINGEX,
122
- NETMSG_PONGEX,
123
- NETMSG_CHECKSUM_REQUEST,
124
- NETMSG_CHECKSUM_RESPONSE,
125
- NETMSG_CHECKSUM_ERROR,
126
-
127
- NETMSG_REDIRECT,
128
-
129
- NETMSG_I_AM_NPM_PACKAGE
130
-
131
- }
132
-
133
- interface chunk {
134
- bytes: number,
135
- flags: number,
136
- sequence?: number,
137
- seq?: number,
138
- // type: 'sys' | 'game',
139
- sys: Boolean,
140
- msgid: number,
141
- msg: string,
142
- raw: Buffer,
143
- extended_msgid?: Buffer;
144
- }
145
-
146
- interface _packet {
147
- twprotocol: { flags: number, ack: number, chunkAmount: number, size: number },
148
- chunks: chunk[]
149
- }
150
-
151
26
  var messageTypes = [
152
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"],
153
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"]
@@ -157,27 +32,27 @@ var messageTypes = [
157
32
  declare interface iMessage {
158
33
  team: number,
159
34
  client_id: number,
160
- author?: { ClientInfo?: ClientInfo, PlayerInfo?: PlayerInfo },
35
+ author?: { ClientInfo?: SnapshotItemTypes.ClientInfo, PlayerInfo?: SnapshotItemTypes.PlayerInfo },
161
36
  message: string
162
37
  }
163
38
 
164
39
  declare interface iEmoticon {
165
40
  client_id: number,
166
41
  emoticon: number,
167
- author?: { ClientInfo?: ClientInfo, PlayerInfo?: PlayerInfo }
42
+ author?: { ClientInfo?: SnapshotItemTypes.ClientInfo, PlayerInfo?: SnapshotItemTypes.PlayerInfo }
168
43
  }
169
44
 
170
45
  declare interface iKillMsg {
171
46
  killer_id: number,
172
- killer?: { ClientInfo?: ClientInfo, PlayerInfo?: PlayerInfo },
47
+ killer?: { ClientInfo?: SnapshotItemTypes.ClientInfo, PlayerInfo?: SnapshotItemTypes.PlayerInfo },
173
48
  victim_id: number,
174
- victim?: { ClientInfo?: ClientInfo, PlayerInfo?: PlayerInfo },
49
+ victim?: { ClientInfo?: SnapshotItemTypes.ClientInfo, PlayerInfo?: SnapshotItemTypes.PlayerInfo },
175
50
  weapon: number,
176
51
  special_mode: number
177
52
  }
178
53
 
179
54
  declare interface iOptions {
180
- identity?: ClientInfo,
55
+ identity?: SnapshotItemTypes.ClientInfo,
181
56
  password?: string,
182
57
  ddnet_version?: {version: number, release_version: string},
183
58
  timeout?: number, // in ms
@@ -185,32 +60,37 @@ declare interface iOptions {
185
60
  lightweight?: boolean // experimental, only sends keepalive's (sendinput has to be called manually)
186
61
  }
187
62
 
188
- export declare interface Client {
189
-
190
-
191
- on(event: 'connected', listener: () => void): this;
192
- on(event: 'disconnect', listener: (reason: string) => void): this;
193
-
194
- on(event: 'emote', listener: (message: iEmoticon) => void): this;
195
- on(event: 'message', listener: (message: iMessage) => void): this;
196
- on(event: 'broadcast', listener: (message: string) => void): this;
197
- on(event: 'kill', listener: (kill: iKillMsg) => void): this;
198
- on(event: 'motd', listener: (message: string) => void): this;
199
-
200
- on(event: 'map_details', listener: (message: {map_name: string, map_sha256: Buffer, map_crc: number, map_size: number, map_url: string}) => void): this;
201
- on(event: 'capabilities', listener: (message: {ChatTimeoutCode: boolean, AnyPlayerFlag: boolean, PingEx: boolean, AllowDummy: boolean, SyncWeaponInput: boolean}) => void): this;
202
-
203
- 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;
204
75
  }
205
76
 
206
77
  export class Client extends EventEmitter {
207
-
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;
208
87
  private host: string;
209
88
  private port: number;
210
89
  private name: string;
211
90
  private State: number; // 0 = offline; 1 = STATE_CONNECTING = 1, STATE_LOADING = 2, STATE_ONLINE = 3
212
91
  private ack: number;
213
92
  private clientAck: number;
93
+ private lastCheckedChunkAck: number;
214
94
  private receivedSnaps: number; /* wait for 2 ss before seeing self as connected */
215
95
  private socket: net.Socket | undefined;
216
96
  private TKEN: Buffer;
@@ -258,7 +138,7 @@ export class Client extends EventEmitter {
258
138
  this.currentSnapshotGameTick = 0;
259
139
 
260
140
  this.SnapshotParts = 0;
261
-
141
+ this.rcon = new Rcon(this);
262
142
  this.SnapUnpacker = new Snapshot(this);
263
143
  // this.eSnapHolder = [];
264
144
  this.requestResend = false;
@@ -277,6 +157,7 @@ export class Client extends EventEmitter {
277
157
  this.State = States.STATE_OFFLINE; // 0 = offline; 1 = STATE_CONNECTING = 1, STATE_LOADING = 2, STATE_ONLINE = 3
278
158
  this.ack = 0; // ack of messages the client has received
279
159
  this.clientAck = 0; // ack of messages the client has sent
160
+ this.lastCheckedChunkAck = 0; // this.ack gets reset to this when flushing - used for resetting tick on e.g. map change
280
161
  this.receivedSnaps = 0; /* wait for 2 snaps before seeing self as connected */
281
162
  this.socket = net.createSocket("udp4");
282
163
  this.socket.bind();
@@ -295,25 +176,35 @@ export class Client extends EventEmitter {
295
176
 
296
177
  this.UUIDManager = new UUIDManager();
297
178
 
298
- this.UUIDManager.RegisterName("what-is@ddnet.tw", NETMSG_Sys.NETMSG_WHATIS);
299
- this.UUIDManager.RegisterName("it-is@ddnet.tw", NETMSG_Sys.NETMSG_ITIS);
300
- this.UUIDManager.RegisterName("i-dont-know@ddnet.tw", NETMSG_Sys.NETMSG_IDONTKNOW);
301
-
302
- this.UUIDManager.RegisterName("rcon-type@ddnet.tw", NETMSG_Sys.NETMSG_RCONTYPE);
303
- this.UUIDManager.RegisterName("map-details@ddnet.tw", NETMSG_Sys.NETMSG_MAP_DETAILS);
304
- this.UUIDManager.RegisterName("capabilities@ddnet.tw", NETMSG_Sys.NETMSG_CAPABILITIES);
305
- this.UUIDManager.RegisterName("clientver@ddnet.tw", NETMSG_Sys.NETMSG_CLIENTVER);
306
- this.UUIDManager.RegisterName("ping@ddnet.tw", NETMSG_Sys.NETMSG_PING);
307
- this.UUIDManager.RegisterName("pong@ddnet.tw", NETMSG_Sys.NETMSG_PONGEX);
308
- this.UUIDManager.RegisterName("checksum-request@ddnet.tw", NETMSG_Sys.NETMSG_CHECKSUM_REQUEST);
309
- this.UUIDManager.RegisterName("checksum-response@ddnet.tw", NETMSG_Sys.NETMSG_CHECKSUM_RESPONSE);
310
- this.UUIDManager.RegisterName("checksum-error@ddnet.tw", NETMSG_Sys.NETMSG_CHECKSUM_ERROR);
311
- this.UUIDManager.RegisterName("redirect@ddnet.org", NETMSG_Sys.NETMSG_REDIRECT);
312
-
313
- this.UUIDManager.RegisterName("i-am-npm-package@swarfey.gitlab.io", NETMSG_Sys.NETMSG_I_AM_NPM_PACKAGE);
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
+ this.UUIDManager.RegisterName("i-am-npm-package@swarfey.gitlab.io", NETMSG.System.NETMSG_I_AM_NPM_PACKAGE);
314
195
 
315
196
  }
316
197
 
198
+ private OnEnterGame() {
199
+ this.snaps = [];
200
+ this.SnapUnpacker = new Snapshot(this);
201
+ this.SnapshotParts = 0;
202
+ this.receivedSnaps = 0;
203
+ this.SnapshotUnpacker = new SnapshotWrapper(this);
204
+ this.currentSnapshotGameTick = 0;
205
+ this.AckGameTick = -1;
206
+ this.PredGameTick = 0;
207
+ }
317
208
  private ResendAfter(lastAck: number) {
318
209
  this.clientAck = lastAck;
319
210
 
@@ -327,8 +218,8 @@ export class Client extends EventEmitter {
327
218
  this.SendMsgEx(toResend);
328
219
  }
329
220
 
330
- private Unpack(packet: Buffer): _packet {
331
- var unpacked: _packet = { twprotocol: { flags: packet[0] >> 4, ack: ((packet[0]&0xf)<<8) | packet[1], chunkAmount: packet[2], size: packet.byteLength - 3 }, chunks: [] }
221
+ private Unpack(packet: Buffer): _Packet {
222
+ var unpacked: _Packet = { twprotocol: { flags: packet[0] >> 4, ack: ((packet[0]&0xf)<<8) | packet[1], chunkAmount: packet[2], size: packet.byteLength - 3 }, chunks: [] }
332
223
 
333
224
 
334
225
  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)
@@ -346,10 +237,9 @@ export class Client extends EventEmitter {
346
237
 
347
238
 
348
239
  for (let i = 0; i < unpacked.twprotocol.chunkAmount; i++) {
349
- var chunk: chunk = {} as chunk;
240
+ var chunk: Chunk = {} as Chunk;
350
241
  chunk.bytes = ((packet[0] & 0x3f) << 4) | (packet[1] & ((1 << 4) - 1));
351
242
  chunk.flags = (packet[0] >> 6) & 3;
352
- chunk.sequence = -1;
353
243
 
354
244
  if (chunk.flags & 1) {
355
245
  chunk.seq = ((packet[1] & 0xf0) << 2) | packet[2];
@@ -459,9 +349,23 @@ export class Client extends EventEmitter {
459
349
  this.socket.send(packet, 0, packet.length, this.port, this.host)
460
350
  }
461
351
 
462
- /** Queue a chunk (It will get sent in the next packet). */
463
- QueueChunkEx(Msg: MsgPacker) {
352
+ /** Queue a chunk (instantly sent if flush flag is set - otherwise it will be sent in the next packet). */
353
+ QueueChunkEx(Msg: MsgPacker | MsgPacker[]) {
354
+ if (Msg instanceof Array) {
355
+ for (let chunk of Msg)
356
+ this.QueueChunkEx(chunk);
357
+ return;
358
+ }
359
+ if (this.queueChunkEx.length > 0) {
360
+ let total_size = 0;
361
+ for (let chunk of this.queueChunkEx)
362
+ total_size += chunk.size;
363
+ if (total_size + Msg.size + 3 > 1394 - 4)
364
+ this.Flush();
365
+ }
464
366
  this.queueChunkEx.push(Msg);
367
+ if (Msg.flag & 4)
368
+ this.Flush();
465
369
  }
466
370
 
467
371
  /** Send a Raw Buffer (as chunk) to the server. */
@@ -482,10 +386,9 @@ export class Client extends EventEmitter {
482
386
  }
483
387
 
484
388
  private MsgToChunk(packet: Buffer) {
485
- var chunk: chunk = {} as chunk;
389
+ var chunk: Chunk = {} as Chunk;
486
390
  chunk.bytes = ((packet[0] & 0x3f) << 4) | (packet[1] & ((1 << 4) - 1));
487
391
  chunk.flags = (packet[0] >> 6) & 3;
488
- chunk.sequence = -1;
489
392
 
490
393
  if (chunk.flags & 1) {
491
394
  chunk.seq = ((packet[1]&0xf0)<<2) | packet[2];
@@ -509,10 +412,27 @@ export class Client extends EventEmitter {
509
412
  }
510
413
  return chunk;
511
414
  }
415
+ Flush() {
416
+ // if (this.queueChunkEx.length == 0)
417
+ console.log("flushing");
418
+ this.SendMsgEx(this.queueChunkEx);
419
+ this.queueChunkEx = [];
420
+ this.ack = this.lastCheckedChunkAck;
512
421
 
422
+ }
513
423
 
514
424
  /** Connect the client to the server. */
515
- connect() {
425
+ async connect() {
426
+ // test via regex whether or not this.host is a domain or an ip
427
+ // if not, resolve it
428
+ if (!this.host.match(/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/)) {
429
+ dnsLookup(this.host, 4, (err, address, family) => {
430
+ if (err) throw err;
431
+ this.host = address;
432
+ console.log(err, address, family)
433
+ })
434
+ }
435
+
516
436
  this.State = States.STATE_CONNECTING;
517
437
 
518
438
  let predTimer = setInterval(() => {
@@ -533,8 +453,10 @@ export class Client extends EventEmitter {
533
453
  }, 500);
534
454
  if (!this.options?.lightweight) {
535
455
  let inputInterval = setInterval(() => {
536
- if (this.State == States.STATE_OFFLINE)
456
+ if (this.State == States.STATE_OFFLINE) {
537
457
  clearInterval(inputInterval)
458
+ // console.log("???");
459
+ }
538
460
  if (this.State != States.STATE_ONLINE)
539
461
  return;
540
462
  this.time = new Date().getTime();
@@ -555,7 +477,6 @@ export class Client extends EventEmitter {
555
477
  let timeoutTime = this.options?.timeout ? this.options.timeout : 15000;
556
478
  if ((new Date().getTime() - this.lastRecvTime) > timeoutTime) {
557
479
  this.State = States.STATE_OFFLINE;
558
- this.emit("timeout");
559
480
  this.emit("disconnect", "Timed Out. (no packets received for " + (new Date().getTime() - this.lastRecvTime) + "ms)");
560
481
  clearInterval(Timeout);
561
482
  }
@@ -595,7 +516,7 @@ export class Client extends EventEmitter {
595
516
  }
596
517
 
597
518
  var i_am_npm_package = new MsgPacker(0, true, 1);
598
- i_am_npm_package.AddBuffer(this.UUIDManager.LookupType(NETMSG_Sys.NETMSG_I_AM_NPM_PACKAGE)!.hash);
519
+ i_am_npm_package.AddBuffer(this.UUIDManager.LookupType(NETMSG.System.NETMSG_I_AM_NPM_PACKAGE)!.hash);
599
520
 
600
521
  i_am_npm_package.AddString(`https://www.npmjs.com/package/teeworlds/v/${version}`);
601
522
 
@@ -614,11 +535,21 @@ export class Client extends EventEmitter {
614
535
  this.lastRecvTime = new Date().getTime();
615
536
  }
616
537
 
617
- var unpacked: _packet = this.Unpack(packet);
618
- unpacked.chunks = unpacked.chunks.filter(chunk => ((chunk.flags & 2) && (chunk.flags & 1)) ? chunk.seq! > this.ack : true); // filter out already received chunks
619
-
538
+ var unpacked: _Packet = this.Unpack(packet);
539
+ // unpacked.chunks = unpacked.chunks.filter(chunk => ((chunk.flags & 2) && (chunk.flags & 1)) ? chunk.seq! > this.ack : true); // filter out already received chunks
540
+ this.sentChunkQueue.forEach((buff, i) => {
541
+ let chunkFlags = (buff[0] >> 6) & 3;
542
+ if (chunkFlags & 1) {
543
+ let chunk = this.MsgToChunk(buff);
544
+ if (chunk.seq && chunk.seq >= this.ack)
545
+ this.sentChunkQueue.splice(i, 1);
546
+ }
547
+ })
620
548
  unpacked.chunks.forEach(chunk => {
549
+ if (!(((chunk.flags & 2) && (chunk.flags & 1)) ? chunk.seq! > this.ack : true))
550
+ return; // filter out already received chunks
621
551
  if (chunk.flags & 1 && (chunk.flags !== 15)) { // vital and not connless
552
+ this.lastCheckedChunkAck = chunk.seq!;
622
553
  if (chunk.seq === (this.ack+1)%(1<<10)) { // https://github.com/nobody-mb/twchatonly/blob/master/chatonly.cpp#L237
623
554
  this.ack = chunk.seq!;
624
555
 
@@ -628,47 +559,35 @@ export class Client extends EventEmitter {
628
559
  let Bottom = (this.ack - (1<<10)/2);
629
560
 
630
561
  if(Bottom < 0) {
631
- if((chunk.seq! <= this.ack) || (chunk.seq! >= (Bottom + (1<<10))))
632
- return;
562
+ if((chunk.seq! <= this.ack) || (chunk.seq! >= (Bottom + (1<<10)))) {}
563
+ else
564
+ this.requestResend = true;
633
565
  } else {
634
- if(chunk.seq! <= this.ack && chunk.seq! >= Bottom)
635
- return;
566
+ if(chunk.seq! <= this.ack && chunk.seq! >= Bottom) {}
567
+ else
568
+ this.requestResend = true;
636
569
  }
637
- this.requestResend = true;
638
-
639
570
  }
640
571
  }
641
572
 
642
- })
643
- this.sentChunkQueue.forEach((buff, i) => {
644
- let chunkFlags = (buff[0] >> 6) & 3;
645
- if (chunkFlags & 1) {
646
- let chunk = this.MsgToChunk(buff);
647
- if (chunk.seq && chunk.seq >= this.ack)
648
- this.sentChunkQueue.splice(i, 1);
649
- }
650
- })
651
-
652
-
653
- unpacked.chunks.forEach((chunk, index) => {
654
573
  if (chunk.sys) {
655
574
  // system messages
656
- if (chunk.msgid == NETMSG_Sys.NETMSG_PING) { // ping
657
- let packer = new MsgPacker(NETMSG_Sys.NETMSG_PING_REPLY, true, 0);
575
+ if (chunk.msgid == NETMSG.System.NETMSG_PING) { // ping
576
+ let packer = new MsgPacker(NETMSG.System.NETMSG_PING_REPLY, true, 0);
658
577
 
659
578
  this.SendMsgEx(packer); // send ping reply
660
- } else if (chunk.msgid == NETMSG_Sys.NETMSG_PING_REPLY) { // Ping reply
579
+ } else if (chunk.msgid == NETMSG.System.NETMSG_PING_REPLY) { // Ping reply
661
580
  this.game._ping_resolve(new Date().getTime())
662
- }
663
-
581
+ } else if (this.rcon._checkChunks(chunk)) {}
664
582
  // packets neccessary for connection
665
583
  // https://ddnet.org/docs/libtw2/connection/
666
584
 
667
- if (chunk.msgid == NETMSG_Sys.NETMSG_MAP_CHANGE) {
668
- var Msg = new MsgPacker(NETMSG_Sys.NETMSG_READY, true, 1); /* ready */
585
+ if (chunk.msgid == NETMSG.System.NETMSG_MAP_CHANGE) {
586
+ this.Flush();
587
+ var Msg = new MsgPacker(NETMSG.System.NETMSG_READY, true, 1); /* ready */
669
588
  this.SendMsgEx(Msg);
670
- } else if (chunk.msgid == NETMSG_Sys.NETMSG_CON_READY) {
671
- var info = new MsgPacker(NETMSG_Game.CL_STARTINFO, false, 1);
589
+ } else if (chunk.msgid == NETMSG.System.NETMSG_CON_READY) {
590
+ var info = new MsgPacker(NETMSG.Game.CL_STARTINFO, false, 1);
672
591
  if (this.options?.identity) {
673
592
  info.AddString(this.options.identity.name);
674
593
  info.AddString(this.options.identity.clan);
@@ -692,7 +611,7 @@ export class Client extends EventEmitter {
692
611
  this.SendMsgEx([info, crashmeplx]);
693
612
  }
694
613
 
695
- if (chunk.msgid >= NETMSG_Sys.NETMSG_SNAP && chunk.msgid <= NETMSG_Sys.NETMSG_SNAPSINGLE) {
614
+ if (chunk.msgid >= NETMSG.System.NETMSG_SNAP && chunk.msgid <= NETMSG.System.NETMSG_SNAPSINGLE) {
696
615
  this.receivedSnaps++; /* wait for 2 ss before seeing self as connected */
697
616
  if (this.receivedSnaps == 2) {
698
617
  if (this.State != States.STATE_ONLINE)
@@ -713,12 +632,12 @@ export class Client extends EventEmitter {
713
632
  let Crc = 0;
714
633
  let CompleteSize = 0;
715
634
 
716
- if (chunk.msgid == NETMSG_Sys.NETMSG_SNAP) {
635
+ if (chunk.msgid == NETMSG.System.NETMSG_SNAP) {
717
636
  NumParts = unpacker.unpackInt();
718
637
  Part = unpacker.unpackInt();
719
638
  }
720
639
 
721
- if (chunk.msgid != NETMSG_Sys.NETMSG_SNAPEMPTY) {
640
+ if (chunk.msgid != NETMSG.System.NETMSG_SNAPEMPTY) {
722
641
  Crc = unpacker.unpackInt();
723
642
  PartSize = unpacker.unpackInt();
724
643
  }
@@ -761,28 +680,28 @@ export class Client extends EventEmitter {
761
680
 
762
681
  }
763
682
 
764
- if (chunk.msgid >= NETMSG_Sys.NETMSG_WHATIS && chunk.msgid <= NETMSG_Sys.NETMSG_CHECKSUM_ERROR) {
765
- if (chunk.msgid == NETMSG_Sys.NETMSG_WHATIS) {
683
+ if (chunk.msgid >= NETMSG.System.NETMSG_WHATIS && chunk.msgid <= NETMSG.System.NETMSG_CHECKSUM_ERROR) {
684
+ if (chunk.msgid == NETMSG.System.NETMSG_WHATIS) {
766
685
  let Uuid = chunk.raw.slice(0, 16);
767
686
 
768
687
  let uuid = this.UUIDManager.LookupUUID(Uuid);
769
688
  let packer = new MsgPacker(0, true, 1);
770
689
  if (uuid !== undefined) {
771
690
  // IT_IS msg
772
- packer.AddBuffer(this.UUIDManager.LookupType(NETMSG_Sys.NETMSG_ITIS)!.hash);
691
+ packer.AddBuffer(this.UUIDManager.LookupType(NETMSG.System.NETMSG_ITIS)!.hash);
773
692
 
774
693
  packer.AddBuffer(Uuid);
775
694
  packer.AddString(uuid.name);
776
695
  } else {
777
696
  // dont_know msg
778
- packer.AddBuffer(this.UUIDManager.LookupType(NETMSG_Sys.NETMSG_IDONTKNOW)!.hash);
697
+ packer.AddBuffer(this.UUIDManager.LookupType(NETMSG.System.NETMSG_IDONTKNOW)!.hash);
779
698
 
780
699
  packer.AddBuffer(Uuid);
781
700
  }
782
701
  this.QueueChunkEx(packer)
783
702
  }
784
703
 
785
- if (chunk.msgid == NETMSG_Sys.NETMSG_MAP_DETAILS) { // TODO: option for downloading maps
704
+ if (chunk.msgid == NETMSG.System.NETMSG_MAP_DETAILS) { // TODO: option for downloading maps
786
705
  let unpacker = new MsgUnpacker(chunk.raw);
787
706
 
788
707
  let map_name = unpacker.unpackString();
@@ -799,7 +718,7 @@ export class Client extends EventEmitter {
799
718
  this.emit("map_details", {map_name, map_sha256, map_crc, map_size, map_url})
800
719
  // unpacker.unpack
801
720
 
802
- } else if (chunk.msgid == NETMSG_Sys.NETMSG_CAPABILITIES) {
721
+ } else if (chunk.msgid == NETMSG.System.NETMSG_CAPABILITIES) {
803
722
  let unpacker = new MsgUnpacker(chunk.raw);
804
723
  let Version = unpacker.unpackInt();
805
724
  let Flags = unpacker.unpackInt();
@@ -837,9 +756,9 @@ export class Client extends EventEmitter {
837
756
  }
838
757
  this.emit("capabilities", {ChatTimeoutCode, AnyPlayerFlag, PingEx, AllowDummy, SyncWeaponInput});
839
758
  // https://github.com/ddnet/ddnet/blob/06e3eb564150e9ab81b3a5595c48e9fe5952ed32/src/engine/client/client.cpp#L1565
840
- } else if (chunk.msgid == NETMSG_Sys.NETMSG_PINGEX) {
759
+ } else if (chunk.msgid == NETMSG.System.NETMSG_PINGEX) {
841
760
  let packer = new MsgPacker(0, true, 2);
842
- packer.AddBuffer(this.UUIDManager.LookupType(NETMSG_Sys.NETMSG_PONGEX)!.hash);
761
+ packer.AddBuffer(this.UUIDManager.LookupType(NETMSG.System.NETMSG_PONGEX)!.hash);
843
762
 
844
763
  this.SendMsgEx(packer, 2);
845
764
  }
@@ -850,9 +769,9 @@ export class Client extends EventEmitter {
850
769
  // game messages
851
770
 
852
771
  // vote list:
853
- if (chunk.msgid == NETMSG_Game.SV_VOTECLEAROPTIONS) {
772
+ if (chunk.msgid == NETMSG.Game.SV_VOTECLEAROPTIONS) {
854
773
  this.VoteList = [];
855
- } else if (chunk.msgid == NETMSG_Game.SV_VOTEOPTIONLISTADD) {
774
+ } else if (chunk.msgid == NETMSG.Game.SV_VOTEOPTIONLISTADD) {
856
775
  let unpacker = new MsgUnpacker(chunk.raw)
857
776
  let NumOptions = unpacker.unpackInt()
858
777
  let list: string[] = [];
@@ -862,11 +781,11 @@ export class Client extends EventEmitter {
862
781
  list = list.slice(0, NumOptions);
863
782
 
864
783
  this.VoteList.push(...list);
865
- } else if (chunk.msgid == NETMSG_Game.SV_VOTEOPTIONADD) {
784
+ } else if (chunk.msgid == NETMSG.Game.SV_VOTEOPTIONADD) {
866
785
  let unpacker = new MsgUnpacker(chunk.raw)
867
786
 
868
787
  this.VoteList.push(unpacker.unpackString());
869
- } else if (chunk.msgid == NETMSG_Game.SV_VOTEOPTIONREMOVE) {
788
+ } else if (chunk.msgid == NETMSG.Game.SV_VOTEOPTIONREMOVE) {
870
789
  let unpacker = new MsgUnpacker(chunk.raw)
871
790
 
872
791
  let index = this.VoteList.indexOf(unpacker.unpackString());
@@ -877,7 +796,7 @@ export class Client extends EventEmitter {
877
796
  }
878
797
 
879
798
  // events
880
- if (chunk.msgid == NETMSG_Game.SV_EMOTICON) {
799
+ if (chunk.msgid == NETMSG.Game.SV_EMOTICON) {
881
800
  let unpacker = new MsgUnpacker(chunk.raw);
882
801
  let unpacked = {
883
802
  client_id: unpacker.unpackInt(),
@@ -894,11 +813,11 @@ export class Client extends EventEmitter {
894
813
 
895
814
 
896
815
 
897
- } else if (chunk.msgid == NETMSG_Game.SV_BROADCAST) {
816
+ } else if (chunk.msgid == NETMSG.Game.SV_BROADCAST) {
898
817
  let unpacker = new MsgUnpacker(chunk.raw);
899
818
 
900
819
  this.emit("broadcast", unpacker.unpackString());
901
- } if (chunk.msgid == NETMSG_Game.SV_CHAT) {
820
+ } if (chunk.msgid == NETMSG.Game.SV_CHAT) {
902
821
  let unpacker = new MsgUnpacker(chunk.raw);
903
822
  let unpacked: iMessage = {
904
823
  team: unpacker.unpackInt(),
@@ -913,7 +832,7 @@ export class Client extends EventEmitter {
913
832
  }
914
833
  }
915
834
  this.emit("message", unpacked)
916
- } else if (chunk.msgid == NETMSG_Game.SV_KILLMSG) {
835
+ } else if (chunk.msgid == NETMSG.Game.SV_KILLMSG) {
917
836
  let unpacked: iKillMsg = {} as iKillMsg;
918
837
  let unpacker = new MsgUnpacker(chunk.raw);
919
838
  unpacked.killer_id = unpacker.unpackInt();
@@ -927,7 +846,7 @@ export class Client extends EventEmitter {
927
846
  if (unpacked.killer_id != -1 && unpacked.killer_id < 64)
928
847
  unpacked.killer = { ClientInfo: this.SnapshotUnpacker.getObjClientInfo(unpacked.killer_id), PlayerInfo: this.SnapshotUnpacker.getObjPlayerInfo(unpacked.killer_id) }
929
848
  this.emit("kill", unpacked)
930
- } else if (chunk.msgid == NETMSG_Game.SV_MOTD) {
849
+ } else if (chunk.msgid == NETMSG.Game.SV_MOTD) {
931
850
  let unpacker = new MsgUnpacker(chunk.raw);
932
851
  let message = unpacker.unpackString();
933
852
  this.emit("motd", message);
@@ -935,22 +854,26 @@ export class Client extends EventEmitter {
935
854
 
936
855
  // packets neccessary for connection
937
856
  // https://ddnet.org/docs/libtw2/connection/
938
- if (chunk.msgid == NETMSG_Game.SV_READYTOENTER) {
939
- var Msg = new MsgPacker(15, true, 1); /* entergame */
857
+ if (chunk.msgid == NETMSG.Game.SV_READYTOENTER) {
858
+ var Msg = new MsgPacker(NETMSG.System.NETMSG_ENTERGAME, true, 1); /* entergame */
940
859
  this.SendMsgEx(Msg);
860
+ this.OnEnterGame();
941
861
  }
942
862
  }
943
863
  })
944
864
 
945
-
946
- if (new Date().getTime() - this.time >= 1000 && this.State == States.STATE_ONLINE) {
947
- this.time = new Date().getTime();
948
- this.SendControlMsg(0);
865
+ if (this.State == States.STATE_ONLINE) {
866
+ if (new Date().getTime() - this.time >= 500) {
867
+ this.Flush();
868
+ }
869
+ if (new Date().getTime() - this.time >= 1000) {
870
+ this.time = new Date().getTime();
871
+ this.SendControlMsg(0);
872
+ }
873
+
949
874
  }
950
875
  })
951
876
  }
952
-
953
-
954
877
  /** Sending the input. (automatically done unless options.lightweight is on) */
955
878
  sendInput(input = this.movement.input) {
956
879
  if (this.State != States.STATE_ONLINE)