protected bool JoinApplyGameStateChanges(HivePeer peer, JoinGameRequest joinRequest, SendParameters sendParameters, out Actor actor) { var isCreatingGame = false; var isNewGame = false; if (peer.JoinStage == HivePeer.JoinStages.CreatingOrLoadingGame) { isCreatingGame = true; if (this.CheckBeforeJoinThisIsNewCreatedRoom(joinRequest)) { isNewGame = true; this.ApplyGameProperties(joinRequest); } else { this.CopyGamePropertiesForMasterUpdate(joinRequest); } } actor = null; peer.JoinStage = HivePeer.JoinStages.ConvertingParams; if (this.IsDisposed) { // join arrived after being disposed - repeat join operation if (Log.IsWarnEnabled) { Log.WarnFormat("Join operation on disposed game. GameName={0}", this.Name); } return false; } if (!this.ConvertParamsAndValidateGame(peer, joinRequest, sendParameters)) { return false; } peer.JoinStage = HivePeer.JoinStages.CheckingCacheSlice; if (joinRequest.CacheSlice.HasValue && !this.EventCache.HasSlice(joinRequest.CacheSlice.Value)) { var msg = string.Format(HiveErrorMessages.CacheSliceNoAviable, joinRequest.CacheSlice); this.SendErrorResponse(peer, joinRequest.OperationCode, ErrorCode.OperationInvalid, msg, sendParameters); joinRequest.OnJoinFailed(ErrorCode.OperationInvalid, msg); if (Log.IsWarnEnabled) { Log.WarnFormat("JoinApplyGameStateChanges: Game '{0}' userId '{1}' failed to join. msg:{2} -- peer:{3}", this.Name, peer.UserId, msg, peer); } return false; } peer.JoinStage = HivePeer.JoinStages.AddingActor; ErrorCode errorcode; string reason; // create an new actor bool isNewActor; if (this.TryAddPeerToGame(peer, joinRequest.ActorNr, out actor, out isNewActor, out errorcode, out reason, joinRequest) == false) { this.SendErrorResponse(peer, joinRequest.OperationCode, errorcode, reason, sendParameters); joinRequest.OnJoinFailed(errorcode, reason); if (Log.IsWarnEnabled) { Log.WarnFormat("JoinApplyGameStateChanges: Game '{0}' userId '{1}' failed to join. msg:{2} -- peer:{3}", this.Name, peer.UserId, reason, peer); } return false; } // check if a room removal is in progress and cancel it if so if (this.RemoveTimer != null) { this.RemoveTimer.Dispose(); this.RemoveTimer = null; } if (this.MasterClientId == 0) { this.UpdateMasterClientId(); } if (Log.IsDebugEnabled) { Log.DebugFormat("JoinApplyGameStateChanges: Actor {0} is added. MasterClientId is {1}", actor.ActorNr, this.MasterClientId); } peer.JoinStage = HivePeer.JoinStages.CheckAfterJoinParams; // set game properties for join from the first actor (game creator) if (isNewGame) { this.DeleteCacheOnLeave = joinRequest.DeleteCacheOnLeave; this.SuppressRoomEvents = joinRequest.SuppressRoomEvents; if (this.MaxEmptyRoomTTL < joinRequest.EmptyRoomLiveTime) { var msg = string.Format(HiveErrorMessages.MaxTTLExceeded, joinRequest.EmptyRoomLiveTime, MaxEmptyRoomTTL); this.SendErrorResponse(peer, joinRequest.OperationCode, ErrorCode.OperationInvalid, msg, sendParameters); joinRequest.OnJoinFailed(ErrorCode.OperationInvalid, msg); if (Log.IsWarnEnabled) { Log.WarnFormat("Game '{0}' userId '{1}' failed to create. msg:{2} -- peer:{3}", this.Name, peer.UserId, msg, peer); } return false; } this.EmptyRoomLiveTime = joinRequest.EmptyRoomLiveTime; this.PlayerTTL = joinRequest.PlayerTTL; this.CheckUserOnJoin = joinRequest.CheckUserOnJoin; this.PublishUserId = joinRequest.PublishUserId; if (joinRequest.GameProperties != null) { this.Properties.SetProperties(joinRequest.GameProperties); } if (joinRequest.AddUsers != null) { this.Properties.Set((byte)GameParameter.ExpectedUsers, joinRequest.AddUsers); } } if (Log.IsDebugEnabled) { if (isCreatingGame) { Log.DebugFormat( "{0} Game - name={2}, lobyName={3}, lobbyType={4}, maxPlayers={5}, IsOpen={6}, IsVisible={7}, EmptyRoomLiveTime={8}, PlayerTTL={9}, CheckUserOnJoin={10}, PublishUserId={11}, ExpectedUsers={12}", isNewGame ? "Created" : "Loaded", // 0 "", // 1 this.Name, // 2 this.LobbyId, this.LobbyType, this.MaxPlayers, this.IsOpen, this.IsVisible, this.EmptyRoomLiveTime, this.PlayerTTL, this.CheckUserOnJoin, this.PublishUserId, joinRequest.AddUsers != null ? joinRequest.AddUsers.Aggregate((current, next) => current + ", " + next) : "" ); } } if (!this.AddExpectedUsers(joinRequest)) { this.SendErrorResponse(peer, joinRequest.OperationRequest.OperationCode, ErrorCode.InternalServerError, HiveErrorMessages.CantAddSlots, sendParameters); joinRequest.OnJoinFailed(ErrorCode.InternalServerError, HiveErrorMessages.CantAddSlots); if (Log.IsWarnEnabled) { Log.WarnFormat("Game '{0}' userId '{1}' failed to join. msg:{2}", this.Name, peer.UserId, HiveErrorMessages.CantAddSlots); } return false; } peer.JoinStage = HivePeer.JoinStages.ApplyActorProperties; // set custom actor properties if defined if (joinRequest.ActorProperties != null) { // this is set by the server only joinRequest.ActorProperties.Remove((byte)ActorParameter.IsInactive); joinRequest.ActorProperties.Remove((byte)ActorParameter.UserId); actor.Properties.SetProperties(joinRequest.ActorProperties); } if (!isNewGame && this.ModifyExpectedUsersProperty(joinRequest.AddUsers)) { const byte propertyId = (byte)GameParameter.ExpectedUsers; var propertiesChangedEvent = new PropertiesChangedEvent(0) { Properties = new Hashtable { {propertyId, this.Properties.GetProperty(propertyId).Value} } }; this.PublishEvent(propertiesChangedEvent, this.Actors, sendParameters); // shouldn't we publish this in the next JoinStage2? } return true; }
private bool ConvertParamsAndValidateGame(HivePeer peer, JoinGameRequest joinRequest, SendParameters sendParameters) { // ValidateGame checks isOpen and maxplayers // and does not apply to rejoins if (this.CheckBeforeJoinThisIsNewCreatedRoom(joinRequest)) { return true; } if (joinRequest.IsRejoining) { string errorMsg; ErrorCode errorcode; if (this.CheckUserOnJoin) { if (this.ActorsManager.GetActorByUserId(peer.UserId) != null) { return true; } errorcode = ErrorCode.JoinFailedWithRejoinerNotFound; errorMsg = HiveErrorMessages.UserNotFound; } else { if (this.ActorsManager.GetActorByNumber(joinRequest.ActorNr) != null) { return true; } errorcode = ErrorCode.JoinFailedWithRejoinerNotFound; errorMsg = string.Format(HiveErrorMessages.ActorNotFound, joinRequest.ActorNr); } if (joinRequest.JoinMode == JoinModes.RejoinOnly) { this.SendErrorResponse(peer, joinRequest.OperationCode, errorcode, errorMsg, sendParameters); joinRequest.OnJoinFailed(errorcode, errorMsg); if (Log.IsWarnEnabled) { Log.WarnFormat("ConvertParamsAndValidateGame: Game '{0}' userId '{1}' failed to join. msg:'{2}' (JoinMode={3}) -- peer:{4}", this.Name, peer.UserId, errorMsg, joinRequest.JoinMode, peer); } return false; } //TBD - I suggest beeing even stricter if the room is configured with expected users - we don't support JoinMode2! if (joinRequest.JoinMode == JoinModes.RejoinOrJoin && this.ActorsManager.IsExpectedUser(peer.UserId)) { errorMsg = HiveErrorMessages.CanNotUseRejoinOrJoinIfPlayerExpected; this.SendErrorResponse(peer, joinRequest.OperationCode, ErrorCode.OperationDenied, errorMsg, sendParameters); joinRequest.OnJoinFailed(ErrorCode.OperationDenied, errorMsg); if (Log.IsWarnEnabled) { Log.WarnFormat("Game '{0}' userId '{1}' failed to join. msg:{2} (JoinMode={3}) -- peer:{4}", this.Name, peer.UserId, errorMsg, joinRequest.JoinMode, peer); } return false; } } return this.ValidateGame(peer, joinRequest, sendParameters); }
protected override void HandleJoinGameOperation(HivePeer peer, SendParameters sendParameters, JoinGameRequest joinGameRequest) { if (this.isClosed) { if (!this.CheckGameCanBeCreated(peer, joinGameRequest)) { return; } if (!this.ReinitGame()) { this.SendErrorResponse(peer, joinGameRequest.OperationCode, ErrorCode.InternalServerError, HiveErrorMessages.ReinitGameFailed, sendParameters); joinGameRequest.OnJoinFailed(ErrorCode.InternalServerError, HiveErrorMessages.ReinitGameFailed); this.JoinFailureHandler(LeaveReason.ServerDisconnect, peer, joinGameRequest); if (Log.IsWarnEnabled) { Log.WarnFormat("Game '{0}' userId '{1}' failed to join. msg:{2}", this.Name, peer.UserId, HiveErrorMessages.ReinitGameFailed); } return; } } //TBD do we still need this? string msg; if (!this.ValidatePlugin(joinGameRequest, out msg)) { this.SendErrorResponse(peer, joinGameRequest.OperationCode, ErrorCode.PluginMismatch, msg, sendParameters); joinGameRequest.OnJoinFailed(ErrorCode.InternalServerError, HiveErrorMessages.ReinitGameFailed); this.JoinFailureHandler(LeaveReason.ServerDisconnect, peer, joinGameRequest); if (Log.IsWarnEnabled) { Log.WarnFormat("HandleJoinGameOperation: Game '{0}' userId '{1}' failed to join. msg:{2} -- peer:{3}", this.Name, peer.UserId, msg, peer); } return; } if (this.ActorsManager.ActorNumberCounter == 0) // we were just beeing created { if (!this.CheckGameCanBeCreated(peer, joinGameRequest)) { return; } this.HandleCreateGameOperationInt(peer, sendParameters, joinGameRequest, true); } else { peer.SetPrivateCustomTypeCache(this.customTypeCache); RequestHandler handler = () => { try { return this.ProcessBeforeJoinGame(joinGameRequest, sendParameters, peer); } catch (Exception e) { Log.ErrorFormat("Exception: {0}", e); throw; } }; var info = new BeforeJoinGameCallInfo(this.PendingPluginContinue, this.callEnv) { Request = joinGameRequest, UserId = peer.UserId, Nickname = joinGameRequest.GetNickname(), Handler = handler, Peer = peer, SendParams = sendParameters, OnFail = (onFailMsg, errorData) => { this.allowSetGameState = false; joinGameRequest.OnJoinFailed(ErrorCode.PluginReportedError, onFailMsg); this.OnJoinFailHandler(LeaveReason.ServerDisconnect, onFailMsg, errorData, peer, sendParameters, joinGameRequest); } }; try { this.Plugin.BeforeJoin(info); } catch (Exception e) { this.Plugin.ReportError(Photon.Hive.Plugin.ErrorCodes.UnhandledException, e); } } }
protected bool ValidateGame(HivePeer peer, JoinGameRequest joinGameRequest, SendParameters sendParameters) { // check if the game is open if (this.IsOpen == false) { this.SendErrorResponse(peer, joinGameRequest.OperationCode, ErrorCode.GameClosed, HiveErrorMessages.GameClosed, sendParameters); joinGameRequest.OnJoinFailed(ErrorCode.GameClosed, HiveErrorMessages.GameClosed); if (Log.IsWarnEnabled) { Log.WarnFormat("ValidateGame: Game '{0}' userId '{1}' failed to join. msg:{2} -- peer: {3}", this.Name, peer.UserId, HiveErrorMessages.GameClosed, peer); } return false; } var am = this.ActorsManager; var isGameFull = am.ActorsCount + am.InactiveActorsCount + am.YetExpectedUsersCount >= this.MaxPlayers; // check if the maximum number of players has already been reached if (this.MaxPlayers > 0 && isGameFull && !this.ActorsManager.IsExpectedUser(peer.UserId)) { this.SendErrorResponse(peer, joinGameRequest.OperationCode, ErrorCode.GameFull, HiveErrorMessages.GameFull, sendParameters); joinGameRequest.OnJoinFailed(ErrorCode.GameFull, HiveErrorMessages.GameFull); if (Log.IsWarnEnabled) { Log.WarnFormat("ValidateGame: Game '{0}' userId '{1}' failed to join. msg:{2} -- peer:{3}", this.Name, peer.UserId, HiveErrorMessages.GameFull, peer); } return false; } return true; }
private bool CheckGameCanBeCreated(HivePeer peer, JoinGameRequest joinGameRequest) { if (joinGameRequest.OperationCode == (byte)OperationCode.Join || joinGameRequest.JoinMode == JoinModes.CreateIfNotExists || joinGameRequest.JoinMode == JoinModes.RejoinOrJoin // for backwards compatibility - it seams some games expect this behavior - ISSUE: Codemasters uses RejoinOrJoin and now expects this to return false! || this.Plugin.IsPersistent) { return true; } this.SendErrorResponse(peer, joinGameRequest.OperationCode, ErrorCode.GameIdNotExists, HiveErrorMessages.GameIdDoesNotExist, new SendParameters()); if (Log.IsWarnEnabled) { Log.WarnFormat( "CheckGameCanBeCreated: Game '{0}' userId '{1}' failed to join game. msg:'{2}' (JoinMode={3}) -- peer:{4}", this.Name, peer.UserId, HiveErrorMessages.GameIdDoesNotExist, joinGameRequest.JoinMode, peer); } joinGameRequest.OnJoinFailed(ErrorCode.GameIdNotExists, HiveErrorMessages.GameIdDoesNotExist); this.JoinFailureHandler(LeaveReason.ServerDisconnect, peer, joinGameRequest); return false; }