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:
@@ -0,0 +1,63 @@
|
||||
import { World } from '../src/renderer/game/engine/world'
|
||||
import { GameState } from '../src/renderer/game/types/domain'
|
||||
|
||||
export function stateFingerprint(s: GameState): string {
|
||||
const parts = [
|
||||
s.year, s.month, s.seq, s.totalTicks,
|
||||
s.family.stones,
|
||||
s.family.reputation,
|
||||
s.family.generation,
|
||||
JSON.stringify(sortedInv(s.family.inventory)),
|
||||
JSON.stringify(sortedBld(s.family.buildings)),
|
||||
s.family.headId,
|
||||
s.family.techniques.join(',')
|
||||
]
|
||||
const members = Object.values(s.members)
|
||||
.map((c) => `${c.id}:${c.alive}:${c.realm.major}/${c.realm.minor}:${Math.floor(c.realmProgress * 10) / 10}:${Math.floor(c.health * 10) / 10}:${c.state}:${c.bornYear}:${c.techniqueRank ?? 0}:${Math.floor((c.techniqueProgress ?? 0) * 10) / 10}:${c.post ?? ''}:${c.aspiration ?? ''}:${c.spouseId ?? ''}:${c.children.join('-')}`)
|
||||
.sort()
|
||||
parts.push(members.join('|'))
|
||||
parts.push(JSON.stringify(sortedNpc(s.npcFamilies)))
|
||||
parts.push(s.missions.length + ':' + s.missions.map((m) => `${m.defId}:${m.stage}:${m.stageMonth}:${m.done}:${m.memberIds.join('+')}`).join(';'))
|
||||
parts.push(s.chronicle.length + ':' + s.chronicle.slice(-5).map((e) => `${e.year}${e.month}${e.category}`).join(','))
|
||||
parts.push(s.battles.length)
|
||||
parts.push(Object.keys(s.completedEvents).length + ':' + s.completedEvents.slice(-3).join(','))
|
||||
parts.push(JSON.stringify(sortedFlags(s.family.flag)))
|
||||
parts.push(s.yearlyReports.length)
|
||||
return hash32(parts.join('\u0001'))
|
||||
}
|
||||
|
||||
function sortedInv(inv: Record<string, number>): Array<[string, number]> {
|
||||
return Object.entries(inv).sort((a, b) => (a[0] < b[0] ? -1 : 1))
|
||||
}
|
||||
function sortedBld(b: Record<string, number>): Array<[string, number]> {
|
||||
return Object.entries(b).sort((a, b) => (a[0] < b[0] ? -1 : 1))
|
||||
}
|
||||
function sortedFlags(f: Record<string, number | boolean | string>): Array<[string, string]> {
|
||||
return Object.entries(f)
|
||||
.map(([k, v]) => [k, String(v)] as [string, string])
|
||||
.sort((a, b) => (a[0] < b[0] ? -1 : 1))
|
||||
}
|
||||
function sortedNpc(n: GameState['npcFamilies']): Array<[string, string]> {
|
||||
return Object.entries(n)
|
||||
.map(([k, v]) => [k, `${v.relation}:${v.power}:${v.allied}`] as [string, string])
|
||||
.sort((a, b) => (a[0] < b[0] ? -1 : 1))
|
||||
}
|
||||
|
||||
function hash32(str: string): string {
|
||||
let h = 2166136261
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
h ^= str.charCodeAt(i)
|
||||
h = Math.imul(h, 16777619)
|
||||
h = (h << 13) | (h >>> 19)
|
||||
}
|
||||
return (h >>> 0).toString(16).padStart(8, '0')
|
||||
}
|
||||
|
||||
export function longRun(seed: string, months = 560): World {
|
||||
const w = World.create({ seed, surname: '钟', familyName: '钟家', motto: 'm', difficulty: 'normal' })
|
||||
for (let i = 0; i < months; i++) {
|
||||
if (w.state.gameOver) break
|
||||
w.advanceMonth()
|
||||
}
|
||||
return w
|
||||
}
|
||||
Reference in New Issue
Block a user