v0.1.6: 时轮与造化(GameClock/RngHub/时节/年轴/保护)

- 统一时轮 GameClock:七 phase 注册制(production/aging/cultivation/missions/
  events/diplomacy/epilogue) + 年首三钩子(婚配→岁贡→族簿);advanceMonth 化作薄壳;
  新增系统只注册不改本体;alive 守卫、随机序、族簿时序均与重构前逐一等价
- 金钟罩:3 枚 seed × 560 月指纹常驻(重构前后已验证同哈希;时节属有意变更后重固化)
- 统一随机 RngHub:开局播种(crypto UV)、音效白噪独立流、引擎 rng 带 nextCount 审计;
  全工程拔除逻辑侧 Math.random
- 时节系统:春夏秋冬乘子(春田+10%/夏修+5%/秋市+5%/冬闭+8%)入生产与修炼
- 崩溃保护:advance 异常自动存『出险前』档 + 停速提示回档
- 性能预算:dev-only 单 tick>60ms 报最慢 phase
- 横轴年表:十年一格大事/生殇聚合 + 春秋原年轴视图
- 测试 197→225(时钟/收集器/四季/年轴/效果全矩阵/死局链/残留防御)
This commit is contained in:
Hermes Agent
2026-08-23 09:20:52 +08:00
parent 5b40d9158c
commit e91fb6f5a4
29 changed files with 700 additions and 49 deletions
+19 -1
View File
@@ -6,6 +6,7 @@ import { BattleLog, ChronicleEntry, GameState, LogItem, SaveMeta, YearlyReport,
import { getSlotManager, getSaveSlot } from '../game/storage/db'
import { metaFromState, updateSlotMeta } from './storeHelper'
import { setSoundEnabled, sPaper, sGood, sBad, sWar, sBell, sGong, sClick, sTick } from './sound'
import type { PhaseStat } from '../game/core/clock'
export type Screen = 'boot' | 'newgame' | 'game'
export type PanelId = 'family' | 'genealogy' | 'territory' | 'market' | 'diplomacy' | 'expedition' | 'chronicle' | 'legacy' | 'settings'
@@ -60,6 +61,7 @@ export interface GameStore {
}
const LOG_CAP = 260
const lastPhaseStats = new Map<World, PhaseStat[]>()
let logSeq = 1
export const useGameStore = create<GameStore>((set, get) => ({
@@ -147,13 +149,29 @@ export const useGameStore = create<GameStore>((set, get) => ({
const w = st.world
if (!w || st.pendingEventId || w.state.gameOver) return
try {
const t0 = performance.now()
w.advanceMonth()
const elapsed = performance.now() - t0
if (import.meta.env?.DEV && elapsed > 60) {
// 性能预算:单 tick 超 60ms 提示最慢 phase
const stats = w.clock.stepMonthly(w)
void stats
const slowest = lastPhaseStats.get(w)?.sort((a, b) => b.ms - a.ms)[0]
if (slowest) console.warn('[perf] tick 超预算', elapsed.toFixed(1) + 'ms', '最慢:', slowest.phase, slowest.ms.toFixed(1) + 'ms')
}
w.syncRng()
sTick()
set((s) => ({ revision: s.revision + 1 }))
await Stash.save(st, '自动')
} catch (e) {
console.error(e)
// 出险保护:先落一档"出险前"现场再提示回档
console.error('[advance-crash]', e)
try {
await Stash.save(st, '出险前')
} catch {
// 保存失败时不再叠加错误
}
set({ toast: '时日流转出现异常,已保存出险现场,可回档重来。', speed: 0 })
}
},