Fix state/save injection timing and corruption in EmulatorJS - #3624
Merged
Conversation
Save states were inconsistently saved and frequently failed to load, especially on threaded cores (SNES, N64). Two timing races were the cause: - On game start, a selected state was applied after a fixed 10ms delay with no check that the core was ready. Heavier cores aren't booted in that window, so the state applied partially and left a black screen. Replace the fixed delay with a gameManager readiness poll plus a short settle window before applying the state (mirrors the console player). - The Save & Quit handler read the state from a running emulator. On threaded cores the worker thread mutates emulator memory while getState() reads it, producing torn/corrupt buffers that are then stored permanently. Capture the screenshot while running, then pause before serializing the state and save file. Also refuse to upload zero-length state buffers so a failed capture can't overwrite good states on the server. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PoAdK2fmqHGmGuXWaKN1HT
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
This PR fixes critical timing and data corruption issues when loading save states in the EmulatorJS player, particularly affecting heavier cores (SNES with enhancement chips, N64, DS) that require longer boot times.
Fixes #2319
Changes
Added
waitForGameManager()polling function - Replaces the unreliable fixed 10ms delay with a proper poll (up to 5s timeout) that waits for EmulatorJS'gameManagerto be fully initialized before attempting save/state injection. This prevents "black screen" failures on cores that need longer to boot.Added state settle delay - Introduces a 500ms delay after the game manager is ready but before applying a state, allowing the core to render a few frames and stabilize before state deserialization.
Fixed state corruption on save/quit - Reordered operations to capture the screenshot while the game is running (before pause), then pause and wait 50ms before reading state/save files. This prevents torn reads from threaded cores (SNES, N64) that race the worker thread and produce corrupt, unloadable states.
Added empty state validation - The
saveState()utility now rejects zero-length state buffers (indicating serialization failure) to prevent corrupt captures from overwriting good states on the server.Improved error handling - Added null checks and console warnings for edge cases where the game manager isn't ready.
Testing
https://claude.ai/code/session_01PoAdK2fmqHGmGuXWaKN1HT