简单Elixir游戏服设计- 丰富桌子进程

Posted damnit

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了简单Elixir游戏服设计- 丰富桌子进程相关的知识,希望对你有一定的参考价值。

轮到处理桌子进程了。桌子进程抛开消息发送,基本上就是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游戏服设计- 丰富桌子进程的主要内容,如果未能解决你的问题,请参考以下文章

简单Elixir游戏服设计-测试驱动?

简单Elixir游戏服设计- 游戏玩法介绍

Elixir游戏服设计六

简单Elixir游戏服设计-call和测试不舒服的地方

简单Elixir游戏服设计-完善测试和代码改进

简单Elixir游戏服设计-玩法simple_poker