asobi_lua_config (asobi v0.84.0)

View Source

Loads game configuration from Lua files in the game directory.

Supports two modes:

  1. Single mode — a match.lua in the game directory. The script declares its config as globals (match_size, max_players, strategy, bots). The mode name defaults to "default".

  2. Multi-mode — a config.lua that returns a table mapping mode names to script paths:

    return {
        arena = "arena/match.lua",
        ctf   = "ctf/match.lua"
    }

    Each match script declares its own config as globals.

If neither file exists, the loader is a no-op (Erlang OTP projects that configure via sys.config are unaffected).

Match script globals

match_size     = 4                          -- required, positive integer
max_players    = 10                         -- optional, defaults to match_size
strategy       = "fill"                     -- optional, "fill" | "skill_based"
bots           = { script = "bots/ai.lua", min_players = 4 } -- optional; min_players defaults to match_size, enabled defaults to true
game_type      = "world"                    -- optional, "match" (default) or "world"
listed         = true                       -- optional, browsable via match.list / world.list (matches default false, worlds true)
quick_play     = true                       -- optional, reachable via world.find_or_create (default true)
state_strategy = "shared"                   -- optional, "shared" picks asobi_lua_match_shared (encode-once broadcast)
guest_auth     = true                       -- optional, offer anonymous no-account play (needs an operator pepper; ADR 0004)
registration   = "closed"                   -- optional, "open" | "oauth_only" | "closed" (operator sys.config wins)

-- World mode config (large session games, game_type = "world"):
tick_rate               = 50              -- optional, ms per world tick (default 50 = 20 Hz)
grid_size               = 1               -- optional, zones per dimension (default 10)
zone_size               = 1200            -- optional, world units per zone (default 200)
view_radius             = 0               -- optional, zone radius a player subscribes to (default 1)
persistent              = false           -- optional, snapshot zones to DB across restarts
lazy_zones              = true            -- optional, on-demand zone loading
zone_idle_timeout       = 30000           -- optional, ms before idle zone is reaped
max_active_zones        = 10000           -- optional, cap on concurrent zones
spatial_grid_cell_size  = 64              -- optional, cell size for spatial grid indexing
cold_tick_divisor       = 10              -- optional, tick rate divisor for cold (unoccupied) zones
empty_grace_ms          = 60000           -- optional, ms to keep an empty world alive before finishing
player_ttl_ms           = 0               -- optional, 0=remove on disconnect, -1=keep forever, N=grace ms

Setting game_type = "world" routes the script through the asobi_lua_world bridge (zone_tick/2 + handle_input/3 returning entities). Defaults to "match", which uses the asobi_lua_match bridge (tick/1 + wrapped-state callbacks).

guest_auth and registration are read from match.lua in single-mode and from config.lua (the manifest) in multi-mode. guest_auth only declares intent; guest auth is on iff the operator also supplies a >= 32-byte pepper (ADR 0004). registration declares a signup posture for a deployment that states none: it lands in the script layer asobi_registration reads only when the operator's sys.config leaves registration unset, and an unrecognised value is logged and dropped rather than downgrading the posture.

This module reads Lua and nothing else: it hands the config term it derived to asobi_game_config:apply_config/1, which owns the merge with operator config and the order the app-env keys are written in (ADR 0006).

Bot scripts can export a names list that the platform reads after loading:

names = {"Spark", "Blitz", "Volt"}

Summary

Functions

apply_guest_auth(GameDir)

-spec apply_guest_auth(string() | binary()) -> ok.

apply_registration_mode(GameDir)

-spec apply_registration_mode(string() | binary()) -> ok.

maybe_load_game_config()

-spec maybe_load_game_config() -> ok | {error, term()}.

reload_game_modes()

-spec reload_game_modes() -> ok | {error, term()}.