server tables 但我 efm 游戏 join b- 信息 tor
轮到处理桌子进程了。桌子进程抛开消息发送,基本上就是table的转调用。
无谓测试驱动先还是写代码先,反正怎么顺就怎么搞。
- defmodule TableServer do
- use GenServer, restart: :temporary, start: {__MODULE__, :start_link, []}
- def start_link(table) do
- GenServer.start_link(__MODULE__, table, name: register_name(table))
- end
- def init(table) do
- {:ok, table}
- end
- def register_name(%{} = table), do: register_name(table |> SimpleTable.get_id)
- def register_name(id), do: {:via, Registry, {LocalRegistry, {Table, id}}}
- def exist?(table) do
- key = {Table, table |> SimpleTable.get_id}
- case Registry.lookup(LocalRegistry, key) do
- [{_pid, _}] -> true
- [] -> false
- end
- end
- def create(player) do
- table = SimpleTable.init
- |> SimpleTable.set_id(player |> Player.get_id)
- |> SimpleTable.set_creator(player)
- |> SimpleTable.add_seat(player)
- TableSupervisor.start_table(table)
- end
- def join(table, player), do: GenServer.cast(table, {:join, player: player})
- def quit(table, player), do: GenServer.cast(table, {:quit, player: player})
- def dismiss(table, player), do: GenServer.cast(table, {:dismiss, player: player})
- def start(table, player), do: GenServer.cast(table, {:start, player: player})
- def open(table, player), do: GenServer.cast(table, {:open, player: player})
- def makeup(table, player), do: GenServer.cast(table, {:makeup, player: player})
- def handle_cast(request, table) do
- {:ok, table} = inner_handle_cast(request, table)
- {:noreply, table}
- end
- def send_error(_player, _error) do
- end
- def inner_handle_cast({:join, player: player}, table) do
- with {:ok, table} <- table |> SimpleTable.join(player)
- do
- seat = SimpleTable.find_seat(table, player)
- broadcast_join(table, seat)
- else
- {:error, error} ->
- send_error(player, error)
- end
- {:ok, table}
- end
- def inner_handle_cast({:quit, player: player}, table) do
- with {:ok, table} <- table |> SimpleTable.quit(player)
- do
- broadcast_quit(table, player)
- else
- {:error, error} ->
- send_error(player, error)
- end
- {:ok, table}
- end
- def inner_handle_cast({:dismiss, player: player}, table) do
- with {:ok, table} <- table |> SimpleTable.dismiss(player)
- do
- broadcast_dismiss(table)
- else
- {:error, error} ->
- send_error(player, error)
- end
- {:ok, table}
- end
- def inner_handle_cast({:start, player: player}, table) do
- with {:ok, table} <- table |> SimpleTable.start(player)
- do
- broadcast_start(table)
- else
- {:error, error} ->
- send_error(player, error)
- end
- {:ok, table}
- end
- def inner_handle_cast({:open, player: player}, table) do
- with {:ok, table} <- table |> SimpleTable.open(player)
- do
- send_open(table, player)
- else
- {:error, error} ->
- send_error(player, error)
- end
- {:ok, table}
- end
- def inner_handle_cast({:makeup, player: player}, table) do
- with {:ok, table} <- table |> SimpleTable.make_up(player)
- do
- send_makeup(table, player)
- else
- {:error, error} ->
- send_error(player, error)
- end
- {:ok, table}
- end
- def broadcast_join(_table, _seat) do
- end
- def broadcast_quit(_table, _player) do
- end
- def broadcast_dismiss(_table) do
- end
- def broadcast_start(_table) do
- end
- def send_open(_table, _player) do
- end
- def send_makeup(_table, _player) do
- end
- end
虽然table_server 很简单,但我还是花了点时间在上面。
主要在考虑下面的问题:
1. 要不要用exactor 库简化api接口
后来没有用, exactor 还是适合于速错模式用, 而游戏我们通常要try catch,如果要用,需要包装exactor的宏,麻烦。
当然如果把table存到ets里, 就可以比较方便的崩溃恢复, 也许这比较适合用exactor。
2. inner_handle_cast 应该是怎么样的接口才方便修改
想来想去,用 {cmd, keyword_list} 比较方便, 直观且容易修改
3. 消息发送怎么样才方便以及直观
一开始是尝试 broadcast_table, 诱惑是凡是发消息就调用该接口。
但明显感觉有2个缺陷
一个是粒度太大(结果是该函数里比如要有不同分支)
一个无法直观每个操作的具体影响
所以最后改成,需要发送什么,就搞个api发送什么, 这就有broadcast_join broadcast_quit 等等,
感觉就清晰很多,自然很多,并且粒度小了发送的信息也少了。
下回增加相关的测试和代码吧
简单Elixir游戏服设计- 丰富桌子进程
来源: http://www.bubuko.com/infodetail-2354135.html