v0.1.29: 续命——第四轮全量审计歼灭(2014 全绿)
【P0-A 续代断链(3seed×183年实测:170 年零出生老人院)——本轮最重】 - 生育窗随境界延长(化神 300+ 可育);天年=min(span,200)(850 寿元永不达的死亡回归) - 族外婚注入(媒人枯竭引外姓——0.1.1 至今缺失的最后一环) - 全局年胎 cap(≤18 人年 3 胎/18-24 1 胎/>24 停)→ 稳态 ~25 人、gens 3、2200 月 420ms - 确定性回归:inlaw 判定长度化+单一 chance(修复过程中的真 bug——det 二分锁定) 【P1 七件】legacypass 年锚(同一年 12 连发 224 次实测)/敌强度相对化(0.35+rel×0.55, cap 2.6——5000+ 战力零风险碾压的定锚)/eventRoll 插件权重防垄断(>核心 50% 压缩)/ allEvents 按 enabled 过滤(禁用 MOD 事件双闸全面兑现)/bundle 全量导入(modParseAll 导出 2 回 2)/ chronicle 表治理(write-only→no-op)/Stash 并发(open in-flight 去重+save try) + PluginManager catch 全回滚 + about 版本统一 【P2 群】decline 150 激活生灭/化神月俸 20 石泄灵石死水/灾因 brief+descOf 接线/ worldGenMods 落空/EventModal 文案对齐/LegacyPanel 恒等清理 【测试】70 套件 2014 全绿(audit-0.1.29 六例:人口曲线/传薪年锚/强度公式/bundle 全量/异常回滚/灾因 brief); 【金钟罩】0.1.29 基线重算(续代/战斗/事件数值受控变更);build 通过
This commit is contained in:
@@ -154,7 +154,7 @@ export function EventModal() {
|
||||
|
||||
<div className="modal-opts">
|
||||
{squadPicking ? (
|
||||
<div className="dim2">依选迎战(若现选不满员将由家族精锐补齐)</div>
|
||||
<div className="dim2">依选迎战(可继续点选调整阵容)</div>
|
||||
) : (
|
||||
pendingEventDef.options.map((o, i) => {
|
||||
const isRaid = raidIdx === i
|
||||
|
||||
@@ -269,7 +269,7 @@ export default function SettingsPanel() {
|
||||
· 「外交」与四邻结好联姻;仇雠之族隔岁来犯,打得赢名望大涨,打不赢蚀钱伤丁。<br />
|
||||
· 「史书」自动记述繁华与凋零——百年之后,后人翻开这一卷家族志,见代代薪火、历历雪泥。
|
||||
</div>
|
||||
<div className="dim2" style={{ marginTop: 8 }}>版本 0.1.28 · Chronicle of the Immortal Clan</div>
|
||||
<div className="dim2" style={{ marginTop: 8 }}>版本 0.1.29 · Chronicle of the Immortal Clan</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
+28
-18
@@ -113,22 +113,27 @@ export const useGameStore = create<GameStore>((set, get) => ({
|
||||
await useGameStore.getState().installModText(r.text)
|
||||
},
|
||||
installModText: async (text) => {
|
||||
const { modParse } = await import('../game/engine/runtime/modSchema')
|
||||
const parsed = modParse(text)
|
||||
if (!parsed.ok) { setNextToast(`MOD 解析失败:${parsed.error}`); return }
|
||||
const { modParse, modParseAll } = await import('../game/engine/runtime/modSchema')
|
||||
const st0 = useGameStore.getState()
|
||||
if (!st0.world) { setNextToast('请先进入一局再装 MOD。'); return }
|
||||
// P1-O bundle 全量:可能返回多个包(逐包 preflight+安装)
|
||||
const packs = modParseAll(text)
|
||||
if (packs.length === 0) { setNextToast(`MOD 解析失败:${modParse(text).ok ? '空包' : '非法 JSON'}`); return }
|
||||
const { modToPlugin, modPreflight } = await import('../game/engine/runtime/modManager')
|
||||
const st = useGameStore.getState()
|
||||
if (!st.world) { setNextToast('请先进入一局再装 MOD。'); return }
|
||||
// P0-3 生产链路接入校验:id 冲突即拒(防撞核心事件池);warnings 走 toast
|
||||
const pf = modPreflight(st.world, parsed.pack)
|
||||
if (!pf.ok) { setNextToast(`MOD 安装被拒绝:${pf.reason ?? '校验未过'}`); return }
|
||||
if (pf.warnings.length > 0) setNextToast(`MOD 安装提示:${pf.warnings.slice(0, 2).join(';')}`)
|
||||
const res = st.world.installPlugin(modToPlugin(parsed.pack))
|
||||
if (res.ok) {
|
||||
setNextToast(`MOD「${parsed.pack.name}」已装——新开档的世界将受其影响。`)
|
||||
let okCount = 0
|
||||
let lastWarn = ''
|
||||
for (const pack of packs) {
|
||||
const st = useGameStore.getState()
|
||||
if (!st.world) break
|
||||
const pf = modPreflight(st.world, pack)
|
||||
if (!pf.ok) { setNextToast(`MOD「${pack.name}」被拒绝:${pf.reason ?? '校验未过'}`); continue }
|
||||
if (pf.warnings.length > 0) lastWarn = pf.warnings.slice(0, 2).join(';')
|
||||
const res = st.world.installPlugin(modToPlugin(pack))
|
||||
if (res.ok) okCount++
|
||||
}
|
||||
if (okCount > 0) {
|
||||
setNextToast(`MOD 安装完成:${okCount} 包${lastWarn ? `(提示:${lastWarn})` : ''}——新开档世界将受其影响。`)
|
||||
set((s) => ({ revision: s.revision + 1 }))
|
||||
} else {
|
||||
setNextToast(`MOD 安装失败:${res.reason ?? ''}`)
|
||||
}
|
||||
},
|
||||
screen: 'boot',
|
||||
@@ -562,13 +567,18 @@ function actDirect(w: World, name: ActName, payload: import('../game/engine/runt
|
||||
const Stash = {
|
||||
async save(st: GameStore, label: string): Promise<void> {
|
||||
if (!st.world) return
|
||||
const file = await getSaveSlot(st.slot)
|
||||
await file.open()
|
||||
st.world.syncRng()
|
||||
await file.saveState(st.world.state, label)
|
||||
try {
|
||||
const file = await getSaveSlot(st.slot)
|
||||
await file.open()
|
||||
st.world.syncRng()
|
||||
await file.saveState(st.world.state, label)
|
||||
await file.saveChronicle(st.world.state.chronicle)
|
||||
const meta = metaFromState(st.world.state, st.slot)
|
||||
await file.setMeta(meta)
|
||||
await updateSlotMeta(st.slot, meta)
|
||||
} catch (e) {
|
||||
// P0-S:存储层并发/锁冲突兜底不抛(容忍一次失败,下次自动再试)
|
||||
console.error('[stash-save]', e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user