public static void GetAndSendRankTop8(Session session, Session.EncodingScheme encoding, bool single = false)
        {
            funapi.Leaderboard.QueryRequest request =
                new funapi.Leaderboard.QueryRequest(
                    single ? kSingleLeaderboardId : kLeaderboardId, funapi.Leaderboard.Timespan.kAllTime,
                    new funapi.Leaderboard.Range(funapi.Leaderboard.RangeType.kFromTop, 0, 7));

            funapi.Leaderboard.GetLeaderboard(request, (_1, _2, _3) => { OnGetRankTop8(_1, _2, _3, session, encoding, single); });
        }
Example #2
0
        private static void OnFacebookAuthenticated(
            FacebookAuthentication.AuthenticationRequest param_request,
            FacebookAuthentication.AuthenticationResponse param_response,
            bool param_error, Session session, string account_id, Session.EncodingScheme encoding)
        {
            if (param_error)
            {
                // 인증에 오류가 있습니다. 장애 오류입니다.
                Log.Error("Failed to authenticate. Facebook authentication error: id={0}", account_id);
                if (encoding == Session.EncodingScheme.kJsonEncoding)
                {
                    session.SendMessage("login", Utility.MakeResponse("nop", "facebook authentication error"),
                                        Session.Encryption.kDefault);
                }
                else
                {
                    Log.Assert(encoding == Session.EncodingScheme.kProtobufEncoding);
                    FunMessage      funmsg = new FunMessage();
                    LobbyLoginReply reply  = new LobbyLoginReply();
                    reply.result = "nop";
                    reply.msg    = "facebook authentication error";
                    funmsg.AppendExtension_lobby_login_repl(reply);
                    session.SendMessage("login", funmsg);
                }
                return;
            }

            if (!param_response.Success)
            {
                // 인증에 실패했습니다. 올바르지 않은 access token 입니다.
                Log.Info("Failed to authenticate. Wrong Facebook access token: id={0}", account_id);
                if (encoding == Session.EncodingScheme.kJsonEncoding)
                {
                    session.SendMessage("login",
                                        Utility.MakeResponse("nop", "facebook authentication fail: " + param_response.Error.Message),
                                        Session.Encryption.kDefault);
                }
                else
                {
                    Log.Assert(encoding == Session.EncodingScheme.kProtobufEncoding);
                    FunMessage      funmsg = new FunMessage();
                    LobbyLoginReply reply  = new LobbyLoginReply();
                    reply.result = "nop";
                    reply.msg    = "facebook authentication fail: " + param_response.Error.Message;
                    funmsg.AppendExtension_lobby_login_repl(reply);
                    session.SendMessage("login", funmsg);
                }
                return;
            }

            // 인증에 성공했습니다.
            Log.Info("Succeed to authenticate facebook account: id={0}", account_id);

            // 이어서 로그인 처리를 진행합니다.
            AccountManager.CheckAndSetLoggedInAsync(account_id, session, (_1, _2, _3) => { OnLogin_Completed(_1, _2, _3, encoding); });
        }
        // Websocket 연결이 끊기면 불립니다.
        public static void OnWebSocketDisconnected(Session session, Session.EncodingScheme encoding)
        {
            string id = null;

            if (session.GetFromContext("id", out id))
            {
                Log.Info("Websocket disconnected: id={0}", id);
            }
            // 세션을 초기화 합니다.
            FreeUser(session, encoding);
        }
        public static void OnGetRankTop8(
            funapi.Leaderboard.QueryRequest request, funapi.Leaderboard.QueryResponse response,
            bool error, Session session, Session.EncodingScheme encoding, bool single)
        {
            if (error)
            {
                Log.Error("Failed to query leaderboard. Leaderboard system error.");
                return;
            }
            string msgtype = single ? "ranklist_single" : "ranklist";

            if (encoding == Session.EncodingScheme.kJsonEncoding)
            {
                JObject result = new JObject();
                result ["ranks"] = new JObject();
                int index = 0;
                foreach (funapi.Leaderboard.Record record in response.Records)
                {
                    string index_str = index.ToString();
                    result ["ranks"] [index_str]           = new JObject();
                    result ["ranks"] [index_str] ["rank"]  = record.Rank;
                    result ["ranks"] [index_str] ["score"] = record.Score;
                    result ["ranks"] [index_str] ["id"]    = record.PlayerAccount.Id;
                    ++index;
                }
                session.SendMessage(msgtype, result, Session.Encryption.kDefault);
            }
            else
            {
                Log.Assert(encoding == Session.EncodingScheme.kProtobufEncoding);

                FunMessage         message = new FunMessage();
                LobbyRankListReply reply   = new LobbyRankListReply();
                reply.result = "Success";
                int index = 0;
                foreach (funapi.Leaderboard.Record record in response.Records)
                {
                    LobbyRankListReply.RankElement el = new LobbyRankListReply.RankElement();
                    string index_str = index.ToString();
                    el.rank  = record.Rank;
                    el.score = (int)record.Score;
                    el.id    = record.PlayerAccount.Id;
                    reply.rank.Add(el);
                    ++index;
                }
                message.AppendExtension_lobby_rank_list_repl(reply);
                session.SendMessage(msgtype, message, Session.Encryption.kDefault);
            }
        }
        public static void Install()
        {
            Session.EncodingScheme encoding = Session.EncodingScheme.kUnknownEncoding;
            UInt64 tcp_json_port            = Flags.GetUInt64("tcp_json_port");
            UInt64 udp_json_port            = Flags.GetUInt64("udp_json_port");
            UInt64 http_json_port           = Flags.GetUInt64("http_json_port");
            UInt64 websocket_json_port      = Flags.GetUInt64("websocket_json_port");
            UInt64 tcp_protobuf_port        = Flags.GetUInt64("tcp_protobuf_port");
            UInt64 udp_protobuf_port        = Flags.GetUInt64("udp_protobuf_port");
            UInt64 http_protobuf_port       = Flags.GetUInt64("http_protobuf_port");
            UInt64 websocket_protobuf_port  = Flags.GetUInt64("websocket_protobuf_port");

            if (tcp_json_port != 0 || udp_json_port != 0 || http_json_port != 0 || websocket_json_port != 0)
            {
                encoding = Session.EncodingScheme.kJsonEncoding;
            }
            if (tcp_protobuf_port != 0 || udp_protobuf_port != 0 || http_protobuf_port != 0 || websocket_protobuf_port != 0)
            {
                if (encoding != Session.EncodingScheme.kUnknownEncoding)
                {
                    Log.Fatal("Cannot set both JSON and Protobuf. Enable only one in MANIFEST.game.json");
                }
                encoding = Session.EncodingScheme.kProtobufEncoding;
            }
            if (encoding == Session.EncodingScheme.kUnknownEncoding)
            {
                Log.Fatal("Either JSON or Protobuf must be enabled.");
            }
            NetworkHandlerRegistry.RegisterSessionHandler(
                new NetworkHandlerRegistry.SessionOpenedHandler(OnSessionOpened),
                (_1, _2) => { OnSessionClosed(_1, _2, encoding); });
            NetworkHandlerRegistry.RegisterTcpTransportDetachedHandler((_1) => { OnTcpDisconnected(_1, encoding); });
            NetworkHandlerRegistry.RegisterWebSocketTransportDetachedHandler((_1) => { OnWebSocketDisconnected(_1, encoding); });

            // for json
            NetworkHandlerRegistry.RegisterMessageHandler("ready", new NetworkHandlerRegistry.JsonMessageHandler(OnReady));
            NetworkHandlerRegistry.RegisterMessageHandler("relay", new NetworkHandlerRegistry.JsonMessageHandler(OnRelay));
            NetworkHandlerRegistry.RegisterMessageHandler("result", new NetworkHandlerRegistry.JsonMessageHandler(OnResult));

            // for pbuf
            NetworkHandlerRegistry.RegisterMessageHandler("ready", new NetworkHandlerRegistry.ProtobufMessageHandler(OnReady2));
            NetworkHandlerRegistry.RegisterMessageHandler("relay", new NetworkHandlerRegistry.ProtobufMessageHandler(OnRelay2));
            NetworkHandlerRegistry.RegisterMessageHandler("result", new NetworkHandlerRegistry.ProtobufMessageHandler(OnResult2));
        }
