Seat fixes: per-tile state lookup and saving near the map edge - #24
Merged
tomluchowski merged 2 commits intoAug 2, 2026
Merged
Conversation
A seat remembers, for every tile of the game map and of the editor's copy paste container, what it last told its player about it. The two containers keep their states in two separate maps, filled once when each container is sized, and most of the code looks a tile up in the first map and falls back to the second. Four kinds of mistake had crept into that pattern, all in Seat.cpp: hasVisionOnTile() and notifyTileClaimedByEnemy() find the tile in the fallback map through one iterator and then read or write through the other, which is the end of the first map. That is a read past the end of a std::map whenever the server asks about a copy paste container tile. updateTileStateForSeat() looked the tile up with operator[] before doing the find with fallback. The lookup creates a default state for the tile in the game map's map even when the tile belongs to the container, so the find always succeeded, the fallback was dead code, and the update went to the stray entry rather than to the container's own. The stray entries also outlive the container whose tiles they are keyed by. setVisibleBuildingOnTile(), notifyBuildingRemovedFromGameMap(), tileMarkedDiggingNotifiedToPlayer() and exportTileToPacket() had no fallback at all, only the inserting operator[]. They now share one lookup helper that searches both maps and never inserts; the export keeps sending a default state for a tile it does not know, since that is what the insertion amounted to. Also two smaller ones found on the way, both in the render manager: initGameRenderer() hides the creature overlays around its first render target update with the same lockstep double loop, without null checks, that used to crash ODFrameListener::frameStarted(); it gets the same fix. And a range for in Building.cpp iterated the building objects through a reference of the wrong pointer type, converting every element to a temporary pair on the way. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> (cherry picked from commit 3804e4a)
Every seat writes the tiles it has ever seen, and the loop over the columns of the map was bounded by the height of the map instead of its width. On a map taller than it is wide it read past the end of the array: DuelToDeath is 120 by 151, and saving a game there left a level file cut off in the middle of that list and took the game down with it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> (cherry picked from commit ab2858d)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two fixes to
Seat, one commit each:Split out of #16 so each topic can be reviewed on its own. Merging all of the split PRs reproduces the tree of #16 exactly.
🤖 Generated with Claude Code