#47 Fix late battles referencing unrelated battles (event id collision)#66
Open
Crocatowa wants to merge 2 commits into
Open
#47 Fix late battles referencing unrelated battles (event id collision)#66Crocatowa wants to merge 2 commits into
Crocatowa wants to merge 2 commits into
Conversation
merge Develop
…d collision Synthetic "battle fought" events were assigned Id = Events.Count, which collides with real event ids whenever unsupported event types are skipped during parsing (common in late worldgen). The collision corrupts World.Events ordering so GetEvent's binary search resolves a battle's events to an unrelated, older battle. Assign synthetic ids above the highest existing id so World.Events stays sorted and collision-free. Adds regression tests. Co-authored-by: Cursor <cursoragent@cursor.com>
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.
Summary
Fixes #47. Late-worldgen battles were showing an Events list full of "battle fought" events belonging to a different, much older battle, with none of their own events. This was caused by an ID collision between synthetically-generated events and real events.
Root cause
BattleFoughtevents are generated in code (not read from XML) and were assignedId = world.Events.Count:When the legends XML contains an event type the parser doesn't recognize, that event is silently skipped (the
defaultcase inXMLParser.AddEventadds nothing). This makesWorld.Events.Countsmaller thanmaxEventId + 1.As a result the synthetic IDs (
= Count) collide with real event IDs and get appended out of order, breaking the ascending-sort invariant thatWorld.GetEvent→GetLegendsObjectrelies on. Its fast pathif (id < list.Count && list[id].Id == id) return list[id]then deterministically returns a syntheticBattleFought(theirIdequals their list index), so when a late battle resolves its<event>children it receives battle-fought events from an unrelated earlier battle.Early battles reference low event IDs below the collision boundary, which is why the issue only appears later in worldgen.
Fix
Assign synthetic event IDs strictly above the highest existing event ID, keeping
World.Eventssorted and collision-free (O(1), since events are appended in ID order):Changes
BattleFought: assign synthetic event id above the current max instead of usingEvents.Count.BattleFoughtTests: add regression tests for the gapped-list id assignment and the sorted/collision-free invariant.Testing
dotnet testrun — not run by me (no .NET SDK on my dev machine); please verify in CI / locally.Notes for reviewers
World.Eventsis in ascending ID order when battles are parsed, which holds today (events parse before collections, in document/ID order). I usedlast.Id + 1overEvents.Max(...)to keep it O(1).developto match the repo's integration flow — happy to retargetmainif preferred.War.cs(world.Events.Last().Yearfor war length), which is out of scope here but may be worth a separate look.Made with Cursor