Example #6
0
        public static void HandleSingleModeResult(Session session, bool win, Session.EncodingScheme encoding)
        {
            string id;

            if (!session.GetFromContext("id", out id))
            {
                Log.Warning("Failed to update singlemode game result. Not logged in.");
                if (encoding == Session.EncodingScheme.kJsonEncoding)
                {
                    session.SendMessage("error", Utility.MakeResponse("fail", "not logged in"));
                }
                else
                {
                    Log.Assert(encoding == Session.EncodingScheme.kProtobufEncoding);
                    FunMessage       funmsg = new FunMessage();
                    PongErrorMessage msg    = new PongErrorMessage();
                    msg.result = "fail";
                    msg.msg    = "not logged in";
                    funmsg.AppendExtension_pong_error(msg);
                    session.SendMessage("error", funmsg);
                }
                return;
            }

            User user = User.FetchById(id);

            if (user == null)
            {
                Log.Error("Cannot find uwer's id in db: id={0}", id);
                return;
            }

            if (win)
            {
                Leaderboard.OnWin(user, true);
            }
            else
            {
                Leaderboard.OnLose(user, true);
            }
        }
        public static void HandleReadySignal(Session session, Session.EncodingScheme encoding)
        {
            session.AddToContext("ready", 1);
            string opponent_id;

            Log.Verify(session.GetFromContext("opponent", out opponent_id));
            Session opponent_session = AccountManager.FindLocalSession(opponent_id);

            // 상대의 상태를 확인합니다.
            if (opponent_session != null &&
                (opponent_session.IsTransportAttached(Session.Transport.kTcp) ||
                 opponent_session.IsTransportAttached(Session.Transport.kWebSocket)))
            {
                long is_opponent_ready = 0;
                opponent_session.GetFromContext("ready", out is_opponent_ready);
                if (is_opponent_ready == 1)
                {
                    // 둘 다 준비가 되었습니다. 시작 신호를 보냅니다.
                    if (encoding == Session.EncodingScheme.kJsonEncoding)
                    {
                        JObject response = Utility.MakeResponse("ok");
                        session.SendMessage("start", response);
                        opponent_session.SendMessage("start", response);
                    }
                    else
                    {
                        Log.Assert(encoding == Session.EncodingScheme.kProtobufEncoding);
                        FunMessage       funmsg = new FunMessage();
                        GameStartMessage msg    = new GameStartMessage();
                        msg.result = "ok";
                        session.SendMessage("start", funmsg);
                        funmsg.AppendExtension_game_start(msg);
                        opponent_session.SendMessage("start", funmsg);
                    }
                }
            }
            else
            {
                // 아직 상대가 방에 없기 때문에 기다린다.
            }
        }
