Skip to content

fix(world): build per-zone Lua VM in the zone process#56

Merged
Taure merged 2 commits into
mainfrom
fix/per-zone-lua-state
Jun 29, 2026
Merged

fix(world): build per-zone Lua VM in the zone process#56
Taure merged 2 commits into
mainfrom
fix/per-zone-lua-state

Conversation

@Taure

@Taure Taure commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Problem

game.zone.spawn (and zone-based game.spatial / game.terrain) silently did nothing from Lua on lazy and snapshot-recovered zones - in fact all per-zone Lua (zone_tick, handle_input) was dead there. The per-zone Luerl VM was only ever stitched in on the pre-spawned path, and a VM (opaque closures) can't survive a jsonb snapshot. Large worlds (grid_size > 100 defaults to lazy) and persistent worlds were affected.

Fix

Implements the new optional asobi_world callbacks from widgrensit/asobi#131:

  • init_zone_state/2 builds the zone's Luerl VM in the zone process (handle_continue), so it binds zone_pid => self() and match_pid => world_server_pid. Covers every creation path uniformly - pre-spawned, lazy, recovered. Re-encodes gameplay state restored from a snapshot.
  • dump_zone_state/1 decodes the Luerl game_state ref to a plain, jsonb-safe map (or null when never seeded, so a script's game_state == nil init guard still fires after recovery) and drops the VM.

generate_world no longer injects per-zone VMs; it returns plain zone states and each zone builds its own.

Depends on widgrensit/asobi#131 (merged); pinned via rebar.lock.

Tests

New asobi_lua_zone_spawn_tests:

  • init_zone_state builds a VM from an empty (lazy) zone_state.
  • gameplay state round-trips through dump_zone_state -> jsonb -> init_zone_state.
  • a never-seeded zone round-trips as nil, not an empty table.
  • dump_zone_state without a VM stays jsonb-safe (degraded path).
  • end-to-end: game.zone.spawn from Lua reaches a live asobi_zone built purely via handle_continue.

Existing world/resource-limit/property suites migrated to the new init_zone_state/2 contract. Full suite: 223 eunit, 0 failures.

Follow-up (separate)

widgrensit/asobi#132 - lazy-reaped zones don't reload their DB snapshot on respawn, so their gameplay state doesn't round-trip yet (eager persistent worlds do).

Taure added 2 commits June 29, 2026 17:25
Implement the new asobi_world init_zone_state/2 and dump_zone_state/1
callbacks. Each zone now builds its own Luerl VM from the script in its
own process, bound to the zone pid, so game.zone.spawn (and zone-based
game.spatial / game.terrain) resolve on lazy and snapshot-recovered
zones, not just pre-spawned ones.

- init_zone_state/2 constructs the VM with zone_pid => self() and
  match_pid => world_server_pid, and re-encodes gameplay state restored
  from a snapshot. The VM is never persisted, only rebuilt here.
- dump_zone_state/1 decodes the Luerl game_state ref to a plain map for
  jsonb (null when never seeded, so a script's `game_state == nil` guard
  still fires after recovery) and drops the VM.

generate_world no longer injects per-zone VMs; it returns plain zone
states and each zone builds its own.

Requires asobi with init_zone_state/2 + dump_zone_state/1
(widgrensit/asobi#131); the asobi pin bump follows once that merges.
@Taure Taure merged commit a4d1de8 into main Jun 29, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant