teeworlds 2.4.4 → 2.4.7

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
@@ -5,12 +5,16 @@ import { EventEmitter } from 'stream';
5
5
 
6
6
  import { unpackString, MsgUnpacker } from "./MsgUnpacker";
7
7
 
8
- import Movement from './movement';
8
+ import Movement from './components/movement';
9
+ import { PlayerInput, PlayerInfo, Projectile, Laser, Pickup, Flag, GameInfo, GameData, CharacterCore, Character, ClientInfo, SpectatorInfo, Common, Explosion, Spawn, HammerHit, Death, SoundGlobal, SoundWorld, DamageInd } from "./snapshots";
9
10
 
10
11
  import { MsgPacker } from './MsgPacker';
11
- import { Snapshot } from './snapshot';
12
+ import { Item, Snapshot } from './snapshot';
12
13
  import Huffman from "./huffman";
13
14
  import { Game } from "./components/game";
15
+ import { SnapshotWrapper } from "./components/snapshot";
16
+
17
+ import { UUIDManager } from "./UUIDManager";
14
18
 
15
19
  const huff = new Huffman();
16
20
 
@@ -104,6 +108,21 @@ enum NETMSG_Sys {
104
108
  NETMSG_RCON_CMD_REM,
105
109
 
106
110
  NUM_NETMSGS,
111
+
112
+ NETMSG_WHATIS = 65536,
113
+ NETMSG_ITIS,
114
+ NETMSG_IDONTKNOW,
115
+
116
+ NETMSG_RCONTYPE,
117
+ NETMSG_MAP_DETAILS,
118
+ NETMSG_CAPABILITIES,
119
+ NETMSG_CLIENTVER,
120
+ NETMSG_PINGEX,
121
+ NETMSG_PONGEX,
122
+ NETMSG_CHECKSUM_REQUEST,
123
+ NETMSG_CHECKSUM_RESPONSE,
124
+ NETMSG_CHECKSUM_ERROR
125
+
107
126
  }
108
127
 
