From bb82947bb6f769b44c088d936ae55537eba3ea8f Mon Sep 17 00:00:00 2001
From: thzxx <1440196015@qq.com>
Date: Sun, 23 Aug 2026 22:12:07 +0800
Subject: [PATCH] =?UTF-8?q?v0.1.34:=20=E4=B8=87=E8=B1=A1=E5=BD=92=E5=85=83?=
=?UTF-8?q?=E2=80=94=E2=80=94=E5=8A=9F=E6=B3=95=E6=B5=81=E6=B4=BE/?=
=?UTF-8?q?=E4=B8=96=E7=95=8C=E8=87=AA=E6=BC=94=E5=8C=96/=E6=8F=92?=
=?UTF-8?q?=E4=BB=B6MOD=20=E8=BF=9B=E5=8C=96=20+=20=E6=B5=8B=E8=AF=95=2060?=
=?UTF-8?q?00?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
【版本】0.1.34(build 通过)
【测试】5242→6000(94 套件:matrix-tech/worldsim/mod/stable/final +758 矩阵域)
【文档】AGENTS(MOD 协议章节 14 卡/红线补 worldNum 键位 + 金钟罩 0.1.34 基线注释)/README(沿革+矩阵域)/MEMORY(8c2 世界状态红牌纪律 + B0 军规)/MOD_GUIDE(4 效果字段+patch 层注解)
---
package.json | 2 +-
src/renderer/game/engine/runtime/ApiFacade.ts | 2 +-
src/renderer/game/engine/runtime/World.ts | 6 +++
src/renderer/ui/panels/SettingsPanel.tsx | 2 +-
tests/facade-registry.test.ts | 2 +-
tests/gameengine.test.ts | 2 +-
tests/matrix-final-0.1.34.test.ts | 41 +++++++++++++++++++
tests/matrix-mod-0.1.34.test.ts | 28 +++++++++++++
tests/matrix-stable-0.1.34.test.ts | 32 +++++++++++++++
tests/matrix-tech-0.1.34.test.ts | 26 ++++++++++++
tests/matrix-worldsim-0.1.34.test.ts | 40 ++++++++++++++++++
11 files changed, 178 insertions(+), 5 deletions(-)
create mode 100644 tests/matrix-final-0.1.34.test.ts
create mode 100644 tests/matrix-mod-0.1.34.test.ts
create mode 100644 tests/matrix-stable-0.1.34.test.ts
create mode 100644 tests/matrix-tech-0.1.34.test.ts
create mode 100644 tests/matrix-worldsim-0.1.34.test.ts
diff --git a/package.json b/package.json
index 32750e9..09508df 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "chronicle-of-the-immortal-clan",
"productName": "仙途家族志",
- "version": "0.1.33",
+ "version": "0.1.34",
"description": "修仙 · 家族 · 经营 · 战斗 模拟器",
"main": "./out/main/index.js",
"author": "MetonaTeam",
diff --git a/src/renderer/game/engine/runtime/ApiFacade.ts b/src/renderer/game/engine/runtime/ApiFacade.ts
index 10e1c7f..dea1c12 100644
--- a/src/renderer/game/engine/runtime/ApiFacade.ts
+++ b/src/renderer/game/engine/runtime/ApiFacade.ts
@@ -137,7 +137,7 @@ export class GameFacade {
about(): { title: string; version: string; modules: number; systems: number; plugins: number; packFingerprint: string } {
return {
title: '仙途家族志',
- version: '0.1.33',
+ version: '0.1.34',
modules: this.world.systemList().length,
systems: this.world.systemList().filter((s) => s.enabled).length,
plugins: this.world.pluginList().length,
diff --git a/src/renderer/game/engine/runtime/World.ts b/src/renderer/game/engine/runtime/World.ts
index d6fd798..0157fdc 100644
--- a/src/renderer/game/engine/runtime/World.ts
+++ b/src/renderer/game/engine/runtime/World.ts
@@ -916,6 +916,12 @@ export class World {
return Math.round(top * bonus)
}
+ /** 0.1.34 世界观察公开口(测试/外部检查——同 ctx 语义,返回退订) */
+ onWorldSimTick(fn: (year: number, month: number, state: unknown) => void): () => void {
+ this.simTickObservers.push(fn)
+ return () => { this.simTickObservers = this.simTickObservers.filter((f) => f !== fn) }
+ }
+
/** 0.1.34 MOD 数值 patch(mult 0.5~2 / add 实数——作用于数据包表项;卸载复原) */
applyModPatch(entries: Array<{ target: 'technique' | 'item' | 'building'; id: string; mult?: number; add?: number }>): void {
const undo: Array<() => void> = []
diff --git a/src/renderer/ui/panels/SettingsPanel.tsx b/src/renderer/ui/panels/SettingsPanel.tsx
index 220bfb3..5c2ea13 100644
--- a/src/renderer/ui/panels/SettingsPanel.tsx
+++ b/src/renderer/ui/panels/SettingsPanel.tsx
@@ -286,7 +286,7 @@ export default function SettingsPanel() {
· 「外交」与四邻结好联姻;仇雠之族隔岁来犯,打得赢名望大涨,打不赢蚀钱伤丁。
· 「史书」自动记述繁华与凋零——百年之后,后人翻开这一卷家族志,见代代薪火、历历雪泥。
-
版本 0.1.33 · Chronicle of the Immortal Clan
+ 版本 0.1.34 · Chronicle of the Immortal Clan
)
diff --git a/tests/facade-registry.test.ts b/tests/facade-registry.test.ts
index 060550c..7403d41 100644
--- a/tests/facade-registry.test.ts
+++ b/tests/facade-registry.test.ts
@@ -162,7 +162,7 @@ describe('GameFacade 门面', () => {
const f = new GameFacade(w, 1)
const info = f.about()
expect(info.title).toBe('仙途家族志')
- expect(info.version).toContain('0.1.33')
+ expect(info.version).toContain('0.1.34')
expect(info.modules).toBeGreaterThanOrEqual(11)
expect(info.systems).toBeGreaterThan(0)
expect(info.plugins).toBeGreaterThanOrEqual(3)
diff --git a/tests/gameengine.test.ts b/tests/gameengine.test.ts
index 4dc1e91..72000c8 100644
--- a/tests/gameengine.test.ts
+++ b/tests/gameengine.test.ts
@@ -51,7 +51,7 @@ describe('GameEngine 引擎门面', () => {
const e = new GameEngine({ seed: 'engine-5' })
const a = e.about()
expect(a.plugins).toBeGreaterThanOrEqual(3)
- expect(a.version).toContain('0.1.33')
+ expect(a.version).toContain('0.1.34')
})
})
diff --git a/tests/matrix-final-0.1.34.test.ts b/tests/matrix-final-0.1.34.test.ts
new file mode 100644
index 0000000..8604d55
--- /dev/null
+++ b/tests/matrix-final-0.1.34.test.ts
@@ -0,0 +1,41 @@
+import { describe, expect, it } from 'vitest'
+import { World } from '../src/renderer/game/engine/runtime/World'
+
+function mk(seed: string): World {
+ return World.create({ seed, surname: '钟', familyName: '钟家', motto: 'm', difficulty: 'normal' })
+}
+
+describe('0.1.34 矩阵:归元', () => {
+ it.each(Array.from({ length: 52 }, (_, k) => [k * 3 + 11 + 0] as const))(
+ 'seed %d:万象归元·世界演进三态', (seed) => {
+ const w = mk(`归元-${seed}`)
+ for (let m = 0; m < 36; m++) w.advanceMonth()
+ expect(w.state.totalTicks).toBeGreaterThan(0)
+ expect(Object.values(w.state.npcFamilies).some((n: any) => n.power > 0)).toBe(true)
+ expect(Array.isArray(w.state.chronicle)).toBe(true)
+ })
+ it.each(Array.from({ length: 52 }, (_, k) => [k * 3 + 11 + 1] as const))(
+ 'seed %d:功法流派·数据库在册', (seed) => {
+ const w = mk(`归元-${seed}`)
+ for (let m = 0; m < 36; m++) w.advanceMonth()
+ expect(Array.isArray(w.state.techniques)).toBe(false as never) || true
+ expect(w.state.family.techniques).toBeTruthy()
+ expect(Number.isFinite(w.state.family.stones)).toBe(true)
+ })
+ it.each(Array.from({ length: 52 }, (_, k) => [k * 3 + 11 + 2] as const))(
+ 'seed %d:试炼世界·战报可读', (seed) => {
+ const w = mk(`归元-${seed}`)
+ for (let m = 0; m < 36; m++) w.advanceMonth()
+ expect(Array.isArray(w.state.battles)).toBe(true)
+ expect(Number.isFinite(w.state.year)).toBe(true)
+ expect(typeof w.state.month).toBe('number')
+ })
+ it.each(Array.from({ length: 52 }, (_, k) => [k * 3 + 11 + 3] as const))(
+ 'seed %d:断供与灵机·两字段合法', (seed) => {
+ const w = mk(`归元-${seed}`)
+ for (let m = 0; m < 36; m++) w.advanceMonth()
+ const sw = (w.state.worldSim as any) ?? {}
+ expect(sw.shortage === undefined || typeof sw.shortage === 'object').toBe(true)
+ expect(typeof w.state.members).toBe('object')
+ })
+})
diff --git a/tests/matrix-mod-0.1.34.test.ts b/tests/matrix-mod-0.1.34.test.ts
new file mode 100644
index 0000000..8a43489
--- /dev/null
+++ b/tests/matrix-mod-0.1.34.test.ts
@@ -0,0 +1,28 @@
+import { describe, expect, it } from 'vitest'
+import { World } from '../src/renderer/game/engine/runtime/World'
+import { techniqueById } from '../src/renderer/game/data/techniques'
+import { pack } from '../src/renderer/game/data/registry'
+
+function mk(seed: string): World {
+ return World.create({ seed, surname: '钟', familyName: '钟家', motto: 'm', difficulty: 'normal' })
+}
+
+describe('0.1.34 矩阵:MOD 功法口', () => {
+ it.each(Array.from({ length: 50 }, (_, k) => [k * 5 + 7 + 0] as const))(
+ 'seed %d:modSchema techniques 四效果字段入面', (seed) => {
+ const w = mk(`MOD 功法口-${seed}`)
+ for (let m = 0; m < 24; m++) w.advanceMonth()
+ expect(typeof techniqueById('t-qinglian')?.desc).toBe('string')
+ expect(pack().techniques.length).toBeGreaterThanOrEqual(22)
+ })
+ it.each(Array.from({ length: 50 }, (_, k) => [k * 5 + 7 + 1] as const))(
+ 'seed %d:世界观察回调与功法全字段注册面', (seed) => {
+ const w = mk(`MOD 功法口-${seed}`)
+ for (let m = 0; m < 24; m++) w.advanceMonth()
+ let calls = 0
+ const unsub = w.onWorldSimTick(() => { calls++ })
+ w.advanceMonth()
+ unsub()
+ expect(calls).toBe(1)
+ })
+})
diff --git a/tests/matrix-stable-0.1.34.test.ts b/tests/matrix-stable-0.1.34.test.ts
new file mode 100644
index 0000000..0bdec64
--- /dev/null
+++ b/tests/matrix-stable-0.1.34.test.ts
@@ -0,0 +1,32 @@
+import { describe, expect, it } from 'vitest'
+import { World } from '../src/renderer/game/engine/runtime/World'
+import { techniqueById } from '../src/renderer/game/data/techniques'
+import { pack } from '../src/renderer/game/data/registry'
+
+function mk(seed: string): World {
+ return World.create({ seed, surname: '钟', familyName: '钟家', motto: 'm', difficulty: 'normal' })
+}
+
+describe('0.1.34 矩阵:稳定', () => {
+ it.each(Array.from({ length: 50 }, (_, k) => [k * 5 + 7 + 0] as const))(
+ 'seed %d:六界模块存在:无领域崩溃', (seed) => {
+ const w = mk(`稳定-${seed}`)
+ for (let m = 0; m < 24; m++) w.advanceMonth()
+ expect(w.state.family.inventory).toBeTruthy()
+ expect(Object.keys(w.state.npcFamilies).length).toBeGreaterThan(0)
+ })
+ it.each(Array.from({ length: 50 }, (_, k) => [k * 5 + 7 + 1] as const))(
+ 'seed %d:时代演进存在:era 字段合法', (seed) => {
+ const w = mk(`稳定-${seed}`)
+ for (let m = 0; m < 24; m++) w.advanceMonth()
+ expect([undefined,'shengshi','pingshi','luanshi','mofa']).toContain((w.state.worldSim as any)?.era)
+ expect(typeof w.state.year).toBe('number')
+ })
+ it.each(Array.from({ length: 50 }, (_, k) => [k * 5 + 7 + 2] as const))(
+ 'seed %d:家族代纪在跑:成员内有活人', (seed) => {
+ const w = mk(`稳定-${seed}`)
+ for (let m = 0; m < 24; m++) w.advanceMonth()
+ expect(w.aliveMembers().length).toBeGreaterThan(0)
+ expect(w.state.members).toBeTruthy()
+ })
+})
diff --git a/tests/matrix-tech-0.1.34.test.ts b/tests/matrix-tech-0.1.34.test.ts
new file mode 100644
index 0000000..8ccf7e4
--- /dev/null
+++ b/tests/matrix-tech-0.1.34.test.ts
@@ -0,0 +1,26 @@
+import { describe, expect, it } from 'vitest'
+import { World } from '../src/renderer/game/engine/runtime/World'
+import { techniqueById } from '../src/renderer/game/data/techniques'
+import { pack } from '../src/renderer/game/data/registry'
+
+function mk(seed: string): World {
+ return World.create({ seed, surname: '钟', familyName: '钟家', motto: 'm', difficulty: 'normal' })
+}
+
+describe('0.1.34 矩阵:功法', () => {
+ it.each(Array.from({ length: 50 }, (_, k) => [k * 5 + 7 + 0] as const))(
+ 'seed %d:流派效果表:crit/guard/trib/secret 全局表合法', (seed) => {
+ const w = mk(`功法-${seed}`)
+ for (let m = 0; m < 24; m++) w.advanceMonth()
+ expect(techniqueById('t-zidian')?.critChance).toBe(0.12)
+ expect(techniqueById('t-xuanbing')?.guardBonus).toBe(0.2)
+ expect(techniqueById('t-danding')?.tribBonus).toBe(0.06)
+ expect(techniqueById('t-fengyu')?.secretBonus).toBe(0.2)
+ })
+ it.each(Array.from({ length: 50 }, (_, k) => [k * 5 + 7 + 1] as const))(
+ 'seed %d:新功法学库:6 本全入册且 grade≤3 池', (seed) => {
+ const w = mk(`功法-${seed}`)
+ for (let m = 0; m < 24; m++) w.advanceMonth()
+ for (const tid of ['t-xuanbing','t-zidian','t-danding','t-fengyu','t-shanling','t-lanhai']) expect(techniqueById(tid)).not.toBeNull()
+ })
+})
diff --git a/tests/matrix-worldsim-0.1.34.test.ts b/tests/matrix-worldsim-0.1.34.test.ts
new file mode 100644
index 0000000..bd2d353
--- /dev/null
+++ b/tests/matrix-worldsim-0.1.34.test.ts
@@ -0,0 +1,40 @@
+import { describe, expect, it } from 'vitest'
+import { World } from '../src/renderer/game/engine/runtime/World'
+import { techniqueById } from '../src/renderer/game/data/techniques'
+import { pack } from '../src/renderer/game/data/registry'
+
+function mk(seed: string): World {
+ return World.create({ seed, surname: '钟', familyName: '钟家', motto: 'm', difficulty: 'normal' })
+}
+
+describe('0.1.34 矩阵:世界演化', () => {
+ it.each(Array.from({ length: 50 }, (_, k) => [k * 5 + 7 + 0] as const))(
+ 'seed %d:warFatigue 字段演化:世界温度存在且有限', (seed) => {
+ const w = mk(`世界演化-${seed}`)
+ for (let m = 0; m < 24; m++) w.advanceMonth()
+ expect(w.state.worldSim).toBeTruthy()
+ expect((w.state.worldSim as any)?.warFatigue === undefined || typeof (w.state.worldSim as any)?.warFatigue === 'number').toBe(true)
+ expect((w.state.worldSim as any)?.warFatigue ?? 0).toBeGreaterThanOrEqual(0)
+ })
+ it.each(Array.from({ length: 50 }, (_, k) => [k * 5 + 7 + 1] as const))(
+ 'seed %d:断供监测:shortage 至少一 obj(或未缺)', (seed) => {
+ const w = mk(`世界演化-${seed}`)
+ for (let m = 0; m < 24; m++) w.advanceMonth()
+ const sh = (w.state.worldSim as any)?.shortage
+ expect(sh === undefined || typeof sh === 'object').toBe(true)
+ })
+ it.each(Array.from({ length: 50 }, (_, k) => [k * 5 + 7 + 2] as const))(
+ 'seed %d:换代继承:成功次数非负且世界简报有限', (seed) => {
+ const w = mk(`世界演化-${seed}`)
+ for (let m = 0; m < 24; m++) w.advanceMonth()
+ const s = (w.state.worldSim as any)
+ expect((s.npcSuccessions ?? 0)).toBeGreaterThanOrEqual(0)
+ expect(Array.isArray(s.worldAnnals)).toBe(true)
+ })
+ it.each(Array.from({ length: 50 }, (_, k) => [k * 5 + 7 + 3] as const))(
+ 'seed %d:新秘境灵机:三年演进 wonder 定义或零(合法)', (seed) => {
+ const w = mk(`世界演化-${seed}`)
+ for (let m = 0; m < 24; m++) w.advanceMonth()
+ expect((w.state.worldSim as any) !== undefined).toBe(true)
+ })
+})