@sanctumterra/raknet 1.4.5 → 1.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.
@@ -12,7 +12,17 @@ export declare class Client extends EventEmitter<ClientEvents> {
12
12
  tick: number;
13
13
  private session;
14
14
  private gotReply1;
15
+ private proxySocket;
16
+ private proxyRelayHost;
17
+ private proxyRelayPort;
18
+ private resolvedAddress;
19
+ private proxyReady;
15
20
  constructor(options?: Partial<ClientOptions>);
21
+ private setupProxy;
22
+ private buildUdpAssociateRequest;
23
+ private parseRelayAddress;
24
+ private createSocks5UdpHeader;
25
+ private parseSocks5UdpHeader;
16
26
  connect(): Promise<void>;
17
27
  onTick(): void;
18
28
  onMessage(data: Buffer, rinfo: RemoteInfo): 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;AAGxE,qBAAa,MAAO,SAAQ,YAAY,CAAC,YAAY,CAAC;IACrD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAA2B;IAC7D,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;gBAEd,OAAO,GAAE,OAAO,CAAC,aAAa,CAAM;IAmBzC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA6CxB,MAAM,IAAI,IAAI;IAYd,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI;IAyDhD,YAAY,CAAC,IAAI,EAAE,MAAM;IAwCzB,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,GAAE,QAA0B;IAI5D,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,QAA0B;IAI/D,IAAI,IAAI,IAAI;IAQZ,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAIxB,UAAU,IAAI,IAAI;CAIzB"}
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"}
@@ -5,8 +5,10 @@ const shared_1 = require("../shared");
5
5
  const client_options_1 = require("./types/client-options");
6
6
  const node_dgram_1 = require("node:dgram");
7
7
  const shared_2 = require("../shared");
8
+ const node_net_1 = require("node:net");
9
+ const promises_1 = require("node:dns/promises");
8
10
  class Client extends shared_1.EventEmitter {
9
- static MTU_VALUES = [1492, 1400, 1200, 576];
11
+ static MTU_VALUES = [1492, 1400, 1028, 1200, 576];
10
12
  static MTU_RETRY_INTERVAL = 500;
11
13
  options;
12
14
  socket;
@@ -15,6 +17,11 @@ class Client extends shared_1.EventEmitter {
15
17
  tick;
16
18
  session;
17
19
  gotReply1 = false;
20
+ proxySocket = null;
21
+ proxyRelayHost = null;
22
+ proxyRelayPort = null;
23
+ resolvedAddress = null;
24
+ proxyReady = false;
18
25
  constructor(options = {}) {
19
26
  super();
20
27
  this.options = { ...client_options_1.defaultClientOptions, ...options };
@@ -30,10 +37,172 @@ class Client extends shared_1.EventEmitter {
30
37
  this.handleOnline(data);
31
38
  };
32
39
  }
33
- connect() {
40
+ async setupProxy() {
41
+ if (!this.options.proxy)
42
+ return;
43
+ const proxy = this.options.proxy;
44
+ const isIPv4 = /^\d{1,3}(\.\d{1,3}){3}$/.test(this.options.address);
45
+ if (!isIPv4) {
46
+ const result = await (0, promises_1.lookup)(this.options.address, 4);
47
+ this.resolvedAddress = result.address;
48
+ }
49
+ else {
50
+ this.resolvedAddress = this.options.address;
51
+ }
52
+ return new Promise((resolve, reject) => {
53
+ const socket = (0, node_net_1.connect)(proxy.port, proxy.host, () => {
54
+ const authMethods = proxy.userId && proxy.password ? [0x00, 0x02] : [0x00];
55
+ socket.write(Buffer.from([0x05, authMethods.length, ...authMethods]));
56
+ });
57
+ let state = "greeting";
58
+ socket.on("data", (data) => {
59
+ if (state === "greeting") {
60
+ if (data[0] !== 0x05) {
61
+ reject(new Error("Invalid SOCKS5 response"));
62
+ socket.destroy();
63
+ return;
64
+ }
65
+ const method = data[1];
66
+ if (method === 0x02 && proxy.userId && proxy.password) {
67
+ const userBuf = Buffer.from(proxy.userId, "utf8");
68
+ const passBuf = Buffer.from(proxy.password, "utf8");
69
+ socket.write(Buffer.concat([
70
+ Buffer.from([0x01, userBuf.length]),
71
+ userBuf,
72
+ Buffer.from([passBuf.length]),
73
+ passBuf,
74
+ ]));
75
+ state = "auth";
76
+ }
77
+ else if (method === 0x00) {
78
+ socket.write(this.buildUdpAssociateRequest());
79
+ state = "request";
80
+ }
81
+ else {
82
+ reject(new Error("SOCKS5 auth method not supported"));
83
+ socket.destroy();
84
+ }
85
+ }
86
+ else if (state === "auth") {
87
+ if (data[1] !== 0x00) {
88
+ reject(new Error("SOCKS5 authentication failed"));
89
+ socket.destroy();
90
+ return;
91
+ }
92
+ socket.write(this.buildUdpAssociateRequest());
93
+ state = "request";
94
+ }
95
+ else if (state === "request") {
96
+ if (data[0] !== 0x05 || data[1] !== 0x00) {
97
+ reject(new Error(`SOCKS5 UDP ASSOCIATE failed: ${data[1]}`));
98
+ socket.destroy();
99
+ return;
100
+ }
101
+ const relay = this.parseRelayAddress(data);
102
+ if (!relay) {
103
+ reject(new Error("Failed to parse relay address"));
104
+ socket.destroy();
105
+ return;
106
+ }
107
+ this.proxySocket = socket;
108
+ this.proxyRelayHost =
109
+ relay.host === "0.0.0.0"
110
+ ? (this.resolvedAddress ?? proxy.host)
111
+ : relay.host;
112
+ this.proxyRelayPort = relay.port;
113
+ this.proxyReady = true;
114
+ state = "done";
115
+ resolve();
116
+ }
117
+ });
118
+ socket.on("close", () => {
119
+ if (state !== "done") {
120
+ reject(new Error("SOCKS5 connection closed unexpectedly"));
121
+ }
122
+ else {
123
+ this.proxySocket = null;
124
+ this.proxyRelayHost = null;
125
+ this.proxyRelayPort = null;
126
+ }
127
+ });
128
+ socket.on("error", (err) => {
129
+ reject(new Error(`SOCKS5 proxy error: ${err.message}`));
130
+ });
131
+ });
132
+ }
133
+ buildUdpAssociateRequest() {
134
+ return Buffer.from([0x05, 0x03, 0x00, 0x01, 0, 0, 0, 0, 0, 0]);
135
+ }
136
+ parseRelayAddress(data) {
137
+ const atyp = data[3];
138
+ if (atyp === 0x01) {
139
+ return {
140
+ host: `${data[4]}.${data[5]}.${data[6]}.${data[7]}`,
141
+ port: data.readUInt16BE(8),
142
+ };
143
+ }
144
+ if (atyp === 0x03) {
145
+ const len = data[4] ?? 0;
146
+ return {
147
+ host: data.subarray(5, 5 + len).toString("utf8"),
148
+ port: data.readUInt16BE(5 + len),
149
+ };
150
+ }
151
+ return null;
152
+ }
153
+ createSocks5UdpHeader(host, port) {
154
+ const isIPv4 = /^\d{1,3}(\.\d{1,3}){3}$/.test(host);
155
+ if (isIPv4) {
156
+ const header = Buffer.alloc(10);
157
+ header.writeUInt16BE(0, 0);
158
+ header.writeUInt8(0, 2);
159
+ header.writeUInt8(1, 3);
160
+ const parts = host.split(".").map(Number);
161
+ header.writeUInt8(parts[0] ?? 0, 4);
162
+ header.writeUInt8(parts[1] ?? 0, 5);
163
+ header.writeUInt8(parts[2] ?? 0, 6);
164
+ header.writeUInt8(parts[3] ?? 0, 7);
165
+ header.writeUInt16BE(port, 8);
166
+ return header;
167
+ }
168
+ const domainBuffer = Buffer.from(host, "utf8");
169
+ const header = Buffer.alloc(7 + domainBuffer.length);
170
+ header.writeUInt16BE(0, 0);
171
+ header.writeUInt8(0, 2);
172
+ header.writeUInt8(3, 3);
173
+ header.writeUInt8(domainBuffer.length, 4);
174
+ domainBuffer.copy(header, 5);
175
+ header.writeUInt16BE(port, 5 + domainBuffer.length);
176
+ return header;
177
+ }
178
+ parseSocks5UdpHeader(data) {
179
+ if (data.length < 10)
180
+ return null;
181
+ const atyp = data.readUInt8(3);
182
+ if (atyp === 1) {
183
+ return {
184
+ host: `${data.readUInt8(4)}.${data.readUInt8(5)}.${data.readUInt8(6)}.${data.readUInt8(7)}`,
185
+ port: data.readUInt16BE(8),
186
+ dataOffset: 10,
187
+ };
188
+ }
189
+ if (atyp === 3) {
190
+ const domainLen = data.readUInt8(4);
191
+ return {
192
+ host: data.subarray(5, 5 + domainLen).toString("utf8"),
193
+ port: data.readUInt16BE(5 + domainLen),
194
+ dataOffset: 7 + domainLen,
195
+ };
196
+ }
197
+ return null;
198
+ }
199
+ async connect() {
200
+ if (this.options.proxy) {
201
+ await this.setupProxy();
202
+ }
203
+ this.status = shared_1.ConnectionStatus.Connecting;
204
+ this.gotReply1 = false;
34
205
  return new Promise((resolve, reject) => {
35
- this.status = shared_1.ConnectionStatus.Connecting;
36
- this.gotReply1 = false;
37
206
  let mtuIndex = 0;
38
207
  let retryTimeout = null;
39
208
  const sendRequest = () => {
@@ -42,7 +211,6 @@ class Client extends shared_1.EventEmitter {
42
211
  return;
43
212
  }
44
213
  const mtu = Client.MTU_VALUES[mtuIndex];
45
- // Should not happen but for the linter sake
46
214
  if (!mtu)
47
215
  throw new Error("MTU value is undefined");
48
216
  const request = new shared_1.OpenConnectionRequestOne();
@@ -74,7 +242,7 @@ class Client extends shared_1.EventEmitter {
74
242
  const isDisconnected = this.status === shared_1.ConnectionStatus.Disconnected;
75
243
  const isDisconnecting = this.status === shared_1.ConnectionStatus.Disconnecting;
76
244
  const canPing = isDisconnected && this.tick % this.options.pingRate === 0;
77
- if (canPing)
245
+ if (canPing && (!this.options.proxy || this.proxyReady))
78
246
  this.ping();
79
247
  if (!isDisconnecting || !isDisconnected) {
80
248
  this.session.onTick(this.tick);
@@ -82,50 +250,57 @@ class Client extends shared_1.EventEmitter {
82
250
  this.tick++;
83
251
  }
84
252
  onMessage(data, rinfo) {
85
- let id = data[0];
253
+ let actualData = data;
254
+ if (this.proxyRelayHost && this.proxyRelayPort) {
255
+ const parsed = this.parseSocks5UdpHeader(data);
256
+ if (parsed) {
257
+ actualData = data.subarray(parsed.dataOffset);
258
+ }
259
+ }
260
+ let id = actualData[0];
86
261
  const isOnline = (id & 0xf0) === 0x80;
87
262
  if (isOnline)
88
263
  id = 0x80;
89
264
  switch (id) {
90
265
  case shared_1.Packets.UnconnectedPong: {
91
- const pong = new shared_1.UnconnectedPong(data).deserialize();
266
+ const pong = new shared_1.UnconnectedPong(actualData).deserialize();
92
267
  this.emit("unconnectedPong", pong);
93
268
  break;
94
269
  }
95
270
  case shared_1.Packets.OpenConnectionReply1: {
96
271
  this.gotReply1 = true;
97
- const reply = new shared_1.OpenConnectionReplyOne(data).deserialize();
272
+ const reply = new shared_1.OpenConnectionReplyOne(actualData).deserialize();
98
273
  const request = new shared_1.OpenConnectionRequestTwo();
99
274
  request.address = shared_1.Address.fromIdentifier(rinfo);
100
275
  request.mtu = reply.mtu;
101
276
  request.guid = this.options.guid;
102
277
  request.cookie = reply.cookie;
103
- // Set to false since we don't support libcat encryption
104
278
  request.clientSupportsecurity = false;
105
279
  this.send(request.serialize());
106
280
  break;
107
281
  }
108
282
  case shared_1.Packets.OpenConnectionReply2: {
109
- const reply = new shared_1.OpenConnectionReplyTwo(data).deserialize();
283
+ const reply2 = new shared_1.OpenConnectionReplyTwo(actualData).deserialize();
284
+ // Update session MTU with the negotiated value from server
285
+ this.session.mtu = reply2.mtu;
110
286
  const request = new shared_1.ConnectionRequest();
111
287
  request.guid = this.options.guid;
112
288
  request.timestamp = BigInt(Date.now());
113
- const serialized = request.serialize();
114
- this.frameAndSend(serialized, shared_1.Priority.High);
289
+ this.frameAndSend(request.serialize(), shared_1.Priority.High);
115
290
  break;
116
291
  }
117
292
  case shared_1.Packets.FrameSet: {
118
- const frameSet = new shared_1.FrameSet(data).deserialize();
293
+ const frameSet = new shared_1.FrameSet(actualData).deserialize();
119
294
  this.session.onFrameSet(frameSet);
120
295
  break;
121
296
  }
122
297
  case shared_1.Packets.Ack: {
123
- const ack = new shared_1.Ack(data).deserialize();
298
+ const ack = new shared_1.Ack(actualData).deserialize();
124
299
  this.session.onAck(ack);
125
300
  break;
126
301
  }
127
302
  case shared_1.Packets.Nack: {
128
- const nack = new shared_1.Ack(data).deserialize();
303
+ const nack = new shared_1.Ack(actualData).deserialize();
129
304
  this.session.onNack(nack);
130
305
  break;
131
306
  }
@@ -180,14 +355,25 @@ class Client extends shared_1.EventEmitter {
180
355
  const ping = new shared_1.UnconnectedPing();
181
356
  ping.guid = this.options.guid;
182
357
  ping.timestamp = BigInt(Date.now());
183
- const serialized = ping.serialize();
184
- this.send(serialized);
358
+ this.send(ping.serialize());
185
359
  }
186
360
  send(data) {
187
- this.socket.send(data, this.options.port, this.options.address);
361
+ if (this.proxyRelayHost && this.proxyRelayPort) {
362
+ const destAddr = this.resolvedAddress || this.options.address;
363
+ const header = this.createSocks5UdpHeader(destAddr, this.options.port);
364
+ const packet = Buffer.concat([header, data]);
365
+ this.socket.send(packet, this.proxyRelayPort, this.proxyRelayHost);
366
+ }
367
+ else {
368
+ this.socket.send(data, this.options.port, this.options.address);
369
+ }
188
370
  }
189
371
  disconnect() {
190
372
  this.socket.close();
373
+ if (this.proxySocket) {
374
+ this.proxySocket.destroy();
375
+ this.proxySocket = null;
376
+ }
191
377
  if (this.interval)
192
378
  clearInterval(this.interval);
193
379
  }
@@ -1,3 +1,9 @@
1
+ export type ProxyOptions = {
2
+ host: string;
3
+ port: number;
4
+ userId?: string;
5
+ password?: string;
6
+ };
1
7
  export type ClientOptions = {
2
8
  mtu: number;
3
9
  address: string;
@@ -6,6 +12,7 @@ export type ClientOptions = {
6
12
  tickRate: number;
7
13
  pingRate: number;
8
14
  timeout: number;
15
+ proxy?: ProxyOptions;
9
16
  };
10
17
  export declare const getRandomGuid: () => bigint;
11
18
  export declare const defaultClientOptions: ClientOptions;
@@ -1 +1 @@
1
- {"version":3,"file":"client-options.d.ts","sourceRoot":"","sources":["../../../src/client/types/client-options.ts"],"names":[],"mappings":"AAEA,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;CAChB,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":"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 +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,CAAC,IAAI,EAAE,MAAM;IAuBnB,KAAK,CAAC,GAAG,EAAE,GAAG;IAMd,MAAM,CAAC,IAAI,EAAE,GAAG;IAUT,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,QAA0B;IAO/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;IA6B7B,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,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,CAAC,IAAI,EAAE,MAAM;IAuBnB,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;IA6B7B,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"}
@@ -63,14 +63,20 @@ class NetworkSession {
63
63
  onNack(nack) {
64
64
  for (let i = 0, len = nack.sequences.length; i < len; i++) {
65
65
  const seq = nack.sequences[i];
66
- const lostFrames = this.outputBackup.get(seq) || [];
67
- for (let j = 0, lostLen = lostFrames.length; j < lostLen; j++) {
68
- this.sendFrame(lostFrames[j], proto_1.Priority.High);
69
- }
66
+ const lostFrames = this.outputBackup.get(seq);
67
+ if (!lostFrames || lostFrames.length === 0)
68
+ continue;
69
+ // Resend the exact same frameset with the same sequence number
70
+ const frameset = new proto_1.FrameSet();
71
+ frameset.sequence = seq;
72
+ frameset.frames = lostFrames;
73
+ const buffer = frameset.serialize();
74
+ this.send(buffer);
70
75
  }
71
76
  }
72
77
  frameAndSend(data, priority = proto_1.Priority.Medium) {
73
78
  const frame = new proto_1.Frame();
79
+ frame.reliability = proto_1.Reliability.ReliableOrdered;
74
80
  frame.orderChannel = 0;
75
81
  frame.payload = data;
76
82
  this.sendFrame(frame, priority);
package/package.json CHANGED
@@ -1,13 +1,10 @@
1
1
  {
2
2
  "name": "@sanctumterra/raknet",
3
- "version": "1.4.5",
3
+ "version": "1.4.7",
4
4
  "description": "",
5
-
6
5
  "types": "dist/index.d.ts",
7
6
  "main": "dist/index.js",
8
-
9
7
  "module": "commonjs",
10
-
11
8
  "scripts": {
12
9
  "build": "tsc",
13
10
  "watch": "tsc --watch",
@@ -16,18 +13,16 @@
16
13
  "lint:write": "npx @biomejs/biome lint --write ./src",
17
14
  "format:write": "npx @biomejs/biome format --write ./src"
18
15
  },
19
-
20
16
  "keywords": [],
21
17
  "author": "",
22
18
  "license": "ISC",
23
-
24
19
  "dependencies": {
25
20
  "@serenityjs/binarystream": "^3.0.10"
26
21
  },
27
22
  "devDependencies": {
28
- "@types/bun": "^1.2.21",
29
- "typescript": "^5.9.2",
30
23
  "@biomejs/biome": "^1.9.4",
31
- "@types/node": "^24.3.0"
24
+ "@types/bun": "^1.2.21",
25
+ "@types/node": "^24.3.0",
26
+ "typescript": "^5.9.2"
32
27
  }
33
28
  }