Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/reference/configuration-file.md
Original file line number Diff line number Diff line change
Expand Up @@ -437,13 +437,13 @@ Core names have to be exact, and anything you don't list keeps EmulatorJS's own

### `emulatorjs.auto_save_sync`

Upload a save every time the emulator writes one, rather than only on save-and-quit. Closing the tab or suffering a crash mid-game then loses nothing.
Sync a save with the server seconds after it's stored in the browser, rather than only on save-and-quit, so progress is kept even if the tab is closed or the browser crashes. Set it to `false` and the emulator's save button comes back as **Sync save**, for uploading on demand. See [Automatic save sync](../using/saves-and-states.md#automatic-save-sync).

**Default:** `false`
**Default:** `true`

```yaml
emulatorjs:
auto_save_sync: true
auto_save_sync: false
```

### `emulatorjs.disable_auto_unload`
Expand Down
29 changes: 15 additions & 14 deletions docs/resources/snippets/env-vars.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,11 @@

### Assets

| Variable | Default | Required | Description |
| ----------------------------- | ----------- | :------: | ---------------------------------------------------------------------------------- |
| `MAX_ASSET_UPLOAD_SIZE_BYTES` | `536870912` | | Max size of a save/state/screenshot upload request in bytes (0 disables the limit) |
| `MAX_AUTOCLEANUP_LIMIT` | `100` | | Max number of saves a client can keep per slot when autocleanup is on (minimum 1) |
| Variable | Default | Required | Description |
| ----------------------------- | ----------- | :------: | ------------------------------------------------------------------------------------------- |
| `MAX_ASSET_UPLOAD_SIZE_BYTES` | `536870912` | | Max size of a save/state/screenshot upload request in bytes (0 disables the limit) |
| `MAX_AUTOCLEANUP_LIMIT` | `100` | | Max number of saves a client can keep per slot when autocleanup is on (minimum 1) |
| `MAX_SAVES_PER_SLOT` | `50` | | Versions the server keeps per save slot, newest first, on every slotted upload (0 disables) |

### Logging

Expand All @@ -176,16 +177,16 @@

### Web Server

| Variable | Default | Required | Description |
| ---------------------------------- | ------- | :------: | ------------------------------------------------------------------ |
| `WEB_SERVER_CONCURRENCY` | `4` | | Number of API worker processes, raise for several concurrent users |
| `WEB_SERVER_TIMEOUT` | `300` | | Timeout for web server requests in seconds |
| `WEB_SERVER_KEEPALIVE` | `2` | | Keep-Alive connection wait time in seconds |
| `WEB_SERVER_MAX_REQUESTS` | `1000` | | Maximum requests a worker processes before restarting |
| `WEB_SERVER_MAX_REQUESTS_JITTER` | `100` | | Random jitter added to max requests value |
| `WEB_SERVER_WORKER_CONNECTIONS` | `1000` | | Maximum simultaneous clients per worker process |
| `WEB_SERVER_GUNICORN_WAIT_SECONDS` | `30` | | Seconds to wait for Gunicorn to start before giving up |
| `IPV4_ONLY` | `false` | | Bind only to IPv4 |
| Variable | Default | Required | Description |
| ---------------------------------- | ------- | :------: | ---------------------------------------------------------------------------------------- |
| `WEB_SERVER_CONCURRENCY` | `4` | | Number of API worker processes, raise for several concurrent users |
| `WEB_SERVER_TIMEOUT` | `300` | | Timeout for web server requests in seconds |
| `WEB_SERVER_KEEPALIVE` | `65` | | Keep-Alive connection wait time in seconds, keep above nginx's 60s upstream idle timeout |
| `WEB_SERVER_MAX_REQUESTS` | `1000` | | Maximum requests a worker processes before restarting |
| `WEB_SERVER_MAX_REQUESTS_JITTER` | `100` | | Random jitter added to max requests value |
| `WEB_SERVER_WORKER_CONNECTIONS` | `1000` | | Maximum simultaneous clients per worker process |
| `WEB_SERVER_GUNICORN_WAIT_SECONDS` | `30` | | Seconds to wait for Gunicorn to start before giving up |
| `IPV4_ONLY` | `false` | | Bind only to IPv4 |

### Proxy

Expand Down
27 changes: 23 additions & 4 deletions docs/using/saves-and-states.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,38 @@ If a ROM has multiple saves or states, RomM presents a picker before the emulato

## In-emulator behaviour

In-game save/save-state/load-state actions are written straight back to the server, so there's no "forgot to upload" step. The player will also ask you to confirm before navigating away from a running game, which prevents losing any unsaved progress.
Saves and states you create in the emulator are written straight back to the server, so there's no "forgot to upload" step. The player also asks you to confirm before navigating away from a running game, so you don't lose unsaved progress.

In-game, the Export and Import save buttons are replaced by a single **Load save or state** picker, which opens with the same Saves and States tabs as the launch screen. A state applies on the fly; picking a save restarts the game from that save. Either one replaces what's running, so you're asked to confirm first.

A **Sync save** button appears alongside it when [automatic save sync](#automatic-save-sync) is off, to upload the current save on demand.

## Automatic save sync

Normally your save gets uploaded when you **save and quit**. Close the tab instead, or crash the browser, or shut the laptop, and the save never leaves the device. Enable [`emulatorjs.auto_save_sync`](../reference/configuration-file.md#emulatorjsauto_save_sync) and the player uploads every time the emulator writes a save, so it doesn't matter how the session ends:
A save syncs automatically with the server seconds after it's stored in the browser. The player watches the emulator's SRAM while you play and uploads a new version as soon as one appears, so your progress is saved even if the tab is closed or the browser crashes. Leaving the player uploads anything the server doesn't have yet.

This is on by default. Set [`emulatorjs.auto_save_sync`](../reference/configuration-file.md#emulatorjsauto_save_sync) to `false` to go back to uploading only on **save and quit**:

```yaml
emulatorjs:
auto_save_sync: true
auto_save_sync: false
```

Each upload is the entire save file, and some games save constantly. On a small instance you won't notice, but you might with a lot of users and large saves. This is instance-wide, set by the server owner, and only affects in-browser play. Save **states** already upload as you create them and aren't affected either way.

An upload the server doesn't take (it's down, the connection dropped) is held in your browser with the screenshot taken when the game wrote it, and retried later. The player tells you whether it was kept, so a "kept for later" message means the progress is safe even though the save isn't on the server yet. Held saves belong to the account that made them, so a shared browser won't hand your progress to whoever signs in next.

## Save slots

Saves are organized into slots, the same model used by the [sync clients](#device-sync), so the same slots show up whether you played in the browser or on a device.

- **`autosave`** is where ordinary play goes, and it keeps a capped history, so it prunes itself as you play.
- **A named slot**, created on launch, keeps every version. Use one when you want a checkpoint you can always come back to.

Each slot lists its newest version first, tagged **Latest**, with older versions folded behind a toggle. A version written in the browser carries a screenshot from the moment it was written, shown as its thumbnail.

The server prunes a slot to `MAX_SAVES_PER_SLOT` (50 by default, `0` to disable the cap). A client that asks for a tighter limit of its own gets the tighter of the two. Saves uploaded without a slot, such as one you imported by hand, are never pruned.

## Device sync

Saves and states can sync to/from registered devices (Grout on muOS, DeckRommSync on a Deck, etc.). Covered in depth in the ecosystem section:
Expand Down Expand Up @@ -77,7 +96,7 @@ If you use [RetroAchievements](retroachievements.md) in hardcore mode, loading a

- **Save uploaded but the game doesn't see it**: wrong format for the core. Check the compatibility table above, then re-upload or switch cores.
- **State loads a corrupted frame**: state was saved by a different build of the core. If the emulator bundle updated, old states may not load cleanly. Re-create or start a fresh save.
- **Save disappears after play**: the emulator didn't flush on quit. Use the in-game save feature instead of just closing the browser.
- **Save disappears after play**: the emulator didn't write a save at all. Use the in-game save feature rather than relying on the emulator flushing on its own, and check that [automatic save sync](#automatic-save-sync) is on.
- **Can't upload, "file too large"**: reverse proxy limit. Raise `client_max_body_size`/`proxy-body-size` (see [Reverse Proxy](../install/reverse-proxy.md)).

More in [Troubleshooting](../troubleshooting/index.md).
2 changes: 1 addition & 1 deletion scripts/sources.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@
repo = "rommapp/romm"
# Set to a tag (e.g. "v5.0.0") or a full SHA. Generators fetch raw files
# from raw.githubusercontent.com/${repo}/${ref}/...
ref = "839605e679bad7a6b552c4219627f68c32e41e29"
ref = "5.3.0-beta.1"
Loading