# `Cauldron2D.World`
[🔗](https://github.com/jaman/cauldron/blob/v0.1.3/cauldron_2d/lib/cauldron_2d/world.ex#L1)

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 `{:cauldron_frame, %{tick: n, view: view, events: events}}`. 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.

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 implementing `Cauldron2D.Game`. Required
  * `:game_opts` — passed to its `init/1`. Default `[]`
  * `:state` — a game state to start from instead of calling `init/1`, as
    `snapshot/1` returned it. Default none
  * `:hz` — ticks per second, and the `dt` of a step. Default `50`
  * `:tick` — `:fixed`, stepping on the clock, or `:on_input`. Default `:fixed`
  * `:record` — keep a `Cauldron2D.Replay` of joins, leaves and input. Default `false`
  * `:name` — a GenServer name. Default none

# `player_id`

```elixir
@type player_id() :: term()
```

# `stats`

```elixir
@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.

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `game`

```elixir
@spec game(GenServer.server()) :: module()
```

The game module the world runs.

# `input`

```elixir
@spec input(GenServer.server(), player_id(), Cauldron2D.Input.state()) :: :ok
```

Send player `id`'s current input, applied before the next tick.

# `join`

```elixir
@spec join(GenServer.server(), player_id(), map()) :: :ok | {:error, term()}
```

Add the calling process as player `id`. `{:error, reason}` is the game's refusal.

# `leave`

```elixir
@spec leave(GenServer.server(), player_id()) :: :ok
```

Remove player `id`.

# `pause`

```elixir
@spec pause(GenServer.server()) :: :ok
```

Stop stepping until `resume/1`. Nothing for a world stepping on input.

# `paused?`

```elixir
@spec paused?(GenServer.server()) :: boolean()
```

Whether the world is paused.

# `players`

```elixir
@spec players(GenServer.server()) :: [player_id()]
```

The ids of the players present.

# `replay`

```elixir
@spec replay(GenServer.server()) :: Cauldron2D.Replay.t() | nil
```

The replay recorded so far, or `nil` when the world was not started with `record: true`.

# `resume`

```elixir
@spec resume(GenServer.server()) :: :ok
```

Step again, from now.

# `snapshot`

```elixir
@spec snapshot(GenServer.server()) :: term()
```

The game's current state.

# `start_link`

```elixir
@spec start_link(keyword()) :: GenServer.on_start()
```

Start a world; see the module documentation for the options.

# `stats`

```elixir
@spec stats(GenServer.server()) :: stats()
```

How the world is keeping up; see `t:stats/0`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
