Server Operations
Crashes, restarts, and what survives them
This page covers what actually happens to player progress when things go wrong: a world's tick thread crashing, a clean stop or restart, the optional shared database being unreachable, and a hard process kill. The engine's defaults are sensible for every one of these; the point of this page is to explain what each knob does so you change one deliberately, not to recommend different values.
World crash recovery (CrashRecovery)
Hytale's CrashRecovery handles a world-thread crash: an exception that kills one world's tick thread while the server process itself keeps running. It does not handle an OS or JVM process crash - if the process dies, no recovery mode runs at all (see below for what that costs).
It is configured in two places: a server-wide default under Defaults.CrashRecovery in config.json, and a per-world override in the world's own instance config, as a CrashRecovery block.
| Knob | Values | What it does |
|---|---|---|
Mode | None | Reload | Shutdown | What to do when the world's tick thread crashes. On a dedicated server the default world's implicit default is Reload; in singleplayer it is None. |
MaxAttempts | 1-100 (default 3) | How many recovery attempts before giving up and running the Fallback. |
RetryDelaySeconds | 1-3600 (default 5) | How long to wait between attempts. |
Fallback | None | Shutdown (default Shutdown) | What happens once MaxAttempts is exhausted. |
Reload is an in-process reload of that one world from disk: server assets are untouched, every plugin keeps running, and the crashed world's own chunk and entity stores are saved first. Shutdown - and an exhausted-MaxAttempts Fallback - takes the same clean shutdown path as /stop, which runs every plugin's shutdown save.
A handled world crash does not discard plugin state
/stop. Only a true process crash - a native crash, an OOM kill, kill -9 - bypasses all teardown.When would you change the defaults? A disposable world is the honest case: a minigame or event world whose state you would throw away anyway can run Mode: None per-world, so a crash there never spends recovery attempts on a world nobody needs back. For the worlds where player progress lives, the engine's own defaults are the right call.
Database backend operations
Everything in this section applies only if you switched the player-data backend to a shared database in database.json; on the default (ecs) backend, player data rides the world save and none of these knobs exist for you.
dbDownPolicy is a boot-time policy
dbDownPolicy is evaluated at boot, when the database is unreachable; it answers no other question, and there is no separate policy for a database dropping mid-session.
REFUSE_LOGINS(the default; an unrecognized value also parses to it) bounces player logins with a clear message until the database answers. Through a recovery or restart loop where the database is still coming up, players simply cannot join until it does.FALLBACK_TO_ECSlets players in on world-save state instead, which then diverges from what the database holds. Choose it only if being joinable matters more to you than the two stores agreeing.
In steady state, dirty sessions flush to the database every flushIntervalMs (default 30000 ms).
The shutdown drain
On shutdown the database backend drains outstanding player flushes for a hard, non-configurable 10 seconds, warns "some data may not persist" if that expires, and closes the connection pool regardless. If an external process supervisor manages your restarts, give its stop cycle room for that drain - a supervisor that hard-kills the process a moment after asking it to stop turns a clean shutdown into the process-crash case below.
What a process crash discards
A true process crash (native crash, OOM kill, kill -9) bypasses every shutdown save. What that actually costs is bounded:
- At most about 30 seconds of placed-block ledger records. The ledger flushes on a debounced traffic beat and unconditionally at clean shutdown, so a crash can lose only the most recent window. The practical symptom is narrow: a block placed in that window is forgotten as player-placed, so breaking it afterwards can earn XP it shouldn't.
- A live RPG Stations work session and a live Kweebec Nightmare round: both tear down only on clean shutdown.
- Skill, quest, achievement, and statistics state is not on this list. It rides the engine's own world persistence on the default backend, or the periodic database flush (see above) on the database backend.
For what a restart means for configuration changes (which edits need one, which reload live), see Safe Live-Reload Paths; for the one command never to use, see the /plugin reload warning on the same page.
Backup & Recovery
- Configs auto-backup when mod updates (look for
*_backup.jsonfiles) - Player data is stored in the world's entity data (ECS components) by default;
database.jsoncan move it to a shared Postgres or MySQL database instead for a multi-server fleet - in that case player data should be backed up there, not with the world save - A player's quests, achievements and what conversations remember about them are ONE record the shared library keeps per player (stored under one
PROGRESSdomain on the database backend, beside skills, statistics and stations). A save from 1.5.x is carried across by itself: the first time each player connects after the update their old quest and achievement state is copied onto that record, once, and never again. Nothing is asked of you and nothing is lost - Leaderboard cache is in
mods/mmoskilltree/leaderboard-cache.json, keyed by player UUID: renaming a player keeps their row and totals, and a reused name inherits nothing - Offline reward grants spool to
mods/mmoskilltree/pending-rewards.json(keyed by player UUID) until the owed player next connects mods/ziggfreedcommon/holds the shared library's owner files (currencies.json,shops.json,shop-pools.json,boards.json,npc-placements.json) plus its runtime ledgers (placed-blocks.json,npc-placement-ledger.json); back this folder up alongsidemods/mmoskilltree/- Ability configuration retired the old
abilities.jsonblob; current tuning lives inability-settings.jsonandability-overrides.json