static void OnMatchProgressUpdated(string account_id,
                                           funapi.Matchmaking.Match match,
                                           string player_id_joined,
                                           string player_id_left)
        {
            Log.Info("OnMatchProgressUpdated: account_id={0}, match_context={1}, " +
                     "player_id_joined={2}, player_id_left={3}",
                     account_id, match.Context.ToString(), player_id_joined, player_id_left);

            // 누군가 매치에 참여하거나 나갔을 때 이 핸들러를 호출합니다.
            // 또는 다른 곳에서 funapi.Matchmaking.Client.UpdateMatchPlayerContext() 를
            // 호출할 때도 이 핸들러를 호출합니다.
            //
            // 참고: UpdateMatchPlayerContext() 함수는 매치를 요청했던 사용자가
            // 자신이 보낸 user_data 내용을 변경할 때 사용할 수 있습니다.

            string ss = "---------------------------------\n";

            for (int i = 0; i < match.Players.Count; ++i)
            {
                if (i != 0)
                {
                    ss += ", ";
                }
                ss += String.Format("account_id={0}, user_data={1}",
                                    match.Players[i].Id,
                                    match.Players[i].Context.ToString());
            }
            ss += "\n---------------------------------";
            Log.Info(ss);
        }
Esempio n. 2
0
        private static funapi.Matchmaking.Server.MatchState CheckCompletion(funapi.Matchmaking.Match match)
        {
            Log.Assert(match.MatchType == (int)MatchmakingType.kMatch1vs1);

            if (match.Players.Count < 2)
            {
                return(funapi.Matchmaking.Server.MatchState.kMatchNeedMorePlayer);
            }

            Log.Info("Match completed: team_a={0}, team_b={1}",
                     match.Context ["A"].ToString(Newtonsoft.Json.Formatting.None),
                     match.Context ["B"].ToString(Newtonsoft.Json.Formatting.None));

            return(funapi.Matchmaking.Server.MatchState.kMatchComplete);
        }
Esempio n. 3
0
        private static void OnJoined(funapi.Matchmaking.Player player, funapi.Matchmaking.Match match)
        {
            Log.Assert(match.MatchType == (int)MatchmakingType.kMatch1vs1);

            // 팀을 구성합니다. 1vs1 만 있기 때문에 각 플레이어를 A, B 팀으로 나눕니다.

            JToken value;

            if (!match.Context.TryGetValue("A", out value))
            {
                match.Context ["A"] = player.Id;
            }
            else
            {
                match.Context ["B"] = player.Id;
            }
        }
Esempio n. 4
0
        private static void OnLeft(funapi.Matchmaking.Player player, funapi.Matchmaking.Match match)
        {
            Log.Assert(match.MatchType == (int)MatchmakingType.kMatch1vs1);

            string team_a = Utility.ReadStringFromJsonObject(match.Context, "A");

            if (team_a == player.Id)
            {
                match.Context.Remove("A");
                return;
            }
            string team_b = Utility.ReadStringFromJsonObject(match.Context, "B");

            if (team_b == player.Id)
            {
                match.Context.Remove("B");
                return;
            }
        }
