Plugin version
2.3.0
Server
Jellyfin
Server version
12.1.0
Area
Games / Emulators
What happened
Summary
Exiting a running retro game through the pause menu's plain Exit option (not "Save and exit") uploads a save state to the server, overwriting the user's single synced state slot for that game with no confirmation and no immediate indication in the GUI. A user who fat-fingers "Restart" on a game they have saved progess in can inadvertently destroy their progress with no way to recover.
As a less serious side-issue, if you are a user attempting to test for this specific issue and you test for it by starting a game that you have never played and then do a plain Exit, the GUI will continue to show no Resume option / save badge until the user navigates away and back, giving a false signal for how the Exit option is actually working.
Environment
- Moonfin 2.6.0, Linux desktop (AppImage, x86_64), native emulation (libretro)
- Server: Jellyfin 12.1.0 + Moonbase 2.3.0
- Also reproduced the data-loss half on Moonfin for Android (native cores) earlier the same day
Expected
Plain Exit exits without writing a state (that's what the separate "Save and exit" option implies).
Actual
- Plain Exit uploads/overwrites the state exactly like "Save and exit" — the two menu options appear to have identical persistence behavior, which makes the menu itself misleading.
- The detail screen shows stale save status after exit, so the overwrite is invisible until the user leaves and returns.
Why this matters
The synced state is a single slot per game, overwritten in place, with no history. This makes the "Restart" a time bomb that can destroy your progress with no notification to the user that this is a risk and, as far as I can tell, no way to avoid it once you've clicked "Restart". If you accidentally hit "Restart", your progress is hosed.
Put more simply, the UI should not misinform the user, it's a bad user experience (duh :P ).
I hit this in real life within hours of first setup (opened a game at the title screen to test a controller, exited, lost the real state), and only worked out what had happened by watching the server's saves folder during a controlled retest later.
Suggestions (any subset would help)
- Make plain Exit not write a state, or add a confirmation when the write would overwrite an older state with less play time.
- A general guard against over-writing states with more play time than the current state, or making that the default and allowing opt-out, might not be a bad idea generally actually.
- Longer term: Save state management. E.g. keep N previous states per game (even 2–3 would eliminate most data loss) or expose a "restore previous state" in the plugin dashboard (blue/green saves).
Lastly, thanks for releasing the retro games feature. I absolutely love it and it makes me want to play my old games again. I love being able to sit down at basically any screen in my home and play my favorite childhood games with my saves synced. It's really cool and I hope you continue development.
Steps to reproduce
- Pick a game with no existing save state (I used NES Tetris). Confirm no
lr-<system>-<gameid>.state exists in the server's Moonbase saves folder for the user.
- Launch the game in the desktop client with native emulation, play a few seconds.
- Open the pause menu and choose plain Exit (not "Save and exit").
- Observe the game's detail screen: no Continue option, no saved-game badge.
- Check the server:
saves/<user id>/lr-nes-<gameid>.state now exists, timestamped at the moment of exit.
- Navigate away from the detail screen and back: the Continue option / Save Foundbadge now appears.
- Note that this appears to be per-core in some sense in that if I run in a browser with JS emulation and not a native core it doesn't have the Continue option but if I open the game on my phone with the core downloaded I see it.
Frequency
Always
Screenshot of the problem
I used EmulatorJS for the screenshot since I'm writing the issue at my desktop but you get the idea.
Server logs / errors (optional)
Plugin version
2.3.0
Server
Jellyfin
Server version
12.1.0
Area
Games / Emulators
What happened
Summary
Exiting a running retro game through the pause menu's plain Exit option (not "Save and exit") uploads a save state to the server, overwriting the user's single synced state slot for that game with no confirmation and no immediate indication in the GUI. A user who fat-fingers "Restart" on a game they have saved progess in can inadvertently destroy their progress with no way to recover.
As a less serious side-issue, if you are a user attempting to test for this specific issue and you test for it by starting a game that you have never played and then do a plain Exit, the GUI will continue to show no Resume option / save badge until the user navigates away and back, giving a false signal for how the Exit option is actually working.
Environment
Expected
Plain Exit exits without writing a state (that's what the separate "Save and exit" option implies).
Actual
Why this matters
The synced state is a single slot per game, overwritten in place, with no history. This makes the "Restart" a time bomb that can destroy your progress with no notification to the user that this is a risk and, as far as I can tell, no way to avoid it once you've clicked "Restart". If you accidentally hit "Restart", your progress is hosed.
Put more simply, the UI should not misinform the user, it's a bad user experience (duh :P ).
I hit this in real life within hours of first setup (opened a game at the title screen to test a controller, exited, lost the real state), and only worked out what had happened by watching the server's saves folder during a controlled retest later.
Suggestions (any subset would help)
Lastly, thanks for releasing the retro games feature. I absolutely love it and it makes me want to play my old games again. I love being able to sit down at basically any screen in my home and play my favorite childhood games with my saves synced. It's really cool and I hope you continue development.
Steps to reproduce
lr-<system>-<gameid>.stateexists in the server's Moonbase saves folder for the user.saves/<user id>/lr-nes-<gameid>.statenow exists, timestamped at the moment of exit.Frequency
Always
Screenshot of the problem
I used EmulatorJS for the screenshot since I'm writing the issue at my desktop but you get the idea.
Server logs / errors (optional)