From 6dd9b42f4026d41065eb00b281e41be2eeab2f4f Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Sun, 22 Jun 2025 06:36:47 -0700 Subject: [PATCH 01/24] feat(webui): update inventory when in-game changes are made (#2239) A bit of a rough initial implementation, but already works pretty well. Closes #2224 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2239 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- src/controllers/api/missionInventoryUpdateController.ts | 3 +++ src/controllers/api/nameWeaponController.ts | 2 ++ src/controllers/api/purchaseController.ts | 2 ++ src/controllers/api/renamePetController.ts | 2 ++ src/controllers/api/sellController.ts | 2 ++ src/services/webService.ts | 1 + static/webui/script.js | 3 +++ 7 files changed, 15 insertions(+) diff --git a/src/controllers/api/missionInventoryUpdateController.ts b/src/controllers/api/missionInventoryUpdateController.ts index 3b5009c2..93f8033c 100644 --- a/src/controllers/api/missionInventoryUpdateController.ts +++ b/src/controllers/api/missionInventoryUpdateController.ts @@ -7,6 +7,7 @@ import { generateRewardSeed, getInventory } from "@/src/services/inventoryServic import { getInventoryResponse } from "./inventoryController"; import { logger } from "@/src/utils/logger"; import { IMissionInventoryUpdateResponse } from "@/src/types/missionTypes"; +import { sendWsBroadcastTo } from "@/src/services/webService"; /* **** INPUT **** @@ -76,6 +77,7 @@ export const missionInventoryUpdateController: RequestHandler = async (req, res) InventoryJson: JSON.stringify(inventoryResponse), MissionRewards: [] }); + sendWsBroadcastTo(account._id.toString(), { update_inventory: true }); return; } @@ -106,6 +108,7 @@ export const missionInventoryUpdateController: RequestHandler = async (req, res) AffiliationMods, ConquestCompletedMissionsCount } satisfies IMissionInventoryUpdateResponse); + sendWsBroadcastTo(account._id.toString(), { update_inventory: true }); }; /* diff --git a/src/controllers/api/nameWeaponController.ts b/src/controllers/api/nameWeaponController.ts index 5d1011be..8d378feb 100644 --- a/src/controllers/api/nameWeaponController.ts +++ b/src/controllers/api/nameWeaponController.ts @@ -3,6 +3,7 @@ import { getAccountIdForRequest } from "@/src/services/loginService"; import { getInventory, updateCurrency } from "@/src/services/inventoryService"; import { getJSONfromString } from "@/src/helpers/stringHelpers"; import { TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes"; +import { sendWsBroadcastTo } from "@/src/services/webService"; interface INameWeaponRequest { ItemName: string; @@ -27,4 +28,5 @@ export const nameWeaponController: RequestHandler = async (req, res) => { res.json({ InventoryChanges: currencyChanges }); + sendWsBroadcastTo(accountId, { update_inventory: true }); }; diff --git a/src/controllers/api/purchaseController.ts b/src/controllers/api/purchaseController.ts index 4b35e0c5..ba314845 100644 --- a/src/controllers/api/purchaseController.ts +++ b/src/controllers/api/purchaseController.ts @@ -3,6 +3,7 @@ import { getAccountIdForRequest } from "@/src/services/loginService"; import { IPurchaseRequest } from "@/src/types/purchaseTypes"; import { handlePurchase } from "@/src/services/purchaseService"; import { getInventory } from "@/src/services/inventoryService"; +import { sendWsBroadcastTo } from "@/src/services/webService"; export const purchaseController: RequestHandler = async (req, res) => { const purchaseRequest = JSON.parse(String(req.body)) as IPurchaseRequest; @@ -11,4 +12,5 @@ export const purchaseController: RequestHandler = async (req, res) => { const response = await handlePurchase(purchaseRequest, inventory); await inventory.save(); res.json(response); + sendWsBroadcastTo(accountId, { update_inventory: true }); }; diff --git a/src/controllers/api/renamePetController.ts b/src/controllers/api/renamePetController.ts index 61212641..40b4ec37 100644 --- a/src/controllers/api/renamePetController.ts +++ b/src/controllers/api/renamePetController.ts @@ -1,6 +1,7 @@ import { getJSONfromString } from "@/src/helpers/stringHelpers"; import { getInventory, updateCurrency } from "@/src/services/inventoryService"; import { getAccountIdForRequest } from "@/src/services/loginService"; +import { sendWsBroadcastTo } from "@/src/services/webService"; import { IInventoryChanges } from "@/src/types/purchaseTypes"; import { RequestHandler } from "express"; @@ -22,6 +23,7 @@ export const renamePetController: RequestHandler = async (req, res) => { ...data, inventoryChanges: inventoryChanges }); + sendWsBroadcastTo(accountId, { update_inventory: true }); }; interface IRenamePetRequest { diff --git a/src/controllers/api/sellController.ts b/src/controllers/api/sellController.ts index fdfb3a82..ff5c8f42 100644 --- a/src/controllers/api/sellController.ts +++ b/src/controllers/api/sellController.ts @@ -15,6 +15,7 @@ import { InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes"; import { ExportDojoRecipes } from "warframe-public-export-plus"; import { IInventoryChanges } from "@/src/types/purchaseTypes"; import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel"; +import { sendWsBroadcastTo } from "@/src/services/webService"; export const sellController: RequestHandler = async (req, res) => { const payload = JSON.parse(String(req.body)) as ISellRequest; @@ -279,6 +280,7 @@ export const sellController: RequestHandler = async (req, res) => { res.json({ inventoryChanges: inventoryChanges // "inventoryChanges" for this response instead of the usual "InventoryChanges" }); + sendWsBroadcastTo(accountId, { update_inventory: true }); }; interface ISellRequest { diff --git a/src/services/webService.ts b/src/services/webService.ts index 92578c61..25db1d69 100644 --- a/src/services/webService.ts +++ b/src/services/webService.ts @@ -125,6 +125,7 @@ interface IWsMsgToClient { isRegister: boolean; }; logged_out?: boolean; + update_inventory?: boolean; } const wsOnConnect = (ws: ws, _req: http.IncomingMessage): void => { diff --git a/static/webui/script.js b/static/webui/script.js index 44f7ade0..1f1e86dd 100644 --- a/static/webui/script.js +++ b/static/webui/script.js @@ -79,6 +79,9 @@ function openWebSocket() { if ("logged_out" in msg) { sendAuth(); } + if ("update_inventory" in msg) { + updateInventory(); + } }; window.ws.onclose = function () { ws_is_open = false; From bf12f90c8899ab0324841c0684573c18f54232b3 Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Sun, 22 Jun 2025 06:37:17 -0700 Subject: [PATCH 02/24] chore: replace unlockAllMissions config with an account cheats button (#2241) This way, mission completion rewards are given. This is especially import for junction rewards like quest keys (Closes #2229). Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2241 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- config.json.example | 1 - src/controllers/api/inventoryController.ts | 28 +------ .../custom/completeAllMissionsController.ts | 34 ++++++++ src/helpers/stringHelpers.ts | 6 ++ src/routes/custom.ts | 2 + src/services/configService.ts | 1 - src/services/missionInventoryUpdateService.ts | 2 +- static/webui/index.html | 9 +- static/webui/script.js | 84 ++++++++++--------- 9 files changed, 91 insertions(+), 76 deletions(-) create mode 100644 src/controllers/custom/completeAllMissionsController.ts diff --git a/config.json.example b/config.json.example index 9287091c..78eac7a1 100644 --- a/config.json.example +++ b/config.json.example @@ -13,7 +13,6 @@ "skipTutorial": false, "skipAllDialogue": false, "unlockAllScans": false, - "unlockAllMissions": false, "infiniteCredits": false, "infinitePlatinum": false, "infiniteEndo": false, diff --git a/src/controllers/api/inventoryController.ts b/src/controllers/api/inventoryController.ts index cdaf8d4d..ed4b8cff 100644 --- a/src/controllers/api/inventoryController.ts +++ b/src/controllers/api/inventoryController.ts @@ -6,13 +6,7 @@ import allDialogue from "@/static/fixed_responses/allDialogue.json"; import { ILoadoutDatabase } from "@/src/types/saveLoadoutTypes"; import { IInventoryClient, IShipInventory, equipmentKeys } from "@/src/types/inventoryTypes/inventoryTypes"; import { IPolarity, ArtifactPolarity, EquipmentFeatures } from "@/src/types/inventoryTypes/commonInventoryTypes"; -import { - ExportCustoms, - ExportFlavour, - ExportRegions, - ExportResources, - ExportVirtuals -} from "warframe-public-export-plus"; +import { ExportCustoms, ExportFlavour, ExportResources, ExportVirtuals } from "warframe-public-export-plus"; import { applyCheatsToInfestedFoundry, handleSubsumeCompletion } from "@/src/services/infestedFoundryService"; import { addMiscItems, @@ -22,7 +16,7 @@ import { generateRewardSeed } from "@/src/services/inventoryService"; import { logger } from "@/src/utils/logger"; -import { catBreadHash } from "@/src/helpers/stringHelpers"; +import { addString, catBreadHash } from "@/src/helpers/stringHelpers"; import { Types } from "mongoose"; import { getNemesisManifest } from "@/src/helpers/nemesisHelpers"; import { getPersonalRooms } from "@/src/services/personalRoomsService"; @@ -167,18 +161,6 @@ export const getInventoryResponse = async ( } } - if (config.unlockAllMissions) { - inventoryResponse.Missions = []; - for (const tag of Object.keys(ExportRegions)) { - inventoryResponse.Missions.push({ - Completes: 1, - Tier: 1, - Tag: tag - }); - } - addString(inventoryResponse.NodeIntrosCompleted, "TeshinHardModeUnlocked"); - } - if (config.unlockAllShipDecorations) { inventoryResponse.ShipDecorations = []; for (const [uniqueName, item] of Object.entries(ExportResources)) { @@ -362,12 +344,6 @@ const allEudicoHeistJobs = [ "/Lotus/Types/Gameplay/Venus/Jobs/Heists/HeistProfitTakerBountyFour" ]; -const addString = (arr: string[], str: string): void => { - if (arr.indexOf(str) == -1) { - arr.push(str); - } -}; - const getExpRequiredForMr = (rank: number): number => { if (rank <= 30) { return 2500 * rank * rank; diff --git a/src/controllers/custom/completeAllMissionsController.ts b/src/controllers/custom/completeAllMissionsController.ts new file mode 100644 index 00000000..2e7ac2fb --- /dev/null +++ b/src/controllers/custom/completeAllMissionsController.ts @@ -0,0 +1,34 @@ +import { addString } from "@/src/helpers/stringHelpers"; +import { getInventory } from "@/src/services/inventoryService"; +import { getAccountIdForRequest } from "@/src/services/loginService"; +import { addFixedLevelRewards } from "@/src/services/missionInventoryUpdateService"; +import { handleStoreItemAcquisition } from "@/src/services/purchaseService"; +import { IMissionReward } from "@/src/types/missionTypes"; +import { RequestHandler } from "express"; +import { ExportRegions } from "warframe-public-export-plus"; + +export const completeAllMissionsController: RequestHandler = async (req, res) => { + const accountId = await getAccountIdForRequest(req); + const inventory = await getInventory(accountId); + const MissionRewards: IMissionReward[] = []; + for (const [tag, node] of Object.entries(ExportRegions)) { + if (!inventory.Missions.find(x => x.Tag == tag)) { + inventory.Missions.push({ + Completes: 1, + Tier: 1, + Tag: tag + }); + + if (node.missionReward) { + console.log(node.missionReward); + addFixedLevelRewards(node.missionReward, inventory, MissionRewards); + } + } + } + for (const reward of MissionRewards) { + await handleStoreItemAcquisition(reward.StoreItem, inventory, reward.ItemCount, undefined, true); + } + addString(inventory.NodeIntrosCompleted, "TeshinHardModeUnlocked"); + await inventory.save(); + res.end(); +}; diff --git a/src/helpers/stringHelpers.ts b/src/helpers/stringHelpers.ts index 06d2ac28..3512c1ea 100644 --- a/src/helpers/stringHelpers.ts +++ b/src/helpers/stringHelpers.ts @@ -54,3 +54,9 @@ export const regexEscape = (str: string): string => { str = str.split("}").join("\\}"); return str; }; + +export const addString = (arr: string[], str: string): void => { + if (arr.indexOf(str) == -1) { + arr.push(str); + } +}; diff --git a/src/routes/custom.ts b/src/routes/custom.ts index 75eb80a4..35d89d4d 100644 --- a/src/routes/custom.ts +++ b/src/routes/custom.ts @@ -12,6 +12,7 @@ import { ircDroppedController } from "@/src/controllers/custom/ircDroppedControl import { unlockAllIntrinsicsController } from "@/src/controllers/custom/unlockAllIntrinsicsController"; import { addMissingMaxRankModsController } from "@/src/controllers/custom/addMissingMaxRankModsController"; import { webuiFileChangeDetectedController } from "@/src/controllers/custom/webuiFileChangeDetectedController"; +import { completeAllMissionsController } from "@/src/controllers/custom/completeAllMissionsController"; import { createAccountController } from "@/src/controllers/custom/createAccountController"; import { createMessageController } from "@/src/controllers/custom/createMessageController"; @@ -40,6 +41,7 @@ customRouter.get("/ircDropped", ircDroppedController); customRouter.get("/unlockAllIntrinsics", unlockAllIntrinsicsController); customRouter.get("/addMissingMaxRankMods", addMissingMaxRankModsController); customRouter.get("/webuiFileChangeDetected", webuiFileChangeDetectedController); +customRouter.get("/completeAllMissions", completeAllMissionsController); customRouter.post("/createAccount", createAccountController); customRouter.post("/createMessage", createMessageController); diff --git a/src/services/configService.ts b/src/services/configService.ts index 6ef2e96f..79d76d73 100644 --- a/src/services/configService.ts +++ b/src/services/configService.ts @@ -19,7 +19,6 @@ export interface IConfig { skipTutorial?: boolean; skipAllDialogue?: boolean; unlockAllScans?: boolean; - unlockAllMissions?: boolean; infiniteCredits?: boolean; infinitePlatinum?: boolean; infiniteEndo?: boolean; diff --git a/src/services/missionInventoryUpdateService.ts b/src/services/missionInventoryUpdateService.ts index 499115f9..e903f9de 100644 --- a/src/services/missionInventoryUpdateService.ts +++ b/src/services/missionInventoryUpdateService.ts @@ -1367,7 +1367,7 @@ export const addFixedLevelRewards = ( if (rewards.countedItems) { for (const item of rewards.countedItems) { MissionRewards.push({ - StoreItem: `/Lotus/StoreItems${item.ItemType.substring("Lotus/".length)}`, + StoreItem: toStoreItem(item.ItemType), ItemCount: item.ItemCount }); } diff --git a/static/webui/index.html b/static/webui/index.html index 1a748968..dca46e9d 100644 --- a/static/webui/index.html +++ b/static/webui/index.html @@ -452,9 +452,6 @@ -