fix!: Wait for the whole component tree to load before starting the game - #3998
Open
spydon wants to merge 2 commits into
Open
fix!: Wait for the whole component tree to load before starting the game#3998spydon wants to merge 2 commits into
spydon wants to merge 2 commits into
Conversation
5 tasks
spydon
marked this pull request as ready for review
August 14, 2026 22:22
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.
Description
Previously the
GameWidgetonly awaited the game's ownonLoadbefore removing the loading widget and starting the game. Components added during the initial load (the world, the camera, and anything added inonLoad) were still loading in the lifecycle queue when the first frames ran, so aloadingBuilderdisappeared too early and the game started half-materialized.With this PR the
GameWidgetwaits for the whole initial component tree to be loaded and mounted before the game attaches and starts ticking:Gamegained aready()method that theGameWidgetawaits afterload()andmount(), before the firstupdate. It is a no-op by default and overridden byFlameGame.FlameGame.ready()no longer polls with zero-delay timers. It now drains the lifecycle queue event-driven, sleeping on a new internalComponent.loadSettledfuture (which completes on load success or failure, without interfering with how load errors are reported throughComponent.loadedor the currentZone) and on a new internal queue mutation notification, so it also wakes up when a stuck component is removed while loading. This also makesready()work undertestWidgets' fake async, where zero-delay timer polling either stalls or spins.loaderFutureinGameWidgetnow stops early if the widget is disposed or the game instance is swapped out while the game is still loading, instead of continuing to mount components into a disposed game.dequeueAdd/dequeueRemovenow traverse the queue withforEachWhereinstead of the shared iterator, since they can be called from user code that runs whileprocessLifecycleEventsis iterating (the queue only supports one iteration at a time).flame_test'sinitializeGameand the benchmark helper boot games the same way, so tests and benchmarks match the production startup path.Note that a component whose initial
onLoadnever completes will now keep the game on the loading widget instead of starting without it, which is the intent of this change. Removing such a component unblocks the start.Checklist
docsand added dartdoc comments with///.examplesordocs.Breaking Change?
Migration instructions
The game no longer starts while components added during the initial load are still loading:
GameWidget.loadingBuilder, or add the slow components after the initial load instead of duringonLoad.onLoadawaits something that only happens once the game is running (an update tick, an overlay interaction) will now keep the game on the loading widget forever; restructure such loads so they complete on their own.GameWidgetmay need an extratester.pump()before the game is attached, since the loader now also waits for the component tree.Gamesubclass defines its ownready()member, it now overridesGame.ready()and is awaited by theGameWidgetbefore the game starts.Related Issues
Closes #3997