v0.1.24: 寰宇初构——世界种子生成器 + 插件时轮锚点(1034 全绿)

【世界种子生成器(NPC 数量不再定死)】
- sim/worldgen.ts:generateWorld(seed) 确定性塑造天下——NPC 4~8 家随机
  (老牌世家模板 + 词库组合新贵,名字去重)、初始关系网(1-2世仇+1盟友)、
  开局 era 三态、区域风味、市场偏移 ±15%
- 独立派生 rng(seed::worldgen)——World.rng 主序列零消耗:同 seed 世界可重放、
  玩法随机序列不受生成器移动(金钟罩玩法序保护)
- state.worldGen 落档(normalize 旧档按 seed 重放=同世界,存档兼容)
- creation 初始化 npcFamilies/initSim 关系网/era/池偏置全走 worldgen——开局即恩怨
- 局内补位目标 = 开局家数(4~8),生灭闭环持续

【插件深化(0.1.24 第二组钩子)】
- PluginContext.beforePhase/afterPhase(时轮锚点:phase 前后挂勾,卸载全摘)
- PluginContext.addNpcTemplate(世界模板注入——词库插件化)
- plugin-public 文档同步;示例 Plugin 契约升级

【测试适配(世界名单随机化)】
- 静态 npc id 假设全面改动态取家(anyNpc helper 共享);
- 难度梯度用例改「同 seed 不同难度」比较;worldgen 确定性/范围/去重/关系对称 7 例

【测试】1034 全绿(45 套件);金钟罩 0.1.24 基线固化(worldgen 随机世界)+ worldAnnals 等;
build 通过
This commit is contained in:
2026-08-23 16:15:22 +08:00
parent 04ef80faa5
commit ec25bf92fc
28 changed files with 382 additions and 72 deletions
+65
View File
@@ -0,0 +1,65 @@
import { describe, expect, it } from 'vitest'
import { World } from '../src/renderer/game/engine/runtime/World'
import { generateWorld } from '../src/renderer/game/engine/sim/worldgen'
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)
})
})