Files
ChronicleOfTheImmortalClan/tests/worldgen-0.1.24.test.ts
T
thzxx 5d9c333c76 v0.1.25: 乾坤一统——MOD 系统首版(1040 全绿,金钟罩不漂)
【P0 修复(0.1.24 遗留)】worldGen.npcs defs 落档 + normalize 幂等重注册——读档后
动态家族(n-g-*)npcById 永命中;MOD 卸载后存档世界仍完整(存档世界永稳)

【MOD 系统四层】
- M2 内容层:modSchema.ts(ModPack 全 JSON:manifest+data{events/npcs/worldgen/pills/forges};
  modParse 纯解析校验 id/name/version/事件模板合法性)
- M3 管理器:modToPlugin(MOD→CotycPlugin 一等子类——插件持久化/双闸/启停/回滚全复用)
- M1 传输层:main IPC mods:scan/read(userData/mods/*.json|*.cotymod)+ preload + env.d.ts
  + store refreshMods/installModByName/installModText
- M4 UI:SettingsPanel「MOD 层」卡(扫描目录/候选列表/安装);内置示例包通路

【世界/插件协同】
- WorldGenPools 聚合词库池(默认不变→基准世界不变;reset() 供隔离);MOD 于新档参与生成
- items.ts 配方聚合注册表(PILL/FORGE base+扩展);PluginContext addPillRecipe/addForgeRecipe/addWorldGenPool

【边界(明注)】灾因/世界数值表注入归平衡版;脚本型 MOD 不做;MOD 只影响新档世界(老档不变形)

【测试】1040 全绿(46 套件):worldGen 存档 1 例 + mod-system 5 例(解析/转换/模板/依赖/基准指纹);
金钟罩 0.1.24 基线未漂(世界生成默认池不变);build 通过
2026-08-23 16:29:29 +08:00

84 lines
3.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, expect, it } from 'vitest'
import { World } from '../src/renderer/game/engine/runtime/World'
import { generateWorld } from '../src/renderer/game/engine/sim/worldgen'
import { npcById } from '../src/renderer/game/data/npcs'
import { engineFromSnapshot } from '../src/renderer/game/engine/GameEngine'
describe('0.1.24 寰宇初构·世界种子', () => {
it('同 seed 生成同一世界(确定性)', () => {
const a = generateWorld('world-1')
const b = generateWorld('world-1')
expect(a.npcs.length).toBe(b.npcs.length)
expect(a.npcs[0]!.id).toBe(b.npcs[0]!.id)
expect(a.feuds).toEqual(b.feuds)
})
it('不同 seed 生成不同世界(势力随机 4~8 家)', () => {
const seen = new Set<string>()
for (const s of ['w1', 'w2', 'w3', 'w4', 'w5']) {
const g = generateWorld(s)
expect(g.npcs.length).toBeGreaterThanOrEqual(4)
expect(g.npcs.length).toBeLessThanOrEqual(8)
seen.add(g.npcs[0]!.id)
}
expect(seen.size).toBeGreaterThan(1)
})
it('势力名单无重名(去重保证)', () => {
for (const s of ['n1', 'n2', 'n3', 'n4']) {
const g = generateWorld(s)
const names = g.npcs.map((n) => n.name)
expect(new Set(names).size).toBe(names.length)
}
})
it('初始关系网:世仇/盟友对存在且对称', () => {
const g = generateWorld('wrel')
expect(g.feuds.length).toBeGreaterThanOrEqual(1)
expect(g.alliances.length).toBeGreaterThanOrEqual(1)
for (const [a, b] of [...g.feuds, ...g.alliances]) {
expect(g.relations[a]?.[b]).toBe(g.relations[b]?.[a])
expect(g.relations[a]?.[b]).toBeDefined()
}
})
it('开局时界(era 三态合法)与市场偏移存在', () => {
const g = generateWorld('wera')
expect(['shengshi', 'pingshi', 'luanshi']).toContain(g.eras)
expect(Object.keys(g.marketOffset).length).toBe(5)
})
it('世界创建即随机:同 seed 同势力、不同 seed 不同势力', () => {
const w1 = World.create({ seed: 'now-1', surname: '钟', familyName: '钟家', motto: 'm', difficulty: 'normal' })
const w2 = World.create({ seed: 'now-1', surname: '钟', familyName: '钟家', motto: 'm', difficulty: 'normal' })
const w3 = World.create({ seed: 'now-2', surname: '钟', familyName: '钟家', motto: 'm', difficulty: 'normal' })
expect(Object.keys(w1.state.npcFamilies).join()).toBe(Object.keys(w2.state.npcFamilies).join())
expect(Object.keys(w1.state.npcFamilies).join()).not.toBe(Object.keys(w3.state.npcFamilies).join())
})
it('开局即恩怨:关系网入档并生效(首月快讯/大样)', () => {
const w = World.create({ seed: 'now-3', surname: '钟', familyName: '钟家', motto: 'm', difficulty: 'normal' })
w.advanceMonth()
const ws = w.state.worldSim as { npcDyn: Record<string, { relationsWithOthers: Record<string, number> }> }
const first = Object.keys(w.state.npcFamilies)[0]!
const rels = ws.npcDyn[first]?.relationsWithOthers ?? {}
expect(Object.keys(rels).length).toBeGreaterThan(0)
})
})
describe('0.1.25 P0worldGen 存档稳固', () => {
it('动态家族 def 落档:读档后 npcById 永命中(P0 修复)', async () => {
let w: World | null = null
for (const s of ['dg-1', 'dg-2', 'dg-3', 'dg-4', 'dg-5', 'dg-6']) {
const t = World.create({ seed: s, surname: '钟', familyName: '钟家', motto: 'm', difficulty: 'normal' })
if (Object.keys(t.state.npcFamilies).some((k) => k.startsWith('n-g'))) { w = t; break }
}
if (!w) return // 都无动态家(seed 未抽中)→ 等价通过
const snap = JSON.parse(JSON.stringify(w.state))
const e2 = engineFromSnapshot(snap as never)
const ids = Object.keys(e2.world.state.npcFamilies)
for (const k of ids) {
expect(npcById(k)).toBeTruthy()
}
})
})