コード例 #1
0
        /// <summary>
        /// Uses the OperationResponses provided by the server to advance the internal state and call ops as needed.
        /// </summary>
        /// <remarks>
        /// When this method finishes, it will call your OnOpResponseAction (if any). This way, you can get any
        /// operation response without overriding this class.
        ///
        /// To implement a more complex game/app logic, you should implement your own class that inherits the
        /// LoadBalancingClient. Override this method to use your own operation-responses easily.
        ///
        /// This method is essential to update the internal state of a LoadBalancingClient, so overriding methods
        /// must call base.OnOperationResponse().
        /// </remarks>
        /// <param name="operationResponse">Contains the server's response for an operation called by this peer.</param>
        public virtual void OnOperationResponse(OperationResponse operationResponse)
        {
            // if (operationResponse.ReturnCode != 0) this.DebugReturn(DebugLevel.ERROR, operationResponse.ToStringFull());

            // use the "secret" or "token" whenever we get it. doesn't really matter if it's in AuthResponse.
            if (operationResponse.Parameters.ContainsKey(ParameterCode.Secret))
            {
                if (this.AuthValues == null)
                {
                    this.AuthValues = new AuthenticationValues();
                    //this.DebugReturn(DebugLevel.ERROR, "Server returned secret. Created AuthValues.");
                }

                this.AuthValues.Token = operationResponse[ParameterCode.Secret] as string;
            }

            switch (operationResponse.OperationCode)
            {
                case OperationCode.FindFriends:
                    if (operationResponse.ReturnCode != 0)
                    {
                        this.DebugReturn(DebugLevel.ERROR, "OpFindFriends failed: " + operationResponse.ToStringFull());
                        this.isFetchingFriendList = false;
                        break;
                    }

                    bool[] onlineList = operationResponse[ParameterCode.FindFriendsResponseOnlineList] as bool[];
                    string[] roomList = operationResponse[ParameterCode.FindFriendsResponseRoomIdList] as string[];

                    this.FriendList = new List<FriendInfo>(this.friendListRequested.Length);
                    for (int index = 0; index < this.friendListRequested.Length; index++)
                    {
                        FriendInfo friend = new FriendInfo();
                        friend.Name = this.friendListRequested[index];
                        friend.Room = roomList[index];
                        friend.IsOnline = onlineList[index];
                        this.FriendList.Insert(index, friend);
                    }

                    this.friendListRequested = null;
                    this.isFetchingFriendList = false;
                    this.friendListTimestamp = Environment.TickCount;
                    if (this.friendListTimestamp == 0)
                    {
                        this.friendListTimestamp = 1;   // makes sure the timestamp is not accidentally 0
                    }
                    break;
                case OperationCode.Authenticate:
                    {
                        if (operationResponse.ReturnCode != 0)
                        {
                            this.DebugReturn(DebugLevel.ERROR, operationResponse.ToStringFull() + " Server: " + this.Server + " Address: " + this.loadBalancingPeer.ServerAddress);

                            switch (operationResponse.ReturnCode)
                            {
                                case ErrorCode.InvalidAuthentication:
                                    this.DisconnectedCause = DisconnectCause.InvalidAuthentication;
                                    break;
                                case ErrorCode.CustomAuthenticationFailed:
                                    this.DisconnectedCause = DisconnectCause.CustomAuthenticationFailed;
                                    break;
                                case ErrorCode.InvalidRegion:
                                    this.DisconnectedCause = DisconnectCause.InvalidRegion;
                                    break;
                                case ErrorCode.MaxCcuReached:
                                    this.DisconnectedCause = DisconnectCause.MaxCcuReached;
                                    break;
                                case ErrorCode.OperationNotAllowedInCurrentState:
                                    this.DisconnectedCause = DisconnectCause.OperationNotAllowedInCurrentState;
                                    break;
                            }
                            this.State = ClientState.Disconnecting;
                            this.Disconnect();
                            break;  // if auth didn't succeed, we disconnect (above) and exit this operation's handling
                        }

                        if (this.Server == ServerConnection.NameServer || this.Server == ServerConnection.MasterServer)
                        {
                            if (operationResponse.Parameters.ContainsKey(ParameterCode.UserId))
                            {
                                this.UserId = (string)operationResponse.Parameters[ParameterCode.UserId];
                                this.DebugReturn(DebugLevel.INFO, string.Format("Setting UserId sent by Server:{0}", this.UserId));
                            }
                            if (operationResponse.Parameters.ContainsKey((byte)233))
                            {
                                this.NickName = (string)operationResponse.Parameters[(byte)233];
                                this.DebugReturn(DebugLevel.INFO, string.Format("Setting Nickname sent by Server:{0}", this.NickName));
                            }
                        }

                        if (this.Server == ServerConnection.NameServer)
                        {
                            // on the NameServer, authenticate returns the MasterServer address for a region and we hop off to there
                            this.MasterServerAddress = operationResponse[ParameterCode.Address] as string;
                            this.DisconnectToReconnect();
                        }
                        else if (this.Server == ServerConnection.MasterServer)
                        {
                            this.State = ClientState.ConnectedToMaster;

                            if (this.AutoJoinLobby)
                            {
                                this.loadBalancingPeer.OpJoinLobby(this.CurrentLobby);
                            }
                        }
                        else if (this.Server == ServerConnection.GameServer)
                        {
                            this.State = ClientState.ConnectingToGameserver;

                            if (this.lastJoinType == JoinType.JoinRoom || this.lastJoinType == JoinType.JoinRandomRoom)
                            {
                                // if we just "join" the game, do so. if we "join-or-create", we have to set the createIfNotExists parameter to true
                                this.State = ClientState.Joining;
                                this.OpJoinRoom(this.CurrentRoom.Name, this.lastJoinActorNumber);
                            }
                            else if(this.lastJoinType == JoinType.JoinOrCreateRoom)
                            {
                                this.State = ClientState.Joining;
                                this.OpJoinOrCreateRoom(this.CurrentRoom.Name, this.lastJoinActorNumber, this.createRoomOptions, this.CurrentLobby);
                            }
                            else if (this.lastJoinType == JoinType.CreateRoom)
                            {
                                this.State = ClientState.Joining;   // yes, "joining" even though we technically create the game now on the game server
                                this.OpCreateRoom(this.CurrentRoom.Name, this.createRoomOptions, this.CurrentLobby);
                            }
                            break;
                        }
                        break;
                    }

                case OperationCode.GetRegions:
                    this.AvailableRegions = operationResponse[ParameterCode.Region] as string[];
                    this.AvailableRegionsServers = operationResponse[ParameterCode.Address] as string[];
                    break;

                case OperationCode.Leave:
                    //this.CleanCachedValues(); // this is done in status change on "disconnect"
                    this.State = ClientState.DisconnectingFromGameserver;
                    this.loadBalancingPeer.Disconnect();
                    break;

                case OperationCode.JoinLobby:
                    this.State = ClientState.JoinedLobby;
                    break;

                case OperationCode.JoinRandomGame:  // this happens only on the master server. on gameserver this is a "regular" join
                case OperationCode.CreateGame:
                case OperationCode.JoinGame:
                    {
                        if (this.Server == ServerConnection.GameServer)
                        {
                            this.GameEnteredOnGameServer(operationResponse);
                        }
                        else
                        {
                            if (operationResponse.ReturnCode == ErrorCode.NoRandomMatchFound)
                            {
                                // this happens only for JoinRandomRoom
                                // TODO: implement callback/reaction when no random game could be found (this is no bug and can simply happen if no games are open)
                                this.State = ClientState.JoinedLobby; // TODO: maybe we have to return to another state here (if we didn't join a lobby)
                                break;
                            }

                            // TODO: handle more error cases

                            if (operationResponse.ReturnCode != 0)
                            {
                                if (this.loadBalancingPeer.DebugOut >= DebugLevel.ERROR)
                                {
                                    this.DebugReturn(DebugLevel.ERROR, string.Format("Getting into game failed, client stays on masterserver: {0}.", operationResponse.ToStringFull()));
                                }

                                this.State = ClientState.JoinedLobby; // TODO: maybe we have to return to another state here (if we didn't join a lobby)
                                break;
                            }

                            this.GameServerAddress = (string)operationResponse[ParameterCode.Address];
                            string gameId = operationResponse[ParameterCode.RoomName] as string;
                            if (!string.IsNullOrEmpty(gameId))
                            {
                                // is only sent by the server's response, if it has not been sent with the client's request before!
                                this.CurrentRoom.Name = gameId;
                            }

                            this.DisconnectToReconnect();
                        }

                        break;
                    }
            }

            if (this.OnOpResponseAction != null) this.OnOpResponseAction(operationResponse);
        }
