Runs a Cauldron2D.Game at a fixed tick and keeps its players supplied with views.
{:ok, world} = Cauldron2D.World.start_link(game: MyGame, game_opts: [seed: 1], hz: 50)Players join from their own processes with Cauldron2D.Player.join/3; each tick the
world applies the input they sent, steps the game once per due step, and sends every
player whose frame is due {:cauldron_frame, %{tick: n, view: view, events: events}}
— every tick, or as often as the player asked (join/4's :frames, frames/3),
the view built only for those frames. A player whose
process exits is removed. Every join and leave is told to the subscribers of
Cauldron2D.World.Presence, and each tick's events to those of
Cauldron2D.World.Events. stats/1 says how the world is keeping up.
The next tick is timed only once the last has run, for when the next step falls due,
so the world's mailbox never holds more than one tick: input sent while a slow tick
runs is applied before the next step, however far the world falls behind. Steps
more than Cauldron2D.Loop's :max_steps behind are dropped, not owed.
A world started with tick: :on_input has no clock: it runs one step, with dt of
1 / hz, each time a player's input arrives, and sends views after it. That is the
world for a turn-based game. pause/1 stops a clocked world stepping until
resume/1; time paused is not owed afterwards, and input sent meanwhile is applied
on resume.
Options
:game— the module implementingCauldron2D.Game. Required:game_opts— passed to itsinit/1. Default[]:state— a game state to start from instead of callinginit/1, assnapshot/1returned it. Default none:hz— ticks per second, and thedtof a step. Default50:tick—:fixed, stepping on the clock, or:on_input. Default:fixed:record— keep aCauldron2D.Replayof joins, leaves and input. Defaultfalse:name— a GenServer name. Default none
Summary
Types
How the world is keeping up: the players present, the ticks a second it is set to,
the steps run so far, and over the last 256 ticks that ran a step — how many they
were, the microseconds a tick took (stepping and sending every view) as a mean, a
95th percentile and the longest, and behind, how many of them had more than one
step due.
Functions
Returns a specification to start this module under a supervisor.
Change how often player id is sent frames, as join/4's :frames takes it.
The game module the world runs.
Send player id's current input, applied before the next tick.
Add the calling process as player id. {:error, :taken} when another process plays
as id; any other {:error, reason} is the game's refusal.
Remove player id.
Stop stepping until resume/1. Nothing for a world stepping on input.
Whether the world is paused.
The ids of the players present.
The replay recorded so far, or nil when the world was not started with record: true.
Step again, from now.
The game's current state.
Start a world; see the module documentation for the options.
How the world is keeping up; see stats/0.
Types
@type player_id() :: term()
@type stats() :: %{ players: non_neg_integer(), hz: number(), steps: non_neg_integer(), ticks: non_neg_integer(), tick_us: %{ mean: non_neg_integer(), p95: non_neg_integer(), max: non_neg_integer() }, behind: non_neg_integer() }
How the world is keeping up: the players present, the ticks a second it is set to,
the steps run so far, and over the last 256 ticks that ran a step — how many they
were, the microseconds a tick took (stepping and sending every view) as a mean, a
95th percentile and the longest, and behind, how many of them had more than one
step due.
Functions
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec frames(GenServer.server(), player_id(), boolean() | number()) :: :ok
Change how often player id is sent frames, as join/4's :frames takes it.
@spec game(GenServer.server()) :: module()
The game module the world runs.
@spec input(GenServer.server(), player_id(), Cauldron2D.Input.state()) :: :ok
Send player id's current input, applied before the next tick.
@spec join(GenServer.server(), player_id(), map(), keyword()) :: :ok | {:error, term()}
Add the calling process as player id. {:error, :taken} when another process plays
as id; any other {:error, reason} is the game's refusal.
:frames is how often the player is sent a frame: true (default) after every tick
that steps, a number for that many frames a second at most, or false for none — a
second seat played from a process that already receives frames as another player. A
frame carries the events of every step since the player's last frame. :timeout is how
many milliseconds the world is given to take the player in, default 10_000.
@spec leave(GenServer.server(), player_id()) :: :ok
Remove player id.
@spec pause(GenServer.server()) :: :ok
Stop stepping until resume/1. Nothing for a world stepping on input.
@spec paused?(GenServer.server()) :: boolean()
Whether the world is paused.
@spec players(GenServer.server()) :: [player_id()]
The ids of the players present.
@spec replay(GenServer.server()) :: Cauldron2D.Replay.t() | nil
The replay recorded so far, or nil when the world was not started with record: true.
@spec resume(GenServer.server()) :: :ok
Step again, from now.
@spec snapshot(GenServer.server()) :: term()
The game's current state.
@spec start_link(keyword()) :: GenServer.on_start()
Start a world; see the module documentation for the options.
@spec stats(GenServer.server()) :: stats()
How the world is keeping up; see stats/0.