返回提交历史
Modified
src/controllers/api/inventoryController.ts
+26
-29
Modified
src/controllers/api/sellController.ts
+1
-1
Modified
src/controllers/api/upgradesController.ts
+3
-0
Modified
src/helpers/inventoryHelpers.ts
+81
-0
Modified
src/services/missionInventoryUpdateService.ts
+27
-11
Modified
src/types/requestTypes.ts
+1
-0
Modified
static/webui/script.js
+16
-1
Modified
static/webui/translations/de.js
+5
-0
Modified
static/webui/translations/en.js
+5
-0
Modified
static/webui/translations/es.js
+5
-0
Modified
static/webui/translations/fr.js
+5
-0
Modified
static/webui/translations/ru.js
+5
-0
Modified
static/webui/translations/uk.js
+5
-0
Modified
static/webui/translations/zh.js
+5
-0
XFEstudio/XFESpaceNinjaServer
feat: U5 mods (#3631)
Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/3631 Reviewed-by: Sainan <63328889+sainan@users.noreply.github.com> Co-authored-by: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com> Co-committed-by: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com>
1e26a006
代码差异
14 个文件
+190
-42
@@ -38,6 +38,7 @@ import { Ship } from "../../models/shipModel.ts";
38
38
import {
39
39
convertIColorToLegacyColors,
40
40
convertIColorToLegacyColorsWithAtt,
41
convertToLegacyFingerprint,
41
42
fromOid,
42
43
toLegacyOid,
43
44
toOid,
@@ -621,19 +622,21 @@ export const getInventoryResponse = async (
621
622
if (version_compare(buildLabel, "2014.02.05.00.00") < 0) {
622
623
// Pre-U12 builds store mods in an array called Cards, and have no concept of RawUpgrades
623
624
inventoryResponse.Cards = [];
624
for (const rawUpgrade of inventoryResponse.RawUpgrades) {
625
const id = inventory.RawUpgrades.find(x => x.ItemType == rawUpgrade.ItemType)?._id;
626
if (id) {
627
for (let i = 0; i < rawUpgrade.ItemCount; i++) {
628
const card = {
629
ItemType: rawUpgrade.ItemType,
630
ItemId: toOid2(id, buildLabel),
631
Rank: 0,
632
AmountRemaining: rawUpgrade.ItemCount
633
} as IUpgradeClient;
634
// Client doesn't see the mods unless they are in both Cards and Upgrades
635
inventoryResponse.Cards.push(card);
636
inventoryResponse.Upgrades.push(card);
625
if (version_compare(buildLabel, gameToBuildVersion["7.3.0"]) >= 0) {
626
for (const rawUpgrade of inventoryResponse.RawUpgrades) {
627
const id = inventory.RawUpgrades.find(x => x.ItemType == rawUpgrade.ItemType)?._id;
628
if (id) {
629
for (let i = 0; i < rawUpgrade.ItemCount; i++) {
630
const card = {
631
ItemType: rawUpgrade.ItemType,
632
ItemId: toOid2(id, buildLabel),
633
Rank: 0,
634
AmountRemaining: rawUpgrade.ItemCount
635
} as IUpgradeClient;
636
// Client doesn't see the mods unless they are in both Cards and Upgrades
637
inventoryResponse.Cards.push(card);
638
inventoryResponse.Upgrades.push(card);
639
}
637
640
}
638
641
}
639
642
}
@@ -661,17 +664,15 @@ export const getInventoryResponse = async (
661
664
toLegacyOid(upgrade.ItemId);
662
665
if (version_compare(buildLabel, gameToBuildVersion["18.18.0"]) < 0) {
663
666
// Pre-U18.18 builds use a different UpgradeFingerprint format
664
let rank: number = 0;
665
if (upgrade.UpgradeFingerprint) {
666
rank = Number.parseFloat(
667
upgrade.UpgradeFingerprint.substring(
668
upgrade.UpgradeFingerprint.indexOf(":") + 1,
669
upgrade.UpgradeFingerprint.lastIndexOf("}")
670
)
671
);
672
}
673
upgrade.UpgradeFingerprint = `lvl=${rank}|`;
674
if (version_compare(buildLabel, gameToBuildVersion["13.0.0"]) < 0) {
667
const json = JSON.parse(upgrade.UpgradeFingerprint || '{"lvl":0}') as { lvl?: number };
668
const rank: number = json.lvl ?? 0;
669
upgrade.UpgradeFingerprint = convertToLegacyFingerprint(
670
upgrade.UpgradeFingerprint || '{"lvl":0}'
671
);
672
if (
673
version_compare(buildLabel, gameToBuildVersion["7.3.0"]) >= 0 &&
674
version_compare(buildLabel, gameToBuildVersion["13.0.0"]) < 0
675
) {
675
676
// Pre-U10 builds
676
677
if (
677
678
!upgrade.AmountRemaining ||
@@ -803,11 +804,7 @@ export const getInventoryResponse = async (
803
804
inventoryResponse.Upgrades = inventoryResponse.Upgrades.filter(x =>
804
805
allowedMods.includes(x.ItemType)
805
806
);
806
if (inventoryResponse.Cards) {
807
inventoryResponse.Cards = inventoryResponse.Cards.filter(x =>
808
allowedMods.includes(x.ItemType)
809
);
810
}
807
if (inventoryResponse.Cards) inventoryResponse.Cards = [];
811
808
}
812
809
}
813
810
}
@@ -312,7 +312,7 @@ export const sellController: RequestHandler = async (req, res) => {
312
312
break;
313
313
case "Upgrades":
314
314
payload.Items.Upgrades.forEach(sellItem => {
315
if (sellItem.Count == 0) {
315
if (sellItem.Count == 0 || !sellItem.String.includes("/")) {
316
316
inventory.Upgrades.pull({ _id: sellItem.String });
317
317
} else {
318
318
addMods(inventory, [
@@ -156,6 +156,9 @@ export const upgradesController: RequestHandler = async (req, res) => {
156
156
const item = inventory[payload.Category].id(itemId)!;
157
157
item.UpgradeNodes = payload.Weapon.UpgradeNodes;
158
158
}
159
if (payload.Cost) {
160
updateCurrency(inventory, payload.Cost, false);
161
}
159
162
}
160
163
} else {
161
164
const payload = JSON.parse(String(req.body)) as IUpgradesRequest;
@@ -105,6 +105,87 @@ export const convertIColorToLegacyColorsWithAtt = (
105
105
return convertedColors;
106
106
};
107
107
108
// ChatGPT wrote that and seems it looks fine
109
export const convertFromLegacyFingerprint = (s: string): string => {
110
let index = 0;
111
112
const parseBlock = (isArrayItem = false): Record<string, unknown> | Record<string, unknown>[] => {
113
const obj: Record<string, unknown> = {};
114
115
while (index < s.length) {
116
if (s[index] === "|") {
117
index++;
118
continue;
119
}
120
if (s[index] === "}") {
121
index++;
122
break;
123
}
124
125
const eqPos = s.indexOf("=", index);
126
if (eqPos === -1) break;
127
const key = s.slice(index, eqPos);
128
index = eqPos + 1;
129
130
if (s[index] === "{" && s[index + 1] === "|") {
131
index += 2;
132
const items: Record<string, unknown>[] = [];
133
while (index < s.length && !(s[index] === "|" && s[index + 1] === "}")) {
134
if (s[index] === "{" && s[index + 1] === "|") index += 2;
135
const item = parseBlock(true) as Record<string, unknown>;
136
items.push(item);
137
}
138
index += 2;
139
obj[key] = items;
140
continue;
141
}
142
143
if (s[index] === "{") {
144
index++;
145
obj[key] = parseBlock() as Record<string, unknown>;
146
continue;
147
}
148
149
const nextSep = s.indexOf("|", index);
150
const value = nextSep === -1 ? s.slice(index) : s.slice(index, nextSep);
151
index = nextSep === -1 ? s.length : nextSep;
152
obj[key] = value;
153
}
154
155
return isArrayItem ? obj : obj;
156
};
157
158
const result = parseBlock() as Record<string, unknown>;
159
return JSON.stringify(result);
160
};
161
162
export const convertToLegacyFingerprint = (s: string): string => {
163
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
164
const obj: Record<string, unknown> = JSON.parse(s);
165
const serialize = (o: unknown): string => {
166
if (Array.isArray(o)) {
167
return o.map(item => `{|${serialize(item)}|}`).join("|");
168
} else if (typeof o === "object" && o !== null) {
169
const parts: string[] = [];
170
for (const k in o as Record<string, unknown>) {
171
const v = (o as Record<string, unknown>)[k];
172
if (Array.isArray(v)) {
173
parts.push(`${k}={|${serialize(v)}|}`);
174
} else if (typeof v === "object" && v !== null) {
175
parts.push(`${k}={|${serialize(v)}|}`);
176
} else {
177
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
178
parts.push(`${k}=${v}`);
179
}
180
}
181
return parts.join("|");
182
} else {
183
return String(o);
184
}
185
};
186
return serialize(obj) + "|";
187
};
188
108
189
export const convertLegacyColorsToIColor = (colors: number[] | undefined): IColor => {
109
190
if (colors) {
110
191
return { t0: colors[0], t1: colors[1], t2: colors[2], t3: colors[3], en: colors[4] };
@@ -95,7 +95,13 @@ import {
95
95
import { config } from "./configService.ts";
96
96
import libraryDailyTasks from "../../static/fixed_responses/libraryDailyTasks.json" with { type: "json" };
97
97
import type { IGoal, ISyndicateJob, ISyndicateMissionInfo } from "../types/worldStateTypes.ts";
98
import { fromOid, toObjectId, toOid2, version_compare } from "../helpers/inventoryHelpers.ts";
98
import {
99
convertFromLegacyFingerprint,
100
fromOid,
101
toObjectId,
102
toOid2,
103
version_compare
104
} from "../helpers/inventoryHelpers.ts";
99
105
import type { TAccountDocument } from "./loginService.ts";
100
106
import type { ITypeCount } from "../types/commonTypes.ts";
101
107
import type { IEquipmentClient } from "../types/equipmentTypes.ts";
@@ -531,10 +537,9 @@ export const addMissionInventoryUpdates = async (
531
537
clientUpgrade.ItemCount ??= 1;
532
538
if (account.BuildLabel && version_compare(account.BuildLabel, gameToBuildVersion["18.18.0"]) < 0) {
533
539
// Acquired Mods have a different UpgradeFingerprint format in pre-U18.18.0 builds, this converts them to the format the database expects
534
clientUpgrade.UpgradeFingerprint = `{"lvl":${clientUpgrade.UpgradeFingerprint.substring(
535
clientUpgrade.UpgradeFingerprint.indexOf("=") + 1,
536
clientUpgrade.UpgradeFingerprint.lastIndexOf("|")
537
)}}`;
540
clientUpgrade.UpgradeFingerprint = convertFromLegacyFingerprint(
541
clientUpgrade.UpgradeFingerprint
542
);
538
543
}
539
544
// Handle Fusion Core drops
540
545
const parsedFingerprint = JSON.parse(clientUpgrade.UpgradeFingerprint) as { lvl?: number };
@@ -544,13 +549,24 @@ export const addMissionInventoryUpdates = async (
544
549
UpgradeFingerprint: clientUpgrade.UpgradeFingerprint
545
550
});
546
551
} else if (id == "") {
547
// U19 does not provide RawUpgrades and instead interleaves them with riven progress here
548
addMods(inventory, [
549
{
552
if (
553
account.BuildLabel &&
554
version_compare(account.BuildLabel, gameToBuildVersion["7.3.0"]) >= 0
555
) {
556
// U19 does not provide RawUpgrades and instead interleaves them with riven progress here
557
addMods(inventory, [
558
{
559
ItemType: clientUpgrade.ItemType,
560
ItemCount: clientUpgrade.ItemCount
561
}
562
]);
563
} else {
564
// U5 Mods
565
inventory.Upgrades.push({
550
566
ItemType: clientUpgrade.ItemType,
551
ItemCount: clientUpgrade.ItemCount
552
}
553
]);
567
UpgradeFingerprint: clientUpgrade.UpgradeFingerprint
568
});
569
}
554
570
} else {
555
571
const upgrade = inventory.Upgrades.id(id)!;
556
572
upgrade.UpgradeFingerprint = clientUpgrade.UpgradeFingerprint; // primitive way to copy over the riven challenge progress
@@ -266,6 +266,7 @@ export interface IUpgradesRequestLegacy {
266
266
PolarityRemap: IPolarity[];
267
267
UpgradesToAttach?: IUpgradeClient[];
268
268
UpgradesToDetach?: IUpgradeClient[];
269
Cost?: number;
269
270
}
270
271
export interface IUpgradeOperation {
271
272
OperationType: string;
@@ -793,6 +793,21 @@ function fetchItemList() {
793
793
},
794
794
"/Lotus/Language/Game/Rank_Utility": {
795
795
name: loc("guildView_rank_utility")
796
},
797
"/Lotus/Upgrades/Modules/GrineerMeleeModule": {
798
name: loc("code_meleeMod")
799
},
800
"/Lotus/Upgrades/Modules/GrineerPistolModule": {
801
name: loc("code_pistolMod")
802
},
803
"/Lotus/Upgrades/Modules/GrineerRifleModule": {
804
name: loc("code_rifleMod")
805
},
806
"/Lotus/Upgrades/Modules/GrineerShotgunModule": {
807
name: loc("code_shotgunMod")
808
},
809
"/Lotus/Upgrades/Modules/OrokinWarframeModule": {
810
name: loc("code_warframeMod")
796
811
}
797
812
};
798
813
for (const [type, items] of Object.entries(data)) {
@@ -1670,7 +1685,7 @@ function translateInventoryDataToDom() {
1670
1685
td.textContent = itemMap[item.ItemType]?.name ?? item.ItemType;
1671
1686
if (itemMap[item.ItemType]?.badReason == "notraw") {
1672
1687
// Assuming this is a riven with a pending challenge, so rank would be N/A, but otherwise it's fine.
1673
} else {
1688
} else if (!Number.isNaN(rank)) {
1674
1689
td.innerHTML += " <span title='" + loc("code_rank") + "'>★ " + rank + "/" + maxRank + "</span>";
1675
1690
}
1676
1691
tr.appendChild(td);
@@ -30,6 +30,11 @@ dict = {
30
30
code_ancientFusionCoreCommon: `Antiker Fusionskern (Gewöhnlich)`,
31
31
code_ancientFusionCoreUncommon: `Antiker Fusionskern (Ungewöhnlich)`,
32
32
code_ancientFusionCoreRare: `Antiker Fusionskern (Selten)`,
33
code_meleeMod: `[UNTRANSLATED] Melee Mod`,
34
code_pistolMod: `[UNTRANSLATED] Pistol Mod`,
35
code_rifleMod: `[UNTRANSLATED] Rifle Mod`,
36
code_shotgunMod: `[UNTRANSLATED] Shotgun Mod`,
37
code_warframeMod: `[UNTRANSLATED] Warframe Mod`,
33
38
code_legendaryCore: `Legendärer Kern`,
34
39
code_traumaticPeculiar: `Kuriose Mod: Traumatisch`,
35
40
code_starter: `|MOD| (Defekt)`,
@@ -29,6 +29,11 @@ dict = {
29
29
code_ancientFusionCoreCommon: `Ancient Fusion Core (Common)`,
30
30
code_ancientFusionCoreUncommon: `Ancient Fusion Core (Uncommon)`,
31
31
code_ancientFusionCoreRare: `Ancient Fusion Core (Rare)`,
32
code_meleeMod: `Melee Mod`,
33
code_pistolMod: `Pistol Mod`,
34
code_rifleMod: `Rifle Mod`,
35
code_shotgunMod: `Shotgun Mod`,
36
code_warframeMod: `Warframe Mod`,
32
37
code_legendaryCore: `Legendary Core`,
33
38
code_traumaticPeculiar: `Traumatic Peculiar`,
34
39
code_starter: `|MOD| (Flawed)`,
@@ -30,6 +30,11 @@ dict = {
30
30
code_ancientFusionCoreCommon: `[UNTRANSLATED] Ancient Fusion Core (Common)`,
31
31
code_ancientFusionCoreUncommon: `[UNTRANSLATED] Ancient Fusion Core (Uncommon)`,
32
32
code_ancientFusionCoreRare: `[UNTRANSLATED] Ancient Fusion Core (Rare)`,
33
code_meleeMod: `[UNTRANSLATED] Melee Mod`,
34
code_pistolMod: `[UNTRANSLATED] Pistol Mod`,
35
code_rifleMod: `[UNTRANSLATED] Rifle Mod`,
36
code_shotgunMod: `[UNTRANSLATED] Shotgun Mod`,
37
code_warframeMod: `[UNTRANSLATED] Warframe Mod`,
33
38
code_legendaryCore: `Núcleo legendario`,
34
39
code_traumaticPeculiar: `Traumatismo peculiar`,
35
40
code_starter: `|MOD| (Defectuoso)`,
@@ -30,6 +30,11 @@ dict = {
30
30
code_ancientFusionCoreCommon: `[UNTRANSLATED] Ancient Fusion Core (Common)`,
31
31
code_ancientFusionCoreUncommon: `[UNTRANSLATED] Ancient Fusion Core (Uncommon)`,
32
32
code_ancientFusionCoreRare: `[UNTRANSLATED] Ancient Fusion Core (Rare)`,
33
code_meleeMod: `[UNTRANSLATED] Melee Mod`,
34
code_pistolMod: `[UNTRANSLATED] Pistol Mod`,
35
code_rifleMod: `[UNTRANSLATED] Rifle Mod`,
36
code_shotgunMod: `[UNTRANSLATED] Shotgun Mod`,
37
code_warframeMod: `[UNTRANSLATED] Warframe Mod`,
33
38
code_legendaryCore: `Coeur Légendaire`,
34
39
code_traumaticPeculiar: `Traumatisme Atypique`,
35
40
code_starter: `|MOD| (Défectueux)`,
@@ -30,6 +30,11 @@ dict = {
30
30
code_ancientFusionCoreCommon: `[UNTRANSLATED] Ancient Fusion Core (Common)`,
31
31
code_ancientFusionCoreUncommon: `[UNTRANSLATED] Ancient Fusion Core (Uncommon)`,
32
32
code_ancientFusionCoreRare: `[UNTRANSLATED] Ancient Fusion Core (Rare)`,
33
code_meleeMod: `[UNTRANSLATED] Melee Mod`,
34
code_pistolMod: `[UNTRANSLATED] Pistol Mod`,
35
code_rifleMod: `[UNTRANSLATED] Rifle Mod`,
36
code_shotgunMod: `[UNTRANSLATED] Shotgun Mod`,
37
code_warframeMod: `[UNTRANSLATED] Warframe Mod`,
33
38
code_legendaryCore: `Легендарное ядро`,
34
39
code_traumaticPeculiar: `Травмирующая Странность`,
35
40
code_starter: `|MOD| (Повреждённый)`,