Esempio n. 5
0
 private static bool CheckJoinable(funapi.Matchmaking.Player player, funapi.Matchmaking.Match match)
 {
     Log.Assert(match.MatchType == (int)MatchmakingType.kMatch1vs1);
     // 조건없이 바로 매칭합니다.
     return(true);
 }
        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 SpawnDedicatedServer(funapi.Matchmaking.Match match)
        {
            //
            // 데디케이티드 서버 인자 설정 가이드
            //

            // 1. 매치 ID
            // 방을 식별하는 용도로 사용합니다.
            // 여기서는 매치메이킹 기능을 사용하므로 매치 ID 를 그대로 사용합니다.
            // 아래 함수를 사용하면 스폰 이후 방 정보를 가져올 수 있습니다.
            // DedicatedServerManager::GetGameState(
            //     const Uuid &match_id, const GetGameStateCallback &callback);
            //
            Guid match_id = match.MatchId;

            // 2. 매치 데이터
            // 이 매치에서 사용할 데이터를 넣습니다.
            // 이 데이터는 각 데디케이티드 서버에서 다음과 같이 받을 수 있습니다.
            // - 유니티 플러그인:
            //     - FunapiDedicatedServer.MatchDataCallback 에 등록한 콜백 함수
            // - 언리얼 엔진 플러그인:
            //     - SetMatchDataCallback 으로 등록한 콜백 함수
            //     - GetMatchDataJsonString() 함수
            //
            // 이 예제에서는 매치 타입에 따른 데이터를 넣습니다.
            JObject match_data = new JObject();

            match_data[kMatchType] = match.MatchType;

            // 3. 데디케이티드 서버 인자
            // 데디케이티드 서버 프로세스 실행 시 함께 넘겨 줄 인자를 설정합니다.
            // 유니티, 언리얼 데디케이티드 서버에서 지원하는 인자가 있거나, 별도로
            // 인자를 지정해야 할 경우 이 곳에 입력하면 됩니다.
            List <string> dedicated_server_args = new List <string> {
                "HighRise?game=FFA", "-log"
            };

            // 4. account_ids
            // 데디케이티드 서버 프로세스 생성 시 함께 전달할 계정 ID를 추가합니다.
            //
            // 게임 클라이언트는 데디케이티드 서버 프로세스 생성 후 리다이렉션 요청을 받으며
            // 이후 데디케이티드 서버로 진입하게 됩니다. 데디케이티드 서버는 이 때 클라이언트가
            // 올바른 account_id 와 token 을 가지고 있는지 다음과 같이 검증할 수 있습니다.
            // - 유니티 플러그인:
            //     - FunapiDedicatedServer.AuthUser(string uid, string token)
            // - 언리얼 플러그인:
            //     - bool FunapiDedicatedServer::AuthUser(
            //         const FString& options, const FString& uid_field,
            //         const FString& token_field, FString &error_message);
            //
            List <string> account_ids = new List <string> ();

            foreach (funapi.Matchmaking.Player player in match.Players)
            {
                account_ids.Add(player.Id);
            }

            // 5. user_data
            // 데디케이티드 서버 프로세스 생성 시 함께 전달할 유저 데이터를 추가합니다.
            // 유저 데이터는 각 데디케이티드 서버에서 다음과 같이 받을 수 있습니다.
            // (uid == account_id 와 동일합니다)
            // - 유니티 플러그인:
            //     - FunapiDedicatedServer.UserDataCallback 에 등록한 콜백 함수
            //     - FunapiDedicatedServer.GetUserDataJsonString(string uid) 함수
            // 언리얼 플러그인:
            //     - FunapiDedicatedServer::SetUserDataCallback 으로 등록한 콜백 함수
            //     - FunapiDedicatedServer::GetUserDataJsonString(const FString &uid) 함수
            //
            // 이 예제에서는 matchmaking 에서 제공하는 user_context 의 user_data 영역
            // ( MatchmakingClient::StartMatchmaking2 에서 지정한 user_data )
            // 을 추가합니다.
            List <JObject> user_data_list = new List <JObject> ();

            foreach (funapi.Matchmaking.Player player in match.Players)
            {
                user_data_list.Add(player.Context["user_data"].ToJObject());
            }

            // 두 컨테이너의 길이가 같아야 합니다. 0번 인덱스의 account_id 는 0번의 user_data
            // 를 사용하게 됩니다.
            Log.Assert(account_ids.Count == user_data_list.Count);

            // 준비한 인자들을 넣고 데디케이티드 서버 생성 요청을 합니다.
            // response_handler 는 스폰 요청에 대한 응답만 하기 때문에
            // 데디케이티드 서버
            DedicatedServerManager.SendCallback send_cb =
                new DedicatedServerManager.SendCallback(
                    (Guid match_id2, List <string> users2, bool success2) => {
                OnDedicatedServerSpawned(match_id2, users2, success2, match_data, match.MatchType);
            });
            DedicatedServerManager.Spawn(
                match_id, match_data, dedicated_server_args,
                account_ids, user_data_list, send_cb);
        }