From 4535b193e098a306468e73d1366a04ee21d5e7f3 Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Mon, 9 Jun 2025 03:37:42 -0700 Subject: [PATCH 1/3] chore: handle nightwaveOverride having an invalid value (#2133) Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2133 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- src/services/worldStateService.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/services/worldStateService.ts b/src/services/worldStateService.ts index 1dee4116..5bea6f20 100644 --- a/src/services/worldStateService.ts +++ b/src/services/worldStateService.ts @@ -19,6 +19,7 @@ import { IWorldState } from "../types/worldStateTypes"; import { version_compare } from "../helpers/inventoryHelpers"; +import { logger } from "../utils/logger"; const sortieBosses = [ "SORTIE_BOSS_HYENA", @@ -1275,7 +1276,13 @@ export const isArchwingMission = (node: IRegion): boolean => { export const getNightwaveSyndicateTag = (buildLabel: string | undefined): string | undefined => { if (config.worldState?.nightwaveOverride) { - return config.worldState.nightwaveOverride; + if (config.worldState.nightwaveOverride in nightwaveTagToSeason) { + return config.worldState.nightwaveOverride; + } + logger.warn(`ignoring invalid config value for worldState.nightwaveOverride`, { + value: config.worldState.nightwaveOverride, + valid_values: Object.keys(nightwaveTagToSeason) + }); } if (!buildLabel || version_compare(buildLabel, "2025.05.20.10.18") >= 0) { return "RadioLegionIntermission13Syndicate"; From 870c96485452aa6eca27b07a1be8d789367dc1c0 Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Mon, 9 Jun 2025 06:54:58 -0700 Subject: [PATCH 2/3] feat: add eidolonOverride & vallisOverride to replace lockTime (#2135) I think for now it's best to keep the client time somewhat in sync with the server/database time to avoid various issues. Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2135 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- README.md | 3 +- config.json.example | 3 +- src/services/configService.ts | 3 +- src/services/worldStateService.ts | 55 ++++++++++++++++++++++++++++++- 4 files changed, 60 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 24d3b2fb..e8d2b419 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,8 @@ SpaceNinjaServer requires a `config.json`. To set it up, you can copy the [confi - `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 ]`. -- `worldState.lockTime` will lock the time provided in worldState if nonzero, e.g. `1743202800` for night in POE. +- `worldState.eidolonOverride` can be set to `day` or `night` to lock the time to day/fass and night/vome on Plains of Eidolon/Cambion Drift. +- `worldState.vallisOverride` can be set to `warm` or `cold` to lock the temperature on Orb Vallis. - `worldState.nightwaveOverride` will lock the nightwave season, assuming the client is new enough for it. Valid values: - `RadioLegionIntermission13Syndicate` for Nora's Mix Vol. 9 - `RadioLegionIntermission12Syndicate` for Nora's Mix Vol. 8 diff --git a/config.json.example b/config.json.example index 4000024f..b9ebaab0 100644 --- a/config.json.example +++ b/config.json.example @@ -55,7 +55,8 @@ "affinityBoost": false, "resourceBoost": false, "starDays": true, - "lockTime": 0, + "eidolonOverride": "", + "vallisOverride": "", "nightwaveOverride": "" } } diff --git a/src/services/configService.ts b/src/services/configService.ts index ba67cf06..dc8a78bc 100644 --- a/src/services/configService.ts +++ b/src/services/configService.ts @@ -61,7 +61,8 @@ interface IConfig { affinityBoost?: boolean; resourceBoost?: boolean; starDays?: boolean; - lockTime?: number; + eidolonOverride?: string; + vallisOverride?: string; nightwaveOverride?: string; }; } diff --git a/src/services/worldStateService.ts b/src/services/worldStateService.ts index 5bea6f20..e2041907 100644 --- a/src/services/worldStateService.ts +++ b/src/services/worldStateService.ts @@ -939,8 +939,61 @@ const getCalendarSeason = (week: number): ICalendarSeason => { }; }; +const doesTimeSatsifyConstraints = (timeSecs: number): boolean => { + if (config.worldState?.eidolonOverride) { + const eidolonEpoch = 1391992660; + const eidolonCycle = Math.trunc((timeSecs - eidolonEpoch) / 9000); + const eidolonCycleStart = eidolonEpoch + eidolonCycle * 9000; + const eidolonCycleEnd = eidolonCycleStart + 9000; + const eidolonCycleNightStart = eidolonCycleEnd - 3000; + if (config.worldState.eidolonOverride == "day") { + if ( + //timeSecs < eidolonCycleStart || + isBeforeNextExpectedWorldStateRefresh(timeSecs * 1000, eidolonCycleNightStart * 1000) + ) { + return false; + } + } else { + if ( + timeSecs < eidolonCycleNightStart || + isBeforeNextExpectedWorldStateRefresh(timeSecs * 1000, eidolonCycleEnd * 1000) + ) { + return false; + } + } + } + + if (config.worldState?.vallisOverride) { + const vallisEpoch = 1541837628; + const vallisCycle = Math.trunc((timeSecs - vallisEpoch) / 1600); + const vallisCycleStart = vallisEpoch + vallisCycle * 1600; + const vallisCycleEnd = vallisCycleStart + 1600; + const vallisCycleColdStart = vallisCycleStart + 400; + if (config.worldState.vallisOverride == "cold") { + if ( + timeSecs < vallisCycleColdStart || + isBeforeNextExpectedWorldStateRefresh(timeSecs * 1000, vallisCycleEnd * 1000) + ) { + return false; + } + } else { + if ( + //timeSecs < vallisCycleStart || + isBeforeNextExpectedWorldStateRefresh(timeSecs * 1000, vallisCycleColdStart * 1000) + ) { + return false; + } + } + } + + return true; +}; + export const getWorldState = (buildLabel?: string): IWorldState => { - const timeSecs = config.worldState?.lockTime || Math.round(Date.now() / 1000); + let timeSecs = Math.round(Date.now() / 1000); + while (!doesTimeSatsifyConstraints(timeSecs)) { + timeSecs -= 60; + } const timeMs = timeSecs * 1000; const day = Math.trunc((timeMs - EPOCH) / 86400000); const week = Math.trunc(day / 7); From 2b555a64564bd6769c5f3b9193820c48eb234186 Mon Sep 17 00:00:00 2001 From: bishan178 Date: Mon, 9 Jun 2025 08:20:34 -0700 Subject: [PATCH 3/3] chore(webui): update Chinese translation (#2137) Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2137 Co-authored-by: bishan178 Co-committed-by: bishan178 --- static/webui/translations/zh.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/static/webui/translations/zh.js b/static/webui/translations/zh.js index 49f39413..d46ce77d 100644 --- a/static/webui/translations/zh.js +++ b/static/webui/translations/zh.js @@ -18,7 +18,7 @@ dict = { code_kDrive: `K式悬浮板`, code_legendaryCore: `传奇核心`, code_traumaticPeculiar: `创伤怪奇`, - code_starter: `|MOD| (有瑕疵的)`, + code_starter: `|MOD|(有瑕疵的)`, code_badItem: `(Imposter)`, code_maxRank: `满级`, code_rename: `重命名`, @@ -39,7 +39,7 @@ dict = { code_count: `数量`, code_focusAllUnlocked: `所有专精学派均已解锁。`, code_focusUnlocked: `已解锁 |COUNT| 个新专精学派!需要游戏内仓库更新才能生效,您可以通过访问星图来触发仓库更新。`, - code_addModsConfirm: `确定要向账户添加 |COUNT| 张MOD吗?`, + code_addModsConfirm: `确定要向账户添加 |COUNT| 张MOD吗?`, code_succImport: `导入成功。`, code_gild: `镀金`, code_moa: `恐鸟`, @@ -53,7 +53,7 @@ dict = { code_completed: `已完成`, code_active: `正在执行`, code_pigment: `颜料`, - code_mature: `成长至战备`, + code_mature: `成长并战备`, code_unmature: `逆转衰老基因`, login_description: `使用您的 OpenWF 账户凭证登录(与游戏内连接本服务器时使用的昵称相同)。`, login_emailLabel: `电子邮箱`, @@ -83,21 +83,21 @@ dict = { inventory_hoverboards: `K式悬浮板`, inventory_moaPets: `恐鸟`, inventory_kubrowPets: `动物同伴`, - inventory_evolutionProgress: `[UNTRANSLATED] Incarnon Evolution Progress`, + inventory_evolutionProgress: `灵化之源进度`, inventory_bulkAddSuits: `添加缺失战甲`, inventory_bulkAddWeapons: `添加缺失武器`, inventory_bulkAddSpaceSuits: `添加缺失Archwing`, inventory_bulkAddSpaceWeapons: `添加缺失Archwing武器`, inventory_bulkAddSentinels: `添加缺失守护`, inventory_bulkAddSentinelWeapons: `添加缺失守护武器`, - inventory_bulkAddEvolutionProgress: `[UNTRANSLATED] Add Missing Incarnon Evolution Progress`, + inventory_bulkAddEvolutionProgress: `添加缺失的灵化之源`, inventory_bulkRankUpSuits: `所有战甲升满级`, inventory_bulkRankUpWeapons: `所有武器升满级`, inventory_bulkRankUpSpaceSuits: `所有Archwing升满级`, inventory_bulkRankUpSpaceWeapons: `所有Archwing武器升满级`, inventory_bulkRankUpSentinels: `所有守护升满级`, inventory_bulkRankUpSentinelWeapons: `所有守护武器升满级`, - inventory_bulkRankUpEvolutionProgress: `[UNTRANSLATED] Max Rank All Incarnon Evolution Progress`, + inventory_bulkRankUpEvolutionProgress: `所有灵化之源最大等级`, quests_list: `任务`, quests_completeAll: `完成所有任务`, @@ -133,7 +133,7 @@ dict = { cheats_infiniteHelminthMaterials: `无限Helminth材料`, cheats_claimingBlueprintRefundsIngredients: `取消蓝图制造时返还材料`, cheats_dontSubtractVoidTraces: `虚空光体无消耗`, - cheats_dontSubtractConsumables: `消耗物品使用时损耗`, + cheats_dontSubtractConsumables: `消耗物品使用时无损耗`, cheats_unlockAllShipFeatures: `解锁所有飞船功能`, cheats_unlockAllShipDecorations: `解锁所有飞船装饰`, cheats_unlockAllFlavourItems: `解锁所有装饰物品`, @@ -162,12 +162,12 @@ dict = { cheats_noDojoResearchCosts: `无视道场研究消耗`, cheats_noDojoResearchTime: `无视道场研究时间`, cheats_fastClanAscension: `快速升级氏族`, - cheats_spoofMasteryRank: `伪造精通段位(-1为禁用)`, + cheats_spoofMasteryRank: `伪造精通段位(-1为禁用)`, cheats_saveSettings: `保存设置`, cheats_account: `账户`, cheats_unlockAllFocusSchools: `解锁所有专精学派`, cheats_helminthUnlockAll: `完全升级Helminth`, - cheats_intrinsicsUnlockAll: `[UNTRANSLATED] Max Rank All Intrinsics`, + cheats_intrinsicsUnlockAll: `所有内源之力最大等级`, cheats_changeSupportedSyndicate: `支持的集团`, cheats_changeButton: `更改`, cheats_none: `无`,