109
128
  interface chunk {
@@ -118,9 +137,7 @@ interface chunk {
118
137
  raw: Buffer,
119
138
  extended_msgid?: Buffer;
120
139
  }
121
- function toHexStream(buff: Buffer): string {
122
- return buff.toJSON().data.map(a => ('0' + (a & 0xff).toString(16)).slice(-2)).join("");
123
- }
140
+
124
141
  interface _packet {
125
142
  twprotocol: { flags: number, ack: number, chunkAmount: number, size: number },
126
143
  chunks: chunk[]
@@ -131,42 +148,7 @@ var messageTypes = [
131
148
  ["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"]
132
149
  ]
133
150
 
134
- var messageUUIDs = {
135
- "WHAT_IS": Buffer.from([0x24, 0x5e, 0x50, 0x97, 0x9f, 0xe0, 0x39, 0xd6, 0xbf, 0x7d, 0x9a, 0x29, 0xe1, 0x69, 0x1e, 0x4c]),
136
- "IT_IS": Buffer.from([0x69, 0x54, 0x84, 0x7e, 0x2e, 0x87, 0x36, 0x03, 0xb5, 0x62, 0x36, 0xda, 0x29, 0xed, 0x1a, 0xca]),
137
- "I_DONT_KNOW": Buffer.from([0x41, 0x69, 0x11, 0xb5, 0x79, 0x73, 0x33, 0xbf, 0x8d, 0x52, 0x7b, 0xf0, 0x1e, 0x51, 0x9c, 0xf0]),
138
- "RCON_TYPE": Buffer.from([0x12, 0x81, 0x0e, 0x1f, 0xa1, 0xdb, 0x33, 0x78, 0xb4, 0xfb, 0x16, 0x4e, 0xd6, 0x50, 0x59, 0x26]),
139
- "MAP_DETAILS": Buffer.from([0xf9, 0x11, 0x7b, 0x3c, 0x80, 0x39, 0x34, 0x16, 0x9f, 0xc0, 0xae, 0xf2, 0xbc, 0xb7, 0x5c, 0x03]),
140
- "CLIENT_VERSION": Buffer.from([0x8c, 0x00, 0x13, 0x04, 0x84, 0x61, 0x3e, 0x47, 0x87, 0x87, 0xf6, 0x72, 0xb3, 0x83, 0x5b, 0xd4]),
141
- "CAPABILITIES": Buffer.from([0xf6, 0x21, 0xa5, 0xa1, 0xf5, 0x85, 0x37, 0x75, 0x8e, 0x73, 0x41, 0xbe, 0xee, 0x79, 0xf2, 0xb2]),
142
- }
143
-
144
- function arrStartsWith(arr: number[], arrStart: number[], start = 0) {
145
- arr.splice(0, start)
146
- for (let i = 0; i < arrStart.length; i++) {
147
- if (arr[i] == arrStart[i])
148
- continue;
149
- else return false;
150
- }
151
- return true;
152
- }
153
- declare interface PlayerInfo {
154
- local: number,
155
- client_id: number,
156
- team: number,
157
- score: number,
158
- latency: number,
159
- }
160
151
 
161
- declare interface ClientInfo {
162
- name: string,
163
- clan: string,
164
- country: number,
165
- skin: string,
166
- use_custom_color: number,
167
- color_body: number,
168
- color_feet: number,
169
- }
170
152
  declare interface iMessage {
171
153
  team: number,
172
154
  client_id: number,
@@ -210,6 +192,10 @@ export declare interface Client {
210
192
  on(event: 'kill', listener: (kill: iKillMsg) => void): this;
211
193
  on(event: 'motd', listener: (message: string) => void): this;
212
194
 
195
+ on(event: 'map_details', listener: (message: {map_name: string, map_sha256: Buffer, map_crc: number, map_size: number, map_url: string}) => void): this;
196
+ on(event: 'capabilities', listener: (message: {ChatTimeoutCode: boolean, AnyPlayerFlag: boolean, PingEx: boolean, AllowDummy: boolean, SyncWeaponInput: boolean}) => void): this;
197
+
198
+ on(event: 'snapshot', listener: (items: Item[]) => void): this;
213
199
  }
214
200
 
215
201
  export class Client extends EventEmitter {
@@ -226,6 +212,8 @@ export class Client extends EventEmitter {
226
212
  private time: number;
227
213
  private SnapUnpacker: Snapshot;
228
214
 
215
+ public SnapshotUnpacker: SnapshotWrapper;
216
+
229
217
  private PredGameTick: number;
230
218
  private AckGameTick: number;
231
219
 
@@ -253,6 +241,7 @@ export class Client extends EventEmitter {
253
241
  public readonly options?: iOptions;
254
242
  private requestResend: boolean;
255
243
 
244
+ private UUIDManager: UUIDManager;
256
245
 
257
246
  constructor(ip: string, port: number, nickname: string, options?: iOptions) {
258
247
  super();
@@ -265,7 +254,7 @@ export class Client extends EventEmitter {
265
254
 
266
255
  this.SnapshotParts = 0;
267
256
 
268
- this.SnapUnpacker = new Snapshot();
257
+ this.SnapUnpacker = new Snapshot(this);
269
258
  // this.eSnapHolder = [];
270
259
  this.requestResend = false;
271
260
 
@@ -293,10 +282,28 @@ export class Client extends EventEmitter {
293
282
  this.lastRecvTime = new Date().getTime();
294
283
 
295
284
  this.lastSentMessages = [];
285
+
296
286
  this.movement = new Movement();
297
287
 
298
288
  this.game = new Game(this);
289
+ this.SnapshotUnpacker = new SnapshotWrapper(this);
299
290
 
291
+ this.UUIDManager = new UUIDManager();
292
+
293
+
294
+ this.UUIDManager.RegisterName("what-is@ddnet.tw", NETMSG_Sys.NETMSG_WHATIS);
295
+ this.UUIDManager.RegisterName("it-is@ddnet.tw", NETMSG_Sys.NETMSG_ITIS);
296
+ this.UUIDManager.RegisterName("i-dont-know@ddnet.tw", NETMSG_Sys.NETMSG_IDONTKNOW);
297
+
298
+ this.UUIDManager.RegisterName("rcon-type@ddnet.tw", NETMSG_Sys.NETMSG_RCONTYPE);
299
+ this.UUIDManager.RegisterName("map-details@ddnet.tw", NETMSG_Sys.NETMSG_MAP_DETAILS);
300
+ this.UUIDManager.RegisterName("capabilities@ddnet.tw", NETMSG_Sys.NETMSG_CAPABILITIES);
301
+ this.UUIDManager.RegisterName("clientver@ddnet.tw", NETMSG_Sys.NETMSG_CLIENTVER);
302
+ this.UUIDManager.RegisterName("ping@ddnet.tw", NETMSG_Sys.NETMSG_PING);
303
+ this.UUIDManager.RegisterName("pong@ddnet.tw", NETMSG_Sys.NETMSG_PONGEX);
304
+ this.UUIDManager.RegisterName("checksum-request@ddnet.tw", NETMSG_Sys.NETMSG_CHECKSUM_REQUEST);
305
+ this.UUIDManager.RegisterName("checksum-response@ddnet.tw", NETMSG_Sys.NETMSG_CHECKSUM_RESPONSE);
306
+ this.UUIDManager.RegisterName("checksum-error@ddnet.tw", NETMSG_Sys.NETMSG_CHECKSUM_ERROR);
300
307
 
301
308
  }
302
309
 
@@ -347,12 +354,15 @@ export class Client extends EventEmitter {
347
354
  chunk.msgid = (packet[0] - (packet[0] & 1)) / 2;
348
355
  chunk.msg = messageTypes[packet[0] & 1][chunk.msgid];
349
356
  chunk.raw = packet.slice(1, chunk.bytes)
350
- Object.values(messageUUIDs).forEach((a, i) => {
351
- if (a.byteLength >= 16 && a.compare(packet.slice(0, 16)) == 0) {
352
- chunk.extended_msgid = a;
353
- chunk.msg = Object.keys(messageUUIDs)[i];
357
+ if (chunk.msgid == 0 && chunk.raw.byteLength >= 16) {
358
+ let uuid = this.UUIDManager.LookupUUID(chunk.raw.slice(0, 16));
359
+ if (uuid !== undefined) {
360
+ chunk.extended_msgid = uuid.hash;
361
+ chunk.msg = uuid.name;
362
+ chunk.raw = chunk.raw.slice(16);
363
+ chunk.msgid = uuid.type_id;
354
364
  }
355
- })
365
+ }
356
366
 
357
367
  packet = packet.slice(chunk.bytes)
358
368
  unpacked.chunks.push(chunk)
@@ -360,8 +370,9 @@ export class Client extends EventEmitter {
360
370
  return unpacked
361
371
  }
362
372
 
363
- /* Send a Control Msg to the server. (used for disconnect)*/
364
- SendControlMsg(msg: number, ExtraMsg: string = "") {
373
+
374
+ /** Send a Control Msg to the server. (used for disconnect)*/
375
+ SendControlMsg(msg: number, ExtraMsg: string = "") {
365
376
  this.lastSendTime = new Date().getTime();
366
377
  return new Promise((resolve, reject) => {
367
378
  if (this.socket) {
@@ -380,8 +391,9 @@ export class Client extends EventEmitter {
380
391
  })
381
392
  }
382
393
 
383
- /* Send a Msg (or Msg[]) to the server.*/
384
- SendMsgEx(Msgs: MsgPacker[] | MsgPacker) {
394
+
395
+ /** Send a Msg (or Msg[]) to the server.*/
396
+ SendMsgEx(Msgs: MsgPacker[] | MsgPacker, flags = 0) {
385
397
  if (this.State == States.STATE_OFFLINE)
386
398
  return;
387
399
  if (!this.socket)
@@ -417,7 +429,7 @@ export class Client extends EventEmitter {
417
429
  this.lastSentMessages.push({msg: Msg, ack: this.clientAck})
418
430
  }
419
431
  })
420
- let flags = 0;
432
+ // let flags = 0;
421
433
  if (this.requestResend)
422
434
  flags |= 4;
423
435
 
@@ -439,12 +451,14 @@ export class Client extends EventEmitter {
439
451
  return;
440
452
  this.socket.send(packet, 0, packet.length, this.port, this.host)
441
453
  }
442
- /* Queue a chunk (It will get sent in the next packet). */
454
+
455
+ /** Queue a chunk (It will get sent in the next packet). */
443
456
  QueueChunkEx(Msg: MsgPacker) {
444
457
  this.queueChunkEx.push(Msg);
445
458
  }
446
- /* Send a Raw Buffer (as chunk) to the server. */
447
- SendMsgRaw(chunks: Buffer[]) {
459
+
460
+ /** Send a Raw Buffer (as chunk) to the server. */
461
+ SendMsgRaw(chunks: Buffer[]) {
448
462
  if (this.State == States.STATE_OFFLINE)
449
463
  return;
450
464
  if (!this.socket)
@@ -476,17 +490,22 @@ export class Client extends EventEmitter {
476
490
  chunk.msgid = (packet[0]-(packet[0]&1))/2;
477
491
  chunk.msg = messageTypes[packet[0]&1][chunk.msgid];
478
492
  chunk.raw = packet.slice(1, chunk.bytes)
479
- Object.values(messageUUIDs).forEach((a, i) => {
480
- if (a.byteLength >= 16 && a.compare(packet.slice(0, 16)) === 0) {
481
- chunk.extended_msgid = a;
482
- chunk.msg = Object.keys(messageUUIDs)[i];
483
- }
484
- })
493
+ if (chunk.msgid == 0) {
494
+ let uuid = this.UUIDManager.LookupUUID(chunk.raw.slice(0,16));
495
+ if (uuid !== undefined) {
496
+ chunk.extended_msgid = uuid.hash;
497
+ chunk.msgid = uuid.type_id;
498
+ chunk.msg = uuid.name;
499
+ chunk.raw = chunk.raw.slice(16);
500
+ }
501
+
502
+ }
485
503
  return chunk;
486
504
  }
487
505
 
488
- /* Connect the client to the server. */
489
- connect() {
506
+
507
+ /** Connect the client to the server. */
508
+ connect() {
490
509
  this.State = States.STATE_CONNECTING;
491
510
 
492
511
  let predTimer = setInterval(() => {
@@ -496,7 +515,7 @@ export class Client extends EventEmitter {
496
515
  } else if (this.State == States.STATE_OFFLINE)
497
516
  clearInterval(predTimer);
498
517
 
499
- }, 20);
518
+ }, 1000/50); // 50 ticks per second
500
519
 
501
520
  this.SendControlMsg(1, "TKEN")
502
521
  let connectInterval = setInterval(() => {
@@ -513,7 +532,7 @@ export class Client extends EventEmitter {
513
532
  return;
514
533
  this.time = new Date().getTime();
515
534
  this.sendInput();
516
- }, 500)
535
+ }, 50)
517
536
  }
518
537
 
519
538
  let resendTimeout = setInterval(() => {
@@ -557,17 +576,15 @@ export class Client extends EventEmitter {
557
576
 
558
577
  var client_version = new MsgPacker(0, true, 1);
559
578
  client_version.AddBuffer(Buffer.from("8c00130484613e478787f672b3835bd4", 'hex'));
560
- let randomUuid = Buffer.allocUnsafe(16);
561
-
562
- randomBytes(16).copy(randomUuid);
579
+ let randomUuid = randomBytes(16);
563
580
 
564
581
  client_version.AddBuffer(randomUuid);
565
582
  if (this.options?.ddnet_version !== undefined) {
566
583
  client_version.AddInt(this.options?.ddnet_version.version);
567
584
  client_version.AddString("DDNet " + this.options?.ddnet_version.release_version);
568
585
  } else {
569
- client_version.AddInt(16003);
570
- client_version.AddString("DDNet 16.0.3");
586
+ client_version.AddInt(16050);
587
+ client_version.AddString("DDNet 16.5.0");
571
588
  }
572
589
 
573
590
  this.SendMsgEx([client_version, info])
@@ -714,12 +731,12 @@ export class Client extends EventEmitter {
714
731
 
715
732
  let snapUnpacked = this.SnapUnpacker.unpackSnapshot(mergedSnaps, DeltaTick, GameTick, Crc);
716
733
 
717
- this.emit("snapshot");
734
+ this.emit("snapshot", snapUnpacked.items);
718
735
  this.AckGameTick = snapUnpacked.recvTick;
719
- if (Math.abs(this.PredGameTick - this.AckGameTick) > 10)
736
+ if (Math.abs(this.PredGameTick - this.AckGameTick) > 10) {
720
737
  this.PredGameTick = this.AckGameTick + 1;
721
-
722
- this.sendInput();
738
+ this.sendInput();
739
+ }
723
740
  }
724
741
 
725
742
 
@@ -729,7 +746,93 @@ export class Client extends EventEmitter {
729
746
  // })
730
747
 
731
748
 
732
- }
749
+ }
750
+
751
+ if (chunk.msgid >= NETMSG_Sys.NETMSG_WHATIS && chunk.msgid <= NETMSG_Sys.NETMSG_CHECKSUM_ERROR) {
752
+ if (chunk.msgid == NETMSG_Sys.NETMSG_WHATIS) {
753
+ let Uuid = chunk.raw.slice(0, 16);
754
+
755
+ let uuid = this.UUIDManager.LookupUUID(Uuid);
756
+ let packer = new MsgPacker(0, true, 1);
757
+ if (uuid !== undefined) {
758
+ // IT_IS msg
759
+ packer.AddBuffer(this.UUIDManager.LookupType(NETMSG_Sys.NETMSG_ITIS)!.hash);
760
+
761
+ packer.AddBuffer(Uuid);
762
+ packer.AddString(uuid.name);
763
+ } else {
764
+ // dont_know msg
765
+ packer.AddBuffer(this.UUIDManager.LookupType(NETMSG_Sys.NETMSG_IDONTKNOW)!.hash);
766
+
767
+ packer.AddBuffer(Uuid);
768
+ }
769
+ this.QueueChunkEx(packer)
770
+ }
771
+
772
+ if (chunk.msgid == NETMSG_Sys.NETMSG_MAP_DETAILS) { // TODO: option for downloading maps
773
+ let unpacker = new MsgUnpacker(chunk.raw);
774
+
775
+ let map_name = unpacker.unpackString();
776
+ let map_sha256: Buffer = Buffer.alloc(32);
777
+ if (unpacker.remaining.length >= 32)
778
+ map_sha256 = unpacker.unpackRaw(32);
779
+ let map_crc = unpacker.unpackInt();
780
+ let map_size = unpacker.unpackInt();
781
+
782
+ let map_url = "";
783
+ if (unpacker.remaining.length)
784
+ map_url = unpacker.unpackString();
785
+
786
+ this.emit("map_details", {map_name, map_sha256, map_crc, map_size, map_url})
787
+ // unpacker.unpack
788
+
789
+ } else if (chunk.msgid == NETMSG_Sys.NETMSG_CAPABILITIES) {
790
+ let unpacker = new MsgUnpacker(chunk.raw);
791
+ let Version = unpacker.unpackInt();
792
+ let Flags = unpacker.unpackInt();
793
+ if (Version <= 0)
794
+ return;
795
+ let DDNet = false;
796
+ if (Version >= 1) {
797
+ DDNet = Boolean(Flags & 1);
798
+
799
+ }
800
+ let ChatTimeoutCode = DDNet;
801
+ let AnyPlayerFlag = DDNet;
802
+ let PingEx = false;
803
+ let AllowDummy = true;
804
+ let SyncWeaponInput = false;
805
+ if(Version >= 1)
806
+ {
807
+ ChatTimeoutCode = Boolean(Flags & 2);
808
+ }
809
+ if(Version >= 2)
810
+ {
811
+ AnyPlayerFlag = Boolean(Flags & 4);
812
+ }
813
+ if(Version >= 3)
814
+ {
815
+ PingEx = Boolean(Flags & 8);
816
+ }
817
+ if(Version >= 4)
818
+ {
819
+ AllowDummy = Boolean(Flags & 16);
820
+ }
821
+ if(Version >= 5)
822
+ {
823
+ SyncWeaponInput = Boolean(Flags & 32);
824
+ }
825
+ this.emit("capabilities", {ChatTimeoutCode, AnyPlayerFlag, PingEx, AllowDummy, SyncWeaponInput});
826
+ // https://github.com/ddnet/ddnet/blob/06e3eb564150e9ab81b3a5595c48e9fe5952ed32/src/engine/client/client.cpp#L1565
827
+ } else if (chunk.msgid == NETMSG_Sys.NETMSG_PINGEX) {
828
+ let packer = new MsgPacker(0, true, 2);
829
+ packer.AddBuffer(this.UUIDManager.LookupType(NETMSG_Sys.NETMSG_PONGEX)!.hash);
830
+
831
+ this.SendMsgEx(packer, 2);
832
+ }
833
+
834
+ }
835
+
733
836
  } else {
734
837
  // game messages
735
838
 
@@ -743,7 +846,7 @@ export class Client extends EventEmitter {
743
846
  for (let i = 0; i < 15; i++) {
744
847
  list.push(unpacker.unpackString());
745
848
  }
746
- list = list.slice(NumOptions);
849
+ list = list.slice(0, NumOptions);
747
850
 
748
851
  this.VoteList.push(...list);
749
852
  } else if (chunk.msgid == NETMSG_Game.SV_VOTEOPTIONADD) {
@@ -770,8 +873,8 @@ export class Client extends EventEmitter {
770
873
 
771
874
  if (unpacked.client_id != -1) {
772
875
  unpacked.author = {
773
- ClientInfo: this.client_info(unpacked.client_id),
774
- PlayerInfo: this.player_info(unpacked.client_id)
876
+ ClientInfo: this.SnapshotUnpacker.getObjClientInfo(unpacked.client_id),
877
+ PlayerInfo: this.SnapshotUnpacker.getObjPlayerInfo(unpacked.client_id)
775
878
  }
776
879
  }
777
880
  this.emit("emote", unpacked)
@@ -792,8 +895,8 @@ export class Client extends EventEmitter {
792
895
 
793
896
  if (unpacked.client_id != -1) {
794
897
  unpacked.author = {
795
- ClientInfo: this.client_info(unpacked.client_id),
796
- PlayerInfo: this.player_info(unpacked.client_id)
898
+ ClientInfo: this.SnapshotUnpacker.getObjClientInfo(unpacked.client_id),
899
+ PlayerInfo: this.SnapshotUnpacker.getObjPlayerInfo(unpacked.client_id)
797
900
  }
798
901
  }
799
902
  this.emit("message", unpacked)
@@ -805,11 +908,11 @@ export class Client extends EventEmitter {
805
908
  unpacked.weapon = unpacker.unpackInt();
806
909
  unpacked.special_mode = unpacker.unpackInt();
807
910
  if (unpacked.victim_id != -1 && unpacked.victim_id < 64) {
808
- unpacked.victim = { ClientInfo: this.client_info(unpacked.victim_id), PlayerInfo: this.player_info(unpacked.victim_id) }
911
+ unpacked.victim = { ClientInfo: this.SnapshotUnpacker.getObjClientInfo(unpacked.victim_id), PlayerInfo: this.SnapshotUnpacker.getObjPlayerInfo(unpacked.victim_id) }
809
912
 
810
913
  }
811
914
  if (unpacked.killer_id != -1 && unpacked.killer_id < 64)
812
- unpacked.killer = { ClientInfo: this.client_info(unpacked.killer_id), PlayerInfo: this.player_info(unpacked.killer_id) }
915
+ unpacked.killer = { ClientInfo: this.SnapshotUnpacker.getObjClientInfo(unpacked.killer_id), PlayerInfo: this.SnapshotUnpacker.getObjPlayerInfo(unpacked.killer_id) }
813
916
  this.emit("kill", unpacked)
814
917
  } else if (chunk.msgid == NETMSG_Game.SV_MOTD) {
815
918
  let unpacker = new MsgUnpacker(chunk.raw);
@@ -834,8 +937,9 @@ export class Client extends EventEmitter {
834
937
  })
835
938
  }
836
939
 
837
- /* Sending the input. (automatically done unless options.lightweight is on) */
838
- sendInput(input = this.movement.input) {
940
+
941
+ /** Sending the input. (automatically done unless options.lightweight is on) */
942
+ sendInput(input = this.movement.input) {
839
943
  if (this.State != States.STATE_ONLINE)
840
944
  return;
841
945
 
@@ -857,12 +961,14 @@ export class Client extends EventEmitter {
857
961
 
858
962
  this.SendMsgEx(inputMsg);
859
963
  }
860
- get input() {
964
+ /** returns the movement object of the client */
965
+ get input() {
861
966
  return this.movement.input;
862
967
  }
863
968
 
864
- /* Disconnect the client. */
865
- Disconnect() {
969
+
970
+ /** Disconnect the client. */
971
+ Disconnect() {
866
972
  return new Promise((resolve) => {
867
973
  this.SendControlMsg(4).then(() => {
868
974
  resolve(true);
@@ -874,46 +980,11 @@ export class Client extends EventEmitter {
874
980
  })
875
981
  }
876
982
 
877
- /* Get the client_info from a specific player id. */
878
- client_info(id: number) {
879
- let delta = this.SnapUnpacker.deltas.filter(_delta =>
880
- _delta.type_id == 11
881
- && _delta.id == id
882
- );
883
-
884
- if (delta.length == 0)
885
- return undefined;
886
- return delta[0].parsed as ClientInfo;
887
- // .sort((a, b) => a.id - b.id)
888
- // .map(a => a.parsed as ClientInfo);
889
- }
890
-
891
- /* Get all client infos. */
892
- get client_infos(): ClientInfo[] {
893
-
894
- return this.SnapUnpacker.deltas.filter(_delta => _delta.type_id == 11)
895
- .sort((a, b) => a.id - b.id)
896
- .map(a => a.parsed as ClientInfo);
897
- }
898
- /* Get the player info from a specific player id. */
899
- player_info(id: number) {
900
- let delta = this.SnapUnpacker.deltas.filter(_delta =>
901
- _delta.type_id == 10
902
- && _delta.id == id
903
- );
904
-
905
- if (delta.length == 0)
906
- return undefined;
907
- return delta[0].parsed as PlayerInfo;
908
- }
909
- /* Get all player infos. */
910
- get player_infos(): PlayerInfo[] {
911
- return this.SnapUnpacker.deltas.filter(_delta => _delta.type_id == 10)
912
- .sort((a, b) => a.id - b.id)
913
- .map(player => player.parsed as PlayerInfo);
914
- }
915
-
916
- get VoteOptionList(): string[] {
983
+ /** Get all available vote options (for example for map voting) */
984
+ get VoteOptionList(): string[] {
917
985
  return this.VoteList;
918
986
  }
987
+ get rawSnapUnpacker(): Snapshot {
988
+ return this.SnapUnpacker;
989
+ }
919
990
  }
@@ -59,19 +59,19 @@ var Game = /** @class */ (function () {
59
59
  packer.AddString(message);
60
60
  this.send(packer);
61
61
  };
62
- /* Set the team of an bot. (-1 spectator team, 0 team red/normal team, 1 team blue) */
62
+ /** Set the team of an bot. (-1 spectator team, 0 team red/normal team, 1 team blue) */
63
63
  Game.prototype.SetTeam = function (team) {
64
64
  var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_SETTEAM, false, 1);
65
65
  packer.AddInt(team);
66
66
  this.send(packer);
67
67
  };
68
- /* Spectate an player, taking their id as parameter. pretty useless */
68
+ /** Spectate an player, taking their id as parameter. pretty useless */
69
69
  Game.prototype.SpectatorMode = function (SpectatorID) {
70
70
  var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_SETSPECTATORMODE, false, 1);
71
71
  packer.AddInt(SpectatorID);
72
72
  this.send(packer);
73
73
  };
74
- /* Change the player info */
74
+ /** Change the player info */
75
75
  Game.prototype.ChangePlayerInfo = function (playerInfo) {
76
76
  var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_CHANGEINFO, false, 1);
77
77
  packer.AddString(playerInfo.name);
@@ -83,18 +83,18 @@ var Game = /** @class */ (function () {
83
83
  packer.AddInt(playerInfo.color_feet);
84
84
  this.send(packer);
85
85
  };
86
- /* Kill */
86
+ /** Kill */
87
87
  Game.prototype.Kill = function () {
88
88
  var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_KILL, false, 1);
89
89
  this.send(packer);
90
90
  };
91
- /* Send emote */
91
+ /** Send emote */
92
92
  Game.prototype.Emote = function (emote) {
93
93
  var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_EMOTICON, false, 1);
94
94
  packer.AddInt(emote);
95
95
  this.send(packer);
96
96
  };
97
- /* Vote for an already running vote (f3 / f4) */
97
+ /** Vote for an already running vote (true = f3 / false = f4) */
98
98
  Game.prototype.Vote = function (vote) {
99
99
  var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_VOTE, false, 1);
100
100
  packer.AddInt(vote ? 1 : -1);
@@ -107,24 +107,24 @@ var Game = /** @class */ (function () {
107
107
  packer.AddString(Reason);
108
108
  this.send(packer);
109
109
  };
110
- /* Call a vote for an server option (for example ddnet maps) */
110
+ /** Call a vote for an server option (for example ddnet maps) */
111
111
  Game.prototype.CallVoteOption = function (Value, Reason) {
112
112
  this.CallVote("option", Value, Reason);
113
113
  };
114
- /* Call a vote to kick a player. Requires the player id */
114
+ /** Call a vote to kick a player. Requires the player id */
115
115
  Game.prototype.CallVoteKick = function (PlayerID, Reason) {
116
116
  this.CallVote("kick", PlayerID, Reason);
117
117
  };
118
- /* Call a vote to set a player in spectator mode. Requires the player id */
118
+ /** Call a vote to set a player in spectator mode. Requires the player id */
119
119
  Game.prototype.CallVoteSpectate = function (PlayerID, Reason) {
120
120
  this.CallVote("spectate", PlayerID, Reason);
121
121
  };
122
- /** probably some verification of using ddnet client.*/
122
+ /** probably some verification of using ddnet client. */
123
123
  Game.prototype.IsDDNetLegacy = function () {
124
124
  var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_ISDDNETLEGACY, false, 1);
125
125
  this.send(packer);
126
126
  };
127
- /* returns the ping in ms */
127
+ /** returns the ping in ms (as a promise) */
128
128
  Game.prototype.Ping = function () {
129
129
  var _this = this;
130
130
  return new Promise(function (resolve, reject) {