/** * MOD 包 schema(0.1.25《乾坤一统》) * MOD = 可分发的外部内容包(JSON 单文件/文件)——Manifest + 纯数据。 * MOD 经 ModManager 转换为 CotycPlugin 进标准插件管线(持久化/双闸/回滚免费获得)。 */ import { EventDef } from '../../data/events' import { NpcFamilyDef } from '../../data/npcs' export interface ModPackData { /** 追加事件(需与既有 id 无冲突) */ events?: EventDef[] /** 世界模板(worldgen 池候选——新档生成时参与) */ npcs?: NpcFamilyDef[] /** 世界生成词库注入 */ worldgen?: { styles?: string[] regions?: string[] fams?: string[] suffixes?: string[] } /** 丹方/铸器配方 */ pills?: Array<{ output: string; name: string; danfangLevel: number; stones: number; lingcao: number; beastcore: number; desc: string }> forges?: Array<{ output: string; name: string; stones: number; lingkuang: number; beastcore: number; desc: string }> } export interface ModPack { id: string name: string version: string gameVersion?: string author?: string description?: string depends?: string[] conflicts?: string[] data: ModPackData } export type ModParseResult = { ok: true; pack: ModPack } | { ok: false; error: string } const ID_RE = /^[a-z0-9][a-z0-9-_]{1,31}$/i /** 纯解析(任何文本 → ModPack 或错误);校验层供 vitest 直测 */ export function modParse(text: string): ModParseResult { let raw: unknown try { raw = JSON.parse(text) } catch { return { ok: false, error: 'MOD 文件不是合法 JSON。' } } if (!raw || typeof raw !== 'object') return { ok: false, error: 'MOD 内容为空。' } const p = raw as Record if (typeof p.id !== 'string' || !ID_RE.test(p.id)) return { ok: false, error: '缺失/非法的 MOD id。' } if (typeof p.name !== 'string' || !p.name.trim()) return { ok: false, error: '缺失 MOD 名称。' } if (typeof p.version !== 'string' || !p.version.trim()) return { ok: false, error: '缺失 MOD 版本号。' } const data = (p.data ?? {}) as Record if (!data || typeof data !== 'object') return { ok: false, error: 'MOD data 段缺失。' } if (Array.isArray(data.events)) { for (const e of data.events) { if (!e || typeof e !== 'object') return { ok: false, error: 'MOD 事件表含非法行。' } const ev = e as Record if (typeof ev.id !== 'string' || typeof ev.name !== 'string' || !Array.isArray(ev.options)) { return { ok: false, error: `MOD 事件 ${String(ev.id ?? '?')} 缺 id/name/options。` } } } } if (Array.isArray(data.npcs)) { for (const n of data.npcs) { const nn = n as Record if (typeof nn.id !== 'string' || typeof nn.name !== 'string' || typeof nn.region !== 'string') { return { ok: false, error: 'MOD 模板表含非法行。' } } } } return { ok: true, pack: raw as ModPack } }