Example #8
0
        private static void CancelMatchmaking(Session session, Session.EncodingScheme encoding)
        {
            // 로그인 한 Id 를 가져옵니다.
            string id;

            if (!session.GetFromContext("id", out id))
            {
                Log.Warning("Failed to cancel matchmaking. Not logged in.");
                if (encoding == Session.EncodingScheme.kJsonEncoding)
                {
                    session.SendMessage("error", Utility.MakeResponse("fail", "not logged in"));
                }
                else
                {
                    Log.Assert(encoding == Session.EncodingScheme.kProtobufEncoding);
                    FunMessage       funmsg = new FunMessage();
                    PongErrorMessage msg    = new PongErrorMessage();
                    msg.result = "fail";
                    msg.msg    = "not logged in";
                    funmsg.AppendExtension_pong_error(msg);
                    session.SendMessage("error", funmsg);
                }
                return;
            }

            // 매치메이킹 취소 상태로 변경합니다.
            session.AddToContext("matching", "cancel");

            funapi.Matchmaking.Client.CancelCallback cancel_cb = (string player_id,
                                                                  funapi.Matchmaking.CancelResult result) => {
                if (encoding == Session.EncodingScheme.kJsonEncoding)
                {
                    JObject response = new JObject();

                    if (result == funapi.Matchmaking.CancelResult.kSuccess)
                    {
                        Log.Info("Succeed to cancel matchmaking: id={0}", player_id);
                        response = Utility.MakeResponse("Cancel");
                    }
                    else if (result == funapi.Matchmaking.CancelResult.kNoRequest)
                    {
                        response = Utility.MakeResponse("NoRequest");
                    }
                    else
                    {
                        response = Utility.MakeResponse("Error");
                    }

                    session.SendMessage("match", response, Session.Encryption.kDefault);
                }
                else
                {
                    Log.Assert(encoding == Session.EncodingScheme.kProtobufEncoding);
                    FunMessage      funmsg = new FunMessage();
                    LobbyMatchReply reply  = new LobbyMatchReply();

                    if (result == funapi.Matchmaking.CancelResult.kSuccess)
                    {
                        Log.Info("Succeed to cancel matchmaking: id={0}", player_id);
                        reply.result = "Cancel";
                    }
                    else if (result == funapi.Matchmaking.CancelResult.kNoRequest)
                    {
                        reply.result = "NoRequest";
                    }
                    else
                    {
                        reply.result = "Error";
                    }

                    funmsg.AppendExtension_lobby_match_repl(reply);
                    session.SendMessage("match", funmsg, Session.Encryption.kDefault);
                }
            };

            funapi.Matchmaking.Client.Cancel((int)MatchmakingType.kMatch1vs1, id, (_1, _2) => { cancel_cb(_1, _2); });
        }
