Cauldron2D.World.Lockstep (Cauldron2D v0.2.6)

Copy Markdown View Source

How a Cauldron2D.World on one machine keeps a world on another in step with it.

The host keeps each join, leave and input it applies, in order (logged/2), and after each tick sends every follower {:cauldron_steps, host, base, actions, due, check} (flushed/3): the actions it applied since the last, the steps it then ran (due) from step base, and every 60 steps {step, checksum} of the state the steps left (Cauldron2D.Game.checksum/1). A follower applies the same actions to its own state and runs the same steps (followed/2), draining the game's events after each and keeping them in drained for its next frames. A player of the follower's own is ready once its join comes back from the host, and is sent frames from then on. One that finds itself at another step than base, or whose checksum differs, takes the host's state again (resynced/1).

A follower starts from start/1 of the host: the game's Cauldron2D.Game.export/1 of the state, the step and the tick rate. Its state is Cauldron2D.Game.restore/1 of it.

Summary

Functions

{step, checksum} of the state when due steps from base passed a checking step, else nil; nil while world has no followers.

world after sending its followers what it applied and the due steps it ran from step base, with check/3 as the steps left the state.

world, a follower, after the host's {base, actions, due, check} and every further one already waiting in its mailbox. Returns {world, stepped?}.

world keeping action for its followers; nothing kept while it has none.

world, a follower, at the host's state and step as they are now.

What a follower of world starts from, once what world applied is sent to those following it already.

world, a follower, at the step and state of start.

Types

action()

@type action() :: {:join, term(), map()} | {:leave, term()} | {:input, term(), term()}

start()

@type start() :: %{state: term(), steps: non_neg_integer(), hz: number()}

Functions

check(world, base, due)

@spec check(map(), non_neg_integer(), non_neg_integer()) ::
  {non_neg_integer(), term()} | nil

{step, checksum} of the state when due steps from base passed a checking step, else nil; nil while world has no followers.

flushed(world, base, due, check)

@spec flushed(map(), non_neg_integer(), non_neg_integer(), tuple() | nil) :: map()

world after sending its followers what it applied and the due steps it ran from step base, with check/3 as the steps left the state.

followed(world, steps)

@spec followed(map(), tuple()) :: {map(), boolean()}

world, a follower, after the host's {base, actions, due, check} and every further one already waiting in its mailbox. Returns {world, stepped?}.

logged(world, action)

@spec logged(map(), action()) :: map()

world keeping action for its followers; nothing kept while it has none.

resynced(world)

@spec resynced(map()) :: map()

world, a follower, at the host's state and step as they are now.

start(world)

@spec start(map()) :: {map(), start()}

What a follower of world starts from, once what world applied is sent to those following it already.

started(world, map)

@spec started(map(), start()) :: map()

world, a follower, at the step and state of start.