asobi_lua_api (asobi v0.75.1)
View SourceInstalls the game.* Lua API into a Luerl state, giving Lua scripts
access to engine features like economy, leaderboards, notifications,
storage, messaging, spatial queries, and zone spawning.
Called from asobi_lua_match:init/1 and asobi_lua_world:init/1
before the Lua script's init() runs.
Available API
-- IDs
game.id() -- generate UUIDv7
-- Logging
game.log(level, message) -- structured log line ("debug"|"info"|"warning"|"error")
game.log(level, message, meta) -- with a metadata table
-- Messaging
game.broadcast(event, payload) -- broadcast to all match players
-- event: 1-64 chars of [A-Za-z0-9_-],
-- and not an asobi-reserved name
game.send(player_id, message) -- send to specific player
-- Economy
game.economy.grant(player_id, currency, amount, reason)
game.economy.debit(player_id, currency, amount, reason)
game.economy.balance(player_id)
game.economy.purchase(player_id, listing_id)
-- Leaderboards
game.leaderboard.submit(board_id, player_id, score)
game.leaderboard.top(board_id, count)
game.leaderboard.rank(board_id, player_id)
game.leaderboard.around(board_id, player_id, count)
-- Notifications
game.notify(player_id, type, subject, data)
game.notify_many(player_ids, type, subject, data)
-- Key-Value Storage
game.storage.get(collection, key)
game.storage.set(collection, key, value)
game.storage.player_get(player_id, collection, key)
game.storage.player_set(player_id, collection, key, value)
-- Chat
game.chat.send(channel_id, sender_id, content)
-- Spatial queries (operate on entity tables)
game.spatial.query_radius(entities, x, y, radius)
game.spatial.query_radius(entities, x, y, radius, opts)
game.spatial.query_radius(x, y, radius) -- zone-based (requires zone_pid)
game.spatial.query_rect(x1, y1, x2, y2) -- zone-based (requires zone_pid)
game.spatial.nearest(entities, x, y, n)
game.spatial.nearest(entities, x, y, n, opts)
game.spatial.in_range(entity_a, entity_b, range)
game.spatial.distance(entity_a, entity_b)
-- Zone spawning (world mode only, requires zone_pid in context)
game.zone.spawn(template_id, x, y) -- false if template_id is unknown
game.zone.spawn(template_id, x, y, overrides) -- false if template_id is unknown
game.zone.despawn(entity_id)
-- Terrain (world mode only, requires terrain_store_pid in context)
game.terrain.get_chunk(cx, cy) -- get compressed chunk data
game.terrain.preload(coords_list) -- preload chunks asyncResult envelope
The persistence-style calls (economy.*, storage.*, leaderboard.top/rank/around,
terrain.get_chunk, notify) return a wrapped result: { ok = Value } on
success, { error = "reason" } on failure (ok_result/2 / error_result/2 via
wrap_result/2). Read result.ok. The plain calls (broadcast, send,
chat.send, zone.spawn/despawn, leaderboard.submit, spatial.*) return
their value directly. broadcast is the exception on the failure side: an
event name asobi rejects at the socket boundary (empty, over 64 bytes,
outside [A-Za-z0-9_-], or one of asobi's own reserved wire event names such
as state/tick/finished) returns { error = "reason" } rather than
being silently dropped downstream.
Extension namespaces
An installed extension declaring asobi_extension:lua/0 gets its namespace
installed here too, so a game script calls game.quests.progress(...) exactly
as it calls a core function. Four mechanics, each forced by how Luerl behaves:
the namespace table is pre-created (set_table_keys does not auto-vivify),
installation happens in this same PreInstall window (Lua closures capture
_ENV at compile time), the declared effects runs through pick/3 like
core's own, and {M, F, A} is applied fully qualified rather than captured as
a fun. A binding returns {ok, Value} | {error, Binary} and reaches Lua
through the same { ok = ... } / { error = "..." } envelope.