From 1cf7b41d3f3072b631d1870f5f1b2c967762a490 Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Tue, 29 Apr 2025 12:27:25 -0700 Subject: [PATCH 1/4] chore: note that random element functions could return undefined (#1910) We should be explicit about the fact that we expect the arrays to not be empty. Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1910 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- .../api/activateRandomModController.ts | 2 +- .../api/artifactTransmutationController.ts | 2 +- .../api/modularWeaponSaleController.ts | 2 +- src/helpers/rivenHelper.ts | 8 ++++---- src/services/inventoryService.ts | 10 +++++----- src/services/loginRewardService.ts | 2 +- src/services/missionInventoryUpdateService.ts | 2 +- src/services/personalRoomsService.ts | 12 +++++------ src/services/rngService.ts | 6 +++--- src/services/serversideVendorsService.ts | 4 ++-- src/services/worldStateService.ts | 20 +++++++++---------- 11 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/controllers/api/activateRandomModController.ts b/src/controllers/api/activateRandomModController.ts index 4ac822c7..5dc8499c 100644 --- a/src/controllers/api/activateRandomModController.ts +++ b/src/controllers/api/activateRandomModController.ts @@ -17,7 +17,7 @@ export const activateRandomModController: RequestHandler = async (req, res) => { ItemCount: -1 } ]); - const rivenType = getRandomElement(rivenRawToRealWeighted[request.ItemType]); + const rivenType = getRandomElement(rivenRawToRealWeighted[request.ItemType])!; const fingerprint = createVeiledRivenFingerprint(ExportUpgrades[rivenType]); const upgradeIndex = inventory.Upgrades.push({ diff --git a/src/controllers/api/artifactTransmutationController.ts b/src/controllers/api/artifactTransmutationController.ts index 7e39e79e..4310c7c4 100644 --- a/src/controllers/api/artifactTransmutationController.ts +++ b/src/controllers/api/artifactTransmutationController.ts @@ -28,7 +28,7 @@ export const artifactTransmutationController: RequestHandler = async (req, res) }); const rawRivenType = getRandomRawRivenType(); - const rivenType = getRandomElement(rivenRawToRealWeighted[rawRivenType]); + const rivenType = getRandomElement(rivenRawToRealWeighted[rawRivenType])!; const fingerprint = createVeiledRivenFingerprint(ExportUpgrades[rivenType]); const upgradeIndex = diff --git a/src/controllers/api/modularWeaponSaleController.ts b/src/controllers/api/modularWeaponSaleController.ts index f60f6c3d..3e37547b 100644 --- a/src/controllers/api/modularWeaponSaleController.ts +++ b/src/controllers/api/modularWeaponSaleController.ts @@ -141,7 +141,7 @@ const getModularWeaponSale = ( getItemType: (parts: string[]) => string ): IModularWeaponSaleInfo => { const rng = new CRng(day); - const parts = partTypes.map(partType => rng.randomElement(partTypeToParts[partType])); + const parts = partTypes.map(partType => rng.randomElement(partTypeToParts[partType])!); let partsCost = 0; for (const part of parts) { partsCost += ExportWeapons[part].premiumPrice!; diff --git a/src/helpers/rivenHelper.ts b/src/helpers/rivenHelper.ts index 35426a29..34a7babc 100644 --- a/src/helpers/rivenHelper.ts +++ b/src/helpers/rivenHelper.ts @@ -31,7 +31,7 @@ export interface IFingerprintStat { } export const createVeiledRivenFingerprint = (meta: IUpgrade): IVeiledRivenFingerprint => { - const challenge = getRandomElement(meta.availableChallenges!); + const challenge = getRandomElement(meta.availableChallenges!)!; const fingerprintChallenge: IRivenChallenge = { Type: challenge.fullName, Progress: 0, @@ -54,11 +54,11 @@ export const createVeiledRivenFingerprint = (meta: IUpgrade): IVeiledRivenFinger export const createUnveiledRivenFingerprint = (meta: IUpgrade): IUnveiledRivenFingerprint => { const fingerprint: IUnveiledRivenFingerprint = { - compat: getRandomElement(meta.compatibleItems!), + compat: getRandomElement(meta.compatibleItems!)!, lim: 0, lvl: 0, lvlReq: getRandomInt(8, 16), - pol: getRandomElement(["AP_ATTACK", "AP_DEFENSE", "AP_TACTIC"]), + pol: getRandomElement(["AP_ATTACK", "AP_DEFENSE", "AP_TACTIC"])!, buffs: [], curses: [] }; @@ -81,7 +81,7 @@ export const randomiseRivenStats = (meta: IUpgrade, fingerprint: IUnveiledRivenF if (Math.random() < 0.5) { const entry = getRandomElement( meta.upgradeEntries!.filter(x => x.canBeCurse && !fingerprint.buffs.find(y => y.Tag == x.tag)) - ); + )!; fingerprint.curses.push({ Tag: entry.tag, Value: Math.trunc(Math.random() * 0x40000000) }); } }; diff --git a/src/services/inventoryService.ts b/src/services/inventoryService.ts index c3d47ec6..da8b0848 100644 --- a/src/services/inventoryService.ts +++ b/src/services/inventoryService.ts @@ -1798,7 +1798,7 @@ export const addKeyChainItems = async ( }; export const createLibraryDailyTask = (): ILibraryDailyTaskInfo => { - const enemyTypes = getRandomElement(libraryDailyTasks); + const enemyTypes = getRandomElement(libraryDailyTasks)!; const enemyAvatar = ExportEnemies.avatars[enemyTypes[0]]; const scansRequired = getRandomInt(2, 4); return { @@ -1944,22 +1944,22 @@ export const giveNemesisPetRecipe = (inventory: TInventoryDatabaseDocument, neme "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadA", "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadB", "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadC" - ]); + ])!; const body = getRandomElement([ "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartBodyA", "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartBodyB", "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartBodyC" - ]); + ])!; const legs = getRandomElement([ "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartLegsA", "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartLegsB", "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartLegsC" - ]); + ])!; const tail = getRandomElement([ "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartTailA", "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartTailB", "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartTailC" - ]); + ])!; const recipeType = Object.entries(ExportRecipes).find(arr => arr[1].resultType == head)![0]; addRecipes(inventory, [ { diff --git a/src/services/loginRewardService.ts b/src/services/loginRewardService.ts index c897442e..1734247a 100644 --- a/src/services/loginRewardService.ts +++ b/src/services/loginRewardService.ts @@ -102,7 +102,7 @@ const getRandomLoginReward = (rng: CRng, day: number, inventory: TInventoryDatab // This account has all applicable warframes and weapons already mastered (filthy cheater), need a different reward. return getRandomLoginReward(rng, day, inventory); } - reward.StoreItemType = toStoreItem(rng.randomElement(eligibleRecipes)); + reward.StoreItemType = toStoreItem(rng.randomElement(eligibleRecipes)!); } return { //_id: toOid(new Types.ObjectId()), diff --git a/src/services/missionInventoryUpdateService.ts b/src/services/missionInventoryUpdateService.ts index 89b55cea..35486d21 100644 --- a/src/services/missionInventoryUpdateService.ts +++ b/src/services/missionInventoryUpdateService.ts @@ -930,7 +930,7 @@ export const addMissionRewards = async ( if (rewardInfo.useVaultManifest) { MissionRewards.push({ - StoreItem: getRandomElement(corruptedMods), + StoreItem: getRandomElement(corruptedMods)!, ItemCount: 1 }); } diff --git a/src/services/personalRoomsService.ts b/src/services/personalRoomsService.ts index 97f1b41d..8cf49ec1 100644 --- a/src/services/personalRoomsService.ts +++ b/src/services/personalRoomsService.ts @@ -47,12 +47,12 @@ export const createGarden = (): IGardeningDatabase => { Name: "Garden0", Plants: [ { - PlantType: getRandomElement(plantTypes), + PlantType: getRandomElement(plantTypes)!, EndTime: endTime, PlotIndex: 0 }, { - PlantType: getRandomElement(plantTypes), + PlantType: getRandomElement(plantTypes)!, EndTime: endTime, PlotIndex: 1 } @@ -62,12 +62,12 @@ export const createGarden = (): IGardeningDatabase => { Name: "Garden1", Plants: [ { - PlantType: getRandomElement(plantTypes), + PlantType: getRandomElement(plantTypes)!, EndTime: endTime, PlotIndex: 0 }, { - PlantType: getRandomElement(plantTypes), + PlantType: getRandomElement(plantTypes)!, EndTime: endTime, PlotIndex: 1 } @@ -77,12 +77,12 @@ export const createGarden = (): IGardeningDatabase => { Name: "Garden2", Plants: [ { - PlantType: getRandomElement(plantTypes), + PlantType: getRandomElement(plantTypes)!, EndTime: endTime, PlotIndex: 0 }, { - PlantType: getRandomElement(plantTypes), + PlantType: getRandomElement(plantTypes)!, EndTime: endTime, PlotIndex: 1 } diff --git a/src/services/rngService.ts b/src/services/rngService.ts index 84a4ed8d..68225ca1 100644 --- a/src/services/rngService.ts +++ b/src/services/rngService.ts @@ -6,7 +6,7 @@ export interface IRngResult { probability: number; } -export const getRandomElement = (arr: T[]): T => { +export const getRandomElement = (arr: T[]): T | undefined => { return arr[Math.floor(Math.random() * arr.length)]; }; @@ -113,7 +113,7 @@ export class CRng { return min; } - randomElement(arr: T[]): T { + randomElement(arr: T[]): T | undefined { return arr[Math.floor(this.random() * arr.length)]; } @@ -145,7 +145,7 @@ export class SRng { return min; } - randomElement(arr: T[]): T { + randomElement(arr: T[]): T | undefined { return arr[this.randomInt(0, arr.length - 1)]; } diff --git a/src/services/serversideVendorsService.ts b/src/services/serversideVendorsService.ts index d594e79f..82ceae46 100644 --- a/src/services/serversideVendorsService.ts +++ b/src/services/serversideVendorsService.ts @@ -212,7 +212,7 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani while (processed.ItemManifest.length + offersToAdd.length < numItemsTarget) { // TODO: Consider per-bin item limits // TODO: Consider item probability weightings - offersToAdd.push(rng.randomElement(manifest.items)); + offersToAdd.push(rng.randomElement(manifest.items)!); } } else { let binThisCycle; @@ -256,7 +256,7 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani for (let i = 0; i != rawItem.numRandomItemPrices; ++i) { let itemPrice: { type: string; count: IRange }; do { - itemPrice = rng.randomElement(manifest.randomItemPricesPerBin![rawItem.bin]); + itemPrice = rng.randomElement(manifest.randomItemPricesPerBin![rawItem.bin])!; } while (item.ItemPrices.find(x => x.ItemType == itemPrice.type)); item.ItemPrices.push({ ItemType: itemPrice.type, diff --git a/src/services/worldStateService.ts b/src/services/worldStateService.ts index 6fd0b71a..e2e2ea23 100644 --- a/src/services/worldStateService.ts +++ b/src/services/worldStateService.ts @@ -225,7 +225,7 @@ const pushSortieIfRelevant = (worldState: IWorldState, day: number): void => { const seed = new CRng(day).randomInt(0, 0xffff); const rng = new CRng(seed); - const boss = rng.randomElement(sortieBosses); + const boss = rng.randomElement(sortieBosses)!; const modifiers = [ "SORTIE_MODIFIER_LOW_ENERGY", @@ -302,7 +302,7 @@ const pushSortieIfRelevant = (worldState: IWorldState, day: number): void => { missionIndex = ExportRegions[node].missionIndex; if (missionIndex != 28) { - missionIndex = rng.randomElement(availableMissionIndexes); + missionIndex = rng.randomElement(availableMissionIndexes)!; } } while ( specialMissionTypes.indexOf(missionIndex) != -1 && @@ -312,7 +312,7 @@ const pushSortieIfRelevant = (worldState: IWorldState, day: number): void => { if (i == 2 && rng.randomInt(0, 2) == 2) { const filteredModifiers = modifiers.filter(mod => mod !== "SORTIE_MODIFIER_MELEE_ONLY"); - const modifierType = rng.randomElement(filteredModifiers); + const modifierType = rng.randomElement(filteredModifiers)!; if (boss == "SORTIE_BOSS_PHORID") { selectedNodes.push({ @@ -346,7 +346,7 @@ const pushSortieIfRelevant = (worldState: IWorldState, day: number): void => { ? modifiers.filter(mod => mod != "SORTIE_MODIFIER_HAZARD_RADIATION") : modifiers; - const modifierType = rng.randomElement(filteredModifiers); + const modifierType = rng.randomElement(filteredModifiers)!; selectedNodes.push({ missionType, @@ -389,7 +389,7 @@ const getSeasonDailyChallenge = (day: number): ISeasonChallenge => { Daily: true, Activation: { $date: { $numberLong: dayStart.toString() } }, Expiry: { $date: { $numberLong: dayEnd.toString() } }, - Challenge: rng.randomElement(dailyChallenges) + Challenge: rng.randomElement(dailyChallenges)! }; }; @@ -408,7 +408,7 @@ const getSeasonWeeklyChallenge = (week: number, id: number): ISeasonChallenge => _id: { $oid: "67e1bb2d9d00cb47" + challengeId.toString().padStart(8, "0") }, Activation: { $date: { $numberLong: weekStart.toString() } }, Expiry: { $date: { $numberLong: weekEnd.toString() } }, - Challenge: rng.randomElement(weeklyChallenges) + Challenge: rng.randomElement(weeklyChallenges)! }; }; @@ -425,7 +425,7 @@ const getSeasonWeeklyHardChallenge = (week: number, id: number): ISeasonChalleng _id: { $oid: "67e1bb2d9d00cb47" + challengeId.toString().padStart(8, "0") }, Activation: { $date: { $numberLong: weekStart.toString() } }, Expiry: { $date: { $numberLong: weekEnd.toString() } }, - Challenge: rng.randomElement(weeklyHardChallenges) + Challenge: rng.randomElement(weeklyHardChallenges)! }; }; @@ -1196,7 +1196,7 @@ export const getLiteSortie = (week: number): ILiteSortie => { "MT_EXTERMINATION", "MT_SABOTAGE", "MT_RESCUE" - ]), + ])!, node: firstNode }, { @@ -1206,8 +1206,8 @@ export const getLiteSortie = (week: number): ILiteSortie => { "MT_ARTIFACT", "MT_EXCAVATE", "MT_SURVIVAL" - ]), - node: rng.randomElement(nodes) + ])!, + node: rng.randomElement(nodes)! }, { missionType: "MT_ASSASSINATION", From de1e2a25f239624b0b72b5eb63a19b7a1c18804c Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Tue, 29 Apr 2025 12:27:38 -0700 Subject: [PATCH 2/4] fix(webui): ensure that all requests using authz revalidate it (#1911) Closes #1907 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1911 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- static/webui/script.js | 281 +++++++++++++++++++++-------------------- 1 file changed, 147 insertions(+), 134 deletions(-) diff --git a/static/webui/script.js b/static/webui/script.js index b7c63fdf..6c18ed52 100644 --- a/static/webui/script.js +++ b/static/webui/script.js @@ -375,6 +375,7 @@ function fetchItemList() { } fetchItemList(); +// Assumes that caller revalidates authz function updateInventory() { const req = $.get("/api/inventory.php?" + window.authz + "&xpBasedLevelCapDisabled=1"); req.done(data => { @@ -487,25 +488,27 @@ function updateInventory() { a.href = "#"; a.onclick = function (event) { event.preventDefault(); - if (item.XP < maxXP) { - addGearExp(category, item.ItemId.$oid, maxXP - item.XP); - } - if ("exalted" in itemMap[item.ItemType]) { - for (const exaltedType of itemMap[item.ItemType].exalted) { - const exaltedItem = data.SpecialItems.find(x => x.ItemType == exaltedType); - if (exaltedItem) { - const exaltedCap = - itemMap[exaltedType]?.type == "weapons" ? 800_000 : 1_600_000; - if (exaltedItem.XP < exaltedCap) { - addGearExp( - "SpecialItems", - exaltedItem.ItemId.$oid, - exaltedCap - exaltedItem.XP - ); + revalidateAuthz(() => { + if (item.XP < maxXP) { + addGearExp(category, item.ItemId.$oid, maxXP - item.XP); + } + if ("exalted" in itemMap[item.ItemType]) { + for (const exaltedType of itemMap[item.ItemType].exalted) { + const exaltedItem = data.SpecialItems.find(x => x.ItemType == exaltedType); + if (exaltedItem) { + const exaltedCap = + itemMap[exaltedType]?.type == "weapons" ? 800_000 : 1_600_000; + if (exaltedItem.XP < exaltedCap) { + addGearExp( + "SpecialItems", + exaltedItem.ItemId.$oid, + exaltedCap - exaltedItem.XP + ); + } } } } - } + }); }; a.title = loc("code_maxRank"); a.innerHTML = ``; @@ -1229,76 +1232,22 @@ function addMissingEvolutionProgress() { } function maxRankAllEvolutions() { - const req = $.get("/api/inventory.php?" + window.authz + "&xpBasedLevelCapDisabled=1"); + revalidateAuthz(() => { + const req = $.get("/api/inventory.php?" + window.authz + "&xpBasedLevelCapDisabled=1"); + req.done(data => { + const requests = []; - req.done(data => { - const requests = []; - - data.EvolutionProgress.forEach(item => { - if (item.Rank < 5) { - requests.push({ - ItemType: item.ItemType, - Rank: 5 - }); - } - }); - - if (Object.keys(requests).length > 0) { - return setEvolutionProgress(requests); - } - - toast(loc("code_noEquipmentToRankUp")); - }); -} - -function maxRankAllEquipment(categories) { - const req = $.get("/api/inventory.php?" + window.authz + "&xpBasedLevelCapDisabled=1"); - - req.done(data => { - window.itemListPromise.then(itemMap => { - const batchData = {}; - - categories.forEach(category => { - data[category].forEach(item => { - const maxXP = - category === "Suits" || - category === "SpaceSuits" || - category === "Sentinels" || - category === "Hoverboards" - ? 1_600_000 - : 800_000; - - if (item.XP < maxXP) { - if (!batchData[category]) { - batchData[category] = []; - } - batchData[category].push({ - ItemId: { $oid: item.ItemId.$oid }, - XP: maxXP - }); - } - if (category === "Suits") { - if ("exalted" in itemMap[item.ItemType]) { - for (const exaltedType of itemMap[item.ItemType].exalted) { - const exaltedItem = data["SpecialItems"].find(x => x.ItemType == exaltedType); - if (exaltedItem) { - const exaltedCap = itemMap[exaltedType]?.type == "weapons" ? 800_000 : 1_600_000; - if (exaltedItem.XP < exaltedCap) { - batchData["SpecialItems"] ??= []; - batchData["SpecialItems"].push({ - ItemId: { $oid: exaltedItem.ItemId.$oid }, - XP: exaltedCap - }); - } - } - } - } - } - }); + data.EvolutionProgress.forEach(item => { + if (item.Rank < 5) { + requests.push({ + ItemType: item.ItemType, + Rank: 5 + }); + } }); - if (Object.keys(batchData).length > 0) { - return sendBatchGearExp(batchData); + if (Object.keys(requests).length > 0) { + return setEvolutionProgress(requests); } toast(loc("code_noEquipmentToRankUp")); @@ -1306,6 +1255,64 @@ function maxRankAllEquipment(categories) { }); } +function maxRankAllEquipment(categories) { + revalidateAuthz(() => { + const req = $.get("/api/inventory.php?" + window.authz + "&xpBasedLevelCapDisabled=1"); + req.done(data => { + window.itemListPromise.then(itemMap => { + const batchData = {}; + + categories.forEach(category => { + data[category].forEach(item => { + const maxXP = + category === "Suits" || + category === "SpaceSuits" || + category === "Sentinels" || + category === "Hoverboards" + ? 1_600_000 + : 800_000; + + if (item.XP < maxXP) { + if (!batchData[category]) { + batchData[category] = []; + } + batchData[category].push({ + ItemId: { $oid: item.ItemId.$oid }, + XP: maxXP + }); + } + if (category === "Suits") { + if ("exalted" in itemMap[item.ItemType]) { + for (const exaltedType of itemMap[item.ItemType].exalted) { + const exaltedItem = data["SpecialItems"].find(x => x.ItemType == exaltedType); + if (exaltedItem) { + const exaltedCap = + itemMap[exaltedType]?.type == "weapons" ? 800_000 : 1_600_000; + if (exaltedItem.XP < exaltedCap) { + batchData["SpecialItems"] ??= []; + batchData["SpecialItems"].push({ + ItemId: { $oid: exaltedItem.ItemId.$oid }, + XP: exaltedCap + }); + } + } + } + } + } + }); + }); + + if (Object.keys(batchData).length > 0) { + return sendBatchGearExp(batchData); + } + + toast(loc("code_noEquipmentToRankUp")); + }); + }); + }); +} + +// Assumes that caller revalidates authz function addGearExp(category, oid, xp) { const data = {}; data[category] = [ @@ -1314,16 +1321,14 @@ function addGearExp(category, oid, xp) { XP: xp } ]; - revalidateAuthz(() => { - $.post({ - url: "/custom/addXp?" + window.authz, - contentType: "application/json", - data: JSON.stringify(data) - }).done(function () { - if (category != "SpecialItems") { - updateInventory(); - } - }); + $.post({ + url: "/custom/addXp?" + window.authz, + contentType: "application/json", + data: JSON.stringify(data) + }).done(function () { + if (category != "SpecialItems") { + updateInventory(); + } }); } @@ -1598,32 +1603,34 @@ function doAcquireMod() { const uiConfigs = [...$("#server-settings input[id]")].map(x => x.id); function doChangeSettings() { - fetch("/custom/config?" + window.authz) - .then(response => response.json()) - .then(json => { - for (const i of uiConfigs) { - var x = document.getElementById(i); - if (x != null) { - if (x.type == "checkbox") { - if (x.checked === true) { - json[i] = true; - } else { - json[i] = false; + revalidateAuthz(() => { + fetch("/custom/config?" + window.authz) + .then(response => response.json()) + .then(json => { + for (const i of uiConfigs) { + var x = document.getElementById(i); + if (x != null) { + if (x.type == "checkbox") { + if (x.checked === true) { + json[i] = true; + } else { + json[i] = false; + } + } else if (x.type == "number") { + json[i] = parseInt(x.value); } - } else if (x.type == "number") { - json[i] = parseInt(x.value); } } - } - $.post({ - url: "/custom/config?" + window.authz, - contentType: "text/plain", - data: JSON.stringify(json, null, 2) - }).then(() => { - // A few cheats affect the inventory response which in turn may change what values we need to show - updateInventory(); + $.post({ + url: "/custom/config?" + window.authz, + contentType: "text/plain", + data: JSON.stringify(json, null, 2) + }).then(() => { + // A few cheats affect the inventory response which in turn may change what values we need to show + updateInventory(); + }); }); - }); + }); } // Cheats route @@ -1876,33 +1883,39 @@ function doChangeSupportedSyndicate() { } function doAddCurrency(currency) { - $.post({ - url: "/custom/addCurrency?" + window.authz, - contentType: "application/json", - data: JSON.stringify({ - currency, - delta: document.getElementById(currency + "-delta").valueAsNumber - }) - }).then(function () { - updateInventory(); + revalidateAuthz(() => { + $.post({ + url: "/custom/addCurrency?" + window.authz, + contentType: "application/json", + data: JSON.stringify({ + currency, + delta: document.getElementById(currency + "-delta").valueAsNumber + }) + }).then(function () { + updateInventory(); + }); }); } function doQuestUpdate(operation, itemType) { - $.post({ - url: "/custom/manageQuests?" + window.authz + "&operation=" + operation + "&itemType=" + itemType, - contentType: "application/json" - }).then(function () { - updateInventory(); + revalidateAuthz(() => { + $.post({ + url: "/custom/manageQuests?" + window.authz + "&operation=" + operation + "&itemType=" + itemType, + contentType: "application/json" + }).then(function () { + updateInventory(); + }); }); } function doBulkQuestUpdate(operation) { - $.post({ - url: "/custom/manageQuests?" + window.authz + "&operation=" + operation, - contentType: "application/json" - }).then(function () { - updateInventory(); + revalidateAuthz(() => { + $.post({ + url: "/custom/manageQuests?" + window.authz + "&operation=" + operation, + contentType: "application/json" + }).then(function () { + updateInventory(); + }); }); } From 0af7f4120163a773c1ad5435ca7e1799a1396f45 Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Tue, 29 Apr 2025 12:27:47 -0700 Subject: [PATCH 3/4] fix: unset LibraryPersonalTarget after completing it (#1913) Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1913 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- src/services/missionInventoryUpdateService.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/services/missionInventoryUpdateService.ts b/src/services/missionInventoryUpdateService.ts index 35486d21..66328a0d 100644 --- a/src/services/missionInventoryUpdateService.ts +++ b/src/services/missionInventoryUpdateService.ts @@ -380,6 +380,7 @@ export const addMissionInventoryUpdates = async ( : 10) ) { progress.Completed = true; + inventory.LibraryPersonalTarget = undefined; } logger.debug(`synthesis of ${scan.EnemyType} added to personal target progress`); synthesisIgnored = false; From 9468768947aad5f500631aa786e3096071d403a2 Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Tue, 29 Apr 2025 12:28:01 -0700 Subject: [PATCH 4/4] fix: weapon seed's low dword being sign extended (#1914) JavaScript's semantics here are incredibly stupid, but basically if the initial DWORD's high WORD's MSB is true, the number would become negative after the shift left by 16. Then when ORing it with the highDword, the initial DWORD would be sign-extended to a QWORD, meaning the high DWORD would become all 1s, basically cancelling out the entire OR operation. Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1914 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- src/services/serversideVendorsService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/serversideVendorsService.ts b/src/services/serversideVendorsService.ts index 82ceae46..171c60fc 100644 --- a/src/services/serversideVendorsService.ts +++ b/src/services/serversideVendorsService.ts @@ -286,7 +286,7 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani item.LocTagRandSeed = (rng.randomInt(0, 0xffff) << 16) | rng.randomInt(0, 0xffff); if (vendorInfo.RandomSeedType == "VRST_WEAPON") { const highDword = (rng.randomInt(0, 0xffff) << 16) | rng.randomInt(0, 0xffff); - item.LocTagRandSeed = (BigInt(highDword) << 32n) | BigInt(item.LocTagRandSeed); + item.LocTagRandSeed = (BigInt(highDword) << 32n) | (BigInt(item.LocTagRandSeed) & 0xffffffffn); } } processed.ItemManifest.push(item);