123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235 |
- -module(game_session).
- -behaviour(gen_server).
- -include_lib("server/include/requests.hrl").
- -include_lib("server/include/settings.hrl").
- -compile(export_all).
- -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
- -record(state, { user = undefined, rpc, rpc_mon, games = [] }).
- -record(participation, {
- game_id :: 'GameId'(),
- reg_num :: integer(),
- rel_module :: atom(),
- rel_pid :: pid(), %% relay, which handles communication gameman maps game_id onto pid
- tab_module :: atom(),
- tab_pid :: pid(),
- ref :: any(), %% monitor reference to relay
- role = viewer :: atom() %% [viewer, player, ghost]
- }).
- start(RPC) when is_pid(RPC) -> gen_server:start(?MODULE, [RPC], []).
- start_link(RPC) when is_pid(RPC) -> gen_server:start_link(?MODULE, [RPC], []).
- bot_session_attach(Pid, UserInfo) -> gen_server:cast(Pid, {bot_session_attach, UserInfo}).
- process_request(Pid, Msg) -> gen_server:call(Pid, {client_request, Msg}).
- process_request(Pid, Source, Msg) -> gen_server:call(Pid, {client_request, Msg}).
- send_message_to_player(Pid, Message) -> Pid ! {server,Message}, ok.
- init([RPC]) -> MonRef = erlang:monitor(process, RPC),
- {ok, #state{rpc = RPC, rpc_mon = MonRef}}.
- handle_call({client_request, Request}, From, State) -> handle_client_request(Request, From, State);
- handle_call(Request, From, State) ->
- gas:info(?MODULE,"Unrecognized call: ~p from ~p", [Request,From]),
- {stop, {unknown_call, From, Request}, State}.
- handle_cast({bot_session_attach, UserInfo}, State = #state{user = undefined}) ->
- {noreply, State#state{user = UserInfo}};
- handle_cast(Msg, State) ->
- gas:info(?MODULE,"Unrecognized cast: ~p", [Msg]),
- {stop, {error, {unknown_cast, Msg}}, State}.
- handle_info({relay_event, SubscrId, RelayMsg}, State) ->
- handle_relay_message(RelayMsg, SubscrId, State);
- handle_info({relay_kick, SubscrId, Reason}, State) ->
- gas:info(?MODULE,"Recived a kick notification from the table: ~p", [Reason]),
- handle_relay_kick(Reason, SubscrId, State);
- handle_info({'DOWN', MonitorRef, _Type, _Object, _Info} = Msg, State = #state{rpc_mon = MonitorRef}) ->
- gas:info(?MODULE, "connection closed, shutting down session:~p", [Msg]),
- {stop, normal, State};
- handle_info({'DOWN', OtherRef, process, _Object, Info} = _Msg, #state{games = Games, rpc = RPC} = State) ->
- case lists:keyfind(OtherRef, #participation.ref, Games) of
- #participation{} ->
- gas:info(?MODULE,"The table is down: ~p", [Info]),
- gas:info(?MODULE,"Closing the client and sutting down the session.", []),
- send_message_to_player(RPC,
- #disconnect{reason_id = <<"tableDown">>,
- reason = <<"The table you are playing on is unexpectedly down.">>}),
- {stop, table_down, State};
- _ -> {noreply, State} end;
- handle_info(Info, State=#state{rpc=RPC}) ->
- gas:info(?MODULE,"Unrecognized info: ~p", [Info]),
- {noreply, State}.
- terminate(Reason, #state{rpc=RPC}) ->
- gas:info(?MODULE,"Terminating session: ~p", [Reason]),
- ok.
- code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
- %% Register User
- register_user_by_module(RPC,User,GameId,#state{games=Games} = State) ->
- UserId = User#'PlayerInfo'.id,
- case game:get_relay_mod_pid(GameId) of
- {FLMod, FLPid} ->
- gas:info(?MODULE,"Found the game: ~p by module ~p Trying to register...",[FLPid,FLMod]),
- case FLMod:reg(FLPid, User) of
- {ok, {RegNum, {RMod, RPid}, {TMod, TPid}}} ->
- gas:info(?MODULE,"join to game relay: ~p",[{RMod, RPid}]),
- {ok, _SubscrId} = RMod:subscribe(RPid, self(), UserId, RegNum),
- Ref = erlang:monitor(process, RPid),
- Part = #participation{
- ref = Ref, game_id = GameId, reg_num = RegNum,
- rel_module = RMod, rel_pid = RPid,
- tab_module = TMod, tab_pid = TPid, role = player},
- NewGames = game:plist_setkey(GameId,#participation.game_id,Games,Part),
- {reply, ok, State#state{games = NewGames}};
- {error, finished} ->
- gas:info(?MODULE,"The game is finished: ~p.",[GameId]),
- ok = send_message_to_player(RPC, #disconnect{reason_id = <<"gameFinished">>, reason = null}),
- {reply, {error, finished}, State};
- {error, out} ->
- gas:info(?MODULE,"Out of the game: ~p.",[GameId]),
- ok = send_message_to_player(RPC, #disconnect{reason_id = <<"disconnected">>,reason = null}),
- {reply, {error, out}, State};
- {error, not_allowed} ->
- gas:error(?MODULE,"Not allowed to connect: ~p.",[GameId]),
- ok = send_message_to_player(RPC, #disconnect{reason_id = <<"notAllowed">>,reason = null}),
- {reply, {error, not_allowed}, State};
- UnknownError ->
- gas:error(?MODULE,"Unknown Registration Error: ~p.",[GameId]),
- ok = send_message_to_player(RPC, #disconnect{reason_id = term_to_binary(UnknownError),reason = null}),
- {reply, UnknownError, State}
- end;
- undefined ->
- gas:error(?MODULE,"Game not found: ~p.",[GameId]),
- ok = send_message_to_player(RPC, #disconnect{reason_id = <<"notExists">>, reason = null}),
- {reply, {error, not_exists}, State}
- end.
- %%===================================================================
- handle_client_request(#session_attach{token = Token}, _From, #state{user = undefined} = State) ->
- gas:info(?MODULE,"Checking session token: ~p", [Token]),
- case auth_server:get_user_info(wf:to_binary(Token)) of
- false ->
- gas:error(?MODULE,"failed session attach: ~p", [Token]),
- {stop, normal, {error, invalid_token}, State};
- UserInfo ->
- gas:info(?MODULE,"successfull session attach. Your user info: ~p", [UserInfo]),
- {reply, UserInfo, State#state{user = UserInfo}} end;
- handle_client_request(_, _From, #state{user = undefined} = State) ->
- gas:info(?MODULE,"Unknown session call", []),
- {reply, {error, do_session_attach_first}, State};
- handle_client_request(#logout{}, _From, State) ->
- gas:info(?MODULE,"Logout", []),
- {stop, normal, ok, State};
- handle_client_request(#stats_action{player_id = PlayerId, game_type = GameModule}, _From, #state{rpc = RPC} = State) ->
- Res = game:get_player_info(GameModule, PlayerId),
- gas:info(?MODULE,"Get player stats: ~p", [Res]),
- send_message_to_player(RPC, Res),
- {reply, Res, State};
- handle_client_request(#chat{game = GameId, who = DisplayName, message = Msg0}, _From,
- #state{user = User, games = Games} = State) ->
- gas:info(?MODULE,"Chat Message ~n ~p", [Msg0]),
- Msg = #chat_event{game = GameId, message = Msg0, who = DisplayName },
- Participation = get_relay(GameId, Games),
- Res = case Participation of
- false ->
- {error, chat_not_registered};
- #participation{rel_pid = Srv, rel_module = RMod} ->
- RMod:publish(Srv, Msg)
- end,
- {reply, Res, State};
- handle_client_request(#join_game{game = GameId}, _From,
- #state{user = User, rpc = RPC, games = Games} = State) ->
- UserId = User#'PlayerInfo'.id,
- gas:info(?MODULE,"Join game ~p user ~p from ~p", [GameId, UserId,_From]),
- case get_relay(GameId, Games) of
- #participation{} -> {reply, {error, already_joined}, State};
- false -> register_user_by_module(RPC,User,GameId,State) end;
- handle_client_request(#game_action{game = GameId} = Msg, _From, State) ->
- gas:info(?MODULE,"Game action ~p", [{GameId,Msg,_From}]),
- Participation = get_relay(GameId, State#state.games),
- case Participation of
- false ->
- {reply, {error, game_not_found}, State};
- #participation{reg_num = RegNum, tab_pid = TPid, tab_module = TMod} ->
- UId = (State#state.user)#'PlayerInfo'.id,
- gas:info(?MODULE,"PLAYER ~p MOVES ~p in GAME ~p",[UId,Msg,GameId]),
- {reply, TMod:submit(TPid, RegNum, Msg), State}
- end;
- handle_client_request(#pause_game{game = GameId, action = Action}, _From, State) ->
- Participation = get_relay(GameId, State#state.games),
- gas:info(?MODULE,"Pause game: ~p, user: ~p games: ~p",
- [GameId, State#state.user, State#state.games]),
- case Participation of
- false ->
- gas:info(?MODULE,"A", []),
- {reply, {error, game_not_found}, State};
- #participation{reg_num = RegNum, tab_pid = TPid, tab_module = TMod} ->
- Signal = case Action of
- pause -> pause_game;
- resume -> resume_game
- end,
- Res = TMod:signal(TPid, RegNum, {Signal, self()}),
- gas:info(?MODULE,"B. Res: ~p", [Res]),
- {reply, Res, State}
- end;
- handle_client_request(Request, _From, State=#state{rpc=RPC}) ->
- gas:info(?MODULE,"unrecognized client request: ~p", [Request]),
- {stop, {unknown_client_request, Request}, State}.
- %%===================================================================
- handle_relay_message(Msg, _SubscrId, #state{rpc = RPC} = State) ->
- try send_message_to_player(RPC, Msg) of
- ok -> {noreply, State};
- tcp_closed -> {stop, normal, State};
- E -> {stop, normal, State}
- catch exit:{normal, {gen_server,call, [RPC, {server, _}]}} -> {stop, normal, State};
- exit:{noproc, {gen_server,call, [RPC, {server, _}]}} -> {stop, normal, State};
- E:R -> {stop, normal, State} end.
- %%===================================================================
- %% The notification from the current table to rejoin to the game
- %% because the user for example was moved to another table.
- handle_relay_kick({rejoin, GameId}, _SubscrId,
- #state{user = User, games = Games, rpc = RPC} = State) ->
- gas:info(?MODULE,"Rejoin request from relay. GameId ~p User ~p",[GameId,User#'PlayerInfo'.id]),
- register_user_by_module(RPC,User,GameId,State);
- handle_relay_kick(Reason, _SubscrId, #state{rpc = RPC} = State) ->
- {ReasonId, ReasonText} =
- case Reason of
- table_closed -> {<<"tableClosed">>, null};
- table_down -> {null, <<"The table was closed unexpectedly.">>};
- game_over -> {null, <<"The game is over.">>};
- _ -> {<<"kicked">>, null}
- end,
- send_message_to_player(RPC, #disconnect{reason_id = ReasonId, reason = ReasonText}),
- {stop, normal, State}.
- %%===================================================================
- get_relay(GameId, GameList) ->
- lists:keyfind(GameId, #participation.game_id, GameList).
|