Fix undo corruption when merged house becomes vacant - #795
Conversation
Thanks to @csfreitas for finding the cause on bvschaik#795
|
Good catch! I did disable undo on house evolution merge/split, but missed this one. |
|
Could you detail the steps required to reproduce the bug so I can check whether the fix works? I tried to reproduce but I could not. I built some statues (to be deleted later), then some houses. I caused the people to emigrate with high taxes and 0 wages. I deleted the statues just before a 2x2 merged house got vacated. The 3 vacant lots chose building ids outside the deleted statue range due to this bit of code in src/building/building.c: julius/src/building/building.c Lines 54 to 62 in 3c7d865 The code for creating a building explicitly checks the undo list, so they are not reused. Also, please don't bother with writing a test for this - the tests are only for integration testing the game logic, not these kind of bugs. |
|
Thanks for checking this, Bianca. You are right about the building-ID protection, and I need to correct my earlier explanation. My original diagnostic forced the house to become vacant between I then ran a separate local, headless diagnostic without this PR's fix, using the normal construction APIs and The test in this PR only checks that undo gets disabled; it does not demonstrate the reported corruption. Understood about the integration suite: I will not pursue adding this diagnostic there. I have moved this PR to draft. I do not currently have valid reproduction steps for the proposed cause, and the existing fix should not be treated as established. Sorry for presenting the earlier result too confidently, and thank you for catching this. The next step is to identify a sequence reachable through normal gameplay before proposing a correction. |
Summary
brugle-lugdunum-native.savfixture.Root cause
When a merged house becomes empty,
building_house_change_to_vacant_lot()keeps one building record and creates three additional vacant lots. This path did not invalidate an Undo operation that was still being prepared.During a clear-land transaction,
game_undo_contains_building()cannot protect the recorded building IDs whilegame_can_undo()is false (ready == 0). A newly created vacant lot can therefore reuse the ID of a demolished building. Performing Undo later restores the old building record over that ID, while the vacant-lot tile continues to reference it.The corrupted save from #775 contains the resulting invariant violation: tile
(50, 63)references building ID414, but building414is a 2x2 villa at(43, 83).The fix follows the existing policy used by other house merge and split paths: structural simulation changes that create building records invalidate the pending Undo operation.
Regression test
The test starts a clear-land Undo transaction, makes an existing merged house become vacant, finishes the transaction, and verifies that Undo is no longer available. Before the fix, Undo remains available and permits the unsafe ID reuse path.
Validation
CI note
The Emscripten job currently fails at the linker before tests run. The workflow installs
emsdk latest, which now resolves to 6.0.9; the previous successful upstream run used 6.0.1. The failure is missing C++ RTTI symbols fromlibembind-rtti.aand is unrelated to this change.Fixes #775