Repository navigation
Enhance: RN version alignment & basic specifications - #42
Conversation
新增的专门测试用例设计与实现
针对同一个节内的键,构建初始状态:["K_Head", "K_Mid1", "K_Mid2", "K_Mid3", "K_Tail"]: 头部删除与重增 (Head): 针对 CINI 实体的节层级,构建初始状态:["Sec_Head", "Sec_Mid1", "Sec_Mid2", "Sec_Mid3", "Sec_Tail"]: 头部节删除与重增 (Head Section): 交错压力测试(Interleaved Key & Section Stress Test): 在节为 Head 时删除其 Head 键并重加(键移至节内队尾); |
|
已完成将 FA2sp 全局所有与地图交互的代码从原始 CINI::CurrentDocument 全面迁移到代理实例 CINIExt::CurrentDocument 的重构。 重构细节总结 全局代理实例与头文件组织: 在 FA2sp/Miscs/Hooks.INI.h 中声明了静态代理实例: 所有 ExtraWindow 窗口实例迁移: 将 FA2sp/ExtraWindow/Common.h 及以下 13 个对话框头文件与实现文件中的 static CINI& map; 统一改为 static CINIExt& map;,并初始化为 CINIExt::CurrentDocument: FA2sp 全局引用清理: 全面扫描并替换了 FA2sp 目录下全部 46 个引用源文件(包括 IsoView、MapData、SingleplayerSettings、TileSetBrowserFrame、LuaConsole 等),将其中的 CINI::CurrentDocument 全部替换为 CINIExt::CurrentDocument。 |
…_Editor - Implement O(1) multi-index SequencedKeyList and decoupled CINIOrderTracker - Track section and key order in LoadINIExt and preserve exact sequence on save - Add SaveMap.PreserveINIKeySorting configuration option and translations - Add Revenge Now configuration suite in Supplementary/RevengeNow/
…Tracker range helpers
…ml for PR verify and add release.yml
…ti-target matrix packaging
… Scripts/, and remove obsolete FinalRevengeDefaults.ini
… includes and remove unused TileGroups.ini
…eepComments=false
…keys and sections
… raw INI strings in UTs
…n pointer switching
…nce across all FA2sp components
… CINIExt::CurrentDocument
bb35081 to
771ee55
Compare
… strictly CINIExt::CurrentDocument
…workflows, and release packaging strategy
…I order switch fix, dead code cleanup, UT harness fix)
The reusable-workflow refactor in PR #42 replaced the previous push/pull_request triggers with pull_request only, so commits on master stopped producing the FA2sp_Release_<sha> artifact. Restore the push trigger (still skipping docs/image only changes) and keep the PR verification.
@@ -1,81 +1,195 @@
INI 键值与小节顺序对齐实施方案与完成报告 (Alignment Plan & Architecture Report)
一、方案核心架构设计
1.1 零破坏解耦设计 (Decoupled Sidecar Design)
由于旧版 32 位
FinalSun.exe/FinalAlert2YR.dat核心逻辑与CINI/INISection的二进制结构存在紧耦合(IDA 逆向已证实EntitiesDictionary与IndicesDictionary具有固定内存偏移),任何直接修改sizeof(INISection)或改变内部std::map类型的改动都会引发主程序崩溃。因此采用外置侧车追踪器 (
CINIOrderTracker):SequencedKeyList,采用std::vector的1.2 自适应键排序 (Adaptive Sorting)
针对红警地图逻辑中具有严苛顺序要求的特殊 Section(例如脚本动作序号
0, 1, 2...、单位结构列表[Units],[Structures]、触发[TeamTypes]):WestwoodNumericKeyCompare),避免将重新添加的编号键挤压到 Section 末尾导致地图解析逻辑错乱。1.3 CINIExt 代理与动态函数指针零开销切换机制 (Dynamic Function Pointer Dispatch)
为了杜绝在业务代码或单元测试中到处“手动补充调用
RecordKey/RemoveKey”的别扭耦合,同时避免在热点写入路径上产生不必要的分支判断:CINIExt继承自CINI(sizeof(CINIExt) == sizeof(CINI) == 80字节,零新增成员变量,确保直接重映射0x7ACC80时不会踩踏相邻结构CMapData::Size)。CINIExt::CurrentDocument全局引用,并在注释中严格规范所有开发者统一使用该实例。FnRecordKey、FnRemoveKey、FnRecordSection、FnRemoveSection。AdaptiveSorting/PreserveINISorting启用时:函数指针指向真实的CINIOrderTracker::RecordKey/RecordSection。SetAdaptiveSorting(false)时直接切换为内部static void NoOp(...) noexcept {}空函数。if),直接调用空函数内联或直接返回,开销趋近于 0。二、单元测试 (UT) 架构与用例矩阵
2.1 In-Process 进程内测试架构
传统单元测试难以覆盖与
FinalAlert2YR.dat二进制宿主高度绑定的 INI 内存与钩子逻辑。为此设计并实现了进程内挂钩测试架构:FA2sp.UnitTest/,编译生成 32 位动态链接库Supplementary/FA2sp.UnitTest.dll。CFinalSunApp::InitInstance(地址0x41FAD0)。Supplementary/UnitTest.log,并通过 GoogleTest 导出Supplementary/UnitTest.xml。testing::InitGoogleTest(&argc, argv),执行RUN_ALL_TESTS()。ExitProcess(res)退出,杜绝弹出主界面阻塞 CI 无人值守环境。2.2 运行隔离机制 (Strict Isolation Mechanism)
FA2sp.dll,会导致 Hook 符号与 Syringe 注入表发生冲突。Scripts/RunUnitTest.bat实现了自动化隔离:FA2sp.dll临时重命名为FA2sp.dll.isolated;Syringe.exe FinalAlert2YR.dat注入FA2sp.UnitTest.dll执行测试;finally阶段无条件还原FA2sp.dll;2.3 单元测试覆盖矩阵 (21 Tests)
在
FA2sp.UnitTest/CINIOrderTrackerTest.cpp中构建了 21 个自动化测试用例,覆盖所有排列组合与边界情况:PreservesInsertionOrderIgnoresDuplicateAdditionsReAddAfterRemovePushedToTailQueueSemanticsRemoveHeadAndTailClearResetsStateSectionOrderTrackingAndQueueSemanticsKeyOrderTrackingAndQueueSemanticsRealCINICrudKeyOperationsCINIExt的WriteString/DeleteKey透明追踪RealCINICrudSectionOperationsCINIExt的AddSection/DeleteSection透明追踪RealCINIAutoTrackingUntrackedItemsRecordKey录入的新键在遍历时自动捕获RealCINIDeletedItemsOmittedDuringIterationEvenWithoutUntrackRealCINIPreserveOrderTrueVsNaturalMapOrderstd::map字母序输出RealCINIComplexMapLifecycleSimulationRealCINISameKeyDeletedAndReaddedHeadMiddleTailCombinationsRealCINISameSectionDeletedAndReaddedHeadMiddleTailCombinationsRealCINIInterleavedKeyAndSectionDeleteReaddStressTestAdaptiveSortingNumericKeysPreserveNaturalOrderOnDeleteAndReadd0, 1, 2, 3自然数字升序而非排到末尾AdaptiveSortingWestwoodNumericComparatorMultiDigit0..9, 10, 11正确排在 9 之后,而非按 ASCII 字符排在 1 之后)AdaptiveSortingMixedSectionPreservesTextHeaderAndOrdersNumericArrayAdaptiveSortingUntrackedKeyWithoutManualRecordKeyAutoSortedDynamicFunctionPointerSwitchingAdaptiveSortingToggleNoOp(零开销无记录),开启后实时挂接追踪三、持续集成 (CI) 工作流改动
CI 架构重构为基于 GitHub Actions 的模块化、多触发点流水线体系:
flowchart TD PR[Pull Request] --> MSBuildWF[msbuild.yml] Merge[Master Push / Merged PR] --> ReleaseWF[release.yml] Dispatch[workflow_dispatch 手动触发] --> ReleaseWF MSBuildWF --> Reusable[reusable-build-and-test.yml] ReleaseWF --> Reusable subgraph ReusableJob ["reusable-build-and-test.yml (windows-2022)"] Checkout[递归拉取代码与子模块 lfs] --> NuGet[还原 NuGet 依赖] NuGet --> Build[MSBuild 编译 FA2sp.sln x86 Release] Build --> DeployBin[部署产物至 Supplementary] DeployBin --> RunUT[执行 Scripts/RunUnitTest.bat] RunUT --> UploadLogs[上传 UT 日志与 XML 报告] UploadLogs --> UploadArtifacts[上传构建产物 FA2sp.dll / pdb] end ReusableJob --> PackageMatrix["package 任务 (矩阵: YR, MO, RN)"] PackageMatrix --> DownloadBin[下载编译构建产物] DownloadBin --> ScriptPkg["./Scripts/PackageRelease.ps1"] ScriptPkg --> GHRelease[发布至 GitHub Releases]3.1 可复用构建与测试工作流 (
reusable-build-and-test.yml)windows-2022虚拟机。submodules: recursive与lfs: true,确保FA2pp、MFC42、googletest、lexilla、scintilla完整克隆。nuget restore FA2sp.sln还原项目第三方依赖(如lua、openssl)。msbuild /m /p:Configuration=Release /p:Platform=x86 FA2sp.sln,一次性并发编译主工程与 UT 工程。Scripts\RunUnitTest.bat运行测试套件。if: always()策略,无论测试成功还是失败,均完整收集并上传UnitTest.log、UnitTest.xml及syringe.log(保留 7 天),便于远端复现和排查断言错误。3.2 PR 校验流水线 (
msbuild.yml)reusable-build-and-test.yml进行严格的零警告、全绿测试卡点验证,防止任何破坏性改动合并入主干。3.3 自动发版流水线 (
release.yml)master分支的 PR 合并或手动调度。v1.6.x)或接受自定义 Tag。matrix: [YR, MO, RN]矩阵任务,并行调用发包脚本分发三种针对性架构的 ZIP 包。四、Release 脚本分拣与打包思路
打包脚本
Scripts/PackageRelease.ps1承担了本地发布模拟与 CI 矩阵打包的核心职能。其设计理念为:分层覆盖 (Layered Overlay) + 白名单/黑名单清洗 (Sanitization)。4.1 分层覆盖分拣流程
每个发行版(Edition)的打包流水线严格遵循以下阶段:
flowchart LR Base[Supplementary/ 基础公共文件] --> Staging[临时暂存区 staging_TARGET] Custom[Supplementary/TARGET/ 专属配置] -->|覆盖写入| Staging Bin[bin_output/ 最新 FA2sp.dll / pdb] -->|注入| Staging Clean[清洗剔除: UnitTest.dll, *.log, *.xml] --> Staging Staging --> Compress[Compress-Archive 生成 FA2sp-TARGET-Version.zip]Supplementary/下的所有通用编辑器运行资源(FinalAlert2YR.dat、核心 CSF 语言包、公共图块、Syringe 运行库等)全量克隆到暂存区staging_$t。YR(原版尤里复仇):MentalOmega/与RevengeNow/目录。FAData.ini及原生 YR 触发/小队/动作配置。MO(心灵终结 Mental Omega):staging/MentalOmega/下的文件,逐项覆盖到暂存区根目录(如 MO 专属FAData.ini、CSF 与定制库)。MentalOmega/与RevengeNow/子目录。RN(复仇时刻 Revenge Now):staging/RevengeNow/下的文件,逐项覆盖到暂存区根目录。SaveMap.PreserveINISorting=true(保持小节物理出现顺序);SaveMap.AdaptiveSorting=true(自适应数字键递增排序与文本键保序);SaveMap.KeepComments=false(不保留注释);UTF8Support.AlwaysSaveAsUTF8=true(总是以 UTF-8 编码保存地图);MentalOmega/与RevengeNow/子目录。bin_output/或Release/目录,将最新编译的FA2sp.dll与符号文件FA2sp.pdb复制到暂存区。FA2sp.UnitTest.dll;RunUnitTest.bat;*.log、报告*.xml;*.isolated。Compress-Archive输出标准发布包:FA2sp-{Target}-{Version}.zip。五、开发者规范与注意事项
FA2sp所有模块与对话框窗口中,必须始终操作CINIExt::CurrentDocument,严禁直接使用底层CINI::CurrentDocument。CINI::CurrentDocument会绕过CINIExt的虚函数与成员拦截(WriteString、DeleteKey、AddSection等),导致CINIOrderTracker追踪断裂。FA2pp/为第三方子模块,绝对不得做任何就地修改或提交。FA2sp.sln编译通过(0 警告、0 错误)与Scripts\RunUnitTest.bat21 项测试全绿通过后方可提交。git push。