This commit is contained in:
parent
4a5ccc719d
commit
8ae0c08e8d
@ -26,8 +26,7 @@ defmodule Amethyst.Application do
|
|||||||
children = [
|
children = [
|
||||||
{Task.Supervisor, name: Amethyst.ConnectionSupervisor},
|
{Task.Supervisor, name: Amethyst.ConnectionSupervisor},
|
||||||
{Amethyst.Keys, 1024},
|
{Amethyst.Keys, 1024},
|
||||||
{Amethyst.GameRegistry, []},
|
{Amethyst.GameCoordinator, %Amethyst.GameCoordinator.State{games: %{}, gid: 0}},
|
||||||
{Amethyst.GameCoordinator, []},
|
|
||||||
{PartitionSupervisor,
|
{PartitionSupervisor,
|
||||||
child_spec: DynamicSupervisor.child_spec([]),
|
child_spec: DynamicSupervisor.child_spec([]),
|
||||||
name: Amethyst.GameMetaSupervisor
|
name: Amethyst.GameMetaSupervisor
|
||||||
|
@ -41,6 +41,9 @@ defmodule Amethyst.API.Game do
|
|||||||
- 'state_refs' are your references (see `instantiate/1`)
|
- 'state_refs' are your references (see `instantiate/1`)
|
||||||
"""
|
"""
|
||||||
@callback login(from :: pid(), player_cfg :: keyword(), state_refs :: map()) :: :accept | :reject
|
@callback login(from :: pid(), player_cfg :: keyword(), state_refs :: map()) :: :accept | :reject
|
||||||
|
def login(%{:mod => mod, :refs => refs}, player_cfg) do
|
||||||
|
mod.login(self(), player_cfg, refs)
|
||||||
|
end
|
||||||
@doc """
|
@doc """
|
||||||
`player_position/3` is called when a player moves. This function is called with the absolute coordinates
|
`player_position/3` is called when a player moves. This function is called with the absolute coordinates
|
||||||
that the player client expects. TODO: Teleport Player API.
|
that the player client expects. TODO: Teleport Player API.
|
||||||
@ -50,57 +53,15 @@ defmodule Amethyst.API.Game do
|
|||||||
- `state_refs` are your references (see `instantiate/1`)
|
- `state_refs` are your references (see `instantiate/1`)
|
||||||
"""
|
"""
|
||||||
@callback player_position(from :: pid(), {x :: float(), y :: float(), z :: float()}, state_refs :: map()) :: :ok
|
@callback player_position(from :: pid(), {x :: float(), y :: float(), z :: float()}, state_refs :: map()) :: :ok
|
||||||
|
def player_position(%{:mod => mod, :refs => refs}, {x, y, z}) do
|
||||||
|
mod.player_position(self(), {x, y, z}, refs)
|
||||||
|
end
|
||||||
@doc """
|
@doc """
|
||||||
Whether or not this game instance can be joined by a new player. This should include basic logic such as
|
Whether or not this game instance can be joined by a new player. This should include basic logic such as
|
||||||
if joining makes sense, for instance
|
if joining makes sense, for instance if the game is full or if the game has already started.
|
||||||
"""
|
"""
|
||||||
@callback joinable?(state_refs :: map()) :: boolean()
|
@callback joinable?(state_refs :: map()) :: boolean()
|
||||||
|
def joinable?(%{:mod => mod, :refs => refs}) do
|
||||||
def child_spec(mod, refs) do
|
mod.joinable?(refs)
|
||||||
%{
|
|
||||||
id: __MODULE__,
|
|
||||||
start: {__MODULE__, :start_link, [mod, refs]}
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec start(Amethyst.API.Game, term()) :: {:ok, pid}
|
|
||||||
def start(mod, refs) do
|
|
||||||
pid = spawn(fn ->
|
|
||||||
true = refs |> Enum.all?(fn {_key, pid } -> Process.link(pid) end)
|
|
||||||
loop(mod, refs)
|
|
||||||
end)
|
|
||||||
{:ok, pid}
|
|
||||||
end
|
|
||||||
def start_link(mod, refs) do
|
|
||||||
{:ok, pid} = start(mod, refs)
|
|
||||||
Process.link(pid)
|
|
||||||
{:ok, pid}
|
|
||||||
end
|
|
||||||
defp loop(mod, refs) do
|
|
||||||
receive do
|
|
||||||
{:login, caller, cfg} ->
|
|
||||||
Task.Supervisor.start_child(refs[:task_supervisor],
|
|
||||||
fn -> mod.login(caller, cfg, refs) end)
|
|
||||||
{:player_position, caller, pos} ->
|
|
||||||
Task.Supervisor.start_child(refs[:task_supervisor],
|
|
||||||
fn -> mod.player_position(caller, pos, refs) end)
|
|
||||||
end
|
|
||||||
loop(mod, refs)
|
|
||||||
end
|
|
||||||
|
|
||||||
def login(pid, cfg) do
|
|
||||||
send(pid, {:login, self(), cfg})
|
|
||||||
receive do
|
|
||||||
:ok -> :ok
|
|
||||||
:refuse -> :refuse
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec player_position(atom() | pid() | port() | reference() | {atom(), atom()}, {float(), float(), float()}) :: {float(), float(), float()}
|
|
||||||
def player_position(pid, pos) do
|
|
||||||
send(pid, {:player_position, self(), pos})
|
|
||||||
receive do
|
|
||||||
pos -> pos
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -38,7 +38,7 @@ defmodule Amethyst.GameCoordinator do
|
|||||||
which defines callbacks for various events, a map containing pids to the game's state (called references
|
which defines callbacks for various events, a map containing pids to the game's state (called references
|
||||||
or refs) and optional metadata.
|
or refs) and optional metadata.
|
||||||
"""
|
"""
|
||||||
defstruct mod: :none, refs: %{}, opts: []
|
defstruct mod: :none, refs: %{}, opts: [], gid: 0
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec start_link(State) :: {:ok, pid()}
|
@spec start_link(State) :: {:ok, pid()}
|
||||||
@ -87,20 +87,18 @@ defmodule Amethyst.GameCoordinator do
|
|||||||
# TODO: Instantiation can fail (including with an exception), and if it does the entire GameCoordinator goes down
|
# 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.
|
# We should gracefully handle situations where we cannot create a game.
|
||||||
{:ok, refs} = type.instantiate(game_supervisor_pid)
|
{:ok, refs} = type.instantiate(game_supervisor_pid)
|
||||||
refs = refs |> Map.put(:game_supervisor, game_supervisor_pid) |> Map.put(:task_supervisor, task_supervisor_pid)
|
refs = refs |> Map.put(:game_supervisor, game_supervisor_pid) |> Map.put(:task_supervisor, task_supervisor_pid) |> Map.put(:game_coordinator, self())
|
||||||
game = %Game{
|
game = %Game{
|
||||||
mod: type, refs: refs, opts: []
|
mod: type, refs: refs, opts: [], gid: state.gid
|
||||||
}
|
}
|
||||||
games = state.games |> Map.put(state.gid, game)
|
games = state.games |> Map.put(state.gid, game)
|
||||||
{game, %State{gid: state.gid + 1, games: games}}
|
{game, %State{gid: state.gid + 1, games: games}}
|
||||||
end
|
end
|
||||||
|
|
||||||
defp _find(type, state) do
|
defp _find(type, state) do
|
||||||
if length(existing) > 0 do
|
case state.games |> Enum.find(fn {_, game} -> game.mod == type end) do
|
||||||
[{_mod, pid, _} | _] = existing
|
nil -> {nil, state}
|
||||||
{pid, games}
|
{_, game} -> {game, state}
|
||||||
else
|
|
||||||
{nil, games}
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -107,14 +107,7 @@ defmodule Amethyst.Server.Play do
|
|||||||
{:ok, state}
|
{:ok, state}
|
||||||
else
|
else
|
||||||
game = Keyword.fetch!(state, :game)
|
game = Keyword.fetch!(state, :game)
|
||||||
{nx, ny, nz} = Amethyst.API.Game.player_position(game, {x, y, z})
|
{Amethyst.API.Game.player_position(game, {x, y, z}), state}
|
||||||
# If pos is not very close to the position the client wants, synchronize them
|
|
||||||
# TODO: Make a general-purpose distance function
|
|
||||||
dist = :math.sqrt((nx - x)**2 + (ny - y)**2 + (nz - z)**2)
|
|
||||||
if dist > 0.01 do
|
|
||||||
# TODO: Implement synchronization
|
|
||||||
raise "The game wants to resynchronize the player, but I haven't implemented that yet"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
def handle(tuple, _, state) do # TODO: These error cases should be somehow moved into some shared area? Maybe even moved out of the modules themselves
|
def handle(tuple, _, state) do # TODO: These error cases should be somehow moved into some shared area? Maybe even moved out of the modules themselves
|
||||||
|
@ -14,4 +14,10 @@ defmodule Example.Game do
|
|||||||
Logger.info("The refs for this game are #{inspect(refs)}")
|
Logger.info("The refs for this game are #{inspect(refs)}")
|
||||||
:ok
|
:ok
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def player_position(from, {x, y, z}, refs) do
|
||||||
|
Logger.info("Player at #{inspect(from)} moved to #{x}, #{y}, #{z}")
|
||||||
|
:ok
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user