@sanctumterra/raknet 1.4.7 → 1.4.9

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.
@@ -5,6 +5,8 @@ import { type RemoteInfo } from "node:dgram";
5
5
  export declare class Client extends EventEmitter<ClientEvents> {
6
6
  private static readonly MTU_VALUES;
7
7
  private static readonly MTU_RETRY_INTERVAL;
8
+ private static readonly STALE_TIMEOUT_MS;
9
+ private static readonly PING_INTERVAL_TICKS;
8
10
  options: ClientOptions;
9
11
  private socket;
10
12
  private interval;
@@ -17,6 +19,8 @@ export declare class Client extends EventEmitter<ClientEvents> {
17
19
  private proxyRelayPort;
18
20
  private resolvedAddress;
19
21
  private proxyReady;
22
+ private lastPongTime;
23
+ private isDisconnected;
20
24
  constructor(options?: Partial<ClientOptions>);
21
25
  private setupProxy;
22
26
  private buildUdpAssociateRequest;
@@ -25,6 +29,9 @@ export declare class Client extends EventEmitter<ClientEvents> {
25
29
  private parseSocks5UdpHeader;
26
30
  connect(): Promise<void>;
27
31
  onTick(): void;
32
+ private sendConnectedPing;
33
+ private handleDisconnect;
34
+ private cleanup;
28
35
  onMessage(data: Buffer, rinfo: RemoteInfo): void;
29
36
  handleOnline(data: Buffer): void;
30
37
  sendFrame(frame: Frame, priority?: Priority): void;
@@ -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,EAIV,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;IAE1C,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;gBAEf,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;IAYd,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI;IAgEhD,YAAY,CAAC,IAAI,EAAE,MAAM;IAyCzB,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;CAQzB"}
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;IAgEhD,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"}
@@ -10,6 +10,8 @@ const promises_1 = require("node:dns/promises");
10
10
  class Client extends shared_1.EventEmitter {
11
11
  static MTU_VALUES = [1492, 1400, 1028, 1200, 576];
12
12
  static MTU_RETRY_INTERVAL = 500;
13
+ static STALE_TIMEOUT_MS = 10000; // 10 seconds without pong = stale
14
+ static PING_INTERVAL_TICKS = 100; // Send connected ping every ~2 seconds at 50 tick rate
13
15
  options;
14
16
  socket;
15
17
  interval;
@@ -22,9 +24,11 @@ class Client extends shared_1.EventEmitter {
22
24
  proxyRelayPort = null;
23
25
  resolvedAddress = null;
24
26
  proxyReady = false;
27
+ lastPongTime = Date.now();
28
+ isDisconnected = false;
25
29
  constructor(options = {}) {
26
30
  super();
27
- this.options = { ...client_options_1.defaultClientOptions, ...options };
31
+ this.options = { ...(0, client_options_1.createDefaultClientOptions)(), ...options };
28
32
  this.status = shared_1.ConnectionStatus.Disconnected;
29
33
  this.tick = 0;
30
34
  this.socket = (0, node_dgram_1.createSocket)("udp4");
@@ -241,14 +245,57 @@ class Client extends shared_1.EventEmitter {
241
245
  onTick() {
242
246
  const isDisconnected = this.status === shared_1.ConnectionStatus.Disconnected;
243
247
  const isDisconnecting = this.status === shared_1.ConnectionStatus.Disconnecting;
248
+ const isConnected = this.status === shared_1.ConnectionStatus.Connected;
244
249
  const canPing = isDisconnected && this.tick % this.options.pingRate === 0;
245
250
  if (canPing && (!this.options.proxy || this.proxyReady))
246
251
  this.ping();
252
+ // Send connected pings and check for stale connection when connected
253
+ if (isConnected) {
254
+ // Send connected ping periodically
255
+ if (this.tick % Client.PING_INTERVAL_TICKS === 0) {
256
+ this.sendConnectedPing();
257
+ }
258
+ // Check for stale connection
259
+ const timeSinceLastPong = Date.now() - this.lastPongTime;
260
+ if (timeSinceLastPong > Client.STALE_TIMEOUT_MS) {
261
+ this.handleDisconnect("Connection timed out (stale)");
262
+ return;
263
+ }
264
+ }
247
265
  if (!isDisconnecting || !isDisconnected) {
248
266
  this.session.onTick(this.tick);
249
267
  }
250
268
  this.tick++;
251
269
  }
270
+ sendConnectedPing() {
271
+ const ping = new shared_1.ConnectedPing();
272
+ ping.timestamp = BigInt(Date.now());
273
+ this.frameAndSend(ping.serialize(), shared_1.Priority.High);
274
+ }
275
+ handleDisconnect(reason) {
276
+ if (this.isDisconnected)
277
+ return;
278
+ this.isDisconnected = true;
279
+ this.status = shared_1.ConnectionStatus.Disconnected;
280
+ this.emit("disconnect", reason);
281
+ this.cleanup();
282
+ }
283
+ cleanup() {
284
+ if (this.interval) {
285
+ clearInterval(this.interval);
286
+ this.interval = null;
287
+ }
288
+ try {
289
+ this.socket.close();
290
+ }
291
+ catch {
292
+ // Socket may already be closed
293
+ }
294
+ if (this.proxySocket) {
295
+ this.proxySocket.destroy();
296
+ this.proxySocket = null;
297
+ }
298
+ }
252
299
  onMessage(data, rinfo) {
253
300
  let actualData = data;
254
301
  if (this.proxyRelayHost && this.proxyRelayPort) {
@@ -318,6 +365,7 @@ class Client extends shared_1.EventEmitter {
318
365
  break;
319
366
  }
320
367
  case shared_1.Packets.ConnectedPong: {
368
+ this.lastPongTime = Date.now();
321
369
  break;
322
370
  }
323
371
  case shared_1.Packets.ConnectedPing: {
@@ -325,7 +373,11 @@ class Client extends shared_1.EventEmitter {
325
373
  const pong = new shared_1.ConnectedPong();
326
374
  pong.pingTimestamp = ping.timestamp;
327
375
  pong.pongTimestamp = BigInt(Date.now());
328
- this.frameAndSend(ping.serialize(), shared_1.Priority.High);
376
+ this.frameAndSend(pong.serialize(), shared_1.Priority.High);
377
+ break;
378
+ }
379
+ case shared_1.Packets.Disconnect: {
380
+ this.handleDisconnect("Server disconnected");
329
381
  break;
330
382
  }
331
383
  case shared_1.Packets.ConnectionRequestAccepted: {
@@ -336,6 +388,8 @@ class Client extends shared_1.EventEmitter {
336
388
  nic.incomingTimestamp = BigInt(Date.now());
337
389
  nic.serverTimestamp = accepted.timestamp;
338
390
  this.frameAndSend(nic.serialize(), shared_1.Priority.High);
391
+ this.status = shared_1.ConnectionStatus.Connected;
392
+ this.lastPongTime = Date.now(); // Reset stale timer on connect
339
393
  this.emit("connect");
340
394
  break;
341
395
  }
@@ -369,13 +423,14 @@ class Client extends shared_1.EventEmitter {
369
423
  }
370
424
  }
371
425
  disconnect() {
372
- this.socket.close();
373
- if (this.proxySocket) {
374
- this.proxySocket.destroy();
375
- this.proxySocket = null;
426
+ if (this.isDisconnected)
427
+ return;
428
+ // Send disconnect packet to server if connected
429
+ if (this.status === shared_1.ConnectionStatus.Connected) {
430
+ const disconnect = new shared_1.DisconnectMessage();
431
+ this.frameAndSend(disconnect.serialize(), shared_1.Priority.High);
376
432
  }
377
- if (this.interval)
378
- clearInterval(this.interval);
433
+ this.handleDisconnect("Client disconnected");
379
434
  }
380
435
  }
381
436
  exports.Client = Client;
@@ -3,6 +3,7 @@ export interface ClientEvents {
3
3
  unconnectedPong: UnconnectedPong;
4
4
  error: Error;
5
5
  connect: undefined;
6
+ disconnect: string;
6
7
  encapsulated: Buffer;
7
8
  }
8
9
  //# sourceMappingURL=client-events.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client-events.d.ts","sourceRoot":"","sources":["../../../src/client/types/client-events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,MAAM,WAAW,YAAY;IAC5B,eAAe,EAAE,eAAe,CAAC;IACjC,KAAK,EAAE,KAAK,CAAC;IACb,OAAO,EAAE,SAAS,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACrB"}
1
+ {"version":3,"file":"client-events.d.ts","sourceRoot":"","sources":["../../../src/client/types/client-events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,MAAM,WAAW,YAAY;IAC5B,eAAe,EAAE,eAAe,CAAC;IACjC,KAAK,EAAE,KAAK,CAAC;IACb,OAAO,EAAE,SAAS,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACrB"}
@@ -14,6 +14,6 @@ export type ClientOptions = {
14
14
  timeout: number;
15
15
  proxy?: ProxyOptions;
16
16
  };
17
- export declare const getRandomGuid: () => bigint;
18
- export declare const defaultClientOptions: ClientOptions;
17
+ export declare const generateGuid: () => bigint;
18
+ export declare const createDefaultClientOptions: () => ClientOptions;
19
19
  //# sourceMappingURL=client-options.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client-options.d.ts","sourceRoot":"","sources":["../../../src/client/types/client-options.ts"],"names":[],"mappings":"AAEA,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;AACF,eAAO,MAAM,aAAa,cACgC,CAAC;AAE3D,eAAO,MAAM,oBAAoB,EAAE,aAQlC,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;CACrB,CAAC;AAEF,eAAO,MAAM,YAAY,QAAO,MAC0B,CAAC;AAE3D,eAAO,MAAM,0BAA0B,QAAO,aAQ5C,CAAC"}
@@ -1,14 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.defaultClientOptions = exports.getRandomGuid = void 0;
4
- const getRandomGuid = () => BigInt(Math.floor(Date.now() + Math.random() * 10000000));
5
- exports.getRandomGuid = getRandomGuid;
6
- exports.defaultClientOptions = {
3
+ exports.createDefaultClientOptions = exports.generateGuid = void 0;
4
+ const generateGuid = () => BigInt(Math.floor(Date.now() + Math.random() * 10000000));
5
+ exports.generateGuid = generateGuid;
6
+ const createDefaultClientOptions = () => ({
7
7
  mtu: 1492,
8
8
  address: "127.0.0.1",
9
9
  port: 19132,
10
- guid: (0, exports.getRandomGuid)(),
10
+ guid: (0, exports.generateGuid)(),
11
11
  tickRate: 20,
12
12
  pingRate: 40,
13
13
  timeout: 30000,
14
- };
14
+ });
15
+ exports.createDefaultClientOptions = createDefaultClientOptions;
@@ -7,9 +7,15 @@ export declare class Connection extends EventEmitter<ConnectionEvents> {
7
7
  private rinfo;
8
8
  private mtu;
9
9
  private guid;
10
+ private static readonly STALE_TIMEOUT_MS;
11
+ private static readonly PING_INTERVAL_TICKS;
10
12
  private session;
13
+ private lastActivityTime;
14
+ private isDisconnected;
11
15
  constructor(server: Server, rinfo: RemoteInfo, mtu: number, guid: bigint);
12
16
  onTick(tick: number): void;
17
+ disconnect(reason?: string): void;
18
+ isStale(): boolean;
13
19
  onFrameSet(frameSet: FrameSet): void;
14
20
  getAddress(): RemoteInfo;
15
21
  onMessage(data: Buffer): void;
@@ -1 +1 @@
1
- {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../src/server/connection.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,GAAG,EAMR,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;IAI5D,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,GAAG;IACX,OAAO,CAAC,IAAI;IANb,OAAO,CAAC,OAAO,CAAiB;gBAGvB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,UAAU,EACjB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM;IAQd,MAAM,CAAC,IAAI,EAAE,MAAM;IAInB,UAAU,CAAC,QAAQ,EAAE,QAAQ;IAI7B,UAAU,IAAI,UAAU;IAIxB,SAAS,CAAC,IAAI,EAAE,MAAM;IAqDtB,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;IAQd,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;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"}
@@ -7,7 +7,11 @@ class Connection extends shared_1.EventEmitter {
7
7
  rinfo;
8
8
  mtu;
9
9
  guid;
10
+ static STALE_TIMEOUT_MS = 10000; // 10 seconds without activity = stale
11
+ static PING_INTERVAL_TICKS = 100; // Send ping every ~2 seconds at 50 tick rate
10
12
  session;
13
+ lastActivityTime = Date.now();
14
+ isDisconnected = false;
11
15
  constructor(server, rinfo, mtu, guid) {
12
16
  super();
13
17
  this.server = server;
@@ -19,15 +23,44 @@ class Connection extends shared_1.EventEmitter {
19
23
  this.session.handle = this.onMessage.bind(this);
20
24
  }
21
25
  onTick(tick) {
26
+ if (this.isDisconnected)
27
+ return;
28
+ // Check for stale connection
29
+ const timeSinceLastActivity = Date.now() - this.lastActivityTime;
30
+ if (timeSinceLastActivity > Connection.STALE_TIMEOUT_MS) {
31
+ this.disconnect("Connection timed out (stale)");
32
+ return;
33
+ }
34
+ // Send connected ping periodically
35
+ if (tick % Connection.PING_INTERVAL_TICKS === 0) {
36
+ const ping = new shared_1.ConnectedPing();
37
+ ping.timestamp = BigInt(Date.now());
38
+ this.session.frameAndSend(ping.serialize(), shared_1.Priority.High);
39
+ }
22
40
  this.session.onTick(tick);
23
41
  }
42
+ disconnect(reason = "Disconnected") {
43
+ if (this.isDisconnected)
44
+ return;
45
+ this.isDisconnected = true;
46
+ // Send disconnect packet to client
47
+ const disconnect = new shared_1.DisconnectMessage();
48
+ this.session.frameAndSend(disconnect.serialize(), shared_1.Priority.High);
49
+ // Emit disconnect event
50
+ this.server.emit("disconnect", this);
51
+ }
52
+ isStale() {
53
+ return this.isDisconnected;
54
+ }
24
55
  onFrameSet(frameSet) {
56
+ this.lastActivityTime = Date.now();
25
57
  this.session.onFrameSet(frameSet);
26
58
  }
27
59
  getAddress() {
28
60
  return this.rinfo;
29
61
  }
30
62
  onMessage(data) {
63
+ this.lastActivityTime = Date.now();
31
64
  const id = data[0];
32
65
  switch (id) {
33
66
  case shared_1.Packets.ConnectionRequest: {
@@ -47,6 +80,7 @@ class Connection extends shared_1.EventEmitter {
47
80
  break;
48
81
  }
49
82
  case shared_1.Packets.Disconnect: {
83
+ this.isDisconnected = true;
50
84
  this.server.emit("disconnect", this);
51
85
  break;
52
86
  }
@@ -58,6 +92,10 @@ class Connection extends shared_1.EventEmitter {
58
92
  this.session.frameAndSend(pong.serialize(), shared_1.Priority.High);
59
93
  break;
60
94
  }
95
+ case shared_1.Packets.ConnectedPong: {
96
+ // Pong received, activity time already updated above
97
+ break;
98
+ }
61
99
  case 254: {
62
100
  this.emit("encapsulated", data);
63
101
  break;
@@ -15,7 +15,7 @@ class Server extends shared_1.EventEmitter {
15
15
  constructor(options = {}) {
16
16
  super();
17
17
  this.socket = (0, node_dgram_1.createSocket)("udp4");
18
- this.options = { ...types_1.defaultRaknetServerOptions, ...options };
18
+ this.options = { ...(0, types_1.createDefaultServerOptions)(), ...options };
19
19
  this.connections = new Map();
20
20
  this.advertisement = {
21
21
  gamemode: "Survival",
@@ -8,5 +8,5 @@ export type RaknetServerOptions = {
8
8
  mtu: number;
9
9
  enableServerLogs: boolean;
10
10
  };
11
- export declare const defaultRaknetServerOptions: RaknetServerOptions;
11
+ export declare const createDefaultServerOptions: () => RaknetServerOptions;
12
12
  //# sourceMappingURL=server-options.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server-options.d.ts","sourceRoot":"","sources":["../../../src/server/types/server-options.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,mBAAmB,GAAG;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,gBAAgB,EAAE,OAAO,CAAC;CAC1B,CAAC;AAEF,eAAO,MAAM,0BAA0B,EAAE,mBASxC,CAAC"}
1
+ {"version":3,"file":"server-options.d.ts","sourceRoot":"","sources":["../../../src/server/types/server-options.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,mBAAmB,GAAG;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,gBAAgB,EAAE,OAAO,CAAC;CAC1B,CAAC;AAEF,eAAO,MAAM,0BAA0B,QAAO,mBAS5C,CAAC"}
@@ -1,14 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.defaultRaknetServerOptions = void 0;
3
+ exports.createDefaultServerOptions = void 0;
4
4
  const client_1 = require("../../client");
5
- exports.defaultRaknetServerOptions = {
5
+ const createDefaultServerOptions = () => ({
6
6
  port: 19132,
7
7
  address: "0.0.0.0",
8
- guid: (0, client_1.getRandomGuid)(),
8
+ guid: (0, client_1.generateGuid)(),
9
9
  motd: "SanctumTerra",
10
10
  maxConnections: 100,
11
11
  tickRate: 20,
12
12
  mtu: 1492,
13
13
  enableServerLogs: true,
14
- };
14
+ });
15
+ exports.createDefaultServerOptions = createDefaultServerOptions;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanctumterra/raknet",
3
- "version": "1.4.7",
3
+ "version": "1.4.9",
4
4
  "description": "",
5
5
  "types": "dist/index.d.ts",
6
6
  "main": "dist/index.js",