From c06abded11bb3bad5c4f1f390f289f9bb0f3c3e5 Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Wed, 30 Apr 2025 13:27:36 -0700 Subject: [PATCH 1/9] fix: always multiply acquired gear quantity by purchaseQuantity (#1924) Closes #1915 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1924 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- src/controllers/api/inboxController.ts | 4 ++-- src/services/inventoryService.ts | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/controllers/api/inboxController.ts b/src/controllers/api/inboxController.ts index 7adc2d3d..7462de3e 100644 --- a/src/controllers/api/inboxController.ts +++ b/src/controllers/api/inboxController.ts @@ -11,7 +11,7 @@ import { import { getAccountForRequest, getAccountFromSuffixedName, getSuffixedName } from "@/src/services/loginService"; import { addItems, combineInventoryChanges, getInventory } from "@/src/services/inventoryService"; import { logger } from "@/src/utils/logger"; -import { ExportFlavour, ExportGear } from "warframe-public-export-plus"; +import { ExportFlavour } from "warframe-public-export-plus"; import { handleStoreItemAcquisition } from "@/src/services/purchaseService"; import { fromStoreItem, isStoreItem } from "@/src/services/itemDataService"; @@ -50,7 +50,7 @@ export const inboxController: RequestHandler = async (req, res) => { inventory, attachmentItems.map(attItem => ({ ItemType: isStoreItem(attItem) ? fromStoreItem(attItem) : attItem, - ItemCount: attItem in ExportGear ? (ExportGear[attItem].purchaseQuantity ?? 1) : 1 + ItemCount: 1 })), inventoryChanges ); diff --git a/src/services/inventoryService.ts b/src/services/inventoryService.ts index da8b0848..6c5a4b06 100644 --- a/src/services/inventoryService.ts +++ b/src/services/inventoryService.ts @@ -486,6 +486,10 @@ export const addItem = async ( }; } if (typeName in ExportGear) { + // Multipling by purchase quantity for gear because: + // - The Saya's Vigil scanner message has it as a non-counted attachment. + // - Blueprints for Ancient Protector Specter, Shield Osprey Specter, etc. have num=1 despite giving their purchaseQuantity. + quantity *= ExportGear[typeName].purchaseQuantity ?? 1; const consumablesChanges = [ { ItemType: typeName, From 3de68e51d5fccabb4a64d7209b33c11c9fc54886 Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Wed, 30 Apr 2025 13:27:47 -0700 Subject: [PATCH 2/9] fix: properly set Harvestable & DeathSquadable fields (#1925) Closes #1916 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1925 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- src/models/inventoryModels/inventoryModel.ts | 4 +- src/services/missionInventoryUpdateService.ts | 54 ++++++++----------- src/types/requestTypes.ts | 1 + 3 files changed, 25 insertions(+), 34 deletions(-) diff --git a/src/models/inventoryModels/inventoryModel.ts b/src/models/inventoryModels/inventoryModel.ts index dcb5a536..f3c8f0d8 100644 --- a/src/models/inventoryModels/inventoryModel.ts +++ b/src/models/inventoryModels/inventoryModel.ts @@ -1688,9 +1688,9 @@ const inventorySchema = new Schema( //Like BossAladV,BossCaptainVor come for you on missions % chance DeathMarks: { type: [String], default: [] }, //Zanuka - Harvestable: Boolean, + Harvestable: { type: Boolean, default: true }, //Grustag three - DeathSquadable: Boolean, + DeathSquadable: { type: Boolean, default: true }, EndlessXP: { type: [endlessXpProgressSchema], default: undefined }, diff --git a/src/services/missionInventoryUpdateService.ts b/src/services/missionInventoryUpdateService.ts index 66328a0d..18073ce8 100644 --- a/src/services/missionInventoryUpdateService.ts +++ b/src/services/missionInventoryUpdateService.ts @@ -143,38 +143,6 @@ export const addMissionInventoryUpdates = async ( ]); } } - - // Somewhat heuristically detect G3 capture: - // - https://onlyg.it/OpenWF/SpaceNinjaServer/issues/1365 - // - https://onlyg.it/OpenWF/SpaceNinjaServer/issues/1694 - // - https://onlyg.it/OpenWF/SpaceNinjaServer/issues/1724 - if ( - inventoryUpdates.MissionFailed && - inventoryUpdates.MissionStatus == "GS_FAILURE" && - inventoryUpdates.ObjectiveReached && - !inventoryUpdates.LockedWeaponGroup && - !inventory.LockedWeaponGroup && - !inventoryUpdates.LevelKeyName - ) { - const loadout = (await Loadout.findById(inventory.LoadOutPresets, "NORMAL"))!; - const config = loadout.NORMAL.id(inventory.CurrentLoadOutIds[0].$oid)!; - const SuitId = new Types.ObjectId(config.s!.ItemId.$oid); - - inventory.BrandedSuits ??= []; - if (!inventory.BrandedSuits.find(x => x.equals(SuitId))) { - inventory.BrandedSuits.push(SuitId); - - await createMessage(inventory.accountOwnerId, [ - { - sndr: "/Lotus/Language/Menu/Mailbox_WarframeSender", - msg: "/Lotus/Language/G1Quests/BrandedMessage", - sub: "/Lotus/Language/G1Quests/BrandedTitle", - att: ["/Lotus/Types/Recipes/Components/BrandRemovalBlueprint"], - highPriority: true // TOVERIFY: I cannot find any content of this within the last 10 years so I can only assume that highPriority is set (it certainly would make sense), but I just don't know for sure that it is so on live. - } - ]); - } - } } if (inventoryUpdates.RewardInfo) { if (inventoryUpdates.RewardInfo.periodicMissionTag) { @@ -537,6 +505,23 @@ export const addMissionInventoryUpdates = async ( } break; } + case "BrandedSuits": { + inventory.BrandedSuits ??= []; + if (!inventory.BrandedSuits.find(x => x.equals(value.$oid))) { + inventory.BrandedSuits.push(new Types.ObjectId(value.$oid)); + + await createMessage(inventory.accountOwnerId, [ + { + sndr: "/Lotus/Language/Menu/Mailbox_WarframeSender", + msg: "/Lotus/Language/G1Quests/BrandedMessage", + sub: "/Lotus/Language/G1Quests/BrandedTitle", + att: ["/Lotus/Types/Recipes/Components/BrandRemovalBlueprint"], + highPriority: true // TOVERIFY: I cannot find any content of this within the last 10 years so I can only assume that highPriority is set (it certainly would make sense), but I just don't know for sure that it is so on live. + } + ]); + } + break; + } case "LockedWeaponGroup": { inventory.LockedWeaponGroup = { s: new Types.ObjectId(value.s.$oid), @@ -545,12 +530,17 @@ export const addMissionInventoryUpdates = async ( m: value.m ? new Types.ObjectId(value.m.$oid) : undefined, sn: value.sn ? new Types.ObjectId(value.sn.$oid) : undefined }; + inventory.Harvestable = false; break; } case "UnlockWeapons": { inventory.LockedWeaponGroup = undefined; break; } + case "IncHarvester": { + inventory.Harvestable = true; + break; + } case "CurrentLoadOutIds": { if (value.LoadOuts) { const loadout = await Loadout.findOne({ loadoutOwnerId: inventory.accountOwnerId }); diff --git a/src/types/requestTypes.ts b/src/types/requestTypes.ts index 976c48f5..e47b5b86 100644 --- a/src/types/requestTypes.ts +++ b/src/types/requestTypes.ts @@ -130,6 +130,7 @@ export type IMissionInventoryUpdateRequest = { }[]; KubrowPetEggs?: IKubrowPetEggClient[]; DiscoveredMarkers?: IDiscoveredMarker[]; + BrandedSuits?: IOid; // sent when captured by g3 LockedWeaponGroup?: ILockedWeaponGroupClient; // sent when captured by zanuka UnlockWeapons?: boolean; // sent when recovered weapons from zanuka capture IncHarvester?: boolean; // sent when recovered weapons from zanuka capture From 660768b53b254bc8deeef0403b3559f9df9956f3 Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Wed, 30 Apr 2025 13:28:01 -0700 Subject: [PATCH 3/9] fix: handle DuviriInfo being absent from inventory (#1926) Closes #1917 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1926 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- src/controllers/api/inventoryController.ts | 9 ++++++++- src/models/inventoryModels/inventoryModel.ts | 4 ++-- src/services/missionInventoryUpdateService.ts | 2 +- src/types/inventoryTypes/inventoryTypes.ts | 2 +- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/controllers/api/inventoryController.ts b/src/controllers/api/inventoryController.ts index e9b15a63..4f73a5f7 100644 --- a/src/controllers/api/inventoryController.ts +++ b/src/controllers/api/inventoryController.ts @@ -106,7 +106,14 @@ export const inventoryController: RequestHandler = async (request, response) => const currentDuviriMood = Math.trunc(Date.now() / 7200000); if (lastSyncDuviriMood != currentDuviriMood) { logger.debug(`refreshing duviri seed`); - inventory.DuviriInfo.Seed = generateRewardSeed(); + if (!inventory.DuviriInfo) { + inventory.DuviriInfo = { + Seed: generateRewardSeed(), + NumCompletions: 0 + }; + } else { + inventory.DuviriInfo.Seed = generateRewardSeed(); + } } } inventory.LastInventorySync = new Types.ObjectId(); diff --git a/src/models/inventoryModels/inventoryModel.ts b/src/models/inventoryModels/inventoryModel.ts index f3c8f0d8..8c53d608 100644 --- a/src/models/inventoryModels/inventoryModel.ts +++ b/src/models/inventoryModels/inventoryModel.ts @@ -391,8 +391,8 @@ MailboxSchema.set("toJSON", { const DuviriInfoSchema = new Schema( { - Seed: BigInt, - NumCompletions: { type: Number, default: 0 } + Seed: { type: BigInt, required: true }, + NumCompletions: { type: Number, required: true } }, { _id: false, diff --git a/src/services/missionInventoryUpdateService.ts b/src/services/missionInventoryUpdateService.ts index 18073ce8..0b0b3f72 100644 --- a/src/services/missionInventoryUpdateService.ts +++ b/src/services/missionInventoryUpdateService.ts @@ -601,7 +601,7 @@ export const addMissionInventoryUpdates = async ( case "duviriCaveOffers": { // Duviri cave offers (generated with the duviri seed) change after completing one of its game modes (not when aborting). if (inventoryUpdates.MissionStatus != "GS_QUIT") { - inventory.DuviriInfo.Seed = generateRewardSeed(); + inventory.DuviriInfo!.Seed = generateRewardSeed(); } break; } diff --git a/src/types/inventoryTypes/inventoryTypes.ts b/src/types/inventoryTypes/inventoryTypes.ts index 4973ff87..92b6973e 100644 --- a/src/types/inventoryTypes/inventoryTypes.ts +++ b/src/types/inventoryTypes/inventoryTypes.ts @@ -202,7 +202,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu OperatorLoadOuts: IOperatorConfigClient[]; KahlLoadOuts: IOperatorConfigClient[]; - DuviriInfo: IDuviriInfo; + DuviriInfo?: IDuviriInfo; Mailbox?: IMailboxClient; SubscribedToEmails: number; Created: IMongoDate; From 3d6c880c96537a4b34cd3622757815dc2eef5ade Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Wed, 30 Apr 2025 13:28:16 -0700 Subject: [PATCH 4/9] feat: handle client setting InfestationDate on equipment (#1927) Closes #1919 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1927 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- src/controllers/custom/addXpController.ts | 4 ++-- src/helpers/inventoryHelpers.ts | 4 ++++ src/services/inventoryService.ts | 18 +++++++++++------- src/services/missionInventoryUpdateService.ts | 5 ++--- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/controllers/custom/addXpController.ts b/src/controllers/custom/addXpController.ts index 7cb284fe..0ca05102 100644 --- a/src/controllers/custom/addXpController.ts +++ b/src/controllers/custom/addXpController.ts @@ -1,4 +1,4 @@ -import { addGearExpByCategory, getInventory } from "@/src/services/inventoryService"; +import { applyClientEquipmentUpdates, getInventory } from "@/src/services/inventoryService"; import { getAccountIdForRequest } from "@/src/services/loginService"; import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes"; import { TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes"; @@ -20,7 +20,7 @@ export const addXpController: RequestHandler = async (req, res) => { } } } - addGearExpByCategory(inventory, gear, category as TEquipmentKey); + applyClientEquipmentUpdates(inventory, gear, category as TEquipmentKey); } await inventory.save(); res.end(); diff --git a/src/helpers/inventoryHelpers.ts b/src/helpers/inventoryHelpers.ts index 79466fb3..4dd38c5a 100644 --- a/src/helpers/inventoryHelpers.ts +++ b/src/helpers/inventoryHelpers.ts @@ -10,6 +10,10 @@ export const toMongoDate = (date: Date): IMongoDate => { return { $date: { $numberLong: date.getTime().toString() } }; }; +export const fromMongoData = (date: IMongoDate): Date => { + return new Date(parseInt(date.$date.$numberLong)); +}; + export const kubrowWeights: Record = { COMMON: 6, UNCOMMON: 4, diff --git a/src/services/inventoryService.ts b/src/services/inventoryService.ts index 6c5a4b06..043383b1 100644 --- a/src/services/inventoryService.ts +++ b/src/services/inventoryService.ts @@ -69,6 +69,7 @@ import { import { createShip } from "./shipService"; import { catbrowDetails, + fromMongoData, kubrowDetails, kubrowFurPatternsWeights, kubrowWeights, @@ -1475,21 +1476,20 @@ export const addEmailItem = async ( return inventoryChanges; }; -//TODO: wrong id is not erroring -export const addGearExpByCategory = ( +export const applyClientEquipmentUpdates = ( inventory: TInventoryDatabaseDocument, gearArray: IEquipmentClient[], categoryName: TEquipmentKey ): void => { const category = inventory[categoryName]; - gearArray.forEach(({ ItemId, XP }) => { - if (!XP) { - return; + gearArray.forEach(({ ItemId, XP, InfestationDate }) => { + const item = category.id(ItemId.$oid); + if (!item) { + throw new Error(`No item with id ${ItemId.$oid} in ${categoryName}`); } - const item = category.id(ItemId.$oid); - if (item) { + if (XP) { item.XP ??= 0; item.XP += XP; @@ -1504,6 +1504,10 @@ export const addGearExpByCategory = ( }); } } + + if (InfestationDate) { + item.InfestationDate = fromMongoData(InfestationDate); + } }); }; diff --git a/src/services/missionInventoryUpdateService.ts b/src/services/missionInventoryUpdateService.ts index 0b0b3f72..dc670c59 100644 --- a/src/services/missionInventoryUpdateService.ts +++ b/src/services/missionInventoryUpdateService.ts @@ -21,7 +21,6 @@ import { addFocusXpIncreases, addFusionPoints, addFusionTreasures, - addGearExpByCategory, addItem, addLevelKeys, addLoreFragmentScans, @@ -32,6 +31,7 @@ import { addShipDecorations, addSkin, addStanding, + applyClientEquipmentUpdates, combineInventoryChanges, generateRewardSeed, getCalendarProgress, @@ -660,9 +660,8 @@ export const addMissionInventoryUpdates = async ( } break; default: - // Equipment XP updates if (equipmentKeys.includes(key as TEquipmentKey)) { - addGearExpByCategory(inventory, value as IEquipmentClient[], key as TEquipmentKey); + applyClientEquipmentUpdates(inventory, value as IEquipmentClient[], key as TEquipmentKey); } break; // if ( From ed54e00a03127929e6df11b7ebd08a304080b638 Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Wed, 30 Apr 2025 13:28:24 -0700 Subject: [PATCH 5/9] fix: compatibility with echoes of duviri (#1928) Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1928 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- src/controllers/api/inboxController.ts | 15 ++++++++++++--- src/services/worldStateService.ts | 22 ++++++++++++++++++++++ src/types/worldStateTypes.ts | 13 +++++++++++++ 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/src/controllers/api/inboxController.ts b/src/controllers/api/inboxController.ts index 7462de3e..94d253ad 100644 --- a/src/controllers/api/inboxController.ts +++ b/src/controllers/api/inboxController.ts @@ -14,6 +14,7 @@ import { logger } from "@/src/utils/logger"; import { ExportFlavour } from "warframe-public-export-plus"; import { handleStoreItemAcquisition } from "@/src/services/purchaseService"; import { fromStoreItem, isStoreItem } from "@/src/services/itemDataService"; +import { IOid } from "@/src/types/commonTypes"; export const inboxController: RequestHandler = async (req, res) => { const { deleteId, lastMessage: latestClientMessageId, messageId } = req.query; @@ -28,10 +29,10 @@ export const inboxController: RequestHandler = async (req, res) => { return; } - await deleteMessageRead(deleteId as string); + await deleteMessageRead(parseOid(deleteId as string)); res.status(200).end(); } else if (messageId) { - const message = await getMessage(messageId as string); + const message = await getMessage(parseOid(messageId as string)); message.r = true; await message.save(); @@ -100,7 +101,7 @@ export const inboxController: RequestHandler = async (req, res) => { await createNewEventMessages(req); const messages = await Inbox.find({ ownerId: accountId }).sort({ date: 1 }); - const latestClientMessage = messages.find(m => m._id.toString() === latestClientMessageId); + const latestClientMessage = messages.find(m => m._id.toString() === parseOid(latestClientMessageId as string)); if (!latestClientMessage) { logger.debug(`this should only happen after DeleteAllRead `); @@ -123,3 +124,11 @@ export const inboxController: RequestHandler = async (req, res) => { res.json({ Inbox: inbox }); } }; + +// 33.6.0 has query arguments like lastMessage={"$oid":"68112baebf192e786d1502bb"} instead of lastMessage=68112baebf192e786d1502bb +const parseOid = (oid: string): string => { + if (oid[0] == "{") { + return (JSON.parse(oid) as IOid).$oid; + } + return oid; +}; diff --git a/src/services/worldStateService.ts b/src/services/worldStateService.ts index e2e2ea23..9350360e 100644 --- a/src/services/worldStateService.ts +++ b/src/services/worldStateService.ts @@ -724,6 +724,11 @@ export const getWorldState = (buildLabel?: string): IWorldState => { SyndicateMissions: [...staticWorldState.SyndicateMissions] }; + // Omit void fissures for versions prior to Whispers in the Walls to avoid errors with the unknown deimos nodes having void fissures. + if (buildLabel && version_compare(buildLabel, "2023.11.06.13.39") <= 0) { + worldState.ActiveMissions = []; + } + if (config.worldState?.starDays) { worldState.Goals.push({ _id: { $oid: "67a4dcce2a198564d62e1647" }, @@ -1227,3 +1232,20 @@ export const isArchwingMission = (node: IRegion): boolean => { } return false; }; + +export const version_compare = (a: string, b: string): number => { + const a_digits = a + .split("/")[0] + .split(".") + .map(x => parseInt(x)); + const b_digits = b + .split("/")[0] + .split(".") + .map(x => parseInt(x)); + for (let i = 0; i != a_digits.length; ++i) { + if (a_digits[i] != b_digits[i]) { + return a_digits[i] > b_digits[i] ? 1 : -1; + } + } + return 0; +}; diff --git a/src/types/worldStateTypes.ts b/src/types/worldStateTypes.ts index 303c3c33..1e8d4033 100644 --- a/src/types/worldStateTypes.ts +++ b/src/types/worldStateTypes.ts @@ -10,6 +10,7 @@ export interface IWorldState { LiteSorties: ILiteSortie[]; SyndicateMissions: ISyndicateMissionInfo[]; GlobalUpgrades: IGlobalUpgrade[]; + ActiveMissions: IFissure[]; NodeOverrides: INodeOverride[]; EndlessXpChoices: IEndlessXpChoice[]; SeasonInfo: { @@ -71,6 +72,18 @@ export interface IGlobalUpgrade { LocalizeDescTag: string; } +export interface IFissure { + _id: IOid; + Region: number; + Seed: number; + Activation: IMongoDate; + Expiry: IMongoDate; + Node: string; + MissionType: string; + Modifier: string; + Hard?: boolean; +} + export interface INodeOverride { _id: IOid; Activation?: IMongoDate; From 7d02906656324900f99d3aa9b2599cd724fd44fe Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Wed, 30 Apr 2025 13:28:34 -0700 Subject: [PATCH 6/9] fix: better handling of assassination missions in sorties (#1930) Closes #1918 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1930 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- src/services/rngService.ts | 6 ++-- src/services/worldStateService.ts | 59 ++++++++++++++----------------- 2 files changed, 29 insertions(+), 36 deletions(-) diff --git a/src/services/rngService.ts b/src/services/rngService.ts index 68225ca1..0e836466 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 | undefined => { +export const getRandomElement = (arr: readonly T[]): T | undefined => { return arr[Math.floor(Math.random() * arr.length)]; }; @@ -113,7 +113,7 @@ export class CRng { return min; } - randomElement(arr: T[]): T | undefined { + randomElement(arr: readonly T[]): T | undefined { return arr[Math.floor(this.random() * arr.length)]; } @@ -145,7 +145,7 @@ export class SRng { return min; } - randomElement(arr: T[]): T | undefined { + randomElement(arr: readonly T[]): T | undefined { return arr[this.randomInt(0, arr.length - 1)]; } diff --git a/src/services/worldStateService.ts b/src/services/worldStateService.ts index 9350360e..a8b4cf5a 100644 --- a/src/services/worldStateService.ts +++ b/src/services/worldStateService.ts @@ -33,9 +33,11 @@ const sortieBosses = [ "SORTIE_BOSS_LEPHANTIS", "SORTIE_BOSS_INFALAD", "SORTIE_BOSS_CORRUPTED_VOR" -]; +] as const; -const sortieBossToFaction: Record = { +type TSortieBoss = (typeof sortieBosses)[number]; + +const sortieBossToFaction: Record = { SORTIE_BOSS_HYENA: "FC_CORPUS", SORTIE_BOSS_KELA: "FC_GRINEER", SORTIE_BOSS_VOR: "FC_GRINEER", @@ -74,21 +76,22 @@ const sortieFactionToSpecialMissionTileset: Record = { FC_INFESTATION: "CorpusShipTileset" }; -const sortieBossNode: Record = { - SORTIE_BOSS_HYENA: "SolNode127", - SORTIE_BOSS_KELA: "SolNode193", - SORTIE_BOSS_VOR: "SolNode108", - SORTIE_BOSS_RUK: "SolNode32", - SORTIE_BOSS_HEK: "SolNode24", - SORTIE_BOSS_KRIL: "SolNode99", - SORTIE_BOSS_TYL: "SolNode105", - SORTIE_BOSS_JACKAL: "SolNode104", +const sortieBossNode: Record, string> = { SORTIE_BOSS_ALAD: "SolNode53", SORTIE_BOSS_AMBULAS: "SolNode51", - SORTIE_BOSS_NEF: "SettlementNode20", - SORTIE_BOSS_RAPTOR: "SolNode210", + SORTIE_BOSS_HEK: "SolNode24", + SORTIE_BOSS_HYENA: "SolNode127", + SORTIE_BOSS_INFALAD: "SolNode166", + SORTIE_BOSS_JACKAL: "SolNode104", + SORTIE_BOSS_KELA: "SolNode193", + SORTIE_BOSS_KRIL: "SolNode99", SORTIE_BOSS_LEPHANTIS: "SolNode712", - SORTIE_BOSS_INFALAD: "SolNode705" + SORTIE_BOSS_NEF: "SettlementNode20", + SORTIE_BOSS_PHORID: "SolNode171", + SORTIE_BOSS_RAPTOR: "SolNode210", + SORTIE_BOSS_RUK: "SolNode32", + SORTIE_BOSS_TYL: "SolNode105", + SORTIE_BOSS_VOR: "SolNode108" }; const eidolonJobs = [ @@ -270,6 +273,7 @@ const pushSortieIfRelevant = (worldState: IWorldState, day: number): void => { key in sortieTilesets ) { if ( + value.missionIndex != 0 && // Assassination will be decided independently value.missionIndex != 5 && // Sorties do not have capture missions !availableMissionIndexes.includes(value.missionIndex) ) { @@ -310,28 +314,17 @@ const pushSortieIfRelevant = (worldState: IWorldState, day: number): void => { sortieFactionToSpecialMissionTileset[sortieBossToFaction[boss]] ); - if (i == 2 && rng.randomInt(0, 2) == 2) { + if (i == 2 && boss != "SORTIE_BOSS_CORRUPTED_VOR" && rng.randomInt(0, 2) == 2) { const filteredModifiers = modifiers.filter(mod => mod !== "SORTIE_MODIFIER_MELEE_ONLY"); const modifierType = rng.randomElement(filteredModifiers)!; - if (boss == "SORTIE_BOSS_PHORID") { - selectedNodes.push({ - missionType: "MT_ASSASSINATION", - modifierType, - node, - tileset: sortieTilesets[node as keyof typeof sortieTilesets] - }); - nodes.splice(randomIndex, 1); - continue; - } else if (sortieBossNode[boss]) { - selectedNodes.push({ - missionType: "MT_ASSASSINATION", - modifierType, - node: sortieBossNode[boss], - tileset: sortieTilesets[sortieBossNode[boss] as keyof typeof sortieTilesets] - }); - continue; - } + selectedNodes.push({ + missionType: "MT_ASSASSINATION", + modifierType, + node: sortieBossNode[boss], + tileset: sortieTilesets[sortieBossNode[boss] as keyof typeof sortieTilesets] + }); + continue; } const missionType = eMissionType[missionIndex].tag; From 2c3043f40ea323c1cfd6d66f21baaafe7a306c92 Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Wed, 30 Apr 2025 15:45:42 -0700 Subject: [PATCH 7/9] fix: login failure on U32 veilbreaker (#1932) Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1932 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- src/controllers/api/loginController.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/controllers/api/loginController.ts b/src/controllers/api/loginController.ts index 565bebf0..09fca8c7 100644 --- a/src/controllers/api/loginController.ts +++ b/src/controllers/api/loginController.ts @@ -7,6 +7,7 @@ import { Account } from "@/src/models/loginModel"; import { createAccount, isCorrectPassword, isNameTaken } from "@/src/services/loginService"; import { IDatabaseAccountJson, ILoginRequest, ILoginResponse } from "@/src/types/loginTypes"; import { logger } from "@/src/utils/logger"; +import { version_compare } from "@/src/services/worldStateService"; export const loginController: RequestHandler = async (request, response) => { const loginRequest = JSON.parse(String(request.body)) as ILoginRequest; // parse octet stream of json data to json object @@ -94,7 +95,7 @@ export const loginController: RequestHandler = async (request, response) => { }; const createLoginResponse = (myAddress: string, account: IDatabaseAccountJson, buildLabel: string): ILoginResponse => { - return { + const resp: ILoginResponse = { id: account.id, DisplayName: account.DisplayName, CountryCode: account.CountryCode, @@ -108,11 +109,14 @@ const createLoginResponse = (myAddress: string, account: IDatabaseAccountJson, b Nonce: account.Nonce, Groups: [], IRC: config.myIrcAddresses ?? [myAddress], - platformCDNs: [`https://${myAddress}/`], HUB: `https://${myAddress}/api/`, NRS: config.NRS, DTLS: 99, BuildLabel: buildLabel, MatchmakingBuildId: buildConfig.matchmakingBuildId }; + if (version_compare(buildLabel, "2023.04.25.23.40") >= 0) { + resp.platformCDNs = [`https://${myAddress}/`]; + } + return resp; }; From c4b2248df5e77c52c2b6a027fc492020df90fe18 Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Wed, 30 Apr 2025 23:50:02 -0700 Subject: [PATCH 8/9] fix: login failure on U31.5 angels of the zariman (#1933) Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1933 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- src/controllers/api/loginController.ts | 14 ++++++++------ src/types/loginTypes.ts | 4 ++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/controllers/api/loginController.ts b/src/controllers/api/loginController.ts index 09fca8c7..cf5f759f 100644 --- a/src/controllers/api/loginController.ts +++ b/src/controllers/api/loginController.ts @@ -100,7 +100,6 @@ const createLoginResponse = (myAddress: string, account: IDatabaseAccountJson, b DisplayName: account.DisplayName, CountryCode: account.CountryCode, ClientType: account.ClientType, - CrossPlatformAllowed: account.CrossPlatformAllowed, ForceLogoutVersion: account.ForceLogoutVersion, AmazonAuthToken: account.AmazonAuthToken, AmazonRefreshToken: account.AmazonRefreshToken, @@ -109,14 +108,17 @@ const createLoginResponse = (myAddress: string, account: IDatabaseAccountJson, b Nonce: account.Nonce, Groups: [], IRC: config.myIrcAddresses ?? [myAddress], - HUB: `https://${myAddress}/api/`, NRS: config.NRS, DTLS: 99, - BuildLabel: buildLabel, - MatchmakingBuildId: buildConfig.matchmakingBuildId + BuildLabel: buildLabel }; - if (version_compare(buildLabel, "2023.04.25.23.40") >= 0) { - resp.platformCDNs = [`https://${myAddress}/`]; + if (version_compare(buildLabel, "2022.09.06.19.24") >= 0) { + resp.CrossPlatformAllowed = account.CrossPlatformAllowed; + resp.HUB = `https://${myAddress}/api/`; + resp.MatchmakingBuildId = buildConfig.matchmakingBuildId; + if (version_compare(buildLabel, "2023.04.25.23.40") >= 0) { + resp.platformCDNs = [`https://${myAddress}/`]; + } } return resp; }; diff --git a/src/types/loginTypes.ts b/src/types/loginTypes.ts index 17128e2a..654bc4dc 100644 --- a/src/types/loginTypes.ts +++ b/src/types/loginTypes.ts @@ -4,7 +4,7 @@ export interface IAccountAndLoginResponseCommons { DisplayName: string; CountryCode: string; ClientType: string; - CrossPlatformAllowed: boolean; + CrossPlatformAllowed?: boolean; ForceLogoutVersion: number; AmazonAuthToken?: string; AmazonRefreshToken?: string; @@ -46,7 +46,7 @@ export interface ILoginResponse extends IAccountAndLoginResponseCommons { id: string; Groups: IGroup[]; BuildLabel: string; - MatchmakingBuildId: string; + MatchmakingBuildId?: string; platformCDNs?: string[]; NRS?: string[]; DTLS: number; From 8eefd67d79d8f2d5e3adf8efa184205417cccca0 Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Thu, 1 May 2025 13:09:45 +0200 Subject: [PATCH 9/9] chore: fix typo --- src/helpers/inventoryHelpers.ts | 2 +- src/services/inventoryService.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/helpers/inventoryHelpers.ts b/src/helpers/inventoryHelpers.ts index 4dd38c5a..5efc801d 100644 --- a/src/helpers/inventoryHelpers.ts +++ b/src/helpers/inventoryHelpers.ts @@ -10,7 +10,7 @@ export const toMongoDate = (date: Date): IMongoDate => { return { $date: { $numberLong: date.getTime().toString() } }; }; -export const fromMongoData = (date: IMongoDate): Date => { +export const fromMongoDate = (date: IMongoDate): Date => { return new Date(parseInt(date.$date.$numberLong)); }; diff --git a/src/services/inventoryService.ts b/src/services/inventoryService.ts index 043383b1..089e2fbb 100644 --- a/src/services/inventoryService.ts +++ b/src/services/inventoryService.ts @@ -69,7 +69,7 @@ import { import { createShip } from "./shipService"; import { catbrowDetails, - fromMongoData, + fromMongoDate, kubrowDetails, kubrowFurPatternsWeights, kubrowWeights, @@ -1506,7 +1506,7 @@ export const applyClientEquipmentUpdates = ( } if (InfestationDate) { - item.InfestationDate = fromMongoData(InfestationDate); + item.InfestationDate = fromMongoDate(InfestationDate); } }); };