Example #9
0
        private static void StartMatchmaking(Session session, Session.EncodingScheme encoding)
        {
            // 로그인 한 Id 를 가져옵니다.
            string id;

            if (!session.GetFromContext("id", out id))
            {
                Log.Warning("Failed to request matchmaking. Not logged in.");
                if (encoding == Session.EncodingScheme.kJsonEncoding)
                {
                    session.SendMessage("error", Utility.MakeResponse("fail", "not logged in"));
                }
                else
                {
                    Log.Assert(encoding == Session.EncodingScheme.kProtobufEncoding);
                    FunMessage       funmsg = new FunMessage();
                    PongErrorMessage msg    = new PongErrorMessage();
                    msg.result = "fail";
                    msg.msg    = "not logged in";
                    funmsg.AppendExtension_pong_error(msg);
                    session.SendMessage("error", funmsg);
                }
                return;
            }

            funapi.Matchmaking.Client.MatchCallback match_cb = (string player_id, funapi.Matchmaking.Match match,
                                                                funapi.Matchmaking.MatchResult result) => {
                JObject         response = new JObject();
                LobbyMatchReply reply    = new LobbyMatchReply();

                if (result == funapi.Matchmaking.MatchResult.kSuccess)
                {
                    // Matchmaking 에 성공했습니다.
                    Log.Info("Succeed in matchmaking: id={0}", player_id);

                    string player_a_id = Utility.ReadStringFromJsonObject(match.Context, "A");
                    string player_b_id = Utility.ReadStringFromJsonObject(match.Context, "B");
                    Log.Assert(player_a_id != null && player_b_id != null);

                    string opponent_id;
                    if (player_a_id == player_id)
                    {
                        opponent_id = player_b_id;
                    }
                    else
                    {
                        opponent_id = player_a_id;
                    }

                    session.AddToContext("opponent", opponent_id);
                    session.AddToContext("matching", "done");
                    session.AddToContext("ready", 0);

                    if (encoding == Session.EncodingScheme.kJsonEncoding)
                    {
                        response      = Utility.MakeResponse("Success");
                        response["A"] = player_a_id;
                        response["B"] = player_b_id;
                    }
                    else
                    {
                        Log.Assert(encoding == Session.EncodingScheme.kProtobufEncoding);
                        reply.result  = "Success";
                        reply.player1 = player_a_id;
                        reply.player2 = player_b_id;
                    }
                    // 유저를 Game 서버로 보냅니다.
                    Common.Redirect(session, "game");
                }
                else if (result == funapi.Matchmaking.MatchResult.kAlreadyRequested)
                {
                    // Matchmaking 요청을 중복으로 보냈습니다.
                    Log.Info("Failed in matchmaking. Already requested: id={0}", player_id);
                    session.AddToContext("matching", "failed");
                    if (encoding == Session.EncodingScheme.kJsonEncoding)
                    {
                        response = Utility.MakeResponse("AlreadyRequested");
                    }
                    else
                    {
                        Log.Assert(encoding == Session.EncodingScheme.kProtobufEncoding);
                        reply.result = "AlreadyRequested";
                    }
                }
                else if (result == funapi.Matchmaking.MatchResult.kTimeout)
                {
                    // Matchmaking 처리가 시간 초과되었습니다.
                    Log.Info("Failed in matchmaking. Timeout: id={0}", player_id);
                    session.AddToContext("matching", "failed");
                    if (encoding == Session.EncodingScheme.kJsonEncoding)
                    {
                        response = Utility.MakeResponse("Timeout");
                    }
                    else
                    {
                        Log.Assert(encoding == Session.EncodingScheme.kProtobufEncoding);
                        reply.result = "Timeout";
                    }
                }
                else
                {
                    // Matchmaking 에 오류가 발생했습니다.
                    Log.Error("Failed in matchmaking. Error: id={0}", player_id);
                    session.AddToContext("matching", "failed");
                    if (encoding == Session.EncodingScheme.kJsonEncoding)
                    {
                        response = Utility.MakeResponse("Error");
                    }
                    else
                    {
                        Log.Assert(encoding == Session.EncodingScheme.kProtobufEncoding);
                        reply.result = "Error";
                    }
                }

                if (encoding == Session.EncodingScheme.kJsonEncoding)
                {
                    session.SendMessage("match", response, Session.Encryption.kDefault);
                }
                else
                {
                    FunMessage funmsg = new FunMessage();
                    funmsg.AppendExtension_lobby_match_repl(reply);
                    session.SendMessage("match", funmsg, Session.Encryption.kDefault);
                }
            };

            // 빈 Player Context 를 만듭니다. 지금 구현에서는 Matchmaking 서버가
            // 조건 없이 Matching 합니다. Level 등의 조건으로 Matching 하려면
            // 여기에 Level 등의 Matching 에 필요한 정보를 넣습니다.
            JObject player_ctxt = new JObject();

            // Matchmaking 을 요청합니다.
            funapi.Matchmaking.Client.Start(
                (int)MatchmakingType.kMatch1vs1, id, player_ctxt, new funapi.Matchmaking.Client.MatchCallback(match_cb),
                funapi.Matchmaking.Client.TargetServerSelection.kMostNumberOfPlayers, null, kMatchmakingTimeout);
        }
