Exemplo n.º 1
0
 public static void OnTcpTransportDetached(Session session)
 {
     Log.Info("TCP transport detached: session_id={0}", session.Id);
     // TCP 연결이 닫혔으나 세션은 유효합니다. 이 세션이 매칭 요청을 했다면
     // 매칭을 취소합니다. 클라이언트는 TCP 연결이 끊어졌을 때 매칭을 다시 시도하게
     // 해야 합니다.
     Event.EventFunction event_fn = new Event.EventFunction(() => {
         MatchmakingHelper.CancelMatchmaking(session);
     });
     Event.Invoke(event_fn, session.Id);
 }
Exemplo n.º 2
0
        public static void OnLogout(
            SessionResponse.ResponseResult error, SessionResponse response, bool caused_by_session_close)
        {
            // 로그아웃 이후 처리를 담당합니다.
            Log.Info("OnLogout: session={0}, result={1}, caused_by={2},, data={3}",
                     response.session.Id, (error == SessionResponse.ResponseResult.OK ? "ok" : "failed"),
                     (caused_by_session_close ? "session close" : "action"),
                     response.data.ToString());

            Event.EventFunction event_fn = new Event.EventFunction(() => {
                MatchmakingHelper.CancelMatchmaking(response.session);

                // 세션 닫힘 이벤트가 아니라면 로그아웃 요청으로 이 콜백을 호출한 경우므로
                // 메시지를 보냅니다.
                if (!caused_by_session_close)
                {
                    SendMyMessage(response.session, kLogoutMessage, response.error_code,
                                  response.error_message, response.data);
                }
            });
            Event.Invoke(event_fn, response.session.Id);
        }
        static void OnMatchCompleted(string account_id,
                                     funapi.Matchmaking.Match match,
                                     funapi.Matchmaking.MatchResult result,
                                     Session session,
                                     SessionResponse.SessionResponseHandler handler)
        {
            //
            // 매치 결과를 받는 콜백 핸들러입니다. 매치를 요청한 각 플레이어를 대상으로
            // 핸들러를 호출합니다.
            // 매치를 정상적으로 성사한 경우: match_id 로 직렬화 한 이벤트에서 실행합니다.
            // 매치 성사에 실패한 경우: 직렬화하지 않은 이벤트에서 실행합니다.
            //
            // 매치메이킹에 참여하는 사람이 많지 않거나 matchmaking_server_wrapper.cs 에서
            // 정의한 매치 조건이 까다로운 경우, 클라이언트가 매치메이킹을 요청하는 시점과
            // 매치가 성사되는 이 시점의 차가 커질 수 있습니다.
            //
            // 따라서 클라이언트는 매치메이킹 요청을 보낸 후 이 핸들러에서 메시지를 보내기
            // 전까지 다른 행동을 할 수 있도록 만들어야 합니다.
            //

            Log.Info("OnMatchCompleted: account_id={0}, result={1}", account_id, result);

            if (result != funapi.Matchmaking.MatchResult.kSuccess)
            {
                // funapi.Matchmaking.Client.MatchResult 결과에 따라 어떻게 처리할 지 결정합니다.
                if (result == funapi.Matchmaking.MatchResult.kError)
                {
                    // 엔진 내부 에러입니다.
                    // 일반적으로 RPC 서비스를 사용할 수 없을 경우 발생합니다.
                    handler(SessionResponse.ResponseResult.FAILED,
                            new SessionResponse(session, 500, "Internal server error.",
                                                new JObject()));
                }
                else if (result == funapi.Matchmaking.MatchResult.kAlreadyRequested)
                {
                    // 이미 이 account_id 로 매치메이킹 요청을 했습니다. 매치 타입이 다르더라도
                    // ID 가 같다면 실패합니다.
                    handler(SessionResponse.ResponseResult.FAILED,
                            new SessionResponse(session, 400, "Already requested.", new JObject()));
                }
                else if (result == funapi.Matchmaking.MatchResult.kTimeout)
                {
                    // 매치메이킹 요청을 지정한 시간 안에 수행하지 못했습니다.
                    // 더 넓은 범위의 매치 재시도 또는 클라이언트에게 단순 재시도를 요구할 수 있습니다.
                    handler(SessionResponse.ResponseResult.FAILED,
                            new SessionResponse(session, 400, "Timed out.", new JObject()));
                }
                else
                {
                    // 아이펀 엔진에서 추후 MatchResult 를 더 추가할 경우를 대비해
                    // 이곳에 로그를 기록합니다.
                    Log.Warning("not supported error: result={0}", result);
                    handler(SessionResponse.ResponseResult.FAILED,
                            new SessionResponse(session, 500, "Unknown error.", new JObject()));
                }
                return;
            }

            // 매치 결과 ID 입니다.
            Guid match_id = match.MatchId;
            // 매치메이킹 서버에서 정의한 JSON 컨텍스트 입니다.
            // 매치메이킹 요청(StartMatchmaking2) 시 인자로 넣는 context 와는 다른
            // context 라는 점에 주의하세요.
            JObject match_context = match.Context;
            // 매치메이킹 요청 시 지정한 매치 타입입니다.
            long match_type = match.MatchType;
            // 이 매치에 참여한 플레이어 정보입니다.
            string player_ss = "[";

            for (int i = 0; i < match.Players.Count; ++i)
            {
                if (i != 0)
                {
                    player_ss += ", ";
                }
                player_ss += String.Format("account_id={0}, user_data={1}",
                                           match.Players[i].Id,
                                           match.Players[i].Context.ToString());
            }
            player_ss += "]";

            Log.Info("Matchmaking succeed: match_id={0}, match_context={1}, match_type={2}, players={3}",
                     match_id, match_context.ToString(), match_type, player_ss);

            // 매치메이킹에 성공했습니다. 매치메이킹 서버(matchmaking_server_wrapper.cc)에서
            // 매치에 성공한 사람들을 모아 데디케이티드 서버 생성을 시작합니다.
            // (CheckMatchRequirements 함수에서 kMatchComplete 를 반환한 후입니다)
            // 이 시점에서는 단순히 히스토리만 초기화하고 메시지는 보내지 않습니다.
            // (데디케이티드 서버 생성 후 최종적으로 성공 메시지를 보냅니다)

            Event.EventFunction event_fn = new Event.EventFunction(() => {
                ClearMatchHistory(session);
            });
            Event.Invoke(event_fn, session.Id);
        }
        // 세션을 정리합니다.
        public static void FreeUser(Session session, Session.EncodingScheme encoding)
        {
            // 유저를 정리하기 위한 Context 를 읽어옵니다.
            string id;
            string opponent_id;

            session.GetFromContext("id", out id);
            session.GetFromContext("opponent", out opponent_id);

            // Session Context 를 초기화 합니다.
            session.Context = new JObject();

            // 로그아웃하고 세션을 종료합니다.
            if (id != string.Empty)
            {
                AccountManager.LogoutCallback logout_cb = (string param_account_id,
                                                           Session param_session,
                                                           bool param_result) => {
                    Log.InfoIf(param_result, "Logged out(local) by session close: id={0}", param_account_id);
                };
                AccountManager.SetLoggedOutAsync(id, logout_cb);
            }

            // 대전 상대가 있는 경우, 상대가 승리한 것으로 처리하고 로비서버로 보냅니다.
            if (opponent_id == string.Empty)
            {
                return;
            }
            Session opponent_session = AccountManager.FindLocalSession(opponent_id);

            if (opponent_session == null)
            {
                return;
            }

            Event.EventFunction update = () => {
                User user          = User.FetchById(id);
                User opponent_user = User.FetchById(opponent_id);

                Event.AssertNoRollback();

                // 편의상 아래 함수에서 ORM 데이터 업데이트 처리도 합니다.
                Leaderboard.OnWin(opponent_user);
                Leaderboard.OnLose(user);

                if (encoding == Session.EncodingScheme.kJsonEncoding)
                {
                    opponent_session.SendMessage("result", Utility.MakeResponse("win"));
                }
                else
                {
                    Log.Assert(encoding == Session.EncodingScheme.kProtobufEncoding);
                    FunMessage        funmsg = new FunMessage();
                    GameResultMessage msg    = new GameResultMessage();
                    msg.result = "win";
                    funmsg.AppendExtension_game_result(msg);
                    opponent_session.SendMessage("result", funmsg);
                }

                Common.Redirect(opponent_session, "lobby");
            };

            Event.Invoke(update);
        }