Defer UI operations until UI system runs frame update#6789
Merged
metalgearsloth merged 1 commit intoJul 16, 2026
Conversation
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.
Redux of Space-Wizards-Federation/RobustToolbox#50. There's a few more comments on that issue, but here's a copy-paste of the description:
In the UI system, some updates are applied immediately, while some are deferred until the frame update. This changes all the operations to be deferred. This fixes a UI bug, but there's a more fundamental underlying bug here.
First, the bug;
forcemap PackedstartroundFor clarification:

Two important components here; the
TechnologyDatabaseComponentstores the information on unlocked and available technologies, and theUserInterfaceComponentprovides the UI (uh-huh). TheResearchConsoleBoundUserInterface.UpdateStatecalls an update on theResearchConsoleMenu, which in turn reads theTechnologyDatabaseComponentto populate the UI. When you press the "Research" button, a message is sent to the server which causes it toDirty()both of these components.For the broken computers, the
ClientGameStateManager.ApplyGameStateapplies the state to theUserInterfaceComponentbefore theTechnologyDatabaseComponent, but because theSharedUserInterfaceSystemhas aComponentHandleStatesubscription, it performs the work in that callback immediately so the UI ends up reading stale values. By deferring all the UI operations until the frame render, we know that any components the UI wants to read will have had their state applied.I didn't look into why one of the computers seems to work - suspect it's simply serialization and the order of components stored in that map.
There seems to be a more fundamental issue here; because the component state updates are unordered, any time you have a system which subscribes to
ComponentHandleStateand reads from a different component, you're in danger of getting stale data. I did a quick scan over all the subscriptions in content and most look pretty benign, though it's gonna be a bunch of work to untangle, especially with systems which raise further events in that subscription.SharedSolutionContainerSystemlooks suspicious, for example, whileFixtureSystem(in engine) seems to have a much clearer issue if the updates arrive out of order.