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:
2026-08-23 09:20:52 +08:00
parent 106db18017
commit a7ee125866
29 changed files with 700 additions and 49 deletions
+72
View File
@@ -0,0 +1,72 @@
import type { World } from '../engine/world'
/**
* 统一时轮调度:所有系统以 phase 注册,由时钟按固定顺序驱动。
* - 月度 phaseproduction / aging / cultivation / missions / events / diplomacy / epilogue
* - 年首钩子:onYearStart(婚配 → 声望岁贡 → 岁末族簿)
* 新增系统 = 注册一行,不再修改 advanceMonth 本体。
*/
export type PhaseId =
| 'production'
| 'aging'
| 'cultivation'
| 'missions'
| 'events'
| 'diplomacy'
| 'epilogue'
export type SystemHook = (w: World) => void
export interface PhaseStat {
phase: PhaseId
ms: number
count: number
}
export const PHASE_ORDER: PhaseId[] = [
'production',
'aging',
'cultivation',
'missions',
'events',
'diplomacy',
'epilogue'
]
export class GameClock {
private monthly = new Map<PhaseId, SystemHook[]>()
private yearly: SystemHook[] = []
register(phase: PhaseId, fn: SystemHook): void {
const list = this.monthly.get(phase) ?? []
list.push(fn)
this.monthly.set(phase, list)
}
onYearStart(fn: SystemHook): void {
this.yearly.push(fn)
}
fireYearStart(w: World): void {
for (const fn of this.yearly) fn(w)
}
stepMonthly(w: World): PhaseStat[] {
const report: PhaseStat[] = []
for (const phase of PHASE_ORDER) {
const t0 = performance.now()
const fns = this.monthly.get(phase) ?? []
for (const fn of fns) fn(w)
const ms = performance.now() - t0
report.push({ phase, ms, count: fns.length })
}
return report
}
subscriptionCount(): number {
let n = 0
for (const list of this.monthly.values()) n += list.length
return n + this.yearly.length
}
}