コード例 #2
0
        /// <summary>
        /// Uses the OperationResponses provided by the server to advance the internal state and call ops as needed.
        /// </summary>
        /// <remarks>
        /// When this method finishes, it will call your OnOpResponseAction (if any). This way, you can get any
        /// operation response without overriding this class.
        ///
        /// To implement a more complex game/app logic, you should implement your own class that inherits the
        /// LoadBalancingClient. Override this method to use your own operation-responses easily.
        ///
        /// This method is essential to update the internal state of a LoadBalancingClient, so overriding methods
        /// must call base.OnOperationResponse().
        /// </remarks>
        /// <param name="operationResponse">Contains the server's response for an operation called by this peer.</param>
        public virtual void OnOperationResponse(OperationResponse operationResponse)
        {
            // if (operationResponse.ReturnCode != 0) this.DebugReturn(DebugLevel.ERROR, operationResponse.ToStringFull());

            // use the "secret" or "token" whenever we get it. doesn't really matter if it's in AuthResponse.
            if (operationResponse.Parameters.ContainsKey(ParameterCode.Secret))
            {
                if (this.AuthValues == null)
                {
                    this.AuthValues = new AuthenticationValues();
                    //this.DebugReturn(DebugLevel.ERROR, "Server returned secret. Created AuthValues.");
                }

                this.AuthValues.Token = operationResponse[ParameterCode.Secret] as string;
            }

            switch (operationResponse.OperationCode)
            {
                case OperationCode.FindFriends:
                    if (operationResponse.ReturnCode != 0)
                    {
                        this.DebugReturn(DebugLevel.ERROR, "OpFindFriends failed: " + operationResponse.ToStringFull());
                        this.isFetchingFriendList = false;
                        break;
                    }

                    bool[] onlineList = operationResponse[ParameterCode.FindFriendsResponseOnlineList] as bool[];
                    string[] roomList = operationResponse[ParameterCode.FindFriendsResponseRoomIdList] as string[];

                    this.FriendList = new List<FriendInfo>(this.friendListRequested.Length);
                    for (int index = 0; index < this.friendListRequested.Length; index++)
                    {
                        FriendInfo friend = new FriendInfo();
                        friend.Name = this.friendListRequested[index];
                        friend.Room = roomList[index];
                        friend.IsOnline = onlineList[index];
                        this.FriendList.Insert(index, friend);
                    }

                    this.friendListRequested = null;
                    this.isFetchingFriendList = false;
                    this.friendListTimestamp = Environment.TickCount;
                    if (this.friendListTimestamp == 0)
                    {
                        this.friendListTimestamp = 1;   // makes sure the timestamp is not accidentally 0
                    }
                    break;
                case OperationCode.Authenticate:
                    {
                        if (operationResponse.ReturnCode != 0)
                        {
                            this.DebugReturn(DebugLevel.ERROR, operationResponse.ToStringFull() + " Server: " + this.Server + " Address: " + this.loadBalancingPeer.ServerAddress);

                            switch (operationResponse.ReturnCode)
                            {
                                case ErrorCode.InvalidAuthentication:
                                    this.DisconnectedCause = DisconnectCause.InvalidAuthentication;
                                    break;
                                case ErrorCode.CustomAuthenticationFailed:
                                    this.DisconnectedCause = DisconnectCause.CustomAuthenticationFailed;
                                    break;
                                case ErrorCode.InvalidRegion:
                                    this.DisconnectedCause = DisconnectCause.InvalidRegion;
                                    break;
                                case ErrorCode.MaxCcuReached:
                                    this.DisconnectedCause = DisconnectCause.MaxCcuReached;
                                    break;
                                case ErrorCode.OperationNotAllowedInCurrentState:
                                    this.DisconnectedCause = DisconnectCause.OperationNotAllowedInCurrentState;
                                    break;
                            }
                            this.State = ClientState.Disconnecting;
                            this.Disconnect();
                            break;  // if auth didn't succeed, we disconnect (above) and exit this operation's handling
                        }

                        if (this.Server == ServerConnection.NameServer || this.Server == ServerConnection.MasterServer)
                        {
                            if (operationResponse.Parameters.ContainsKey(ParameterCode.UserId))
                            {
                                string incomingId = (string)operationResponse.Parameters[ParameterCode.UserId];
                                if (!string.IsNullOrEmpty(incomingId))
                                {
                                    this.UserId = incomingId;
                                    this.DebugReturn(DebugLevel.INFO, string.Format("Setting UserId sent by Server:{0}", this.UserId));
                                }
                            }
                            if (operationResponse.Parameters.ContainsKey((byte)233))
                            {
                                this.NickName = (string)operationResponse.Parameters[(byte)233];
                                this.DebugReturn(DebugLevel.INFO, string.Format("Setting Nickname sent by Server:{0}", this.NickName));
                            }
                        }

                        if (this.Server == ServerConnection.NameServer)
                        {
                            // on the NameServer, authenticate returns the MasterServer address for a region and we hop off to there
                            this.MasterServerAddress = operationResponse[ParameterCode.Address] as string;
                            this.DisconnectToReconnect();
                        }
                        else if (this.Server == ServerConnection.MasterServer)
                        {
                            this.State = ClientState.ConnectedToMaster;

                            if (this.AutoJoinLobby)
                            {
                                this.loadBalancingPeer.OpJoinLobby(this.CurrentLobby);
                            }
                        }
                        else if (this.Server == ServerConnection.GameServer)
                        {
                            this.State = ClientState.Joining;
                            this.enterRoomParamsCache.PlayerProperties = this.LocalPlayer.CustomProperties;
                            this.enterRoomParamsCache.OnGameServer = true;

                            if (this.lastJoinType == JoinType.JoinRoom || this.lastJoinType == JoinType.JoinRandomRoom || this.lastJoinType == JoinType.JoinOrCreateRoom)
                            {
                                this.loadBalancingPeer.OpJoinRoom(this.enterRoomParamsCache);
                            }
                            else if (this.lastJoinType == JoinType.CreateRoom)
                            {
                                this.loadBalancingPeer.OpCreateRoom(this.enterRoomParamsCache);
                            }
                            break;
                        }
                        break;
                    }

                case OperationCode.GetRegions:
                    this.AvailableRegions = operationResponse[ParameterCode.Region] as string[];
                    this.AvailableRegionsServers = operationResponse[ParameterCode.Address] as string[];
                    break;

                case OperationCode.Leave:
                    //this.CleanCachedValues(); // this is done in status change on "disconnect"
                    this.State = ClientState.DisconnectingFromGameserver;
                    this.loadBalancingPeer.Disconnect();
                    break;

                case OperationCode.JoinLobby:
                    this.State = ClientState.JoinedLobby;
                    break;

                case OperationCode.LeaveLobby:
                    this.State = ClientState.ConnectedToMaster;
                    break;

                case OperationCode.JoinRandomGame:  // this happens only on the master server. on gameserver this is a "regular" join
                case OperationCode.CreateGame:
                case OperationCode.JoinGame:
                    {
                        if (this.Server == ServerConnection.GameServer)
                        {
                            this.GameEnteredOnGameServer(operationResponse);
                        }
                        else
                        {
                            // TODO: handle more error cases
                            if (operationResponse.ReturnCode != 0)
                            {
                                // TODO: error callbacks?! at the moment, developers have to implement this.OnOpResponseAction to get error cases of this.
                                //if (operationResponse.ReturnCode == ErrorCode.NoRandomMatchFound)
                                //{
                                //    // this happens only for JoinRandomRoom
                                //    break;
                                //}

                                if (this.loadBalancingPeer.DebugOut >= DebugLevel.ERROR)
                                {
                                    this.DebugReturn(DebugLevel.ERROR, string.Format("Getting into game failed, client stays on masterserver: {0}.", operationResponse.ToStringFull()));
                                }
                                break;
                            }

                            this.GameServerAddress = (string)operationResponse[ParameterCode.Address];
                            string roomName = operationResponse[ParameterCode.RoomName] as string;
                            if (!string.IsNullOrEmpty(roomName))
                            {
                                this.enterRoomParamsCache.RoomName = roomName;
                            }

                            this.DisconnectToReconnect();
                        }

                        break;
                    }
            }

            if (this.OnOpResponseAction != null) this.OnOpResponseAction(operationResponse);
        }