更新日期:2026-07-04
編碼:UTF-8 對象:開發者、逆向工程研究者與 AI 維護代理
本文件描述目前程式與補丁契約。完整的修改時間線、除錯案例、代理操作規範與驗證方式均已整合於本文件尾部。機器可讀的欄位與 offset 位於 data/game_schema.json;精確 EXE/BCI bytes 位於 docs/reverse-engineering/known-patches.md。
- 唯一的即時工作區是本文件頂端的離線路徑。舊的 OneDrive 路徑只可當歷史背景,不能作為讀寫目標。
- 先執行
Get-Location。部分沙箱會忽略含中文的cwd,實際從C:\開始;不要在根目錄做遞迴搜尋。 - 先執行
git status --short --ignored和git diff。工作樹可能已有使用者或其他代理的變更,禁止任意覆寫。 - Git 若回報 dubious ownership,使用一次性的
git -c safe.directory=... -C ...,不要改全域設定。 - 修改任何遊戲檔前,必須確認所選路徑內存在
Against_Rome.exe。僅有「目錄存在」不足以證明它是遊戲根目錄。 - 不得把未知 EXE 位元組、未知 BCI opcode、Ghidra 自動命名的
FUN_*,寫成已證實語意。 - 不得弱化回復保護。遇到缺少原版基線、未知 patch state 或不安全 ZIP 路徑時,應停止並清楚報錯。
- 每個新補丁至少要有:原始值、修改值、狀態偵測、回復方式、版本/長度防護、失敗時 rollback、文件與 schema 同步。
本專案文檔與開發使用以下語意;不要混用:
- 穩定/已實機驗證(Stable):程式路徑與遊戲行為都有證據。
- 靜態驗證(Static Verified):位元組、反編譯、檔案結構或 round-trip 已核對,但缺少足夠的長時間實機測試。
- 候選(Candidate):有合理的資料流或格式證據,只能讀取/研究,不應由修改器自動寫入。
- 舊版相容狀態:目前不再產生,但偵測和回復必須保留。
- 已否決(Rejected):實機結果證明假設錯誤或造成回歸。保留精確紀錄是為了防止再次加入。
- 未知(Unknown):位元組或資料不符合任何已知狀態。必須保留原檔並警告,不得強寫。
- Ghidra 的
FUN_*只是導航點,必須有 call path、資料流、字串註冊或實機證據,才能命名其意義。 - 每個寫入功能必須能偵測原版/目前版/舊版/未知狀態,且有明確回復路徑。
| 檔案 | 責任 |
|---|---|
src/Program.cs |
WinForms 入口、DPI、UAC |
src/UI/ModifierForm.cs |
手工 UI、事件 wiring、文件頁 |
src/UI/ModifierForm.Data.cs |
備份載入、目前資料讀取、狀態偵測、顯示 |
src/UI/ModifierForm.Patches.cs |
套用、回復、rollback、遊戲檔補丁 |
src/UI/ModifierForm.Presets.cs |
一鍵啟用/關閉所有功能控制 |
src/UI/ModifierForm.SaveManager.cs |
存檔瀏覽、備份、回復、刪除 |
src/UI/ModifierForm.DgVoodoo.cs |
dgVoodoo2 受管安裝/移除 |
src/Core/TroopConfig.cs |
欄位 enum、單位 metadata、平衡規則 |
src/UI/TroopPresetForm.cs |
9 欄單位 preset 編輯 |
src/Core/GameLZSS.cs |
遊戲 LZSS 與 PFIL@ 包裝 |
src/Core/Bci/ |
BCI 特徵碼搜尋、字組寫入與 PFIL 腳本封裝 |
src/Core/EndlessAi/ |
AI Ultimate M1–M5 模組、狀態偵測與套用協調 |
src/Core/Localization.cs |
中英文 UI/log |
data/game_schema.json |
機器可讀的欄位、offset 與 patch metadata |
目標框架為 .NET 8 Windows、WinForms、x64、nullable enabled、PerMonitorV2 DPI。程式 manifest 要求管理員權限,因為正常遊戲安裝位於 Program Files (x86)。
GetGamePath() 回傳 UI 中選定的遊戲路徑。套用、回復、啟動、SAVE、語言 overlay、dgVoodoo2 都必須從這個根目錄推導。任何會寫入或刪除的入口,都應要求 <gamePath>\Against_Rome.exe 存在。
原版資料來源順序:
- 內嵌
Backup.zip。 - 執行檔旁的本機
Backup.zip。 - 使用者所選遊戲安裝中的檔案,載入成記憶體基線。
公開版本不包含原始遊戲資料,因此第三種方式是正式支援路徑。補丁從原版基線重新產生,避免在已修改資料上累積倍率。
FileRollbackScope 追蹤每個目標在第一次修改前的 bytes 或「原先不存在」狀態。SafeWriteAllBytes 使用暫存檔完成單檔替換;流程成功後才 Commit(),否則回復所有已追蹤目標。
這不是多檔案的檔案系統原子交易。2026-07-02 工作樹雖已把 EXE、INI、DAU、team.dat、ENDL BCI 的候選內容先產生為 byte[],實際仍逐檔寫入,語言與 dgVoodoo2 也有各自 I/O。安全性來自預先驗證加 rollback,不可描述成真正的單次 atomic commit。
commit 後要先 Dispose/清空 rollback scope,再更新 UI;UI refresh 例外不應回滾已完成的遊戲檔。
DecompressPfil讀取 64-byte PFIL header 與 LZSS payload;無 PFIL header 時回傳原始 bytes。CompressPfil要求原始 header 至少 64 bytes,並重寫解壓大小(header offset 16 是唯一的大小欄位)。- 遊戲文字使用 Windows-1251;專案文件使用 UTF-8。
- 修改後至少驗證
decompress(compress(payload)) == payload。 - 環狀視窗初始化契約(2026-07-02 修正):遊戲 EXE 解壓器(
FUN_00565c00) 只把環狀視窗前0xFEE個位置填為空格0x20,最後 18 個位置 (0xFEE..0xFFF)是memset(0)後的0x00;寫入位置從0xFEE開始。 壓縮器的視窗模型必須完全一致。舊版GameLZSS把整個視窗當成全空格, 導致檔案開頭 18 bytes 內的空格串可能被匹配到0xFEE..0xFFF的「假想空格」, 遊戲解壓時輸出0x00——文字檔會被 NUL 截斷(症狀:No Mem len=0 CLMK\mk_tcon.c [1138],.sdl解析出 0 個物件)。二進位檔(BCI) 開頭無空格串所以從未觸發。 objdef.dau還要求解壓文字總長不變。- 資料是簡單逗號分隔,現行相容契約為
Split(',')/Join;不要換成 RFC 4180 quote parser。
路徑:SYSTEM/DATA_MP/DEFAULTS/objdef.dau。
主要 zero-based 欄位:
| Index | 名稱 | 狀態 |
|---|---|---|
| 4 | Moves | stable |
| 19 | Hp | stable |
| 23 | Movsf | stable |
| 24 | Sirad | stable |
| 52 | Name | candidate |
| 78..84 | Weapon 1 | stable;angle 82 保留 |
| 86..92 | Weapon 2 | stable |
| 94..100 | Weapon 3 | stable |
| 142 | Aw | stable |
| 146 | Vw | stable |
| 156 | HousingCapacity / wohnwer |
stable |
| 42 | StorageCapacity / maxre |
stable |
| 73 | BuildTime / buildt |
stable |
| 74 | UpgradeTime / upgrdt |
stable |
| 191 | Bmovs | stable |
| 199 | Weapon 1 damage/type base | candidate |
原版/平衡數值先形成 fallback,自訂 preset 再逐欄覆蓋。舊版短 preset 只覆蓋存在的欄位;缺欄位繼承 fallback。不支援 spell radius 的單位,第 9 欄固定為 0。
內建平衡層由 TroopConfig.BalancedUnitStats 直接保存全部 43 個兵種的九項最終值:HP,Dmg,VW,AW,Speed,Sight,Relt,Range,SpellRadius。啟用平衡後不得再套用通用階級矩陣、盾牌、雙手武器或兵種類型倍率。靜態初始化會檢查平衡表與 UnitMeta 數量一致,且 UnitOrder 中每個兵種都有完整九欄。
設計方向:羅馬整體素質最強;條頓近戰輸出最高;塞爾特步兵防禦與步行遠程最強,投石兵採高單發傷害;匈奴騎兵最強,弓騎兵採低單發、高射速。步兵、騎兵與領主維持相同移動速度。精確數值以 BalancedUnitStats 為唯一來源。
- 對原版
wohnwer > 0的所有 row 生效;已觀察到 22 rows。 - 寫入
original * 20,不是current * 20。 - 保留欄位寬度與整個解壓 payload 長度。
LoadCurrentData以所有正值 row 對比original * 20來偵測狀態。- 整合 UI、preset、apply、restore 與 state detection。
- 對所有以
Bau開頭(即建築物)的 row 生效。 - 讀取備份原版的
buildt(Index 73) 與upgrdt(Index 74),若數值大於 0 則除以 10,最低限制為 1 毫秒,防止因 0 導致計時器異常。 - 修改後使用
PadLeft與CheckLen維持原欄位字串長度,確保objdef.dau檔案解壓長度完全一致。 - 遊戲中的維修效率是由生命值與建造時間決定。當建造時間縮短 10 倍,每秒修復生命值比例即同步提升 10 倍,實現建造、升級與維修的全面加速。
- 整合 UI、一鍵預設開關、讀取現有設定偵測、套用及還原機制。已完成實機驗證,確認修改後數值在遊戲中生效,功能運作正常。
- 對所有以
Bau開頭且名稱包含Hau(主堡/主帳)或Lag(倉庫/倉帳)的 row 生效。 - 讀取原版的
maxre(Index 42) 資源儲存容量,若大於 0 則乘以 10 倍。 - 修改後使用
PadLeft與CheckLen維持原欄位字串長度,確保objdef.dau檔案解壓長度完全一致。 - 整合 UI、一鍵預設開關、讀取現有設定偵測、套用及還原機制。已完成實機驗證,確認修改後主堡與倉庫資源容量上限成功提升 10 倍,且無溢位或異常現象。
路徑:SYSTEM/ress.ini。
[objres] 主要欄位:
| 範圍 | 用途 | 修改規則 |
|---|---|---|
| 1..6 | 建造成本 | free construction 時清零 |
| 7..12 | 升級成本 | free upgrade 時清零 |
| 13..18 | 單位生產成本 | free production 時清零,保留明確例外 |
| 19..24 | 裝備/卸裝退還 | 必須保留 |
| 25..28 | 祭司法術成本 | no spell cost 時清零 |
FigTiePac00_Packpferd 完全排除於免費模式,保留原始成本與退還。不得重新加入 healing-food/healing-speed 修改,也不得為修 UI quota 問題而清除 19..24;騎乘村民與戰鬥單位的 reservation count 涉及 EXE/UI runtime 語意。
路徑:SYSTEM/cl_script.ini。
目前管理:
Radius = <faction>, SpellN, valueValue = <faction>, SpellN, value(法術效果主要值,如傷害、治療量或百分比)Value2 = <faction>, SpellN, value(法術效果次要值,如復活士氣百分比)CiviDelay = <faction>, valueMoralsDecLostMemMoralsDecFleeMoralsDecOverPopMoralsIncIdle
修改時保留註解和未管理內容,依 faction + key 定位。Balance toggle 的事件只應更新預覽,不應偷偷重讀所有 live game files。強制英文 toggle 也不應由 live overlay 自動勾選。
路徑:SYSTEM/CLAK/cl_scint.ini。
目前管理:
SpellODef = <faction>, SpellN, alias(復活技能男性屍體別名)SpellODef2 = <faction>, SpellN, alias(復活技能女性屍體別名)
修改時會根據法師技能與復活術強化勾選狀態,將塞爾特的 SpellODef(原為 KEL_INF00 劍士)改為 KEL_INF01(槍盾兵),SpellODef2(原為 KEL_SCH00 弓兵)改為 KEL_INF02(女雙劍士)。本檔案以 PFIL@ 解壓與寫回。
路徑:MAPS/**/team.dat。
最大人口補丁只修改 [teamdata] zero-based column 4 為 1600;maxteamobjgenerell 保留。column 5 是 banner version。team.dat 不負責無盡模式增援 count。
AI Ultimate 已拆成五個可獨立控制的模組:M1 增援規模、M2 增援節奏、M3 敗亡快速回收、M4 保證聚落生成與留守、M5 開局資源。R0 常駐修復不提供開關,負責還原已否決的全域 CLAK 修改。實作入口為 src/Core/EndlessAi/EndlessAiOrchestrator.cs。
M3 另包含 P15:兩個定居型 party 在敗亡清理結束時,終態由
DELETE_PARTY (256) 改為 DELETE_TEAM (257)(解壓偏移 0x109E8、
0x16374)。這會使用腳本既有的 team-cleanup 路徑,先清除舊村落、NPC
登錄與隊伍物件,再回收隊伍編號;突襲與增援 party 仍維持 256。
主要路徑:MAPS/ENDL_000..004/SCRIPT/ak_level.bci。
目前目標狀態:
- 增援 count:4 → 20;EXE runtime clamp 為 1..20。
- 軍事增援 cooldown(
0x178E0):180000 ms → 5000 ms。 - 政黨撤退/清理期限採混合值:非聚落型四處
0x119C0、0x12FFC、0x13FE8、0x17F38由 600000 ms 改為 5000 ms;聚落型處理器的0x10700、0x160EC保留 600000 ms。聚落型 state 51/52 會先等待引擎完成 舊村莊/城牆清理,期限只是保險出口。舊版把六處全改為 5000 ms,會在清理完成 前強制進入 DELETE_PARTY,使同一隊重生後仍把村民送往舊村莊;下次套用會自動 把該舊啟用狀態遷移為目前的混合值。 SYSTEM/CLAK/SCRIPT/ak_haupthaus.bci舊村莊逐物件清理節拍:唯一特徵碼位於0x3248,原版死亡後迴圈為1500 + rand(-25,25)ms,每輪只處理一個已確認的 建築/城牆物件。AI Ultimate 僅把基準1500 -> 100,成為每個物件 75..125 ms, 保留確認協定;71 個物件的理論清理時間由約 105 秒降到約 7 秒。停用時還原 1500, 已啟用但仍為 1500 的舊版可在下次套用時遷移。此全域主建築腳本也會加速玩家主 建築死亡後的村莊清理,但不影響正常存活村莊的生產節拍。 同形的「政黨建立初始到達逾時」(0x7F24)刻意不改(改了會讓到達中的政黨 在定居前就撤退)。- 死亡確認計數(
0x1068C):20 → 3 個連續 tick(村莊、領袖、村民、成員 全滅的確認去彈跳)。 - 軍事增援部隊數門檻:4 → 40(
s_searchTeamUnits(team) < 40);這不是電腦玩家數上限。舊版的 8 可辨識並於下次套用遷移。 - completed-job recycle:0 → 1。
- 增援捐贈公式維持原版;
v56[party]撤退配額由[90,15]改為[66,0],使整個 type-5 增援黨團移交村莊而不撤退。此補丁必須與門檻 40 同步套用及還原;先前只改配額、門檻仍為 8 的組合會在約一波後停止增援。 - gate 保持原版
66,0。 - 六個 AI 排程延遲點全部改為
5000..10000 ms。前三個是內層突襲計時器;後三個是外層排程的初始與更新範圍,會直接限制呼叫定居/軍事增援生成器的 dispatcher。後三個若維持原版 60–240 秒,即使前三個已加速,AI 出場仍會變慢。曾測試1000..2000 ms,實機出現電腦不再重生,因此已否決;該暫行狀態可辨識並自動遷回 5–10 秒。 - 定居生成器的 default 與 0/1/2/3 現存政黨分支機率都改為 101,使有合格隊伍時必定觸發。單人模式的 occupied mask 固定保護玩家 team 0,
pickTeam只會從尚未占用的 CPU team 1–7 選擇,因此結果上限是玩家加 7 個電腦(共 8 隊),且不會重複建立已占用隊伍。 - 聚落模板:
MAPS/ENDL_*/Endlos_*_Siedlung*.sdl(解壓後為 INI 文字)主建築 (namedef 含_Haupt;羅馬為Hauptzelt)的resv由0,0,0,0,0,0改為614,300,372,250,460,288(各欄取原版戰役 AI 聚落實測最大值),加速村莊型 AI 起步;還原時改回全零。MP_* 下的同名模板不動,維持 ENDL 範圍一致。
舊版 112,272 gate bypass 已否決:它會配合過快 loops 耗盡每隊 20-slot NPC job table,造成後期不再補兵。現行 migration 一律恢復 66,0。
全域 CLAK 經濟 patch 部分否決:ak_npc.bci(自由平民保留)與 ak_produktion.bci(生產閘門)的舊修改會讓玩家資源建築停止生產,一律還原、不啟用。
ak_haupthaus.bci 的轉換人數修改(0x3FCC 處 [81,59] -> [66,20],特徵碼唯一命中)已重新啟用並跟隨 AI Ultimate 開關:s_createBattleUnitsMax 的最後一個引數由「推入變數 59」改為「推入常數 20」。EXE 端實作 FUN_005249d0 證實該引數是每支戰鬥部隊的成員數(EXE 鉗制 0..20),且每次呼叫會收集最多 100 名閒置村民、按此人數分批全部轉換(一批 = 一支部隊)。實際運行時原版值為 6,即玩家觀察到的 6 人小隊。玩家手動轉換 UI 是否受影響仍需一次實機回歸驗證。
2026-07-03 修正:實機測試顯示僅改 ak_haupthaus 後 AI 轉換仍為 6 人。追查確認該呼叫位於 var57 == 34(CIVRECREATE_WAIT)分支,只在軍事增援重建鏈觸發;村莊型 AI 日常的「村民轉部隊」實際走 Dorfverteidigung.bci 的四個 s_addNPCJob_createUnit(team, 1, type∈{1,2,6,3}, 0, 0, 6, 6, 1, 0) 呼叫(pushsym 位於解壓後 0xF1BC/0xF264/0xF30C/0xF3B4)。引數 6/7 是每支部隊的成員數下限/上限(job +0x11/+0x12;arg2=1 時 EXE 鉗制 1..20),EXE job 執行器(約 00548700)按該範圍收集閒置村民後呼叫 FUN_00523a00 一次——一個 job 產生一支 N 人部隊。這同時證實 ak_level.bci 軍事 job 的 4..4 -> 20..20 是每隊成員數而非部隊數。AI Ultimate 現在以特徵碼 [66,0, 66,1, 66,?, 66,?, 66,0, 66,0, 66,?, 66,1, 90,8, 128,157, 73,-9, 86](強制恰好 4 處命中)把八個字面值 6 -> 20,還原時改回 6。已於 2026-07-03 實機驗證:套用後村莊型 AI 確實一次轉換 20 名村民為一支部隊。
2026-07-01 曾從 ESAVE_000/ENDL_002 的 CLAK\scr.dat 取出內嵌 ak_level,與 live BCI 做 exact SHA-256 比對,兩者相同。2026-07-02 的存檔證據(所有參戰隊伍 npcActive=0、全部 NPC job slots 空閒、0x17F38 已為 5000 仍無人復活)推翻了「0x17F38 是村落型重生計時」的舊解讀:該位置實為 type-5 處理器的 RETREAT_INIT 期限。2026-07-03 新的 ESAVE_000 現場則證明六處全改 5000 會造成另一個回歸:team 3 已重新 active,但仍保留 71 筆舊村莊資料與舊基準座標,城牆尚未清除就已重生。完整狀態機顯示聚落型 0x10700、0x160EC 是 state 51/52 清理條件的保險期限,不可縮成 5 秒;目前只加速其餘四處,聚落型兩處維持 600000。ak_npc.bci 的重新啟用路徑為原生內建,存檔檔案一律不碰。
目前仍需五張 ENDL 地圖的長時間 late-wave regression test;短期成功不能標成完整 runtime verified。
2026-07-03 現場診斷紀錄:目前 ESAVE_002 是 ENDL_002,存檔時間為
11:04:54;五張 live ak_level.bci 約在 11:18:13 才重新寫入,因此存檔早於
最後一次套用。CLAK\scr.dat 內嵌腳本雖已有軍事 cooldown 5000、六處撤退期限
5000、死亡確認 3 tick、recycle 1、count 20、門檻 8、gate 66,0 與六個生成
機率 101,但前三個 polling loops 仍是已否決的 1000..2000 ms。此狀態已知會
讓電腦重生停滯;套用程式不會回寫既有存檔的內嵌腳本,所以舊局不能拿來驗收
5–10 秒修正版。
同次唯讀檢查發現 live ENDL_002 解壓 payload 與存檔不相同(save SHA-256
4dd021f2f86336e6fc61a269c677ef7403cad833494d467c8fe1cd5580f771a2;live
SHA-256 49839eb76743893b879be201c729c8104c09415acccc29928fbcea29eee02429),相差
42,885 bytes,且 live payload 無法通過正常 BCI opcode/特徵碼結構辨識。即使它
可自我 decompress→compress→decompress 相等,也只代表能重現既有異常資料,
不代表遊戲相容。下一步必須先用可信原版基線還原五張 live 腳本、重新套用並逐張
解壓驗證特徵碼,之後開新無盡局測試;禁止直接修改存檔 CLAK\scr.dat。
- offset
0x161a88 - original
89 15 C4 7D 9E 02 - patched
90 90 90 90 90 90
只接受已知 signature;Unknown EXE 不寫入。
現行 patch 使用 setter trampoline:
- hook
005364c1/file offset0x1364c1 - cave
0056258f/file offset0x16258f - 以
value * 3產生 3x - 保留負值檢查、呼叫
004c0900、回到005364d1
狀態包含 Original、Legacy2x、Expanded3x、Unknown;Legacy2x 必須可偵測、升級與回復。
舊四處 shift-6 → shift-7 patch 已否決:
0x1366c4,0x1366cd0x0d722c,0x0d723b
現行程式不再寫入舊 07 bytes,只偵測並還原。3x 建造範圍與紅框同步已完成實機驗證確認。
- 祭司解鎖四個法術對獻祭所(祭壇,
OD_BAUOPF)數量的限制位於FUN_0044a010(VA0x0044a010)。 - 該限制為硬編碼於 EXE 的
cmp esi, N指令位元組,其中 N 為 1、2、3、4。 - 修改方案是將這 12 處(3 陣營 × 4 法術) cmp 指令的第 3 個位元組(立即數)修改為
0x00,即完全免除祭壇數量限制。 - 檔案偏移量 (File Offsets):
- 條頓 (
FigGerPri00):0x4A112(法術 1),0x4A136(法術 2),0x4A15A(法術 3),0x4A0E3(法術 4) - 塞爾特 (
FigKelPri00):0x4A1CC(法術 1),0x4A293(法術 2),0x4A2B7(法術 3),0x4A249(法術 4) - 匈奴 (
FigHunPri00):0x4A329(法術 1),0x4A3F0(法術 2),0x4A414(法術 3),0x4A3A6(法術 4)
- 條頓 (
- 偵測機制:必須 12 處原始位元組完全匹配或修補位元組完全匹配;任何混合或未知狀態皆判定為 Unknown 並跳過,以確保還原與寫入安全性。
強制英文開關是手動、預設關閉。語言 overlay 原版基線位於 <gamePath>\.against-rome-modifier-language-backup。
回復合約:
- overlay 存在且 baseline/manifest 缺失:中止並明確報錯。
- baseline 完整:精確回復原檔。
- 原版不存在的 overlay-only 檔案:回復時刪除。
不得把 active ToEng 檔當成原版。真實安裝曾有 332 個 overlay 檔但無 baseline,而當時 Backup.zip 的 146 entries 不含這些目標。修復工具為 tools/Repair-LanguageBackup.ps1。
唯一 live save root 是 <gamePath>\SAVE。Windows 在非提升狀態啟動舊遊戲時,可能把寫入導向 %LOCALAPPDATA%\VirtualStore\Program Files (x86)\Against Rome\SAVE;修改器本身要求管理員並把遊戲 WorkingDirectory 設為所選根目錄,但外部非提升捷徑仍可能重建 VirtualStore。
ZIP 備份先建立 .tmp,加入修改器產生的 manifest.json,成功後再 move。ZIP entry 禁止 absolute path、leading slash 與 .. traversal。存檔 restore 成功後先 commit,再清理 staging;cleanup 失敗只記錄。
修改器內嵌 x86 D3D8.dll、DDraw.dll、dgVoodooCpl.exe、dgVoodoo.conf。它不下載 runtime dependency,也不覆蓋非受管 DLL。遊戲根目錄的 manifest 記錄受管檔與 hash;使用者改過的受管檔不會被無聲刪除。來源、版本與 SHA-256 見 ThirdParty/dgVoodoo2/REDISTRIBUTION.md。
mainTabControl的 header 故意隱藏,左側按鈕負責導航。StyleNavButton綁定前必須先建立對應TabPage。settingsLayout第一列放置pnlNumericCard(系統)、pnlSwitchesCard(資源)與pnlBuildCard(建設)三欄;第二列的pnlAiCard橫跨三欄,容納 M1–M5 並依寬度換行。pnlTipsCard指南卡片拆分為左右雙欄,左半部lblTipsContent顯示操作指引,右半部lblTipsDetail顯示功能詳細說明,以避免說明文字過長導致的高度截斷問題。- 新 toggle 必須同步 UI field、localization、apply、restore、state detection 與文件。
- 移除舊有的
.arpreset全域設定檔匯入/匯出功能,改由一鍵「所有功能開啟」與「所有功能關閉」按鈕控制所有開關狀態。 .artroop目前有 9 個屬性;舊短格式缺欄位時使用 fallback。
查詢順序:
docs/reverse-engineering/data/game_schema.jsonre_workspace/ghidra_inventory/against_rome_function_index.csvre_workspace/ghidra_inventory/against_rome_decompiled_functions.c- 必要時新增 focused script 到
tools/re/
re_workspace/ 是本機證據與產物,禁止上傳;tools/re/ 的可重現 scripts 可以公開。完整反編譯不等於取得原始碼,不能還原原始識別字、註解或 build system。
- AI Ultimate 五張 ENDL 地圖的長時間回歸。
apt.dat的安全格式與用途。- BCI opcode 的完整解碼。
[volkres]多個 candidate 欄位。
基本驗證:
dotnet build .\AgainstRomeModifier.csproj -c Release --no-restore
dotnet run --project .\tests\verify_split_patches\verify_split_patches.csproj -c Release
Get-Content .\data\game_schema.json -Raw | ConvertFrom-Json | Out-Null
git diff --check依修改類型追加:
- PFIL:壓縮/解壓 round-trip。
objdef.dau:解壓長度完全相等、短 row bounds。- EXE:original/current/legacy/unknown 四種 state。
- ENDL:五張 map、enable/disable/migration、長時間 waves、save embedded script。
- 語言:manifest、數量、path safety、SHA-256、缺 baseline abort。
- 存檔:完整
.tmpZIP、manifest、path traversal、commit 後 cleanup。
不得提交:原始遊戲資料、Backup.zip、MAPS/、SYSTEM/、SAVE/、ToEng/、原始遊戲封存、本機語言 baseline、.codex/、.agents/、re_workspace/、內部 AI 稽核、工具下載 cache。
可以提交:C# source、README、技術文件、schema、tools/re/ scripts、已記錄來源與 hash 的 dgVoodoo2 檔。未獲使用者明確要求時,不 commit、不 push、不 rewrite history、不 force-push;本 repo 也不應使用 git push --mirror。
- 讀本文件(
TechDoc.md)與data/game_schema.json。 - 讀特定功能對應的
docs/reverse-engineering/*說明文件。 - 檢查工作樹差異,分離既有變更與新開發的變更。
- 以穩定識別字定位代碼位置,不要過度依賴歷史行號。
- 在撰寫變更前,先明確定義:原始 state 匹配、目標 state、unknown state 的安全拒絕行為、以及 restore 的還原方式。
- 保持小步前進與局部修改;不要在無關區域進行大範圍重構。
- 跑與所改區域風險相稱的 build、schema、round-trip、或 byte/state 比對測試。
- 變更完畢後,同步更新代碼、README、技術文件、補丁細節與 schema。
- 最後提交前重新審視 diff,確保沒有覆寫使用者現有工作。
| 症狀 | 根因 | 錯誤處理 | 正確處理 |
|---|---|---|---|
命令從 C:\ 掃描並大量 access denied |
中文 cwd 未被沙箱採用 | 繼續進行盲目的全域遞迴搜尋 | Get-Location、使用絕對/完整路徑、git -C、直接定位目標檔 |
| Git 回報 dubious ownership | sandbox user 與 repo owner 不同 | 修改全域 safe.directory 設定 | 單次使用 -c safe.directory=... 參數 |
| Build 讀不到 NuGet.Config | sandbox 權限限制 | 認定 C# 專案損毀 | 先用 --no-restore 建置;必要時核准讀取使用者設定 |
| UI 效果不顯示 | 初始化順序導致 null page | 刪除「看似沒用」的 styling 設定 | 先查 UI 建立順序與事件 wiring |
| Toggle 又自動變回 live 狀態 | constructor 與 load path 同時寫 Checked | 只修改單一地方 | 同時檢查初始化、event、LoadCurrentData、以及 preset 相互干擾 |
| 免費模式仍有錯誤退還 | 成本與退還欄位重疊 | 只清 obvious cost 或清掉 19..24 欄 | 用原版資料核對完整欄位分組並保留 equipment refund (19..24) |
| AI 前期正常、後期不補兵 | 20-slot NPC job table 耗盡 | 再提高 concurrency 或直接 bypass gate | 設定有界的 active=8、gate 恢復原值、實施 completed job recycle,並進行長時間測試 |
| AI bytes 已改但玩家感覺沒變 | save 中已有排程/timer | 再次盲改 offsets 常數 | 比對 live BCI、save embedded BCI、與遊戲 runtime 排程狀態 |
| 語言回復丟 InvalidOperationException | overlay 存在但原版 baseline 缺失 | 移除防護 guard 或直接將 overlay 檔案視為原版 | 保留 loud guard,重建並藉由雜湊驗證 baseline 正確性 |
| 存檔 ZIP 半成品殘留 | 直接寫入正式 ZIP 檔案 | 捕捉例外後直接繼續 | 先將資料寫入 .tmp 暫存檔,完整建立後再 move/rename |
| restore 後 cleanup 失敗導致整體回滾 | cleanup 程序在 commit 之前執行 | 把刪除 staging 當作核心交易 | 先進行 commit,再對 staging 目錄執行 best-effort cleanup |
| 廣泛 source patch 套不上 | 亂碼/行尾/context 漂移 | 擴大 patch context 範圍 | 使用 ASCII 穩定識別字小範圍 patch,先用 Select-String 檢驗 |
| 文件把候選當事實 | 只看到 Ghidra decompile | 直接命義並寫成 patch | 結合 call-path + bytes + runtime 證據分層記錄 |
.gitignore 有英文規則但遊戲檔仍出現 |
真實資料夾是本地化名稱 | 假設已忽略成功 | 對照實際 on-disk name 與 git status --ignored 的真實輸出 |
- 修正
ress.ini生產/退還分組;保留FigTiePac00_Packpferd。 - 移除 healing 修改與 UI 敘述。
- 發現
.codex/、re_workspace/不應納入版本庫;保留可重現的tools/re/。
- 移除已證實無引用的 UI helper;修正 sidebar highlight 初始化順序。
- 建立
docs/reverse-engineering/、data/game_schema.json與多個 Ghidra scripts。 - 公開建置改為
Backup.zipoptional,並支援從使用者安裝建立基線。 - 修正 rollback commit/Dispose 語意、簡單逗號格式相容、weapon slot bounds。
- 建立 AI Ultimate toggle,開始區分
team.dat與ak_level.bci的責任。 - 記錄騎乘村民/戰鬥單位 UI 計數不是單純資料欄位問題。
- 曾加入 active gate bypass;後續證明會導致隱藏資源耗盡,現在只保留遷移/回復紀錄。
- balance toggle 移入核心開關區,保留原事件 wiring。
- 針對「完整反編譯、DX12、大改架構」只做可行性評估;沒有把 Ghidra output 當原始碼。
- 從下載/cache 構想改成建置時內嵌與受管 install/remove。
- 建立所有權 manifest、衝突拒絕和使用者修改檔保護。
- 找到 20-slot NPC job table 是 late-run stall 根因。
- 改為 count 20、respawn 5s、active 8、gate 原值、job recycle。
- 強化語言 baseline、存檔回復 commit 後清理與 dead-code 驗證。
- 舊 checkout 當時移除過無效的 village-range UI;此結論已被後來 live checkout 的 setter patch 取代,不能拿來刪除現行功能。
- 確立
<selected game path>\SAVE是唯一 live save root,並整理 VirtualStore 歷史存檔。 - 稽核所有 write/delete path,補上 restore game-root 與 ZIP traversal guard。
- 對
CodeAuditReport.md的 AI claim 逐項查 code,只修已證實問題。 - backup ZIP改用 temporary archive + generated manifest;避免 lock 內 logging。
- 唯一 live checkout 搬到離線中文路徑;舊 OneDrive 只留歷史參考。
- 完成 332-file 語言 baseline 重建工具與 hash 驗證流程。
- 村莊 setter 的 2x 實機路徑與紅色虛線框同步行為獲確認;舊四處 shift patch 正式列為 rejected。
- 發現本地化原始遊戲資料夾約 1.42 GB、4623 files,必須保持 ignored/local-only。
- setter trampoline 升級為 2.5x,保留
Legacy2xdetection/migration;新倍率已完成實機確認。 - balance toggle 不再重讀 live files;強制英文 toggle 改為 manual、default off。
- 新增全 22 個正
wohnwerrows 的 20x switch,整合 preset/apply/restore/detection/docs。 - AI Ultimate 移入 core switches,沒有改 patch 語意。
- README/技術文件/ignore/dgVoodoo provenance 更新為公開發佈邊界。
- 讀取
ESAVE_000的 ENDL_002 embedded script,證明 save 與 live BCI exact match。
- 發現
TechDoc.md與兩個未追蹤摘要是亂碼,重建乾淨 UTF-8 中文技術文件。 - 整合上述歷史為本手冊。
- 核對既有 in-memory patch generation/stats layering 重構可編譯。
- 明確記錄其不是完整跨檔原子交易,避免後續代理高估安全性。
- 以比對原版實機安裝與
遊戲原始檔案\,驗證修改器所寫的每個位置。 - 獨立小工具進行
DecompressPfil→CompressPfil驗證,對objdef.dau、ress.ini等所有關鍵檔做 round-trip,位元組完全相等。 - 驗算村莊 setter 3x trampoline 的組語在 bytes 層級正確無誤。
- 證實
objdef.dau內確實有 22 個正值wohnwer行。 - 掃描五張無盡地圖腳本,特徵碼全部命中且初始值正確。
- MIT LICENSE 新增並推送。
- 完成
objdef.dau建造/升級/維修 10 倍加速,以及主堡與倉庫儲存量 10 倍的實機驗證。 - 確認建造/升級時間縮小為 1/10,且修復速率相應提升 10 倍。
- 確認主堡(Haupthaus)與倉庫(Lager)資源儲存上限正確提升 10 倍。
- 將村莊建造與紅框範圍補丁的組語乘數從 2.5 倍升級至 3 倍(LEA 縮放與 NOP 補齊)。
- 更新狀態偵測列舉(Expanded3x)、語意字典與元數據。
- 實作傷害法術提升 5 倍,治療法術提升 50 倍的數據修改邏輯。
- 將
SYSTEM/CLAK/cl_scint.ini納入備份與修改機制,動態替換復活召喚的 ODef 別名(男屍體轉槍盾兵KEL_INF01,女屍體轉女雙劍士KEL_INF02)。 - 實作復活後的單位生命值與士氣設定值為 100%。