1. 程式人生 > >簡單Elixir遊戲服設計- 豐富桌子進程

簡單Elixir遊戲服設計- 豐富桌子進程

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.ex

雖然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遊戲服設計- 豐富桌子進程