@sanctumterra/raknet 1.4.11 → 1.4.13

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.
@@ -20,6 +20,7 @@ export declare class Client extends EventEmitter<ClientEvents> {
20
20
  private resolvedAddress;
21
21
  private proxyReady;
22
22
  private lastPongTime;
23
+ private lastActivityTime;
23
24
  private isDisconnected;
24
25
  constructor(options?: Partial<ClientOptions>);
25
26
  private setupProxy;
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,YAAY,EAWZ,QAAQ,EAIR,KAAK,KAAK,EAKV,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EACN,KAAK,aAAa,EAElB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAgB,KAAK,UAAU,EAAe,MAAM,YAAY,CAAC;AAKxE,qBAAa,MAAO,SAAQ,YAAY,CAAC,YAAY,CAAC;IACrD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAiC;IACnE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAO;IACjD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IACjD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAO;IAE3C,OAAO,EAAE,aAAa,CAAC;IAC9B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAwB;IACxC,OAAO,CAAC,MAAM,CAAmB;IAC1B,IAAI,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,SAAS,CAAS;IAE1B,OAAO,CAAC,WAAW,CAA0B;IAC7C,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,UAAU,CAAS;IAE3B,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,cAAc,CAAS;gBAEnB,OAAO,GAAE,OAAO,CAAC,aAAa,CAAM;YAmBlC,UAAU;IAoGxB,OAAO,CAAC,wBAAwB;IAIhC,OAAO,CAAC,iBAAiB;IAuBzB,OAAO,CAAC,qBAAqB;IA4B7B,OAAO,CAAC,oBAAoB;IA2Bf,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAiD9B,MAAM,IAAI,IAAI;IA6BrB,OAAO,CAAC,iBAAiB;IAMzB,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,OAAO;IAgBR,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI;IAuEhD,YAAY,CAAC,IAAI,EAAE,MAAM;IAgDzB,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,GAAE,QAA0B;IAI5D,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,QAA0B;IAI/D,IAAI,IAAI,IAAI;IAOZ,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAWxB,UAAU,IAAI,IAAI;CAWzB"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,YAAY,EAWZ,QAAQ,EAIR,KAAK,KAAK,EAKV,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EACN,KAAK,aAAa,EAElB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAgB,KAAK,UAAU,EAAe,MAAM,YAAY,CAAC;AAKxE,qBAAa,MAAO,SAAQ,YAAY,CAAC,YAAY,CAAC;IACrD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAiC;IACnE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAO;IACjD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IACjD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAO;IAE3C,OAAO,EAAE,aAAa,CAAC;IAC9B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAwB;IACxC,OAAO,CAAC,MAAM,CAAmB;IAC1B,IAAI,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,SAAS,CAAS;IAE1B,OAAO,CAAC,WAAW,CAA0B;IAC7C,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,UAAU,CAAS;IAE3B,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,gBAAgB,CAAsB;IAC9C,OAAO,CAAC,cAAc,CAAS;gBAEnB,OAAO,GAAE,OAAO,CAAC,aAAa,CAAM;YAmBlC,UAAU;IAoGxB,OAAO,CAAC,wBAAwB;IAIhC,OAAO,CAAC,iBAAiB;IAuBzB,OAAO,CAAC,qBAAqB;IA4B7B,OAAO,CAAC,oBAAoB;IA2Bf,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAiD9B,MAAM,IAAI,IAAI;IA6BrB,OAAO,CAAC,iBAAiB;IAMzB,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,OAAO;IAgBR,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI;IAmEhD,YAAY,CAAC,IAAI,EAAE,MAAM;IAkDzB,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,GAAE,QAA0B;IAI5D,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,QAA0B;IAI/D,IAAI,IAAI,IAAI;IAOZ,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAWxB,UAAU,IAAI,IAAI;CAWzB"}
@@ -25,6 +25,7 @@ class Client extends shared_1.EventEmitter {
25
25
  resolvedAddress = null;
26
26
  proxyReady = false;
27
27
  lastPongTime = Date.now();
28
+ lastActivityTime = Date.now();
28
29
  isDisconnected = false;
29
30
  constructor(options = {}) {
30
31
  super();
@@ -35,7 +36,7 @@ class Client extends shared_1.EventEmitter {
35
36
  this.socket.bind();
36
37
  this.interval = setInterval(this.onTick.bind(this), 1000 / this.options.tickRate);
37
38
  this.socket.on("message", this.onMessage.bind(this));
38
- this.session = new shared_1.NetworkSession(this.options.mtu);
39
+ this.session = new shared_1.NetworkSession(this.options.mtu, this.options.debug);
39
40
  this.session.send = this.send.bind(this);
40
41
  this.session.handle = (data) => {
41
42
  this.handleOnline(data);
@@ -255,9 +256,9 @@ class Client extends shared_1.EventEmitter {
255
256
  if (this.tick % Client.PING_INTERVAL_TICKS === 0) {
256
257
  this.sendConnectedPing();
257
258
  }
258
- // Check for stale connection
259
- const timeSinceLastPong = Date.now() - this.lastPongTime;
260
- if (timeSinceLastPong > Client.STALE_TIMEOUT_MS) {
259
+ // Check for stale connection (no activity at all)
260
+ const timeSinceLastActivity = Date.now() - this.lastActivityTime;
261
+ if (timeSinceLastActivity > Client.STALE_TIMEOUT_MS) {
261
262
  this.handleDisconnect("Connection timed out (stale)");
262
263
  return;
263
264
  }
@@ -337,23 +338,19 @@ class Client extends shared_1.EventEmitter {
337
338
  break;
338
339
  }
339
340
  case shared_1.Packets.FrameSet: {
340
- try {
341
- const frameSet = new shared_1.FrameSet(actualData).deserialize();
342
- this.session.onFrameSet(frameSet);
343
- }
344
- catch (error) {
345
- const message = error instanceof Error ? error.message : "Unknown error";
346
- shared_2.Logger.error(`Frame set error: ${message}`);
347
- this.handleDisconnect(`Frame set error: ${message}`);
348
- }
341
+ this.lastActivityTime = Date.now();
342
+ const frameSet = new shared_1.FrameSet(actualData).deserialize();
343
+ this.session.onFrameSet(frameSet);
349
344
  break;
350
345
  }
351
346
  case shared_1.Packets.Ack: {
347
+ this.lastActivityTime = Date.now();
352
348
  const ack = new shared_1.Ack(actualData).deserialize();
353
349
  this.session.onAck(ack);
354
350
  break;
355
351
  }
356
352
  case shared_1.Packets.Nack: {
353
+ this.lastActivityTime = Date.now();
357
354
  const nack = new shared_1.Ack(actualData).deserialize();
358
355
  this.session.onNack(nack);
359
356
  break;
@@ -397,7 +394,9 @@ class Client extends shared_1.EventEmitter {
397
394
  this.frameAndSend(nic.serialize(), shared_1.Priority.High);
398
395
  this.status = shared_1.ConnectionStatus.Connected;
399
396
  this.lastPongTime = Date.now(); // Reset stale timer on connect
397
+ this.lastActivityTime = Date.now();
400
398
  this.emit("connect");
399
+ console.log("Raknet Connected");
401
400
  break;
402
401
  }
403
402
  default: {
@@ -13,6 +13,7 @@ export type ClientOptions = {
13
13
  pingRate: number;
14
14
  timeout: number;
15
15
  proxy?: ProxyOptions;
16
+ debug: boolean;
16
17
  };
17
18
  export declare const generateGuid: () => bigint;
18
19
  export declare const createDefaultClientOptions: () => ClientOptions;
@@ -1 +1 @@
1
- {"version":3,"file":"client-options.d.ts","sourceRoot":"","sources":["../../../src/client/types/client-options.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,YAAY,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,YAAY,QAAO,MAC0B,CAAC;AAE3D,eAAO,MAAM,0BAA0B,QAAO,aAQ5C,CAAC"}
1
+ {"version":3,"file":"client-options.d.ts","sourceRoot":"","sources":["../../../src/client/types/client-options.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,KAAK,EAAE,OAAO,CAAC;CACf,CAAC;AAEF,eAAO,MAAM,YAAY,QAAO,MAC0B,CAAC;AAE3D,eAAO,MAAM,0BAA0B,QAAO,aAS5C,CAAC"}
@@ -11,5 +11,6 @@ const createDefaultClientOptions = () => ({
11
11
  tickRate: 20,
12
12
  pingRate: 40,
13
13
  timeout: 30000,
14
+ debug: false,
14
15
  });
15
16
  exports.createDefaultClientOptions = createDefaultClientOptions;
@@ -1 +1 @@
1
- {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../src/server/connection.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,GAAG,EAOR,YAAY,EACZ,KAAK,KAAK,EACV,KAAK,QAAQ,EAIb,QAAQ,EACR,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEhD,qBAAa,UAAW,SAAQ,YAAY,CAAC,gBAAgB,CAAC;IAS5D,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,GAAG;IACX,OAAO,CAAC,IAAI;IAXb,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IACjD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAO;IAElD,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,gBAAgB,CAAsB;IAC9C,OAAO,CAAC,cAAc,CAAS;gBAGtB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,UAAU,EACjB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM;IAQd,MAAM,CAAC,IAAI,EAAE,MAAM;IAoBnB,UAAU,CAAC,MAAM,SAAiB,GAAG,IAAI;IAYzC,OAAO,IAAI,OAAO;IAIlB,UAAU,CAAC,QAAQ,EAAE,QAAQ;IAW7B,UAAU,IAAI,UAAU;IAIxB,SAAS,CAAC,IAAI,EAAE,MAAM;IA2DtB,KAAK,CAAC,OAAO,EAAE,GAAG;IAIzB,uFAAuF;IAChF,MAAM,CAAC,OAAO,EAAE,GAAG;IAInB,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,GAAE,QAAwB;IAI1D,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,GAAE,QAAwB;IAIhE,IAAI,CAAC,IAAI,EAAE,MAAM;CAGxB"}
1
+ {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../src/server/connection.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,GAAG,EAOR,YAAY,EACZ,KAAK,KAAK,EACV,KAAK,QAAQ,EAIb,QAAQ,EACR,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEhD,qBAAa,UAAW,SAAQ,YAAY,CAAC,gBAAgB,CAAC;IAS5D,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,GAAG;IACX,OAAO,CAAC,IAAI;IAXb,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IACjD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAO;IAElD,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,gBAAgB,CAAsB;IAC9C,OAAO,CAAC,cAAc,CAAS;gBAGtB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,UAAU,EACjB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM;IAWd,MAAM,CAAC,IAAI,EAAE,MAAM;IAoBnB,UAAU,CAAC,MAAM,SAAiB,GAAG,IAAI;IAYzC,OAAO,IAAI,OAAO;IAIlB,UAAU,CAAC,QAAQ,EAAE,QAAQ;IAK7B,UAAU,IAAI,UAAU;IAIxB,SAAS,CAAC,IAAI,EAAE,MAAM;IA8DtB,KAAK,CAAC,OAAO,EAAE,GAAG;IAIzB,uFAAuF;IAChF,MAAM,CAAC,OAAO,EAAE,GAAG;IAInB,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,GAAE,QAAwB;IAI1D,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,GAAE,QAAwB;IAIhE,IAAI,CAAC,IAAI,EAAE,MAAM;CAGxB"}
@@ -18,7 +18,7 @@ class Connection extends shared_1.EventEmitter {
18
18
  this.rinfo = rinfo;
19
19
  this.mtu = mtu;
20
20
  this.guid = guid;
21
- this.session = new shared_1.NetworkSession(this.mtu);
21
+ this.session = new shared_1.NetworkSession(this.mtu, this.server.options.enableServerLogs);
22
22
  this.session.send = this.send.bind(this);
23
23
  this.session.handle = this.onMessage.bind(this);
24
24
  }
@@ -46,22 +46,15 @@ class Connection extends shared_1.EventEmitter {
46
46
  // Send disconnect packet to client
47
47
  const disconnect = new shared_1.DisconnectMessage();
48
48
  this.session.frameAndSend(disconnect.serialize(), shared_1.Priority.High);
49
- // Emit disconnect event
50
- this.server.emit("disconnect", this);
49
+ // Emit disconnect event with reason
50
+ this.server.emit("disconnect", { connection: this, reason });
51
51
  }
52
52
  isStale() {
53
53
  return this.isDisconnected;
54
54
  }
55
55
  onFrameSet(frameSet) {
56
56
  this.lastActivityTime = Date.now();
57
- try {
58
- this.session.onFrameSet(frameSet);
59
- }
60
- catch (error) {
61
- const message = error instanceof Error ? error.message : "Unknown error";
62
- shared_1.Logger.error(`Frame set error: ${message}`);
63
- this.disconnect(`Frame set error: ${message}`);
64
- }
57
+ this.session.onFrameSet(frameSet);
65
58
  }
66
59
  getAddress() {
67
60
  return this.rinfo;
@@ -88,7 +81,10 @@ class Connection extends shared_1.EventEmitter {
88
81
  }
89
82
  case shared_1.Packets.Disconnect: {
90
83
  this.isDisconnected = true;
91
- this.server.emit("disconnect", this);
84
+ this.server.emit("disconnect", {
85
+ connection: this,
86
+ reason: "Client disconnected",
87
+ });
92
88
  break;
93
89
  }
94
90
  case shared_1.Packets.ConnectedPing: {
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/server/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAGN,YAAY,EAQZ,MAAM,WAAW,CAAC;AAEnB,OAAO,EACN,KAAK,aAAa,EAElB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EAExB,MAAM,SAAS,CAAC;AAGjB,qBAAa,MAAO,SAAQ,YAAY,CAAC,kBAAkB,CAAC;IAC3D,OAAO,CAAC,MAAM,CAAS;IACvB,SAAgB,OAAO,EAAE,mBAAmB,CAAC;IACtC,aAAa,EAAE,aAAa,CAAC;IACpC,OAAO,CAAC,WAAW,CAA0B;IAC7C,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,YAAY,CAAiB;gBAEzB,OAAO,GAAE,OAAO,CAAC,mBAAmB,CAAM;IAuB/C,IAAI;IAOJ,MAAM;IAab,OAAO,CAAC,YAAY;IAYpB,OAAO,CAAC,SAAS;IA6EV,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;CAGzD"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/server/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAGN,YAAY,EAQZ,MAAM,WAAW,CAAC;AAEnB,OAAO,EACN,KAAK,aAAa,EAElB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EAExB,MAAM,SAAS,CAAC;AAGjB,qBAAa,MAAO,SAAQ,YAAY,CAAC,kBAAkB,CAAC;IAC3D,OAAO,CAAC,MAAM,CAAS;IACvB,SAAgB,OAAO,EAAE,mBAAmB,CAAC;IACtC,aAAa,EAAE,aAAa,CAAC;IACpC,OAAO,CAAC,WAAW,CAA0B;IAC7C,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,YAAY,CAAiB;gBAEzB,OAAO,GAAE,OAAO,CAAC,mBAAmB,CAAM;IAuB/C,IAAI;IAOJ,MAAM;IAab,OAAO,CAAC,YAAY;IAcpB,OAAO,CAAC,SAAS;IA6EV,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;CAGzD"}
@@ -47,15 +47,12 @@ class Server extends shared_1.EventEmitter {
47
47
  this.socket.on("message", this.onMessage.bind(this));
48
48
  this.on("disconnect", this.onDisconnect.bind(this));
49
49
  }
50
- onDisconnect(connection, executedByServer = false) {
50
+ onDisconnect({ connection, reason, }) {
51
51
  const address = connection.getAddress();
52
52
  this.connections.delete(`${address.address}:${address.port}`);
53
53
  this.advertisement.playerCount = this.connections.size;
54
- if (executedByServer) {
55
- this.emit("disconnect", connection);
56
- }
57
54
  if (this.options.enableServerLogs) {
58
- shared_1.Logger.info(`Client disconnected ${address.address}:${address.port}`);
55
+ shared_1.Logger.info(`Client disconnected ${address.address}:${address.port} - ${reason}`);
59
56
  }
60
57
  }
61
58
  onMessage(message, rinfo) {
@@ -1,7 +1,11 @@
1
1
  import type { Connection } from "../connection";
2
+ export interface DisconnectEvent {
3
+ connection: Connection;
4
+ reason: string;
5
+ }
2
6
  export interface RaknetServerEvents {
3
7
  listening: undefined;
4
8
  connect: Connection;
5
- disconnect: Connection;
9
+ disconnect: DisconnectEvent;
6
10
  }
7
11
  //# sourceMappingURL=server-events.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server-events.d.ts","sourceRoot":"","sources":["../../../src/server/types/server-events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,MAAM,WAAW,kBAAkB;IAClC,SAAS,EAAE,SAAS,CAAC;IACrB,OAAO,EAAE,UAAU,CAAC;IACpB,UAAU,EAAE,UAAU,CAAC;CACvB"}
1
+ {"version":3,"file":"server-events.d.ts","sourceRoot":"","sources":["../../../src/server/types/server-events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,MAAM,WAAW,eAAe;IAC/B,UAAU,EAAE,UAAU,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IAClC,SAAS,EAAE,SAAS,CAAC;IACrB,OAAO,EAAE,UAAU,CAAC;IACpB,UAAU,EAAE,eAAe,CAAC;CAC5B"}
@@ -1,6 +1,7 @@
1
1
  import { Ack, Frame, FrameSet, Priority } from "./proto";
2
2
  export declare class NetworkSession {
3
3
  mtu: number;
4
+ debug: boolean;
4
5
  send: (data: Buffer) => void;
5
6
  handle: (data: Buffer) => void;
6
7
  outputReliableIndex: number;
@@ -12,13 +13,23 @@ export declare class NetworkSession {
12
13
  outputBackup: Map<number, Frame[]>;
13
14
  receivedFrameSequences: Set<number>;
14
15
  lostFrameSequences: Set<number>;
16
+ pendingAcks: Set<number>;
15
17
  lastInputSequence: number;
16
- fragmentsQueue: Map<number, Map<number, Frame>>;
18
+ fragmentsQueue: Map<number, {
19
+ frames: Map<number, Frame>;
20
+ timestamp: number;
21
+ }>;
17
22
  inputHighestSequenceIndex: Array<number>;
18
23
  inputOrderIndex: Array<number>;
19
24
  protected inputOrderingQueue: Map<number, Map<number, Frame>>;
20
- constructor(mtu: number);
21
- onTick(): void;
25
+ private receivedReliableFrameIndices;
26
+ private highestReliableIndex;
27
+ private static readonly RECEIVE_WINDOW_SIZE;
28
+ private static readonly RELIABLE_WINDOW_SIZE;
29
+ private static readonly FRAGMENT_TIMEOUT_MS;
30
+ private static readonly ORDER_QUEUE_MAX_SIZE;
31
+ constructor(mtu: number, debug?: boolean);
32
+ onTick(_tick?: number): void;
22
33
  onAck(ack: Ack): void;
23
34
  onNack(nack: Ack): void;
24
35
  frameAndSend(data: Buffer, priority?: Priority): void;
@@ -1 +1 @@
1
- {"version":3,"file":"network_session.d.ts","sourceRoot":"","sources":["../../src/shared/network_session.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAW,QAAQ,EAAe,MAAM,SAAS,CAAC;AAK/E,qBAAa,cAAc;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAG,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,MAAM,EAAG,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAGhC,mBAAmB,SAAK;IACxB,gBAAgB,SAAK;IAC5B,SAAS,CAAC,cAAc,SAAK;IACtB,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,YAAY,EAAE,GAAG,CAAC,KAAK,CAAC,CAAa;IACrC,YAAY,uBAA8B;IAG1C,sBAAsB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAa;IAChD,kBAAkB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAa;IAC5C,iBAAiB,SAAM;IACvB,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAa;IAC5D,yBAAyB,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACzC,eAAe,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACtC,SAAS,CAAC,kBAAkB,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAa;gBAE9D,GAAG,EAAE,MAAM;IAUvB,MAAM;IAuBN,KAAK,CAAC,GAAG,EAAE,GAAG;IAMd,MAAM,CAAC,IAAI,EAAE,GAAG;IAeT,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,QAA0B;IAQ/D,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,GAAE,QAA0B;IA8C5D,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ;IAW3C,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAiB/B,UAAU,CAAC,QAAQ,EAAE,QAAQ;IA+B7B,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAY/B,gBAAgB,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAiCpC,eAAe,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAcnC,aAAa,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;CA8BxC"}
1
+ {"version":3,"file":"network_session.d.ts","sourceRoot":"","sources":["../../src/shared/network_session.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAW,QAAQ,EAAe,MAAM,SAAS,CAAC;AAK/E,qBAAa,cAAc;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAG,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,MAAM,EAAG,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAGhC,mBAAmB,SAAK;IACxB,gBAAgB,SAAK;IAC5B,SAAS,CAAC,cAAc,SAAK;IACtB,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,YAAY,EAAE,GAAG,CAAC,KAAK,CAAC,CAAa;IACrC,YAAY,uBAA8B;IAG1C,sBAAsB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAa;IAChD,kBAAkB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAa;IAC5C,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAa;IACrC,iBAAiB,SAAM;IACvB,cAAc,EAAE,GAAG,CACzB,MAAM,EACN;QAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CACjD,CAAa;IACP,yBAAyB,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACzC,eAAe,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACtC,SAAS,CAAC,kBAAkB,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAa;IAE1E,OAAO,CAAC,4BAA4B,CAA0B;IAC9D,OAAO,CAAC,oBAAoB,CAAM;IAGlC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAQ;IACnD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAAQ;IACpD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAS;IACpD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAAO;gBAEvC,GAAG,EAAE,MAAM,EAAE,KAAK,UAAQ;IAWtC,MAAM,CAAC,KAAK,CAAC,EAAE,MAAM;IAuDrB,KAAK,CAAC,GAAG,EAAE,GAAG;IAMd,MAAM,CAAC,IAAI,EAAE,GAAG;IAeT,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,QAA0B;IAQ/D,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,GAAE,QAA0B;IA8C5D,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ;IAW3C,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAiB/B,UAAU,CAAC,QAAQ,EAAE,QAAQ;IAkD7B,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAwB/B,gBAAgB,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IA2CpC,eAAe,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAenC,aAAa,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;CAyCxC"}
@@ -7,6 +7,7 @@ const logger_1 = require("./logger");
7
7
  const MTU_HEADER_SIZE = 36;
8
8
  class NetworkSession {
9
9
  mtu;
10
+ debug;
10
11
  send;
11
12
  handle;
12
13
  // Output
@@ -20,13 +21,22 @@ class NetworkSession {
20
21
  // Input
21
22
  receivedFrameSequences = new Set();
22
23
  lostFrameSequences = new Set();
24
+ pendingAcks = new Set();
23
25
  lastInputSequence = -1;
24
26
  fragmentsQueue = new Map();
25
27
  inputHighestSequenceIndex;
26
28
  inputOrderIndex;
27
29
  inputOrderingQueue = new Map();
28
- constructor(mtu) {
30
+ receivedReliableFrameIndices = new Set();
31
+ highestReliableIndex = -1;
32
+ // goofy ahh geyser stuff
33
+ static RECEIVE_WINDOW_SIZE = 2048;
34
+ static RELIABLE_WINDOW_SIZE = 4096;
35
+ static FRAGMENT_TIMEOUT_MS = 30000;
36
+ static ORDER_QUEUE_MAX_SIZE = 256;
37
+ constructor(mtu, debug = false) {
29
38
  this.mtu = mtu;
39
+ this.debug = debug;
30
40
  this.outputOrderIndex = new Array(32).fill(0);
31
41
  this.outputSequenceIndex = new Array(32).fill(0);
32
42
  this.inputHighestSequenceIndex = Array.from({ length: 32 }).fill(0);
@@ -34,10 +44,36 @@ class NetworkSession {
34
44
  for (let index = 0; index < 32; index++)
35
45
  this.inputOrderingQueue.set(index, new Map());
36
46
  }
37
- onTick() {
38
- if (this.receivedFrameSequences.size > 0) {
39
- const ackSeqs = Array.from(this.receivedFrameSequences);
40
- this.receivedFrameSequences.clear();
47
+ onTick(_tick) {
48
+ const now = Date.now();
49
+ const windowStart = this.lastInputSequence - NetworkSession.RECEIVE_WINDOW_SIZE;
50
+ if (windowStart > 0) {
51
+ for (const seq of this.receivedFrameSequences) {
52
+ if (seq < windowStart)
53
+ this.receivedFrameSequences.delete(seq);
54
+ }
55
+ for (const seq of this.lostFrameSequences) {
56
+ if (seq < windowStart)
57
+ this.lostFrameSequences.delete(seq);
58
+ }
59
+ }
60
+ const reliableWindowStart = this.highestReliableIndex - NetworkSession.RELIABLE_WINDOW_SIZE;
61
+ if (reliableWindowStart > 0) {
62
+ for (const idx of this.receivedReliableFrameIndices) {
63
+ if (idx < reliableWindowStart)
64
+ this.receivedReliableFrameIndices.delete(idx);
65
+ }
66
+ }
67
+ for (const [splitId, entry] of this.fragmentsQueue) {
68
+ if (now - entry.timestamp > NetworkSession.FRAGMENT_TIMEOUT_MS) {
69
+ if (this.debug)
70
+ logger_1.Logger.warn(`Fragment queue ${splitId} timed out, dropping ${entry.frames.size} fragments`);
71
+ this.fragmentsQueue.delete(splitId);
72
+ }
73
+ }
74
+ if (this.pendingAcks.size > 0) {
75
+ const ackSeqs = Array.from(this.pendingAcks);
76
+ this.pendingAcks.clear();
41
77
  const ack = new proto_1.Ack();
42
78
  ack.sequences = ackSeqs;
43
79
  this.send(ack.serialize());
@@ -145,27 +181,53 @@ class NetworkSession {
145
181
  this.send(buffer);
146
182
  }
147
183
  onFrameSet(frameSet) {
184
+ // Already received this exact sequence so ignore duplicate
148
185
  if (this.receivedFrameSequences.has(frameSet.sequence)) {
149
- throw new Error("Duplicate frame set received");
186
+ if (this.debug)
187
+ logger_1.Logger.warn(`Duplicate frame set received: sequence ${frameSet.sequence}`);
188
+ return;
150
189
  }
190
+ // Remove from lost if we finally got it
151
191
  this.lostFrameSequences.delete(frameSet.sequence);
152
- const isLess = frameSet.sequence < this.lastInputSequence;
153
- const isEqual = frameSet.sequence === this.lastInputSequence;
154
- if (isLess || isEqual) {
155
- throw new Error("Frame set received is out of order");
156
- }
192
+ // Track this sequence as received and queue ACK
157
193
  this.receivedFrameSequences.add(frameSet.sequence);
158
- const diff = frameSet.sequence - this.lastInputSequence;
159
- if (diff > 1) {
160
- for (let index = this.lastInputSequence + 1; index < frameSet.sequence; index++)
161
- this.lostFrameSequences.add(index);
194
+ this.pendingAcks.add(frameSet.sequence);
195
+ // If this is a newer sequence than we've seen, update tracking
196
+ if (frameSet.sequence > this.lastInputSequence) {
197
+ const diff = frameSet.sequence - this.lastInputSequence;
198
+ // Mark any gaps as lost (for NACK)
199
+ if (diff > 1) {
200
+ for (let index = this.lastInputSequence + 1; index < frameSet.sequence; index++) {
201
+ // Only mark as lost if we haven't already received it
202
+ if (!this.receivedFrameSequences.has(index)) {
203
+ this.lostFrameSequences.add(index);
204
+ }
205
+ }
206
+ }
207
+ this.lastInputSequence = frameSet.sequence;
162
208
  }
163
- this.lastInputSequence = frameSet.sequence;
209
+ else {
210
+ // zOut-of-order packet (arrived late but still valid)
211
+ if (this.debug)
212
+ logger_1.Logger.warn(`Out-of-order frame set received: sequence ${frameSet.sequence} (expected > ${this.lastInputSequence})`);
213
+ }
214
+ // Process all frames
164
215
  for (const frame of frameSet.frames) {
165
216
  this.handleFrame(frame);
166
217
  }
167
218
  }
168
219
  handleFrame(frame) {
220
+ // Duplicate detection for reliable frames
221
+ if (frame.isReliable()) {
222
+ if (this.receivedReliableFrameIndices.has(frame.reliableFrameIndex)) {
223
+ // Already processed tsis reliable frame, skip
224
+ return;
225
+ }
226
+ this.receivedReliableFrameIndices.add(frame.reliableFrameIndex);
227
+ if (frame.reliableFrameIndex > this.highestReliableIndex) {
228
+ this.highestReliableIndex = frame.reliableFrameIndex;
229
+ }
230
+ }
169
231
  if (frame.isSplit()) {
170
232
  this.handleSplitFrame(frame);
171
233
  }
@@ -183,38 +245,49 @@ class NetworkSession {
183
245
  const splitId = frame.splitId;
184
246
  let entry = this.fragmentsQueue.get(splitId);
185
247
  if (!entry) {
186
- entry = new Map();
248
+ entry = { frames: new Map(), timestamp: Date.now() };
187
249
  this.fragmentsQueue.set(splitId, entry);
188
250
  }
189
- entry.set(frame.splitFrameIndex, frame);
190
- if (entry.size === frame.splitSize) {
191
- {
192
- const stream = new binarystream_1.BinaryStream();
193
- for (let index = 0; index < frame.splitSize; index++) {
194
- const sframe = entry.get(index);
195
- if (!sframe) {
196
- throw new Error(`Missing fragment at index ${index} for splitId=${frame.splitId}`);
197
- }
198
- stream.write(sframe.payload);
251
+ entry.frames.set(frame.splitFrameIndex, frame);
252
+ if (entry.frames.size === frame.splitSize) {
253
+ const stream = new binarystream_1.BinaryStream();
254
+ for (let index = 0; index < frame.splitSize; index++) {
255
+ const sframe = entry.frames.get(index);
256
+ if (!sframe) {
257
+ if (this.debug)
258
+ logger_1.Logger.warn(`Missing fragment at index ${index} for splitId=${frame.splitId}`);
259
+ this.fragmentsQueue.delete(splitId);
260
+ return;
199
261
  }
200
- const reassembledFrame = new proto_1.Frame();
201
- reassembledFrame.reliability = frame.reliability;
202
- reassembledFrame.reliableFrameIndex = frame.reliableFrameIndex;
203
- reassembledFrame.sequenceFrameIndex = frame.sequenceFrameIndex;
204
- reassembledFrame.orderedFrameIndex = frame.orderedFrameIndex;
205
- reassembledFrame.orderChannel = frame.orderChannel;
206
- reassembledFrame.payload = stream.getBuffer();
207
- this.handleFrame(reassembledFrame);
262
+ stream.write(sframe.payload);
208
263
  }
264
+ const reassembledFrame = new proto_1.Frame();
265
+ reassembledFrame.reliability = frame.reliability;
266
+ reassembledFrame.reliableFrameIndex = frame.reliableFrameIndex;
267
+ reassembledFrame.sequenceFrameIndex = frame.sequenceFrameIndex;
268
+ reassembledFrame.orderedFrameIndex = frame.orderedFrameIndex;
269
+ reassembledFrame.orderChannel = frame.orderChannel;
270
+ reassembledFrame.payload = stream.getBuffer();
209
271
  this.fragmentsQueue.delete(splitId);
272
+ // Process the reassembled frame (but skip split handling since it's no longer split)
273
+ if (reassembledFrame.isSequenced()) {
274
+ this.handleSequenced(reassembledFrame);
275
+ }
276
+ else if (reassembledFrame.isOrdered()) {
277
+ this.handleOrdered(reassembledFrame);
278
+ }
279
+ else {
280
+ this.handle(reassembledFrame.payload);
281
+ }
210
282
  }
211
283
  }
212
284
  handleSequenced(frame) {
213
285
  const channel = frame.orderChannel;
214
- const currentHighestSequence = this.inputHighestSequenceIndex[channel];
215
- const isLess = frame.sequenceFrameIndex < currentHighestSequence;
216
- if (isLess || frame.orderedFrameIndex === this.inputOrderIndex[channel]) {
217
- logger_1.Logger.warn("Frame dropped, sequence is less than current highest sequence");
286
+ const currentHighestSequence = this.inputHighestSequenceIndex[channel] ?? 0;
287
+ // Sequenced frames: drop if older than what we've seen, otherwise process immediately
288
+ // They don't need ordering, just drop stale ones
289
+ if (frame.sequenceFrameIndex < currentHighestSequence) {
290
+ // Old sequenced frame, drop it
218
291
  return;
219
292
  }
220
293
  this.inputHighestSequenceIndex[channel] = frame.sequenceFrameIndex + 1;
@@ -222,32 +295,42 @@ class NetworkSession {
222
295
  }
223
296
  handleOrdered(frame) {
224
297
  const channel = frame.orderChannel;
225
- const expectedOrderIndex = this.inputOrderIndex[channel];
226
- const isEqual = frame.orderedFrameIndex === expectedOrderIndex;
227
- if (frame.orderedFrameIndex > expectedOrderIndex) {
228
- const unordered = this.inputOrderingQueue.get(channel);
229
- if (!unordered) {
230
- logger_1.Logger.warn("No unordered queue found");
231
- return;
298
+ const expectedOrderIndex = this.inputOrderIndex[channel] ?? 0;
299
+ if (frame.orderedFrameIndex === expectedOrderIndex) {
300
+ // This is the frame we're waiting for - process it
301
+ this.inputHighestSequenceIndex[channel] = 0;
302
+ this.inputOrderIndex[channel] = expectedOrderIndex + 1;
303
+ this.handle(frame.payload);
304
+ // Now flush any queued frames that are now in order
305
+ const outOfOrderQueue = this.inputOrderingQueue.get(channel);
306
+ if (outOfOrderQueue) {
307
+ let nextIndex = expectedOrderIndex + 1;
308
+ while (outOfOrderQueue.has(nextIndex)) {
309
+ const queuedFrame = outOfOrderQueue.get(nextIndex);
310
+ if (queuedFrame) {
311
+ this.handle(queuedFrame.payload);
312
+ outOfOrderQueue.delete(nextIndex);
313
+ }
314
+ nextIndex++;
315
+ }
316
+ this.inputOrderIndex[channel] = nextIndex;
232
317
  }
233
- unordered.set(frame.orderedFrameIndex, frame);
234
318
  }
235
- else if (isEqual) {
236
- this.inputHighestSequenceIndex[frame.orderChannel] = 0;
237
- this.inputOrderIndex[frame.orderChannel] = frame.orderedFrameIndex + 1;
238
- this.handle(frame.payload);
239
- let index = this.inputOrderIndex[frame.orderChannel];
240
- const outOfOrderQueue = this.inputOrderingQueue.get(frame.orderChannel);
241
- for (; outOfOrderQueue.has(index); index++) {
242
- const frame = outOfOrderQueue.get(index);
243
- if (!frame)
244
- break;
245
- this.handle(frame.payload);
246
- outOfOrderQueue.delete(index);
319
+ else if (frame.orderedFrameIndex > expectedOrderIndex) {
320
+ // Future frame n queue it for later
321
+ const outOfOrderQueue = this.inputOrderingQueue.get(channel);
322
+ if (outOfOrderQueue) {
323
+ // Prevent unbounded queue growth
324
+ if (outOfOrderQueue.size < NetworkSession.ORDER_QUEUE_MAX_SIZE) {
325
+ outOfOrderQueue.set(frame.orderedFrameIndex, frame);
326
+ }
327
+ else {
328
+ if (this.debug)
329
+ logger_1.Logger.debug(`Order queue for channel ${channel} is full, dropping frame ${frame.orderedFrameIndex}`);
330
+ }
247
331
  }
248
- this.inputOrderingQueue.set(frame.orderChannel, outOfOrderQueue);
249
- this.inputOrderIndex[frame.orderChannel] = index;
250
332
  }
333
+ // If frame.orderedFrameIndex < expectedOrderIndex, it's a duplicate/old frame - ignore it
251
334
  }
252
335
  }
253
336
  exports.NetworkSession = NetworkSession;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanctumterra/raknet",
3
- "version": "1.4.11",
3
+ "version": "1.4.13",
4
4
  "description": "",
5
5
  "types": "dist/index.d.ts",
6
6
  "main": "dist/index.js",