Some changes to how games are created
Some checks failed
Build & Test / nix-build (push) Failing after 27s

This commit is contained in:
Kodi Craft 2024-08-25 13:17:25 +02:00
parent ec7119251c
commit dc9a2f2b5f
Signed by: kodi
GPG Key ID: 69D9EED60B242822
4 changed files with 36 additions and 26 deletions

View File

@ -27,7 +27,11 @@ defmodule Amethyst.Application do
{Task.Supervisor, name: Amethyst.ConnectionSupervisor}, {Task.Supervisor, name: Amethyst.ConnectionSupervisor},
{Amethyst.Keys, 1024}, {Amethyst.Keys, 1024},
{Amethyst.GameRegistry, []}, {Amethyst.GameRegistry, []},
{Amethyst.GameCoordinator, []} {Amethyst.GameCoordinator, []},
{PartitionSupervisor,
child_spec: DynamicSupervisor.child_spec([]),
name: Amethyst.GameMetaSupervisor
}
] ]
children = case Application.fetch_env!(:amethyst, :port) do children = case Application.fetch_env!(:amethyst, :port) do

View File

@ -19,9 +19,9 @@ defmodule Amethyst.API.Game do
This module includes the interface for defining and registering This module includes the interface for defining and registering
a game with Amethyst. a game with Amethyst.
""" """
@callback instantiate() :: {:ok, new_state :: term} | {:error, reason :: term} @callback instantiate(supervisor :: pid()) :: {:ok, state_refs :: map()} | {:error, reason :: term}
@callback login(from :: pid(), player_cfg :: keyword(), state :: term) :: {:ok, new_state :: term} | {:refuse, new_state :: term} @callback login(from :: pid(), player_cfg :: keyword(), state_refs :: map()) :: :ok
@callback player_position(from :: pid(), {x :: float(), y :: float(), z :: float()}, state :: term) :: {{x :: float(), y :: float(), z :: float()}, state :: term} @callback player_position(from :: pid(), {x :: float(), y :: float(), z :: float()}, state_refs :: map()) :: :ok
defmacro __using__(opts) do defmacro __using__(opts) do
meta = Keyword.get(opts, :meta, []) meta = Keyword.get(opts, :meta, [])
@ -41,27 +41,20 @@ defmodule Amethyst.API.Game do
end end
@spec start(Amethyst.API.Game, term()) :: no_return() @spec start(Amethyst.API.Game, term()) :: no_return()
def start(mod, state) do def start(mod, refs) do
loop(mod, state) true = refs |> Enum.all?(fn {_key, pid } -> Process.link(pid) end)
loop(mod, refs)
end end
defp loop(mod, state) do defp loop(mod, refs) do
receive do receive do
{:login, caller, cfg} -> {:login, caller, cfg} ->
case mod.login(caller, cfg, state) do Task.Supervisor.start_child(refs[:task_supervisor],
{:ok, state} -> fn -> mod.login(caller, cfg, refs) end)
send(caller, :ok)
loop(mod, state)
{:refuse, state} ->
send(caller, :refuse)
loop(mod, state)
end
{:player_position, caller, pos} -> {:player_position, caller, pos} ->
case mod.player_position(caller, pos, state) do Task.Supervisor.start_child(refs[:task_supervisor],
{pos, state} -> fn -> mod.player_position(caller, pos, refs) end)
send(caller, pos)
loop(mod, state)
end
end end
loop(mod, refs)
end end
def login(pid, cfg) do def login(pid, cfg) do

View File

@ -53,8 +53,20 @@ defmodule Amethyst.GameCoordinator do
end end
defp _create(type, games) do defp _create(type, games) do
state = type.instantiate() # Create a DynamicSupervisor for this game
pid = spawn(Amethyst.API.Game, :start, [type, state]) {:ok, game_supervisor_pid} = DynamicSupervisor.start_child(
{:via, PartitionSupervisor, {Amethyst.GameMetaSupervisor, type}},
DynamicSupervisor
)
{:ok, task_supervisor_pid} = DynamicSupervisor.start_child(
game_supervisor_pid,
Task.Supervisor
)
# TODO: Instantiation can fail (including with an exception), and if it does the entire GameCoordinator goes down
# We should gracefully handle situations where we cannot create a game.
{:ok, refs} = type.instantiate(game_supervisor_pid)
refs = refs |> Map.put(:game_supervisor, game_supervisor_pid) |> Map.put(:task_supervisor, task_supervisor_pid)
pid = spawn(Amethyst.API.Game, :start, [type, refs])
games = [{type, pid, []} | games] games = [{type, pid, []} | games]
{pid, games} {pid, games}
end end

View File

@ -3,13 +3,14 @@ defmodule Example.Game do
use Amethyst.API.Game, meta: [default: true] use Amethyst.API.Game, meta: [default: true]
@impl true @impl true
def instantiate() do def instantiate(supervisor) do
{:ok, [:hello]} Logger.info("The supervisor for this game is at #{inspect(supervisor)}")
{:ok, %{}}
end end
@impl true @impl true
def login(from, cfg, state) do def login(from, cfg, _state) do
Logger.info("Player logged in from #{inspect(from)}: #{inspect(cfg)}") Logger.info("Player logged in from #{inspect(from)}: #{inspect(cfg)}")
{:ok, state} :ok
end end
end end