簡單Elixir遊戲服設計- 豐富桌子進程
阿新 • • 發佈:2017-10-16
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 deftable_server.exinit(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) enddef 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遊戲服設計- 豐富桌子進程