From f2d3837dc0bc9794f1acee41824b920d870f440b Mon Sep 17 00:00:00 2001 From: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com> Date: Mon, 29 Sep 2025 17:36:04 +0200 Subject: [PATCH] give all missing skins --- src/controllers/api/inventoryController.ts | 128 +++++++++++-------- src/models/inventoryModels/inventoryModel.ts | 1 - src/services/saveLoadoutService.ts | 26 ++-- src/types/inventoryTypes/inventoryTypes.ts | 1 - static/webui/index.html | 4 - static/webui/translations/de.js | 1 - static/webui/translations/en.js | 1 - static/webui/translations/es.js | 1 - static/webui/translations/fr.js | 1 - static/webui/translations/ru.js | 1 - static/webui/translations/uk.js | 1 - static/webui/translations/zh.js | 1 - 12 files changed, 85 insertions(+), 82 deletions(-) diff --git a/src/controllers/api/inventoryController.ts b/src/controllers/api/inventoryController.ts index 86a8d7b1..a0bf71f9 100644 --- a/src/controllers/api/inventoryController.ts +++ b/src/controllers/api/inventoryController.ts @@ -15,6 +15,7 @@ import { applyCheatsToInfestedFoundry, handleSubsumeCompletion } from "../../ser import { addEmailItem, addItem, + addItems, addMiscItems, allDailyAffiliationKeys, checkCalendarAutoAdvance, @@ -268,6 +269,65 @@ export const inventoryController: RequestHandler = async (request, response) => } } inventory.LastInventorySync = new Types.ObjectId(); + + const weaponMap = new Map(); + for (const skin of inventory.WeaponSkins) { + weaponMap.set(skin.ItemType, skin._id.toString()); + } + + const itemsToAdd = new Set(); + + for (const key of equipmentKeys) { + if (key in inventory) { + for (const equipment of inventory[key]) { + for (const config of equipment.Configs) { + if (config.Skins) collectSkins(config.Skins, weaponMap, itemsToAdd); + } + } + } + } + + for (const key of ["AdultOperatorLoadOuts", "OperatorLoadOuts", "KahlLoadOuts"] as const) { + if (key in inventory) { + for (const loadOut of inventory[key]) { + if (loadOut.Skins) collectSkins(loadOut.Skins, weaponMap, itemsToAdd); + } + } + } + + if (inventory.LotusCustomization?.Skins) collectSkins(inventory.LotusCustomization.Skins, weaponMap, itemsToAdd); + + if (itemsToAdd.size > 0) { + logger.debug(`Adding ${itemsToAdd.size} items due to migration from unlockAllSkins cheat`); + const inventoryChanges = await addItems(inventory, Array.from(itemsToAdd)); + + if (inventoryChanges.WeaponSkins) { + for (const skin of inventoryChanges.WeaponSkins as IWeaponSkinClient[]) { + weaponMap.set(skin.ItemType, skin.ItemId.toString()); + } + } + + for (const key of equipmentKeys) { + if (key in inventory) { + for (const equipment of inventory[key]) { + for (const config of equipment.Configs) { + if (config.Skins) replaceSkinIds(config.Skins, weaponMap); + } + } + } + } + + for (const key of ["AdultOperatorLoadOuts", "OperatorLoadOuts", "KahlLoadOuts"] as const) { + if (key in inventory) { + for (const loadOut of inventory[key]) { + if (loadOut.Skins) replaceSkinIds(loadOut.Skins, weaponMap); + } + } + } + + if (inventory.LotusCustomization?.Skins) replaceSkinIds(inventory.LotusCustomization.Skins, weaponMap); + } + await inventory.save(); response.json( @@ -334,45 +394,6 @@ export const getInventoryResponse = async ( }); } - if (inventory.unlockAllSkins) { - const missingWeaponSkins = new Set(Object.keys(ExportCustoms)); - inventoryResponse.WeaponSkins.forEach(x => missingWeaponSkins.delete(x.ItemType)); - for (const uniqueName of missingWeaponSkins) { - inventoryResponse.WeaponSkins.push({ - ItemId: { - $oid: "ca70ca70ca70ca70" + catBreadHash(uniqueName).toString(16).padStart(8, "0") - }, - ItemType: uniqueName - }); - } - } else { - for (const key of equipmentKeys) { - if (key in inventoryResponse) { - for (const equipment of inventoryResponse[key]) { - equipment.Configs.forEach(config => { - if (config.Skins) processSkins(config.Skins, inventoryResponse.WeaponSkins, equipment.ItemType); - }); - } - } - } - - for (const key of ["AdultOperatorLoadOuts", "OperatorLoadOuts", "KahlLoadOuts"] as const) { - if (key in inventoryResponse) { - inventoryResponse[key].forEach(loadOut => { - if (loadOut.Skins) processSkins(loadOut.Skins, inventoryResponse.WeaponSkins, key); - }); - } - } - - if (inventoryResponse.LotusCustomization?.Skins) { - processSkins( - inventoryResponse.LotusCustomization.Skins, - inventoryResponse.WeaponSkins, - "LotusCustomization" - ); - } - } - if (typeof config.spoofMasteryRank === "number" && config.spoofMasteryRank >= 0) { inventoryResponse.PlayerLevel = config.spoofMasteryRank; if (!xpBasedLevelCapDisabled) { @@ -505,20 +526,21 @@ for (const key of Object.keys(ExportCustoms)) { skinLookupTable[catBreadHash(key)] = key; } -const processSkins = (skins: string[], weaponSKins: IWeaponSkinClient[], contextName: string): void => { - skins.forEach((skinId, i) => { +const collectSkins = (skins: string[], weaponMap: Map, itemsToAdd: Set): void => { + for (const skinId of skins) { if (skinId.startsWith("ca70ca70ca70ca70")) { - const skinItemType = skinLookupTable[parseInt(skinId.slice(16), 16)]; - const inventoryItem = weaponSKins.find(x => x.ItemType === skinItemType); - - if (inventoryItem) { - skins[i] = inventoryItem.ItemId.$oid; - } else { - skins[i] = skinItemType; - if (!ExportCustoms[skinItemType].alwaysAvailable) { - logger.warn(`Get ${skinItemType} or you may loose your appearance on ${contextName}`); - } - } + const typeName = skinLookupTable[parseInt(skinId.slice(16), 16)]; + if (!weaponMap.has(typeName)) itemsToAdd.add(typeName); } - }); + } +}; + +const replaceSkinIds = (skins: string[], weaponMap: Map): void => { + for (let i = 0; i < skins.length; i++) { + const skinId = skins[i]; + if (skinId.startsWith("ca70ca70ca70ca70")) { + const inventoryId = weaponMap.get(skinLookupTable[parseInt(skinId.slice(16), 16)]); + if (inventoryId) skins[i] = inventoryId; + } + } }; diff --git a/src/models/inventoryModels/inventoryModel.ts b/src/models/inventoryModels/inventoryModel.ts index 7571f145..58c57b93 100644 --- a/src/models/inventoryModels/inventoryModel.ts +++ b/src/models/inventoryModels/inventoryModel.ts @@ -1445,7 +1445,6 @@ const inventorySchema = new Schema( unlockDoubleCapacityPotatoesEverywhere: Boolean, unlockExilusEverywhere: Boolean, unlockArcanesEverywhere: Boolean, - unlockAllSkins: Boolean, syndicateMissionsRepeatable: Boolean, instantFinishRivenChallenge: Boolean, noDailyStandingLimits: Boolean, diff --git a/src/services/saveLoadoutService.ts b/src/services/saveLoadoutService.ts index 506a5444..1c4dcbd4 100644 --- a/src/services/saveLoadoutService.ts +++ b/src/services/saveLoadoutService.ts @@ -139,22 +139,16 @@ export const handleInventoryItemConfigChange = async ( case "WeaponSkins": { const itemEntries = equipment as IItemEntry; for (const [itemId, itemConfigEntries] of Object.entries(itemEntries)) { - if (itemId.startsWith("ca70ca70ca70ca70")) { - logger.warn( - `unlockAllSkins does not work with favoriting items because you don't actually own it` - ); - } else { - const inventoryItem = inventory.WeaponSkins.id(itemId); - if (!inventoryItem) { - logger.warn(`inventory item WeaponSkins not found with id ${itemId}`); - continue; - } - if ("Favorite" in itemConfigEntries) { - inventoryItem.Favorite = itemConfigEntries.Favorite; - } - if ("IsNew" in itemConfigEntries) { - inventoryItem.IsNew = itemConfigEntries.IsNew; - } + const inventoryItem = inventory.WeaponSkins.id(itemId); + if (!inventoryItem) { + logger.warn(`inventory item WeaponSkins not found with id ${itemId}`); + continue; + } + if ("Favorite" in itemConfigEntries) { + inventoryItem.Favorite = itemConfigEntries.Favorite; + } + if ("IsNew" in itemConfigEntries) { + inventoryItem.IsNew = itemConfigEntries.IsNew; } } break; diff --git a/src/types/inventoryTypes/inventoryTypes.ts b/src/types/inventoryTypes/inventoryTypes.ts index 9a3f9366..83d00c1d 100644 --- a/src/types/inventoryTypes/inventoryTypes.ts +++ b/src/types/inventoryTypes/inventoryTypes.ts @@ -38,7 +38,6 @@ export interface IAccountCheats { unlockDoubleCapacityPotatoesEverywhere?: boolean; unlockExilusEverywhere?: boolean; unlockArcanesEverywhere?: boolean; - unlockAllSkins?: boolean; syndicateMissionsRepeatable?: boolean; instantFinishRivenChallenge?: boolean; noDailyStandingLimits?: boolean; diff --git a/static/webui/index.html b/static/webui/index.html index c39023b9..737af753 100644 --- a/static/webui/index.html +++ b/static/webui/index.html @@ -962,10 +962,6 @@ -
- - -
diff --git a/static/webui/translations/de.js b/static/webui/translations/de.js index e628ae95..3800d109 100644 --- a/static/webui/translations/de.js +++ b/static/webui/translations/de.js @@ -215,7 +215,6 @@ dict = { cheats_dontSubtractVoidTraces: `Void-Spuren nicht verbrauchen`, cheats_dontSubtractConsumables: `Verbrauchsgegenstände (Ausrüstung) nicht verbrauchen`, cheats_unlockAllShipFeatures: `Alle Schiffs-Funktionen freischalten`, - cheats_unlockAllSkins: `Alle Skins freischalten`, cheats_unlockAllCapturaScenes: `Alle Photora-Szenen freischalten`, cheats_universalPolarityEverywhere: `Universelle Polarität überall`, cheats_unlockDoubleCapacityPotatoesEverywhere: `Orokin Reaktor & Beschleuniger überall`, diff --git a/static/webui/translations/en.js b/static/webui/translations/en.js index e2cdb5fd..e70998a9 100644 --- a/static/webui/translations/en.js +++ b/static/webui/translations/en.js @@ -214,7 +214,6 @@ dict = { cheats_dontSubtractVoidTraces: `Don't Subtract Void Traces`, cheats_dontSubtractConsumables: `Don't Subtract Consumables`, cheats_unlockAllShipFeatures: `Unlock All Ship Features`, - cheats_unlockAllSkins: `Unlock All Skins`, cheats_unlockAllCapturaScenes: `Unlock All Captura Scenes`, cheats_universalPolarityEverywhere: `Universal Polarity Everywhere`, cheats_unlockDoubleCapacityPotatoesEverywhere: `Potatoes Everywhere`, diff --git a/static/webui/translations/es.js b/static/webui/translations/es.js index 39194178..405b3f44 100644 --- a/static/webui/translations/es.js +++ b/static/webui/translations/es.js @@ -215,7 +215,6 @@ dict = { cheats_dontSubtractVoidTraces: `No descontar vestigios del Vacío`, cheats_dontSubtractConsumables: `No restar consumibles`, cheats_unlockAllShipFeatures: `Desbloquear todas las funciones de nave`, - cheats_unlockAllSkins: `Desbloquear todas las skins`, cheats_unlockAllCapturaScenes: `Desbloquear todas las escenas de Captura`, cheats_universalPolarityEverywhere: `Polaridad universal en todas partes`, cheats_unlockDoubleCapacityPotatoesEverywhere: `Patatas en todas partes`, diff --git a/static/webui/translations/fr.js b/static/webui/translations/fr.js index e9520553..9357982b 100644 --- a/static/webui/translations/fr.js +++ b/static/webui/translations/fr.js @@ -215,7 +215,6 @@ dict = { cheats_dontSubtractVoidTraces: `Ne pas consommer de Void Traces`, cheats_dontSubtractConsumables: `Ne pas retirer de consommables`, cheats_unlockAllShipFeatures: `Débloquer tous les segments du vaisseau`, - cheats_unlockAllSkins: `Débloquer tous les skins`, cheats_unlockAllCapturaScenes: `Débloquer toutes les scènes captura`, cheats_universalPolarityEverywhere: `Polarités universelles partout`, cheats_unlockDoubleCapacityPotatoesEverywhere: `Réacteurs et Catalyseurs partout`, diff --git a/static/webui/translations/ru.js b/static/webui/translations/ru.js index e579508d..50c7bb27 100644 --- a/static/webui/translations/ru.js +++ b/static/webui/translations/ru.js @@ -215,7 +215,6 @@ dict = { cheats_dontSubtractVoidTraces: `Не вычитать количество Отголосков Бездны`, cheats_dontSubtractConsumables: `Не вычитать количество расходников`, cheats_unlockAllShipFeatures: `Разблокировать все функции корабля`, - cheats_unlockAllSkins: `Разблокировать все скины`, cheats_unlockAllCapturaScenes: `Разблокировать все сцены Каптуры`, cheats_universalPolarityEverywhere: `Универсальная полярность везде`, cheats_unlockDoubleCapacityPotatoesEverywhere: `Реакторы/Катализаторы орокин везде`, diff --git a/static/webui/translations/uk.js b/static/webui/translations/uk.js index 6b745335..c2be4396 100644 --- a/static/webui/translations/uk.js +++ b/static/webui/translations/uk.js @@ -215,7 +215,6 @@ dict = { cheats_dontSubtractVoidTraces: `Не вираховувати кількість Відлуння`, cheats_dontSubtractConsumables: `Не вираховувати кількість витратних матеріалів`, cheats_unlockAllShipFeatures: `Розблокувати всі функції судна`, - cheats_unlockAllSkins: `Розблокувати всі скіни`, cheats_unlockAllCapturaScenes: `Розблокувати всі сцени Світлописця`, cheats_universalPolarityEverywhere: `Будь-яка полярність скрізь`, cheats_unlockDoubleCapacityPotatoesEverywhere: `Орокінські Реактори/Каталізатори скрізь`, diff --git a/static/webui/translations/zh.js b/static/webui/translations/zh.js index 58f7e8c8..66b40b08 100644 --- a/static/webui/translations/zh.js +++ b/static/webui/translations/zh.js @@ -215,7 +215,6 @@ dict = { cheats_dontSubtractVoidTraces: `虚空光体无消耗`, cheats_dontSubtractConsumables: `消耗物品使用时无损耗`, cheats_unlockAllShipFeatures: `解锁所有飞船功能`, - cheats_unlockAllSkins: `解锁所有外观`, cheats_unlockAllCapturaScenes: `解锁所有Captura场景`, cheats_universalPolarityEverywhere: `全局万用极性`, cheats_unlockDoubleCapacityPotatoesEverywhere: `全物品自带Orokin反应堆`,