h1z1-server 0.25.2-1 → 0.25.2-2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "h1z1-server",
3
- "version": "0.25.2-1",
3
+ "version": "0.25.2-2",
4
4
  "description": "Library for emulating h1z1 servers",
5
5
  "author": "Quentin Gruber <quentingruber@gmail.com> (http://github.com/quentingruber)",
6
6
  "license": "GPL-3.0-only",
@@ -15,7 +15,7 @@
15
15
  "dependencies": {
16
16
  "@types/node": "18.13.0",
17
17
  "debug": "4.3.4",
18
- "h1emu-core": "1.1.1",
18
+ "h1emu-core": "1.1.2",
19
19
  "h1z1-dataschema": "1.7.0",
20
20
  "mongodb": "5.0.1",
21
21
  "threads": "1.7.0",
@@ -1,321 +1,321 @@
1
- // ======================================================================
2
- //
3
- // GNU GENERAL PUBLIC LICENSE
4
- // Version 3, 29 June 2007
5
- // copyright (C) 2020 - 2021 Quentin Gruber
6
- // copyright (C) 2021 - 2023 H1emu community
7
- //
8
- // https://github.com/QuentinGruber/h1z1-server
9
- // https://www.npmjs.com/package/h1z1-server
10
- //
11
- // Based on https://github.com/psemu/soe-network
12
- // ======================================================================
13
-
14
- const { LogicalPacket } = require("../servers/SoeServer/logicalPacket");
15
-
16
- const EventEmitter = require("node:events").EventEmitter,
17
- SOEInputStream =
18
- require("../servers/SoeServer/soeinputstream").SOEInputStream,
19
- SOEOutputStream =
20
- require("../servers/SoeServer/soeoutputstream").SOEOutputStream,
21
- { Soeprotocol, append_crc_legacy } = require("h1emu-core"),
22
- util = require("node:util"),
23
- fs = require("node:fs"),
24
- dgram = require("node:dgram"),
25
- debug = require("debug")("SOEClient");
26
-
27
- function createSessionId() {
28
- return (Math.random() * 0xffffffff) >>> 0;
29
- }
30
-
31
- class SOEClient {
32
- constructor(protocolName, serverAddress, serverPort, cryptoKey, localPort) {
33
- EventEmitter.call(this);
34
- const me = this;
35
-
36
- this._guid = ((Math.random() * 0xffffffff) >>> 0).toString(16);
37
- debug(this._guid, "Creating new SOEClient instance");
38
- this._protocolName = protocolName;
39
- this._serverAddress = serverAddress;
40
- this._serverPort = serverPort;
41
- this._localPort = localPort;
42
- this._cryptoKey = cryptoKey;
43
- this._useEncryption = true;
44
- this._dumpData = false;
45
-
46
- this._outQueue = [];
47
-
48
- const connection = (this._connection = dgram.createSocket("udp4"));
49
- const protocol = (this._protocol = new Soeprotocol(true, 0));
50
- const inputStream = (this._inputStream = new SOEInputStream(cryptoKey));
51
- const outputStream = (this._outputStream = new SOEOutputStream(cryptoKey));
52
-
53
- let n1 = 0,
54
- n2 = 0;
55
-
56
- inputStream.on("appdata", function (data) {
57
- if (me._dumpData) {
58
- fs.writeFileSync("soeclient_apppacket_" + n2++ + ".dat", data);
59
- }
60
- me.emit("appdata", null, data);
61
- });
62
-
63
- inputStream.on("ack", function (sequence) {
64
- nextAck = sequence;
65
- });
66
-
67
- inputStream.on("outoforder", function (sequence) {
68
- outOfOrderPackets.push(sequence);
69
- });
70
-
71
- outputStream.on("data", function (data, sequence, fragment) {
72
- if (fragment) {
73
- me._sendPacket("DataFragment", {
74
- sequence: sequence,
75
- data: data,
76
- });
77
- } else {
78
- me._sendPacket("Data", {
79
- sequence: sequence,
80
- data: data,
81
- });
82
- }
83
- });
84
-
85
- var lastAck = -1,
86
- nextAck = -1,
87
- outOfOrderPackets = [];
88
-
89
- function checkAck() {
90
- if (lastAck !== nextAck) {
91
- lastAck = nextAck;
92
- me._sendPacket("Ack", {
93
- channel: 0,
94
- sequence: nextAck,
95
- });
96
- }
97
- me._ackTimer = setTimeout(checkAck, 50);
98
- }
99
-
100
- checkAck();
101
-
102
- function checkOutOfOrderQueue() {
103
- if (outOfOrderPackets.length) {
104
- return;
105
- const packets = [];
106
- for (let i = 0; i < 20; i++) {
107
- const sequence = outOfOrderPackets.shift();
108
- packets.push({
109
- name: "OutOfOrder",
110
- soePacket: {
111
- channel: 0,
112
- sequence: sequence,
113
- },
114
- });
115
- if (!outOfOrderPackets.length) {
116
- break;
117
- }
118
- }
119
- debug("Sending " + packets.length + " OutOfOrder packets");
120
- me._sendPacket(
121
- "MultiPacket",
122
- {
123
- subPackets: packets,
124
- },
125
- true
126
- );
127
- }
128
- me._outOfOrderTimer = setTimeout(checkOutOfOrderQueue, 10);
129
- }
130
-
131
- checkOutOfOrderQueue();
132
-
133
- function checkOutQueue() {
134
- if (me._outQueue.length) {
135
- const logical = new LogicalPacket(me._outQueue.shift());
136
- const data = logical.canCrc
137
- ? append_crc_legacy(logical.data, this._crcSeed)
138
- : logical.data;
139
- if (me._dumpData) {
140
- fs.writeFileSync("debug/soeclient_" + n1++ + "_out.dat", data);
141
- }
142
- me._connection.send(
143
- data,
144
- 0,
145
- data.length,
146
- me._serverPort,
147
- me._serverAddress,
148
- function (err, bytes) {}
149
- );
150
- }
151
- me._outQueueTimer = setTimeout(checkOutQueue, 0);
152
- }
153
-
154
- checkOutQueue();
155
-
156
- function handlePacket(packet) {
157
- switch (packet.name) {
158
- case "SessionReply":
159
- debug("Received session reply from server");
160
- me._compression = 0;
161
- me._crcSeed = packet.crc_seed;
162
- me._crcLength = packet.crc_length;
163
- me._udpLength = packet.udp_length;
164
- inputStream.toggleEncryption(me._useEncryption);
165
- outputStream.toggleEncryption(me._useEncryption);
166
- outputStream.setFragmentSize(packet.udp_length - 7);
167
- me.emit("connect", null, packet);
168
- break;
169
- case "Disconnect":
170
- debug("Received disconnect from server");
171
- me.disconnect();
172
- me.emit("disconnect");
173
- break;
174
- case "MultiPacket":
175
- let lastOutOfOrder = 0;
176
- const channel = 0;
177
- for (let i = 0; i < packet.sub_packets.length; i++) {
178
- const subPacket = packet.sub_packets[i];
179
- switch (subPacket.name) {
180
- case "OutOfOrder":
181
- if (subPacket.sequence > lastOutOfOrder) {
182
- lastOutOfOrder = subPacket.sequence;
183
- }
184
- break;
185
- default:
186
- handlePacket({
187
- soePacket: subPacket,
188
- });
189
- }
190
- }
191
- if (lastOutOfOrder > 0) {
192
- debug(
193
- "Received multiple out-order-packet packet on channel " +
194
- channel +
195
- ", sequence " +
196
- lastOutOfOrder
197
- );
198
- outputStream.resendData(lastOutOfOrder);
199
- }
200
- break;
201
- case "Ping":
202
- debug("Received ping from server");
203
- break;
204
- case "NetStatusReply":
205
- debug("Received net status reply from server");
206
- break;
207
- case "Data":
208
- debug("Received data packet from server");
209
- inputStream.write(Buffer.from(packet.data), packet.sequence, false);
210
- break;
211
- case "DataFragment":
212
- debug("Received data fragment from server");
213
- inputStream.write(Buffer.from(packet.data), packet.sequence, true);
214
- break;
215
- case "OutOfOrder":
216
- debug(
217
- "Received out-order-packet packet on channel " +
218
- packet.channel +
219
- ", sequence " +
220
- packet.sequence
221
- );
222
- //outputStream.resendData(result.sequence);
223
- break;
224
- case "Ack":
225
- outputStream.ack(packet.sequence, new Map());
226
- break;
227
- case "FatalError":
228
- debug("Received fatal error from server");
229
- break;
230
- case "FatalErrorReply":
231
- break;
232
- }
233
- }
234
-
235
- connection.on("message", function (data, remote) {
236
- if (me._dumpData) {
237
- fs.writeFileSync("debug/soeclient_" + n1++ + "_in.dat", data);
238
- }
239
- const result = JSON.parse(protocol.parse(data));
240
- handlePacket(result);
241
- });
242
-
243
- connection.on("listening", function () {
244
- const address = this.address();
245
- debug("Listening on " + address.address + ":" + address.port);
246
- });
247
- }
248
-
249
- connect() {
250
- debug(
251
- "Setting up connection for " +
252
- this._serverAddress +
253
- ":" +
254
- this._serverPort
255
- );
256
- this._sessionId = createSessionId();
257
- const me = this;
258
- this._connection.bind(this._localPort, function () {
259
- me._sendPacket("SessionRequest", {
260
- protocol: me._protocolName,
261
- crc_length: 3,
262
- session_id: me._sessionId,
263
- udp_length: 512,
264
- });
265
- });
266
- }
267
-
268
- disconnect() {
269
- clearTimeout(this._outQueueTimer);
270
- clearTimeout(this._ackTimer);
271
- clearTimeout(this._outOfOrderTimer);
272
- try {
273
- this._sendPacket("Disconnect", {});
274
- this._connection.close();
275
- } catch (e) {}
276
- }
277
-
278
- toggleEncryption(value) {
279
- value = !!value;
280
- this._useEncryption = value;
281
- debug(this._guid, "Toggling encryption: value = " + value);
282
- this._outputStream.toggleEncryption(value);
283
- this._inputStream.toggleEncryption(value);
284
- }
285
-
286
- toggleDataDump(value) {
287
- this._dumpData = value;
288
- }
289
-
290
- _sendPacket(packetName, packet, prioritize) {
291
- if (packet.data) {
292
- packet.data = [...packet.data];
293
- }
294
- const data = Buffer.from(
295
- this._protocol.pack(packetName, JSON.stringify(packet))
296
- );
297
- debug(this._guid, "Sending " + packetName + " packet to server");
298
- if (this._dumpData) {
299
- fs.writeFileSync(
300
- "debug/soeclient_" + this._guid + "_outpacket_" + q++ + ".dat",
301
- data
302
- );
303
- }
304
- if (prioritize) {
305
- this._outQueue.unshift(data);
306
- } else {
307
- this._outQueue.push(data);
308
- }
309
- }
310
-
311
- sendAppData(data, overrideEncryption) {
312
- debug(this._guid, "Sending app data: " + data.length + " bytes");
313
- this._outputStream.write(data, overrideEncryption);
314
- }
315
- }
316
-
317
- util.inherits(SOEClient, EventEmitter);
318
-
319
- var q = 0;
320
-
321
- exports.SOEClient = SOEClient;
1
+ // ======================================================================
2
+ //
3
+ // GNU GENERAL PUBLIC LICENSE
4
+ // Version 3, 29 June 2007
5
+ // copyright (C) 2020 - 2021 Quentin Gruber
6
+ // copyright (C) 2021 - 2023 H1emu community
7
+ //
8
+ // https://github.com/QuentinGruber/h1z1-server
9
+ // https://www.npmjs.com/package/h1z1-server
10
+ //
11
+ // Based on https://github.com/psemu/soe-network
12
+ // ======================================================================
13
+
14
+ const { LogicalPacket } = require("../servers/SoeServer/logicalPacket");
15
+
16
+ const EventEmitter = require("node:events").EventEmitter,
17
+ SOEInputStream =
18
+ require("../servers/SoeServer/soeinputstream").SOEInputStream,
19
+ SOEOutputStream =
20
+ require("../servers/SoeServer/soeoutputstream").SOEOutputStream,
21
+ { Soeprotocol, append_crc_legacy } = require("h1emu-core"),
22
+ util = require("node:util"),
23
+ fs = require("node:fs"),
24
+ dgram = require("node:dgram"),
25
+ debug = require("debug")("SOEClient");
26
+
27
+ function createSessionId() {
28
+ return (Math.random() * 0xffffffff) >>> 0;
29
+ }
30
+
31
+ class SOEClient {
32
+ constructor(protocolName, serverAddress, serverPort, cryptoKey, localPort) {
33
+ EventEmitter.call(this);
34
+ const me = this;
35
+
36
+ this._guid = ((Math.random() * 0xffffffff) >>> 0).toString(16);
37
+ debug(this._guid, "Creating new SOEClient instance");
38
+ this._protocolName = protocolName;
39
+ this._serverAddress = serverAddress;
40
+ this._serverPort = serverPort;
41
+ this._localPort = localPort;
42
+ this._cryptoKey = cryptoKey;
43
+ this._useEncryption = true;
44
+ this._dumpData = false;
45
+
46
+ this._outQueue = [];
47
+
48
+ const connection = (this._connection = dgram.createSocket("udp4"));
49
+ const protocol = (this._protocol = new Soeprotocol(true, 0));
50
+ const inputStream = (this._inputStream = new SOEInputStream(cryptoKey));
51
+ const outputStream = (this._outputStream = new SOEOutputStream(cryptoKey));
52
+
53
+ let n1 = 0,
54
+ n2 = 0;
55
+
56
+ inputStream.on("appdata", function (data) {
57
+ if (me._dumpData) {
58
+ fs.writeFileSync("soeclient_apppacket_" + n2++ + ".dat", data);
59
+ }
60
+ me.emit("appdata", null, data);
61
+ });
62
+
63
+ inputStream.on("ack", function (sequence) {
64
+ nextAck = sequence;
65
+ });
66
+
67
+ inputStream.on("outoforder", function (sequence) {
68
+ outOfOrderPackets.push(sequence);
69
+ });
70
+
71
+ outputStream.on("data", function (data, sequence, fragment) {
72
+ if (fragment) {
73
+ me._sendPacket("DataFragment", {
74
+ sequence: sequence,
75
+ data: data,
76
+ });
77
+ } else {
78
+ me._sendPacket("Data", {
79
+ sequence: sequence,
80
+ data: data,
81
+ });
82
+ }
83
+ });
84
+
85
+ var lastAck = -1,
86
+ nextAck = -1,
87
+ outOfOrderPackets = [];
88
+
89
+ function checkAck() {
90
+ if (lastAck !== nextAck) {
91
+ lastAck = nextAck;
92
+ me._sendPacket("Ack", {
93
+ channel: 0,
94
+ sequence: nextAck,
95
+ });
96
+ }
97
+ me._ackTimer = setTimeout(checkAck, 50);
98
+ }
99
+
100
+ checkAck();
101
+
102
+ function checkOutOfOrderQueue() {
103
+ if (outOfOrderPackets.length) {
104
+ return;
105
+ const packets = [];
106
+ for (let i = 0; i < 20; i++) {
107
+ const sequence = outOfOrderPackets.shift();
108
+ packets.push({
109
+ name: "OutOfOrder",
110
+ soePacket: {
111
+ channel: 0,
112
+ sequence: sequence,
113
+ },
114
+ });
115
+ if (!outOfOrderPackets.length) {
116
+ break;
117
+ }
118
+ }
119
+ debug("Sending " + packets.length + " OutOfOrder packets");
120
+ me._sendPacket(
121
+ "MultiPacket",
122
+ {
123
+ subPackets: packets,
124
+ },
125
+ true
126
+ );
127
+ }
128
+ me._outOfOrderTimer = setTimeout(checkOutOfOrderQueue, 10);
129
+ }
130
+
131
+ checkOutOfOrderQueue();
132
+
133
+ function checkOutQueue() {
134
+ if (me._outQueue.length) {
135
+ const logical = new LogicalPacket(me._outQueue.shift());
136
+ const data = logical.canCrc
137
+ ? append_crc_legacy(logical.data, this._crcSeed)
138
+ : logical.data;
139
+ if (me._dumpData) {
140
+ fs.writeFileSync("debug/soeclient_" + n1++ + "_out.dat", data);
141
+ }
142
+ me._connection.send(
143
+ data,
144
+ 0,
145
+ data.length,
146
+ me._serverPort,
147
+ me._serverAddress,
148
+ function (err, bytes) {}
149
+ );
150
+ }
151
+ me._outQueueTimer = setTimeout(checkOutQueue, 0);
152
+ }
153
+
154
+ checkOutQueue();
155
+
156
+ function handlePacket(packet) {
157
+ switch (packet.name) {
158
+ case "SessionReply":
159
+ debug("Received session reply from server");
160
+ me._compression = 0;
161
+ me._crcSeed = packet.crc_seed;
162
+ me._crcLength = packet.crc_length;
163
+ me._udpLength = packet.udp_length;
164
+ inputStream.toggleEncryption(me._useEncryption);
165
+ outputStream.toggleEncryption(me._useEncryption);
166
+ outputStream.setFragmentSize(packet.udp_length - 7);
167
+ me.emit("connect", null, packet);
168
+ break;
169
+ case "Disconnect":
170
+ debug("Received disconnect from server");
171
+ me.disconnect();
172
+ me.emit("disconnect");
173
+ break;
174
+ case "MultiPacket":
175
+ let lastOutOfOrder = 0;
176
+ const channel = 0;
177
+ for (let i = 0; i < packet.sub_packets.length; i++) {
178
+ const subPacket = packet.sub_packets[i];
179
+ switch (subPacket.name) {
180
+ case "OutOfOrder":
181
+ if (subPacket.sequence > lastOutOfOrder) {
182
+ lastOutOfOrder = subPacket.sequence;
183
+ }
184
+ break;
185
+ default:
186
+ handlePacket({
187
+ soePacket: subPacket,
188
+ });
189
+ }
190
+ }
191
+ if (lastOutOfOrder > 0) {
192
+ debug(
193
+ "Received multiple out-order-packet packet on channel " +
194
+ channel +
195
+ ", sequence " +
196
+ lastOutOfOrder
197
+ );
198
+ outputStream.resendData(lastOutOfOrder);
199
+ }
200
+ break;
201
+ case "Ping":
202
+ debug("Received ping from server");
203
+ break;
204
+ case "NetStatusReply":
205
+ debug("Received net status reply from server");
206
+ break;
207
+ case "Data":
208
+ debug("Received data packet from server");
209
+ inputStream.write(Buffer.from(packet.data), packet.sequence, false);
210
+ break;
211
+ case "DataFragment":
212
+ debug("Received data fragment from server");
213
+ inputStream.write(Buffer.from(packet.data), packet.sequence, true);
214
+ break;
215
+ case "OutOfOrder":
216
+ debug(
217
+ "Received out-order-packet packet on channel " +
218
+ packet.channel +
219
+ ", sequence " +
220
+ packet.sequence
221
+ );
222
+ //outputStream.resendData(result.sequence);
223
+ break;
224
+ case "Ack":
225
+ outputStream.ack(packet.sequence, new Map());
226
+ break;
227
+ case "FatalError":
228
+ debug("Received fatal error from server");
229
+ break;
230
+ case "FatalErrorReply":
231
+ break;
232
+ }
233
+ }
234
+
235
+ connection.on("message", function (data, remote) {
236
+ if (me._dumpData) {
237
+ fs.writeFileSync("debug/soeclient_" + n1++ + "_in.dat", data);
238
+ }
239
+ const result = JSON.parse(protocol.parse(data));
240
+ handlePacket(result);
241
+ });
242
+
243
+ connection.on("listening", function () {
244
+ const address = this.address();
245
+ debug("Listening on " + address.address + ":" + address.port);
246
+ });
247
+ }
248
+
249
+ connect() {
250
+ debug(
251
+ "Setting up connection for " +
252
+ this._serverAddress +
253
+ ":" +
254
+ this._serverPort
255
+ );
256
+ this._sessionId = createSessionId();
257
+ const me = this;
258
+ this._connection.bind(this._localPort, function () {
259
+ me._sendPacket("SessionRequest", {
260
+ protocol: me._protocolName,
261
+ crc_length: 3,
262
+ session_id: me._sessionId,
263
+ udp_length: 512,
264
+ });
265
+ });
266
+ }
267
+
268
+ disconnect() {
269
+ clearTimeout(this._outQueueTimer);
270
+ clearTimeout(this._ackTimer);
271
+ clearTimeout(this._outOfOrderTimer);
272
+ try {
273
+ this._sendPacket("Disconnect", {});
274
+ this._connection.close();
275
+ } catch (e) {}
276
+ }
277
+
278
+ toggleEncryption(value) {
279
+ value = !!value;
280
+ this._useEncryption = value;
281
+ debug(this._guid, "Toggling encryption: value = " + value);
282
+ this._outputStream.toggleEncryption(value);
283
+ this._inputStream.toggleEncryption(value);
284
+ }
285
+
286
+ toggleDataDump(value) {
287
+ this._dumpData = value;
288
+ }
289
+
290
+ _sendPacket(packetName, packet, prioritize) {
291
+ if (packet.data) {
292
+ packet.data = [...packet.data];
293
+ }
294
+ const data = Buffer.from(
295
+ this._protocol.pack(packetName, JSON.stringify(packet))
296
+ );
297
+ debug(this._guid, "Sending " + packetName + " packet to server");
298
+ if (this._dumpData) {
299
+ fs.writeFileSync(
300
+ "debug/soeclient_" + this._guid + "_outpacket_" + q++ + ".dat",
301
+ data
302
+ );
303
+ }
304
+ if (prioritize) {
305
+ this._outQueue.unshift(data);
306
+ } else {
307
+ this._outQueue.push(data);
308
+ }
309
+ }
310
+
311
+ sendAppData(data, overrideEncryption) {
312
+ debug(this._guid, "Sending app data: " + data.length + " bytes");
313
+ this._outputStream.write(data, overrideEncryption);
314
+ }
315
+ }
316
+
317
+ util.inherits(SOEClient, EventEmitter);
318
+
319
+ var q = 0;
320
+
321
+ exports.SOEClient = SOEClient;