h1z1-server 0.23.3-2 → 0.23.3-4
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/data/2016/dataSources/ServerItemDefinitions.json +4 -3
- package/package.json +1 -1
- package/src/packets/ClientProtocol/ClientProtocol_1080/voice.ts +3 -3
- package/src/protocols/h1emuprotocol.ts +20 -0
- package/src/servers/H1emuServer/h1emuLoginServer.ts +2 -1
- package/src/servers/LoginServer/loginserver.ts +73 -46
- package/src/servers/LoginServer/workers/httpServer.ts +4 -2
- package/src/servers/ZoneServer2015/zoneserver.ts +3 -4
- package/src/servers/ZoneServer2016/classes/zoneclient.ts +2 -0
- package/src/servers/ZoneServer2016/commands/commandhandler.ts +142 -124
- package/src/servers/ZoneServer2016/commands/commands.ts +1907 -1735
- package/src/servers/ZoneServer2016/data/lootspawns.ts +72 -0
- package/src/servers/ZoneServer2016/entities/basefullcharacter.ts +10 -2
- package/src/servers/ZoneServer2016/entities/character.ts +1 -1
- package/src/servers/ZoneServer2016/entities/explosiveentity.ts +1 -0
- package/src/servers/ZoneServer2016/entities/vehicle.ts +2 -1
- package/src/servers/ZoneServer2016/managers/worlddatamanager.ts +30 -20
- package/src/servers/ZoneServer2016/models/enums.ts +4 -0
- package/src/servers/ZoneServer2016/zonepackethandlers.ts +84 -29
- package/src/servers/ZoneServer2016/zoneserver.ts +134 -33
- package/src/types/zone2016packets.ts +7 -1
- package/src/types/zoneserver.ts +14 -1
- package/src/utils/constants.ts +1 -0
- package/src/utils/enums.ts +24 -0
- package/src/utils/utils.ts +23 -6
|
@@ -2866,7 +2866,6 @@
|
|
|
2866
2866
|
"IS_ARMOR": 0,
|
|
2867
2867
|
"PASSIVE_EQUIP_SLOT_GROUP_ID": 0,
|
|
2868
2868
|
"SCRAP_VALUE_OVERRIDE": 0,
|
|
2869
|
-
"WORLD_MODEL_ID": 2,
|
|
2870
2869
|
"PICKUP_EFFECT": 5151
|
|
2871
2870
|
},
|
|
2872
2871
|
"40": {
|
|
@@ -22561,7 +22560,8 @@
|
|
|
22561
22560
|
"IS_ARMOR": 0,
|
|
22562
22561
|
"PASSIVE_EQUIP_SLOT_GROUP_ID": 0,
|
|
22563
22562
|
"SCRAP_VALUE_OVERRIDE": 0,
|
|
22564
|
-
"PICKUP_EFFECT": 5151
|
|
22563
|
+
"PICKUP_EFFECT": 5151,
|
|
22564
|
+
"WORLD_MODEL_ID": 8019
|
|
22565
22565
|
},
|
|
22566
22566
|
"1536": {
|
|
22567
22567
|
"NAME": "Hammer",
|
|
@@ -60885,7 +60885,8 @@
|
|
|
60885
60885
|
"IS_ARMOR": 0,
|
|
60886
60886
|
"PASSIVE_EQUIP_SLOT_GROUP_ID": 0,
|
|
60887
60887
|
"SCRAP_VALUE_OVERRIDE": 0,
|
|
60888
|
-
"PICKUP_EFFECT": 5151
|
|
60888
|
+
"PICKUP_EFFECT": 5151,
|
|
60889
|
+
"WORLD_MODEL_ID": 9583
|
|
60889
60890
|
},
|
|
60890
60891
|
"2274": {
|
|
60891
60892
|
"NAME": "Police Body Armor",
|
package/package.json
CHANGED
|
@@ -35,7 +35,7 @@ export const voicePackets: any = [
|
|
|
35
35
|
],
|
|
36
36
|
},
|
|
37
37
|
],
|
|
38
|
-
["Voice.LeaveChannel", 0x8202, {}],
|
|
39
|
-
["Voice.RadioChannel", 0x8207, {}],
|
|
40
|
-
["Voice.LeaveRadio", 0x8208, {}],
|
|
38
|
+
["Voice.LeaveChannel", 0x8202, { fields: [] }],
|
|
39
|
+
["Voice.RadioChannel", 0x8207, { fields: [] }],
|
|
40
|
+
["Voice.LeaveRadio", 0x8208, { fields: [] }],
|
|
41
41
|
];
|
|
@@ -128,6 +128,26 @@ const packets = [
|
|
|
128
128
|
],
|
|
129
129
|
},
|
|
130
130
|
],
|
|
131
|
+
[
|
|
132
|
+
"ClientIsAdminRequest",
|
|
133
|
+
0x14,
|
|
134
|
+
{
|
|
135
|
+
fields: [
|
|
136
|
+
{ name: "reqId", type: "uint32", defaultValue: 0 },
|
|
137
|
+
{ name: "guid", type: "uint64string", defaultValue: 0 },
|
|
138
|
+
],
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
[
|
|
142
|
+
"ClientIsAdminReply",
|
|
143
|
+
0x15,
|
|
144
|
+
{
|
|
145
|
+
fields: [
|
|
146
|
+
{ name: "reqId", type: "uint32", defaultValue: 0 },
|
|
147
|
+
{ name: "status", type: "boolean", defaultValue: 0 },
|
|
148
|
+
],
|
|
149
|
+
},
|
|
150
|
+
],
|
|
131
151
|
];
|
|
132
152
|
|
|
133
153
|
export const [H1emuPacketsPacketTypes, H1emuPacketsPackets] =
|
|
@@ -30,7 +30,8 @@ export class H1emuLoginServer extends H1emuServer {
|
|
|
30
30
|
break;
|
|
31
31
|
case "CharacterCreateReply":
|
|
32
32
|
case "CharacterExistReply":
|
|
33
|
-
case "CharacterDeleteReply":
|
|
33
|
+
case "CharacterDeleteReply":
|
|
34
|
+
case "ClientIsAdminReply": {
|
|
34
35
|
this.emit("processInternalReq", packet, ["status"]);
|
|
35
36
|
break;
|
|
36
37
|
}
|
|
@@ -35,7 +35,7 @@ import { Worker } from "worker_threads";
|
|
|
35
35
|
import { httpServerMessage } from "types/shared";
|
|
36
36
|
import { LoginProtocol2016 } from "../../protocols/loginprotocol2016";
|
|
37
37
|
import { crc_length_options } from "../../types/soeserver";
|
|
38
|
-
import { DEFAULT_CRYPTO_KEY } from "../../utils/constants";
|
|
38
|
+
import { DB_NAME, DEFAULT_CRYPTO_KEY } from "../../utils/constants";
|
|
39
39
|
import { healthThreadDecorator } from "../../servers/shared/workers/healthWorker";
|
|
40
40
|
import {
|
|
41
41
|
LoginReply,
|
|
@@ -52,7 +52,11 @@ import {
|
|
|
52
52
|
import { LoginUdp_9packets } from "types/LoginUdp_9packets";
|
|
53
53
|
import { getCharacterModelData } from "../shared/functions";
|
|
54
54
|
import LoginClient from "servers/LoginServer/loginclient";
|
|
55
|
-
import {
|
|
55
|
+
import {
|
|
56
|
+
DB_COLLECTIONS,
|
|
57
|
+
GAME_VERSIONS,
|
|
58
|
+
NAME_VALIDATION_STATUS,
|
|
59
|
+
} from "../../utils/enums";
|
|
56
60
|
import DataSchema from "h1z1-dataschema";
|
|
57
61
|
import { applicationDataKOTK } from "../../packets/LoginUdp/LoginUdp_11/loginpackets";
|
|
58
62
|
import { Resolver } from "dns";
|
|
@@ -183,7 +187,7 @@ export class LoginServer extends EventEmitter {
|
|
|
183
187
|
);
|
|
184
188
|
let status = 0;
|
|
185
189
|
const { serverAddress: fullServerAddress } = await this._db
|
|
186
|
-
.collection(
|
|
190
|
+
.collection(DB_COLLECTIONS.SERVERS)
|
|
187
191
|
.findOne({ serverId: serverId });
|
|
188
192
|
const serverAddress = fullServerAddress.split(":")[0];
|
|
189
193
|
if (serverAddress) {
|
|
@@ -216,19 +220,23 @@ export class LoginServer extends EventEmitter {
|
|
|
216
220
|
const { population } = packet.data;
|
|
217
221
|
const serverId = this._zoneConnections[client.clientId];
|
|
218
222
|
const { maxPopulationNumber } = await this._db
|
|
219
|
-
.collection(
|
|
223
|
+
.collection(DB_COLLECTIONS.SERVERS)
|
|
220
224
|
.findOne({ serverId: serverId });
|
|
221
|
-
this._db
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
225
|
+
this._db
|
|
226
|
+
?.collection(DB_COLLECTIONS.SERVERS)
|
|
227
|
+
.findOneAndUpdate(
|
|
228
|
+
{ serverId: serverId },
|
|
229
|
+
{
|
|
230
|
+
$set: {
|
|
231
|
+
populationNumber: population,
|
|
232
|
+
populationLevel: Number(
|
|
233
|
+
((population / maxPopulationNumber) * 3).toFixed(
|
|
234
|
+
0
|
|
235
|
+
)
|
|
236
|
+
),
|
|
237
|
+
},
|
|
238
|
+
}
|
|
239
|
+
);
|
|
232
240
|
break;
|
|
233
241
|
}
|
|
234
242
|
default:
|
|
@@ -276,7 +284,10 @@ export class LoginServer extends EventEmitter {
|
|
|
276
284
|
}`
|
|
277
285
|
);
|
|
278
286
|
delete this._zoneConnections[client.clientId];
|
|
279
|
-
if (
|
|
287
|
+
if (
|
|
288
|
+
client.serverId &&
|
|
289
|
+
!Object.values(this._zoneConnections).includes(client.serverId)
|
|
290
|
+
) {
|
|
280
291
|
await this.updateServerStatus(client.serverId, false);
|
|
281
292
|
}
|
|
282
293
|
}
|
|
@@ -371,7 +382,7 @@ export class LoginServer extends EventEmitter {
|
|
|
371
382
|
status: 1,
|
|
372
383
|
};
|
|
373
384
|
return await this._db
|
|
374
|
-
.collection(
|
|
385
|
+
.collection(DB_COLLECTIONS.CHARACTERS_LIGHT)
|
|
375
386
|
.find(charactersQuery)
|
|
376
387
|
.toArray();
|
|
377
388
|
}
|
|
@@ -395,15 +406,15 @@ export class LoginServer extends EventEmitter {
|
|
|
395
406
|
client.protocolName === "LoginUdp_9"
|
|
396
407
|
? GAME_VERSIONS.H1Z1_15janv_2015
|
|
397
408
|
: GAME_VERSIONS.H1Z1_6dec_2016;
|
|
398
|
-
console.warn(
|
|
399
|
-
|
|
400
|
-
);
|
|
409
|
+
//console.warn(
|
|
410
|
+
// "Your session id is not a valid json string, please update your launcher to avoid this warning"
|
|
411
|
+
//);
|
|
401
412
|
}
|
|
402
413
|
if (this._soloMode) {
|
|
403
414
|
client.loginSessionId = String(sessionId);
|
|
404
415
|
} else {
|
|
405
416
|
const realSession = await this._db
|
|
406
|
-
.collection(
|
|
417
|
+
.collection(DB_COLLECTIONS.USERS_SESSIONS)
|
|
407
418
|
.findOne({ guid: sessionId });
|
|
408
419
|
client.loginSessionId = realSession ? realSession.authKey : sessionId;
|
|
409
420
|
}
|
|
@@ -449,7 +460,7 @@ export class LoginServer extends EventEmitter {
|
|
|
449
460
|
let status = isValidCharacterName(characterName);
|
|
450
461
|
if (!this._soloMode) {
|
|
451
462
|
const blackListedEntry = await this._db
|
|
452
|
-
.collection(
|
|
463
|
+
.collection(DB_COLLECTIONS.BLACK_LIST_ENTRIES)
|
|
453
464
|
.findOne({
|
|
454
465
|
WORD: characterName.toUpperCase(),
|
|
455
466
|
});
|
|
@@ -461,7 +472,7 @@ export class LoginServer extends EventEmitter {
|
|
|
461
472
|
}
|
|
462
473
|
} else {
|
|
463
474
|
const duplicateCharacter = await this._db
|
|
464
|
-
.collection(
|
|
475
|
+
.collection(DB_COLLECTIONS.CHARACTERS_LIGHT)
|
|
465
476
|
.findOne({
|
|
466
477
|
"payload.name": characterName,
|
|
467
478
|
serverId: baseResponse.serverId,
|
|
@@ -555,16 +566,18 @@ export class LoginServer extends EventEmitter {
|
|
|
555
566
|
}
|
|
556
567
|
|
|
557
568
|
async updateServerStatus(serverId: number, status: boolean) {
|
|
558
|
-
const server = await this._db
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
569
|
+
const server = await this._db
|
|
570
|
+
.collection(DB_COLLECTIONS.SERVERS)
|
|
571
|
+
.findOneAndUpdate(
|
|
572
|
+
{ serverId: serverId },
|
|
573
|
+
{
|
|
574
|
+
$set: {
|
|
575
|
+
allowedAccess: status,
|
|
576
|
+
populationNumber: 0,
|
|
577
|
+
populationLevel: 0,
|
|
578
|
+
},
|
|
579
|
+
}
|
|
580
|
+
);
|
|
568
581
|
this.clients.forEach((client: Client) => {
|
|
569
582
|
if (client.gameVersion === server.value.gameVersion) {
|
|
570
583
|
this.sendData(client, "ServerUpdate", {
|
|
@@ -576,7 +589,10 @@ export class LoginServer extends EventEmitter {
|
|
|
576
589
|
}
|
|
577
590
|
|
|
578
591
|
async updateServersStatus(): Promise<void> {
|
|
579
|
-
const servers = await this._db
|
|
592
|
+
const servers = await this._db
|
|
593
|
+
.collection(DB_COLLECTIONS.SERVERS)
|
|
594
|
+
.find()
|
|
595
|
+
.toArray();
|
|
580
596
|
|
|
581
597
|
for (let index = 0; index < servers.length; index++) {
|
|
582
598
|
const server: GameServer = servers[index];
|
|
@@ -593,7 +609,7 @@ export class LoginServer extends EventEmitter {
|
|
|
593
609
|
let servers;
|
|
594
610
|
if (!this._soloMode) {
|
|
595
611
|
servers = await this._db
|
|
596
|
-
.collection(
|
|
612
|
+
.collection(DB_COLLECTIONS.SERVERS)
|
|
597
613
|
.find({
|
|
598
614
|
gameVersion: client.gameVersion,
|
|
599
615
|
})
|
|
@@ -675,7 +691,7 @@ export class LoginServer extends EventEmitter {
|
|
|
675
691
|
const characterId = packet.characterId;
|
|
676
692
|
const characterQuery = { characterId: characterId };
|
|
677
693
|
const charracterToDelete = await this._db
|
|
678
|
-
.collection(
|
|
694
|
+
.collection(DB_COLLECTIONS.CHARACTERS_LIGHT)
|
|
679
695
|
.findOne(characterQuery);
|
|
680
696
|
if (
|
|
681
697
|
charracterToDelete &&
|
|
@@ -688,7 +704,7 @@ export class LoginServer extends EventEmitter {
|
|
|
688
704
|
)) as number;
|
|
689
705
|
if (deletionStatus) {
|
|
690
706
|
await this._db
|
|
691
|
-
.collection(
|
|
707
|
+
.collection(DB_COLLECTIONS.CHARACTERS_LIGHT)
|
|
692
708
|
.updateOne(characterQuery, {
|
|
693
709
|
$set: {
|
|
694
710
|
status: 0,
|
|
@@ -712,11 +728,13 @@ export class LoginServer extends EventEmitter {
|
|
|
712
728
|
loginSessionId: string | undefined
|
|
713
729
|
): Promise<CharacterLoginReply> {
|
|
714
730
|
const { serverAddress, populationNumber, maxPopulationNumber } =
|
|
715
|
-
await this._db
|
|
731
|
+
await this._db
|
|
732
|
+
.collection(DB_COLLECTIONS.SERVERS)
|
|
733
|
+
.findOne({ serverId: serverId });
|
|
716
734
|
const character = await this._db
|
|
717
|
-
.collection(
|
|
735
|
+
.collection(DB_COLLECTIONS.CHARACTERS_LIGHT)
|
|
718
736
|
.findOne({ characterId: characterId });
|
|
719
|
-
|
|
737
|
+
let connectionStatus =
|
|
720
738
|
Object.values(this._zoneConnections).includes(serverId) &&
|
|
721
739
|
(populationNumber < maxPopulationNumber || !maxPopulationNumber);
|
|
722
740
|
debug(`connectionStatus ${connectionStatus}`);
|
|
@@ -728,9 +746,16 @@ export class LoginServer extends EventEmitter {
|
|
|
728
746
|
}
|
|
729
747
|
const hiddenSession = connectionStatus
|
|
730
748
|
? await this._db
|
|
731
|
-
.collection(
|
|
749
|
+
.collection(DB_COLLECTIONS.USERS_SESSIONS)
|
|
732
750
|
.findOne({ authKey: loginSessionId })
|
|
733
751
|
: { guid: "" };
|
|
752
|
+
connectionStatus = false;
|
|
753
|
+
if (!connectionStatus) {
|
|
754
|
+
// Admins bypass max pop
|
|
755
|
+
connectionStatus = (await this.askZone(serverId, "ClientIsAdminRequest", {
|
|
756
|
+
guid: hiddenSession?.guid,
|
|
757
|
+
})) as boolean;
|
|
758
|
+
}
|
|
734
759
|
return {
|
|
735
760
|
unknownQword1: "0x0",
|
|
736
761
|
unknownDword1: 0,
|
|
@@ -936,7 +961,7 @@ export class LoginServer extends EventEmitter {
|
|
|
936
961
|
} else {
|
|
937
962
|
let sessionObj;
|
|
938
963
|
const storedUserSession = await this._db
|
|
939
|
-
?.collection(
|
|
964
|
+
?.collection(DB_COLLECTIONS.USERS_SESSIONS)
|
|
940
965
|
.findOne({ authKey: client.loginSessionId, serverId: serverId });
|
|
941
966
|
if (storedUserSession) {
|
|
942
967
|
sessionObj = storedUserSession;
|
|
@@ -946,7 +971,9 @@ export class LoginServer extends EventEmitter {
|
|
|
946
971
|
authKey: client.loginSessionId,
|
|
947
972
|
guid: generateRandomGuid(),
|
|
948
973
|
};
|
|
949
|
-
await this._db
|
|
974
|
+
await this._db
|
|
975
|
+
?.collection(DB_COLLECTIONS.USERS_SESSIONS)
|
|
976
|
+
.insertOne(sessionObj);
|
|
950
977
|
}
|
|
951
978
|
let newCharacterData;
|
|
952
979
|
switch (client.gameVersion) {
|
|
@@ -974,7 +1001,7 @@ export class LoginServer extends EventEmitter {
|
|
|
974
1001
|
: 0;
|
|
975
1002
|
|
|
976
1003
|
if (creationStatus === 1) {
|
|
977
|
-
await this._db.collection(
|
|
1004
|
+
await this._db.collection(DB_COLLECTIONS.CHARACTERS_LIGHT).insertOne({
|
|
978
1005
|
authKey: client.loginSessionId,
|
|
979
1006
|
serverId: serverId,
|
|
980
1007
|
gameVersion: client.gameVersion,
|
|
@@ -1008,11 +1035,11 @@ export class LoginServer extends EventEmitter {
|
|
|
1008
1035
|
debug("connected to mongo !");
|
|
1009
1036
|
// if no collections exist on h1server database , fill it with samples
|
|
1010
1037
|
const dbIsEmpty =
|
|
1011
|
-
(await mongoClient.db(
|
|
1038
|
+
(await mongoClient.db(DB_NAME).collections()).length < 1;
|
|
1012
1039
|
if (dbIsEmpty) {
|
|
1013
1040
|
await initMongo(mongoClient, debugName);
|
|
1014
1041
|
}
|
|
1015
|
-
this._db = mongoClient.db(
|
|
1042
|
+
this._db = mongoClient.db(DB_NAME);
|
|
1016
1043
|
this.updateServersStatus();
|
|
1017
1044
|
}
|
|
1018
1045
|
|
|
@@ -15,6 +15,8 @@ import { MongoClient } from "mongodb";
|
|
|
15
15
|
import { httpServerMessage } from "types/shared";
|
|
16
16
|
import { parentPort, workerData } from "worker_threads";
|
|
17
17
|
import http from "http";
|
|
18
|
+
import { DB_COLLECTIONS } from "../../../utils/enums";
|
|
19
|
+
import { DB_NAME } from "../../../utils/constants";
|
|
18
20
|
function sendMessageToServer(type: string, requestId: number, data: any) {
|
|
19
21
|
const message: httpServerMessage = {
|
|
20
22
|
type: type,
|
|
@@ -29,7 +31,7 @@ const { MONGO_URL, SERVER_PORT } = workerData;
|
|
|
29
31
|
const client = new MongoClient(MONGO_URL, {
|
|
30
32
|
maxPoolSize: 5,
|
|
31
33
|
});
|
|
32
|
-
const dbName =
|
|
34
|
+
const dbName = DB_NAME;
|
|
33
35
|
const db = client.db(dbName);
|
|
34
36
|
client.connect();
|
|
35
37
|
let requestCount = 0;
|
|
@@ -61,7 +63,7 @@ httpServer.on("request", async function (req, res) {
|
|
|
61
63
|
const queryObject: any = queryString ? parseQueryString(queryString) : null;
|
|
62
64
|
switch (path) {
|
|
63
65
|
case "servers": {
|
|
64
|
-
const collection = db.collection(
|
|
66
|
+
const collection = db.collection(DB_COLLECTIONS.SERVERS);
|
|
65
67
|
const serversArray = await collection.find().toArray();
|
|
66
68
|
res.writeHead(200, { "Content-Type": "text/json" });
|
|
67
69
|
res.write(JSON.stringify(serversArray));
|
|
@@ -36,7 +36,7 @@ import { ZoneClient as Client } from "./classes/zoneclient";
|
|
|
36
36
|
import { h1z1PacketsType } from "../../types/packets";
|
|
37
37
|
import { Vehicle } from "./classes/vehicle";
|
|
38
38
|
import { Resolver } from "dns";
|
|
39
|
-
import { DEFAULT_CRYPTO_KEY } from "../../utils/constants";
|
|
39
|
+
import { DB_NAME, DEFAULT_CRYPTO_KEY } from "../../utils/constants";
|
|
40
40
|
|
|
41
41
|
process.env.isBin && require("./workers/dynamicWeather");
|
|
42
42
|
|
|
@@ -658,12 +658,11 @@ export class ZoneServer2015 extends EventEmitter {
|
|
|
658
658
|
}
|
|
659
659
|
debug("connected to mongo !");
|
|
660
660
|
// if no collections exist on h1server database , fill it with samples
|
|
661
|
-
const dbIsEmpty =
|
|
662
|
-
(await mongoClient.db("h1server").collections()).length < 1;
|
|
661
|
+
const dbIsEmpty = (await mongoClient.db(DB_NAME).collections()).length < 1;
|
|
663
662
|
if (dbIsEmpty) {
|
|
664
663
|
await initMongo(mongoClient, debugName);
|
|
665
664
|
}
|
|
666
|
-
this._db = mongoClient.db(
|
|
665
|
+
this._db = mongoClient.db(DB_NAME);
|
|
667
666
|
}
|
|
668
667
|
|
|
669
668
|
async start(): Promise<void> {
|
|
@@ -36,6 +36,7 @@ export class ZoneClient2016 {
|
|
|
36
36
|
time: 0,
|
|
37
37
|
};
|
|
38
38
|
speedWarnsNumber: number = 0;
|
|
39
|
+
allowedProjectiles: number = 0;
|
|
39
40
|
pvpStats: {
|
|
40
41
|
shotsFired: number;
|
|
41
42
|
shotsHit: number;
|
|
@@ -60,6 +61,7 @@ export class ZoneClient2016 {
|
|
|
60
61
|
vehicle: {
|
|
61
62
|
mountedVehicle?: string;
|
|
62
63
|
} = {};
|
|
64
|
+
radio: boolean = false;
|
|
63
65
|
npcsToSpawnTimer!: NodeJS.Timeout;
|
|
64
66
|
loginSessionId: string;
|
|
65
67
|
pingTimer: NodeJS.Timeout | undefined;
|