h1z1-server 0.14.2-5 → 0.14.2-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.
- package/package.json +5 -3
- package/scripts/demo/ZoneServer2015.js +9 -0
- package/scripts/demo/ZoneServer2016.js +7 -0
- package/scripts/demo/loginserver2015.js +4 -0
- package/scripts/demo/loginserver2016.js +8 -0
- package/scripts/h1z1-server-demo-2016.js +4 -0
- package/scripts/h1z1-server-demo.js +4 -0
- package/src/clients/gatewayclient.js +105 -105
- package/src/clients/loginclient.ts +227 -227
- package/src/clients/zoneclient.ts +166 -166
- package/src/packets/ClientProtocol/ClientProtocol_860/h1z1packets.ts +12 -11
- package/src/packets/LoginUdp/LoginUdp_11/loginTunnelPackets.ts +43 -43
- package/src/packets/LoginUdp/LoginUdp_11/loginpackets.ts +471 -471
- package/src/packets/LoginUdp/LoginUdp_9/loginTunnelPackets.ts +43 -43
- package/src/packets/LoginUdp/LoginUdp_9/loginpackets.ts +429 -429
- package/src/packets/gatewaypackets.ts +73 -73
- package/src/packets/packettable.ts +37 -37
- package/src/protocols/gatewayprotocol.ts +118 -118
- package/src/protocols/h1z1protocol.ts +10 -10
- package/src/servers/GatewayServer/gatewayserver.ts +133 -133
- package/src/servers/LoginServer/loginserver.ts +549 -549
- package/src/servers/SoeServer/soeclient.ts +48 -48
- package/src/servers/SoeServer/soeinputstream.ts +226 -226
- package/src/servers/SoeServer/soeoutputstream.ts +111 -111
- package/src/servers/SoeServer/soeserver.ts +436 -436
- package/src/servers/SoeServer/workers/udpServerWorker.ts +54 -54
- package/src/servers/ZoneServer/character.ts +66 -66
- package/src/servers/ZoneServer/commands/admin.ts +8 -11
- package/src/servers/ZoneServer/commands/dev.ts +5 -8
- package/src/servers/ZoneServer/commands/hax.ts +82 -23
- package/src/servers/ZoneServer/workers/createBaseEntities.ts +1047 -1046
- package/src/servers/ZoneServer/workers/dynamicWeather.ts +400 -400
- package/src/servers/ZoneServer/zonepackethandlers.ts +13 -13
- package/src/servers/ZoneServer/zoneserver.ts +1 -1
- package/src/servers/ZoneServer2016/commands/admin.ts +21 -0
- package/src/servers/ZoneServer2016/commands/dev.ts +14 -8
- package/src/servers/ZoneServer2016/commands/hax.ts +18 -12
- package/src/servers/ZoneServer2016/workers/createBaseEntities.ts +956 -956
- package/src/servers/ZoneServer2016/workers/saveWorld.ts +27 -27
- package/src/servers/ZoneServer2016/zonepackethandlers.ts +11 -12
- package/src/types/gatewayserver.ts +21 -21
- package/src/types/loginserver.ts +62 -62
- package/src/types/packets.ts +2470 -2470
- package/src/types/shared.ts +6 -6
- package/src/types/soeserver.ts +22 -22
package/package.json
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "h1z1-server",
|
|
3
|
-
"version": "0.14.2-
|
|
3
|
+
"version": "0.14.2-9",
|
|
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",
|
|
7
7
|
"main": "h1z1-server.js",
|
|
8
8
|
"bin": {
|
|
9
|
-
"if-env": "scripts/if-env.js"
|
|
9
|
+
"if-env": "scripts/if-env.js",
|
|
10
|
+
"h1z1-server-demo": "scripts/h1z1-server-demo.js",
|
|
11
|
+
"h1z1-server-demo-2016": "scripts/h1z1-server-demo-2016.js"
|
|
10
12
|
},
|
|
11
13
|
"dependencies": {
|
|
12
14
|
"@swc/cli": "0.1.40",
|
|
@@ -29,7 +31,7 @@
|
|
|
29
31
|
},
|
|
30
32
|
"devDependencies": {
|
|
31
33
|
"chokidar": "3.5.2",
|
|
32
|
-
"prettier": "2.4.
|
|
34
|
+
"prettier": "2.4.1",
|
|
33
35
|
"ts-node": "10.2.1"
|
|
34
36
|
},
|
|
35
37
|
"scripts": {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
process.env.DEBUG = "*";
|
|
2
|
+
const H1Z1servers = require("../../h1z1-server");
|
|
3
|
+
var server = new H1Z1servers.LoginServer(
|
|
4
|
+
1115, // <- server port
|
|
5
|
+
"" // <- MongoDB address ( if blank server start in solo mode )
|
|
6
|
+
);
|
|
7
|
+
server._protocol = new H1Z1servers.LoginProtocol("LoginUdp_11");
|
|
8
|
+
server.start();
|
|
@@ -1,105 +1,105 @@
|
|
|
1
|
-
// ======================================================================
|
|
2
|
-
//
|
|
3
|
-
// GNU GENERAL PUBLIC LICENSE
|
|
4
|
-
// Version 3, 29 June 2007
|
|
5
|
-
// copyright (c) 2020 - 2021 Quentin Gruber
|
|
6
|
-
// copyright (c) 2021 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
|
-
var EventEmitter = require("events").EventEmitter,
|
|
15
|
-
SOEClient = require("./soeclient").SOEClient,
|
|
16
|
-
fs = require("fs"),
|
|
17
|
-
util = require("util"),
|
|
18
|
-
GatewayProtocol = require("../protocols/gatewayprotocol").GatewayProtocol,
|
|
19
|
-
GatewayPackets = require("../protocols/gatewayprotocol").GatewayPackets,
|
|
20
|
-
debug = require("debug")("GatewayClient");
|
|
21
|
-
|
|
22
|
-
function GatewayClientError(message) {
|
|
23
|
-
this.name = this.constructor.name;
|
|
24
|
-
this.message = message;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
util.inherits(GatewayClientError, Error);
|
|
28
|
-
|
|
29
|
-
class GatewayClient {
|
|
30
|
-
constructor(serverAddress, serverPort, key, localPort) {
|
|
31
|
-
EventEmitter.call(this);
|
|
32
|
-
|
|
33
|
-
var soeClient = (this._soeClient = new SOEClient(
|
|
34
|
-
"ExternalGatewayApi_3",
|
|
35
|
-
serverAddress,
|
|
36
|
-
serverPort,
|
|
37
|
-
key,
|
|
38
|
-
localPort
|
|
39
|
-
));
|
|
40
|
-
var protocol = (this._protocol = new GatewayProtocol());
|
|
41
|
-
var me = this;
|
|
42
|
-
|
|
43
|
-
soeClient.on("appdata", function (err, data) {
|
|
44
|
-
var packet = protocol.parse(data);
|
|
45
|
-
var result = packet.result;
|
|
46
|
-
|
|
47
|
-
switch (packet.name) {
|
|
48
|
-
case "LoginReply":
|
|
49
|
-
if (result.loggedIn) {
|
|
50
|
-
me.emit("login", null, result);
|
|
51
|
-
} else {
|
|
52
|
-
me.emit("login", new GatewayClientError("Login failed"));
|
|
53
|
-
}
|
|
54
|
-
break;
|
|
55
|
-
case "TunnelPacketToExternalConnection":
|
|
56
|
-
me.emit("tunneldata", null, packet.tunnelData, packet.flags);
|
|
57
|
-
break;
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
soeClient.on("connect", function (err, result) {
|
|
62
|
-
debug("Connected to login server");
|
|
63
|
-
soeClient.toggleEncryption(false);
|
|
64
|
-
me.emit("connect", err, result);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
soeClient.on("disconnect", function (err, result) {
|
|
68
|
-
debug("Disconnected");
|
|
69
|
-
me.emit("disconnect", err, result);
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
connect(callback) {
|
|
73
|
-
debug("Connecting to gateway server");
|
|
74
|
-
this._soeClient.connect();
|
|
75
|
-
}
|
|
76
|
-
sendTunnelData(tunnelData, channel) {
|
|
77
|
-
channel = channel || 0;
|
|
78
|
-
debug("Sending tunnel data to gateway server");
|
|
79
|
-
var data = this._protocol.pack("TunnelPacketFromExternalConnection", {
|
|
80
|
-
channel: channel,
|
|
81
|
-
tunnelData: tunnelData,
|
|
82
|
-
});
|
|
83
|
-
//fs.writeFileSync("dump/out_tunneldata_" + (tunnelCount++) + ".dat", data);
|
|
84
|
-
this._soeClient.sendAppData(data, true);
|
|
85
|
-
}
|
|
86
|
-
login(characterId, ticket, clientProtocol, clientBuild) {
|
|
87
|
-
debug("Sending login request");
|
|
88
|
-
var data = this._protocol.pack("LoginRequest", {
|
|
89
|
-
characterId: characterId,
|
|
90
|
-
ticket: ticket,
|
|
91
|
-
clientProtocol: clientProtocol,
|
|
92
|
-
clientBuild: clientBuild,
|
|
93
|
-
});
|
|
94
|
-
//fs.writeFileSync("loginrequest.dat", data);
|
|
95
|
-
this._soeClient.sendAppData(data, false);
|
|
96
|
-
this._soeClient.toggleEncryption(true);
|
|
97
|
-
}
|
|
98
|
-
disconnect() {}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
util.inherits(GatewayClient, EventEmitter);
|
|
102
|
-
|
|
103
|
-
var tunnelCount = 0;
|
|
104
|
-
|
|
105
|
-
exports.GatewayClient = GatewayClient;
|
|
1
|
+
// ======================================================================
|
|
2
|
+
//
|
|
3
|
+
// GNU GENERAL PUBLIC LICENSE
|
|
4
|
+
// Version 3, 29 June 2007
|
|
5
|
+
// copyright (c) 2020 - 2021 Quentin Gruber
|
|
6
|
+
// copyright (c) 2021 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
|
+
var EventEmitter = require("events").EventEmitter,
|
|
15
|
+
SOEClient = require("./soeclient").SOEClient,
|
|
16
|
+
fs = require("fs"),
|
|
17
|
+
util = require("util"),
|
|
18
|
+
GatewayProtocol = require("../protocols/gatewayprotocol").GatewayProtocol,
|
|
19
|
+
GatewayPackets = require("../protocols/gatewayprotocol").GatewayPackets,
|
|
20
|
+
debug = require("debug")("GatewayClient");
|
|
21
|
+
|
|
22
|
+
function GatewayClientError(message) {
|
|
23
|
+
this.name = this.constructor.name;
|
|
24
|
+
this.message = message;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
util.inherits(GatewayClientError, Error);
|
|
28
|
+
|
|
29
|
+
class GatewayClient {
|
|
30
|
+
constructor(serverAddress, serverPort, key, localPort) {
|
|
31
|
+
EventEmitter.call(this);
|
|
32
|
+
|
|
33
|
+
var soeClient = (this._soeClient = new SOEClient(
|
|
34
|
+
"ExternalGatewayApi_3",
|
|
35
|
+
serverAddress,
|
|
36
|
+
serverPort,
|
|
37
|
+
key,
|
|
38
|
+
localPort
|
|
39
|
+
));
|
|
40
|
+
var protocol = (this._protocol = new GatewayProtocol());
|
|
41
|
+
var me = this;
|
|
42
|
+
|
|
43
|
+
soeClient.on("appdata", function (err, data) {
|
|
44
|
+
var packet = protocol.parse(data);
|
|
45
|
+
var result = packet.result;
|
|
46
|
+
|
|
47
|
+
switch (packet.name) {
|
|
48
|
+
case "LoginReply":
|
|
49
|
+
if (result.loggedIn) {
|
|
50
|
+
me.emit("login", null, result);
|
|
51
|
+
} else {
|
|
52
|
+
me.emit("login", new GatewayClientError("Login failed"));
|
|
53
|
+
}
|
|
54
|
+
break;
|
|
55
|
+
case "TunnelPacketToExternalConnection":
|
|
56
|
+
me.emit("tunneldata", null, packet.tunnelData, packet.flags);
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
soeClient.on("connect", function (err, result) {
|
|
62
|
+
debug("Connected to login server");
|
|
63
|
+
soeClient.toggleEncryption(false);
|
|
64
|
+
me.emit("connect", err, result);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
soeClient.on("disconnect", function (err, result) {
|
|
68
|
+
debug("Disconnected");
|
|
69
|
+
me.emit("disconnect", err, result);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
connect(callback) {
|
|
73
|
+
debug("Connecting to gateway server");
|
|
74
|
+
this._soeClient.connect();
|
|
75
|
+
}
|
|
76
|
+
sendTunnelData(tunnelData, channel) {
|
|
77
|
+
channel = channel || 0;
|
|
78
|
+
debug("Sending tunnel data to gateway server");
|
|
79
|
+
var data = this._protocol.pack("TunnelPacketFromExternalConnection", {
|
|
80
|
+
channel: channel,
|
|
81
|
+
tunnelData: tunnelData,
|
|
82
|
+
});
|
|
83
|
+
//fs.writeFileSync("dump/out_tunneldata_" + (tunnelCount++) + ".dat", data);
|
|
84
|
+
this._soeClient.sendAppData(data, true);
|
|
85
|
+
}
|
|
86
|
+
login(characterId, ticket, clientProtocol, clientBuild) {
|
|
87
|
+
debug("Sending login request");
|
|
88
|
+
var data = this._protocol.pack("LoginRequest", {
|
|
89
|
+
characterId: characterId,
|
|
90
|
+
ticket: ticket,
|
|
91
|
+
clientProtocol: clientProtocol,
|
|
92
|
+
clientBuild: clientBuild,
|
|
93
|
+
});
|
|
94
|
+
//fs.writeFileSync("loginrequest.dat", data);
|
|
95
|
+
this._soeClient.sendAppData(data, false);
|
|
96
|
+
this._soeClient.toggleEncryption(true);
|
|
97
|
+
}
|
|
98
|
+
disconnect() {}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
util.inherits(GatewayClient, EventEmitter);
|
|
102
|
+
|
|
103
|
+
var tunnelCount = 0;
|
|
104
|
+
|
|
105
|
+
exports.GatewayClient = GatewayClient;
|
|
@@ -1,227 +1,227 @@
|
|
|
1
|
-
// ======================================================================
|
|
2
|
-
//
|
|
3
|
-
// GNU GENERAL PUBLIC LICENSE
|
|
4
|
-
// Version 3, 29 June 2007
|
|
5
|
-
// copyright (c) 2020 - 2021 Quentin Gruber
|
|
6
|
-
// copyright (c) 2021 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
|
-
import { EventEmitter } from "events";
|
|
15
|
-
|
|
16
|
-
import { SOEClient } from "./soeclient";
|
|
17
|
-
import { LoginProtocol } from "../protocols/loginprotocol";
|
|
18
|
-
const loginProtocolName = "LoginUdp_9";
|
|
19
|
-
const debug = require("debug")("LoginClient");
|
|
20
|
-
|
|
21
|
-
interface SoeClient {
|
|
22
|
-
on: Function;
|
|
23
|
-
emit: Function;
|
|
24
|
-
connect: Function;
|
|
25
|
-
start: Function;
|
|
26
|
-
stop: Function;
|
|
27
|
-
_sessionId: number;
|
|
28
|
-
_protocol: LoginProtocol;
|
|
29
|
-
_sendPacket: Function;
|
|
30
|
-
sendAppData: Function;
|
|
31
|
-
toggleEncryption: Function;
|
|
32
|
-
toggleDataDump: Function;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
interface LoginProtocolInterface {
|
|
36
|
-
parse: Function;
|
|
37
|
-
pack: Function;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export class LoginClient extends EventEmitter {
|
|
41
|
-
_gameId: number;
|
|
42
|
-
_environment: string;
|
|
43
|
-
_soeClient: any;
|
|
44
|
-
_protocol: LoginProtocolInterface;
|
|
45
|
-
|
|
46
|
-
constructor(
|
|
47
|
-
gameId: number,
|
|
48
|
-
environment: string,
|
|
49
|
-
serverAddress: string,
|
|
50
|
-
serverPort: number,
|
|
51
|
-
loginKey: Uint8Array,
|
|
52
|
-
localPort: number
|
|
53
|
-
) {
|
|
54
|
-
super();
|
|
55
|
-
this._gameId = gameId;
|
|
56
|
-
this._environment = environment;
|
|
57
|
-
this._soeClient = new SOEClient(
|
|
58
|
-
loginProtocolName,
|
|
59
|
-
serverAddress,
|
|
60
|
-
serverPort,
|
|
61
|
-
loginKey,
|
|
62
|
-
localPort
|
|
63
|
-
);
|
|
64
|
-
this._protocol = new LoginProtocol();
|
|
65
|
-
var n = 0;
|
|
66
|
-
this._soeClient.on("connect", (err: string, result: string) => {
|
|
67
|
-
debug("Connected to login server");
|
|
68
|
-
this.login("FiNgErPrInT");
|
|
69
|
-
});
|
|
70
|
-
this._soeClient.on("disconnect", (err: string, result: string) => {
|
|
71
|
-
debug("Disconnected");
|
|
72
|
-
});
|
|
73
|
-
this._soeClient.on("appdata", (err: string, data: Buffer) => {
|
|
74
|
-
n++;
|
|
75
|
-
var packet, result;
|
|
76
|
-
try {
|
|
77
|
-
packet = this._protocol.parse(data);
|
|
78
|
-
} catch (e) {
|
|
79
|
-
debug("Failed parsing app data loginclient_appdata_" + n + ".dat");
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
result = packet.result;
|
|
84
|
-
|
|
85
|
-
switch (packet.name) {
|
|
86
|
-
case "LoginReply":
|
|
87
|
-
if (result.status === 1) {
|
|
88
|
-
this.emit("login", null, {
|
|
89
|
-
loggedIn: result.loggedIn,
|
|
90
|
-
isMember: result.isMember,
|
|
91
|
-
});
|
|
92
|
-
} else {
|
|
93
|
-
this.emit("login", "Login failed");
|
|
94
|
-
}
|
|
95
|
-
break;
|
|
96
|
-
case "ForceDisconnect":
|
|
97
|
-
break;
|
|
98
|
-
case "CharacterLoginReply":
|
|
99
|
-
if (result.status === 1) {
|
|
100
|
-
debug(JSON.stringify(result, null, 4));
|
|
101
|
-
this.emit("characterlogin", null, result);
|
|
102
|
-
} else {
|
|
103
|
-
this.emit("characterlogin", "Character login failed");
|
|
104
|
-
}
|
|
105
|
-
break;
|
|
106
|
-
case "CharacterCreateReply":
|
|
107
|
-
if (result.status === 1) {
|
|
108
|
-
this.emit("charactercreate", null, {
|
|
109
|
-
characterId: result.characterId,
|
|
110
|
-
});
|
|
111
|
-
} else {
|
|
112
|
-
this.emit("charactercreate", "Character create failed");
|
|
113
|
-
}
|
|
114
|
-
break;
|
|
115
|
-
case "CharacterDeleteReply":
|
|
116
|
-
if (result.status === 1) {
|
|
117
|
-
this.emit("characterdelete", null, {});
|
|
118
|
-
} else {
|
|
119
|
-
this.emit("characterdelete", "Character delete failed");
|
|
120
|
-
}
|
|
121
|
-
break;
|
|
122
|
-
case "CharacterSelectInfoReply":
|
|
123
|
-
if (result.status === 1) {
|
|
124
|
-
this.emit("characterinfo", null, result);
|
|
125
|
-
} else {
|
|
126
|
-
this.emit("characterinfo", "Character info failed");
|
|
127
|
-
}
|
|
128
|
-
break;
|
|
129
|
-
case "ServerListReply":
|
|
130
|
-
this.emit("serverlist", null, {
|
|
131
|
-
servers: result.servers,
|
|
132
|
-
});
|
|
133
|
-
break;
|
|
134
|
-
case "ServerUpdate":
|
|
135
|
-
if (result.status === 1) {
|
|
136
|
-
this.emit("serverupdate", null, result.server);
|
|
137
|
-
} else {
|
|
138
|
-
this.emit("serverupdate", "Server update failed");
|
|
139
|
-
}
|
|
140
|
-
break;
|
|
141
|
-
case "TunnelAppPacketServerToClient":
|
|
142
|
-
break;
|
|
143
|
-
}
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
connect() {
|
|
148
|
-
debug("Connecting to login server");
|
|
149
|
-
this._soeClient.connect();
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
async login(fingerprint: string) {
|
|
153
|
-
async function SetupLoginRequest(
|
|
154
|
-
fingerprint: any,
|
|
155
|
-
sessionId: any,
|
|
156
|
-
protocol: any
|
|
157
|
-
) {
|
|
158
|
-
var data = await protocol.pack("LoginRequest", {
|
|
159
|
-
sessionId: sessionId,
|
|
160
|
-
systemFingerPrint: fingerprint,
|
|
161
|
-
});
|
|
162
|
-
return data;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
var data = await SetupLoginRequest(
|
|
166
|
-
fingerprint,
|
|
167
|
-
this._soeClient._sessionId.toString(),
|
|
168
|
-
this._protocol
|
|
169
|
-
);
|
|
170
|
-
debug("Sending login request");
|
|
171
|
-
this._soeClient.sendAppData(data, true);
|
|
172
|
-
|
|
173
|
-
this.emit("connect");
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
disconnect() {
|
|
177
|
-
this.emit("disconnect");
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
requestServerList() {
|
|
181
|
-
debug("Requesting server list");
|
|
182
|
-
var data = this._protocol.pack("ServerListRequest");
|
|
183
|
-
this._soeClient.sendAppData(data, true);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
requestCharacterInfo() {
|
|
187
|
-
debug("Requesting character info");
|
|
188
|
-
var data = this._protocol.pack("CharacterSelectInfoRequest");
|
|
189
|
-
this._soeClient.sendAppData(data, true);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
requestCharacterLogin(characterId: string, serverId: number, payload: any) {
|
|
193
|
-
debug("Requesting character login");
|
|
194
|
-
var data = this._protocol.pack("CharacterLoginRequest", {
|
|
195
|
-
characterId: characterId,
|
|
196
|
-
serverId: serverId,
|
|
197
|
-
payload: payload,
|
|
198
|
-
});
|
|
199
|
-
if (data) {
|
|
200
|
-
this._soeClient.sendAppData(data, true);
|
|
201
|
-
} else {
|
|
202
|
-
debug("Could not pack character login request data");
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
requestCharacterDelete = function () {};
|
|
207
|
-
|
|
208
|
-
requestCharacterCreate() {
|
|
209
|
-
debug("Requesting character create");
|
|
210
|
-
var data = this._protocol.pack("CharacterCreateRequest", {
|
|
211
|
-
serverId: 1,
|
|
212
|
-
unknown: 0,
|
|
213
|
-
payload: {
|
|
214
|
-
empireId: 2,
|
|
215
|
-
headType: 1,
|
|
216
|
-
profileType: 3,
|
|
217
|
-
gender: 1,
|
|
218
|
-
characterName: "test",
|
|
219
|
-
},
|
|
220
|
-
});
|
|
221
|
-
if (data) {
|
|
222
|
-
this._soeClient.sendAppData(data, true);
|
|
223
|
-
} else {
|
|
224
|
-
debug("Could not pack character create request data");
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
}
|
|
1
|
+
// ======================================================================
|
|
2
|
+
//
|
|
3
|
+
// GNU GENERAL PUBLIC LICENSE
|
|
4
|
+
// Version 3, 29 June 2007
|
|
5
|
+
// copyright (c) 2020 - 2021 Quentin Gruber
|
|
6
|
+
// copyright (c) 2021 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
|
+
import { EventEmitter } from "events";
|
|
15
|
+
|
|
16
|
+
import { SOEClient } from "./soeclient";
|
|
17
|
+
import { LoginProtocol } from "../protocols/loginprotocol";
|
|
18
|
+
const loginProtocolName = "LoginUdp_9";
|
|
19
|
+
const debug = require("debug")("LoginClient");
|
|
20
|
+
|
|
21
|
+
interface SoeClient {
|
|
22
|
+
on: Function;
|
|
23
|
+
emit: Function;
|
|
24
|
+
connect: Function;
|
|
25
|
+
start: Function;
|
|
26
|
+
stop: Function;
|
|
27
|
+
_sessionId: number;
|
|
28
|
+
_protocol: LoginProtocol;
|
|
29
|
+
_sendPacket: Function;
|
|
30
|
+
sendAppData: Function;
|
|
31
|
+
toggleEncryption: Function;
|
|
32
|
+
toggleDataDump: Function;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface LoginProtocolInterface {
|
|
36
|
+
parse: Function;
|
|
37
|
+
pack: Function;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export class LoginClient extends EventEmitter {
|
|
41
|
+
_gameId: number;
|
|
42
|
+
_environment: string;
|
|
43
|
+
_soeClient: any;
|
|
44
|
+
_protocol: LoginProtocolInterface;
|
|
45
|
+
|
|
46
|
+
constructor(
|
|
47
|
+
gameId: number,
|
|
48
|
+
environment: string,
|
|
49
|
+
serverAddress: string,
|
|
50
|
+
serverPort: number,
|
|
51
|
+
loginKey: Uint8Array,
|
|
52
|
+
localPort: number
|
|
53
|
+
) {
|
|
54
|
+
super();
|
|
55
|
+
this._gameId = gameId;
|
|
56
|
+
this._environment = environment;
|
|
57
|
+
this._soeClient = new SOEClient(
|
|
58
|
+
loginProtocolName,
|
|
59
|
+
serverAddress,
|
|
60
|
+
serverPort,
|
|
61
|
+
loginKey,
|
|
62
|
+
localPort
|
|
63
|
+
);
|
|
64
|
+
this._protocol = new LoginProtocol();
|
|
65
|
+
var n = 0;
|
|
66
|
+
this._soeClient.on("connect", (err: string, result: string) => {
|
|
67
|
+
debug("Connected to login server");
|
|
68
|
+
this.login("FiNgErPrInT");
|
|
69
|
+
});
|
|
70
|
+
this._soeClient.on("disconnect", (err: string, result: string) => {
|
|
71
|
+
debug("Disconnected");
|
|
72
|
+
});
|
|
73
|
+
this._soeClient.on("appdata", (err: string, data: Buffer) => {
|
|
74
|
+
n++;
|
|
75
|
+
var packet, result;
|
|
76
|
+
try {
|
|
77
|
+
packet = this._protocol.parse(data);
|
|
78
|
+
} catch (e) {
|
|
79
|
+
debug("Failed parsing app data loginclient_appdata_" + n + ".dat");
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
result = packet.result;
|
|
84
|
+
|
|
85
|
+
switch (packet.name) {
|
|
86
|
+
case "LoginReply":
|
|
87
|
+
if (result.status === 1) {
|
|
88
|
+
this.emit("login", null, {
|
|
89
|
+
loggedIn: result.loggedIn,
|
|
90
|
+
isMember: result.isMember,
|
|
91
|
+
});
|
|
92
|
+
} else {
|
|
93
|
+
this.emit("login", "Login failed");
|
|
94
|
+
}
|
|
95
|
+
break;
|
|
96
|
+
case "ForceDisconnect":
|
|
97
|
+
break;
|
|
98
|
+
case "CharacterLoginReply":
|
|
99
|
+
if (result.status === 1) {
|
|
100
|
+
debug(JSON.stringify(result, null, 4));
|
|
101
|
+
this.emit("characterlogin", null, result);
|
|
102
|
+
} else {
|
|
103
|
+
this.emit("characterlogin", "Character login failed");
|
|
104
|
+
}
|
|
105
|
+
break;
|
|
106
|
+
case "CharacterCreateReply":
|
|
107
|
+
if (result.status === 1) {
|
|
108
|
+
this.emit("charactercreate", null, {
|
|
109
|
+
characterId: result.characterId,
|
|
110
|
+
});
|
|
111
|
+
} else {
|
|
112
|
+
this.emit("charactercreate", "Character create failed");
|
|
113
|
+
}
|
|
114
|
+
break;
|
|
115
|
+
case "CharacterDeleteReply":
|
|
116
|
+
if (result.status === 1) {
|
|
117
|
+
this.emit("characterdelete", null, {});
|
|
118
|
+
} else {
|
|
119
|
+
this.emit("characterdelete", "Character delete failed");
|
|
120
|
+
}
|
|
121
|
+
break;
|
|
122
|
+
case "CharacterSelectInfoReply":
|
|
123
|
+
if (result.status === 1) {
|
|
124
|
+
this.emit("characterinfo", null, result);
|
|
125
|
+
} else {
|
|
126
|
+
this.emit("characterinfo", "Character info failed");
|
|
127
|
+
}
|
|
128
|
+
break;
|
|
129
|
+
case "ServerListReply":
|
|
130
|
+
this.emit("serverlist", null, {
|
|
131
|
+
servers: result.servers,
|
|
132
|
+
});
|
|
133
|
+
break;
|
|
134
|
+
case "ServerUpdate":
|
|
135
|
+
if (result.status === 1) {
|
|
136
|
+
this.emit("serverupdate", null, result.server);
|
|
137
|
+
} else {
|
|
138
|
+
this.emit("serverupdate", "Server update failed");
|
|
139
|
+
}
|
|
140
|
+
break;
|
|
141
|
+
case "TunnelAppPacketServerToClient":
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
connect() {
|
|
148
|
+
debug("Connecting to login server");
|
|
149
|
+
this._soeClient.connect();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async login(fingerprint: string) {
|
|
153
|
+
async function SetupLoginRequest(
|
|
154
|
+
fingerprint: any,
|
|
155
|
+
sessionId: any,
|
|
156
|
+
protocol: any
|
|
157
|
+
) {
|
|
158
|
+
var data = await protocol.pack("LoginRequest", {
|
|
159
|
+
sessionId: sessionId,
|
|
160
|
+
systemFingerPrint: fingerprint,
|
|
161
|
+
});
|
|
162
|
+
return data;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
var data = await SetupLoginRequest(
|
|
166
|
+
fingerprint,
|
|
167
|
+
this._soeClient._sessionId.toString(),
|
|
168
|
+
this._protocol
|
|
169
|
+
);
|
|
170
|
+
debug("Sending login request");
|
|
171
|
+
this._soeClient.sendAppData(data, true);
|
|
172
|
+
|
|
173
|
+
this.emit("connect");
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
disconnect() {
|
|
177
|
+
this.emit("disconnect");
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
requestServerList() {
|
|
181
|
+
debug("Requesting server list");
|
|
182
|
+
var data = this._protocol.pack("ServerListRequest");
|
|
183
|
+
this._soeClient.sendAppData(data, true);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
requestCharacterInfo() {
|
|
187
|
+
debug("Requesting character info");
|
|
188
|
+
var data = this._protocol.pack("CharacterSelectInfoRequest");
|
|
189
|
+
this._soeClient.sendAppData(data, true);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
requestCharacterLogin(characterId: string, serverId: number, payload: any) {
|
|
193
|
+
debug("Requesting character login");
|
|
194
|
+
var data = this._protocol.pack("CharacterLoginRequest", {
|
|
195
|
+
characterId: characterId,
|
|
196
|
+
serverId: serverId,
|
|
197
|
+
payload: payload,
|
|
198
|
+
});
|
|
199
|
+
if (data) {
|
|
200
|
+
this._soeClient.sendAppData(data, true);
|
|
201
|
+
} else {
|
|
202
|
+
debug("Could not pack character login request data");
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
requestCharacterDelete = function () {};
|
|
207
|
+
|
|
208
|
+
requestCharacterCreate() {
|
|
209
|
+
debug("Requesting character create");
|
|
210
|
+
var data = this._protocol.pack("CharacterCreateRequest", {
|
|
211
|
+
serverId: 1,
|
|
212
|
+
unknown: 0,
|
|
213
|
+
payload: {
|
|
214
|
+
empireId: 2,
|
|
215
|
+
headType: 1,
|
|
216
|
+
profileType: 3,
|
|
217
|
+
gender: 1,
|
|
218
|
+
characterName: "test",
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
if (data) {
|
|
222
|
+
this._soeClient.sendAppData(data, true);
|
|
223
|
+
} else {
|
|
224
|
+
debug("Could not pack character create request data");
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|