Skip to content

Commit

Permalink
Convert specific movement events to fit inside generic Events
Browse files Browse the repository at this point in the history
This should reduce the extra DSL required going forward for internal
events that an event router might care about. Preparing for channels
  • Loading branch information
oestrich committed Feb 20, 2020
1 parent b460cec commit 95fc024
Show file tree
Hide file tree
Showing 11 changed files with 287 additions and 306 deletions.
4 changes: 2 additions & 2 deletions example/lib/kantele/events.ex
Expand Up @@ -11,8 +11,8 @@ defmodule Kantele.Events do
end

module(MoveEvent) do
movement_voting(:commit, :commit)
movement_voting(:abort, :abort)
event(Kalevala.Event.Movement.Commit, :commit)
event(Kalevala.Event.Movement.Abort, :abort)
end

module(SayEvent) do
Expand Down
4 changes: 2 additions & 2 deletions example/lib/kantele/events/move_event.ex
Expand Up @@ -4,15 +4,15 @@ defmodule Kantele.MoveEvent do
alias Kantele.CommandView
alias Kantele.MoveView

def commit(conn, event) do
def commit(conn, %{data: event}) do
conn
|> move(:from, event.from, MoveView, "leave", %{})
|> move(:to, event.to, MoveView, "enter", %{})
|> put_character(%{conn.character | room_id: event.to})
|> event("room/look")
end

def abort(conn, event) do
def abort(conn, %{data: event}) do
conn
|> render(MoveView, "fail", event)
|> render(CommandView, "prompt")
Expand Down
60 changes: 2 additions & 58 deletions example/lib/kantele/telemetry.ex
Expand Up @@ -14,71 +14,15 @@ defmodule Kantele.Telemetry do
def init(_arg) do
children = [
{:telemetry_poller, measurements: [], period: 10_000},
{TelemetryMetricsPrometheus, metrics: metrics()},
{Kantele.Telemetry.Logger, []}
{TelemetryMetricsPrometheus, metrics: metrics()}
]

Supervisor.init(children, strategy: :one_for_one)
end

defp metrics() do
[
last_value("vm.memory.total", unit: :byte),
distribution("kalevala.movement.voting.commit.total_time",
unit: {:native, :second},
buckets: [0.000000001, 0.0000001, 0.000001, 0.00001, 0.0001, 0.001, 0.01, 0.1]
)
last_value("vm.memory.total", unit: :byte)
]
end
end

defmodule Kantele.Telemetry.Logger do
@moduledoc """
GenServer to register telemetry events we want to log
"""

use GenServer

require Logger

def start_link(opts) do
GenServer.start_link(__MODULE__, [], opts)
end

def init(_) do
{:ok, %{}, {:continue, :register}}
end

def handle_continue(:register, state) do
events = [
[:kalevala, :movement, :voting, :request],
[:kalevala, :movement, :voting, :commit],
[:kalevala, :movement, :voting, :abort]
]

:telemetry.attach_many(:voting, events, &handle_voting/4, %{})

{:noreply, state}
end

@doc false
def handle_voting([:kalevala, :movement, :voting, :request], event, _metadata, _config) do
Logger.info(
"Character #{event.character} wants to move from #{event.from} to #{event.to}",
event
)
end

def handle_voting([:kalevala, :movement, :voting, :commit], event, _metadata, _config) do
Logger.info("Character #{event.character} is moving from #{event.from} to #{event.to}", event)
end

def handle_voting([:kalevala, :movement, :voting, :abort], event, _metadata, _config) do
Logger.info(
"Character #{event.character} failed moving from #{event.from} to #{event.to} with reason #{
event.reason
}",
event
)
end
end
31 changes: 18 additions & 13 deletions example/lib/kantele/world/room.ex
Expand Up @@ -19,28 +19,33 @@ defmodule Kantele.World.Room do
def movement_request(room, event) do
room.exits
|> Enum.find(fn exit ->
exit.exit_name == event.exit_name
exit.exit_name == event.data.exit_name
end)
|> maybe_vote(room, event)
end

