asobi_presence (asobi v0.84.0)

View Source

Who is reachable, and who counts as online.

Those are two different facts and this module keeps them apart:

  • addressable - the process is a delivery target for send/2, keyed by player id. Player sessions and bots are both addressable.
  • online - a connected human player. Only track/2 records that, and online_count/0 counts exactly those.

Bots (asobi_bot) are addressable but never online. track_bot/2 joins the delivery group and nothing else: a bot does not count toward online_count/0 and does not emit player_online / player_offline presence broadcasts. online_count/0 is the operator-facing concurrency number, and bot fill is itself driven by how few humans are queued, so counting server-spawned bots would both inflate the figure and feed it back into its own input.

Message contract

Everything send/2 delivers arrives at the target process as {asobi_message, message()}. message/0 is the contract between the core servers that produce those terms (asobi_match_server, asobi_world_server, asobi_zone, asobi_matchmaker, the Lua runtime) and the processes that pattern-match them (asobi_ws_handler, asobi_player_session, asobi_bot).

Shared match state is the one shape whose form depends on the recipient: send_match_state/3 hands a session the pre-encoded frame and a bot the same payload as a term. Both are message/0 shapes; see that function.

It is a public type on purpose. send/2 is spec'd with it, so a producer that invents a shape fails dialyzer instead of quietly emitting a term no consumer handles, and a consumer (asobi_bot does this) can spec its own clauses against the same named type rather than an ad-hoc guess.

Summary

Types

event_name()

-type event_name() :: atom() | binary().

message()

-type message() ::
          {match_joined, pid()} |
          {match_left, pid()} |
          {match_state, map()} |
          {match_state_raw, binary()} |
          {match_event, event_name(), map()} |
          {world_joined, pid(), pid() | undefined} |
          {world_zone_changed, pid()} |
          {world_event, event_name(), map()} |
          {zone_delta, non_neg_integer(), [map()]} |
          {zone_delta_raw, binary()} |
          {terrain_chunk, {integer(), integer()}, binary()} |
          {dm_message, map()} |
          {notification, map()} |
          {game_message, term()} |
          {game_message, atom(), term()} |
          {script_error, map()} |
          {script_error, atom(), map()} |
          {extension_event, atom(), binary(), map()}.

Functions

bot_pids(BotId)

-spec bot_pids(binary()) -> [pid()].

The live processes tracked as bot BotId, if any.

disconnect(PlayerId, Reason)

-spec disconnect(binary(), binary()) -> ok.

get_status(PlayerId)

-spec get_status(binary()) -> online | offline.

handle_call(Request, From, State)

-spec handle_call(term(), gen_server:from(), map()) -> {reply, term(), map()}.

handle_cast(Msg, State)

-spec handle_cast(term(), map()) -> {noreply, map()}.

handle_info(Info, State)

-spec handle_info(term(), map()) -> {noreply, map()}.

init/1

-spec init([]) -> {ok, #{}}.

online_count()

-spec online_count() -> non_neg_integer().

revoke_session(PlayerId, Reason)

-spec revoke_session(binary(), binary()) -> ok.

send(PlayerId, Message)

-spec send(binary(), message()) -> ok.

send_match_state(PlayerId, SharedState, PreEncoded)

-spec send_match_state(binary(), map(), binary()) -> ok.

Deliver one tick of shared match state to a roster entry.

Sessions get PreEncoded, the wire frame the caller encoded once for the whole match (ADR 0001). Bots get SharedState, the same payload as a term, because a bot reads the state in Erlang and has no use for a JSON binary: routing it here keeps the one encode per tick and costs a bot no decode.

start_link()

-spec start_link() -> gen_server:start_ret().

track(PlayerId, Pid)

-spec track(binary(), pid()) -> ok.

Track a connected player session: addressable by send/2 and counted by online_count/0.

track_bot(BotId, Pid)

-spec track_bot(binary(), pid()) -> ok.

Track a bot process: addressable by send/2, deliberately not online.

A bot never counts toward online_count/0 and never emits a presence broadcast. See the module docs for why.

untrack(PlayerId)

-spec untrack(binary()) -> ok.

untrack_bot(BotId, Pid)

-spec untrack_bot(binary(), pid()) -> ok.

update(PlayerId, Status)

-spec update(binary(), map()) -> ok.