2.7 KiB
TH1-CI-2026-07-01-004 GrowForest Under-Building Farm
Status
Fixed in code; guardrail added; Unity validation pending.
First Recorded Date
2026-07-01
Raw Symptom And Affected Path
玩家反馈“现在还是会出现庄稼上种树的 bug”,怀疑没有处理 underGroundResource=farm 同时种树的情况。
Affected path:
Unity/Assets/Scripts/TH1_Logic/Action/GridMiscActionLogic.csGridMiscActionType.GrowForest- Kaguya French Napoleonic Code path that allows planting forest on existing buildings.
Why This Is Recurring
GrowForest 的常规合法性只看 GridData.Resource,法典特例还允许在 Windmill/Sawmill/Forge/Market/Wonder/Military... 等已有建筑上种树。TH1 的建筑层会把原资源放入 GridData.ResourceUnderBuilding,例如谷仓/其他建筑下可能保留 Farm。此前判断没有检查 ResourceUnderBuilding,因此 UI 展示和最终执行都可能放行“建筑表层 + 农田底层”的地块。
Root Cause
CheckCan 和 CheckShow 各自内联 GrowForest 判断,且都没有把 ResourceUnderBuilding != ResourceType.None 视为非法种树条件。法典特例在已有建筑上种树时不会清空 Resource,所以隐藏底层资源会持续影响地块状态。
Root-Cause Fix
抽出 CanGrowForestOnGrid(CommonActionParams actionParams) 作为唯一 GrowForest 合法性谓词,并在其中要求:
- terrain 是陆地;
- feature 不是山;
- 当前没有树林;
ResourceUnderBuilding == ResourceType.None;- 常规资源只允许
None/Crop/Fruit; - 法典特例仍只允许既定建筑白名单。
CheckCan 和 CheckShow 均调用该共享谓词。
Guardrail Added
Added Tools/CheckGrowForestUnderBuildingResource.ps1 to assert:
- GrowForest uses a shared
CanGrowForestOnGridpredicate; - the predicate checks
ResourceUnderBuilding != ResourceType.None; CheckCanandCheckShowboth call the predicate.
Tools/GitCheckpoint.ps1 now runs the guardrail when GridMiscActionLogic.cs or the check script changes.
Verification Performed
Tools/CheckGrowForestUnderBuildingResource.ps1passed.Tools/GitCheckpoint.ps1passed and triggered the GrowForest guardrail.dotnet build Unity/TH1.Hotfix.csproj --no-restorepassed with existing warnings.
Remaining Validation Gaps
Unity Editor manual validation is still needed for the exact player-reported scenario:
- build or load a grid whose visible building has
ResourceUnderBuilding = Farm; - confirm GrowForest action does not show and cannot execute;
- confirm normal empty/crop/fruit GrowForest and intended Napoleonic Code building cases still work when
ResourceUnderBuilding = None.