teeworlds 2.3.8 → 2.4.0

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
@@ -10,6 +10,7 @@ import Movement from './movement';
10
10
  import { MsgPacker } from './MsgPacker';
11
11
  import { Snapshot } from './snapshot';
12
12
  import Huffman from "./huffman";
13
+ import { Game } from "./components/game";
13
14
 
14
15
  const huff = new Huffman();
15
16
 
@@ -146,38 +147,7 @@ declare interface iOptions {
146
147
  }
147
148
 
148
149
  export declare interface Client {
149
- host: string;
150
- port: number;
151
- name: string;
152
- State: number; // 0 = offline; 1 = STATE_CONNECTING = 1, STATE_LOADING = 2, STATE_ONLINE = 3
153
- ack: number;
154
- clientAck: number;
155
- receivedSnaps: number; /* wait for 2 ss before seeing self as connected */
156
- lastMsg: string;
157
- socket: net.Socket | undefined;
158
- TKEN: Buffer;
159
- time: number;
160
- SnapUnpacker: Snapshot;
161
-
162
- timer: number;
163
- PredGameTick: number;
164
- AckGameTick: number;
165
-
166
- movement: Movement;
167
-
168
- snaps: Buffer[];
169
-
170
- sentChunkQueue: Buffer[];
171
- queueChunkEx: MsgPacker[];
172
- lastSendTime: number;
173
- lastRecvTime: number;
174
-
175
- lastSentMessages: {msg: MsgPacker, ack: number}[];
176
-
177
- // eSnapHolder: eSnap[];
178
-
179
-
180
- options?: iOptions;
150
+
181
151
 
182
152
  on(event: 'connected', listener: () => void): this;
183
153
  on(event: 'disconnect', listener: (reason: string) => void): this;
@@ -187,15 +157,49 @@ export declare interface Client {
187
157
  on(event: 'kill', listener: (kill: iKillMsg) => void): this;
188
158
  on(event: 'motd', listener: (message: string) => void): this;
189
159
 
190
- requestResend: boolean;
191
160
  }
192
161
 
162
+ export class Client extends EventEmitter {
193
163
 
164
+ private host: string;
165
+ private port: number;
166
+ private name: string;
167
+ private State: number; // 0 = offline; 1 = STATE_CONNECTING = 1, STATE_LOADING = 2, STATE_ONLINE = 3
168
+ private ack: number;
169
+ private clientAck: number;
170
+ private receivedSnaps: number; /* wait for 2 ss before seeing self as connected */
171
+ private socket: net.Socket | undefined;
172
+ private TKEN: Buffer;
173
+ private time: number;
174
+ private SnapUnpacker: Snapshot;
175
+
176
+ private PredGameTick: number;
177
+ private AckGameTick: number;
178
+
179
+ private SnapshotParts: number;
180
+ private currentSnapshotGameTick: number;
194
181
 
195
- export class Client extends EventEmitter {
182
+
183
+ private snaps: Buffer[];
184
+
185
+ private sentChunkQueue: Buffer[];
186
+ private queueChunkEx: MsgPacker[];
187
+ private lastSendTime: number;
188
+ private lastRecvTime: number;
189
+
190
+ private lastSentMessages: {msg: MsgPacker, ack: number}[];
191
+
192
+
193
+ public movement: Movement;
194
+ public game: Game;
195
+
196
+ // eSnapHolder: eSnap[];
196
197
 
197
198
 
199
+ public readonly options?: iOptions;
200
+ private requestResend: boolean;
198
201
 
202
+
199
203
  constructor(ip: string, port: number, nickname: string, options?: iOptions) {
200
204
  super();
201
205
  this.host = ip;
@@ -203,6 +207,10 @@ export class Client extends EventEmitter {
203
207
  this.name = nickname;
204
208
  this.AckGameTick = 0;
205
209
  this.PredGameTick = 0;
210
+ this.currentSnapshotGameTick = 0;
211
+
212
+ this.SnapshotParts = 0;
213
+
206
214
  this.SnapUnpacker = new Snapshot();
207
215
  // this.eSnapHolder = [];
208
216
  this.requestResend = false;
@@ -210,10 +218,7 @@ export class Client extends EventEmitter {
210
218
  if (options)
211
219
  this.options = options;
212
220
 
213
- this.timer = 0;
214
-
215
- this.movement = new Movement();
216
-
221
+
217
222
  this.snaps = [];
218
223
 
219
224
  this.sentChunkQueue = [];
@@ -223,8 +228,7 @@ export class Client extends EventEmitter {
223
228
  this.ack = 0; // ack of messages the client has received
224
229
  this.clientAck = 0; // ack of messages the client has sent
225
230
  this.receivedSnaps = 0; /* wait for 2 snaps before seeing self as connected */
226
- this.lastMsg = "";
227
- this.socket = net.createSocket("udp4")
231
+ this.socket = net.createSocket("udp4");
228
232
  this.socket.bind();
229
233
 
230
234
  this.TKEN = Buffer.from([255, 255, 255, 255])
@@ -233,10 +237,14 @@ export class Client extends EventEmitter {
233
237
  this.lastRecvTime = new Date().getTime();
234
238
 
235
239
  this.lastSentMessages = [];
240
+ this.movement = new Movement();
241
+
242
+ this.game = new Game(this);
243
+
236
244
 
237
245
  }
238
246
 
239
- ResendAfter(lastAck: number) {
247
+ private ResendAfter(lastAck: number) {
240
248
  this.clientAck = lastAck;
241
249
 
242
250
 
@@ -249,7 +257,7 @@ export class Client extends EventEmitter {
249
257
  this.SendMsgEx(toResend);
250
258
  }
251
259
 
252
- Unpack(packet: Buffer): _packet {
260
+ private Unpack(packet: Buffer): _packet {
253
261
  var unpacked: _packet = { twprotocol: { flags: packet[0] >> 4, ack: ((packet[0]&0xf)<<8) | packet[1], chunkAmount: packet[2], size: packet.byteLength - 3 }, chunks: [] }
254
262
 
255
263
 
@@ -294,6 +302,8 @@ export class Client extends EventEmitter {
294
302
  }
295
303
  return unpacked
296
304
  }
305
+
306
+ /* Send a Control Msg to the server. (used for disconnect)*/
297
307
  SendControlMsg(msg: number, ExtraMsg: string = "") {
298
308
  this.lastSendTime = new Date().getTime();
299
309
  return new Promise((resolve, reject) => {
@@ -313,6 +323,7 @@ export class Client extends EventEmitter {
313
323
  })
314
324
  }
315
325
 
326
+ /* Send a Msg (or Msg[]) to the server.*/
316
327
  SendMsgEx(Msgs: MsgPacker[] | MsgPacker) {
317
328
  if (this.State == States.STATE_OFFLINE)
318
329
  return;
@@ -371,11 +382,11 @@ export class Client extends EventEmitter {
371
382
  return;
372
383
  this.socket.send(packet, 0, packet.length, this.port, this.host)
373
384
  }
374
-
385
+ /* Queue a chunk (It will get sent in the next packet). */
375
386
  QueueChunkEx(Msg: MsgPacker) {
376
387
  this.queueChunkEx.push(Msg);
377
388
  }
378
-
389
+ /* Send a Raw Buffer (as chunk) to the server. */
379
390
  SendMsgRaw(chunks: Buffer[]) {
380
391
  if (this.State == States.STATE_OFFLINE)
381
392
  return;
@@ -392,7 +403,7 @@ export class Client extends EventEmitter {
392
403
  this.socket.send(packet, 0, packet.length, this.port, this.host)
393
404
  }
394
405
 
395
- MsgToChunk(packet: Buffer) {
406
+ private MsgToChunk(packet: Buffer) {
396
407
  var chunk: chunk = {} as chunk;
397
408
  chunk.bytes = ((packet[0] & 0x3f) << 4) | (packet[1] & ((1 << 4) - 1));
398
409
  chunk.flags = (packet[0] >> 6) & 3;
@@ -416,6 +427,7 @@ export class Client extends EventEmitter {
416
427
  return chunk;
417
428
  }
418
429
 
430
+ /* Connect the client to the server. */
419
431
  connect() {
420
432
  this.State = States.STATE_CONNECTING;
421
433
 
@@ -468,14 +480,15 @@ export class Client extends EventEmitter {
468
480
  this.time = new Date().getTime() + 2000; // start sending keepalives after 2s
469
481
 
470
482
  if (this.socket)
471
- this.socket.on("message", (a, rinfo) => {
483
+ this.socket.on("message", (packet, rinfo) => {
472
484
  if (this.State == 0 || rinfo.address != this.host || rinfo.port != this.port)
473
485
  return;
474
486
  clearInterval(connectInterval)
475
- if (a.toJSON().data[0] == 0x10) {
476
- if (a.toString().includes("TKEN") || a.toJSON().data[3] == 0x2) {
487
+
488
+ if (packet.toJSON().data[0] == 0x10) {
489
+ if (packet.toString().includes("TKEN") || packet.toJSON().data[3] == 0x2) {
477
490
  clearInterval(connectInterval);
478
- this.TKEN = Buffer.from(a.toJSON().data.slice(a.toJSON().data.length - 4, a.toJSON().data.length))
491
+ this.TKEN = Buffer.from(packet.toJSON().data.slice(packet.toJSON().data.length - 4, packet.toJSON().data.length))
479
492
  this.SendControlMsg(3);
480
493
  this.State = States.STATE_LOADING; // loading state
481
494
  this.receivedSnaps = 0;
@@ -500,26 +513,26 @@ export class Client extends EventEmitter {
500
513
  }
501
514
 
502
515
  this.SendMsgEx([client_version, info])
503
- } else if (a.toJSON().data[3] == 0x4) {
516
+ } else if (packet.toJSON().data[3] == 0x4) {
504
517
  // disconnected
505
518
  this.State = States.STATE_OFFLINE;
506
- let reason: string = (unpackString(a.toJSON().data.slice(4)).result);
519
+ let reason: string = (unpackString(packet.toJSON().data.slice(4)).result);
507
520
  this.emit("disconnect", reason);
508
521
  }
509
- if (a.toJSON().data[3] !== 0x0) { // keepalive
522
+ if (packet.toJSON().data[3] !== 0x0) { // keepalive
510
523
  this.lastRecvTime = new Date().getTime();
511
524
  }
512
525
  } else {
513
526
  this.lastRecvTime = new Date().getTime();
514
-
515
527
  }
516
-
517
528
 
518
- var unpacked: _packet = this.Unpack(a);
519
- unpacked.chunks.forEach(a => {
520
- if (a.flags & 1 && (a.flags !== 15)) { // vital and not connless
521
- if (a.seq === (this.ack+1)%(1<<10)) { // https://github.com/nobody-mb/twchatonly/blob/master/chatonly.cpp#L237
522
- this.ack = a.seq!;
529
+ var unpacked: _packet = this.Unpack(packet);
530
+ unpacked.chunks = unpacked.chunks.filter(chunk => ((chunk.flags & 2) && (chunk.flags & 1)) ? chunk.seq! > this.ack : true); // filter out already received chunks
531
+
532
+ unpacked.chunks.forEach(chunk => {
533
+ if (chunk.flags & 1 && (chunk.flags !== 15)) { // vital and not connless
534
+ if (chunk.seq === (this.ack+1)%(1<<10)) { // https://github.com/nobody-mb/twchatonly/blob/master/chatonly.cpp#L237
535
+ this.ack = chunk.seq!;
523
536
 
524
537
  this.requestResend = false;
525
538
  }
@@ -527,10 +540,10 @@ export class Client extends EventEmitter {
527
540
  let Bottom = (this.ack - (1<<10)/2);
528
541
 
529
542
  if(Bottom < 0) {
530
- if((a.seq! <= this.ack) || (a.seq! >= (Bottom + (1<<10))))
543
+ if((chunk.seq! <= this.ack) || (chunk.seq! >= (Bottom + (1<<10))))
531
544
  return;
532
545
  } else {
533
- if(a.seq! <= this.ack && a.seq! >= Bottom)
546
+ if(chunk.seq! <= this.ack && chunk.seq! >= Bottom)
534
547
  return;
535
548
  }
536
549
  this.requestResend = true;
@@ -539,7 +552,7 @@ export class Client extends EventEmitter {
539
552
  }
540
553
 
541
554
  })
542
- unpacked.chunks.filter(a => a.msgid == NETMSGTYPE.SV_BROADCAST && a.type == 'game').forEach(a => {
555
+ unpacked.chunks.filter(chunk => chunk.msgid == NETMSGTYPE.SV_BROADCAST && chunk.type == 'game').forEach(a => {
543
556
  let unpacker = new MsgUnpacker(a.raw.toJSON().data);
544
557
 
545
558
  this.emit("broadcast", unpacker.unpackString());
@@ -553,62 +566,72 @@ export class Client extends EventEmitter {
553
566
  })
554
567
  let snapChunks: chunk[] = [];
555
568
  if (this.options?.lightweight !== true)
556
- snapChunks = unpacked.chunks.filter(a => a.msg === "SNAP" || a.msg === "SNAP_SINGLE" || a.msg === "SNAP_EMPTY");
569
+ snapChunks = unpacked.chunks.filter(chunk => chunk.msg === "SNAP" || chunk.msg === "SNAP_SINGLE" || chunk.msg === "SNAP_EMPTY");
557
570
  if (snapChunks.length > 0) {
558
- let part = 0;
559
- let num_parts = 1;
571
+ if (Math.abs(this.PredGameTick - this.AckGameTick) > 10)
572
+ this.PredGameTick = this.AckGameTick + 1;
573
+
560
574
  snapChunks.forEach(chunk => {
561
575
  let unpacker = new MsgUnpacker(chunk.raw.toJSON().data);
562
576
 
563
- let AckGameTick = unpacker.unpackInt();
564
-
565
- let DeltaTick = AckGameTick - unpacker.unpackInt();
566
- if (AckGameTick >= this.AckGameTick) {
567
- if (this.AckGameTick == -1) {// reset ack
568
- if (DeltaTick == -1) {// acked reset
569
- this.AckGameTick = AckGameTick;
570
- }
571
- } else
572
- this.AckGameTick = AckGameTick;
573
- if (Math.abs(this.PredGameTick - this.AckGameTick) > 10)
574
- this.PredGameTick = AckGameTick + 1;
575
-
576
- let num_parts = 1;
577
- let part = 0;
577
+ let NumParts = 1;
578
+ let Part = 0;
579
+ let GameTick = unpacker.unpackInt();
580
+ let DeltaTick = GameTick - unpacker.unpackInt();
581
+ let PartSize = 0;
582
+ let Crc = 0;
583
+ let CompleteSize = 0;
584
+
585
+ if (chunk.msg == "SNAP") {
586
+ NumParts = unpacker.unpackInt();
587
+ Part = unpacker.unpackInt();
588
+ }
578
589
 
579
- if (chunk.msg === "SNAP") {
580
- num_parts = unpacker.unpackInt();
581
- part = unpacker.unpackInt();
582
- }
583
-
584
- let crc = 0;
585
- let part_size = 0;
586
590
  if (chunk.msg != "SNAP_EMPTY") {
587
- crc = unpacker.unpackInt(); // crc
588
- part_size = unpacker.unpackInt();
591
+ Crc = unpacker.unpackInt();
592
+ PartSize = unpacker.unpackInt();
589
593
  }
590
- if (part === 0 || this.snaps.length > 30) {
591
- this.snaps = [];
592
- }
593
- chunk.raw = Buffer.from(unpacker.remaining);
594
- this.snaps.push(chunk.raw)
595
-
596
- if ((num_parts - 1) === part && this.snaps.length === num_parts) {
597
594
 
598
- let mergedSnaps = Buffer.concat(this.snaps);
595
+ if (PartSize < 1 || NumParts > 64 || Part < 0 || Part >= NumParts || PartSize <= 0 || PartSize > 900)
596
+ return;
599
597
 
600
- let snapUnpacked = this.SnapUnpacker.unpackSnapshot(mergedSnaps.toJSON().data, DeltaTick, AckGameTick);
601
- this.AckGameTick = snapUnpacked.recvTick;
602
-
603
- this.emit("snapshot");
598
+ if (GameTick >= this.currentSnapshotGameTick) {
599
+ if (GameTick != this.currentSnapshotGameTick) {
600
+ this.snaps = [];
601
+ this.SnapshotParts = 0;
602
+ this.currentSnapshotGameTick = GameTick;
603
+ }
604
+
605
+ // chunk.raw = Buffer.from(unpacker.remaining);
606
+ this.snaps[Part] = Buffer.from(unpacker.remaining);
607
+
608
+ this.SnapshotParts |= 1 << Part;
604
609
 
605
- this.sendInput();
606
- }
610
+ if (this.SnapshotParts == ((1 << NumParts) - 1)) {
611
+ let mergedSnaps = Buffer.concat(this.snaps);
612
+ this.SnapshotParts = 0;
607
613
 
608
- }
614
+ let snapUnpacked = this.SnapUnpacker.unpackSnapshot(mergedSnaps.toJSON().data, DeltaTick, GameTick);
615
+
616
+ this.emit("snapshot");
617
+ this.AckGameTick = snapUnpacked.recvTick;
618
+ if (Math.abs(this.PredGameTick - this.AckGameTick) > 10)
619
+ this.PredGameTick = this.AckGameTick + 1;
620
+
621
+ this.sendInput();
622
+ }
623
+
624
+
625
+ }
626
+
627
+
609
628
  })
610
629
  }
630
+
611
631
  var chunkMessages = unpacked.chunks.map(a => a.msg)
632
+ if (unpacked.chunks.findIndex(chunk => chunk.msgid == 23 && chunk.type == "sys") !== -1) {
633
+ this.game._ping_resolve(new Date().getTime())
634
+ }
612
635
  if (chunkMessages.includes("SV_CHAT")) {
613
636
  var chat = unpacked.chunks.filter(a => a.msg == "SV_CHAT");
614
637
  chat.forEach(a => {
@@ -630,7 +653,7 @@ export class Client extends EventEmitter {
630
653
  }
631
654
  })
632
655
  }
633
- var chat = unpacked.chunks.filter(a => a.msg == "SV_KILL_MSG" || a.msg == "SV_MOTD");
656
+ var chat = unpacked.chunks.filter(chunk => chunk.msg == "SV_KILL_MSG" || chunk.msg == "SV_MOTD");
634
657
  chat.forEach(a => {
635
658
  if (a.msg == "SV_KILL_MSG") {
636
659
  var unpacked: iKillMsg = {} as iKillMsg;
@@ -706,6 +729,7 @@ export class Client extends EventEmitter {
706
729
  })
707
730
  }
708
731
 
732
+ /* Sending the input. (automatically done unless options.lightweight is on) */
709
733
  sendInput(input = this.movement.input) {
710
734
  if (this.State != States.STATE_ONLINE)
711
735
  return;
@@ -737,6 +761,7 @@ export class Client extends EventEmitter {
737
761
  return this.movement.input;
738
762
  }
739
763
 
764
+ /* Disconnect the client. */
740
765
  Disconnect() {
741
766
  return new Promise((resolve) => {
742
767
  this.SendControlMsg(4).then(() => {
@@ -749,64 +774,11 @@ export class Client extends EventEmitter {
749
774
  })
750
775
  }
751
776
 
752
- Say(message: string, team = false) {
753
- var packer = new MsgPacker(NETMSGTYPE.CL_SAY, false, 1);
754
- packer.AddInt(team ? 1 : 0); // team
755
- packer.AddString(message);
756
- if (!this.options?.lightweight)
757
- this.QueueChunkEx(packer);
758
- else
759
- this.SendMsgEx(packer);
760
- }
761
- Vote(vote: boolean) {
762
- var packer = new MsgPacker(NETMSGTYPE.CL_VOTE, false, 1);
763
- packer.AddInt(vote ? 1 : -1);
764
- if (!this.options?.lightweight)
765
- this.QueueChunkEx(packer);
766
- else
767
- this.SendMsgEx(packer);
768
- }
769
- ChangePlayerInfo(playerInfo: ClientInfo) {
770
- var packer = new MsgPacker(NETMSGTYPE.CL_CHANGEINFO, false, 1);
771
- packer.AddString(playerInfo.name); //m_pName);
772
- packer.AddString(playerInfo.clan); //m_pClan);
773
- packer.AddInt(playerInfo.country); //m_Country);
774
- packer.AddString(playerInfo.skin); //m_pSkin);
775
- packer.AddInt(playerInfo.use_custom_color ? 1 : 0); //m_UseCustomColor);
776
- packer.AddInt(playerInfo.color_body); //m_ColorBody);
777
- packer.AddInt(playerInfo.color_feet); //m_ColorFeet);
778
- if (!this.options?.lightweight)
779
- this.QueueChunkEx(packer);
780
- else
781
- this.SendMsgEx(packer);
782
- }
783
- Kill() {
784
- var packer = new MsgPacker(NETMSGTYPE.CL_KILL, false, 1);
785
- if (!this.options?.lightweight)
786
- this.QueueChunkEx(packer);
787
- else
788
- this.SendMsgEx(packer);
789
- }
790
- ChangeTeam(team: number) {
791
- var packer = new MsgPacker(NETMSGTYPE.CL_SETTEAM, false, 1);
792
- packer.AddInt(team);
793
- if (!this.options?.lightweight)
794
- this.QueueChunkEx(packer);
795
- else
796
- this.SendMsgEx(packer);
797
- }
798
- Emote(emote: number) {
799
- var packer = new MsgPacker(NETMSGTYPE.CL_EMOTICON, false, 1);
800
- packer.AddInt(emote);
801
- if (!this.options?.lightweight)
802
- this.QueueChunkEx(packer);
803
- else
804
- this.SendMsgEx(packer);
805
- }
777
+ /* Get the client_info from a specific player id. */
806
778
  client_info(id: number) {
807
- let delta = this.SnapUnpacker.deltas.filter(a =>
808
- a.type_id == 11
809
- && a.id == id
779
+ let delta = this.SnapUnpacker.deltas.filter(_delta =>
780
+ _delta.type_id == 11
781
+ && _delta.id == id
810
782
  );
811
783
 
812
784
  if (delta.length == 0)
@@ -815,25 +787,29 @@ export class Client extends EventEmitter {
815
787
  // .sort((a, b) => a.id - b.id)
816
788
  // .map(a => a.parsed as ClientInfo);
817
789
  }
790
+
791
+ /* Get all client infos. */
818
792
  get client_infos(): ClientInfo[] {
819
793
 
820
- return this.SnapUnpacker.deltas.filter(a => a.type_id == 11)
821
- .sort((a, b) => a.id - b.id)
822
- .map(a => a.parsed as ClientInfo) ;
794
+ return this.SnapUnpacker.deltas.filter(_delta => _delta.type_id == 11)
795
+ .sort((a, b) => a.id - b.id)
796
+ .map(a => a.parsed as ClientInfo);
823
797
  }
798
+ /* Get the player info from a specific player id. */
824
799
  player_info(id: number) {
825
- let delta = this.SnapUnpacker.deltas.filter(a =>
826
- a.type_id == 10
827
- && a.id == id
800
+ let delta = this.SnapUnpacker.deltas.filter(_delta =>
801
+ _delta.type_id == 10
802
+ && _delta.id == id
828
803
  );
829
804
 
830
805
  if (delta.length == 0)
831
806
  return undefined;
832
807
  return delta[0].parsed as PlayerInfo;
833
808
  }
809
+ /* Get all player infos. */
834
810
  get player_infos(): PlayerInfo[] {
835
- return this.SnapUnpacker.deltas.filter(a => a.type_id == 10)
811
+ return this.SnapUnpacker.deltas.filter(_delta => _delta.type_id == 10)
836
812
  .sort((a, b) => a.id - b.id)
837
- .map(a => a.parsed as PlayerInfo);
813
+ .map(player => player.parsed as PlayerInfo);
838
814
  }
839
815
  }
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Game = void 0;
4
+ var MsgPacker_1 = require("../MsgPacker");
5
+ var NETMSGTYPE;
6
+ (function (NETMSGTYPE) {
7
+ NETMSGTYPE[NETMSGTYPE["EX"] = 0] = "EX";
8
+ NETMSGTYPE[NETMSGTYPE["SV_MOTD"] = 1] = "SV_MOTD";
9
+ NETMSGTYPE[NETMSGTYPE["SV_BROADCAST"] = 2] = "SV_BROADCAST";
10
+ NETMSGTYPE[NETMSGTYPE["SV_CHAT"] = 3] = "SV_CHAT";
11
+ NETMSGTYPE[NETMSGTYPE["SV_KILLMSG"] = 4] = "SV_KILLMSG";
12
+ NETMSGTYPE[NETMSGTYPE["SV_SOUNDGLOBAL"] = 5] = "SV_SOUNDGLOBAL";
13
+ NETMSGTYPE[NETMSGTYPE["SV_TUNEPARAMS"] = 6] = "SV_TUNEPARAMS";
14
+ NETMSGTYPE[NETMSGTYPE["SV_EXTRAPROJECTILE"] = 7] = "SV_EXTRAPROJECTILE";
15
+ NETMSGTYPE[NETMSGTYPE["SV_READYTOENTER"] = 8] = "SV_READYTOENTER";
16
+ NETMSGTYPE[NETMSGTYPE["SV_WEAPONPICKUP"] = 9] = "SV_WEAPONPICKUP";
17
+ NETMSGTYPE[NETMSGTYPE["SV_EMOTICON"] = 10] = "SV_EMOTICON";
18
+ NETMSGTYPE[NETMSGTYPE["SV_VOTECLEAROPTIONS"] = 11] = "SV_VOTECLEAROPTIONS";
19
+ NETMSGTYPE[NETMSGTYPE["SV_VOTEOPTIONLISTADD"] = 12] = "SV_VOTEOPTIONLISTADD";
20
+ NETMSGTYPE[NETMSGTYPE["SV_VOTEOPTIONADD"] = 13] = "SV_VOTEOPTIONADD";
21
+ NETMSGTYPE[NETMSGTYPE["SV_VOTEOPTIONREMOVE"] = 14] = "SV_VOTEOPTIONREMOVE";
22
+ NETMSGTYPE[NETMSGTYPE["SV_VOTESET"] = 15] = "SV_VOTESET";
23
+ NETMSGTYPE[NETMSGTYPE["SV_VOTESTATUS"] = 16] = "SV_VOTESTATUS";
24
+ NETMSGTYPE[NETMSGTYPE["CL_SAY"] = 17] = "CL_SAY";
25
+ NETMSGTYPE[NETMSGTYPE["CL_SETTEAM"] = 18] = "CL_SETTEAM";
26
+ NETMSGTYPE[NETMSGTYPE["CL_SETSPECTATORMODE"] = 19] = "CL_SETSPECTATORMODE";
27
+ NETMSGTYPE[NETMSGTYPE["CL_STARTINFO"] = 20] = "CL_STARTINFO";
28
+ NETMSGTYPE[NETMSGTYPE["CL_CHANGEINFO"] = 21] = "CL_CHANGEINFO";
29
+ NETMSGTYPE[NETMSGTYPE["CL_KILL"] = 22] = "CL_KILL";
30
+ NETMSGTYPE[NETMSGTYPE["CL_EMOTICON"] = 23] = "CL_EMOTICON";
31
+ NETMSGTYPE[NETMSGTYPE["CL_VOTE"] = 24] = "CL_VOTE";
32
+ NETMSGTYPE[NETMSGTYPE["CL_CALLVOTE"] = 25] = "CL_CALLVOTE";
33
+ NETMSGTYPE[NETMSGTYPE["CL_ISDDNETLEGACY"] = 26] = "CL_ISDDNETLEGACY";
34
+ NETMSGTYPE[NETMSGTYPE["SV_DDRACETIMELEGACY"] = 27] = "SV_DDRACETIMELEGACY";
35
+ NETMSGTYPE[NETMSGTYPE["SV_RECORDLEGACY"] = 28] = "SV_RECORDLEGACY";
36
+ NETMSGTYPE[NETMSGTYPE["UNUSED"] = 29] = "UNUSED";
37
+ NETMSGTYPE[NETMSGTYPE["SV_TEAMSSTATELEGACY"] = 30] = "SV_TEAMSSTATELEGACY";
38
+ NETMSGTYPE[NETMSGTYPE["CL_SHOWOTHERSLEGACY"] = 31] = "CL_SHOWOTHERSLEGACY";
39
+ NETMSGTYPE[NETMSGTYPE["NUM"] = 32] = "NUM";
40
+ })(NETMSGTYPE || (NETMSGTYPE = {}));
41
+ ;
42
+ var Game = /** @class */ (function () {
43
+ function Game(_client) {
44
+ // this.SendMsgEx = callback;
45
+ this._client = _client;
46
+ this._ping_resolve = function () { };
47
+ }
48
+ Game.prototype.send = function (packer) {
49
+ var _a;
50
+ if (!((_a = this._client.options) === null || _a === void 0 ? void 0 : _a.lightweight))
51
+ this._client.QueueChunkEx(packer);
52
+ else
53
+ this._client.SendMsgEx(packer);
54
+ };
55
+ Game.prototype.Say = function (message, team) {
56
+ if (team === void 0) { team = false; }
57
+ var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_SAY, false, 1);
58
+ packer.AddInt(team ? 1 : 0); // team
59
+ packer.AddString(message);
60
+ this.send(packer);
61
+ };
62
+ /* Set the team of an bot. (-1 spectator team, 0 team red/normal team, 1 team blue) */
63
+ Game.prototype.SetTeam = function (team) {
64
+ var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_SETTEAM, false, 1);
65
+ packer.AddInt(team);
66
+ this.send(packer);
67
+ };
68
+ /* Spectate an player, taking their id as parameter. pretty useless */
69
+ Game.prototype.SpectatorMode = function (SpectatorID) {
70
+ var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_SETSPECTATORMODE, false, 1);
71
+ packer.AddInt(SpectatorID);
72
+ this.send(packer);
73
+ };
74
+ /* Change the player info */
75
+ Game.prototype.ChangePlayerInfo = function (playerInfo) {
76
+ var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_CHANGEINFO, false, 1);
77
+ packer.AddString(playerInfo.name);
78
+ packer.AddString(playerInfo.clan);
79
+ packer.AddInt(playerInfo.country);
80
+ packer.AddString(playerInfo.skin);
81
+ packer.AddInt(playerInfo.use_custom_color ? 1 : 0);
82
+ packer.AddInt(playerInfo.color_body);
83
+ packer.AddInt(playerInfo.color_feet);
84
+ this.send(packer);
85
+ };
86
+ /* Kill */
87
+ Game.prototype.Kill = function () {
88
+ var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_KILL, false, 1);
89
+ this.send(packer);
90
+ };
91
+ /* Send emote */
92
+ Game.prototype.Emote = function (emote) {
93
+ var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_EMOTICON, false, 1);
94
+ packer.AddInt(emote);
95
+ this.send(packer);
96
+ };
97
+ /* Vote for an already running vote (f3 / f4) */
98
+ Game.prototype.Vote = function (vote) {
99
+ var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_VOTE, false, 1);
100
+ packer.AddInt(vote ? 1 : -1);
101
+ this.send(packer);
102
+ };
103
+ Game.prototype.CallVote = function (Type, Value, Reason) {
104
+ var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_CALLVOTE, false, 1);
105
+ packer.AddString(Type);
106
+ packer.AddString(String(Value));
107
+ packer.AddString(Reason);
108
+ this.send(packer);
109
+ };
110
+ /* Call a vote for an server option (for example ddnet maps) */
111
+ Game.prototype.CallVoteOption = function (Value, Reason) {
112
+ this.CallVote("option", Value, Reason);
113
+ };
114
+ /* Call a vote to kick a player. Requires the player id */
115
+ Game.prototype.CallVoteKick = function (PlayerID, Reason) {
116
+ this.CallVote("kick", PlayerID, Reason);
117
+ };
118
+ /* Call a vote to set a player in spectator mode. Requires the player id */
119
+ Game.prototype.CallVoteSpectate = function (PlayerID, Reason) {
120
+ this.CallVote("spectate", PlayerID, Reason);
121
+ };
122
+ /** probably some verification of using ddnet client.*/
123
+ Game.prototype.IsDDNetLegacy = function () {
124
+ var packer = new MsgPacker_1.MsgPacker(NETMSGTYPE.CL_ISDDNETLEGACY, false, 1);
125
+ this.send(packer);
126
+ };
127
+ /* returns the ping in ms */
128
+ Game.prototype.Ping = function () {
129
+ var _this = this;
130
+ return new Promise(function (resolve, reject) {
131
+ var packer = new MsgPacker_1.MsgPacker(22, true, 0);
132
+ var startTime = new Date().getTime();
133
+ _this.send(packer);
134
+ var callback = function (_time) {
135
+ resolve(_time - startTime);
136
+ _this._ping_resolve = function () { };
137
+ };
138
+ _this._ping_resolve = callback;
139
+ });
140
+ };
141
+ return Game;
142
+ }());
143
+ exports.Game = Game;