every level load left another handler attached to a freed HUD.
SpeedRunManager outlives the scene, so it kept calling them and each one
wrote to a disposed Label - thousands of ObjectDisposedException per
frame, growing with each load.
Latent all along: StartTimer was only ever called from StartNewGame, so
after a Continue the timer never ticked and the dead handlers never ran.
Calling StartTimer on Continue (needed for splits and best times) made
it visible.
Also stop the timer when leaving to the menu - StopTimer existed and had
no callers, so the run kept ticking in the main menu.
narrowest safe step: only level identity and progression move. Coins,
lives, skills and death stay entirely on GameStateStore and behave as
before, so nothing is tracked in two places.
GameManager addresses levels by stable LevelId via the catalogue;
LevelScenes is gone, so reordering levels no longer invalidates saves.
Every level entry goes through EnterLevel, which fixes LevelStarted never
firing on the first level or after Continue - ghost recording and splits
have been dead outside mid-campaign.
GoTo announces after a frame, once the incoming scene is actually
current. ChangeSceneToPacked is deferred, so the old code handed
GhostEventHandler the scene being torn down.
FinishLevel takes LevelTime? - GetCurrentLevelTime can legitimately be 0
and inventing a value is exactly the bad data LevelTime refuses.
Continue distinguishes absent from corrupt and refuses to overwrite a
corrupt save. Statistics move to the Profile. 69 tests.
slice 7 regression. level_village_2..5.tscn each reference their own
LevelResource for the death screen label, so pointing the resource back
at the scene forms a cycle Godot cannot resolve - "Parse Error: Busy"
and the level fails to load entirely.
ScenePath was a string for exactly this reason. Reverted, and the rot it
allowed (forest_1 aimed at a nonexistent scene) is now caught by
LevelCatalogue.Validate checking every path resolves, plus a repo-level
structural check - fixed by validation rather than by typing.
project.godot: restores the C# feature flag and dialogue_manager
uses_dotnet, which `godot --headless --import` strips on every run.
new progression.adapters project, no engine reference. Stores take a
directory path; Godot resolves user:// with GlobalizePath and passes it
in, which is what makes them testable at all - originally I'd written
this slice off as untestable.
version lives in a file envelope, not the snapshot, so the domain only
knows the current shape. A newer-build save reports Corrupt with a
reason instead of masquerading as "no save" and getting overwritten.
atomic write via temp + rename. One file per aggregate: saving a run
leaves the profile file byte-identical, asserted.
guard rail fixed - it was matching prose in doc comments, now anchored
to using-directives plus a project.assets.json check. 63 tests.
LevelResource gains a stable Id and swaps the string ScenePath for an
editor-tracked PackedScene. The old path field was never read and had
rotted - forest_1 pointed at level_forest_5.tscn, which doesn't exist,
and borrowed LEVEL_5_NAME so it would have displayed "VILLAGE - 5".
LevelCatalogue lists levels in campaign order and produces the domain's
Campaign; an authoring mistake fails at boot because Campaign.Of rejects
blank and duplicate ids. Not a domain port - nothing in the domain
resolves a level to a scene.
All 8 scenes now have a resource; campaign keeps the existing 6
(tutorial_1, village_1..5). village_6 and forest_1 are catalogued but
deliberately out of the campaign.
GameManager.LevelScenes stays until slice 10 rewrites GameManager.
- Fix double-execution bug in LevelStateHandler (coins/skills were committed twice per level)
- Fix DamageComponent to track multiple targets via HashSet instead of single node
- Fix HealthComponent: update health immediately, decouple from PlayerController via signal wiring in PlayerController
- Remove dead loop in SkillManager.RemoveSkill; simplify O(n²) throw skill loop
- Replace GetNode<T>(path) with .Instance across managers; add Instance to StatisticsManager/SpeedRunManager
- GameManager.GetPlayer() now uses EventBus.PlayerSpawned instead of scanning all scene nodes
- UIManager.UiStack: remove [Export], use private List<Control>
- PlayerState: extract DefaultLives constant, simplify CreateDefault()
* Add GridMovementAbility and PacXonGridInteractor for grid-based movement; integrate with PlayerController and PacXonLevel
* Add GhostMovementComponent and PacXonTrailComponent; integrate ghost movement and trail features in PacXonLevel
* Update main menu button focus and add new movement abilities; adjust player and ghost initialization in PacXonLevel
* Refactor collectable components to C# and update resource scripts for consistency
* Update resource paths and refactor properties for consistency
* Refactor UI components to inherit from Control and update node paths for consistency
* Update node paths and group assignments for consistency across scenes
* Refactor GameManager and PlayerDeathComponent for improved state management and logging; update scene connections for player death handling
* Add PhantomCamera components and UI elements for improved scene management; refactor existing components for better integration
* Refactor skill components and update resource paths for consistency; enhance skill management in scenes
* Add new UID files and update scene configurations for dialogue components; refactor skill management and input handling
* Add next level command and refactor player retrieval in GameManager; update scene files for consistency
* Add skill upgrade system and refactor skill components for enhanced functionality; update resource paths and configurations
* Enhance ChargeProgressBar and Marketplace functionality; add owner exit handling and update skill button states
* Refactor ChargeProgressBar and SkillManager; update skill handling and improve component interactions
* Refactor player and level configurations; streamline FlipPlayerComponent and reposition Spaceship Enter