asobi_lua_reload (asobi v0.75.1)
View SourceShared hot-reload primitive for Lua-backed match and world states.
Both asobi_lua_match and asobi_lua_world (per-world and per-zone) keep a
Luerl state alongside the path of the script that produced it. On every tick
we stat the file; if its mtime has moved, we re-execute the script body
against the current Luerl state — re-declaring globals and functions in
place — preserving in-flight game state.
Behaviour:
- Lua-side state (players, counters, tables) lives inside the Luerl state and
survives reload, because the script body only reassigns globals and
redefines functions; existing locals and table fields are not touched
unless the script explicitly re-runs
init(). - Erlang-side state (the wrapper map) is otherwise untouched, except for one
output field: a successful reload stamps
just_reloaded => truefor exactly the tick that reloaded, cleared on every other call (including a livereload_modeflip tooff).asobi_lua_worldreads this to drivespawn_templates_hint/1(asobi#253);asobi_lua_matchignores it. - A syntax error in the new script logs a warning, remembers the new mtime (so we don't keep retrying the same broken file), and keeps running the old code until the file is fixed.
- The
_ASOBI_LOADEDrequire cache is cleared so transitiverequire()d modules also re-read from disk.
Deployment-mode notes
This is a filesystem-mtime primitive. It assumes the script lives at a
path the BEAM can stat(), and that "the script has changed" can be
expressed as a new mtime. Two real-world deployment models fit that:
- Local dev — Lua files mounted via a Docker bind mount or sitting under
/app/game/directly. Edit-save triggers a reload on the next tick. - Self-hosted prod with a host-volume mount — operator's CI/CD writes
new files into the mounted directory (best practice: write to a temp file
and
mvfor atomic swap). The next tick picks them up.
Two deployment models do NOT use this primitive at runtime, by design:
- Sealed-bundle prod (e.g. asobi managed cloud) — the bundle is
extracted once at boot to an immutable directory; mtime never changes
within a container's lifetime. New deploys are container restarts on a
new generation. The per-tick
stat()is a no-op in this model. - Custom script sources (DB, S3, git, etc.) — these belong behind the
planned
asobi_lua_sourcebehaviour, which will dispatch to either this filesystem implementation or an alternative loader. Until then, custom sources should arrange for files to land on disk and use this primitive, or implement reload outside it.
Operators running self-hosted with high zone counts who want to suppress
per-tick stat overhead can set asobi_lua.reload_mode (or the
ASOBI_LUA_RELOAD env var the release script reads) to:
auto(default) — mtime-poll every tick. Suitable for dev and self-hosted volume-mount setups.off— never reload. Suitable for sealed-bundle prod where code changes are container restarts. The per-tickstat()is skipped.