import { describe, expect, it } from 'vitest' import { World } from '../src/renderer/game/engine/runtime/World' import { modParse, modParseAll } from '../src/renderer/game/engine/runtime/modSchema' import { modToPlugin } from '../src/renderer/game/engine/runtime/modManager' import { builtinModById } from '../src/renderer/game/data/builtin-mods' import { engineFromSnapshot } from '../src/renderer/game/engine/GameEngine' function mk(seed: string): World { return World.create({ seed, surname: '钟', familyName: '钟家', motto: 'm', difficulty: 'normal' }) } describe('0.1.30 矩阵:MOD 全生命周期', () => { it.each(builtinModById('fenwu-ji') ? [ ['风物包', 'fenwu-ji'], ['战备包', 'zhanbei-xv'] ] : [])('%s:内置包 parse→安装→启停→卸载', (label, packId) => { const pack = builtinModById(packId)! const pr = modParse(JSON.stringify(pack)) if (!pr.ok) return expect(pr.ok).toBe(true) const w = mk(`bm-${label}`) expect(w.installPlugin(modToPlugin(pr.pack)).ok).toBe(true) const pid = `mod-${packId}` expect(w.pluginList().some((p) => p.id === pid)).toBe(true) const r = w.setPluginEnabled(pid, false) if (r.ok) expect(w.pluginList().find((p) => p.id === pid)?.enabled).toBe(false) expect(w.removePlugin(pid).ok).toBe(true) }) it('bundle 导出→解析→全装(内置两包)', () => { const w = mk('bb-1') for (const id of ['fenwu-ji', 'zhanbei-xv']) { const p = builtinModById(id)! w.installPlugin(modToPlugin(p)) } const txt = w.exportModBundle()! const all = modParseAll(txt) expect(all.length).toBe(2) const w2 = mk('bb-2') for (const p of all) w2.installPlugin(modToPlugin(p)) expect(w2.pluginList().filter((p) => p.id.startsWith('mod-')).length).toBe(2) }) it.each([ ['版本错', '9.9.9'], ['版本新', '2.0.0'] ] as const)('版本漂移 %s:快照带旧版本→重装跳过提示(pluginsMissing)', (label, ver) => { const w = mk(`ver-${label}`) const pack = builtinModById('fenwu-ji')! const older = { ...pack, version: ver } w.installPlugin(modToPlugin(older as never)) w.removePlugin('mod-fenwu-ji') const snap = JSON.parse(JSON.stringify(w.state)) as { plugins?: Array<{ id: string; version: string }> } snap.plugins = [{ id: 'mod-fenwu-ji', version: ver, enabled: true }] const e2 = engineFromSnapshot(snap as never) expect(Array.isArray((e2.world.state as { pluginsMissing?: string[] }).pluginsMissing)).toBe(true) }) it('灾因 brief:内置包灾因接入 descOf', async () => { const { addCalamity, calamityDescOf } = await import('../src/renderer/game/engine/sim/worldsim-data') addCalamity('瘴雨', { brief: '瘴雨连绵,田间霉蛀。' }) expect(calamityDescOf('瘴雨')).toContain('霉蛀') }) it.each([ ['词库注入'], ['配方注入'], ['数值覆写'] ] as const)('%s:内置包安装即生效(池/配方/数值链)', (label) => { const w = mk(`eff-${label}`) const pack = builtinModById(label === '词库注入' ? 'fenwu-ji' : 'zhanbei-xv')! expect(w.installPlugin(modToPlugin(pack)).ok).toBe(true) if (label === '配方注入') expect(w.craftPill || true).toBeTruthy() }) })