0.1.39 P4: purgeNpc 清理 worldGen.npcs/relations 僵尸定义 + 金钟罩重算 + 4例测试
This commit is contained in:
@@ -743,7 +743,10 @@ function evolveNpc(w: World, s: WorldSimState, noise: number): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 覆灭清理:npcFamilies/npcDyn/关系网/raidCD/排队事件/distress/dynamic def 全摘 */
|
/** 覆灭清理:npcFamilies/npcDyn/关系网/raidCD/排队事件/distress/dynamic def/worldGen.npcs 全摘
|
||||||
|
* 0.1.39 根治:补全 worldGen.npcs + worldGen.relations 中已灭亡 NPC 的定义清理——
|
||||||
|
* 旧版 purgeNpc 遗漏了存档层数据,长跑 180 年后 worldGen.npcs 堆积 20+ 条僵尸定义,
|
||||||
|
* 直接膨胀存档体积且读档时重注册已灭亡 NPC 的 def(虽然无运行时副作用但不洁)。 */
|
||||||
function purgeNpc(w: World, s: WorldSimState, id: string): void {
|
function purgeNpc(w: World, s: WorldSimState, id: string): void {
|
||||||
delete w.state.npcFamilies[id]
|
delete w.state.npcFamilies[id]
|
||||||
delete s.npcDyn[id]
|
delete s.npcDyn[id]
|
||||||
@@ -755,6 +758,18 @@ function purgeNpc(w: World, s: WorldSimState, id: string): void {
|
|||||||
w.state.eventQueue = (w.state.eventQueue ?? []).filter((e) => !e.startsWith('ev-raid-') || !e.endsWith(id))
|
w.state.eventQueue = (w.state.eventQueue ?? []).filter((e) => !e.startsWith('ev-raid-') || !e.endsWith(id))
|
||||||
if (s.distress?.id === id) s.distress = undefined
|
if (s.distress?.id === id) s.distress = undefined
|
||||||
unregisterNpcDef(id)
|
unregisterNpcDef(id)
|
||||||
|
// 0.1.39:从 worldGen.npcs 移除已灭亡 NPC 的定义(存档体积精简——僵尸 def 不再落盘)
|
||||||
|
if (w.state.worldGen?.npcs) {
|
||||||
|
const idx = w.state.worldGen.npcs.findIndex((n) => n.id === id)
|
||||||
|
if (idx >= 0) w.state.worldGen.npcs.splice(idx, 1)
|
||||||
|
}
|
||||||
|
// 0.1.39:从 worldGen.relations 清理已灭亡 NPC 的关系条目(存档体积精简)
|
||||||
|
if (w.state.worldGen?.relations) {
|
||||||
|
delete w.state.worldGen.relations[id]
|
||||||
|
for (const rid of Object.keys(w.state.worldGen.relations)) {
|
||||||
|
delete w.state.worldGen.relations[rid]?.[id]
|
||||||
|
}
|
||||||
|
}
|
||||||
w.emitFx('ripple', `purge:${id}`)
|
w.emitFx('ripple', `purge:${id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -7,11 +7,11 @@ import { World } from '../src/renderer/game/engine/runtime/World'
|
|||||||
* 任何改动(重构日程/调平衡/加系统)若改变了确定性序列或结果,此测试立刻报红。
|
* 任何改动(重构日程/调平衡/加系统)若改变了确定性序列或结果,此测试立刻报红。
|
||||||
* 更新规则:仅当**有意**变更序列逻辑时,三枚 seed 指纹同版更新并注明原因。
|
* 更新规则:仅当**有意**变更序列逻辑时,三枚 seed 指纹同版更新并注明原因。
|
||||||
*/
|
*/
|
||||||
// 0.1.37 天人感应基线:因果系统(karma衰减/灾年调制/NPC姿态调制/渡劫调制) + 飞升试炼三阶段 + 世界奇观(种子派生零rng)——
|
// 0.1.39 淬体·洗髓基线:purgeNpc 清理 worldGen.npcs/relations 僵尸定义(存档体积精简——时序内更改)。
|
||||||
// 受控变更重算(karma入指纹/assessStance karma调制/WorldSim.tick新增D-0.8/D-0.9段)。
|
// 受控变更重算(bell-seed-2 三档:NPC 灭亡后 worldGen 摘要缩小→指纹变;其余 seed 无 NPC 灭亡→零漂)。
|
||||||
const GOLDEN: Record<string, Record<number, string>> = {
|
const GOLDEN: Record<string, Record<number, string>> = {
|
||||||
'bell-seed-1': { 560: '45b0c17a', 1200: '62e037c1', 2160: 'b85dd7c7' },
|
'bell-seed-1': { 560: '45b0c17a', 1200: '62e037c1', 2160: 'b85dd7c7' },
|
||||||
'bell-seed-2': { 560: '1279a1da', 1200: '3439bd8f', 2160: 'a29efe9f' },
|
'bell-seed-2': { 560: 'be278aba', 1200: '01126e70', 2160: 'fd03f9b2' },
|
||||||
'bell-seed-3': { 560: 'f24480f4', 1200: 'e52bed85', 2160: 'abb2a5d2' }
|
'bell-seed-3': { 560: 'f24480f4', 1200: 'e52bed85', 2160: 'abb2a5d2' }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
/**
|
||||||
|
* 0.1.39 P4:purgeNpc 清理 worldGen.npcs/relations 僵尸定义测试
|
||||||
|
* 验证 NPC 灭亡后 worldGen.npcs 和 worldGen.relations 中的对应条目被同步移除。
|
||||||
|
*/
|
||||||
|
import { describe, expect, it } from 'vitest'
|
||||||
|
import { World } from '../src/renderer/game/engine/runtime/World'
|
||||||
|
import { resetSaveBus, attachLogSink } from './world.helpers'
|
||||||
|
import { stateFingerprint, longRun } from './fingerprint.helper'
|
||||||
|
|
||||||
|
function baseWorld(seed: string): World {
|
||||||
|
const w = World.create({ seed, surname: '封', familyName: '封家', motto: 'm', difficulty: 'normal' })
|
||||||
|
resetSaveBus()
|
||||||
|
attachLogSink(w)
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('0.1.39 purgeNpc 存档体积精简', () => {
|
||||||
|
it('开局 worldGen.npcs 非空且与 npcFamilies 一一对应', () => {
|
||||||
|
const w = baseWorld('purge-1')
|
||||||
|
const genNpcs = w.state.worldGen?.npcs ?? []
|
||||||
|
const famIds = Object.keys(w.state.npcFamilies)
|
||||||
|
expect(genNpcs.length).toBe(famIds.length)
|
||||||
|
for (const n of genNpcs) {
|
||||||
|
expect(famIds).toContain(n.id)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('长跑后灭亡 NPC 不残留于 worldGen.npcs', () => {
|
||||||
|
// 用长跑让 NPC 有机会灭亡(180 年 = 2160 月)
|
||||||
|
const w = longRun('purge-2', 2160)
|
||||||
|
if (w.state.gameOver) return // 族灭则跳过
|
||||||
|
|
||||||
|
const genNpcs = w.state.worldGen?.npcs ?? []
|
||||||
|
const famIds = new Set(Object.keys(w.state.npcFamilies))
|
||||||
|
|
||||||
|
// 所有 worldGen.npcs 中的 id 必须在 npcFamilies 中仍然存活
|
||||||
|
for (const n of genNpcs) {
|
||||||
|
expect(famIds.has(n.id)).toBe(true)
|
||||||
|
}
|
||||||
|
// 反过来,所有存活 NPC 必须在 worldGen.npcs 中有定义
|
||||||
|
for (const fid of famIds) {
|
||||||
|
expect(genNpcs.some((n) => n.id === fid)).toBe(true)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('长跑后灭亡 NPC 不残留于 worldGen.relations', () => {
|
||||||
|
const w = longRun('purge-3', 2160)
|
||||||
|
if (w.state.gameOver) return
|
||||||
|
|
||||||
|
const famIds = new Set(Object.keys(w.state.npcFamilies))
|
||||||
|
const rels = w.state.worldGen?.relations ?? {}
|
||||||
|
|
||||||
|
// relations 的 key 必须都是存活 NPC
|
||||||
|
for (const rid of Object.keys(rels)) {
|
||||||
|
expect(famIds.has(rid)).toBe(true)
|
||||||
|
// relations 的 value 中的 key 也必须都是存活 NPC
|
||||||
|
for (const oid of Object.keys(rels[rid] ?? {})) {
|
||||||
|
expect(famIds.has(oid)).toBe(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('确定性:同 seed 同月数 worldGen.npcs 内容一致', () => {
|
||||||
|
const a = longRun('purge-4', 1200)
|
||||||
|
const b = longRun('purge-4', 1200)
|
||||||
|
expect(JSON.stringify(a.state.worldGen?.npcs)).toBe(JSON.stringify(b.state.worldGen?.npcs))
|
||||||
|
expect(stateFingerprint(a.state)).toBe(stateFingerprint(b.state))
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user