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 +2 -2
- package/src/clients/soeclient.js +321 -321
- package/src/servers/GatewayServer/gatewayserver.ts +130 -130
- package/src/servers/LoginServer/loginserver.ts +1092 -1092
- package/src/servers/SoeServer/logicalPacket.ts +49 -49
- package/src/servers/SoeServer/soeserver.ts +607 -607
- package/src/servers/ZoneServer2016/classes/baseItem.ts +54 -54
- package/src/servers/ZoneServer2016/classes/zoneclient.ts +146 -146
- package/src/servers/ZoneServer2016/data/Recipes.ts +2538 -2538
- package/src/servers/ZoneServer2016/data/lootspawns.ts +2741 -2741
- package/src/servers/ZoneServer2016/managers/decaymanager.ts +230 -230
- package/src/servers/ZoneServer2016/managers/worlddatamanager.ts +1267 -1267
- package/src/servers/ZoneServer2016/managers/worldobjectmanager.ts +575 -575
- package/src/servers/ZoneServer2016/zonepackethandlers.ts +2430 -2430
- package/src/servers/ZoneServer2016/zoneserver.ts +8090 -8090
- package/src/utils/utils.ts +827 -827
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "h1z1-server",
|
|
3
|
-
"version": "0.25.2-
|
|
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.
|
|
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",
|
package/src/clients/soeclient.js
CHANGED
|
@@ -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;
|