From e7287933b55bcfe485046a616f109e7ef1477a03 Mon Sep 17 00:00:00 2001 From: Corvus Date: Tue, 29 Jul 2025 07:33:57 -0700 Subject: [PATCH 01/14] chore(webui): update Chinese translation (#2563) Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2563 Co-authored-by: Corvus Co-committed-by: Corvus --- static/webui/translations/zh.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/static/webui/translations/zh.js b/static/webui/translations/zh.js index e8e486b4..d7ceb437 100644 --- a/static/webui/translations/zh.js +++ b/static/webui/translations/zh.js @@ -156,8 +156,8 @@ dict = { invigorations_defensiveLabel: `功能型属性`, invigorations_expiryLabel: `活化时效(可选)`, - abilityOverride_label: `[UNTRANSLATED] Ability Override`, - abilityOverride_onSlot: `[UNTRANSLATED] on slot`, + abilityOverride_label: `技能替换`, + abilityOverride_onSlot: `槽位`, mods_addRiven: `添加裂罅MOD`, mods_fingerprint: `印记`, From 8f77c722cb6e2909f16bdc2afb402dbf59c36ae4 Mon Sep 17 00:00:00 2001 From: Animan8000 Date: Tue, 29 Jul 2025 07:34:04 -0700 Subject: [PATCH 02/14] chore(webui): update German translation (#2564) Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2564 Co-authored-by: Animan8000 Co-committed-by: Animan8000 --- static/webui/translations/de.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/static/webui/translations/de.js b/static/webui/translations/de.js index c23b8f61..2a325d4c 100644 --- a/static/webui/translations/de.js +++ b/static/webui/translations/de.js @@ -156,8 +156,8 @@ dict = { invigorations_defensiveLabel: `Defensives Upgrade`, invigorations_expiryLabel: `Upgrades Ablaufdatum (optional)`, - abilityOverride_label: `[UNTRANSLATED] Ability Override`, - abilityOverride_onSlot: `[UNTRANSLATED] on slot`, + abilityOverride_label: `Fähigkeitsüberschreibung`, + abilityOverride_onSlot: `auf Slot`, mods_addRiven: `Riven hinzufügen`, mods_fingerprint: `Fingerabdruck`, From 48e3f324e22cf921ab76082c45acfbaa3f983673 Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Wed, 30 Jul 2025 01:49:34 -0700 Subject: [PATCH 03/14] chore: log when worldState time is behind real time + make sure client knows fissures are active (#2562) Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2562 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- src/services/worldStateService.ts | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/services/worldStateService.ts b/src/services/worldStateService.ts index 7f5268c9..ac4f9b5d 100644 --- a/src/services/worldStateService.ts +++ b/src/services/worldStateService.ts @@ -1038,13 +1038,13 @@ const pushVoidStorms = (arr: IVoidStorm[], hour: number): void => { }; interface ITimeConstraint { - //name: string; + name: string; isValidTime: (timeSecs: number) => boolean; getIdealTimeBefore: (timeSecs: number) => number; } const eidolonDayConstraint: ITimeConstraint = { - //name: "eidolon day", + name: "eidolon day", isValidTime: (timeSecs: number): boolean => { const eidolonEpoch = 1391992660; const eidolonCycle = Math.trunc((timeSecs - eidolonEpoch) / 9000); @@ -1062,7 +1062,7 @@ const eidolonDayConstraint: ITimeConstraint = { }; const eidolonNightConstraint: ITimeConstraint = { - //name: "eidolon night", + name: "eidolon night", isValidTime: (timeSecs: number): boolean => { const eidolonEpoch = 1391992660; const eidolonCycle = Math.trunc((timeSecs - eidolonEpoch) / 9000); @@ -1089,7 +1089,7 @@ const eidolonNightConstraint: ITimeConstraint = { }; const venusColdConstraint: ITimeConstraint = { - //name: "venus cold", + name: "venus cold", isValidTime: (timeSecs: number): boolean => { const vallisEpoch = 1541837628; const vallisCycle = Math.trunc((timeSecs - vallisEpoch) / 1600); @@ -1115,7 +1115,7 @@ const venusColdConstraint: ITimeConstraint = { }; const venusWarmConstraint: ITimeConstraint = { - //name: "venus warm", + name: "venus warm", isValidTime: (timeSecs: number): boolean => { const vallisEpoch = 1541837628; const vallisCycle = Math.trunc((timeSecs - vallisEpoch) / 1600); @@ -1321,7 +1321,7 @@ export const getWorldState = (buildLabel?: string): IWorldState => { }); } else { constraints.push({ - //name: `duviri ${config.worldState.duviriOverride}`, + name: `duviri ${config.worldState.duviriOverride}`, isValidTime: (timeSecs: number): boolean => { const moodIndex = Math.trunc(timeSecs / 7200); return moodIndex % 5 == desiredMood; @@ -1336,6 +1336,14 @@ export const getWorldState = (buildLabel?: string): IWorldState => { } } const timeSecs = getIdealTimeSatsifyingConstraints(constraints); + if (constraints.length != 0) { + const delta = Math.trunc(Date.now() / 1000) - timeSecs; + if (delta > 1) { + logger.debug( + `reported time is ${delta} seconds behind real time to satisfy selected constraints (${constraints.map(x => x.name).join(", ")})` + ); + } + } const timeMs = timeSecs * 1000; const day = Math.trunc((timeMs - EPOCH) / 86400000); const week = Math.trunc(day / 7); @@ -1823,7 +1831,10 @@ export const populateFissures = async (worldState: IWorldState): Promise = _id: toOid(fissure._id), Region: meta.systemIndex + 1, Seed: 1337, - Activation: toMongoDate(fissure.Activation), + Activation: + fissure.Activation.getTime() < Date.now() // Activation is in the past? + ? { $date: { $numberLong: "1000000000000" } } // Let the client know 'explicitly' to avoid interference from time constraints. + : toMongoDate(fissure.Activation), Expiry: toMongoDate(fissure.Expiry), Node: fissure.Node, MissionType: eMissionType[meta.missionIndex].tag, From 522924a823afa761526c846c2a8765d0f2f0eeea Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Wed, 30 Jul 2025 01:49:55 -0700 Subject: [PATCH 04/14] chore: remove empty ModularParts arrays from equipment (#2565) Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2565 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- src/services/inventoryService.ts | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/services/inventoryService.ts b/src/services/inventoryService.ts index 681ed578..8d2295d6 100644 --- a/src/services/inventoryService.ts +++ b/src/services/inventoryService.ts @@ -25,7 +25,8 @@ import { INemesisWeaponTargetFingerprint, INemesisPetTargetFingerprint, IDialogueDatabase, - IKubrowPetPrintClient + IKubrowPetPrintClient, + equipmentKeys } from "@/src/types/inventoryTypes/inventoryTypes"; import { IGenericUpdate, IUpdateNodeIntrosResponse } from "@/src/types/genericUpdate"; import { IKeyChainRequest, IMissionInventoryUpdateRequest } from "@/src/types/requestTypes"; @@ -2117,6 +2118,21 @@ export const cleanupInventory = (inventory: TInventoryDatabaseDocument): void => inventory.LotusCustomization.syancol = {}; } } + + { + let numFixed = 0; + for (const equipmentKey of equipmentKeys) { + for (const item of inventory[equipmentKey]) { + if (item.ModularParts?.length === 0) { + item.ModularParts = undefined; + ++numFixed; + } + } + } + if (numFixed != 0) { + logger.debug(`removed ModularParts from ${numFixed} non-modular items`); + } + } }; export const getDialogue = (inventory: TInventoryDatabaseDocument, dialogueName: string): IDialogueDatabase => { From 8e639a16bd6cbb03c5b39caf6bf283396c9128cb Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Wed, 30 Jul 2025 01:50:23 -0700 Subject: [PATCH 05/14] feat: initial protovyre/evolving cosmetics (#2566) Basic handling of sending the challenge rewards to the inbox upon completion. Re #2485. Still missing handling for the Protovyre armor pieces which require killing sentients. Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2566 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- .../api/updateChallengeProgressController.ts | 3 +- src/services/inventoryService.ts | 80 ++++++++++++++++--- src/services/missionInventoryUpdateService.ts | 2 +- 3 files changed, 74 insertions(+), 11 deletions(-) diff --git a/src/controllers/api/updateChallengeProgressController.ts b/src/controllers/api/updateChallengeProgressController.ts index b75e820a..e0547c7f 100644 --- a/src/controllers/api/updateChallengeProgressController.ts +++ b/src/controllers/api/updateChallengeProgressController.ts @@ -10,6 +10,7 @@ import { logger } from "@/src/utils/logger"; export const updateChallengeProgressController: RequestHandler = async (req, res) => { const challenges = getJSONfromString(String(req.body)); const account = await getAccountForRequest(req); + logger.debug(`challenge report:`, challenges); const inventory = await getInventory( account._id.toString(), @@ -17,7 +18,7 @@ export const updateChallengeProgressController: RequestHandler = async (req, res ); let affiliationMods: IAffiliationMods[] = []; if (challenges.ChallengeProgress) { - affiliationMods = addChallenges( + affiliationMods = await addChallenges( account, inventory, challenges.ChallengeProgress, diff --git a/src/services/inventoryService.ts b/src/services/inventoryService.ts index 8d2295d6..c8949513 100644 --- a/src/services/inventoryService.ts +++ b/src/services/inventoryService.ts @@ -1904,25 +1904,87 @@ export const addLoreFragmentScans = (inventory: TInventoryDatabaseDocument, arr: }); }; -export const addChallenges = ( +const challengeRewardsInboxMessages: Record = { + SentEvoEphemeraRankOne: { + sub: "/Lotus/Language/Inbox/EvolvingEphemeraUnlockAName", + sndr: "/Lotus/Language/Bosses/Ordis", + msg: "/Lotus/Language/Inbox/EvolvingEphemeraUnlockADesc", + icon: "/Lotus/Interface/Icons/Npcs/Ordis.png", + att: ["/Lotus/Upgrades/Skins/Effects/NarmerEvolvingEphemeraB"] + }, + SentEvoEphemeraRankTwo: { + sub: "/Lotus/Language/Inbox/EvolvingEphemeraUnlockBName", + sndr: "/Lotus/Language/Bosses/Ordis", + msg: "/Lotus/Language/Inbox/EvolvingEphemeraUnlockBDesc", + icon: "/Lotus/Interface/Icons/Npcs/Ordis.png", + att: ["/Lotus/Upgrades/Skins/Effects/NarmerEvolvingEphemeraC"] + }, + SentEvoSyandanaRankOne: { + sub: "/Lotus/Language/Inbox/EvolvingSyandanaUnlockAName", + sndr: "/Lotus/Language/Bosses/Ordis", + msg: "/Lotus/Language/Inbox/EvolvingSyandanaUnlockADesc", + icon: "/Lotus/Interface/Icons/Npcs/Ordis.png", + att: ["/Lotus/Upgrades/Skins/Scarves/NarmerEvolvingSyandanaBCape"] + }, + SentEvoSyandanaRankTwo: { + sub: "/Lotus/Language/Inbox/EvolvingSyandanaUnlockBName", + sndr: "/Lotus/Language/Bosses/Ordis", + msg: "/Lotus/Language/Inbox/EvolvingSyandanaUnlockBDesc", + icon: "/Lotus/Interface/Icons/Npcs/Ordis.png", + att: ["/Lotus/Upgrades/Skins/Scarves/NarmerEvolvingSyandanaCCape"] + }, + SentEvoSekharaRankOne: { + sub: "/Lotus/Language/Inbox/EvolvingSekharaUnlockAName", + sndr: "/Lotus/Language/Bosses/Ordis", + msg: "/Lotus/Language/Inbox/EvolvingSekharaUnlockADesc", + icon: "/Lotus/Interface/Icons/Npcs/Ordis.png", + att: ["/Lotus/Upgrades/Skins/Clan/ZarimanEvolvingSekharaBadgeItemB"] + }, + SentEvoSekharaRankTwo: { + sub: "/Lotus/Language/Inbox/EvolvingSekharaUnlockBName", + sndr: "/Lotus/Language/Bosses/Ordis", + msg: "/Lotus/Language/Inbox/EvolvingSekharaUnlockBDesc", + icon: "/Lotus/Interface/Icons/Npcs/Ordis.png", + att: ["/Lotus/Upgrades/Skins/Clan/ZarimanEvolvingSekharaBadgeItemC"] + } +}; + +export const addChallenges = async ( account: TAccountDocument, inventory: TInventoryDatabaseDocument, ChallengeProgress: IChallengeProgress[], SeasonChallengeCompletions: ISeasonChallenge[] | undefined -): IAffiliationMods[] => { - ChallengeProgress.forEach(({ Name, Progress }) => { - const itemIndex = inventory.ChallengeProgress.findIndex(i => i.Name === Name); - - if (itemIndex !== -1) { - inventory.ChallengeProgress[itemIndex].Progress = Progress; +): Promise => { + for (const { Name, Progress, Completed } of ChallengeProgress) { + let dbChallenge = inventory.ChallengeProgress.find(x => x.Name == Name); + if (dbChallenge) { + dbChallenge.Progress = Progress; } else { - inventory.ChallengeProgress.push({ Name, Progress }); + dbChallenge = { Name, Progress }; + inventory.ChallengeProgress.push(dbChallenge); } if (Name.startsWith("Calendar")) { addString(getCalendarProgress(inventory).SeasonProgress.ActivatedChallenges, Name); } - }); + + if ((Completed?.length ?? 0) > (dbChallenge.Completed?.length ?? 0)) { + dbChallenge.Completed ??= []; + for (const completion of Completed!) { + if (dbChallenge.Completed.indexOf(completion) == -1) { + if (completion == "challengeRewards") { + if (Name in challengeRewardsInboxMessages) { + await createMessage(account._id, [challengeRewardsInboxMessages[Name]]); + dbChallenge.Completed.push(completion); + // Would love to somehow let the client know about inbox or inventory changes, but there doesn't seem to anything for updateChallengeProgress. + continue; + } + } + logger.warn(`ignoring unknown challenge completion`, { challenge: Name, completion }); + } + } + } + } const affiliationMods: IAffiliationMods[] = []; if (SeasonChallengeCompletions) { diff --git a/src/services/missionInventoryUpdateService.ts b/src/services/missionInventoryUpdateService.ts index a7b3d9e4..4a8da370 100644 --- a/src/services/missionInventoryUpdateService.ts +++ b/src/services/missionInventoryUpdateService.ts @@ -292,7 +292,7 @@ export const addMissionInventoryUpdates = async ( addRecipes(inventory, value); break; case "ChallengeProgress": - addChallenges(account, inventory, value, inventoryUpdates.SeasonChallengeCompletions); + await addChallenges(account, inventory, value, inventoryUpdates.SeasonChallengeCompletions); break; case "FusionTreasures": addFusionTreasures(inventory, value); From 0a28eab65db7568d8d86934737118f5fe6d52581 Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Wed, 30 Jul 2025 01:50:43 -0700 Subject: [PATCH 06/14] feat: worldState.tennoLiveRelay config (#2568) Re #2531 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2568 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/services/configService.ts | 1 + src/services/worldStateService.ts | 26 ++++++++++++++++++++++++++ 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/zh.js | 1 + 10 files changed, 38 insertions(+) diff --git a/config.json.example b/config.json.example index 66276fb3..94bd5744 100644 --- a/config.json.example +++ b/config.json.example @@ -70,6 +70,7 @@ "creditBoost": false, "affinityBoost": false, "resourceBoost": false, + "tennoLiveRelay": false, "starDays": true, "galleonOfGhouls": 0, "eidolonOverride": "", diff --git a/src/services/configService.ts b/src/services/configService.ts index 3fd0483e..d76db1bd 100644 --- a/src/services/configService.ts +++ b/src/services/configService.ts @@ -81,6 +81,7 @@ export interface IConfig { creditBoost?: boolean; affinityBoost?: boolean; resourceBoost?: boolean; + tennoLiveRelay?: boolean; starDays?: boolean; galleonOfGhouls?: number; eidolonOverride?: string; diff --git a/src/services/worldStateService.ts b/src/services/worldStateService.ts index ac4f9b5d..69b3eb2d 100644 --- a/src/services/worldStateService.ts +++ b/src/services/worldStateService.ts @@ -1375,6 +1375,32 @@ export const getWorldState = (buildLabel?: string): IWorldState => { worldState.PVPChallengeInstances = []; } + if (config.worldState?.tennoLiveRelay) { + worldState.Goals.push({ + _id: { + $oid: "687bf9400000000000000000" + }, + Activation: { + $date: { + $numberLong: "1752955200000" + } + }, + Expiry: { + $date: { + $numberLong: "2000000000000" + } + }, + Count: 0, + Goal: 0, + Success: 0, + Personal: true, + Desc: "/Lotus/Language/Locations/RelayStationTennoConB", + ToolTip: "/Lotus/Language/Locations/RelayStationTennoConDescB", + Icon: "/Lotus/Interface/Icons/Categories/IconTennoLive.png", + Tag: "TennoConRelayB", + Node: "TennoConBHUB6" + }); + } if (config.worldState?.starDays) { worldState.Goals.push({ _id: { $oid: "67a4dcce2a198564d62e1647" }, diff --git a/static/webui/index.html b/static/webui/index.html index 0e0a6941..78deadc7 100644 --- a/static/webui/index.html +++ b/static/webui/index.html @@ -925,6 +925,10 @@ +
+ + +
diff --git a/static/webui/translations/de.js b/static/webui/translations/de.js index 2a325d4c..1ad0b9d1 100644 --- a/static/webui/translations/de.js +++ b/static/webui/translations/de.js @@ -242,6 +242,7 @@ dict = { worldState_creditBoost: `Event Booster: Credit`, worldState_affinityBoost: `Event Booster: Erfahrung`, worldState_resourceBoost: `Event Booster: Ressourcen`, + worldState_tennoLiveRelay: `[UNTRANSLATED] TennoLive Relay`, worldState_starDays: `Sternen-Tage`, worldState_galleonOfGhouls: `Galeone der Ghule`, disabled: `Deaktiviert`, diff --git a/static/webui/translations/en.js b/static/webui/translations/en.js index b825f923..90c548d6 100644 --- a/static/webui/translations/en.js +++ b/static/webui/translations/en.js @@ -241,6 +241,7 @@ dict = { worldState_creditBoost: `Credit Boost`, worldState_affinityBoost: `Affinity Boost`, worldState_resourceBoost: `Resource Boost`, + worldState_tennoLiveRelay: `TennoLive Relay`, worldState_starDays: `Star Days`, worldState_galleonOfGhouls: `Galleon of Ghouls`, disabled: `Disabled`, diff --git a/static/webui/translations/es.js b/static/webui/translations/es.js index 84390567..43f2f3cf 100644 --- a/static/webui/translations/es.js +++ b/static/webui/translations/es.js @@ -242,6 +242,7 @@ dict = { worldState_creditBoost: `Potenciador de Créditos`, worldState_affinityBoost: `Potenciador de Afinidad`, worldState_resourceBoost: `Potenciador de Recursos`, + worldState_tennoLiveRelay: `[UNTRANSLATED] TennoLive Relay`, worldState_starDays: `Días estelares`, worldState_galleonOfGhouls: `Galeón de Gules`, disabled: `Desactivado`, diff --git a/static/webui/translations/fr.js b/static/webui/translations/fr.js index 626591f5..c582ac39 100644 --- a/static/webui/translations/fr.js +++ b/static/webui/translations/fr.js @@ -242,6 +242,7 @@ dict = { worldState_creditBoost: `Booster de Crédit`, worldState_affinityBoost: `Booster d'Affinité`, worldState_resourceBoost: `Booster de Ressource`, + worldState_tennoLiveRelay: `[UNTRANSLATED] TennoLive Relay`, worldState_starDays: `Jours Stellaires`, worldState_galleonOfGhouls: `Galion des Goules`, disabled: `Désactivé`, diff --git a/static/webui/translations/ru.js b/static/webui/translations/ru.js index 5af30117..502cd69d 100644 --- a/static/webui/translations/ru.js +++ b/static/webui/translations/ru.js @@ -242,6 +242,7 @@ dict = { worldState_creditBoost: `[UNTRANSLATED] Credit Boost`, worldState_affinityBoost: `[UNTRANSLATED] Affinity Boost`, worldState_resourceBoost: `[UNTRANSLATED] Resource Boost`, + worldState_tennoLiveRelay: `[UNTRANSLATED] TennoLive Relay`, worldState_starDays: `[UNTRANSLATED] Star Days`, worldState_galleonOfGhouls: `[UNTRANSLATED] Galleon of Ghouls`, disabled: `[UNTRANSLATED] Disabled`, diff --git a/static/webui/translations/zh.js b/static/webui/translations/zh.js index d7ceb437..dfb44f40 100644 --- a/static/webui/translations/zh.js +++ b/static/webui/translations/zh.js @@ -242,6 +242,7 @@ dict = { worldState_creditBoost: `现金加成`, worldState_affinityBoost: `经验加成`, worldState_resourceBoost: `资源加成`, + worldState_tennoLiveRelay: `[UNTRANSLATED] TennoLive Relay`, worldState_starDays: `活动:星日`, worldState_galleonOfGhouls: `战术警报:尸鬼的帆船战舰`, disabled: `关闭/取消配置`, From 541ec3d702da2dbaa9db7cd7652f5364b079dcdd Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Wed, 30 Jul 2025 01:51:07 -0700 Subject: [PATCH 07/14] feat: claiming of tennolive relay's secret (#2569) Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2569 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- src/services/inventoryService.ts | 12 ++++++++++-- src/types/purchaseTypes.ts | 1 + 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/services/inventoryService.ts b/src/services/inventoryService.ts index c8949513..68cffb4b 100644 --- a/src/services/inventoryService.ts +++ b/src/services/inventoryService.ts @@ -1342,7 +1342,7 @@ export const addStanding = ( // TODO: AffiliationMods support (Nightwave). export const updateGeneric = async (data: IGenericUpdate, accountId: string): Promise => { - const inventory = await getInventory(accountId, "NodeIntrosCompleted MiscItems"); + const inventory = await getInventory(accountId, "NodeIntrosCompleted MiscItems ShipDecorations"); // Make it an array for easier parsing. if (typeof data.NodeIntrosCompleted === "string") { @@ -1351,7 +1351,15 @@ export const updateGeneric = async (data: IGenericUpdate, accountId: string): Pr const inventoryChanges: IInventoryChanges = {}; for (const node of data.NodeIntrosCompleted) { - if (node == "KayaFirstVisitPack") { + if (node == "TC2025") { + inventoryChanges.ShipDecorations = [ + { + ItemType: "/Lotus/Types/Items/ShipDecos/TauGrineerLancerBobbleHead", + ItemCount: 1 + } + ]; + addShipDecorations(inventory, inventoryChanges.ShipDecorations); + } else if (node == "KayaFirstVisitPack") { inventoryChanges.MiscItems = [ { ItemType: "/Lotus/Types/Items/MiscItems/1999FixedStickersPack", diff --git a/src/types/purchaseTypes.ts b/src/types/purchaseTypes.ts index 8b0db0f7..a6764a35 100644 --- a/src/types/purchaseTypes.ts +++ b/src/types/purchaseTypes.ts @@ -74,6 +74,7 @@ export type IInventoryChanges = { InfestedFoundry?: IInfestedFoundryClient; Drones?: IDroneClient[]; MiscItems?: IMiscItem[]; + ShipDecorations?: ITypeCount[]; EmailItems?: ITypeCount[]; CrewShipRawSalvage?: ITypeCount[]; Nemesis?: Partial; From 2fa846f465eac7dfee915d3da8b88ca0eb710e0b Mon Sep 17 00:00:00 2001 From: Corvus Date: Wed, 30 Jul 2025 03:51:42 -0700 Subject: [PATCH 08/14] chore(webui): update Chinese translation (#2572) Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2572 Co-authored-by: Corvus Co-committed-by: Corvus --- static/webui/translations/zh.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/webui/translations/zh.js b/static/webui/translations/zh.js index dfb44f40..10cba643 100644 --- a/static/webui/translations/zh.js +++ b/static/webui/translations/zh.js @@ -242,7 +242,7 @@ dict = { worldState_creditBoost: `现金加成`, worldState_affinityBoost: `经验加成`, worldState_resourceBoost: `资源加成`, - worldState_tennoLiveRelay: `[UNTRANSLATED] TennoLive Relay`, + worldState_tennoLiveRelay: `TennoLive 中继站`, worldState_starDays: `活动:星日`, worldState_galleonOfGhouls: `战术警报:尸鬼的帆船战舰`, disabled: `关闭/取消配置`, From 9901b7af549bb0da56a7fea25d47fb92bc5f050e Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Wed, 30 Jul 2025 04:01:02 -0700 Subject: [PATCH 09/14] chore: rename config.json.example to config-vanilla.json (#2570) Changing file extensions can be a bit of a chore on stock Windows, so this should simplify matters. Another bonus is that the "vanilla" clarifies the general guideline for how the defaults are configured. Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2570 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- .github/workflows/build.yml | 2 +- .prettierignore | 2 +- README.md | 2 +- config.json.example => config-vanilla.json | 0 docker-entrypoint.sh | 2 +- src/index.ts | 2 +- 6 files changed, 5 insertions(+), 5 deletions(-) rename config.json.example => config-vanilla.json (100%) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 375beec1..29b60ea1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,7 @@ jobs: with: node-version: ">=20.6.0" - run: npm ci - - run: cp config.json.example config.json + - run: cp config-vanilla.json config.json - run: npm run verify - run: npm run lint:ci - run: npm run prettier diff --git a/.prettierignore b/.prettierignore index 9ce8be88..e1ab4819 100644 --- a/.prettierignore +++ b/.prettierignore @@ -2,4 +2,4 @@ src/routes/api.ts static/webui/libs/ *.html *.md -config.json.example +config-vanilla.json diff --git a/README.md b/README.md index 0985b846..cd136b9f 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ To get an idea of what functionality you can expect to be missing [have a look t ## config.json -SpaceNinjaServer requires a `config.json`. To set it up, you can copy the [config.json.example](config.json.example), which has most cheats disabled. +SpaceNinjaServer requires a `config.json`. To set it up, you can copy the [config-vanilla.json](config-vanilla.json), which has most cheats disabled. - `logger.level` can be `fatal`, `error`, `warn`, `info`, `http`, `debug`, or `trace`. - `myIrcAddresses` can be used to point to an IRC server. If not provided, defaults to `[ myAddress ]`. diff --git a/config.json.example b/config-vanilla.json similarity index 100% rename from config.json.example rename to config-vanilla.json diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 703b7eaf..27abf98d 100755 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -2,7 +2,7 @@ set -e if [ ! -f conf/config.json ]; then - jq --arg value "mongodb://openwfagent:spaceninjaserver@mongodb:27017/" '.mongodbUrl = $value' /app/config.json.example > /app/conf/config.json + jq --arg value "mongodb://openwfagent:spaceninjaserver@mongodb:27017/" '.mongodbUrl = $value' /app/config-vanilla.json > /app/conf/config.json fi exec npm run start -- --configPath conf/config.json diff --git a/src/index.ts b/src/index.ts index 4887db86..175ce189 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,7 +7,7 @@ try { if (fs.existsSync("config.json")) { console.log("Failed to load " + configPath + ": " + (e as Error).message); } else { - console.log("Failed to load " + configPath + ". You can copy config.json.example to create your config file."); + console.log("Failed to load " + configPath + ". You can copy config-vanilla.json to create your config file."); } process.exit(1); } From f94f2005d30874e0c6d0cbd4aa3c036a5f48ca74 Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Wed, 30 Jul 2025 13:45:00 +0200 Subject: [PATCH 10/14] fix: script error with baroFullyStocked --- static/fixed_responses/worldState/baro.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/fixed_responses/worldState/baro.json b/static/fixed_responses/worldState/baro.json index 352e54ef..7e11cf67 100644 --- a/static/fixed_responses/worldState/baro.json +++ b/static/fixed_responses/worldState/baro.json @@ -431,7 +431,7 @@ { "ItemType": "/Lotus/StoreItems/Types/Items/SongItems/KuvaLichLoginSongItem", "PrimePrice": 140, "RegularPrice": 170000 }, { "ItemType": "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyBaro", "PrimePrice": 100, "RegularPrice": 125000 }, { "ItemType": "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyInaros", "PrimePrice": 120, "RegularPrice": 90000 }, - { "ItemType": "/Lotus/Upgrades/Mods/Pistol/Expert/WeaponPistolFactionDamageMurmursExpert", "PrimePrice": 375, "RegularPrice": 130000 } + { "ItemType": "/Lotus/StoreItems/Upgrades/Mods/Pistol/Expert/WeaponPistolFactionDamageMurmursExpert", "PrimePrice": 375, "RegularPrice": 130000 } ], "allIfAny": [ [ From 9286627668e974573f776e15d6dccde673361aa6 Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Wed, 30 Jul 2025 05:44:42 -0700 Subject: [PATCH 11/14] feat: star days rotation (#2573) Closes #2567 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2573 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- config-vanilla.json | 2 +- src/services/configService.ts | 2 +- src/services/worldStateService.ts | 20 +++++++++++++++++--- static/webui/index.html | 12 ++++++++---- static/webui/script.js | 8 +++++++- 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/zh.js | 1 + 11 files changed, 40 insertions(+), 10 deletions(-) diff --git a/config-vanilla.json b/config-vanilla.json index 94bd5744..12600852 100644 --- a/config-vanilla.json +++ b/config-vanilla.json @@ -71,8 +71,8 @@ "affinityBoost": false, "resourceBoost": false, "tennoLiveRelay": false, - "starDays": true, "galleonOfGhouls": 0, + "starDaysOverride": null, "eidolonOverride": "", "vallisOverride": "", "duviriOverride": "", diff --git a/src/services/configService.ts b/src/services/configService.ts index d76db1bd..f92fe010 100644 --- a/src/services/configService.ts +++ b/src/services/configService.ts @@ -82,8 +82,8 @@ export interface IConfig { affinityBoost?: boolean; resourceBoost?: boolean; tennoLiveRelay?: boolean; - starDays?: boolean; galleonOfGhouls?: number; + starDaysOverride?: boolean; eidolonOverride?: string; vallisOverride?: string; duviriOverride?: string; diff --git a/src/services/worldStateService.ts b/src/services/worldStateService.ts index 69b3eb2d..fc757768 100644 --- a/src/services/worldStateService.ts +++ b/src/services/worldStateService.ts @@ -1349,6 +1349,7 @@ export const getWorldState = (buildLabel?: string): IWorldState => { const week = Math.trunc(day / 7); const weekStart = EPOCH + week * 604800000; const weekEnd = weekStart + 604800000; + const date = new Date(timeMs); const worldState: IWorldState = { BuildLabel: typeof buildLabel == "string" ? buildLabel.split(" ").join("+") : buildConfig.buildLabel, @@ -1401,11 +1402,24 @@ export const getWorldState = (buildLabel?: string): IWorldState => { Node: "TennoConBHUB6" }); } - if (config.worldState?.starDays) { + const isFebruary = date.getUTCMonth() == 1; + if (config.worldState?.starDaysOverride ?? isFebruary) { worldState.Goals.push({ _id: { $oid: "67a4dcce2a198564d62e1647" }, - Activation: { $date: { $numberLong: "1738868400000" } }, - Expiry: { $date: { $numberLong: "2000000000000" } }, + Activation: { + $date: { + $numberLong: config.worldState?.starDaysOverride + ? "1738868400000" + : Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1).toString() + } + }, + Expiry: { + $date: { + $numberLong: config.worldState?.starDaysOverride + ? "2000000000000" + : Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + 1, 1).toString() + } + }, Count: 0, Goal: 0, Success: 0, diff --git a/static/webui/index.html b/static/webui/index.html index 78deadc7..398c1661 100644 --- a/static/webui/index.html +++ b/static/webui/index.html @@ -929,10 +929,6 @@
-
- - -
@@ -946,6 +942,14 @@
+
+ + +
+
+ + +
diff --git a/static/webui/translations/de.js b/static/webui/translations/de.js index 60f48e0a..88c36899 100644 --- a/static/webui/translations/de.js +++ b/static/webui/translations/de.js @@ -243,6 +243,7 @@ dict = { worldState_affinityBoost: `Event Booster: Erfahrung`, worldState_resourceBoost: `Event Booster: Ressourcen`, worldState_tennoLiveRelay: `[UNTRANSLATED] TennoLive Relay`, + worldState_baroTennoConRelay: `[UNTRANSLATED] Baro's TennoCon Relay`, worldState_starDays: `Sternen-Tage`, worldState_galleonOfGhouls: `Galeone der Ghule`, enabled: `[UNTRANSLATED] Enabled`, diff --git a/static/webui/translations/en.js b/static/webui/translations/en.js index 08119b98..e976ffd5 100644 --- a/static/webui/translations/en.js +++ b/static/webui/translations/en.js @@ -242,6 +242,7 @@ dict = { worldState_affinityBoost: `Affinity Boost`, worldState_resourceBoost: `Resource Boost`, worldState_tennoLiveRelay: `TennoLive Relay`, + worldState_baroTennoConRelay: `Baro's TennoCon Relay`, worldState_starDays: `Star Days`, worldState_galleonOfGhouls: `Galleon of Ghouls`, enabled: `Enabled`, diff --git a/static/webui/translations/es.js b/static/webui/translations/es.js index fc064408..32c9e336 100644 --- a/static/webui/translations/es.js +++ b/static/webui/translations/es.js @@ -243,6 +243,7 @@ dict = { worldState_affinityBoost: `Potenciador de Afinidad`, worldState_resourceBoost: `Potenciador de Recursos`, worldState_tennoLiveRelay: `[UNTRANSLATED] TennoLive Relay`, + worldState_baroTennoConRelay: `[UNTRANSLATED] Baro's TennoCon Relay`, worldState_starDays: `Días estelares`, worldState_galleonOfGhouls: `Galeón de Gules`, enabled: `[UNTRANSLATED] Enabled`, diff --git a/static/webui/translations/fr.js b/static/webui/translations/fr.js index 6f641315..14e13f4d 100644 --- a/static/webui/translations/fr.js +++ b/static/webui/translations/fr.js @@ -243,6 +243,7 @@ dict = { worldState_affinityBoost: `Booster d'Affinité`, worldState_resourceBoost: `Booster de Ressource`, worldState_tennoLiveRelay: `[UNTRANSLATED] TennoLive Relay`, + worldState_baroTennoConRelay: `[UNTRANSLATED] Baro's TennoCon Relay`, worldState_starDays: `Jours Stellaires`, worldState_galleonOfGhouls: `Galion des Goules`, enabled: `[UNTRANSLATED] Enabled`, diff --git a/static/webui/translations/ru.js b/static/webui/translations/ru.js index a6976cf5..28b6cc74 100644 --- a/static/webui/translations/ru.js +++ b/static/webui/translations/ru.js @@ -243,6 +243,7 @@ dict = { worldState_affinityBoost: `[UNTRANSLATED] Affinity Boost`, worldState_resourceBoost: `[UNTRANSLATED] Resource Boost`, worldState_tennoLiveRelay: `[UNTRANSLATED] TennoLive Relay`, + worldState_baroTennoConRelay: `[UNTRANSLATED] Baro's TennoCon Relay`, worldState_starDays: `[UNTRANSLATED] Star Days`, worldState_galleonOfGhouls: `[UNTRANSLATED] Galleon of Ghouls`, enabled: `[UNTRANSLATED] Enabled`, diff --git a/static/webui/translations/zh.js b/static/webui/translations/zh.js index cdf86806..5b9b6e55 100644 --- a/static/webui/translations/zh.js +++ b/static/webui/translations/zh.js @@ -243,6 +243,7 @@ dict = { worldState_affinityBoost: `经验加成`, worldState_resourceBoost: `资源加成`, worldState_tennoLiveRelay: `TennoLive 中继站`, + worldState_baroTennoConRelay: `[UNTRANSLATED] Baro's TennoCon Relay`, worldState_starDays: `活动:星日`, worldState_galleonOfGhouls: `战术警报:尸鬼的帆船战舰`, enabled: `启用`, From 601091f1c03f63bd325a14dbf3d3dcafd6bdcebb Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Thu, 31 Jul 2025 02:28:03 -0700 Subject: [PATCH 14/14] chore(webui): clarify that eidolon override also takes effect on deimos (#2576) This is an update in the English translation only. Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2576 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- static/webui/translations/en.js | 6 +++--- static/webui/translations/ru.js | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/static/webui/translations/en.js b/static/webui/translations/en.js index e976ffd5..c31fa20c 100644 --- a/static/webui/translations/en.js +++ b/static/webui/translations/en.js @@ -250,9 +250,9 @@ dict = { worldState_we1: `Weekend 1`, worldState_we2: `Weekend 2`, worldState_we3: `Weekend 3`, - worldState_eidolonOverride: `Eidolon Override`, - worldState_day: `Day`, - worldState_night: `Night`, + worldState_eidolonOverride: `Eidolon/Deimos Override`, + worldState_day: `Day/Fass`, + worldState_night: `Night/Vome`, worldState_vallisOverride: `Orb Vallis Override`, worldState_warm: `Warm`, worldState_cold: `Cold`, diff --git a/static/webui/translations/ru.js b/static/webui/translations/ru.js index 28b6cc74..d495e34a 100644 --- a/static/webui/translations/ru.js +++ b/static/webui/translations/ru.js @@ -251,9 +251,9 @@ dict = { worldState_we1: `[UNTRANSLATED] Weekend 1`, worldState_we2: `[UNTRANSLATED] Weekend 2`, worldState_we3: `[UNTRANSLATED] Weekend 3`, - worldState_eidolonOverride: `[UNTRANSLATED] Eidolon Override`, - worldState_day: `[UNTRANSLATED] Day`, - worldState_night: `[UNTRANSLATED] Night`, + worldState_eidolonOverride: `[UNTRANSLATED] Eidolon/Deimos Override`, + worldState_day: `[UNTRANSLATED] Day/Fass`, + worldState_night: `[UNTRANSLATED] Night/Vome`, worldState_vallisOverride: `[UNTRANSLATED] Orb Vallis Override`, worldState_warm: `[UNTRANSLATED] Warm`, worldState_cold: `[UNTRANSLATED] Cold`,