dredless 0.6.3 → 1.0.0
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/README.md +22 -57
- package/dist/browser/dredless.global.js +827 -1058
- package/dist/browser/dredless.global.js.map +4 -4
- package/docs/ACCOUNT.md +146 -0
- package/docs/API_REFERENCE.md +63 -2550
- package/docs/BROWSER_API.md +151 -70
- package/docs/CLIENT.md +183 -0
- package/docs/EVENTS.md +136 -0
- package/docs/GETTING_STARTED.md +135 -0
- package/docs/MACHINES.md +351 -0
- package/docs/MANAGEMENT.md +285 -0
- package/docs/NODE_API.md +120 -318
- package/docs/PLAYER_INVENTORY.md +235 -0
- package/docs/PROTOCOL.md +227 -0
- package/docs/README.md +44 -0
- package/docs/TROUBLESHOOTING.md +91 -0
- package/docs/WORLD_STATE.md +183 -0
- package/package.json +1 -2
- package/src/browser.d.ts +31 -1
- package/src/browser.js +10 -0
- package/src/client/core.js +302 -15
- package/src/client/domains/index.js +57 -7
- package/src/client/index.d.ts +1 -1
- package/src/index.d.ts +303 -14
- package/src/index.js +10 -0
- package/src/network/account.js +182 -0
- package/src/network/disconnect.d.ts +2 -0
- package/src/network/disconnect.js +53 -0
- package/src/network/index.d.ts +1 -0
- package/src/network/index.js +1 -0
- package/src/network/invites.d.ts +0 -3
- package/src/network/invites.js +3 -40
- package/src/network/session.d.ts +2 -0
- package/src/network/session.js +21 -0
- package/src/protocol/outbound/ship-management.d.ts +66 -1
- package/src/protocol/outbound/ship-management.js +83 -0
- package/src/state/model/decoder.js +101 -56
- package/src/state/model/index.d.ts +4 -0
- package/src/state/model/loader-config.js +0 -997
- package/src/state/model/state.js +28 -80
- package/src/state/world/index.js +27 -1
|
@@ -232,9 +232,9 @@
|
|
|
232
232
|
if (host === "local.drednot.io") return "local_";
|
|
233
233
|
return "";
|
|
234
234
|
}
|
|
235
|
-
function parseCookies(
|
|
235
|
+
function parseCookies(text2 = "") {
|
|
236
236
|
const cookies = /* @__PURE__ */ new Map();
|
|
237
|
-
for (const part of String(
|
|
237
|
+
for (const part of String(text2).split(/;\s*/)) {
|
|
238
238
|
const index = part.indexOf("=");
|
|
239
239
|
if (index <= 0) continue;
|
|
240
240
|
cookies.set(part.slice(0, index).trim(), decodeURIComponent(part.slice(index + 1).trim()));
|
|
@@ -396,8 +396,8 @@
|
|
|
396
396
|
async function fetchNoticeVersion(baseUrl = DEFAULT_BASE_URL) {
|
|
397
397
|
const response = await new HttpClient({ baseUrl }).request("index.html");
|
|
398
398
|
if (!response.ok) throw new Error(`Failed to fetch notice version: ${response.status} ${response.statusText}`);
|
|
399
|
-
const
|
|
400
|
-
const version = parseNoticeVersion(
|
|
399
|
+
const text2 = await response.text();
|
|
400
|
+
const version = parseNoticeVersion(text2);
|
|
401
401
|
if (version == null) throw new Error("Unable to locate notice version in drednot page");
|
|
402
402
|
return version;
|
|
403
403
|
}
|
|
@@ -411,14 +411,14 @@
|
|
|
411
411
|
if (server2 && typeof server2 === "object") return Number(server2.index ?? server2.id);
|
|
412
412
|
return Number(server2);
|
|
413
413
|
}
|
|
414
|
-
function parseGameVersion(
|
|
415
|
-
return
|
|
414
|
+
function parseGameVersion(text2) {
|
|
415
|
+
return text2.match(/Object\.defineProperty\(exports,"GAME_VERSION",\{enumerable:true,get:\(\)=>e\}\);const e="([^"]+)"/)?.[1] || null;
|
|
416
416
|
}
|
|
417
|
-
function parseNoticeVersion(
|
|
418
|
-
const moduleMatch =
|
|
417
|
+
function parseNoticeVersion(text2) {
|
|
418
|
+
const moduleMatch = text2.match(/Object\.defineProperty\(exports,"checkNotice"[\s\S]{0,8000}?setCookie\)\("notice_version",([A-Za-z_$][\w$]*)\)/);
|
|
419
419
|
if (moduleMatch) {
|
|
420
420
|
const constant = moduleMatch[1];
|
|
421
|
-
const prefix =
|
|
421
|
+
const prefix = text2.slice(Math.max(0, moduleMatch.index - 1e3), moduleMatch.index + moduleMatch[0].length);
|
|
422
422
|
const constantMatch = prefix.match(new RegExp(`const\\s+${constant}\\s*=\\s*(\\d+)\\s*;`));
|
|
423
423
|
if (constantMatch) return Number(constantMatch[1]);
|
|
424
424
|
}
|
|
@@ -429,14 +429,14 @@
|
|
|
429
429
|
/notice[^0-9]{0,40}version[^0-9]{0,20}(\d+)/i
|
|
430
430
|
];
|
|
431
431
|
for (const pattern of patterns) {
|
|
432
|
-
const match =
|
|
432
|
+
const match = text2.match(pattern);
|
|
433
433
|
if (match) return Number(match[1]);
|
|
434
434
|
}
|
|
435
435
|
return null;
|
|
436
436
|
}
|
|
437
|
-
function parseServerInfo(
|
|
437
|
+
function parseServerInfo(text2, baseUrl) {
|
|
438
438
|
const host = hostName(baseUrl);
|
|
439
|
-
const match =
|
|
439
|
+
const match = text2.match(/const n=(true|false);const \$="([^"]+)";const o="([^"]+)";const T="([^"]+)";const t="([^"]+)";const S=\[([^\]]+)\];const c=\[([^\]]+)\];const A="([^"]+)";const I="([^"]+)"/s);
|
|
440
440
|
if (!match) return null;
|
|
441
441
|
const [localDomain, baseDomain, testDomain, testGameDomain] = match.slice(2, 6);
|
|
442
442
|
const domains = [...match[6].matchAll(/"((?:[^"\\]|\\.)*)"/g)].map((m) => m[1]);
|
|
@@ -512,8 +512,8 @@
|
|
|
512
512
|
async #fetchMeta() {
|
|
513
513
|
const response = await new HttpClient({ baseUrl: this.baseUrl }).request("index.html");
|
|
514
514
|
if (!response.ok) throw new Error(`Failed to fetch bundle: ${response.status} ${response.statusText}`);
|
|
515
|
-
const
|
|
516
|
-
return { text, version: parseGameVersion(
|
|
515
|
+
const text2 = await response.text();
|
|
516
|
+
return { text: text2, version: parseGameVersion(text2), serverInfo: parseServerInfo(text2, this.baseUrl) };
|
|
517
517
|
}
|
|
518
518
|
};
|
|
519
519
|
fetchGameVersion = (baseUrl = DEFAULT_BASE_URL) => new ServerDirectory(baseUrl).version();
|
|
@@ -550,6 +550,57 @@
|
|
|
550
550
|
}
|
|
551
551
|
};
|
|
552
552
|
|
|
553
|
+
// src/network/disconnect.js
|
|
554
|
+
var DropReason = Object.freeze({
|
|
555
|
+
ProtocolError: 4e3,
|
|
556
|
+
BadVersion: 4001,
|
|
557
|
+
ConnectLimit: 4002,
|
|
558
|
+
ConnectRate: 4003,
|
|
559
|
+
TeamLimit: 4004,
|
|
560
|
+
FullPlayers: 4005,
|
|
561
|
+
FullTeams: 4006,
|
|
562
|
+
TeamNotAvailable: 4007,
|
|
563
|
+
Kicked: 4008,
|
|
564
|
+
Banned: 4009,
|
|
565
|
+
Idle: 4010,
|
|
566
|
+
ShipDestruct: 4011,
|
|
567
|
+
JoinBlocked: 4012,
|
|
568
|
+
HardBanned: 4013,
|
|
569
|
+
NoLoad: 4014,
|
|
570
|
+
Saved: 4015,
|
|
571
|
+
InvalidInvite: 4016,
|
|
572
|
+
Shutdown: 4017,
|
|
573
|
+
ServerError: 4018,
|
|
574
|
+
GTFO: 4019
|
|
575
|
+
});
|
|
576
|
+
var reasonNames = new Map(Object.entries(DropReason).map(([name, code]) => [code, name]));
|
|
577
|
+
var textDecoder = new TextDecoder();
|
|
578
|
+
function normalizeDisconnect(eventOrCode, reason = "") {
|
|
579
|
+
const event = eventOrCode != null && typeof eventOrCode === "object" ? eventOrCode : null;
|
|
580
|
+
const code = event?.code ?? eventOrCode;
|
|
581
|
+
const rawReason = event?.reason ?? reason;
|
|
582
|
+
let text2 = "";
|
|
583
|
+
if (typeof rawReason === "string") text2 = rawReason;
|
|
584
|
+
else if (ArrayBuffer.isView(rawReason)) {
|
|
585
|
+
text2 = textDecoder.decode(new Uint8Array(rawReason.buffer, rawReason.byteOffset, rawReason.byteLength));
|
|
586
|
+
} else if (rawReason instanceof ArrayBuffer) text2 = textDecoder.decode(rawReason);
|
|
587
|
+
const normalizedCode = Number.isInteger(code) ? code : 1006;
|
|
588
|
+
return Object.freeze({
|
|
589
|
+
code: normalizedCode,
|
|
590
|
+
name: reasonNames.get(normalizedCode) ?? null,
|
|
591
|
+
reason: text2,
|
|
592
|
+
// EventEmitter close callbacks don't report whether the handshake was clean.
|
|
593
|
+
wasClean: typeof event?.wasClean === "boolean" ? event.wasClean : null
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
var DisconnectError = class extends Error {
|
|
597
|
+
constructor(disconnect, message = "Disconnected") {
|
|
598
|
+
super(`${message}: ${disconnect.name ?? "Unknown"} (${disconnect.code})${disconnect.reason ? ` \u2014 ${disconnect.reason}` : ""}`);
|
|
599
|
+
this.name = "DisconnectError";
|
|
600
|
+
this.disconnect = disconnect;
|
|
601
|
+
}
|
|
602
|
+
};
|
|
603
|
+
|
|
553
604
|
// src/client/core.js
|
|
554
605
|
init_constants();
|
|
555
606
|
init_runtime();
|
|
@@ -588,16 +639,68 @@
|
|
|
588
639
|
}
|
|
589
640
|
};
|
|
590
641
|
|
|
642
|
+
// src/protocol/outbound/comms.js
|
|
643
|
+
var COMMS_MESSAGE_TYPE = 3;
|
|
644
|
+
function buildCommsMessage(message = "") {
|
|
645
|
+
return {
|
|
646
|
+
type: COMMS_MESSAGE_TYPE,
|
|
647
|
+
msg: String(message)
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
function normalizeCommsEvent(event) {
|
|
651
|
+
const rawMessages = Array.isArray(event?.msgs_text) ? event.msgs_text : [];
|
|
652
|
+
return {
|
|
653
|
+
...event,
|
|
654
|
+
entity: event?.ent_id != null && Number.isFinite(Number(event.ent_id)) ? Number(event.ent_id) : null,
|
|
655
|
+
rawMessages,
|
|
656
|
+
messages: rawMessages.map((message) => ({
|
|
657
|
+
raw: message,
|
|
658
|
+
text: flattenRichText(message)
|
|
659
|
+
}))
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
function flattenRichText(value) {
|
|
663
|
+
if (value == null) return "";
|
|
664
|
+
if (typeof value === "string") return value;
|
|
665
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
666
|
+
if (Array.isArray(value)) return value.map(flattenRichText).join("");
|
|
667
|
+
if (typeof value === "object") {
|
|
668
|
+
if (Object.hasOwn(value, "c")) return flattenRichText(value.c);
|
|
669
|
+
if (Object.hasOwn(value, "text")) return flattenRichText(value.text);
|
|
670
|
+
}
|
|
671
|
+
return "";
|
|
672
|
+
}
|
|
673
|
+
|
|
591
674
|
// src/protocol/outbound/ship-management.js
|
|
592
675
|
var SHIP_MANAGEMENT_TYPE = 4;
|
|
676
|
+
var CREW_LOG_LENGTH = 500;
|
|
593
677
|
var SET_PRIVACY_ACTION = "set_privacy";
|
|
678
|
+
var GRAVITY_ACTION = "gravity";
|
|
679
|
+
var SET_PATRON_PERKS_ACTION = "set_patron_perks";
|
|
594
680
|
var STARTER_RECOVERY_ACTION = "starter_recovery";
|
|
595
681
|
var PLAYER_LIST_ACTION = "player_list";
|
|
596
682
|
var INVITE_RESET_ACTION = "invite_reset";
|
|
597
683
|
var SET_RANK_ACTION = "set_rank";
|
|
598
684
|
var KICK_ACTION = "kick";
|
|
599
685
|
var BAN_ACTION = "ban";
|
|
686
|
+
var UNBAN_ACTION = "unban";
|
|
600
687
|
var DEMOTE_SELF_ACTION = "demote_self";
|
|
688
|
+
var SAVE_SHIP_ACTION = "save_team";
|
|
689
|
+
var RENAME_REQUEST_ACTION = "rename_request";
|
|
690
|
+
var RENAME_COMMIT_ACTION = "rename_commit";
|
|
691
|
+
var GravityDirection = Object.freeze({
|
|
692
|
+
Down: "down",
|
|
693
|
+
Up: "up",
|
|
694
|
+
Left: "left",
|
|
695
|
+
Right: "right"
|
|
696
|
+
});
|
|
697
|
+
function normalizeGravityDirection(value) {
|
|
698
|
+
if (value === GravityDirection.Down || value === 0) return 0;
|
|
699
|
+
if (value === GravityDirection.Up || value === 1) return 1;
|
|
700
|
+
if (value === GravityDirection.Left || value === 2) return 2;
|
|
701
|
+
if (value === GravityDirection.Right || value === 3) return 3;
|
|
702
|
+
throw new RangeError('direction must be "down", "up", "left", "right", or an integer from 0 to 3');
|
|
703
|
+
}
|
|
601
704
|
function requireNonNegativeInteger(value, name) {
|
|
602
705
|
const number = Number(value);
|
|
603
706
|
if (!Number.isInteger(number) || number < 0) throw new RangeError(`${name} must be a non-negative integer`);
|
|
@@ -626,6 +729,13 @@
|
|
|
626
729
|
function buildShipPrivacyMessage(privacy) {
|
|
627
730
|
return buildShipManagementMessage(SET_PRIVACY_ACTION, normalizePrivacy(privacy));
|
|
628
731
|
}
|
|
732
|
+
function buildShipGravityMessage(direction) {
|
|
733
|
+
return buildShipManagementMessage(GRAVITY_ACTION, normalizeGravityDirection(direction));
|
|
734
|
+
}
|
|
735
|
+
function buildSetPatronPerksMessage(enabled) {
|
|
736
|
+
if (typeof enabled !== "boolean") throw new TypeError("enabled must be a boolean");
|
|
737
|
+
return buildShipManagementMessage(SET_PATRON_PERKS_ACTION, enabled);
|
|
738
|
+
}
|
|
629
739
|
function buildStarterRecoveryMessage(itemId) {
|
|
630
740
|
return buildShipManagementMessage(STARTER_RECOVERY_ACTION, requireNonNegativeInteger(itemId, "itemId"));
|
|
631
741
|
}
|
|
@@ -644,9 +754,26 @@
|
|
|
644
754
|
function buildBanPlayerMessage(refId) {
|
|
645
755
|
return buildShipManagementMessage(BAN_ACTION, normalizePlayerRef(refId));
|
|
646
756
|
}
|
|
757
|
+
function buildUnbanPlayerMessage(refId) {
|
|
758
|
+
return buildShipManagementMessage(UNBAN_ACTION, normalizePlayerRef(refId));
|
|
759
|
+
}
|
|
647
760
|
function buildDemoteSelfMessage() {
|
|
648
761
|
return buildShipManagementMessage(DEMOTE_SELF_ACTION);
|
|
649
762
|
}
|
|
763
|
+
function buildSaveShipMessage() {
|
|
764
|
+
return buildShipManagementMessage(SAVE_SHIP_ACTION);
|
|
765
|
+
}
|
|
766
|
+
function buildShipRenameRequestMessage() {
|
|
767
|
+
return buildShipManagementMessage(RENAME_REQUEST_ACTION);
|
|
768
|
+
}
|
|
769
|
+
function buildShipRenameCommitMessage(name, color) {
|
|
770
|
+
if (typeof name !== "string") throw new TypeError("name must be a string");
|
|
771
|
+
if (name.length > 32) throw new RangeError("name must be at most 32 UTF-16 code units");
|
|
772
|
+
if (typeof color !== "string" || !/^#[0-9a-f]{6}$/i.test(color)) {
|
|
773
|
+
throw new TypeError("color must be a #RRGGBB hex string");
|
|
774
|
+
}
|
|
775
|
+
return buildShipManagementMessage(RENAME_COMMIT_ACTION, name, { arg2: color });
|
|
776
|
+
}
|
|
650
777
|
function normalizeShipConfig(event = {}) {
|
|
651
778
|
const source = event && typeof event === "object" ? event : {};
|
|
652
779
|
const config = source.config && typeof source.config === "object" ? source.config : {};
|
|
@@ -665,6 +792,27 @@
|
|
|
665
792
|
enableCheats: Boolean(source.enable_cheats)
|
|
666
793
|
};
|
|
667
794
|
}
|
|
795
|
+
function normalizeCrewLog(event = {}, previous = null) {
|
|
796
|
+
const source = event && typeof event === "object" ? event : {};
|
|
797
|
+
const reset = Boolean(source.reset);
|
|
798
|
+
const amend = Boolean(source.amend);
|
|
799
|
+
const entries = reset ? [] : (previous?.entries || []).slice();
|
|
800
|
+
if (amend) entries.pop();
|
|
801
|
+
const changes = Array.isArray(source.entries) ? source.entries.map((entry) => {
|
|
802
|
+
const value = entry && typeof entry === "object" ? entry : {};
|
|
803
|
+
return {
|
|
804
|
+
icon: value.icon ?? null,
|
|
805
|
+
text: flattenRichText(value.text),
|
|
806
|
+
rawText: value.text ?? null,
|
|
807
|
+
count: value.count ?? 1,
|
|
808
|
+
refId: value.ref ?? null,
|
|
809
|
+
secondaryRefId: value.ref2 ?? null
|
|
810
|
+
};
|
|
811
|
+
}) : [];
|
|
812
|
+
for (const entry of changes) entries.push(entry);
|
|
813
|
+
if (entries.length > CREW_LOG_LENGTH) entries.splice(0, entries.length - CREW_LOG_LENGTH);
|
|
814
|
+
return { entries, changes, reset, amend };
|
|
815
|
+
}
|
|
668
816
|
function normalizeShipPlayerList(event = {}, previous = null, currentCaptainSubrank = null) {
|
|
669
817
|
const source = event && typeof event === "object" ? event : {};
|
|
670
818
|
const changes = Array.isArray(source.player_list) ? source.player_list.map(normalizePlayerListChange) : [];
|
|
@@ -934,7 +1082,7 @@
|
|
|
934
1082
|
const timeout = timeoutValue(options);
|
|
935
1083
|
if (!handle.exists()) throw new Error("Rank target no longer exists");
|
|
936
1084
|
if (handle.rank === value) return this.client;
|
|
937
|
-
const
|
|
1085
|
+
const text2 = { 0: "Restrict to Guests", 1: "Restrict to Crew", 3: "Restrict to Captains" }[value];
|
|
938
1086
|
await this.#open(handle, options);
|
|
939
1087
|
await waitFor(
|
|
940
1088
|
this.client,
|
|
@@ -942,7 +1090,7 @@
|
|
|
942
1090
|
() => handle.rank === value,
|
|
943
1091
|
timeout,
|
|
944
1092
|
"access rank update",
|
|
945
|
-
() => this.#select(
|
|
1093
|
+
() => this.#select(text2)
|
|
946
1094
|
);
|
|
947
1095
|
return this.client;
|
|
948
1096
|
});
|
|
@@ -3550,8 +3698,8 @@
|
|
|
3550
3698
|
}
|
|
3551
3699
|
return out;
|
|
3552
3700
|
}
|
|
3553
|
-
function encodeStringBytes(
|
|
3554
|
-
const bytes = encoder.encode(String(
|
|
3701
|
+
function encodeStringBytes(text2) {
|
|
3702
|
+
const bytes = encoder.encode(String(text2));
|
|
3555
3703
|
const length = bytes.length;
|
|
3556
3704
|
if (length <= 31) {
|
|
3557
3705
|
const out2 = new Uint8Array(1 + length);
|
|
@@ -3895,7 +4043,6 @@
|
|
|
3895
4043
|
SHIELD_GENERATOR_BOOST_STATE_NAMES: () => SHIELD_GENERATOR_BOOST_STATE_NAMES,
|
|
3896
4044
|
SIGN_DISPLAY_MODE_NAMES: () => SIGN_DISPLAY_MODE_NAMES,
|
|
3897
4045
|
SIMPLE_LABEL_STATE_SPEC: () => SIMPLE_LABEL_STATE_SPEC,
|
|
3898
|
-
TABLE_78_FIELD_BITS: () => TABLE_78_FIELD_BITS,
|
|
3899
4046
|
TABLE_78_NUMERIC_FIELDS: () => TABLE_78_NUMERIC_FIELDS,
|
|
3900
4047
|
TEAM_RANK_NAMES: () => TEAM_RANK_NAMES,
|
|
3901
4048
|
THRUSTER_FACING_NAMES: () => THRUSTER_FACING_NAMES,
|
|
@@ -3928,7 +4075,6 @@
|
|
|
3928
4075
|
isOrangeFoolBotState: () => isOrangeFoolBotState,
|
|
3929
4076
|
isRedSentryBotState: () => isRedSentryBotState,
|
|
3930
4077
|
isRedSniperBotState: () => isRedSniperBotState,
|
|
3931
|
-
isSemanticLoaderDelta: () => isSemanticLoaderDelta2,
|
|
3932
4078
|
isShieldHelperBotState: () => isShieldHelperBotState,
|
|
3933
4079
|
isShieldMasterBotState: () => isShieldMasterBotState,
|
|
3934
4080
|
isYellowHunterBotState: () => isYellowHunterBotState,
|
|
@@ -3980,8 +4126,7 @@
|
|
|
3980
4126
|
summarizeShipWorldMetadata: () => summarizeShipWorldMetadata,
|
|
3981
4127
|
summarizeSign: () => summarizeSign,
|
|
3982
4128
|
summarizeSpawnPoint: () => summarizeSpawnPoint,
|
|
3983
|
-
summarizeThruster: () => summarizeThruster
|
|
3984
|
-
table78DeltaRecord: () => table78DeltaRecord
|
|
4129
|
+
summarizeThruster: () => summarizeThruster
|
|
3985
4130
|
});
|
|
3986
4131
|
init_constants();
|
|
3987
4132
|
|
|
@@ -4007,858 +4152,6 @@
|
|
|
4007
4152
|
[2, "allow-filter"],
|
|
4008
4153
|
[3, "block-all"]
|
|
4009
4154
|
]);
|
|
4010
|
-
var DEFAULT_LOADER_PRIORITY = 0;
|
|
4011
|
-
var DEFAULT_LOADER_FILTER_MODE = 0;
|
|
4012
|
-
var DEFAULT_LOADER_STACK = 16;
|
|
4013
|
-
var DEFAULT_LOADER_CYCLE = 1;
|
|
4014
|
-
var DEFAULT_LOADER_PICK = 3;
|
|
4015
|
-
var DEFAULT_LOADER_PLACE = 4;
|
|
4016
|
-
var LOADER_CONFIG_NUMERIC_BITS = [1, 2, 4, 8, 16];
|
|
4017
|
-
var LOADER_CONFIG_NUMERIC_FIELDS = ["q20", "q24", "q28", "q32", "q36"];
|
|
4018
|
-
function wrapLoaderPosition(value) {
|
|
4019
|
-
return value == null ? null : (value % 8 + 8) % 8;
|
|
4020
|
-
}
|
|
4021
|
-
function decodeIndexedLoaderSnapshotRecord(loader, mask = 0, cumulative = null, reference = null) {
|
|
4022
|
-
const config = {
|
|
4023
|
-
pick: 3,
|
|
4024
|
-
place: 4,
|
|
4025
|
-
priority: DEFAULT_LOADER_PRIORITY,
|
|
4026
|
-
requireOutput: false,
|
|
4027
|
-
waitForStack: false,
|
|
4028
|
-
stack: DEFAULT_LOADER_STACK,
|
|
4029
|
-
cycle: DEFAULT_LOADER_CYCLE
|
|
4030
|
-
};
|
|
4031
|
-
if (mask & 32) config.requireOutput = true;
|
|
4032
|
-
if (mask & 64) config.waitForStack = true;
|
|
4033
|
-
switch (mask) {
|
|
4034
|
-
case 0:
|
|
4035
|
-
break;
|
|
4036
|
-
case 1:
|
|
4037
|
-
config.pick = wrapLoaderPosition((loader.q20 ?? 0) + 3);
|
|
4038
|
-
if (cumulative?.q40 != null) config.requireOutput = true;
|
|
4039
|
-
break;
|
|
4040
|
-
case 2:
|
|
4041
|
-
if (reference && cumulative?.q40 != null && loader.q24 != null) {
|
|
4042
|
-
if (loader.q24 <= -8) {
|
|
4043
|
-
config.pick = wrapLoaderPosition((reference.pick ?? 3) + 1);
|
|
4044
|
-
config.place = wrapLoaderPosition((reference.place ?? 4) + 3);
|
|
4045
|
-
config.requireOutput = true;
|
|
4046
|
-
} else {
|
|
4047
|
-
config.pick = wrapLoaderPosition((reference.pick ?? 3) + 2);
|
|
4048
|
-
config.place = wrapLoaderPosition((reference.place ?? 4) + 4);
|
|
4049
|
-
}
|
|
4050
|
-
} else {
|
|
4051
|
-
config.place = wrapLoaderPosition((loader.q24 ?? 0) + 4);
|
|
4052
|
-
}
|
|
4053
|
-
break;
|
|
4054
|
-
case 3:
|
|
4055
|
-
config.pick = reference && loader.q24 <= -8 ? wrapLoaderPosition((reference.pick ?? 3) + (loader.q20 ?? 0) + 3) : wrapLoaderPosition((loader.q20 ?? 0) + 3);
|
|
4056
|
-
config.place = wrapLoaderPosition((loader.q24 ?? 0) + 4);
|
|
4057
|
-
if (cumulative?.q44 != null && cumulative?.q36 == null && cumulative?.q40 == null) {
|
|
4058
|
-
config.requireOutput = true;
|
|
4059
|
-
config.waitForStack = true;
|
|
4060
|
-
}
|
|
4061
|
-
break;
|
|
4062
|
-
case 5:
|
|
4063
|
-
config.pick = wrapLoaderPosition((loader.q28 ?? 0) + 1);
|
|
4064
|
-
config.place = wrapLoaderPosition((loader.q28 ?? 0) + 3);
|
|
4065
|
-
break;
|
|
4066
|
-
case 6:
|
|
4067
|
-
config.pick = wrapLoaderPosition((loader.q24 ?? 0) + 5);
|
|
4068
|
-
config.place = wrapLoaderPosition((loader.q24 ?? 0) + 3);
|
|
4069
|
-
config.requireOutput = true;
|
|
4070
|
-
break;
|
|
4071
|
-
case 7:
|
|
4072
|
-
if (reference && (cumulative?.q40 != null || loader.q24 <= -8 || loader.q28 >= 2)) {
|
|
4073
|
-
if (loader.q24 <= -8) {
|
|
4074
|
-
config.pick = wrapLoaderPosition((reference.pick ?? 3) + (loader.q20 ?? 0) + 5);
|
|
4075
|
-
config.place = wrapLoaderPosition(reference.place ?? 4);
|
|
4076
|
-
config.requireOutput = true;
|
|
4077
|
-
config.waitForStack = true;
|
|
4078
|
-
if (loader.q28 != null) config.priority = loader.q28;
|
|
4079
|
-
} else if (loader.q28 >= 2) {
|
|
4080
|
-
config.pick = wrapLoaderPosition((reference.pick ?? 3) + loader.q28);
|
|
4081
|
-
config.place = wrapLoaderPosition((reference.place ?? 4) + (loader.q20 ?? 0));
|
|
4082
|
-
config.priority = loader.q28 - 4;
|
|
4083
|
-
} else if ((loader.q20 ?? 0) >= 3) {
|
|
4084
|
-
config.pick = wrapLoaderPosition((reference.pick ?? 3) + (loader.q20 ?? 0));
|
|
4085
|
-
config.place = wrapLoaderPosition(reference.place ?? 4);
|
|
4086
|
-
config.priority = (loader.q28 ?? 0) + 1;
|
|
4087
|
-
config.requireOutput = Boolean(reference.requireOutput);
|
|
4088
|
-
config.waitForStack = Boolean(reference.waitForStack);
|
|
4089
|
-
} else {
|
|
4090
|
-
config.pick = wrapLoaderPosition((loader.q20 ?? 0) + 2);
|
|
4091
|
-
config.place = wrapLoaderPosition((reference.place ?? 4) + (loader.q24 ?? 0));
|
|
4092
|
-
config.priority = (loader.q28 ?? 0) + 1;
|
|
4093
|
-
}
|
|
4094
|
-
} else {
|
|
4095
|
-
config.pick = wrapLoaderPosition((loader.q20 ?? 0) + 3);
|
|
4096
|
-
config.place = wrapLoaderPosition((loader.q24 ?? 0) + 4);
|
|
4097
|
-
if (loader.q28 != null) config.priority = loader.q28;
|
|
4098
|
-
}
|
|
4099
|
-
break;
|
|
4100
|
-
case 8:
|
|
4101
|
-
config.pick = wrapLoaderPosition((cumulative?.q40 ?? 0) + 4);
|
|
4102
|
-
config.place = wrapLoaderPosition((cumulative?.q28 ?? 0) + 2);
|
|
4103
|
-
config.requireOutput = true;
|
|
4104
|
-
break;
|
|
4105
|
-
case 9:
|
|
4106
|
-
config.pick = wrapLoaderPosition((loader.q20 ?? 0) + 3);
|
|
4107
|
-
config.place = wrapLoaderPosition((cumulative?.q40 ?? 0) + 3);
|
|
4108
|
-
break;
|
|
4109
|
-
case 18:
|
|
4110
|
-
config.pick = wrapLoaderPosition(loader.q24 ?? 0);
|
|
4111
|
-
config.place = wrapLoaderPosition((loader.q36 ?? 0) + 2);
|
|
4112
|
-
if (loader.q36 != null) config.cycle = loader.q36 / 20 + 1;
|
|
4113
|
-
break;
|
|
4114
|
-
case 32:
|
|
4115
|
-
break;
|
|
4116
|
-
case 65:
|
|
4117
|
-
config.pick = wrapLoaderPosition((loader.q44 ?? 0) + 3);
|
|
4118
|
-
break;
|
|
4119
|
-
case 33:
|
|
4120
|
-
config.pick = wrapLoaderPosition((loader.q40 ?? 0) + 3);
|
|
4121
|
-
config.place = wrapLoaderPosition((loader.q20 ?? 0) + 4);
|
|
4122
|
-
break;
|
|
4123
|
-
case 34:
|
|
4124
|
-
config.pick = wrapLoaderPosition((loader.q24 ?? 0) + 3);
|
|
4125
|
-
config.place = wrapLoaderPosition((loader.q40 ?? 0) + 4);
|
|
4126
|
-
break;
|
|
4127
|
-
case 35:
|
|
4128
|
-
config.pick = wrapLoaderPosition((loader.q24 ?? 0) + 3);
|
|
4129
|
-
config.place = wrapLoaderPosition((loader.q40 ?? 0) + 4);
|
|
4130
|
-
break;
|
|
4131
|
-
case 67:
|
|
4132
|
-
config.pick = wrapLoaderPosition((loader.q24 ?? 0) + 3);
|
|
4133
|
-
config.place = wrapLoaderPosition((loader.q44 ?? 0) + 4);
|
|
4134
|
-
break;
|
|
4135
|
-
case 95:
|
|
4136
|
-
config.pick = wrapLoaderPosition((loader.q24 ?? 0) + 3);
|
|
4137
|
-
config.place = wrapLoaderPosition((loader.q28 ?? 0) + 4);
|
|
4138
|
-
if (loader.q32 != null) config.priority = loader.q32;
|
|
4139
|
-
if (loader.q36 != null) config.stack = DEFAULT_LOADER_STACK + loader.q36;
|
|
4140
|
-
if (loader.q44 != null) config.cycle = loader.q44 / 20 + 1;
|
|
4141
|
-
break;
|
|
4142
|
-
case 98:
|
|
4143
|
-
config.place = wrapLoaderPosition((loader.q40 ?? 0) + 4);
|
|
4144
|
-
break;
|
|
4145
|
-
case 99:
|
|
4146
|
-
config.pick = wrapLoaderPosition((loader.q24 ?? 0) + 3);
|
|
4147
|
-
config.place = wrapLoaderPosition((loader.q40 ?? 0) + 4);
|
|
4148
|
-
break;
|
|
4149
|
-
case 126:
|
|
4150
|
-
config.pick = wrapLoaderPosition(loader.q28 ?? 0);
|
|
4151
|
-
config.place = wrapLoaderPosition(loader.q24 ?? 0);
|
|
4152
|
-
if (loader.q32 != null) config.priority = loader.q32;
|
|
4153
|
-
if (loader.q36 != null) config.stack = DEFAULT_LOADER_STACK + loader.q36;
|
|
4154
|
-
if (loader.q40 != null) config.cycle = loader.q40 / 20 + 1;
|
|
4155
|
-
break;
|
|
4156
|
-
default:
|
|
4157
|
-
return null;
|
|
4158
|
-
}
|
|
4159
|
-
return config;
|
|
4160
|
-
}
|
|
4161
|
-
function decodeLoaderSnapshotRecord(loader, mask = loader?.lastMask ?? 0) {
|
|
4162
|
-
if (!loader) return null;
|
|
4163
|
-
const hasRequireOutput = Boolean(mask & 32);
|
|
4164
|
-
const hasWaitForStack = Boolean(mask & 64);
|
|
4165
|
-
const hasFlag = hasRequireOutput || hasWaitForStack;
|
|
4166
|
-
const slots = [];
|
|
4167
|
-
for (const [index, bit] of LOADER_CONFIG_NUMERIC_BITS.entries()) {
|
|
4168
|
-
if (!(mask & bit)) continue;
|
|
4169
|
-
const value = loader[LOADER_CONFIG_NUMERIC_FIELDS[index]];
|
|
4170
|
-
if (value == null) return null;
|
|
4171
|
-
slots.push(value);
|
|
4172
|
-
}
|
|
4173
|
-
if (hasRequireOutput) {
|
|
4174
|
-
if (loader.q40 == null) return null;
|
|
4175
|
-
slots.push(loader.q40);
|
|
4176
|
-
} else if (hasWaitForStack) {
|
|
4177
|
-
if (loader.q44 == null) return null;
|
|
4178
|
-
slots.push(loader.q44);
|
|
4179
|
-
}
|
|
4180
|
-
if (hasFlag && slots.length) slots.shift();
|
|
4181
|
-
const config = {
|
|
4182
|
-
pick: 3,
|
|
4183
|
-
place: 4,
|
|
4184
|
-
priority: DEFAULT_LOADER_PRIORITY,
|
|
4185
|
-
requireOutput: hasRequireOutput,
|
|
4186
|
-
waitForStack: hasWaitForStack,
|
|
4187
|
-
stack: DEFAULT_LOADER_STACK,
|
|
4188
|
-
cycle: DEFAULT_LOADER_CYCLE
|
|
4189
|
-
};
|
|
4190
|
-
if (mask & 1) {
|
|
4191
|
-
if (!slots.length) return null;
|
|
4192
|
-
config.pick = wrapLoaderPosition(slots.shift() + 3);
|
|
4193
|
-
}
|
|
4194
|
-
if (mask & 2) {
|
|
4195
|
-
if (!slots.length) return null;
|
|
4196
|
-
config.place = wrapLoaderPosition(slots.shift() + 4);
|
|
4197
|
-
}
|
|
4198
|
-
if (mask & 4) {
|
|
4199
|
-
if (!slots.length) return null;
|
|
4200
|
-
config.priority = slots.shift();
|
|
4201
|
-
}
|
|
4202
|
-
if (mask & 8) {
|
|
4203
|
-
if (!slots.length) return null;
|
|
4204
|
-
config.stack = DEFAULT_LOADER_STACK + slots.shift();
|
|
4205
|
-
}
|
|
4206
|
-
if (mask & 16) {
|
|
4207
|
-
if (!slots.length) return null;
|
|
4208
|
-
config.cycle = slots.shift() / 20 + 1;
|
|
4209
|
-
}
|
|
4210
|
-
return config;
|
|
4211
|
-
}
|
|
4212
|
-
function decodeLoaderSemanticDeltaRecord(loader, mask = loader?.lastMask ?? 0) {
|
|
4213
|
-
if (!loader) return null;
|
|
4214
|
-
const hasRequireOutput = Boolean(mask & 32);
|
|
4215
|
-
const hasWaitForStack = Boolean(mask & 64);
|
|
4216
|
-
if (!hasRequireOutput && !hasWaitForStack) return null;
|
|
4217
|
-
const slots = [];
|
|
4218
|
-
for (const [index, bit] of LOADER_CONFIG_NUMERIC_BITS.entries()) {
|
|
4219
|
-
if (!(mask & bit)) continue;
|
|
4220
|
-
slots.push(loader[LOADER_CONFIG_NUMERIC_FIELDS[index]] ?? 0);
|
|
4221
|
-
}
|
|
4222
|
-
if (hasRequireOutput) slots.push(loader.q40 ?? 0);
|
|
4223
|
-
else if (hasWaitForStack) slots.push(loader.q44 ?? 0);
|
|
4224
|
-
if (slots.length) slots.shift();
|
|
4225
|
-
const config = {};
|
|
4226
|
-
if (mask & 1) config.pick = slots.shift() ?? 0;
|
|
4227
|
-
if (mask & 2) config.place = slots.shift() ?? 0;
|
|
4228
|
-
if (mask & 4) config.priority = slots.shift() ?? 0;
|
|
4229
|
-
if (mask & 8) config.stack = slots.shift() ?? 0;
|
|
4230
|
-
if (mask & 16) config.cycleTicks = slots.shift() ?? 0;
|
|
4231
|
-
config.requireOutput = hasRequireOutput;
|
|
4232
|
-
config.waitForStack = hasWaitForStack;
|
|
4233
|
-
return config;
|
|
4234
|
-
}
|
|
4235
|
-
function loaderDeltaRecord(loader, mask, previous) {
|
|
4236
|
-
const record = { lastMask: mask };
|
|
4237
|
-
for (const [field, bit] of [
|
|
4238
|
-
["q20", 1],
|
|
4239
|
-
["q24", 2],
|
|
4240
|
-
["q28", 4],
|
|
4241
|
-
["q32", 8],
|
|
4242
|
-
["q36", 16],
|
|
4243
|
-
["q40", 32],
|
|
4244
|
-
["q44", 64]
|
|
4245
|
-
]) {
|
|
4246
|
-
if (!(mask & bit)) continue;
|
|
4247
|
-
if (field === "q44" && (mask & 32 || loader?.q44 == null)) continue;
|
|
4248
|
-
record[field] = (loader?.[field] ?? 0) - (previous?.[field] ?? 0);
|
|
4249
|
-
}
|
|
4250
|
-
return record;
|
|
4251
|
-
}
|
|
4252
|
-
function isSemanticLoaderDelta(changed, full) {
|
|
4253
|
-
return !full && changed.previous != null && (changed.mask & 96) === 96;
|
|
4254
|
-
}
|
|
4255
|
-
function filterSlotValue(value) {
|
|
4256
|
-
return value == null || value === 0 ? null : value;
|
|
4257
|
-
}
|
|
4258
|
-
var LoaderConfigTracker = class {
|
|
4259
|
-
constructor() {
|
|
4260
|
-
this.pickBases = /* @__PURE__ */ new Map();
|
|
4261
|
-
this.pickDeltaBases = /* @__PURE__ */ new Map();
|
|
4262
|
-
this.placeBases = /* @__PURE__ */ new Map();
|
|
4263
|
-
this.placeDeltaBases = /* @__PURE__ */ new Map();
|
|
4264
|
-
this.currentPicks = /* @__PURE__ */ new Map();
|
|
4265
|
-
this.currentPlaces = /* @__PURE__ */ new Map();
|
|
4266
|
-
this.sparsePositionBaselines = /* @__PURE__ */ new Set();
|
|
4267
|
-
this.priorities = /* @__PURE__ */ new Map();
|
|
4268
|
-
this.priorityOffsets = /* @__PURE__ */ new Map();
|
|
4269
|
-
this.filterModes = /* @__PURE__ */ new Map();
|
|
4270
|
-
this.filterSources = /* @__PURE__ */ new Map();
|
|
4271
|
-
this.requireOutputs = /* @__PURE__ */ new Map();
|
|
4272
|
-
this.waitForStacks = /* @__PURE__ */ new Map();
|
|
4273
|
-
this.stackBases = /* @__PURE__ */ new Map();
|
|
4274
|
-
this.stackSources = /* @__PURE__ */ new Map();
|
|
4275
|
-
this.cycles = /* @__PURE__ */ new Map();
|
|
4276
|
-
this.cycleModes = /* @__PURE__ */ new Map();
|
|
4277
|
-
this.cycleDeltaBases = /* @__PURE__ */ new Map();
|
|
4278
|
-
this.directCycleValues = /* @__PURE__ */ new Map();
|
|
4279
|
-
this.directCycleFields = /* @__PURE__ */ new Map();
|
|
4280
|
-
}
|
|
4281
|
-
updateFromModel(update) {
|
|
4282
|
-
const world = update?.world;
|
|
4283
|
-
const model = update?.result?.model;
|
|
4284
|
-
if (!world || !model) return;
|
|
4285
|
-
const seenEntities = /* @__PURE__ */ new Set();
|
|
4286
|
-
for (const section of model.sections || []) {
|
|
4287
|
-
if (section.table !== 78) continue;
|
|
4288
|
-
for (const changed of section.records || []) {
|
|
4289
|
-
if (changed.indexedLoaderConfig) {
|
|
4290
|
-
this.updateIndexedSnapshotRecord(world.id, changed.entity, changed.record, changed.mask, changed.cumulativeRecord, changed.configEntity);
|
|
4291
|
-
continue;
|
|
4292
|
-
}
|
|
4293
|
-
const loader = changed.record ?? world.model.record(78, changed.entity);
|
|
4294
|
-
this.updateRecord(world.id, changed.entity, loader, changed.mask, changed.previous, {
|
|
4295
|
-
repeatedInUpdate: seenEntities.has(changed.entity),
|
|
4296
|
-
repeatedInSection: changed.repeatedInSection,
|
|
4297
|
-
semanticSnapshot: Boolean(model.full),
|
|
4298
|
-
semanticDelta: isSemanticLoaderDelta(changed, model.full),
|
|
4299
|
-
deltaRecord: loaderDeltaRecord(loader, changed.mask, changed.previous)
|
|
4300
|
-
});
|
|
4301
|
-
seenEntities.add(changed.entity);
|
|
4302
|
-
}
|
|
4303
|
-
}
|
|
4304
|
-
}
|
|
4305
|
-
updateRecord(worldId, entityId, loader, mask = 0, previous = null, options = {}) {
|
|
4306
|
-
if (!loader) return;
|
|
4307
|
-
const key = this.#key(worldId, entityId);
|
|
4308
|
-
const hasTrackedConfig = this.#hasTrackedConfig(key);
|
|
4309
|
-
if (hasTrackedConfig && (options.repeatedInSection || options.repeatedInUpdate) && this.sparsePositionBaselines.has(key) && this.hasPositionConfig(worldId, entityId)) {
|
|
4310
|
-
return;
|
|
4311
|
-
}
|
|
4312
|
-
if (!hasTrackedConfig && this.#isDirectPositionCycleBaseline(loader, mask)) {
|
|
4313
|
-
this.pickBases.set(key, 3);
|
|
4314
|
-
this.pickDeltaBases.set(key, 0);
|
|
4315
|
-
this.placeBases.set(key, 4);
|
|
4316
|
-
this.placeDeltaBases.set(key, 0);
|
|
4317
|
-
this.#setCurrentPosition(key, loader);
|
|
4318
|
-
if (mask & 4 && loader.q28 >= -1 && loader.q28 <= 1) this.priorities.set(key, loader.q28);
|
|
4319
|
-
this.requireOutputs.set(key, Boolean(mask & 32));
|
|
4320
|
-
this.waitForStacks.set(key, Boolean(mask & 64));
|
|
4321
|
-
this.stackBases.set(key, 16);
|
|
4322
|
-
this.stackSources.delete(key);
|
|
4323
|
-
this.cycleModes.set(key, "direct");
|
|
4324
|
-
this.cycleDeltaBases.set(key, 0);
|
|
4325
|
-
this.directCycleValues.set(key, loader.q44 ?? loader.q36);
|
|
4326
|
-
this.directCycleFields.set(key, loader.q44 == null ? "q36" : "q44");
|
|
4327
|
-
this.cycles.set(key, (loader.q44 ?? loader.q36) / 20 + 1);
|
|
4328
|
-
return;
|
|
4329
|
-
}
|
|
4330
|
-
if (!hasTrackedConfig && options.allowSparseBaseline && this.#isSparsePositionBaseline(loader, mask)) {
|
|
4331
|
-
this.#applySparsePositionBaseline(key, loader, mask);
|
|
4332
|
-
return;
|
|
4333
|
-
}
|
|
4334
|
-
const baseline = hasTrackedConfig ? null : this.#loaderBaseline(loader, mask, options.semanticSnapshot);
|
|
4335
|
-
if (hasTrackedConfig && options.semanticDelta && this.#applySemanticDelta(worldId, entityId, loader, mask, previous, options.deltaRecord)) {
|
|
4336
|
-
return;
|
|
4337
|
-
}
|
|
4338
|
-
const hasInitialConfigFields = baseline || mask & 31 && (mask & 32 || mask & 64 && mask & 4);
|
|
4339
|
-
if (!hasTrackedConfig && hasInitialConfigFields && mask !== 32 && mask !== 64) {
|
|
4340
|
-
if (baseline) this.#applyLoaderBaseline(key, loader, baseline);
|
|
4341
|
-
else {
|
|
4342
|
-
const usedQ28AsPositionBase = this.#initializePositionBaseline(key, loader, mask);
|
|
4343
|
-
if (mask & 4 && loader.q28 != null) {
|
|
4344
|
-
if (usedQ28AsPositionBase) this.#initializePriorityOffset(key, loader);
|
|
4345
|
-
else this.priorities.set(key, loader.q28);
|
|
4346
|
-
}
|
|
4347
|
-
}
|
|
4348
|
-
this.requireOutputs.set(key, Boolean(mask & 32));
|
|
4349
|
-
this.waitForStacks.set(key, Boolean(mask & 64));
|
|
4350
|
-
if (!this.stackBases.has(key)) this.#initializeStackBaseline(key, loader);
|
|
4351
|
-
if (!this.cycles.has(key)) this.#initializeCycleBaseline(key, loader);
|
|
4352
|
-
return;
|
|
4353
|
-
}
|
|
4354
|
-
const q44CycleChanged = mask & 64 && this.#usesQ44CycleBase(key) && loader.q44 != null && (this.#fieldChanged(previous, loader, "q44") || this.directCycleValues.has(key) && loader.q44 !== this.directCycleValues.get(key));
|
|
4355
|
-
const q40DirectCycleChanged = mask & 32 && this.cycleModes.get(key) === "q40-direct" && loader.q40 != null && (this.#fieldChanged(previous, loader, "q40") || this.directCycleValues.has(key) && loader.q40 !== this.directCycleValues.get(key));
|
|
4356
|
-
if (q44CycleChanged) {
|
|
4357
|
-
this.directCycleValues.set(key, loader.q44);
|
|
4358
|
-
this.#updateCycle(key, loader);
|
|
4359
|
-
} else if (q40DirectCycleChanged) {
|
|
4360
|
-
this.directCycleValues.set(key, loader.q40);
|
|
4361
|
-
this.#updateCycle(key, loader);
|
|
4362
|
-
} else if (mask & 32 && mask === 32) {
|
|
4363
|
-
this.requireOutputs.set(key, !this.requireOutputs.get(key));
|
|
4364
|
-
} else if (mask & 32 && !this.requireOutputs.has(key)) {
|
|
4365
|
-
this.requireOutputs.set(key, true);
|
|
4366
|
-
}
|
|
4367
|
-
if (!q44CycleChanged) {
|
|
4368
|
-
if (mask & 64 && mask === 64) this.waitForStacks.set(key, !this.waitForStacks.get(key));
|
|
4369
|
-
else if (mask & 64 && !this.waitForStacks.has(key)) this.waitForStacks.set(key, true);
|
|
4370
|
-
}
|
|
4371
|
-
if (mask & 4 && loader.q28 != null) this.priorities.set(key, this.#priority(key, loader.q28));
|
|
4372
|
-
if (mask & 8 && this.filterSources.get(key) === "q32" && loader.q32 != null) this.filterModes.set(key, loader.q32);
|
|
4373
|
-
const q32FilterOnlyUpdate = this.filterSources.get(key) === "q32" && mask === 8;
|
|
4374
|
-
if (mask & 8 && !options.semanticDelta && !q32FilterOnlyUpdate && loader.q32 != null && this.stackBases.has(key)) {
|
|
4375
|
-
const previousConfig = this.getConfig(worldId, entityId, previous);
|
|
4376
|
-
this.stackBases.set(key, previousConfig.stack - (previous?.q32 ?? 0));
|
|
4377
|
-
this.stackSources.set(key, "q32");
|
|
4378
|
-
}
|
|
4379
|
-
if (mask & 16) this.#updateCycle(key, loader);
|
|
4380
|
-
if (mask & 3 && this.hasPositionConfig(worldId, entityId)) this.#setCurrentPosition(key, loader);
|
|
4381
|
-
}
|
|
4382
|
-
updateIndexedSnapshotRecord(worldId, entityId, loader, mask = 0, cumulative = null, configEntity = null) {
|
|
4383
|
-
if (!loader) return false;
|
|
4384
|
-
const reference = configEntity == null || Number(configEntity) === Number(entityId) ? null : this.#trackedConfig(worldId, configEntity);
|
|
4385
|
-
const config = decodeIndexedLoaderSnapshotRecord(loader, mask, cumulative, reference);
|
|
4386
|
-
if (!config) return false;
|
|
4387
|
-
const key = this.#key(worldId, entityId);
|
|
4388
|
-
this.pickBases.set(key, config.pick);
|
|
4389
|
-
this.pickDeltaBases.set(key, loader.q20 ?? 0);
|
|
4390
|
-
this.placeBases.set(key, config.place);
|
|
4391
|
-
this.placeDeltaBases.set(key, loader.q24 ?? 0);
|
|
4392
|
-
this.currentPicks.set(key, config.pick);
|
|
4393
|
-
this.currentPlaces.set(key, config.place);
|
|
4394
|
-
this.sparsePositionBaselines.delete(key);
|
|
4395
|
-
this.priorities.set(key, config.priority);
|
|
4396
|
-
if (mask === 95 && loader.q28 != null) this.priorityOffsets.set(key, config.priority - loader.q28);
|
|
4397
|
-
else this.priorityOffsets.delete(key);
|
|
4398
|
-
this.filterModes.delete(key);
|
|
4399
|
-
this.filterSources.delete(key);
|
|
4400
|
-
this.requireOutputs.set(key, config.requireOutput);
|
|
4401
|
-
this.waitForStacks.set(key, config.waitForStack);
|
|
4402
|
-
this.stackBases.set(key, config.stack - (loader.q32 ?? 0));
|
|
4403
|
-
this.stackSources.delete(key);
|
|
4404
|
-
this.cycles.set(key, config.cycle);
|
|
4405
|
-
if (mask === 95) {
|
|
4406
|
-
this.cycleModes.set(key, "q44-q36-delta");
|
|
4407
|
-
this.cycleDeltaBases.set(key, loader.q36 ?? 0);
|
|
4408
|
-
this.directCycleValues.set(key, loader.q44);
|
|
4409
|
-
this.directCycleFields.set(key, "q44");
|
|
4410
|
-
} else if (mask === 126) {
|
|
4411
|
-
this.cycleModes.set(key, "offset");
|
|
4412
|
-
this.cycleDeltaBases.set(key, loader.q36 ?? 0);
|
|
4413
|
-
this.directCycleValues.delete(key);
|
|
4414
|
-
this.directCycleFields.delete(key);
|
|
4415
|
-
} else {
|
|
4416
|
-
this.cycleModes.set(key, "direct");
|
|
4417
|
-
this.cycleDeltaBases.set(key, 0);
|
|
4418
|
-
}
|
|
4419
|
-
if (loader.q36 != null && mask === 18) {
|
|
4420
|
-
this.directCycleValues.set(key, loader.q36);
|
|
4421
|
-
this.directCycleFields.set(key, "q36");
|
|
4422
|
-
} else if (mask !== 95 && mask !== 126) {
|
|
4423
|
-
this.directCycleValues.delete(key);
|
|
4424
|
-
this.directCycleFields.delete(key);
|
|
4425
|
-
}
|
|
4426
|
-
return true;
|
|
4427
|
-
}
|
|
4428
|
-
delete(worldId, entityId) {
|
|
4429
|
-
const key = this.#key(worldId, entityId);
|
|
4430
|
-
this.pickBases.delete(key);
|
|
4431
|
-
this.pickDeltaBases.delete(key);
|
|
4432
|
-
this.placeBases.delete(key);
|
|
4433
|
-
this.placeDeltaBases.delete(key);
|
|
4434
|
-
this.currentPicks.delete(key);
|
|
4435
|
-
this.currentPlaces.delete(key);
|
|
4436
|
-
this.sparsePositionBaselines.delete(key);
|
|
4437
|
-
this.priorities.delete(key);
|
|
4438
|
-
this.priorityOffsets.delete(key);
|
|
4439
|
-
this.filterModes.delete(key);
|
|
4440
|
-
this.filterSources.delete(key);
|
|
4441
|
-
this.requireOutputs.delete(key);
|
|
4442
|
-
this.waitForStacks.delete(key);
|
|
4443
|
-
this.stackBases.delete(key);
|
|
4444
|
-
this.stackSources.delete(key);
|
|
4445
|
-
this.cycles.delete(key);
|
|
4446
|
-
this.cycleModes.delete(key);
|
|
4447
|
-
this.cycleDeltaBases.delete(key);
|
|
4448
|
-
this.directCycleValues.delete(key);
|
|
4449
|
-
this.directCycleFields.delete(key);
|
|
4450
|
-
}
|
|
4451
|
-
getConfig(worldId, entityId, loader, loaderFilter = null, filterSlots = null) {
|
|
4452
|
-
const key = this.#key(worldId, entityId);
|
|
4453
|
-
const pick = this.currentPicks.has(key) ? this.currentPicks.get(key) : this.#pick(key, loader);
|
|
4454
|
-
const place = this.currentPlaces.has(key) ? this.currentPlaces.get(key) : this.#place(key, loader);
|
|
4455
|
-
const stackBase = this.stackBases.get(key) ?? 16;
|
|
4456
|
-
const stackSource = this.stackSources.get(key) ?? "q32";
|
|
4457
|
-
const stackField = stackSource === "fixed" ? null : loader?.[stackSource];
|
|
4458
|
-
const stack = stackField == null ? this.stackBases.has(key) || this.hasPositionConfig(worldId, entityId) ? stackBase : null : stackBase + stackField;
|
|
4459
|
-
const cycle = this.cycles.has(key) ? this.cycles.get(key) : loader?.q40 == null || loader.q36 == null ? null : (loader.q40 + loader.q36) / 20 + 1;
|
|
4460
|
-
return {
|
|
4461
|
-
pick,
|
|
4462
|
-
place,
|
|
4463
|
-
priority: this.priorities.has(key) ? this.priorities.get(key) : DEFAULT_LOADER_PRIORITY,
|
|
4464
|
-
requireOutput: this.requireOutputs.has(key) ? this.requireOutputs.get(key) : false,
|
|
4465
|
-
waitForStack: this.waitForStacks.has(key) ? this.waitForStacks.get(key) : false,
|
|
4466
|
-
stack: stack ?? DEFAULT_LOADER_STACK,
|
|
4467
|
-
cycle: cycle ?? DEFAULT_LOADER_CYCLE,
|
|
4468
|
-
filterMode: loaderFilter ? loaderFilter.q20 ?? DEFAULT_LOADER_FILTER_MODE : this.#filterMode(key, loader) ?? DEFAULT_LOADER_FILTER_MODE,
|
|
4469
|
-
filterSlots: filterSlots ? [filterSlotValue(filterSlots.q20), filterSlotValue(filterSlots.q24), filterSlotValue(filterSlots.q28)] : null
|
|
4470
|
-
};
|
|
4471
|
-
}
|
|
4472
|
-
hasPositionConfig(worldId, entityId) {
|
|
4473
|
-
const key = this.#key(worldId, entityId);
|
|
4474
|
-
return this.pickBases.has(key) && this.placeBases.has(key);
|
|
4475
|
-
}
|
|
4476
|
-
#hasTrackedConfig(key) {
|
|
4477
|
-
return this.pickBases.has(key) || this.placeBases.has(key) || this.priorities.has(key) || this.priorityOffsets.has(key) || this.filterModes.has(key) || this.requireOutputs.has(key) || this.waitForStacks.has(key) || this.stackBases.has(key) || this.cycles.has(key);
|
|
4478
|
-
}
|
|
4479
|
-
#fieldChanged(previous, loader, field) {
|
|
4480
|
-
return previous != null && loader != null && previous[field] !== loader[field];
|
|
4481
|
-
}
|
|
4482
|
-
#usesQ44CycleBase(key) {
|
|
4483
|
-
const mode = this.cycleModes.get(key);
|
|
4484
|
-
return mode === "q44-q36-delta";
|
|
4485
|
-
}
|
|
4486
|
-
#initializePositionBaseline(key, loader, mask) {
|
|
4487
|
-
const hasQ28PositionBase = loader.q28 != null && mask & 4;
|
|
4488
|
-
if (loader.q24 != null) {
|
|
4489
|
-
this.pickBases.set(key, wrapLoaderPosition(loader.q24 + 3));
|
|
4490
|
-
this.pickDeltaBases.set(key, loader.q20 ?? 0);
|
|
4491
|
-
this.placeDeltaBases.set(key, loader.q24);
|
|
4492
|
-
const initialPlace = hasQ28PositionBase ? loader.q28 + 4 : loader.q36 == null ? null : loader.q36 + 4;
|
|
4493
|
-
if (initialPlace != null) this.placeBases.set(key, wrapLoaderPosition(initialPlace));
|
|
4494
|
-
return hasQ28PositionBase;
|
|
4495
|
-
}
|
|
4496
|
-
if (hasQ28PositionBase) {
|
|
4497
|
-
this.pickBases.set(key, wrapLoaderPosition(loader.q28 + 3));
|
|
4498
|
-
this.pickDeltaBases.set(key, 0);
|
|
4499
|
-
this.placeBases.set(key, 4);
|
|
4500
|
-
this.placeDeltaBases.set(key, 0);
|
|
4501
|
-
return true;
|
|
4502
|
-
}
|
|
4503
|
-
if (loader.q20 != null && loader.q36 != null) {
|
|
4504
|
-
this.pickBases.set(key, wrapLoaderPosition(loader.q36 + 3));
|
|
4505
|
-
this.pickDeltaBases.set(key, 0);
|
|
4506
|
-
this.placeBases.set(key, 4);
|
|
4507
|
-
this.placeDeltaBases.set(key, 0);
|
|
4508
|
-
}
|
|
4509
|
-
return false;
|
|
4510
|
-
}
|
|
4511
|
-
#initializeCycleBaseline(key, loader) {
|
|
4512
|
-
if (loader?.q44 != null && (loader.q36 == null || loader.q40 == null)) {
|
|
4513
|
-
this.cycleModes.set(key, "q44-q36-delta");
|
|
4514
|
-
this.cycleDeltaBases.set(key, loader.q36 ?? 0);
|
|
4515
|
-
this.directCycleValues.set(key, loader.q44);
|
|
4516
|
-
this.directCycleFields.set(key, "q44");
|
|
4517
|
-
this.cycles.set(key, loader.q44 / 20 + 1);
|
|
4518
|
-
return;
|
|
4519
|
-
}
|
|
4520
|
-
if (loader?.q40 == null || loader.q36 == null) return;
|
|
4521
|
-
this.cycleModes.set(key, "offset");
|
|
4522
|
-
this.cycleDeltaBases.set(key, loader.q36 ?? 0);
|
|
4523
|
-
this.directCycleValues.delete(key);
|
|
4524
|
-
this.directCycleFields.delete(key);
|
|
4525
|
-
this.cycles.set(key, loader.q40 / 20 + 1);
|
|
4526
|
-
}
|
|
4527
|
-
#initializeStackBaseline(key, loader) {
|
|
4528
|
-
if (this.stackBases.has(key)) return;
|
|
4529
|
-
if (loader?.q32 == null) return;
|
|
4530
|
-
const baseline = this.#loaderBaseline(loader, loader?.lastMask);
|
|
4531
|
-
if (baseline) {
|
|
4532
|
-
this.stackBases.set(key, baseline.stack - loader.q32);
|
|
4533
|
-
return;
|
|
4534
|
-
}
|
|
4535
|
-
if (loader.q20 == null && loader.q24 == null && loader.q28 == null && loader.q36 != null) {
|
|
4536
|
-
this.stackBases.set(key, 17 + loader.q36);
|
|
4537
|
-
return;
|
|
4538
|
-
}
|
|
4539
|
-
this.stackBases.set(key, 16);
|
|
4540
|
-
}
|
|
4541
|
-
#initializePriorityOffset(key, loader) {
|
|
4542
|
-
if (loader?.q28 == null || loader?.q36 == null) return;
|
|
4543
|
-
const offset = loader.q36 + 2;
|
|
4544
|
-
const priority = loader.q28 + offset;
|
|
4545
|
-
if (priority < -1 || priority > 1) return;
|
|
4546
|
-
this.priorityOffsets.set(key, offset);
|
|
4547
|
-
this.priorities.set(key, priority);
|
|
4548
|
-
}
|
|
4549
|
-
#priority(key, q28) {
|
|
4550
|
-
return q28 + (this.priorityOffsets.get(key) ?? 0);
|
|
4551
|
-
}
|
|
4552
|
-
#updateCycle(key, loader) {
|
|
4553
|
-
const mode = this.cycleModes.get(key);
|
|
4554
|
-
if (mode === "direct") {
|
|
4555
|
-
if (loader?.q36 != null) {
|
|
4556
|
-
this.directCycleValues.set(key, loader.q36);
|
|
4557
|
-
this.directCycleFields.set(key, "q36");
|
|
4558
|
-
this.cycles.set(key, loader.q36 / 20 + 1);
|
|
4559
|
-
} else if (loader?.q44 != null) {
|
|
4560
|
-
this.directCycleValues.set(key, loader.q44);
|
|
4561
|
-
this.directCycleFields.set(key, "q44");
|
|
4562
|
-
this.cycles.set(key, loader.q44 / 20 + 1);
|
|
4563
|
-
}
|
|
4564
|
-
return;
|
|
4565
|
-
}
|
|
4566
|
-
if (mode === "q44-q36-delta") {
|
|
4567
|
-
const base = loader?.q44 ?? this.directCycleValues.get(key);
|
|
4568
|
-
if (base != null) {
|
|
4569
|
-
this.directCycleValues.set(key, base);
|
|
4570
|
-
this.directCycleFields.set(key, "q44");
|
|
4571
|
-
const q36 = loader?.q36 ?? 0;
|
|
4572
|
-
this.cycles.set(key, base < 0 && loader?.q36 != null ? q36 / 20 + 1 : (base + q36 - (this.cycleDeltaBases.get(key) ?? 0)) / 20 + 1);
|
|
4573
|
-
}
|
|
4574
|
-
return;
|
|
4575
|
-
}
|
|
4576
|
-
if (mode === "q40-direct") {
|
|
4577
|
-
if (loader?.q40 != null) {
|
|
4578
|
-
this.directCycleValues.set(key, loader.q40);
|
|
4579
|
-
this.directCycleFields.set(key, "q40");
|
|
4580
|
-
this.cycles.set(key, loader.q40 / 20 + 1);
|
|
4581
|
-
}
|
|
4582
|
-
return;
|
|
4583
|
-
}
|
|
4584
|
-
if (loader?.q40 == null) {
|
|
4585
|
-
if (loader?.q44 != null || loader?.q36 != null) this.cycles.set(key, (loader.q44 ?? loader.q36) / 20 + 1);
|
|
4586
|
-
return;
|
|
4587
|
-
}
|
|
4588
|
-
const deltaBase = this.cycleDeltaBases.get(key) ?? 0;
|
|
4589
|
-
this.cycles.set(key, (loader.q40 + (loader.q36 ?? 0) - deltaBase) / 20 + 1);
|
|
4590
|
-
}
|
|
4591
|
-
#isDirectPositionCycleBaseline(loader, mask) {
|
|
4592
|
-
return (mask & 19) === 19 && loader.q20 != null && loader.q24 != null && loader.q36 != null && loader.q40 == null && loader.q44 == null;
|
|
4593
|
-
}
|
|
4594
|
-
#trackedConfig(worldId, entityId) {
|
|
4595
|
-
const key = this.#key(worldId, entityId);
|
|
4596
|
-
if (!this.#hasTrackedConfig(key)) return null;
|
|
4597
|
-
return {
|
|
4598
|
-
pick: this.currentPicks.has(key) ? this.currentPicks.get(key) : this.pickBases.get(key),
|
|
4599
|
-
place: this.currentPlaces.has(key) ? this.currentPlaces.get(key) : this.placeBases.get(key),
|
|
4600
|
-
priority: this.priorities.get(key) ?? DEFAULT_LOADER_PRIORITY,
|
|
4601
|
-
requireOutput: this.requireOutputs.get(key) ?? false,
|
|
4602
|
-
waitForStack: this.waitForStacks.get(key) ?? false,
|
|
4603
|
-
stack: this.stackBases.get(key) ?? DEFAULT_LOADER_STACK,
|
|
4604
|
-
cycle: this.cycles.get(key) ?? DEFAULT_LOADER_CYCLE
|
|
4605
|
-
};
|
|
4606
|
-
}
|
|
4607
|
-
#isSparsePositionBaseline(loader, mask) {
|
|
4608
|
-
return (mask & 3) === 3 && loader.q20 != null && loader.q24 != null && loader.q28 == null && loader.q32 == null && loader.q36 == null && loader.q44 == null;
|
|
4609
|
-
}
|
|
4610
|
-
#applySparsePositionBaseline(key, loader, mask) {
|
|
4611
|
-
const pickField = loader.q40 == null ? loader.q20 : loader.q24;
|
|
4612
|
-
const placeField = loader.q40 == null ? loader.q24 : loader.q40;
|
|
4613
|
-
const pick = wrapLoaderPosition(pickField + 3);
|
|
4614
|
-
const place = wrapLoaderPosition(placeField + 4);
|
|
4615
|
-
this.pickBases.set(key, pick);
|
|
4616
|
-
this.pickDeltaBases.set(key, loader.q20 ?? 0);
|
|
4617
|
-
this.placeBases.set(key, place);
|
|
4618
|
-
this.placeDeltaBases.set(key, loader.q24 ?? 0);
|
|
4619
|
-
this.currentPicks.set(key, pick);
|
|
4620
|
-
this.currentPlaces.set(key, place);
|
|
4621
|
-
this.sparsePositionBaselines.add(key);
|
|
4622
|
-
this.priorities.set(key, DEFAULT_LOADER_PRIORITY);
|
|
4623
|
-
this.requireOutputs.set(key, Boolean(mask & 32));
|
|
4624
|
-
this.waitForStacks.set(key, Boolean(mask & 64));
|
|
4625
|
-
this.stackBases.set(key, DEFAULT_LOADER_STACK);
|
|
4626
|
-
this.cycles.set(key, DEFAULT_LOADER_CYCLE);
|
|
4627
|
-
}
|
|
4628
|
-
#filterMode(key, loader) {
|
|
4629
|
-
if (this.filterSources.get(key) === "q32" && loader?.q32 != null) {
|
|
4630
|
-
return this.#validFilterMode(loader.q32);
|
|
4631
|
-
}
|
|
4632
|
-
if (this.filterModes.has(key)) return this.#validFilterMode(this.filterModes.get(key));
|
|
4633
|
-
const baseline = this.#loaderBaseline(loader, loader?.lastMask);
|
|
4634
|
-
if (!baseline) return null;
|
|
4635
|
-
return this.#validFilterMode(baseline.filterMode);
|
|
4636
|
-
}
|
|
4637
|
-
#validFilterMode(mode) {
|
|
4638
|
-
return mode >= 0 && mode <= 3 ? mode : null;
|
|
4639
|
-
}
|
|
4640
|
-
#semanticFilterMode(loader, mask) {
|
|
4641
|
-
const q28IsDirectPriority = loader.q28 != null && loader.q28 >= -1 && loader.q28 <= 1;
|
|
4642
|
-
const q24FilterMode = loader.q24 != null && loader.q32 != null && loader.q40 != null ? loader.q24 + 2 : null;
|
|
4643
|
-
const q28FilterMode = loader.q28 != null && loader.q32 != null ? loader.q28 + 1 : null;
|
|
4644
|
-
const q32FilterMode = !q28IsDirectPriority && loader.q28 != null && loader.q32 != null && loader.q40 != null ? loader.q32 + 1 : null;
|
|
4645
|
-
const q32DirectMode = loader.q28 == null && loader.q32 != null && mask & 32 ? loader.q32 : null;
|
|
4646
|
-
if (q28IsDirectPriority && this.#validFilterMode(q24FilterMode) != null) return q24FilterMode;
|
|
4647
|
-
if (this.#validFilterMode(q28FilterMode) != null) return q28FilterMode;
|
|
4648
|
-
if (this.#validFilterMode(q32FilterMode) != null) return q32FilterMode;
|
|
4649
|
-
if (this.#validFilterMode(q32DirectMode) != null) return q32DirectMode;
|
|
4650
|
-
if (this.#validFilterMode(q24FilterMode) != null) return q24FilterMode;
|
|
4651
|
-
return null;
|
|
4652
|
-
}
|
|
4653
|
-
#semanticFilterField(loader, mask) {
|
|
4654
|
-
const q32DirectMode = loader.q28 == null && loader.q32 != null && mask & 32 ? loader.q32 : null;
|
|
4655
|
-
return this.#validFilterMode(q32DirectMode) != null ? "q32" : null;
|
|
4656
|
-
}
|
|
4657
|
-
#loaderBaseline(loader, mask = loader?.lastMask, semanticSnapshot = false) {
|
|
4658
|
-
const snapshot = semanticSnapshot ? decodeLoaderSnapshotRecord(loader, mask) : null;
|
|
4659
|
-
if (snapshot) {
|
|
4660
|
-
return {
|
|
4661
|
-
pickBase: snapshot.pick,
|
|
4662
|
-
pickDeltaBase: loader.q20 ?? 0,
|
|
4663
|
-
placeBase: snapshot.place,
|
|
4664
|
-
placeDeltaBase: loader.q24 ?? 0,
|
|
4665
|
-
priority: snapshot.priority,
|
|
4666
|
-
stack: snapshot.stack,
|
|
4667
|
-
stackField: "fixed",
|
|
4668
|
-
cycle: snapshot.cycle,
|
|
4669
|
-
cycleMode: loader.q44 != null && loader.q40 == null ? "q44-q36-delta" : "offset",
|
|
4670
|
-
filterMode: this.#semanticFilterMode(loader, mask),
|
|
4671
|
-
filterField: this.#semanticFilterField(loader, mask),
|
|
4672
|
-
q32: loader.q32 ?? 0
|
|
4673
|
-
};
|
|
4674
|
-
}
|
|
4675
|
-
if (!loader || loader.q36 == null) return null;
|
|
4676
|
-
if (loader.q40 == null && loader.q44 == null) {
|
|
4677
|
-
if (loader.q20 != null || loader.q24 == null || loader.q28 == null || loader.q32 == null) return null;
|
|
4678
|
-
return {
|
|
4679
|
-
pickBase: wrapLoaderPosition(loader.q28 + 2),
|
|
4680
|
-
pickDeltaBase: 0,
|
|
4681
|
-
placeBase: wrapLoaderPosition(loader.q24 + 4),
|
|
4682
|
-
placeDeltaBase: loader.q24,
|
|
4683
|
-
priority: loader.q28,
|
|
4684
|
-
stack: 16 + loader.q32,
|
|
4685
|
-
cycle: loader.q36 / 20 + 1,
|
|
4686
|
-
cycleMode: "direct",
|
|
4687
|
-
filterMode: loader.q28 + 1,
|
|
4688
|
-
q32: loader.q32
|
|
4689
|
-
};
|
|
4690
|
-
}
|
|
4691
|
-
if (loader.q24 == null && loader.q28 == null && loader.q20 != null && loader.q32 != null && loader.q40 != null && loader.q44 != null) {
|
|
4692
|
-
return {
|
|
4693
|
-
pickBase: wrapLoaderPosition(loader.q20 + 7),
|
|
4694
|
-
pickDeltaBase: loader.q20,
|
|
4695
|
-
placeBase: 4,
|
|
4696
|
-
placeDeltaBase: 0,
|
|
4697
|
-
priority: 0,
|
|
4698
|
-
stack: 16 + loader.q36,
|
|
4699
|
-
stackField: "q36",
|
|
4700
|
-
cycle: loader.q40 / 20 + 1,
|
|
4701
|
-
cycleMode: "q40-direct",
|
|
4702
|
-
filterMode: loader.q32,
|
|
4703
|
-
filterField: "q32",
|
|
4704
|
-
q32: loader.q32
|
|
4705
|
-
};
|
|
4706
|
-
}
|
|
4707
|
-
const q20 = loader.q20 ?? 0;
|
|
4708
|
-
const q32 = loader.q32 ?? 0;
|
|
4709
|
-
let pickBase = null;
|
|
4710
|
-
let placeBase = null;
|
|
4711
|
-
if (loader.q44 != null && loader.q40 == null && loader.q28 == null && loader.q24 != null && loader.q32 != null) {
|
|
4712
|
-
pickBase = wrapLoaderPosition(loader.q24 + 3);
|
|
4713
|
-
placeBase = wrapLoaderPosition(loader.q32 + 4);
|
|
4714
|
-
} else if (loader.q24 != null) {
|
|
4715
|
-
pickBase = wrapLoaderPosition(loader.q24 + 3);
|
|
4716
|
-
placeBase = loader.q28 != null ? wrapLoaderPosition(loader.q28 + 4) : wrapLoaderPosition(loader.q36 + 4);
|
|
4717
|
-
} else if (loader.q28 != null) {
|
|
4718
|
-
pickBase = wrapLoaderPosition(loader.q28 + 3);
|
|
4719
|
-
placeBase = 4;
|
|
4720
|
-
} else if (loader.q20 != null) {
|
|
4721
|
-
pickBase = wrapLoaderPosition(loader.q36 + 3);
|
|
4722
|
-
placeBase = 4;
|
|
4723
|
-
}
|
|
4724
|
-
if (pickBase == null || placeBase == null) return null;
|
|
4725
|
-
const q28IsDirectPriority = loader.q28 != null && loader.q28 >= -1 && loader.q28 <= 1;
|
|
4726
|
-
const priority = loader.q28 != null && loader.q32 != null && loader.q44 != null && loader.q40 != null ? loader.q32 : loader.q28 != null && loader.q32 != null && loader.q44 == null && loader.q40 == null ? loader.q28 : loader.q28 != null && loader.q32 != null && loader.q44 == null && loader.q40 != null ? loader.q32 : loader.q32 != null && loader.q44 != null && loader.q40 == null ? loader.q32 : null;
|
|
4727
|
-
const q28FilterMode = loader.q28 != null && loader.q32 != null && loader.q44 != null ? loader.q28 + 1 : null;
|
|
4728
|
-
const q24FilterMode = loader.q24 != null && loader.q32 != null && loader.q44 != null && loader.q40 != null ? loader.q24 + 2 : null;
|
|
4729
|
-
const q32FilterMode = !q28IsDirectPriority && loader.q28 != null && loader.q32 != null && loader.q44 != null && loader.q40 != null ? loader.q32 + 1 : null;
|
|
4730
|
-
const filterMode = q28IsDirectPriority && q24FilterMode != null && q24FilterMode >= 0 && q24FilterMode <= 3 ? q24FilterMode : q28FilterMode != null && q28FilterMode >= 0 && q28FilterMode <= 3 ? q28FilterMode : q32FilterMode != null && q32FilterMode >= 0 && q32FilterMode <= 3 ? q32FilterMode : q24FilterMode;
|
|
4731
|
-
return {
|
|
4732
|
-
pickBase,
|
|
4733
|
-
pickDeltaBase: q20,
|
|
4734
|
-
placeBase,
|
|
4735
|
-
placeDeltaBase: loader.q24 ?? 0,
|
|
4736
|
-
priority,
|
|
4737
|
-
stack: loader.q32 == null ? null : 16 + loader.q36,
|
|
4738
|
-
cycle: (loader.q40 ?? loader.q44) / 20 + 1,
|
|
4739
|
-
cycleMode: loader.q44 != null && loader.q40 == null ? "q44-q36-delta" : "offset",
|
|
4740
|
-
filterMode,
|
|
4741
|
-
q32
|
|
4742
|
-
};
|
|
4743
|
-
}
|
|
4744
|
-
#applyLoaderBaseline(key, loader, baseline) {
|
|
4745
|
-
this.pickBases.set(key, baseline.pickBase);
|
|
4746
|
-
this.pickDeltaBases.set(key, baseline.pickDeltaBase);
|
|
4747
|
-
this.placeBases.set(key, baseline.placeBase);
|
|
4748
|
-
this.placeDeltaBases.set(key, baseline.placeDeltaBase);
|
|
4749
|
-
this.sparsePositionBaselines.delete(key);
|
|
4750
|
-
this.#setCurrentPosition(key, loader);
|
|
4751
|
-
if (baseline.filterMode != null) {
|
|
4752
|
-
this.filterModes.set(key, baseline.filterMode);
|
|
4753
|
-
if (baseline.filterField) this.filterSources.set(key, baseline.filterField);
|
|
4754
|
-
else this.filterSources.delete(key);
|
|
4755
|
-
}
|
|
4756
|
-
if (baseline.stack != null) {
|
|
4757
|
-
const stackField = baseline.stackField === "fixed" ? 0 : baseline.stackField ? loader[baseline.stackField] ?? 0 : baseline.q32;
|
|
4758
|
-
this.stackBases.set(key, baseline.stack - stackField);
|
|
4759
|
-
if (baseline.stackField) this.stackSources.set(key, baseline.stackField);
|
|
4760
|
-
else this.stackSources.delete(key);
|
|
4761
|
-
}
|
|
4762
|
-
this.cycleModes.set(key, baseline.cycleMode);
|
|
4763
|
-
if (baseline.cycleMode === "direct") {
|
|
4764
|
-
this.cycleDeltaBases.set(key, 0);
|
|
4765
|
-
this.directCycleValues.set(key, loader.q44 ?? loader.q36);
|
|
4766
|
-
this.directCycleFields.set(key, loader.q44 == null ? "q36" : "q44");
|
|
4767
|
-
} else if (baseline.cycleMode === "q44-q36-delta") {
|
|
4768
|
-
this.cycleDeltaBases.set(key, loader.q36 ?? 0);
|
|
4769
|
-
this.directCycleValues.set(key, loader.q44);
|
|
4770
|
-
this.directCycleFields.set(key, "q44");
|
|
4771
|
-
} else if (baseline.cycleMode === "q40-direct") {
|
|
4772
|
-
this.cycleDeltaBases.set(key, 0);
|
|
4773
|
-
this.directCycleValues.set(key, loader.q40);
|
|
4774
|
-
this.directCycleFields.set(key, "q40");
|
|
4775
|
-
} else {
|
|
4776
|
-
this.cycleDeltaBases.set(key, loader.q36 ?? 0);
|
|
4777
|
-
this.directCycleValues.delete(key);
|
|
4778
|
-
this.directCycleFields.delete(key);
|
|
4779
|
-
}
|
|
4780
|
-
this.cycles.set(key, baseline.cycle);
|
|
4781
|
-
if (baseline.priority != null && baseline.priority >= -1 && baseline.priority <= 1) {
|
|
4782
|
-
if (loader.q28 != null) this.priorityOffsets.set(key, baseline.priority - loader.q28);
|
|
4783
|
-
this.priorities.set(key, baseline.priority);
|
|
4784
|
-
} else if (loader.q28 != null && loader.q36 != null) this.#initializePriorityOffset(key, loader);
|
|
4785
|
-
}
|
|
4786
|
-
#applySemanticDelta(worldId, entityId, loader, mask, previous, deltaRecord) {
|
|
4787
|
-
const key = this.#key(worldId, entityId);
|
|
4788
|
-
const delta = decodeLoaderSemanticDeltaRecord(deltaRecord ?? loaderDeltaRecord(loader, mask, previous), mask);
|
|
4789
|
-
if (!delta) return false;
|
|
4790
|
-
const previousConfig = this.getConfig(worldId, entityId, previous);
|
|
4791
|
-
const pick = delta.pick == null ? previousConfig.pick : wrapLoaderPosition((previousConfig.pick ?? DEFAULT_LOADER_PICK) + delta.pick);
|
|
4792
|
-
const place = delta.place == null ? previousConfig.place : wrapLoaderPosition((previousConfig.place ?? DEFAULT_LOADER_PLACE) + delta.place);
|
|
4793
|
-
if (pick != null) {
|
|
4794
|
-
this.pickBases.set(key, pick);
|
|
4795
|
-
this.pickDeltaBases.set(key, loader?.q20 ?? 0);
|
|
4796
|
-
this.currentPicks.set(key, pick);
|
|
4797
|
-
}
|
|
4798
|
-
if (place != null) {
|
|
4799
|
-
this.placeBases.set(key, place);
|
|
4800
|
-
this.placeDeltaBases.set(key, loader?.q24 ?? 0);
|
|
4801
|
-
this.currentPlaces.set(key, place);
|
|
4802
|
-
}
|
|
4803
|
-
if (delta.priority != null) {
|
|
4804
|
-
const priority = previousConfig.priority + delta.priority;
|
|
4805
|
-
this.priorities.set(key, priority);
|
|
4806
|
-
if (loader?.q28 != null) this.priorityOffsets.set(key, priority - loader.q28);
|
|
4807
|
-
else this.priorityOffsets.delete(key);
|
|
4808
|
-
}
|
|
4809
|
-
if (delta.stack != null) {
|
|
4810
|
-
this.stackBases.set(key, previousConfig.stack + delta.stack);
|
|
4811
|
-
this.stackSources.set(key, "fixed");
|
|
4812
|
-
}
|
|
4813
|
-
if (delta.cycleTicks != null) {
|
|
4814
|
-
this.cycles.set(key, previousConfig.cycle + delta.cycleTicks / 20);
|
|
4815
|
-
if (loader?.q44 != null && loader.q40 == null) {
|
|
4816
|
-
this.cycleModes.set(key, "q44-q36-delta");
|
|
4817
|
-
this.cycleDeltaBases.set(key, loader.q36 ?? 0);
|
|
4818
|
-
this.directCycleValues.set(key, loader.q44);
|
|
4819
|
-
this.directCycleFields.set(key, "q44");
|
|
4820
|
-
} else {
|
|
4821
|
-
this.cycleModes.set(key, "offset");
|
|
4822
|
-
this.cycleDeltaBases.set(key, loader?.q36 ?? 0);
|
|
4823
|
-
this.directCycleValues.delete(key);
|
|
4824
|
-
this.directCycleFields.delete(key);
|
|
4825
|
-
}
|
|
4826
|
-
}
|
|
4827
|
-
if (delta.requireOutput) this.requireOutputs.set(key, !previousConfig.requireOutput);
|
|
4828
|
-
if (delta.waitForStack) this.waitForStacks.set(key, !previousConfig.waitForStack);
|
|
4829
|
-
this.sparsePositionBaselines.delete(key);
|
|
4830
|
-
return true;
|
|
4831
|
-
}
|
|
4832
|
-
#setCurrentPosition(key, loader) {
|
|
4833
|
-
const pick = this.#pick(key, loader);
|
|
4834
|
-
const place = this.#place(key, loader);
|
|
4835
|
-
if (pick != null) this.currentPicks.set(key, pick);
|
|
4836
|
-
if (place != null) this.currentPlaces.set(key, place);
|
|
4837
|
-
}
|
|
4838
|
-
#pick(key, loader) {
|
|
4839
|
-
if (!loader) return null;
|
|
4840
|
-
if (this.pickBases.has(key)) return wrapLoaderPosition(this.pickBases.get(key) + ((loader.q20 ?? 0) - (this.pickDeltaBases.get(key) ?? 0)));
|
|
4841
|
-
if (loader.q24 != null) return wrapLoaderPosition(loader.q24 + 3);
|
|
4842
|
-
if (loader.q36 != null) return wrapLoaderPosition(loader.q36 + 3);
|
|
4843
|
-
if (loader.q20 != null) return wrapLoaderPosition(loader.q20);
|
|
4844
|
-
return null;
|
|
4845
|
-
}
|
|
4846
|
-
#place(key, loader) {
|
|
4847
|
-
if (!loader) return null;
|
|
4848
|
-
if (this.placeBases.has(key)) {
|
|
4849
|
-
const base = this.placeBases.get(key);
|
|
4850
|
-
if (loader.q24 != null && this.placeDeltaBases.has(key)) {
|
|
4851
|
-
return wrapLoaderPosition(base + (loader.q24 - this.placeDeltaBases.get(key)));
|
|
4852
|
-
}
|
|
4853
|
-
return wrapLoaderPosition(base);
|
|
4854
|
-
}
|
|
4855
|
-
if (loader.q36 != null) return loader.q24 == null ? 4 : wrapLoaderPosition(loader.q36 + 4);
|
|
4856
|
-
return null;
|
|
4857
|
-
}
|
|
4858
|
-
#key(worldId, entityId) {
|
|
4859
|
-
return `${worldId ?? "-"}:${entityId}`;
|
|
4860
|
-
}
|
|
4861
|
-
};
|
|
4862
4155
|
|
|
4863
4156
|
// src/state/overworld.js
|
|
4864
4157
|
var OVERWORLD_ZONES = Object.freeze([
|
|
@@ -5308,8 +4601,8 @@
|
|
|
5308
4601
|
if (end > reader.bytes.length) return false;
|
|
5309
4602
|
const blob = reader.bytes.slice(peek.offset, end);
|
|
5310
4603
|
try {
|
|
5311
|
-
const
|
|
5312
|
-
return
|
|
4604
|
+
const text2 = decoder.decode(blob);
|
|
4605
|
+
return text2.length > 0 && !/[\u0000-\u0008\u000e-\u001f]/.test(text2);
|
|
5313
4606
|
} catch (_) {
|
|
5314
4607
|
return false;
|
|
5315
4608
|
}
|
|
@@ -5501,6 +4794,7 @@
|
|
|
5501
4794
|
}],
|
|
5502
4795
|
[55, {
|
|
5503
4796
|
name: "player",
|
|
4797
|
+
defaults: { q20: 1, q60: 10, q64: 10, q68: 10 },
|
|
5504
4798
|
packedBeforeValues: true,
|
|
5505
4799
|
fields: numericFields({
|
|
5506
4800
|
256: 20,
|
|
@@ -5535,8 +4829,10 @@
|
|
|
5535
4829
|
]
|
|
5536
4830
|
}],
|
|
5537
4831
|
[56, {
|
|
5538
|
-
name: "
|
|
5539
|
-
|
|
4832
|
+
name: "player_appearance",
|
|
4833
|
+
// Official StateOutfit: four body colors, then four color/style pairs.
|
|
4834
|
+
defaults: { q20: 0, q24: 0, q28: 0, q32: 0, q36: 0, q40: 0, q44: 0, q48: 0, q52: 0, q56: 0, q60: 0, q64: 0 },
|
|
4835
|
+
fields: numericFields({ 1: 20, 2: 24, 4: 28, 8: 32, 16: 36, 32: 40, 64: 44, 128: 48, 256: 52, 512: 56, 1024: 60, 2048: 64 })
|
|
5540
4836
|
}],
|
|
5541
4837
|
[59, { name: "numeric_sparse", fields: numericFields({ 1: 20, 2: 24, 4: 28, 8: 32, 16: 36 }) }],
|
|
5542
4838
|
[60, { name: "fluid_tank", packedBits: [{ bit: 4, offset: 29 }], ...TWO_FIELD_SPEC }],
|
|
@@ -5545,7 +4841,11 @@
|
|
|
5545
4841
|
[63, { name: "numeric_pair", ...TWO_FIELD_SPEC }],
|
|
5546
4842
|
[67, { name: "numeric_single", fields: numericFields({ 1: 20 }) }],
|
|
5547
4843
|
[69, {
|
|
5548
|
-
name: "
|
|
4844
|
+
name: "loader_config",
|
|
4845
|
+
// The official loader component starts with these values. Wire section
|
|
4846
|
+
// 162 sends a packed absolute flag word before the five numeric deltas.
|
|
4847
|
+
defaults: { q20: 3, q24: 4, q28: 1, q32: 16, q36: 20, q41: 0, q42: 0 },
|
|
4848
|
+
packedBeforeValues: true,
|
|
5549
4849
|
packedBits: [{ bit: 32, offset: 41 }, { bit: 64, offset: 42 }],
|
|
5550
4850
|
fields: numericFields({ 1: 20, 2: 24, 4: 28, 8: 32, 16: 36 })
|
|
5551
4851
|
}],
|
|
@@ -5661,7 +4961,8 @@
|
|
|
5661
4961
|
[158, 75],
|
|
5662
4962
|
[160, 76],
|
|
5663
4963
|
[161, 77],
|
|
5664
|
-
[162,
|
|
4964
|
+
[162, 69],
|
|
4965
|
+
// Loader configuration; distinct from navigation state (168).
|
|
5665
4966
|
[163, 72],
|
|
5666
4967
|
[164, 73],
|
|
5667
4968
|
[165, 74],
|
|
@@ -5835,27 +5136,6 @@
|
|
|
5835
5136
|
}
|
|
5836
5137
|
return null;
|
|
5837
5138
|
}
|
|
5838
|
-
var TABLE_78_FIELD_BITS = [
|
|
5839
|
-
["q20", 1],
|
|
5840
|
-
["q24", 2],
|
|
5841
|
-
["q28", 4],
|
|
5842
|
-
["q32", 8],
|
|
5843
|
-
["q36", 16],
|
|
5844
|
-
["q40", 32],
|
|
5845
|
-
["q44", 64]
|
|
5846
|
-
];
|
|
5847
|
-
function table78DeltaRecord(changed) {
|
|
5848
|
-
const record = { lastMask: changed.mask };
|
|
5849
|
-
for (const [field, bit] of TABLE_78_FIELD_BITS) {
|
|
5850
|
-
if (!(changed.mask & bit)) continue;
|
|
5851
|
-
if (field === "q44" && (changed.mask & 32 || changed.record?.q44 == null)) continue;
|
|
5852
|
-
record[field] = (changed.record?.[field] ?? 0) - (changed.previous?.[field] ?? 0);
|
|
5853
|
-
}
|
|
5854
|
-
return record;
|
|
5855
|
-
}
|
|
5856
|
-
function isSemanticLoaderDelta2(changed, full) {
|
|
5857
|
-
return !full && changed.previous != null && (changed.mask & 96) === 96;
|
|
5858
|
-
}
|
|
5859
5139
|
function decodeText(blob) {
|
|
5860
5140
|
if (!(blob instanceof Uint8Array)) return null;
|
|
5861
5141
|
try {
|
|
@@ -5927,10 +5207,16 @@
|
|
|
5927
5207
|
active: record?.q33 == null ? null : Boolean(record.q33)
|
|
5928
5208
|
};
|
|
5929
5209
|
}
|
|
5930
|
-
function summarizeCannon(entity, record, typeId = null) {
|
|
5210
|
+
function summarizeCannon(entity, record, typeId = null, transformRecord = null) {
|
|
5931
5211
|
if (!record || !CANNON_TYPE_IDS.has(typeId)) return null;
|
|
5212
|
+
const relativeAngleRadians = numberOrNull(record.q32, 200);
|
|
5213
|
+
const mountingAngleRadians = numberOrNull(transformRecord?.q28, 127.324);
|
|
5214
|
+
const tau = 2 * Math.PI;
|
|
5215
|
+
const absoluteAngleRadians = relativeAngleRadians == null || mountingAngleRadians == null ? null : ((mountingAngleRadians + relativeAngleRadians) % tau + tau) % tau;
|
|
5932
5216
|
const ammoItemId = record.q24 == null ? null : CANNON_AMMO_COLOR_ITEM_IDS.get(record.q24) ?? null;
|
|
5933
|
-
const
|
|
5217
|
+
const indicatorValue = (record.q40 ?? 0) / 50;
|
|
5218
|
+
const indicatorVisible = indicatorValue >= 1;
|
|
5219
|
+
const indicatorBlinking = indicatorValue === 4;
|
|
5934
5220
|
const recoil = record.q36 ?? null;
|
|
5935
5221
|
const recoil2 = record.q48 ?? null;
|
|
5936
5222
|
return {
|
|
@@ -5940,17 +5226,26 @@
|
|
|
5940
5226
|
ammoItemId,
|
|
5941
5227
|
ammoName: entityNameFromType(ammoItemId),
|
|
5942
5228
|
ammoCount: record.q28 ?? 0,
|
|
5943
|
-
|
|
5229
|
+
relativeAngleRadians,
|
|
5230
|
+
absoluteAngleRadians,
|
|
5944
5231
|
recoil,
|
|
5945
5232
|
recoil2,
|
|
5946
5233
|
recoils: [recoil, recoil2],
|
|
5947
|
-
|
|
5948
|
-
|
|
5234
|
+
indicatorValue,
|
|
5235
|
+
indicatorVisible,
|
|
5236
|
+
indicatorColor: !indicatorVisible ? null : indicatorBlinking ? 16711680 : cannonIndicatorColor(indicatorValue),
|
|
5237
|
+
indicatorBlinking,
|
|
5238
|
+
indicatorBlinkColor: indicatorBlinking ? 16776960 : null,
|
|
5949
5239
|
spin: record.q52 ?? null,
|
|
5950
|
-
|
|
5240
|
+
resourceCount: record.q56 ?? 0,
|
|
5951
5241
|
state: cloneRecord(record)
|
|
5952
5242
|
};
|
|
5953
5243
|
}
|
|
5244
|
+
function cannonIndicatorColor(value) {
|
|
5245
|
+
const distance = Math.abs(Math.fround(2 - Math.fround(value)));
|
|
5246
|
+
const channel = Math.max(0, Math.min(255, Math.trunc(Math.fround(Math.fround(1 - distance) * 255))));
|
|
5247
|
+
return value < 2 ? channel << 16 | 65280 : 16711680 | channel << 8;
|
|
5248
|
+
}
|
|
5954
5249
|
function summarizeThruster(entity, typeId, record) {
|
|
5955
5250
|
if (!THRUSTER_TYPE_IDS.has(typeId)) return null;
|
|
5956
5251
|
const facing = Number.isFinite(Number(record?.q20)) ? Number(record.q20) : 0;
|
|
@@ -6316,15 +5611,13 @@
|
|
|
6316
5611
|
state: cloneRecord(markerRecord)
|
|
6317
5612
|
};
|
|
6318
5613
|
}
|
|
6319
|
-
function summarizeLoader(entity, loaderRecord, loaderFilterRecord = null, filterSlotsRecord = null,
|
|
5614
|
+
function summarizeLoader(entity, loaderRecord, loaderFilterRecord = null, filterSlotsRecord = null, includeDefaults = false, itemHolderRecord = null) {
|
|
6320
5615
|
if (!loaderRecord && !loaderFilterRecord && !includeDefaults) return null;
|
|
6321
|
-
const
|
|
6322
|
-
const
|
|
6323
|
-
const
|
|
6324
|
-
const
|
|
6325
|
-
const
|
|
6326
|
-
const priority = config.priority ?? 0;
|
|
6327
|
-
const filterMode = config.filterMode ?? null;
|
|
5616
|
+
const loader = { ...MODEL_TABLE_SPECS.get(69).defaults, ...loaderRecord };
|
|
5617
|
+
const pick = loader.q20;
|
|
5618
|
+
const place = loader.q24;
|
|
5619
|
+
const priority = loader.q28 - 1;
|
|
5620
|
+
const filterMode = loaderFilterRecord?.q20 ?? 0;
|
|
6328
5621
|
const heldItem = itemSummary(itemHolderRecord?.q20, itemHolderRecord?.q24 ?? null);
|
|
6329
5622
|
return {
|
|
6330
5623
|
entity,
|
|
@@ -6334,13 +5627,13 @@
|
|
|
6334
5627
|
placeName: enumValueName(LOADER_POSITION_NAMES, place),
|
|
6335
5628
|
priority,
|
|
6336
5629
|
priorityName: enumValueName(LOADER_PRIORITY_NAMES, priority),
|
|
6337
|
-
requireOutput:
|
|
6338
|
-
waitForStack:
|
|
6339
|
-
stack:
|
|
6340
|
-
cycle:
|
|
5630
|
+
requireOutput: Boolean(loader.q41),
|
|
5631
|
+
waitForStack: Boolean(loader.q42),
|
|
5632
|
+
stack: loader.q32,
|
|
5633
|
+
cycle: loader.q36 / 20,
|
|
6341
5634
|
filterMode,
|
|
6342
5635
|
filterModeName: enumValueName(LOADER_FILTER_MODE_NAMES, filterMode),
|
|
6343
|
-
filterSlots:
|
|
5636
|
+
filterSlots: filterSlotsRecord ? [filterSlotsRecord.q20, filterSlotsRecord.q24, filterSlotsRecord.q28].map((value) => value || null) : null,
|
|
6344
5637
|
heldItemId: heldItem.itemId,
|
|
6345
5638
|
heldItemName: heldItem.itemName,
|
|
6346
5639
|
heldCount: heldItem.count,
|
|
@@ -6378,7 +5671,7 @@
|
|
|
6378
5671
|
filteredModeName: enumValueName(PUSHER_MODE_NAMES, filteredMode),
|
|
6379
5672
|
angle: numberOrNull(pusherRecord.q28, 10),
|
|
6380
5673
|
speed: pusherRecord.q32 == null ? 20 : pusherRecord.q32 / 100 + 20,
|
|
6381
|
-
length:
|
|
5674
|
+
length: 1e3 + (pusherRecord.q40 ?? 0) / 10,
|
|
6382
5675
|
filterInventory: pusherRecord.q36 === 1,
|
|
6383
5676
|
filterSlots: filterSlotsRecord ? [filterSlotsRecord.q20 ?? null, filterSlotsRecord.q24 ?? null, filterSlotsRecord.q28 ?? null] : null,
|
|
6384
5677
|
state: cloneRecord(pusherRecord),
|
|
@@ -6530,7 +5823,36 @@
|
|
|
6530
5823
|
state: cloneRecord(record)
|
|
6531
5824
|
};
|
|
6532
5825
|
}
|
|
6533
|
-
function
|
|
5826
|
+
function summarizePlayerAppearance(record, player) {
|
|
5827
|
+
if (!record) return null;
|
|
5828
|
+
const style = (colorOffset, styleOffset) => ({
|
|
5829
|
+
color: record[qKey(colorOffset)] ?? 0,
|
|
5830
|
+
styleId: record[qKey(styleOffset)] ?? 0
|
|
5831
|
+
});
|
|
5832
|
+
const override = (offset) => {
|
|
5833
|
+
const id = player[qKey(offset)] ?? 0;
|
|
5834
|
+
return id === 0 ? null : { itemId: id, itemName: entityNameFromType(id) };
|
|
5835
|
+
};
|
|
5836
|
+
return {
|
|
5837
|
+
bodyColor: record.q20 ?? 0,
|
|
5838
|
+
legsColor: record.q24 ?? 0,
|
|
5839
|
+
skinColor: record.q28 ?? 0,
|
|
5840
|
+
feetColor: record.q32 ?? 0,
|
|
5841
|
+
hair: style(36, 40),
|
|
5842
|
+
hat: style(44, 48),
|
|
5843
|
+
face1: style(52, 56),
|
|
5844
|
+
face2: style(60, 64),
|
|
5845
|
+
itemOverrides: {
|
|
5846
|
+
back: override(36),
|
|
5847
|
+
hands: override(40),
|
|
5848
|
+
feet: override(44),
|
|
5849
|
+
head1: override(48),
|
|
5850
|
+
head2: override(52)
|
|
5851
|
+
},
|
|
5852
|
+
state: cloneRecord(record)
|
|
5853
|
+
};
|
|
5854
|
+
}
|
|
5855
|
+
function summarizePlayer(entity, record, previewRecord = null, blueprintItems = [], appearanceRecord = null, localPlayerEntity = null) {
|
|
6534
5856
|
if (!record) return null;
|
|
6535
5857
|
const rawHeldItemId = record.q28 == null ? null : Number(record.q28);
|
|
6536
5858
|
const heldItemId = Number.isFinite(rawHeldItemId) && rawHeldItemId !== 0 ? rawHeldItemId : null;
|
|
@@ -6541,14 +5863,29 @@
|
|
|
6541
5863
|
name: decodeText(record.blob92),
|
|
6542
5864
|
heldItemId,
|
|
6543
5865
|
heldItemName: entityNameFromType(heldItemId),
|
|
6544
|
-
|
|
6545
|
-
|
|
5866
|
+
itemMode: record.q32 ?? null,
|
|
5867
|
+
buildMultiplier: numberOrNull(record.q68, 10),
|
|
5868
|
+
heldItemBeamDistance: numberOrNull(record.q56, 10),
|
|
5869
|
+
heldItemAngle: numberOrNull(record.q80, 200),
|
|
6546
5870
|
shipRank: PLAYER_SHIP_RANKS.get(teamRank) || null,
|
|
6547
5871
|
patronTier: patronTierName(gameRank),
|
|
6548
5872
|
isDeveloper: gameRank === 1,
|
|
6549
5873
|
isPatron: gameRank >= 2 && gameRank <= 6,
|
|
6550
|
-
|
|
5874
|
+
isLocal: entity === localPlayerEntity,
|
|
5875
|
+
zoomedOut: Boolean(record.q107),
|
|
6551
5876
|
muted: Boolean(record.q112),
|
|
5877
|
+
invisible: Boolean(record.q106),
|
|
5878
|
+
cheats: {
|
|
5879
|
+
noclip: Boolean(record.q105),
|
|
5880
|
+
sandboxBuild: Boolean(record.q108)
|
|
5881
|
+
},
|
|
5882
|
+
itemEffectActive: Boolean(record.q111),
|
|
5883
|
+
animation: {
|
|
5884
|
+
facing: record.q20 ?? 1,
|
|
5885
|
+
orientation: record.q24 ?? 0,
|
|
5886
|
+
walking: Boolean(record.q109)
|
|
5887
|
+
},
|
|
5888
|
+
appearance: summarizePlayerAppearance(appearanceRecord, record),
|
|
6552
5889
|
actionPreview: summarizePlayerPreview(entity, previewRecord, blueprintItems),
|
|
6553
5890
|
state: cloneRecord(record)
|
|
6554
5891
|
};
|
|
@@ -6731,9 +6068,6 @@
|
|
|
6731
6068
|
blobKey: blobKey2,
|
|
6732
6069
|
cloneRecord: cloneRecord2,
|
|
6733
6070
|
firstRecord: firstRecord2,
|
|
6734
|
-
TABLE_78_FIELD_BITS: TABLE_78_FIELD_BITS2,
|
|
6735
|
-
table78DeltaRecord: table78DeltaRecord2,
|
|
6736
|
-
isSemanticLoaderDelta: isSemanticLoaderDelta3,
|
|
6737
6071
|
decodeText: decodeText2,
|
|
6738
6072
|
entityNameFromType: entityNameFromType2,
|
|
6739
6073
|
markerTypeIdForTables: markerTypeIdForTables2,
|
|
@@ -6809,7 +6143,7 @@
|
|
|
6809
6143
|
defineLazyProperty: defineLazyProperty2
|
|
6810
6144
|
} = decoder_exports;
|
|
6811
6145
|
var ModelState = class {
|
|
6812
|
-
#
|
|
6146
|
+
#localPlayerEntity = null;
|
|
6813
6147
|
#blueprintItems = null;
|
|
6814
6148
|
#helmOccupied = /* @__PURE__ */ new Map();
|
|
6815
6149
|
#commsStationOccupied = /* @__PURE__ */ new Map();
|
|
@@ -6831,6 +6165,16 @@
|
|
|
6831
6165
|
this.isOverworld = next;
|
|
6832
6166
|
this.#invalidateDerived();
|
|
6833
6167
|
}
|
|
6168
|
+
get localPlayerEntity() {
|
|
6169
|
+
return this.#localPlayerEntity;
|
|
6170
|
+
}
|
|
6171
|
+
setLocalPlayerEntity(entity) {
|
|
6172
|
+
const next = entity == null ? null : Number(entity);
|
|
6173
|
+
if (next !== null && (!Number.isInteger(next) || next < 0)) throw new RangeError("local player entity must be a non-negative integer or null");
|
|
6174
|
+
if (this.#localPlayerEntity === next) return;
|
|
6175
|
+
this.#localPlayerEntity = next;
|
|
6176
|
+
this.#invalidateDerived();
|
|
6177
|
+
}
|
|
6834
6178
|
table(id) {
|
|
6835
6179
|
return this.tables.get(Number(id)) || EMPTY_TABLE2;
|
|
6836
6180
|
}
|
|
@@ -6898,8 +6242,6 @@
|
|
|
6898
6242
|
this.totalErrorCount += 1;
|
|
6899
6243
|
pushCapped2(this.errors, { message: error.message, generation: update.generation }, MAX_RETAINED_ERRORS2);
|
|
6900
6244
|
}
|
|
6901
|
-
this.#remapIndexedLoaderConfig(update);
|
|
6902
|
-
this.#updateLoaderConfig(update);
|
|
6903
6245
|
this.#updateNavigationUnitAutoWarp(update);
|
|
6904
6246
|
this.#updateHelmOccupancy(update);
|
|
6905
6247
|
this.#updateCommsStationOccupancy(update);
|
|
@@ -7001,53 +6343,6 @@
|
|
|
7001
6343
|
this._derived.summariesDirty = true;
|
|
7002
6344
|
this._derived.tableSummariesDirty = true;
|
|
7003
6345
|
}
|
|
7004
|
-
#updateLoaderConfig(update) {
|
|
7005
|
-
const seenEntities = /* @__PURE__ */ new Set();
|
|
7006
|
-
for (const section of update.sections || []) {
|
|
7007
|
-
if (section.table !== 78) continue;
|
|
7008
|
-
for (const changed of section.records || []) {
|
|
7009
|
-
if (changed.indexedLoaderConfig) {
|
|
7010
|
-
this.#loaderConfig.updateIndexedSnapshotRecord(null, changed.entity, changed.record, changed.mask, changed.cumulativeRecord, changed.configEntity);
|
|
7011
|
-
continue;
|
|
7012
|
-
}
|
|
7013
|
-
const typeId = entityTypeIdFromRecord2(this.record(7, changed.entity));
|
|
7014
|
-
this.#loaderConfig.updateRecord(null, changed.entity, changed.record ?? this.record(78, changed.entity), changed.mask, changed.previous, {
|
|
7015
|
-
repeatedInUpdate: seenEntities.has(changed.entity),
|
|
7016
|
-
allowSparseBaseline: typeId === LOADER_TYPE_ID2,
|
|
7017
|
-
repeatedInSection: changed.repeatedInSection,
|
|
7018
|
-
semanticSnapshot: Boolean(update.full),
|
|
7019
|
-
semanticDelta: isSemanticLoaderDelta3(changed, update.full),
|
|
7020
|
-
deltaRecord: table78DeltaRecord2(changed)
|
|
7021
|
-
});
|
|
7022
|
-
seenEntities.add(changed.entity);
|
|
7023
|
-
}
|
|
7024
|
-
}
|
|
7025
|
-
}
|
|
7026
|
-
#remapIndexedLoaderConfig(update) {
|
|
7027
|
-
if (!update.full || update.error) return;
|
|
7028
|
-
const rows = [];
|
|
7029
|
-
for (const section of update.sections || []) {
|
|
7030
|
-
if (section.table !== 78) continue;
|
|
7031
|
-
for (const changed of section.records || []) rows.push(changed);
|
|
7032
|
-
}
|
|
7033
|
-
if (!rows.length) return;
|
|
7034
|
-
const loaderIds = [...this.table(7).entries()].filter(([, record]) => entityTypeIdFromRecord2(record) === LOADER_TYPE_ID2).map(([entity]) => entity).sort((a, b) => a - b);
|
|
7035
|
-
if (loaderIds.length !== rows.length) return;
|
|
7036
|
-
if (rows.every((row, index) => row.entity === loaderIds[index])) return;
|
|
7037
|
-
const remappedTable = /* @__PURE__ */ new Map();
|
|
7038
|
-
for (const [index, changed] of rows.entries()) {
|
|
7039
|
-
const rawRecord = table78DeltaRecord2(changed);
|
|
7040
|
-
changed.configEntity = changed.entity;
|
|
7041
|
-
changed.entity = loaderIds[index];
|
|
7042
|
-
changed.cumulativeRecord = cloneRecord2(changed.record || {});
|
|
7043
|
-
changed.record = cloneRecord2(rawRecord);
|
|
7044
|
-
delete changed.previous;
|
|
7045
|
-
changed.indexedLoaderConfig = true;
|
|
7046
|
-
remappedTable.set(changed.entity, cloneRecord2(rawRecord));
|
|
7047
|
-
update.changedEntities.add(changed.entity);
|
|
7048
|
-
}
|
|
7049
|
-
this.tables.set(78, remappedTable);
|
|
7050
|
-
}
|
|
7051
6346
|
#updateNavigationUnitAutoWarp(update) {
|
|
7052
6347
|
const trackedBeforeUpdate = new Set(this.#navigationUnitAutoWarp.keys());
|
|
7053
6348
|
const initializedThisUpdate = /* @__PURE__ */ new Set();
|
|
@@ -7118,25 +6413,25 @@
|
|
|
7118
6413
|
#updateHelmOccupancy(update) {
|
|
7119
6414
|
const table7 = update.sections.find((section) => section.table === 7);
|
|
7120
6415
|
if (!table7) return;
|
|
7121
|
-
const
|
|
6416
|
+
const changedZoomState = /* @__PURE__ */ new Map();
|
|
7122
6417
|
for (const section of update.sections) {
|
|
7123
6418
|
if (section.table !== 55) continue;
|
|
7124
6419
|
for (const changed of section.records) {
|
|
7125
6420
|
if (!(changed.mask & 16)) continue;
|
|
7126
6421
|
const player = this.record(55, changed.entity);
|
|
7127
|
-
|
|
6422
|
+
changedZoomState.set(changed.entity, Boolean(player?.q107));
|
|
7128
6423
|
}
|
|
7129
6424
|
}
|
|
7130
|
-
const
|
|
6425
|
+
const zoomedOutPlayerCount = [...this.table(55).values()].filter((record) => record?.q107).length;
|
|
7131
6426
|
for (const changed of table7.records) {
|
|
7132
6427
|
const record = this.record(7, changed.entity);
|
|
7133
6428
|
const typeId = entityTypeIdFromRecord2(record);
|
|
7134
6429
|
if (!HELM_TYPE_IDS2.has(typeId)) continue;
|
|
7135
|
-
if (
|
|
6430
|
+
if (zoomedOutPlayerCount > 0 && record?.q20 === 0 && HELM_TYPE_IDS2.has(Number(record?.q32))) {
|
|
7136
6431
|
this.#helmOccupied.set(changed.entity, true);
|
|
7137
6432
|
}
|
|
7138
|
-
if (!(changed.mask & 8) ||
|
|
7139
|
-
this.#helmOccupied.set(changed.entity, [...
|
|
6433
|
+
if (!(changed.mask & 8) || changedZoomState.size === 0) continue;
|
|
6434
|
+
this.#helmOccupied.set(changed.entity, [...changedZoomState.values()].some(Boolean));
|
|
7140
6435
|
}
|
|
7141
6436
|
}
|
|
7142
6437
|
#updateCommsStationOccupancy(update) {
|
|
@@ -7414,7 +6709,8 @@
|
|
|
7414
6709
|
const pusherRecord = rec(72);
|
|
7415
6710
|
const pusherBeamRecord = rec(42);
|
|
7416
6711
|
const launcherRecord = rec(44);
|
|
7417
|
-
const loaderRecord = rec(
|
|
6712
|
+
const loaderRecord = rec(69);
|
|
6713
|
+
const navigationRecord = rec(78);
|
|
7418
6714
|
const loaderFilterRecord = rec(76);
|
|
7419
6715
|
const loaderFilterSlotsRecord = rec(77);
|
|
7420
6716
|
const commsStationRecord = rec(39);
|
|
@@ -7449,14 +6745,14 @@
|
|
|
7449
6745
|
const health = summarizeHealth2(entityId, healthRecord);
|
|
7450
6746
|
const fabricator = summarizeFabricator2(entityId, fabricatorRecord, itemHolderRecord, typeRecord);
|
|
7451
6747
|
const cargoEjector = summarizeCargoEjector2(entityId, typeId, cargoEjectorRecord);
|
|
7452
|
-
const cannon = summarizeCannon2(entityId, cannonRecord, typeId);
|
|
6748
|
+
const cannon = summarizeCannon2(entityId, cannonRecord, typeId, transformRecord);
|
|
7453
6749
|
const thruster = summarizeThruster2(entityId, typeId, thrusterRecord);
|
|
7454
6750
|
const pusher = summarizePusher2(entityId, pusherRecord, loaderFilterSlotsRecord);
|
|
7455
6751
|
const pusherBeam = summarizePusherBeam2(entityId, pusherBeamRecord);
|
|
7456
6752
|
const launcher = summarizeItemLauncher2(entityId, typeId, launcherRecord);
|
|
7457
|
-
const loader = typeId === LOADER_TYPE_ID2 || typeId == null && (loaderRecord || loaderFilterRecord || loaderFilterSlotsRecord) ? summarizeLoader2(entityId, loaderRecord, loaderFilterRecord, loaderFilterSlotsRecord,
|
|
6753
|
+
const loader = typeId === LOADER_TYPE_ID2 || typeId == null && (loaderRecord || loaderFilterRecord || loaderFilterSlotsRecord) ? summarizeLoader2(entityId, loaderRecord, loaderFilterRecord, loaderFilterSlotsRecord, typeId === LOADER_TYPE_ID2, itemHolderRecord) : null;
|
|
7458
6754
|
const cargoHatch = summarizeCargoHatch2(entityId, typeId, loaderFilterRecord, loaderFilterSlotsRecord, rec(45));
|
|
7459
|
-
const navigationUnit = summarizeNavigationUnit2(entityId, typeId,
|
|
6755
|
+
const navigationUnit = summarizeNavigationUnit2(entityId, typeId, navigationRecord, this.#navigationUnitAutoWarp.get(entityId));
|
|
7460
6756
|
const fluidTank = fluidTankRecord ? {
|
|
7461
6757
|
entity: entityId,
|
|
7462
6758
|
amount: fluidTankRecord.q24 ?? null,
|
|
@@ -7465,7 +6761,7 @@
|
|
|
7465
6761
|
const shieldGenerator = typeId === 256 ? summarizeShieldGenerator2(entityId, shieldRecord, itemHolderRecord, shieldGeneratorBoostRecord) : null;
|
|
7466
6762
|
const shieldProjector = typeId === 257 ? summarizeShieldProjector2(entityId, shieldProjectorRecord) : null;
|
|
7467
6763
|
const blueprintPreview = summarizeBlueprintPreview2(entityId, blueprintPreviewRecord, transformRecord);
|
|
7468
|
-
const player = summarizePlayer2(entityId, playerRecord, rec(14), this.#blueprintPreviewItems());
|
|
6764
|
+
const player = summarizePlayer2(entityId, playerRecord, rec(14), this.#blueprintPreviewItems(), rec(56), this.#localPlayerEntity);
|
|
7469
6765
|
const shipControl = summarizeShipControl2(entityId, shipControlRecord);
|
|
7470
6766
|
const helm = summarizeHelm2(entityId, typeId, this.#helmOccupied.get(entityId));
|
|
7471
6767
|
const commsStation = summarizeCommsStation2(entityId, typeId, commsStationRecord, this.#commsStationOccupied.get(entityId));
|
|
@@ -7703,7 +6999,6 @@
|
|
|
7703
6999
|
} else {
|
|
7704
7000
|
for (const records of this.tables.values()) records.delete(entity);
|
|
7705
7001
|
}
|
|
7706
|
-
this.#loaderConfig.delete(null, entity);
|
|
7707
7002
|
this.#helmOccupied.delete(entity);
|
|
7708
7003
|
this.#commsStationOccupied.delete(entity);
|
|
7709
7004
|
this.#navigationUnitAutoWarp.delete(entity);
|
|
@@ -7719,7 +7014,6 @@
|
|
|
7719
7014
|
#readSectionRecords(reader, tag, tableId, spec) {
|
|
7720
7015
|
const section = { tag, table: tableId, name: spec?.name || null, records: [] };
|
|
7721
7016
|
let entity = 0;
|
|
7722
|
-
const seenEntities = tableId === 78 ? /* @__PURE__ */ new Set() : null;
|
|
7723
7017
|
while (reader.remaining > 0) {
|
|
7724
7018
|
const recordOffset = reader.offset;
|
|
7725
7019
|
let delta;
|
|
@@ -7737,7 +7031,6 @@
|
|
|
7737
7031
|
throw new Error(`model table ${tableId} tag ${tag} entity ${entity} mask offset ${reader.offset}: ${error.message}`);
|
|
7738
7032
|
}
|
|
7739
7033
|
const record = this.#getRecord(tableId, entity);
|
|
7740
|
-
const previous = tableId === 78 ? cloneRecord2(record) : null;
|
|
7741
7034
|
record.lastMask = mask;
|
|
7742
7035
|
try {
|
|
7743
7036
|
if (spec) this.#applyRecordSpec(reader, record, mask, spec);
|
|
@@ -7746,10 +7039,6 @@
|
|
|
7746
7039
|
throw new Error(`model table ${tableId} tag ${tag} entity ${entity} mask ${mask} offset ${reader.offset}: ${error.message}`);
|
|
7747
7040
|
}
|
|
7748
7041
|
const changed = { entity, mask };
|
|
7749
|
-
if (previous) changed.previous = previous;
|
|
7750
|
-
if (seenEntities?.has(entity)) changed.repeatedInSection = true;
|
|
7751
|
-
seenEntities?.add(entity);
|
|
7752
|
-
if (tableId === 78) changed.record = cloneRecord2(record);
|
|
7753
7042
|
section.records.push(changed);
|
|
7754
7043
|
}
|
|
7755
7044
|
return section;
|
|
@@ -7757,7 +7046,7 @@
|
|
|
7757
7046
|
#getRecord(tableId, entity) {
|
|
7758
7047
|
if (!this.tables.has(tableId)) this.tables.set(tableId, /* @__PURE__ */ new Map());
|
|
7759
7048
|
const records = this.tables.get(tableId);
|
|
7760
|
-
if (!records.has(entity)) records.set(entity, {});
|
|
7049
|
+
if (!records.has(entity)) records.set(entity, { ...MODEL_TABLE_SPECS2.get(tableId)?.defaults });
|
|
7761
7050
|
return records.get(entity);
|
|
7762
7051
|
}
|
|
7763
7052
|
#applyRecordSpec(reader, record, mask, spec) {
|
|
@@ -8289,6 +7578,7 @@
|
|
|
8289
7578
|
var WorldStore = class {
|
|
8290
7579
|
#overworldId = null;
|
|
8291
7580
|
#shipWorldId = null;
|
|
7581
|
+
#cameraFocus = null;
|
|
8292
7582
|
constructor(limits = {}) {
|
|
8293
7583
|
this.currentWorldId = null;
|
|
8294
7584
|
this.worlds = /* @__PURE__ */ new Map();
|
|
@@ -8305,6 +7595,17 @@
|
|
|
8305
7595
|
}
|
|
8306
7596
|
apply(packet) {
|
|
8307
7597
|
if (!packet || packet.world == null) return null;
|
|
7598
|
+
if (packet.type === 21) {
|
|
7599
|
+
if (this.#cameraFocus && this.#cameraFocus.world !== packet.world) {
|
|
7600
|
+
this.worlds.get(Number(this.#cameraFocus.world))?.model.setLocalPlayerEntity(null);
|
|
7601
|
+
}
|
|
7602
|
+
this.#cameraFocus = packet;
|
|
7603
|
+
this.currentWorldId = Number(packet.world);
|
|
7604
|
+
const world = this.get(packet.world);
|
|
7605
|
+
world.model.setLocalPlayerEntity(null);
|
|
7606
|
+
this.#resolveLocalPlayer(world);
|
|
7607
|
+
return { type: "camera-focus", world, packet };
|
|
7608
|
+
}
|
|
8308
7609
|
if (packet.type === 22) return this.#applyMeta(packet);
|
|
8309
7610
|
if (packet.type === 23) return this.#applyTiles(packet);
|
|
8310
7611
|
if (packet.type === 20) return this.#applyModel(packet);
|
|
@@ -8350,16 +7651,25 @@
|
|
|
8350
7651
|
if (!shipWorld || shipWorld.parentWorld == null || shipWorld.parentEntity == null) return null;
|
|
8351
7652
|
return this.worlds.get(Number(shipWorld.parentWorld))?.entity(shipWorld.parentEntity) || null;
|
|
8352
7653
|
}
|
|
7654
|
+
#resolveLocalPlayer(world) {
|
|
7655
|
+
if (!this.#cameraFocus || Number(this.#cameraFocus.world) !== world.id || world.seed == null) return;
|
|
7656
|
+
const focus = world.decodeEncrypted(this.#cameraFocus.data);
|
|
7657
|
+
if (Array.isArray(focus) && focus.length === 2 && Number.isInteger(focus[0]) && focus[0] >= 0 && focus[1] === 0) {
|
|
7658
|
+
world.model.setLocalPlayerEntity(focus[0]);
|
|
7659
|
+
}
|
|
7660
|
+
}
|
|
8353
7661
|
#applyMeta(packet) {
|
|
8354
7662
|
if (packet.removed) {
|
|
8355
7663
|
const world2 = this.worlds.get(Number(packet.world));
|
|
8356
7664
|
if (world2) world2.readMeta(packet);
|
|
8357
7665
|
this.worlds.delete(Number(packet.world));
|
|
7666
|
+
if (Number(this.#cameraFocus?.world) === Number(packet.world)) this.#cameraFocus = null;
|
|
8358
7667
|
if (this.currentWorldId === Number(packet.world)) this.currentWorldId = null;
|
|
8359
7668
|
return { type: "world-removed", world: world2 || null, packet };
|
|
8360
7669
|
}
|
|
8361
7670
|
const world = this.get(packet.world);
|
|
8362
7671
|
world.readMeta(packet);
|
|
7672
|
+
this.#resolveLocalPlayer(world);
|
|
8363
7673
|
if (this.currentWorldId == null && !world.isOverworld) this.currentWorldId = world.id;
|
|
8364
7674
|
return { type: "world", world };
|
|
8365
7675
|
}
|
|
@@ -8407,7 +7717,10 @@
|
|
|
8407
7717
|
if (packet.model_data && world.seed != null) {
|
|
8408
7718
|
const previousModel = world.model;
|
|
8409
7719
|
try {
|
|
8410
|
-
if (packet.full)
|
|
7720
|
+
if (packet.full) {
|
|
7721
|
+
world.model = new ModelState({ isOverworld: world.isOverworld });
|
|
7722
|
+
world.model.setLocalPlayerEntity(previousModel.localPlayerEntity);
|
|
7723
|
+
}
|
|
8411
7724
|
result.decoded = decodeModelPayload(packet.model_data, packet.world, world.seed);
|
|
8412
7725
|
result.model = world.model.apply(result.decoded, { full: Boolean(packet.full) });
|
|
8413
7726
|
if (result.model?.error && packet.full && previousModel) world.model = previousModel;
|
|
@@ -8466,38 +7779,6 @@
|
|
|
8466
7779
|
};
|
|
8467
7780
|
}
|
|
8468
7781
|
|
|
8469
|
-
// src/protocol/outbound/comms.js
|
|
8470
|
-
var COMMS_MESSAGE_TYPE = 3;
|
|
8471
|
-
function buildCommsMessage(message = "") {
|
|
8472
|
-
return {
|
|
8473
|
-
type: COMMS_MESSAGE_TYPE,
|
|
8474
|
-
msg: String(message)
|
|
8475
|
-
};
|
|
8476
|
-
}
|
|
8477
|
-
function normalizeCommsEvent(event) {
|
|
8478
|
-
const rawMessages = Array.isArray(event?.msgs_text) ? event.msgs_text : [];
|
|
8479
|
-
return {
|
|
8480
|
-
...event,
|
|
8481
|
-
entity: event?.ent_id != null && Number.isFinite(Number(event.ent_id)) ? Number(event.ent_id) : null,
|
|
8482
|
-
rawMessages,
|
|
8483
|
-
messages: rawMessages.map((message) => ({
|
|
8484
|
-
raw: message,
|
|
8485
|
-
text: flattenRichText(message)
|
|
8486
|
-
}))
|
|
8487
|
-
};
|
|
8488
|
-
}
|
|
8489
|
-
function flattenRichText(value) {
|
|
8490
|
-
if (value == null) return "";
|
|
8491
|
-
if (typeof value === "string") return value;
|
|
8492
|
-
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
8493
|
-
if (Array.isArray(value)) return value.map(flattenRichText).join("");
|
|
8494
|
-
if (typeof value === "object") {
|
|
8495
|
-
if (Object.hasOwn(value, "c")) return flattenRichText(value.c);
|
|
8496
|
-
if (Object.hasOwn(value, "text")) return flattenRichText(value.text);
|
|
8497
|
-
}
|
|
8498
|
-
return "";
|
|
8499
|
-
}
|
|
8500
|
-
|
|
8501
7782
|
// src/protocol/outbound/commands.js
|
|
8502
7783
|
init_constants();
|
|
8503
7784
|
var SHA256_K = new Uint32Array([
|
|
@@ -8818,11 +8099,11 @@
|
|
|
8818
8099
|
}
|
|
8819
8100
|
return normalized;
|
|
8820
8101
|
}
|
|
8821
|
-
function buildSignTextMessage(
|
|
8102
|
+
function buildSignTextMessage(text2 = "", mode = SignDisplayMode.Always) {
|
|
8822
8103
|
return {
|
|
8823
8104
|
type: 5,
|
|
8824
8105
|
cmd: SIGN_TEXT_COMMAND,
|
|
8825
|
-
args: [String(
|
|
8106
|
+
args: [String(text2), normalizeSignDisplayMode(mode)]
|
|
8826
8107
|
};
|
|
8827
8108
|
}
|
|
8828
8109
|
|
|
@@ -9354,6 +8635,9 @@
|
|
|
9354
8635
|
get lastPacket() {
|
|
9355
8636
|
return this.client.lastPacket;
|
|
9356
8637
|
}
|
|
8638
|
+
get lastDisconnect() {
|
|
8639
|
+
return this.client.lastDisconnect;
|
|
8640
|
+
}
|
|
9357
8641
|
send(command = {}) {
|
|
9358
8642
|
return this.client.send(command);
|
|
9359
8643
|
}
|
|
@@ -9475,17 +8759,46 @@
|
|
|
9475
8759
|
constructor(client) {
|
|
9476
8760
|
this.client = client;
|
|
9477
8761
|
}
|
|
8762
|
+
canSave() {
|
|
8763
|
+
return this.client.canSaveShip();
|
|
8764
|
+
}
|
|
8765
|
+
save(options = {}) {
|
|
8766
|
+
return this.client.saveShip(options);
|
|
8767
|
+
}
|
|
8768
|
+
rename(name, options = {}) {
|
|
8769
|
+
return this.client.renameShip(name, options);
|
|
8770
|
+
}
|
|
9478
8771
|
requestPlayerList() {
|
|
9479
8772
|
return this.client.requestPlayerList();
|
|
9480
8773
|
}
|
|
9481
|
-
resetInvite() {
|
|
9482
|
-
return this.client.resetInvite();
|
|
8774
|
+
resetInvite(options = {}) {
|
|
8775
|
+
return this.client.resetInvite(options);
|
|
9483
8776
|
}
|
|
9484
8777
|
setPrivacy(privacy) {
|
|
9485
8778
|
return this.client.setShipPrivacy(privacy);
|
|
9486
8779
|
}
|
|
9487
|
-
|
|
9488
|
-
return this.client.
|
|
8780
|
+
setGravity(direction) {
|
|
8781
|
+
return this.client.setShipGravity(direction);
|
|
8782
|
+
}
|
|
8783
|
+
setPatronPerks(enabled) {
|
|
8784
|
+
return this.client.setShipPatronPerks(enabled);
|
|
8785
|
+
}
|
|
8786
|
+
enablePatronPerks() {
|
|
8787
|
+
return this.setPatronPerks(true);
|
|
8788
|
+
}
|
|
8789
|
+
disablePatronPerks() {
|
|
8790
|
+
return this.setPatronPerks(false);
|
|
8791
|
+
}
|
|
8792
|
+
patronPerks() {
|
|
8793
|
+
return this.client.shipConfig?.patronPerks ?? null;
|
|
8794
|
+
}
|
|
8795
|
+
hasPatronPerks(name) {
|
|
8796
|
+
if (name !== void 0 && typeof name !== "string") throw new TypeError("name must be a string");
|
|
8797
|
+
const perks = this.patronPerks();
|
|
8798
|
+
return name === void 0 ? Boolean(perks?.length) : Boolean(perks?.some((perk) => perk.name === name));
|
|
8799
|
+
}
|
|
8800
|
+
recoverStarterItem(itemId, options = {}) {
|
|
8801
|
+
return this.client.recoverStarterItem(itemId, options);
|
|
9489
8802
|
}
|
|
9490
8803
|
setPlayerRank(refId, rank) {
|
|
9491
8804
|
return this.client.setPlayerRank(refId, rank);
|
|
@@ -9496,8 +8809,11 @@
|
|
|
9496
8809
|
banPlayer(refId) {
|
|
9497
8810
|
return this.client.banPlayer(refId);
|
|
9498
8811
|
}
|
|
9499
|
-
|
|
9500
|
-
return this.client.
|
|
8812
|
+
unbanPlayer(refId) {
|
|
8813
|
+
return this.client.unbanPlayer(refId);
|
|
8814
|
+
}
|
|
8815
|
+
demoteSelf(options = {}) {
|
|
8816
|
+
return this.client.demoteSelf(options);
|
|
9501
8817
|
}
|
|
9502
8818
|
config() {
|
|
9503
8819
|
return this.client.shipConfig;
|
|
@@ -9508,6 +8824,9 @@
|
|
|
9508
8824
|
playerList() {
|
|
9509
8825
|
return this.client.playerList;
|
|
9510
8826
|
}
|
|
8827
|
+
crewLog() {
|
|
8828
|
+
return this.client.crewLog;
|
|
8829
|
+
}
|
|
9511
8830
|
};
|
|
9512
8831
|
var InventoryDomain = class {
|
|
9513
8832
|
constructor(client) {
|
|
@@ -10228,8 +9547,8 @@
|
|
|
10228
9547
|
get state() {
|
|
10229
9548
|
return summaryForEntity(this.client, this.scope, this.id)?.contents?.sign || null;
|
|
10230
9549
|
}
|
|
10231
|
-
setText(
|
|
10232
|
-
return this.client.setSignText(
|
|
9550
|
+
setText(text2 = "", mode = 0) {
|
|
9551
|
+
return this.client.setSignText(text2, mode);
|
|
10233
9552
|
}
|
|
10234
9553
|
get text() {
|
|
10235
9554
|
return this.state?.text;
|
|
@@ -10607,7 +9926,7 @@
|
|
|
10607
9926
|
const sid = Number(client?.sid);
|
|
10608
9927
|
if (!Number.isFinite(sid)) return null;
|
|
10609
9928
|
const players = worldStateFor(client, scope)?.model.players() || [];
|
|
10610
|
-
return players.find((player) => player.
|
|
9929
|
+
return players.find((player) => player.isLocal) || null;
|
|
10611
9930
|
}
|
|
10612
9931
|
function currentPlayerRank(client) {
|
|
10613
9932
|
const player = currentPlayerSummary(client);
|
|
@@ -10842,6 +10161,7 @@
|
|
|
10842
10161
|
this.ready = false;
|
|
10843
10162
|
this.packetCount = 0;
|
|
10844
10163
|
this.lastPacket = null;
|
|
10164
|
+
this.lastDisconnect = null;
|
|
10845
10165
|
this.packets = [];
|
|
10846
10166
|
this.packetHistory = normalizeHistoryLimit(packetHistory, DEFAULT_PACKET_HISTORY);
|
|
10847
10167
|
this.worlds = new WorldStore({ eventHistory, modelPacketHistory, chunkHistory });
|
|
@@ -10866,6 +10186,7 @@
|
|
|
10866
10186
|
this.shipConfig = null;
|
|
10867
10187
|
this.captainSubrank = null;
|
|
10868
10188
|
this.playerList = null;
|
|
10189
|
+
this.crewLog = null;
|
|
10869
10190
|
this.outfits = /* @__PURE__ */ new Map();
|
|
10870
10191
|
this.commandAcks = /* @__PURE__ */ new Map();
|
|
10871
10192
|
this.lastCommandAck = null;
|
|
@@ -10874,6 +10195,8 @@
|
|
|
10874
10195
|
this.#resolveReady = resolve;
|
|
10875
10196
|
this.#rejectReady = reject;
|
|
10876
10197
|
});
|
|
10198
|
+
this.readyPromise.catch(() => {
|
|
10199
|
+
});
|
|
10877
10200
|
this.attachMode = attachMode;
|
|
10878
10201
|
this.attached = Boolean(attachMode);
|
|
10879
10202
|
if (connect) this.#connect().catch((error) => this.#fail(error));
|
|
@@ -10895,6 +10218,10 @@
|
|
|
10895
10218
|
#attachedOpened = false;
|
|
10896
10219
|
#resolveReady = null;
|
|
10897
10220
|
#rejectReady = null;
|
|
10221
|
+
#savePending = false;
|
|
10222
|
+
#renamePending = false;
|
|
10223
|
+
#starterRecoveryPending = false;
|
|
10224
|
+
#managementPending = /* @__PURE__ */ new Set();
|
|
10898
10225
|
#inputSettings = {
|
|
10899
10226
|
wrench_mode: 1,
|
|
10900
10227
|
turret_mode: 0
|
|
@@ -10936,17 +10263,170 @@
|
|
|
10936
10263
|
sendShipManagement(act, arg = null) {
|
|
10937
10264
|
return this.sendMessage(buildShipManagementMessage(act, arg));
|
|
10938
10265
|
}
|
|
10266
|
+
canSaveShip() {
|
|
10267
|
+
if (!this.connected || !this.ready) return false;
|
|
10268
|
+
const ship = this.worlds.shipWorld();
|
|
10269
|
+
if (!ship || ship.isOverworld !== false || ship.parentWorld == null) return false;
|
|
10270
|
+
const parent = this.worlds.worlds.get(Number(ship.parentWorld));
|
|
10271
|
+
return parent?.meta?.danger_level === 0;
|
|
10272
|
+
}
|
|
10273
|
+
async saveShip({ timeout = 1e4 } = {}) {
|
|
10274
|
+
this.#assertWritable();
|
|
10275
|
+
if (!Number.isFinite(timeout) || timeout <= 0 || timeout > 2147483647) {
|
|
10276
|
+
throw new RangeError("timeout must be positive milliseconds no greater than 2147483647");
|
|
10277
|
+
}
|
|
10278
|
+
if (this.#savePending) throw new Error("A ship save is already in progress");
|
|
10279
|
+
if (!this.canSaveShip()) throw new Error("Saving requires a connected, ready client with its ship in a known Safe Zone");
|
|
10280
|
+
this.#savePending = true;
|
|
10281
|
+
try {
|
|
10282
|
+
return await new Promise((resolve, reject) => {
|
|
10283
|
+
const cleanup = () => {
|
|
10284
|
+
clearTimeout(timer);
|
|
10285
|
+
this.off("disconnect", disconnected);
|
|
10286
|
+
};
|
|
10287
|
+
const disconnected = (info) => {
|
|
10288
|
+
cleanup();
|
|
10289
|
+
if (info.code === DropReason.Saved) resolve(info);
|
|
10290
|
+
else reject(new DisconnectError(info, "Ship save was not confirmed"));
|
|
10291
|
+
};
|
|
10292
|
+
const timer = setTimeout(() => {
|
|
10293
|
+
cleanup();
|
|
10294
|
+
reject(new Error("Timed out waiting for ship save confirmation (Saved close code)"));
|
|
10295
|
+
}, timeout);
|
|
10296
|
+
this.on("disconnect", disconnected);
|
|
10297
|
+
try {
|
|
10298
|
+
this.sendMessage(buildSaveShipMessage());
|
|
10299
|
+
} catch (error) {
|
|
10300
|
+
cleanup();
|
|
10301
|
+
reject(error);
|
|
10302
|
+
}
|
|
10303
|
+
});
|
|
10304
|
+
} finally {
|
|
10305
|
+
this.#savePending = false;
|
|
10306
|
+
}
|
|
10307
|
+
}
|
|
10308
|
+
async renameShip(name, { color, timeout = 1e4 } = {}) {
|
|
10309
|
+
this.#assertWritable();
|
|
10310
|
+
buildShipRenameCommitMessage(name, color === void 0 ? "#000000" : color);
|
|
10311
|
+
if (!Number.isFinite(timeout) || timeout <= 0 || timeout > 2147483647) {
|
|
10312
|
+
throw new RangeError("timeout must be positive milliseconds no greater than 2147483647");
|
|
10313
|
+
}
|
|
10314
|
+
if (!this.connected || !this.ready) throw new Error("Renaming requires a connected, ready client");
|
|
10315
|
+
if (this.#renamePending) throw new Error("A ship rename is already in progress");
|
|
10316
|
+
const worldId = this.worlds.currentWorldId;
|
|
10317
|
+
this.#renamePending = true;
|
|
10318
|
+
try {
|
|
10319
|
+
await new Promise((resolve, reject) => {
|
|
10320
|
+
const cleanup = () => {
|
|
10321
|
+
clearTimeout(timer);
|
|
10322
|
+
this.off("session", responded);
|
|
10323
|
+
this.off("disconnect", disconnected);
|
|
10324
|
+
this.off("demote", demoted);
|
|
10325
|
+
};
|
|
10326
|
+
const demoted = () => {
|
|
10327
|
+
cleanup();
|
|
10328
|
+
reject(new Error("Ship rename interrupted by demotion"));
|
|
10329
|
+
};
|
|
10330
|
+
const disconnected = (info) => {
|
|
10331
|
+
cleanup();
|
|
10332
|
+
reject(new DisconnectError(info, "Ship rename interrupted"));
|
|
10333
|
+
};
|
|
10334
|
+
const responded = (packet) => {
|
|
10335
|
+
const response = packet.submessage;
|
|
10336
|
+
if (response?.type !== "rename_response") return;
|
|
10337
|
+
cleanup();
|
|
10338
|
+
try {
|
|
10339
|
+
if (!response.allow) throw new Error(response.message || "Ship rename unavailable");
|
|
10340
|
+
if (this.worlds.currentWorldId !== worldId) throw new Error("World changed while requesting ship rename");
|
|
10341
|
+
this.sendMessage(buildShipRenameCommitMessage(name, color === void 0 ? response.initial_color : color));
|
|
10342
|
+
resolve();
|
|
10343
|
+
} catch (error) {
|
|
10344
|
+
reject(error);
|
|
10345
|
+
}
|
|
10346
|
+
};
|
|
10347
|
+
const timer = setTimeout(() => {
|
|
10348
|
+
cleanup();
|
|
10349
|
+
reject(new Error("Timed out waiting for ship rename permission"));
|
|
10350
|
+
}, timeout);
|
|
10351
|
+
this.on("session", responded);
|
|
10352
|
+
this.on("disconnect", disconnected);
|
|
10353
|
+
this.on("demote", demoted);
|
|
10354
|
+
try {
|
|
10355
|
+
this.sendMessage(buildShipRenameRequestMessage());
|
|
10356
|
+
} catch (error) {
|
|
10357
|
+
cleanup();
|
|
10358
|
+
reject(error);
|
|
10359
|
+
}
|
|
10360
|
+
});
|
|
10361
|
+
} finally {
|
|
10362
|
+
this.#renamePending = false;
|
|
10363
|
+
}
|
|
10364
|
+
}
|
|
10939
10365
|
requestPlayerList() {
|
|
10940
10366
|
return this.sendMessage(buildPlayerListMessage());
|
|
10941
10367
|
}
|
|
10942
|
-
resetInvite() {
|
|
10943
|
-
|
|
10368
|
+
resetInvite(options = {}) {
|
|
10369
|
+
const previousKey = this.shipConfig?.inviteKey;
|
|
10370
|
+
return this.#awaitManagementConfirmation("Invite reset", buildInviteResetMessage(), "ship-config", (config) => typeof config?.inviteKey === "string" && config.inviteKey.length > 0 && config.inviteKey !== previousKey, options);
|
|
10944
10371
|
}
|
|
10945
10372
|
setShipPrivacy(privacy) {
|
|
10946
10373
|
return this.sendMessage(buildShipPrivacyMessage(privacy));
|
|
10947
10374
|
}
|
|
10948
|
-
|
|
10949
|
-
return this.sendMessage(
|
|
10375
|
+
setShipGravity(direction) {
|
|
10376
|
+
return this.sendMessage(buildShipGravityMessage(direction));
|
|
10377
|
+
}
|
|
10378
|
+
setShipPatronPerks(enabled) {
|
|
10379
|
+
return this.sendMessage(buildSetPatronPerksMessage(enabled));
|
|
10380
|
+
}
|
|
10381
|
+
async recoverStarterItem(itemId, { timeout = 1e4 } = {}) {
|
|
10382
|
+
this.#assertWritable();
|
|
10383
|
+
const message = buildStarterRecoveryMessage(itemId);
|
|
10384
|
+
if (!Number.isFinite(timeout) || timeout <= 0 || timeout > 2147483647) {
|
|
10385
|
+
throw new RangeError("timeout must be positive milliseconds no greater than 2147483647");
|
|
10386
|
+
}
|
|
10387
|
+
if (!this.connected || !this.ready) throw new Error("Starter recovery requires a connected, ready client");
|
|
10388
|
+
if (this.#starterRecoveryPending) throw new Error("A starter recovery is already in progress");
|
|
10389
|
+
const worldId = this.worlds.currentWorldId;
|
|
10390
|
+
this.#starterRecoveryPending = true;
|
|
10391
|
+
try {
|
|
10392
|
+
await new Promise((resolve, reject) => {
|
|
10393
|
+
const cleanup = () => {
|
|
10394
|
+
clearTimeout(timer);
|
|
10395
|
+
this.off("starter-recovery", responded);
|
|
10396
|
+
this.off("disconnect", disconnected);
|
|
10397
|
+
this.off("demote", demoted);
|
|
10398
|
+
};
|
|
10399
|
+
const disconnected = (info) => {
|
|
10400
|
+
cleanup();
|
|
10401
|
+
reject(new DisconnectError(info, "Starter recovery interrupted"));
|
|
10402
|
+
};
|
|
10403
|
+
const demoted = () => {
|
|
10404
|
+
cleanup();
|
|
10405
|
+
reject(new Error("Starter recovery interrupted by demotion"));
|
|
10406
|
+
};
|
|
10407
|
+
const responded = (result) => {
|
|
10408
|
+
cleanup();
|
|
10409
|
+
if (this.worlds.currentWorldId !== worldId) reject(new Error("World changed during starter recovery"));
|
|
10410
|
+
else if (!result.success) reject(new Error(result.failReason));
|
|
10411
|
+
else resolve();
|
|
10412
|
+
};
|
|
10413
|
+
const timer = setTimeout(() => {
|
|
10414
|
+
cleanup();
|
|
10415
|
+
reject(new Error("Timed out waiting for starter recovery response"));
|
|
10416
|
+
}, timeout);
|
|
10417
|
+
this.on("starter-recovery", responded);
|
|
10418
|
+
this.on("disconnect", disconnected);
|
|
10419
|
+
this.on("demote", demoted);
|
|
10420
|
+
try {
|
|
10421
|
+
this.sendMessage(message);
|
|
10422
|
+
} catch (error) {
|
|
10423
|
+
cleanup();
|
|
10424
|
+
reject(error);
|
|
10425
|
+
}
|
|
10426
|
+
});
|
|
10427
|
+
} finally {
|
|
10428
|
+
this.#starterRecoveryPending = false;
|
|
10429
|
+
}
|
|
10950
10430
|
}
|
|
10951
10431
|
setPlayerRank(refId, rank) {
|
|
10952
10432
|
return this.sendMessage(buildSetPlayerRankMessage(refId, rank));
|
|
@@ -10966,8 +10446,56 @@
|
|
|
10966
10446
|
banPlayer(refId) {
|
|
10967
10447
|
return this.sendMessage(buildBanPlayerMessage(refId));
|
|
10968
10448
|
}
|
|
10969
|
-
|
|
10970
|
-
return this.sendMessage(
|
|
10449
|
+
unbanPlayer(refId) {
|
|
10450
|
+
return this.sendMessage(buildUnbanPlayerMessage(refId));
|
|
10451
|
+
}
|
|
10452
|
+
async demoteSelf(options = {}) {
|
|
10453
|
+
await this.#awaitManagementConfirmation("Self-demotion", buildDemoteSelfMessage(), "demote", () => true, options);
|
|
10454
|
+
}
|
|
10455
|
+
async #awaitManagementConfirmation(operation, message, event, accept, { timeout = 1e4 } = {}) {
|
|
10456
|
+
this.#assertWritable();
|
|
10457
|
+
if (!Number.isFinite(timeout) || timeout <= 0 || timeout > 2147483647) {
|
|
10458
|
+
throw new RangeError("timeout must be positive milliseconds no greater than 2147483647");
|
|
10459
|
+
}
|
|
10460
|
+
if (!this.connected || !this.ready) throw new Error(`${operation} requires a connected, ready client`);
|
|
10461
|
+
if (this.#managementPending.has(operation)) throw new Error(`${operation} is already in progress`);
|
|
10462
|
+
const worldId = this.worlds.currentWorldId;
|
|
10463
|
+
this.#managementPending.add(operation);
|
|
10464
|
+
try {
|
|
10465
|
+
return await new Promise((resolve, reject) => {
|
|
10466
|
+
const cleanup = () => {
|
|
10467
|
+
clearTimeout(timer);
|
|
10468
|
+
this.off(event, responded);
|
|
10469
|
+
this.off("disconnect", disconnected);
|
|
10470
|
+
if (event !== "demote") this.off("demote", demoted);
|
|
10471
|
+
};
|
|
10472
|
+
const fail = (error) => {
|
|
10473
|
+
cleanup();
|
|
10474
|
+
reject(error);
|
|
10475
|
+
};
|
|
10476
|
+
const disconnected = (info) => fail(new DisconnectError(info, `${operation} interrupted`));
|
|
10477
|
+
const demoted = () => fail(new Error(`${operation} interrupted by demotion`));
|
|
10478
|
+
const responded = (result) => {
|
|
10479
|
+
if (this.worlds.currentWorldId !== worldId) {
|
|
10480
|
+
fail(new Error(`World changed during ${operation.toLowerCase()}`));
|
|
10481
|
+
} else if (accept(result)) {
|
|
10482
|
+
cleanup();
|
|
10483
|
+
resolve(result);
|
|
10484
|
+
}
|
|
10485
|
+
};
|
|
10486
|
+
const timer = setTimeout(() => fail(new Error(`Timed out waiting for ${operation.toLowerCase()} confirmation`)), timeout);
|
|
10487
|
+
this.on(event, responded);
|
|
10488
|
+
this.on("disconnect", disconnected);
|
|
10489
|
+
if (event !== "demote") this.on("demote", demoted);
|
|
10490
|
+
try {
|
|
10491
|
+
this.sendMessage(message);
|
|
10492
|
+
} catch (error) {
|
|
10493
|
+
fail(error);
|
|
10494
|
+
}
|
|
10495
|
+
});
|
|
10496
|
+
} finally {
|
|
10497
|
+
this.#managementPending.delete(operation);
|
|
10498
|
+
}
|
|
10971
10499
|
}
|
|
10972
10500
|
sendEntityCommand(cmd, args = [-1, -1, -1]) {
|
|
10973
10501
|
return this.sendMessage({ type: 5, cmd, args });
|
|
@@ -11011,8 +10539,8 @@
|
|
|
11011
10539
|
setLauncherPower(power) {
|
|
11012
10540
|
return this.sendEntityCommand("power", [normalizeLauncherPower(power)]);
|
|
11013
10541
|
}
|
|
11014
|
-
setSignText(
|
|
11015
|
-
return this.sendMessage(buildSignTextMessage(
|
|
10542
|
+
setSignText(text2 = "", mode = 0) {
|
|
10543
|
+
return this.sendMessage(buildSignTextMessage(text2, mode));
|
|
11016
10544
|
}
|
|
11017
10545
|
sendUiConfig(data) {
|
|
11018
10546
|
return this.sendMessage({ type: 8, data });
|
|
@@ -11271,12 +10799,14 @@
|
|
|
11271
10799
|
shipConfig: this.shipConfig,
|
|
11272
10800
|
captainSubrank: this.captainSubrank,
|
|
11273
10801
|
playerList: this.playerList,
|
|
10802
|
+
crewLog: this.crewLog,
|
|
11274
10803
|
outfits: [...this.outfits.entries()].map(([sid, outfit]) => ({ sid, outfit })),
|
|
11275
10804
|
commandAcks: [...this.commandAcks.entries()].map(([world, commandNumber]) => ({ world, commandNumber })),
|
|
11276
10805
|
lastCommandAck: this.lastCommandAck,
|
|
11277
10806
|
decodeErrors: this.decodeErrors.slice(-50),
|
|
11278
10807
|
packetCount: this.packetCount,
|
|
11279
|
-
lastPacket: this.lastPacket
|
|
10808
|
+
lastPacket: this.lastPacket,
|
|
10809
|
+
lastDisconnect: this.lastDisconnect
|
|
11280
10810
|
};
|
|
11281
10811
|
}
|
|
11282
10812
|
state(options = {}) {
|
|
@@ -11401,6 +10931,7 @@
|
|
|
11401
10931
|
}
|
|
11402
10932
|
this.#resolveReady?.(this);
|
|
11403
10933
|
this.#resolveReady = null;
|
|
10934
|
+
this.#rejectReady = null;
|
|
11404
10935
|
}
|
|
11405
10936
|
this.#bindAttachedSocket();
|
|
11406
10937
|
if (this.connected && this.#ownsSocket) this.#attachedOpen();
|
|
@@ -11408,6 +10939,7 @@
|
|
|
11408
10939
|
}
|
|
11409
10940
|
#bindSocket() {
|
|
11410
10941
|
this.ws.onopen = () => {
|
|
10942
|
+
this.lastDisconnect = null;
|
|
11411
10943
|
this.connected = true;
|
|
11412
10944
|
this.ws.send(encodeMsgpack({ type: 1 }));
|
|
11413
10945
|
this.emit("open", this);
|
|
@@ -11421,7 +10953,7 @@
|
|
|
11421
10953
|
const open = () => this.#attachedOpen();
|
|
11422
10954
|
const message = (event) => this.#handleSocketMessage(event?.data ?? event);
|
|
11423
10955
|
const error = (event) => this.#fail(event?.error || new Error("WebSocket error"));
|
|
11424
|
-
const close = (event) => this.#handleSocketClose(event);
|
|
10956
|
+
const close = (event, reason) => this.#handleSocketClose(event, reason);
|
|
11425
10957
|
if (typeof this.ws.addEventListener === "function") {
|
|
11426
10958
|
this.ws.addEventListener("open", open);
|
|
11427
10959
|
this.ws.addEventListener("message", message);
|
|
@@ -11436,13 +10968,16 @@
|
|
|
11436
10968
|
this.ws.on("close", close);
|
|
11437
10969
|
return;
|
|
11438
10970
|
}
|
|
11439
|
-
const
|
|
11440
|
-
|
|
11441
|
-
|
|
11442
|
-
|
|
11443
|
-
|
|
10971
|
+
for (const [type, handler] of Object.entries({ open, message, error, close })) {
|
|
10972
|
+
const previous = this.ws[`on${type}`];
|
|
10973
|
+
this.ws[`on${type}`] = (...args) => {
|
|
10974
|
+
if (typeof previous === "function") previous.apply(this.ws, args);
|
|
10975
|
+
handler(...args);
|
|
10976
|
+
};
|
|
10977
|
+
}
|
|
11444
10978
|
}
|
|
11445
10979
|
#attachedOpen() {
|
|
10980
|
+
this.lastDisconnect = null;
|
|
11446
10981
|
this.connected = true;
|
|
11447
10982
|
if (this.#attachedOpened) return;
|
|
11448
10983
|
this.#attachedOpened = true;
|
|
@@ -11450,17 +10985,39 @@
|
|
|
11450
10985
|
this.emit("open", this);
|
|
11451
10986
|
if (this.#allowWrites) this.#flushMessages();
|
|
11452
10987
|
}
|
|
11453
|
-
#handleSocketClose(event) {
|
|
10988
|
+
#handleSocketClose(event, reason) {
|
|
10989
|
+
const info = normalizeDisconnect(event, reason);
|
|
11454
10990
|
this.connected = false;
|
|
10991
|
+
this.ready = false;
|
|
10992
|
+
this.sid = null;
|
|
10993
|
+
this.lastDisconnect = info;
|
|
11455
10994
|
clearInterval(this.#keepalive);
|
|
11456
10995
|
this.#keepalive = null;
|
|
11457
|
-
this
|
|
10996
|
+
this.#bootstrapped = false;
|
|
10997
|
+
this.#attachedOpened = false;
|
|
10998
|
+
this.#queuedCommands.length = 0;
|
|
10999
|
+
this.#queuedMessages.length = 0;
|
|
11000
|
+
this.shipConfig = null;
|
|
11001
|
+
this.captainSubrank = null;
|
|
11002
|
+
this.playerList = null;
|
|
11003
|
+
this.crewLog = null;
|
|
11004
|
+
this.puiPanels.clear();
|
|
11005
|
+
this.commsPanels.clear();
|
|
11006
|
+
this.currentCommsPanel = null;
|
|
11007
|
+
this.commandAcks.clear();
|
|
11008
|
+
this.lastCommandAck = null;
|
|
11009
|
+
this.#rejectReady?.(new DisconnectError(info, "Disconnected before the client was ready"));
|
|
11010
|
+
this.#resolveReady = null;
|
|
11011
|
+
this.#rejectReady = null;
|
|
11012
|
+
this.emit("disconnect", info);
|
|
11013
|
+
this.emit("close", event, reason);
|
|
11458
11014
|
}
|
|
11459
11015
|
#socketLooksOpen(websocket) {
|
|
11460
11016
|
return websocket?.readyState == null || websocket.readyState === 1 || websocket.readyState === websocket.OPEN;
|
|
11461
11017
|
}
|
|
11462
11018
|
#assertWritable() {
|
|
11463
11019
|
if (!this.#allowWrites) throw new Error("DredlessClient is attached in readonly mode");
|
|
11020
|
+
if (this.lastDisconnect) throw new DisconnectError(this.lastDisconnect);
|
|
11464
11021
|
}
|
|
11465
11022
|
#handleSocketMessage(data) {
|
|
11466
11023
|
if (data && typeof data.arrayBuffer === "function") {
|
|
@@ -11470,6 +11027,7 @@
|
|
|
11470
11027
|
this.#handleMessage(data);
|
|
11471
11028
|
}
|
|
11472
11029
|
#handleMessage(data) {
|
|
11030
|
+
if (this.lastDisconnect) return;
|
|
11473
11031
|
let packet;
|
|
11474
11032
|
try {
|
|
11475
11033
|
packet = decodeIncomingFrame(data);
|
|
@@ -11496,6 +11054,7 @@
|
|
|
11496
11054
|
}
|
|
11497
11055
|
#markReady(packet) {
|
|
11498
11056
|
this.sid = packet.sid >>> 0;
|
|
11057
|
+
this.worlds.apply(packet);
|
|
11499
11058
|
this.worlds.currentWorldId = packet.world ?? this.worlds.currentWorldId;
|
|
11500
11059
|
this.ready = true;
|
|
11501
11060
|
if (this.#ownsSocket) {
|
|
@@ -11508,6 +11067,7 @@
|
|
|
11508
11067
|
}
|
|
11509
11068
|
this.#resolveReady?.(this);
|
|
11510
11069
|
this.#resolveReady = null;
|
|
11070
|
+
this.#rejectReady = null;
|
|
11511
11071
|
this.emit("ready", this);
|
|
11512
11072
|
}
|
|
11513
11073
|
#sendBootstrap() {
|
|
@@ -11585,6 +11145,32 @@
|
|
|
11585
11145
|
#handleSessionSubmessage(packet) {
|
|
11586
11146
|
const submessage = packet?.submessage;
|
|
11587
11147
|
if (!submessage || typeof submessage !== "object") return;
|
|
11148
|
+
if (submessage.type === "demote") {
|
|
11149
|
+
this.shipConfig = null;
|
|
11150
|
+
this.captainSubrank = null;
|
|
11151
|
+
this.playerList = null;
|
|
11152
|
+
this.crewLog = null;
|
|
11153
|
+
this.emit("demote", packet);
|
|
11154
|
+
this.emit("ship-config", null, packet);
|
|
11155
|
+
this.emit("captain-subrank", null, packet);
|
|
11156
|
+
this.emit("player-list", null, packet);
|
|
11157
|
+
this.emit("crew-log", null, packet);
|
|
11158
|
+
return;
|
|
11159
|
+
}
|
|
11160
|
+
if (submessage.type === "log") {
|
|
11161
|
+
this.crewLog = normalizeCrewLog(submessage, this.crewLog);
|
|
11162
|
+
this.emit("crew-log", this.crewLog, packet);
|
|
11163
|
+
return;
|
|
11164
|
+
}
|
|
11165
|
+
if (submessage.type === "starter_recovery_response") {
|
|
11166
|
+
const failReason = submessage.fail_reason == null ? null : String(submessage.fail_reason);
|
|
11167
|
+
this.emit("starter-recovery", Object.freeze({ success: failReason === null, failReason }), packet);
|
|
11168
|
+
return;
|
|
11169
|
+
}
|
|
11170
|
+
if (submessage.type === "perk_response") {
|
|
11171
|
+
this.emit("patron-perks-response", Object.freeze({ failure: Boolean(submessage.failure) }), packet);
|
|
11172
|
+
return;
|
|
11173
|
+
}
|
|
11588
11174
|
if (submessage.type === "config") {
|
|
11589
11175
|
this.shipConfig = normalizeShipConfig(submessage);
|
|
11590
11176
|
this.emit("ship-config", this.shipConfig, packet);
|
|
@@ -11837,6 +11423,174 @@
|
|
|
11837
11423
|
init_cookies();
|
|
11838
11424
|
init_http();
|
|
11839
11425
|
init_servers();
|
|
11426
|
+
|
|
11427
|
+
// src/network/account.js
|
|
11428
|
+
init_runtime();
|
|
11429
|
+
async function fetchAccountDetails(session) {
|
|
11430
|
+
const response = await session.request("account/", {
|
|
11431
|
+
method: "GET",
|
|
11432
|
+
headers: { accept: "text/html" },
|
|
11433
|
+
credentials: "include",
|
|
11434
|
+
cache: "no-store"
|
|
11435
|
+
});
|
|
11436
|
+
session.mergeSetCookies(response);
|
|
11437
|
+
if (!response.ok) throw new Error(`Account page request failed: ${response.status} ${response.statusText}`);
|
|
11438
|
+
return parseAccountDetails(await response.text());
|
|
11439
|
+
}
|
|
11440
|
+
async function fetchClanTag(session) {
|
|
11441
|
+
return (await fetchAccountDetails(session)).clan;
|
|
11442
|
+
}
|
|
11443
|
+
async function setClanTag(session, tag) {
|
|
11444
|
+
if (typeof tag !== "string") throw new TypeError("tag must be a string");
|
|
11445
|
+
return updateClanTag(session, tag);
|
|
11446
|
+
}
|
|
11447
|
+
async function clearClanTag(session) {
|
|
11448
|
+
return updateClanTag(session, "");
|
|
11449
|
+
}
|
|
11450
|
+
async function updateClanTag(session, tag) {
|
|
11451
|
+
const body = tag === "" ? "" : new URLSearchParams({ tag }).toString();
|
|
11452
|
+
await postAccountForm(session, "account/clan", body, "Clan tag update");
|
|
11453
|
+
const clan = await fetchClanTag(session);
|
|
11454
|
+
if ((clan.tag ?? "") !== tag) throw new Error("Clan tag update was not confirmed by the account page");
|
|
11455
|
+
return clan;
|
|
11456
|
+
}
|
|
11457
|
+
async function removeShipPerks(session, shipId) {
|
|
11458
|
+
const id = requirePerkShipId(shipId);
|
|
11459
|
+
await postAccountForm(session, "account/remove_perks", new URLSearchParams({ ship: id }).toString(), "Ship perk removal");
|
|
11460
|
+
const { shipsWithPerks } = await fetchAccountDetails(session);
|
|
11461
|
+
if (shipsWithPerks === null || shipsWithPerks.some((ship) => ship.shipId === id)) {
|
|
11462
|
+
throw new Error("Ship perk removal was not confirmed by the account page");
|
|
11463
|
+
}
|
|
11464
|
+
return shipsWithPerks;
|
|
11465
|
+
}
|
|
11466
|
+
async function postAccountForm(session, path, body, operation) {
|
|
11467
|
+
const response = await session.request(path, {
|
|
11468
|
+
method: "POST",
|
|
11469
|
+
headers: {
|
|
11470
|
+
accept: "text/html",
|
|
11471
|
+
"content-type": "application/x-www-form-urlencoded",
|
|
11472
|
+
...!isBrowser() ? { origin: new URL(session.baseUrl).origin } : {}
|
|
11473
|
+
},
|
|
11474
|
+
body,
|
|
11475
|
+
credentials: "include",
|
|
11476
|
+
referrer: `${session.baseUrl}/account/`,
|
|
11477
|
+
// Node must merge cookies before following the form's redirect.
|
|
11478
|
+
redirect: isBrowser() ? "follow" : "manual"
|
|
11479
|
+
});
|
|
11480
|
+
session.mergeSetCookies(response);
|
|
11481
|
+
if (!response.ok && response.status !== 302 && response.status !== 303) {
|
|
11482
|
+
throw new Error(`${operation} failed: ${response.status} ${response.statusText}`);
|
|
11483
|
+
}
|
|
11484
|
+
await response.text();
|
|
11485
|
+
}
|
|
11486
|
+
function parseAccountDetails(html) {
|
|
11487
|
+
const source = String(html).replace(/<!--[\s\S]*?-->|<(script|style)\b[^>]*>[\s\S]*?<\/\1\s*>/gi, "");
|
|
11488
|
+
let tag = null;
|
|
11489
|
+
let found = false;
|
|
11490
|
+
for (const form of source.matchAll(/<form\b((?:"[^"]*"|'[^']*'|[^'">])*)>([\s\S]*?)<\/form\s*>/gi)) {
|
|
11491
|
+
const action = attributes(form[1]).get("action");
|
|
11492
|
+
if (!action || new URL(action, "https://drednot.io/").pathname !== "/account/clan") continue;
|
|
11493
|
+
for (const input of form[2].matchAll(/<input\b((?:"[^"]*"|'[^']*'|[^'">])*)>/gi)) {
|
|
11494
|
+
const attrs = attributes(input[1]);
|
|
11495
|
+
if (attrs.get("name") !== "tag") continue;
|
|
11496
|
+
tag = attrs.get("value") || null;
|
|
11497
|
+
found = true;
|
|
11498
|
+
break;
|
|
11499
|
+
}
|
|
11500
|
+
if (found) break;
|
|
11501
|
+
}
|
|
11502
|
+
if (!found) throw new Error("Account page has no clan form; authentication may be required or the page format has changed");
|
|
11503
|
+
const fields = /* @__PURE__ */ new Map();
|
|
11504
|
+
let name = null;
|
|
11505
|
+
let color = null;
|
|
11506
|
+
for (const paragraph of source.matchAll(/<p\b[^>]*>([\s\S]*?)<\/p\s*>/gi)) {
|
|
11507
|
+
const label = paragraph[1].match(/<b\b[^>]*>([\s\S]*?)<\/b\s*>/i);
|
|
11508
|
+
const code = paragraph[1].match(/<code\b((?:"[^"]*"|'[^']*'|[^'">])*)>([\s\S]*?)<\/code\s*>/i);
|
|
11509
|
+
if (!code) continue;
|
|
11510
|
+
const attrs = attributes(code[1]);
|
|
11511
|
+
if (label) fields.set(text(label[1]).replace(/:\s*$/, "").toLowerCase(), attrs.get("data-info") ?? null);
|
|
11512
|
+
if ((attrs.get("class") || "").split(/\s+/).includes("user") && /^You are:$/i.test(text(paragraph[1].slice(0, code.index)))) {
|
|
11513
|
+
name = decodeHtml(code[2].replace(/<[^>]*>/g, ""));
|
|
11514
|
+
color = parseAccountColor(attrs.get("style") || "");
|
|
11515
|
+
}
|
|
11516
|
+
}
|
|
11517
|
+
const rawIdentity = fields.get("identity (service)") || null;
|
|
11518
|
+
const identityParts = rawIdentity?.match(/^(.*?)\s*\(([^()]*)\)\s*$/);
|
|
11519
|
+
const count = text(source).match(/Your current clan tag has\s+([\d,]+)\s+other users?\b/i);
|
|
11520
|
+
return {
|
|
11521
|
+
name,
|
|
11522
|
+
color,
|
|
11523
|
+
email: fields.get("email") || null,
|
|
11524
|
+
identity: identityParts ? identityParts[1].trim() : rawIdentity,
|
|
11525
|
+
identityService: identityParts ? identityParts[2].trim() : null,
|
|
11526
|
+
clan: { tag, otherUsers: tag !== null && count ? Number(count[1].replace(/,/g, "")) : null },
|
|
11527
|
+
shipsWithPerks: parseShipsWithPerks(source)
|
|
11528
|
+
};
|
|
11529
|
+
}
|
|
11530
|
+
function parseAccountColor(style) {
|
|
11531
|
+
let color = null;
|
|
11532
|
+
for (const declaration of style.split(";")) {
|
|
11533
|
+
const match = declaration.match(/^\s*background(?:-color)?\s*:\s*#([0-9a-f]{6}|[0-9a-f]{3})\s*(?:!important\s*)?$/i);
|
|
11534
|
+
if (!match) continue;
|
|
11535
|
+
const hex = match[1].length === 3 ? [...match[1]].map((digit) => digit + digit).join("") : match[1];
|
|
11536
|
+
color = parseInt(hex, 16);
|
|
11537
|
+
}
|
|
11538
|
+
return color;
|
|
11539
|
+
}
|
|
11540
|
+
function parseShipsWithPerks(source) {
|
|
11541
|
+
const heading = source.match(/<(b|strong)\b[^>]*>\s*Ships\s+with\s+Perks\s+Applied\s*:\s*<\/\1\s*>/i);
|
|
11542
|
+
if (!heading) return null;
|
|
11543
|
+
const list = source.slice(heading.index + heading[0].length).match(/^\s*(?:<\/[^>]+>\s*)*<ul\b[^>]*>([\s\S]*?)<\/ul\s*>/i);
|
|
11544
|
+
if (!list) throw new Error("Account page's applied-perks list could not be parsed");
|
|
11545
|
+
const ships = [];
|
|
11546
|
+
for (const item of list[1].matchAll(/<li\b[^>]*>([\s\S]*?)<\/li\s*>/gi)) {
|
|
11547
|
+
const form = item[1].match(/<form\b((?:"[^"]*"|'[^']*'|[^'">])*)>([\s\S]*?)<\/form\s*>/i);
|
|
11548
|
+
const action = form && attributes(form[1]).get("action");
|
|
11549
|
+
if (!action || new URL(action, "https://drednot.io/").pathname !== "/account/remove_perks") {
|
|
11550
|
+
throw new Error("Account page's applied-perks entry has no removal form");
|
|
11551
|
+
}
|
|
11552
|
+
let shipId = null;
|
|
11553
|
+
for (const input of form[2].matchAll(/<input\b((?:"[^"]*"|'[^']*'|[^'">])*)>/gi)) {
|
|
11554
|
+
const attrs = attributes(input[1]);
|
|
11555
|
+
if (attrs.get("name") === "ship") shipId = requirePerkShipId(attrs.get("value"));
|
|
11556
|
+
}
|
|
11557
|
+
if (shipId === null) throw new Error("Account page's applied-perks entry has no ship identifier");
|
|
11558
|
+
const label = decodeHtml(item[1].slice(0, form.index).replace(/<[^>]*>/g, ""));
|
|
11559
|
+
const parts = label.match(/^([\s\S]*?) \{([^{}]+)\}\s*$/);
|
|
11560
|
+
ships.push({ shipId, name: parts ? parts[1] : label.trim(), hexCode: parts ? parts[2] : null });
|
|
11561
|
+
}
|
|
11562
|
+
return ships;
|
|
11563
|
+
}
|
|
11564
|
+
function requirePerkShipId(value) {
|
|
11565
|
+
if (typeof value === "number" && (!Number.isSafeInteger(value) || value <= 0)) {
|
|
11566
|
+
throw new RangeError("shipId must be a positive safe integer or a decimal ID string from shipsWithPerks");
|
|
11567
|
+
}
|
|
11568
|
+
if (typeof value !== "string" && typeof value !== "number" || !/^[1-9]\d*$/.test(String(value))) {
|
|
11569
|
+
throw new TypeError("shipId must be a positive integer or a decimal ID string from shipsWithPerks");
|
|
11570
|
+
}
|
|
11571
|
+
return String(value);
|
|
11572
|
+
}
|
|
11573
|
+
function attributes(source) {
|
|
11574
|
+
const result = /* @__PURE__ */ new Map();
|
|
11575
|
+
for (const match of source.matchAll(/([^\s=<>"'`/]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+)))?/g)) {
|
|
11576
|
+
result.set(match[1].toLowerCase(), decodeHtml(match[2] ?? match[3] ?? match[4] ?? ""));
|
|
11577
|
+
}
|
|
11578
|
+
return result;
|
|
11579
|
+
}
|
|
11580
|
+
function text(source) {
|
|
11581
|
+
return decodeHtml(source.replace(/<[^>]*>/g, " ")).replace(/\s+/g, " ").trim();
|
|
11582
|
+
}
|
|
11583
|
+
function decodeHtml(value) {
|
|
11584
|
+
const named = { amp: "&", lt: "<", gt: ">", quot: '"', apos: "'", nbsp: " " };
|
|
11585
|
+
return value.replace(/&(#x[0-9a-f]+|#\d+|amp|lt|gt|quot|apos|nbsp);/gi, (raw, entity) => {
|
|
11586
|
+
const name = entity.toLowerCase();
|
|
11587
|
+
if (Object.hasOwn(named, name)) return named[name];
|
|
11588
|
+
const code = name.startsWith("#x") ? parseInt(name.slice(2), 16) : Number(name.slice(1));
|
|
11589
|
+
return code > 0 && code <= 1114111 && !(code >= 55296 && code <= 57343) ? String.fromCodePoint(code) : "\uFFFD";
|
|
11590
|
+
});
|
|
11591
|
+
}
|
|
11592
|
+
|
|
11593
|
+
// src/network/session.js
|
|
11840
11594
|
var Session = class {
|
|
11841
11595
|
constructor(gameSession = null, gameVersion = null, baseUrl = DEFAULT_BASE_URL) {
|
|
11842
11596
|
this.baseUrl = baseUrl;
|
|
@@ -11884,6 +11638,21 @@
|
|
|
11884
11638
|
this.#readStatus(raw);
|
|
11885
11639
|
return raw;
|
|
11886
11640
|
}
|
|
11641
|
+
fetchAccountDetails() {
|
|
11642
|
+
return fetchAccountDetails(this);
|
|
11643
|
+
}
|
|
11644
|
+
fetchClanTag() {
|
|
11645
|
+
return fetchClanTag(this);
|
|
11646
|
+
}
|
|
11647
|
+
setClanTag(tag) {
|
|
11648
|
+
return setClanTag(this, tag);
|
|
11649
|
+
}
|
|
11650
|
+
clearClanTag() {
|
|
11651
|
+
return clearClanTag(this);
|
|
11652
|
+
}
|
|
11653
|
+
removeShipPerks(shipId) {
|
|
11654
|
+
return removeShipPerks(this, shipId);
|
|
11655
|
+
}
|
|
11887
11656
|
async fetchShips(server2) {
|
|
11888
11657
|
return fetchShips(this, server2);
|
|
11889
11658
|
}
|