defp maybe_vote(nil, room, event) do
%Kalevala.Event.Movement.Voting{
state: :abort,
character: event.character,
from: room.id,
exit_name: event.exit_name,
reason: :no_exit
%Kalevala.Event{
topic: Kalevala.Event.Movement.Voting,
data: %Kalevala.Event.Movement.Voting{
aborted: true,
character: event.data.character,
from: room.id,
exit_name: event.data.exit_name,
reason: :no_exit
}
}
end

defp maybe_vote(room_exit, room, event) do
%Kalevala.Event.Movement.Voting{
state: :request,
character: event.character,
from: room.id,
to: room_exit.end_room_id,
exit_name: room_exit.exit_name
%Kalevala.Event{
topic: Kalevala.Event.Movement.Voting,
data: %Kalevala.Event.Movement.Voting{
character: event.data.character,
from: room.id,
to: room_exit.end_room_id,
exit_name: room_exit.exit_name
}
}
end

Expand Down
22 changes: 14 additions & 8 deletions lib/kalevala/conn.ex
Expand Up @@ -194,9 +194,12 @@ defmodule Kalevala.Conn do
Request the room to move via the exit
"""
def request_movement(conn, exit_name) do
event = %Kalevala.Event.Movement.Request{
character: Private.character(conn),
exit_name: exit_name
event = %Kalevala.Event{
topic: Kalevala.Event.Movement.Request,
data: %Kalevala.Event.Movement.Request{
character: Private.character(conn),
exit_name: exit_name
}
}

event = Kalevala.Event.set_start_time(event)
Expand All @@ -211,11 +214,14 @@ defmodule Kalevala.Conn do
assigns = merge_assigns(conn, assigns)
data = view.render(template, assigns)

event = %Kalevala.Event.Movement{
character: Private.character(conn),
direction: direction,
reason: data,
room_id: room_id
event = %Kalevala.Event{
topic: Kalevala.Event.Movement,
data: %Kalevala.Event.Movement{
character: Private.character(conn),
direction: direction,
reason: data,
room_id: room_id
}
}

Map.put(conn, :events, conn.events ++ [event])
Expand Down
145 changes: 1 addition & 144 deletions lib/kalevala/event.ex
Expand Up @@ -6,149 +6,6 @@ defmodule Kalevala.Event.Metadata do
defstruct [:start_time, :end_time]
end

defmodule Kalevala.Event.Movement do
@moduledoc """
An event to move from one room to another
"""

defstruct [:character, :direction, :reason, :room_id, metadata: %Kalevala.Event.Metadata{}]

@typedoc """
A movement event
- `character` is the character performing the movement
- `direction` is one of two options, `:to` or `:from`, depending if the character
is moving `:to` the room, or moving `:from` the room
- `reason` is what will be sent to other characters in the room and displayed (to players)
- `room_id` is the room the event is intended for
"""
@type t() :: %__MODULE__{}
end

defmodule Kalevala.Event.Movement.Voting do
@moduledoc """
A voting event tracks the state of a character wishing to change rooms
"""

defstruct [
:state,
:character,
:to,
:from,
:exit_name,
:reason,
metadata: %Kalevala.Event.Metadata{}
]

@typedoc """
An event to allow for rooms to abort or commit the character moving.
Each room has a chance to reject movement
- `state` is an enum, one of the following atoms: `:request`, `:commit`, or `:abort`
- `character` is the character performing the action
- `to` is the room the character is going towards
- `from` is the room the character is going away from
- `exit_name` is the name of the exit_name that the player is using
- `reason` is an atom such as `:no_exit` for why the movement is aborted
"""
@type t() :: %__MODULE__{}
end

defmodule Kalevala.Event.Movement.Request do
@moduledoc """
Character requesting to move from their current room in a exit_name
A move request transitions through several stages before commiting or aborting.
The character requests the room to move in a exit_name.
```
%Move.Request{
character: character,
exit_name: "north"
}
```
The room process sends a voting event to the Zone after determining that there is
a valid exit in this exit_name.
```
%Move.Voting{
state: :request,
character: character,
from: start_room_id,
to: end_room_id,
exit_name: "north"
}
```
The zone then asks the `to` and `from` room if they are OK with the character moving. Each
room will be `GenServer.call`ed to block and keep this synchronous. The room `movement/2`
callback will be called for each room, so they can vote on the movement.
`commit` - After both room's agree that the player can move, the zone sends this event to
the character.
```
%Move.Voting{
state: :commit,
character: character,
from: start_room_id,
to: end_room_id,
exit_name: "north"
}
```
`abort` - If either room rejects the movement, the zone will respond with an abort.
```
%Move.Voting{
state: :abort,
character: character,
from: start_room_id,
to: end_room_id,
exit_name: "north",
reason: :door_locked
}
%Move.Voting{
state: :abort,
character: character,
from: start_room_id,
exit_name: "north",
reason: :no_exit
}
```
On a commit, the player leaves the old room, and enters the new one.
```
%Move{
character: character,
direction: :to,
reason: "Player enters from the south."
}
%Move{
character: character,
direction: :from,
reason: "Player leaves to the north."
}
```
"""

defstruct [:character, :exit_name, metadata: %Kalevala.Event.Metadata{}]

@typedoc """
Signal that a character wishes to move to another location
- `character` is the character moving
- `exit` is the exit_name of the exit the player wants to move
"""
@type t() :: %__MODULE__{}
end

defmodule Kalevala.Event do
@moduledoc """
An internal event
Expand All @@ -162,7 +19,7 @@ defmodule Kalevala.Event do

@type topic() :: String.t()

defstruct [:from_pid, :topic, :data]
defstruct [:from_pid, :topic, :data, metadata: %__MODULE__.Metadata{}]

defmacro __using__(_opts) do
quote do
Expand Down

0 comments on commit 95fc024

Please sign in to comment.