【A+I】migrate.ts 迁移链(CURRENT_SCHEMA/MIGRATIONS/migrateIfNeeded/MigrationError)整链铲除→validateLoadedState 结构校验(seed/family/members 断言);信封统一 payload 单格式(去双格式兜底);APP_ID 保留 【F】schemaVersion 字段全删(domain/creation/save 8 处);SaveMeta.version 记游戏版本字符串 【C】chronicle 死表+saveChronicle 死方法(首行 return+unreachable legacy 僵尸)全删 【D/E】GameEngine __state globalThis 泄漏口+seed 三元(恒不可达)删除;engineFromSnapshot/noAutoCreate 保留(测试便利——非兼容机器) 【B/H】normalizeGameState 兼容批删:老档字段补(28行)/worldGen 重放(18行)/P0-2 占位 def(9行)/worldSim 字段批删;保留 npcs 重注册/headId 修复/d distress 防护;initSim 补 0.1.34 四键(唯一初始源) 【G】domain 收紧 5 兼容 optional(techniqueRank/Progress/tribBoost/worldGen 必填)+pcgen 必写 【测试】删 9 个兼容验证体(audit 0.1.0-era/全残缺矩阵/空 worldSim 兜底);5989 全绿——金钟罩零漂(新档结构全字段,删除不涉世界数值)
110 lines
4.3 KiB
TypeScript
110 lines
4.3 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
||
import { World } from '../src/renderer/game/engine/runtime/World'
|
||
import { Rng, seedToRng } from '../src/renderer/game/engine/kernel/rng'
|
||
import { seasonMod } from '../src/renderer/game/data/season'
|
||
import { MAJOR_ORDER } from '../src/renderer/game/data/realms'
|
||
|
||
function mk(seed: string): World {
|
||
return World.create({ seed, surname: '钟', familyName: '钟家', motto: 'm', difficulty: 'normal' })
|
||
}
|
||
|
||
describe('0.1.30 矩阵:月末大圈(600 例级)', () => {
|
||
it.each(Array.from({ length: 48 }, (_, i) => [i * 23 + 1] as const))(
|
||
'seed %d:双月双验', (seed) => {
|
||
const w = mk(`md2-${seed}`)
|
||
w.advanceMonth(); w.advanceMonth()
|
||
expect(w.state.month).toBeGreaterThan(2)
|
||
expect(Number.isFinite(w.state.family.stones)).toBe(true)
|
||
})
|
||
|
||
it.each(Array.from({ length: 40 }, (_, i) => [i * 11 + 4] as const))(
|
||
'seed %d:六载六验', (seed) => {
|
||
const w = mk(`lz-${seed}`)
|
||
for (let i = 0; i < 72; i++) w.advanceMonth()
|
||
expect(w.state.year).toBeGreaterThanOrEqual(6)
|
||
expect(Number.isFinite(w.state.seq)).toBe(true)
|
||
expect(w.state.family.reputation >= 0).toBe(true)
|
||
expect(Array.isArray(w.state.chronicle)).toBe(true)
|
||
expect(w.state.finance).toBeTruthy()
|
||
expect(w.state.family.inventory).toBeTruthy()
|
||
})
|
||
|
||
it.each(Array.from({ length: 36 }, (_, i) => [i * 15 + 7] as const))(
|
||
'seed %d:季度验收(12 月×3 验)', (seed) => {
|
||
const w = mk(`jd-${seed}`)
|
||
for (let i = 0; i < 12; i++) w.advanceMonth()
|
||
expect(w.state.totalTicks).toBe(12)
|
||
expect(Number.isFinite(w.state.family.stones)).toBe(true)
|
||
expect(Array.isArray(w.state.eventQueue)).toBe(true)
|
||
})
|
||
|
||
it.each([
|
||
['春', 2], ['夏', 5], ['秋', 8], ['冬', 11], ['玄月', 1], ['腊月', 12]
|
||
] as const)('%s:季节四因子各验', (label, month) => {
|
||
for (const key of ['field', 'cult', 'market', 'meditation'] as const) {
|
||
const v = seasonMod(month, key)
|
||
expect(v).toBeGreaterThanOrEqual(-0.35)
|
||
expect(v).toBeLessThanOrEqual(0.35)
|
||
}
|
||
void label
|
||
})
|
||
|
||
it.each(Array.from({ length: 24 }, (_, i) => [i * 7 + 5] as const))(
|
||
'seed %d:境界圆周合法', (seed) => {
|
||
const w = mk(`jy2-${seed}`)
|
||
for (const m of MAJOR_ORDER) {
|
||
const c = Object.values(w.state.members)[0]!
|
||
c.realm = { major: m, minor: 0 }
|
||
expect(c.realm).toBeTruthy()
|
||
}
|
||
expect(MAJOR_ORDER.length).toBeGreaterThanOrEqual(6)
|
||
})
|
||
|
||
it.each(Array.from({ length: 20 }, (_, i) => [i * 5 + 1] as const))(
|
||
'seed %d:大衍六合', (seed) => {
|
||
const w = mk(`dy2-${seed}`)
|
||
for (let i = 0; i < 24; i++) w.advanceMonth()
|
||
expect(w.state.seq).toBeGreaterThan(0)
|
||
expect(Array.isArray(w.state.completedEvents)).toBe(true)
|
||
expect(Array.isArray(w.state.missions)).toBe(true)
|
||
expect(typeof w.state.seed).toBe('string') // 0.1.35 版本戳移除——seed 为世界锚
|
||
expect(typeof w.state.seed).toBe('string')
|
||
expect(Array.isArray(w.state.battles)).toBe(true)
|
||
})
|
||
|
||
it.each(Array.from({ length: 32 }, (_, i) => [i * 9 + 2] as const))(
|
||
'seed %d:三十月双验', (seed) => {
|
||
const w = mk(`sy-${seed}`)
|
||
for (let i = 0; i < 30; i++) w.advanceMonth()
|
||
expect(w.state.year).toBeGreaterThanOrEqual(2)
|
||
expect(Number.isFinite(w.state.totalTicks)).toBe(true)
|
||
})
|
||
|
||
it.each(Array.from({ length: 16 }, (_, i) => [i * 3 + 1] as const))(
|
||
'seed %d:rng 四步等变', (seed) => {
|
||
const a = new Rng(seedToRng(`zz-${seed}`))
|
||
const b = new Rng(seedToRng(`zz-${seed}`))
|
||
expect(a.next()).toBe(b.next())
|
||
expect(a.next()).toBe(b.next())
|
||
expect(a.next()).toBe(b.next())
|
||
expect(a.next()).toBe(b.next())
|
||
})
|
||
|
||
it.each([
|
||
['一'], ['二'], ['三'], ['四'], ['五'], ['六'], ['七'], ['八'], ['九'], ['十']
|
||
] as const)('%s:化律(10 月推演)', (label) => {
|
||
const w = mk(`hl-${label}`)
|
||
for (let i = 0; i < 10; i++) w.advanceMonth()
|
||
expect(w.state.seq).toBeGreaterThan(9)
|
||
})
|
||
|
||
it.each(Array.from({ length: 60 }, (_, i) => [i * 3 + 1] as const))(
|
||
'seed %d:六辰常驻', (seed) => {
|
||
const w = mk(`lc-${seed}`)
|
||
w.advanceMonth()
|
||
expect(w.state.month).toBe(2)
|
||
expect(Number.isFinite(w.state.family.stones)).toBe(true)
|
||
expect(typeof w.state.family.headId).toBe('string')
|
||
})
|
||
})
|