Example #10
0
        private static void OnLogin_Completed(string account_id, Session session, bool success, Session.EncodingScheme encoding)
        {
            if (!success)
            {
                // 로그인에 실패 응답을 보냅니다. 중복 로그인이 원인입니다.
                // (1. 같은 ID 로 이미 다른 Session 이 로그인 했거나,
                //  2. 이 Session 이 이미 로그인 되어 있는 경우)
                Log.Info("Failed to login: id={0}", account_id);
                if (encoding == Session.EncodingScheme.kJsonEncoding)
                {
                    session.SendMessage("login",
                                        Utility.MakeResponse("nop", "failed to login"),
                                        Session.Encryption.kDefault);
                }
                else
                {
                    Log.Assert(encoding == Session.EncodingScheme.kProtobufEncoding);
                    FunMessage      funmsg = new FunMessage();
                    LobbyLoginReply reply  = new LobbyLoginReply();
                    reply.result = "nop";
                    reply.msg    = "failed to login";
                    funmsg.AppendExtension_lobby_login_repl(reply);
                    session.SendMessage("login", funmsg);
                }

                // 아래 로그아웃 처리를 한 후 자동으로 로그인 시킬 수 있지만
                // 일단 클라이언트에서 다시 시도하도록 합니다.

                // 1. 이 ID 의 로그인을 풀어버립니다.(로그아웃)
                AccountManager.LogoutCallback logout_cb = (string param_account_id, Session param_session, bool param_success) => {
                    if (!param_success)
                    {
                        return;
                    }
                    if (param_session != null)
                    {
                        // 같은 서버에 로그인 되어 있었습니다.
                        Log.Info("Logged out(local) by duplicated login request: id={0}", param_account_id);
                        session.Close();
                    }
                    else
                    {
                        // 다른 서버에 로그인 되어 있었습니다.
                        // 해당 서버의 OnLoggedOutRemotely() 에서 처리합니다.
                        Log.Info("Logged out(remote) by duplicated login request: id={0}", param_account_id);
                    }
                };

                AccountManager.SetLoggedOutGlobalAsync(account_id, new AccountManager.LogoutCallback(logout_cb));

                // 2. 이 Session 의 로그인을 풀어버립니다.(로그아웃)
                string account_id_logged_in = AccountManager.FindLocalAccount(session);
                if (account_id_logged_in != string.Empty)
                {
                    // OnSessionClosed 에서 처리합니다.
                    Log.Info("Close session. by duplicated login request: id={0}", account_id);
                    session.Close();
                }

                return;
            }

            // User Object 를 가져옵니다.
            User user = User.FetchById(account_id);

            if (user == null)
            {
                // 새로운 유저를 생성합니다.
                user = User.Create(account_id);
                Log.Info("Registered new user: id={0}", account_id);
            }

            Event.AssertNoRollback();

            Log.Info("Succeed to login: id={0}", account_id);

            // 로그인 Activitiy Log 를 남깁니다.
            ActivityLog.PlayerLoggedIn(session.Id.ToString(), account_id, WallClock.Now);

            // Session 에 Login 한 ID 를 저장합니다.
            session.AddToContext("id", account_id);

            if (encoding == Session.EncodingScheme.kJsonEncoding)
            {
                JObject response = Utility.MakeResponse("ok");
                response ["id"]              = account_id;
                response ["winCount"]        = user.GetWinCount();
                response ["loseCount"]       = user.GetLoseCount();
                response ["curRecord"]       = Leaderboard.GetRecord(account_id);
                response ["singleWinCount"]  = user.GetWinCountSingle();
                response ["singleLoseCount"] = user.GetLoseCountSingle();
                response ["singleCurRecord"] = Leaderboard.GetRecord(account_id, true);

                session.SendMessage("login", response, Session.Encryption.kDefault);
            }
            else
            {
                Log.Assert(encoding == Session.EncodingScheme.kProtobufEncoding);
                FunMessage      funmsg = new FunMessage();
                LobbyLoginReply reply  = new LobbyLoginReply();
                reply.result            = "ok";
                reply.id                = account_id;
                reply.win_count         = (int)user.GetWinCount();
                reply.lose_count        = (int)user.GetLoseCount();
                reply.cur_record        = (int)Leaderboard.GetRecord(account_id);
                reply.win_count_single  = (int)user.GetWinCountSingle();
                reply.lose_count_single = (int)user.GetLoseCountSingle();
                reply.cur_record_single = Leaderboard.GetRecord(account_id, true);
                funmsg.AppendExtension_lobby_login_repl(reply);

                session.SendMessage("login", funmsg, Session.Encryption.kDefault);
            }
        }
 // 세션이 닫혔을 때 불리는 함수
 public static void OnSessionClosed(Session session, Session.CloseReason reason, Session.EncodingScheme encoding)
 {
     // 세션 닫힘 Activity Log 를 남깁니다.
     ActivityLog.SessionClosed(session.Id.ToString(), WallClock.Now);
     // 세션을 초기화 합니다.
     FreeUser(session, encoding);
 }
        // 세션을 정리합니다.
        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);
        }
        public static void OnHandleResult(Session session, Session.EncodingScheme encoding)
        {
            // 패배한 쪽만 result를 보내도록 되어있습니다.

            // 내 아이디를 가져옵니다.
            string id;

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

            // 상대방의 아이디와 세션을 가져옵니다.
            string opponent_id;

            Log.Verify(session.GetFromContext("opponent", out opponent_id));
            Session opponent_session = AccountManager.FindLocalSession(opponent_id);

            User user          = User.FetchById(id);
            User opponent_user = User.FetchById(opponent_id);

            Event.AssertNoRollback();

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

            // 상대에게 승리했음을 알립니다.
            if (opponent_session != null)
            {
                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);
                }

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

            // 패배 확인 메세지를 보냅니다.
            if (encoding == Session.EncodingScheme.kJsonEncoding)
            {
                session.SendMessage("result", Utility.MakeResponse("lose"));
            }
            else
            {
                Log.Assert(encoding == Session.EncodingScheme.kProtobufEncoding);
                FunMessage        funmsg = new FunMessage();
                GameResultMessage msg    = new GameResultMessage();
                msg.result = "lose";
                funmsg.AppendExtension_game_result(msg);
                session.SendMessage("result", funmsg);
            }
            session.DeleteFromContext("opponent");
            Common.Redirect(session, "lobby");
        }