/// <summary> /// Internally used to clean up local instances of players and room. /// </summary> private void CleanCachedValues() { this.ChangeLocalID(-1); this.isFetchingFriendList = false; // if this is called on the gameserver, we clean the room we were in. on the master, we keep the room to get into it if (this.Server == ServerConnection.GameServer || this.State == ClientState.Disconnecting || this.State == ClientState.Uninitialized) { this.CurrentRoom = null; // players get cleaned up inside this, too, except LocalPlayer (which we keep) } // when we leave the master, we clean up the rooms list (which might be updated by the lobby when we join again) if (this.Server == ServerConnection.MasterServer || this.State == ClientState.Disconnecting || this.State == ClientState.Uninitialized) { this.RoomInfoList.Clear(); } }
/// <summary> /// Joins a room by roomName. If this client returns to the room, set the previously used Player.ID as actorNumber. /// </summary> /// <remarks> /// This method is useful when you are using a lobby to list rooms and know their names. /// A room's name has to be unique (per region and game version), so it does not matter which lobby it's in. /// /// If this client returns to the room, set the previously used Player.ID as actorNumber. /// When you are using Custom Authentication with unique user IDs, the server will use the userID /// to find the previously assigned actorNumber in the room. /// /// For turnbased games, this is especially useful as rooms can be continued after hours or days. /// To return to a room, set the actorNumber to anything but 0. It's best practice to use -1 with /// Custom Authentication and unique user accounts. /// /// If the room is full, closed or not existing, this will fail. Override this class and implement /// OnOperationResponse(OperationResponse operationResponse) to get the errors. /// /// OpJoinRoom can only be called while the client is connected to a Master Server. /// You should check LoadBalancingClient.Server and LoadBalancingClient.IsConnectedAndReady before calling this method. /// Alternatively, check the returned bool value. /// /// While the server is joining the game, the State will be ClientState.Joining. /// It's set immediately when this method sends the Operation. /// /// If successful, the LoadBalancingClient will get a Game Server Address and use it automatically /// to switch servers and join the room. When you're in the room, this client's State will become /// ClientState.Joined (both, for joining or creating it). /// Set a OnStateChangeAction method to check for states. /// /// When joining a room, this client's Player Custom Properties will be sent to the room. /// Use LocalPlayer.SetCustomProperties to set them, even while not yet in the room. /// Note that the player properties will be cached locally and sent to any next room you would join, too. /// /// It's usually better to use OpJoinOrCreateRoom for invitations. /// Then it does not matter if the room is already setup. /// </remarks> /// <param name="roomName">The name of the room to join. Must be existing already, open and non-full or can't be joined.</param> /// <param name="actorNumber">When returning to a room, use a non-0 value. For Turnbased games, set the previously assigned Player.ID or -1 when using Custom Authentication.</param> /// <returns>If the operation could be sent currently (requires connection to Master Server).</returns> public bool OpJoinRoom(string roomName, int actorNumber) { this.State = ClientState.Joining; this.lastJoinType = JoinType.JoinRoom; this.lastJoinActorNumber = actorNumber; this.createRoomOptions = new RoomOptions(); this.CurrentRoom = CreateRoom(roomName, this.createRoomOptions); Hashtable playerPropsToSend = null; if (this.Server == ServerConnection.GameServer) { playerPropsToSend = this.LocalPlayer.AllProperties; } bool onGameServer = this.Server == ServerConnection.GameServer; return this.loadBalancingPeer.OpJoinRoom(roomName, playerPropsToSend, actorNumber, this.createRoomOptions, null, false, onGameServer); }
/// <summary>Internal "factory" method to create a room-instance.</summary> protected internal virtual Room CreateRoom(string roomName, RoomOptions opt) { if (opt == null) { opt = new RoomOptions(); } Room r = new Room(roomName, opt); return r; }
/// <summary> /// Joins a specific room by name. If the room does not exist (yet), it will be created implicitly. /// </summary> /// <remarks> /// Unlike OpJoinRoom, this operation does not fail if the room does not exist. /// This can be useful when you send invitations to a room before actually creating it: /// Any invited player (whoever is first) can call this and on demand, the room gets created implicitly. /// /// If you set room properties in RoomOptions, they get ignored when the room is existing already. /// This avoids changing the room properties by late joining players. Only when the room gets created, /// the RoomOptions are set in this case. /// /// If this client returns to the room, set the previously used Player.ID as actorNumber. /// When you are using Custom Authentication with unique user IDs, the server will use the userID /// to find the previously assigned actorNumber in the room. /// /// For turnbased games, this is especially useful as rooms can be continued after hours or days. /// To return to a room, set the actorNumber to anything but 0. It's best practice to use -1 with /// Custom Authentication and unique user accounts. /// /// If the room is full or closed, this will fail. Override this class and implement /// OnOperationResponse(OperationResponse operationResponse) to get the errors. /// /// This method can only be called while the client is connected to a Master Server. /// You should check LoadBalancingClient.Server and LoadBalancingClient.IsConnectedAndReady before calling this method. /// Alternatively, check the returned bool value. /// /// While the server is joining the game, the State will be ClientState.Joining. /// It's set immediately when this method sends the Operation. /// /// If successful, the LoadBalancingClient will get a Game Server Address and use it automatically /// to switch servers and join the room. When you're in the room, this client's State will become /// ClientState.Joined (both, for joining or creating it). /// Set a OnStateChangeAction method to check for states. /// /// When entering the room, this client's Player Custom Properties will be sent to the room. /// Use LocalPlayer.SetCustomProperties to set them, even while not yet in the room. /// Note that the player properties will be cached locally and sent to any next room you would join, too. /// </remarks> /// <param name="roomName">The name of the room to join (might be created implicitly).</param> /// <param name="actorNumber">When returning to a room, use a non-0 value. For Turnbased games, set the previously assigned Player.ID or -1 when using Custom Authentication.</param> /// <param name="roomOptions">Contains the parameters and properties of the new room. See RoomOptions class for a description of each.</param> /// <param name="lobby">Typed lobby to be used if the roomname is not in use (and room gets created). If != null, it will also set CurrentLobby.</param> /// <returns>If the operation could be sent currently (requires connection to Master Server).</returns> public bool OpJoinOrCreateRoom(string roomName, int actorNumber, RoomOptions roomOptions, TypedLobby lobby) { if (roomOptions == null) { roomOptions = new RoomOptions(); } this.State = ClientState.Joining; this.lastJoinType = JoinType.JoinOrCreateRoom; this.lastJoinActorNumber = actorNumber; this.createRoomOptions = roomOptions; this.CurrentRoom = CreateRoom(roomName, roomOptions); Hashtable playerPropsToSend = null; if (this.Server == ServerConnection.GameServer) { playerPropsToSend = this.LocalPlayer.AllProperties; } if (lobby != null) this.CurrentLobby = lobby; bool onGameServer = this.Server == ServerConnection.GameServer; return this.loadBalancingPeer.OpJoinRoom(roomName, playerPropsToSend, actorNumber, roomOptions, lobby, true, onGameServer); }
/// <summary>Operation to join a random room if available. You can use room properties to filter accepted rooms.</summary> /// <remarks> /// You can use expectedCustomRoomProperties and expectedMaxPlayers as filters for accepting rooms. /// If you set expectedCustomRoomProperties, a room must have the exact same key values set at Custom Properties. /// You need to define which Custom Room Properties will be available for matchmaking when you create a room. /// See: OpCreateRoom(string roomName, RoomOptions roomOptions, TypedLobby lobby) /// /// This operation fails if no rooms are fitting or available (all full, closed or not visible). /// Override this class and implement OnOperationResponse(OperationResponse operationResponse). /// /// OpJoinRandomRoom can only be called while the client is connected to a Master Server. /// You should check LoadBalancingClient.Server and LoadBalancingClient.IsConnectedAndReady before calling this method. /// Alternatively, check the returned bool value. /// /// While the server is looking for a game, the State will be Joining. /// It's set immediately when this method sent the Operation. /// /// If successful, the LoadBalancingClient will get a Game Server Address and use it automatically /// to switch servers and join the room. When you're in the room, this client's State will become /// ClientState.Joined (both, for joining or creating it). /// Set a OnStateChangeAction method to check for states. /// /// When joining a room, this client's Player Custom Properties will be sent to the room. /// Use LocalPlayer.SetCustomProperties to set them, even while not yet in the room. /// Note that the player properties will be cached locally and sent to any next room you would join, too. /// /// The parameter lobby can be null (using the defaul lobby) or a typed lobby you make up. /// Lobbies are created on the fly, as required by the clients. If you organize matchmaking with lobbies, /// keep in mind that they also fragment your matchmaking. Using more lobbies will put less rooms in each. /// /// The parameter sqlLobbyFilter can only be combined with the LobbyType.SqlLobby. In that case, it's used /// to define a sql-like "WHERE" clause for filtering rooms. This is useful for skill-based matchmaking e.g.. /// /// More about matchmaking: /// http://doc.photonengine.com/en/realtime/current/reference/matchmaking-and-lobby /// </remarks> /// <param name="expectedCustomRoomProperties">Optional. A room will only be joined, if it matches these custom properties (with string keys).</param> /// <param name="expectedMaxPlayers">Filters for a particular maxplayer setting. Use 0 to accept any maxPlayer value.</param> /// <param name="matchmakingMode">Selects one of the available matchmaking algorithms. See MatchmakingMode enum for options.</param> /// <param name="lobby">The lobby in which to find a room. Use null for default lobby.</param> /// <param name="sqlLobbyFilter">Can be used with LobbyType.SqlLobby only. This is a "where" clause of a sql statement. Use null for random game.</param> /// <returns>If the operation could be sent currently (requires connection to Master Server).</returns> public bool OpJoinRandomRoom(Hashtable expectedCustomRoomProperties, byte expectedMaxPlayers, MatchmakingMode matchmakingMode, TypedLobby lobby, string sqlLobbyFilter) { if (lobby == null ) { lobby = TypedLobby.Default; } this.State = ClientState.Joining; this.lastJoinType = JoinType.JoinRandomRoom; this.lastJoinActorNumber = 0; this.CurrentRoom = CreateRoom(null, new RoomOptions()); Hashtable playerPropsToSend = null; if (this.Server == ServerConnection.GameServer) { playerPropsToSend = this.LocalPlayer.AllProperties; } this.CurrentLobby = lobby; return this.loadBalancingPeer.OpJoinRandomRoom(expectedCustomRoomProperties, expectedMaxPlayers, playerPropsToSend, matchmakingMode, lobby, sqlLobbyFilter); }
public bool OpCreateRoom(string roomName, bool isVisible, bool isOpen, byte maxPlayers, Hashtable customGameProperties, string[] propsListedInLobby, string lobbyName, LobbyType lobbyType, int playerTtl, int roomTtl) { this.State = ClientState.Joining; this.lastJoinType = JoinType.CreateRoom; this.lastJoinActorNumber = 0; this.createRoomOptions = new RoomOptions() { IsVisible = isVisible, IsOpen = isOpen, MaxPlayers = maxPlayers, PlayerTtl = playerTtl, EmptyRoomTtl = roomTtl, CleanupCacheOnLeave = true, CustomRoomProperties = customGameProperties, CustomRoomPropertiesForLobby = propsListedInLobby }; this.CurrentRoom = this.CreateRoom(roomName, this.createRoomOptions); Hashtable playerPropsToSend = null; if (this.Server == ServerConnection.GameServer) { playerPropsToSend = this.LocalPlayer.AllProperties; } this.CurrentLobby = new TypedLobby(lobbyName, lobbyType); bool onGameServer = this.Server == ServerConnection.GameServer; return this.loadBalancingPeer.OpCreateRoom(roomName, this.createRoomOptions, new TypedLobby(lobbyName, lobbyType), playerPropsToSend, onGameServer); }
/// <summary> /// Creates a new room on the server (or fails if the name is already in use). /// </summary> /// <remarks> /// If you don't want to create a unique room-name, pass null or "" as name and the server will assign a /// roomName (a GUID as string). Room names are unique. /// /// A room will be attached to the specified lobby. Use null as lobby to attach the /// room to the lobby you are now in. If you are in no lobby, the default lobby is used. /// /// Multiple lobbies can help separate players by map or skill or game type. Each room can only be found /// in one lobby (no matter if defined by name and type or as default). /// /// This method can only be called while the client is connected to a Master Server. /// You should check LoadBalancingClient.Server and LoadBalancingClient.IsConnectedAndReady before calling this method. /// Alternatively, check the returned bool value. /// /// Even when sent, the Operation will fail (on the server) if the roomName is in use. /// Override this class and implement OnOperationResponse(OperationResponse operationResponse) to get the errors. /// /// /// While the server is creating the game, the State will be ClientState.Joining. /// The state Joining is used because the client is on the way to enter a room (no matter if joining or creating). /// It's set immediately when this method sends the Operation. /// /// If successful, the LoadBalancingClient will get a Game Server Address and use it automatically /// to switch servers and enter the room. When you're in the room, this client's State will become /// ClientState.Joined (both, for joining or creating it). /// Set a OnStateChangeAction method to check for states. /// /// When entering the room, this client's Player Custom Properties will be sent to the room. /// Use LocalPlayer.SetCustomProperties to set them, even while not yet in the room. /// Note that the player properties will be cached locally and sent to any next room you would join, too. /// </remarks> /// <param name="roomName">The name to create a room with. Must be unique and not in use or can't be created. If null, the server will assign a GUID as name.</param> /// <param name="roomOptions">Contains the parameters and properties of the new room. See RoomOptions class for a description of each.</param> /// <param name="lobby">The lobby (name and type) in which to create the room. Null uses the current lobby or the default lobby (if not in a lobby).</param> /// <returns>If the operation could be sent currently (requires connection to Master Server).</returns> public bool OpCreateRoom(string roomName, RoomOptions roomOptions, TypedLobby lobby) { this.State = ClientState.Joining; this.lastJoinType = JoinType.CreateRoom; this.lastJoinActorNumber = 0; this.createRoomOptions = roomOptions; this.CurrentRoom = this.CreateRoom(roomName, roomOptions); Hashtable playerPropsToSend = null; if (this.Server == ServerConnection.GameServer) { playerPropsToSend = this.LocalPlayer.AllProperties; } this.CurrentLobby = lobby; bool onGameServer = this.Server == ServerConnection.GameServer; return this.loadBalancingPeer.OpCreateRoom(roomName, roomOptions, lobby, playerPropsToSend, onGameServer); }
void OnJoinRoom(Room room) { Debug.Log("joined game " + room.Name); CurrentState = EntryState.WaitingForOpponent; }
/// <summary> /// Joins a room by name and sets this player's properties. /// </summary> /// <remarks>This override sets the state of the client.</remarks> /// <param name="roomName">The name of the room to join. Must be existing already, open and non-full or can't be joined.</param> /// <returns>If the operation could be sent (has to be connected).</returns> public bool OpJoinRoom(string roomName) { this.State = ClientState.Joining; this.lastJoinType = JoinType.JoinRoom; this.CurrentRoom = CreateRoom(roomName); Hashtable playerPropsToSend = null; if (this.server == ServerConnection.GameServer) { playerPropsToSend = this.LocalPlayer.AllProperties; } return this.loadBalancingPeer.OpJoinRoom(roomName, playerPropsToSend); }
/// <summary> /// Operation to join a random, available room. /// This operation fails if all rooms are closed or full. /// If successful, the result contains a gameserver address and the name of some room. /// </summary> /// <remarks>This override sets the state of the client.</remarks> /// <param name="expectedCustomRoomProperties">Optional. A room will only be joined, if it matches these custom properties (with string keys).</param> /// <param name="expectedMaxPlayers">Filters for a particular maxplayer setting. Use 0 to accept any maxPlayer value.</param> /// <param name="matchmakingMode">Selects one of the available matchmaking algorithms. See MatchmakingMode enum for options.</param> /// <returns>If the operation could be sent currently (requires connection).</returns> public bool OpJoinRandomRoom(Hashtable expectedCustomRoomProperties, byte expectedMaxPlayers, MatchmakingMode matchmakingMode) { this.State = ClientState.Joining; this.lastJoinType = JoinType.JoinRandomRoom; this.CurrentRoom = CreateRoom(null); Hashtable playerPropsToSend = null; if (this.server == ServerConnection.GameServer) { playerPropsToSend = this.LocalPlayer.AllProperties; } return this.loadBalancingPeer.OpJoinRandomRoom(expectedCustomRoomProperties, expectedMaxPlayers, playerPropsToSend, matchmakingMode); }
/// <summary> /// Creates a new room on the server (or fails when the name is already taken). /// </summary> /// <remarks> /// This override sets the state of the client. /// /// The response depends on the server the peer is connected to: /// Master will return a Game Server to connect to. /// Game Server will return the Room's data. /// This is an async request which triggers a OnOperationResponse() call. /// </remarks> /// <param name="roomName">The name to create a room with. Must be unique and not in use or can't be created. If null, the server will assign a GUID as name.</param> /// <param name="isVisible">Shows the room in the lobby's room list.</param> /// <param name="isOpen">Keeps players from joining the room (or opens it to everyone).</param> /// <param name="maxPlayers">Max players before room is considered full (but still listed).</param> /// <param name="customGameProperties">Custom properties to apply to the room on creation (use string-typed keys but short ones).</param> /// <param name="propsListedInLobby">Defines the custom room properties that get listed in the lobby. Null defaults to "none", a string[0].</param> /// <returns>If the operation could be sent (has to be connected).</returns> public bool OpCreateRoom(string roomName, bool isVisible, bool isOpen, byte maxPlayers, Hashtable customGameProperties, string[] propsListedInLobby) { this.State = ClientState.Joining; this.lastJoinType = JoinType.CreateRoom; this.CurrentRoom = this.CreateRoom(roomName, isVisible, isOpen, maxPlayers, customGameProperties, propsListedInLobby); Hashtable playerPropsToSend = null; if (this.server == ServerConnection.GameServer) { playerPropsToSend = this.LocalPlayer.AllProperties; } return this.loadBalancingPeer.OpCreateRoom(roomName, isVisible, isOpen, maxPlayers, customGameProperties, propsListedInLobby, playerPropsToSend); }
/// <summary> /// Called internally, when a game was joined or created on the game server. /// This reads the response, finds out the local player's actorNumber (a.k.a. Player.ID) and applies properties of the room and players. /// </summary> /// <param name="operationResponse">Contains the server's response for an operation called by this peer.</param> private void GameEnteredOnGameServer(OperationResponse operationResponse) { if (operationResponse.ReturnCode != 0) { switch (operationResponse.OperationCode) { case OperationCode.CreateGame: this.DebugReturn(DebugLevel.ERROR, "Create failed on GameServer. Changing back to MasterServer. ReturnCode: " + operationResponse.ReturnCode); break; case OperationCode.JoinGame: case OperationCode.JoinRandomGame: this.DebugReturn(DebugLevel.ERROR, "Join failed on GameServer. Changing back to MasterServer."); if (operationResponse.ReturnCode == ErrorCode.GameDoesNotExist) { this.DebugReturn(DebugLevel.INFO, "Most likely the game became empty during the switch to GameServer."); } // TODO: add callback to join failed break; } this.DisconnectToReconnect(); return; } this.CurrentRoom = this.CreateRoom(this.enterRoomParamsCache.RoomName, this.enterRoomParamsCache.RoomOptions); this.CurrentRoom.LoadBalancingClient = this; this.CurrentRoom.IsLocalClientInside = true; this.State = ClientState.Joined; // TODO: maybe this set should be done later (when the room is fully setup with props and all) if (operationResponse.Parameters.ContainsKey(ParameterCode.ActorList)) { int[] actorsInRoom = (int[])operationResponse.Parameters[ParameterCode.ActorList]; this.UpdatedActorList(actorsInRoom); } // the local player's actor-properties are not returned in join-result. add this player to the list int localActorNr = (int)operationResponse[ParameterCode.ActorNr]; this.ChangeLocalID(localActorNr); Hashtable actorProperties = (Hashtable)operationResponse[ParameterCode.PlayerProperties]; Hashtable gameProperties = (Hashtable)operationResponse[ParameterCode.GameProperties]; this.ReadoutProperties(gameProperties, actorProperties, 0); switch (operationResponse.OperationCode) { case OperationCode.CreateGame: // TODO: add callback "game created" break; case OperationCode.JoinGame: case OperationCode.JoinRandomGame: // TODO: add callback "game joined" break; } }