View Source Kalevala.Character.Controller behaviour (kalevala v0.1.0)

A Kalevala.Character.Controller is the largest building block of handling texting. When starting the foreman, an initial controller is given. This controller is initialized and used from then on. The callbacks required will be called at the appropriate time with a new Conn.

Controllers act as a simple state machine, only allowing transitioning to the next one you set in the Conn. For instance, you can contain all login logic in a LoginController, and handle game commands in its own controller, any paging can be handled in a PagerController which can suppress any outgoing text to prevent scrolling while reading, etc.

example-controller

Example Controller

  defmodule Kantele.Character.LoginController do
    use Kalevala.Character.Controller

    # ... code 
    
    @impl true
    def init(conn) do
      conn
      |> put_session(:login_state, :username)
      |> render(LoginView, "welcome")
      |> prompt(LoginView, "name")
    end

    @impl true
    def recv_event(conn, event) do
      case event.topic do
        "Login" ->
          conn
          |> process_username(event.data["username"])
          |> process_password(event.data["password"])

        _ ->
          conn
      end
    end

    @impl true
    def recv(conn, ""), do: conn

    def recv(conn, data) do
      data = String.trim(data)

      case get_session(conn, :login_state) do
        :username ->
          process_username(conn, data)

        :password ->
          process_password(conn, data)

        :registration ->
          process_registration(conn, data)
      end
    end

    defp process_username(conn, username) do
      case username do
        "" ->
          prompt(conn, LoginView, "name")

        <<4>> ->
          conn
          |> prompt(QuitView, "goodbye")
          |> halt()

        "quit" ->
          conn
          |> prompt(QuitView, "goodbye")
          |> halt()

        username ->
          case Accounts.exists?(username) do
            true ->
              conn
              |> put_session(:login_state, :password)
              |> put_session(:username, username)
              |> send_option(:echo, true)
              |> prompt(LoginView, "password")

            false ->
              conn
              |> put_session(:login_state, :registration)
              |> put_session(:username, username)
              |> prompt(LoginView, "check-registration")
          end
      end
    end

    # ... code ...
  end

managing-state-assigns-session-and-flash

Managing State (assigns, session, and flash)

Controller state is managed in one of three different ways, session, assigns, and flash. These states are made avaiable to the Views which can utilize them as variables as needed.

session

Session

The session maintains state for the lifetime of the player connection. Session state can be set using put_session/3 and variables can be retrieved using get_session/2.

flash

Flash

The flash maintains state for the duration of a player's interaction with a single controller. Switching between controllers will cause the flash to be reset.

assings

Assings

Assigns are temporary storage that allow the setting of variables to be made available to Views

prompts-and-render

Prompts and Render

A prompt is text that is sent followed by a newline character. The above code prompt(LoginView, "check-registration") will render the the "check-registration" prompt of the LoginView followed by a newline.

Render on the other outputs the text but is not followed by a newline. That means contiguous calls to render will append the output to the same line as the previous.

switching-controllers

Switching Controllers

Switching controllers is done by calling the Kalevala.Character.Conn.put_controller/2 function. This will immediately switch to the provided controller and call it's init/1 function.

Link to this section Summary

Callbacks

Called when a Kalevala.Character.Event.Display is sent to the foreman process

Called when a Kalevala.Character.Event is sent to the foreman process

Called when the controller is first switched to

Called when text is received from the player

Called when the connection receives an event (e.g. incoming GMCP)

Functions

Marks the module as a controller and imports controller functions

Link to this section Callbacks

Called when a Kalevala.Character.Event.Display is sent to the foreman process

Called when a Kalevala.Character.Event is sent to the foreman process

Called when the controller is first switched to

Called when text is received from the player

@callback recv_event(Kalevala.Character.Conn.t(), any()) :: Kalevala.Character.Conn.t()

Called when the connection receives an event (e.g. incoming GMCP)

Link to this section Functions

Link to this macro

__using__(opts)

View Source (macro)

Marks the module as a controller and imports controller functions