asobi_zone_manager (asobi v0.84.0)
View SourceLazy zone lifecycle manager for the world server.
Replaces the static zone_pids map with on-demand zone creation and idle reaping. For large worlds (2000x2000 grids), spawning all zones at startup is untenable — this module creates zones on first access and reaps them after an idle timeout.
Hot-path lookups go through ETS directly, bypassing the gen_server.
Summary
Functions
Return existing zone or start a new one. ETS fast path first.
As ensure_zone/2, with an explicit call timeout. Callers on a hot path
that must not stall on a busy manager (asobi_zone's per-tick crossing
check, widgrensit/asobi#271) pass a tighter bound than the gen_server
default and treat a timeout as "not available this tick".
Return all active zone pids. For the ticker.
Non-creating lookup. ETS only.
Spawn all zones in grid. Backward compat for small grids.
Register an externally-spawned zone with the manager.
Hint that zone can be unloaded.
Replace a zone that died under a caller holding its pid.
Provide per-coord initial zone_state. Used to thread per-zone state from
GameMod:generate_world/2 (e.g. lua_state for the asobi_lua_world bridge,
or station/planet seeds for sc_game) through to each zone's init. Without
this, zones would all start with empty zone_state and any callback that
needs per-zone setup would silently no-op.
Update the base zone config used when spawning new zones.
Start the zone manager.
Reset idle timer for a zone. Fire-and-forget.
Called by zone on terminate. Cleans up ETS entry.
Functions
-spec ensure_zone(pid() | atom(), {integer(), integer()}) -> {ok, pid(), created | existing} | {error, term()}.
Return existing zone or start a new one. ETS fast path first.
The third element of a successful result tells the caller whether this call
is what brought the zone into existence (created) or whether it was already
running (existing) - callers that need to backfill subscribers whose
interest ring already covered these coords (widgrensit/asobi#275) only need
to act on created.
-spec ensure_zone(pid() | atom(), {integer(), integer()}, timeout()) -> {ok, pid(), created | existing} | {error, term()}.
As ensure_zone/2, with an explicit call timeout. Callers on a hot path
that must not stall on a busy manager (asobi_zone's per-tick crossing
check, widgrensit/asobi#271) pass a tighter bound than the gen_server
default and treat a timeout as "not available this tick".
Return all active zone pids. For the ticker.
Non-creating lookup. ETS only.
-spec handle_call(term(), gen_server:from(), map()) -> {reply, term(), map()}.
Spawn all zones in grid. Backward compat for small grids.
Register an externally-spawned zone with the manager.
Hint that zone can be unloaded.
-spec revive_zone(pid() | atom(), {integer(), integer()}, pid()) -> {ok, pid(), created | existing} | {error, term()}.
Replace a zone that died under a caller holding its pid.
ensure_zone/2 hands out a pid without a lease on it, so a genuinely-idle
zone can still be reaped in the gap between the lookup and the caller proving
it occupied (widgrensit/asobi#283). The caller that notices this cannot just
retry ensure_zone/2: the ETS slot still points at the dead pid until the
manager has processed its DOWN, so the retry would hand back the same
corpse. This waits for that DOWN (the zone's terminate/2 snapshot has
already run by then, so the replacement loads current state) and starts a
fresh zone.
Returns the already-live zone when someone else got there first.
Provide per-coord initial zone_state. Used to thread per-zone state from
GameMod:generate_world/2 (e.g. lua_state for the asobi_lua_world bridge,
or station/planet seeds for sc_game) through to each zone's init. Without
this, zones would all start with empty zone_state and any callback that
needs per-zone setup would silently no-op.
Update the base zone config used when spawning new zones.
-spec start_link(map()) -> gen_server:start_ret().
Start the zone manager.
Reset idle timer for a zone. Fire-and-forget.
Called by zone on terminate. Cleans up ETS entry.