private void AddActorPropertiesToResponse(GetPropertiesRequest getPropertiesRequest, Actor actor, GetPropertiesResponse response) { if (actor == null) { return; } var actorProperties = actor.Properties.GetProperties(getPropertiesRequest.ActorPropertyKeys); var addUserId = getPropertiesRequest.ActorPropertyKeys == null ? this.PublishUserId : getPropertiesRequest.ActorPropertyKeys.Contains(ActorParameter.UserId); if (addUserId) { actorProperties.Add((byte) ActorParameter.UserId, actor.UserId); } response.ActorProperties.Add(actor.ActorNr, actorProperties); }
protected bool UpdateEventCache(Actor actor, byte eventCode, object data, byte cacheOp, out string msg) { msg = null; CustomEvent customEvent; switch (cacheOp) { case (byte)CacheOperation.DoNotCache: return true; case (byte)CacheOperation.AddToRoomCache: customEvent = new CustomEvent(actor.ActorNr, eventCode, data); this.EventCache.AddEventToCurrentSlice(customEvent); return true; case (byte)CacheOperation.AddToRoomCacheGlobal: customEvent = new CustomEvent(0, eventCode, data); this.EventCache.AddEventToCurrentSlice(customEvent); return true; } return this.UpdateEventCache(actor, eventCode, data, (CacheOperation)cacheOp, ref msg); }
//Probably Obsolote, we don't know if developers use it. protected bool UpdateEventCache(Actor actor, byte evCode, object data, CacheOperation cacheOp, ref string msg) { // cache operations for the actor event cache currently only working with hashtable data Hashtable eventData; if (data == null || data is Hashtable) { eventData = (Hashtable)data; } else { msg = string.Format("Cache operation '{0}' requires a Hashtable as event data.", cacheOp); return false; } switch (cacheOp) { case CacheOperation.MergeCache: this.ActorEventCache.MergeEvent(actor.ActorNr, evCode, eventData); return true; case CacheOperation.RemoveCache: this.ActorEventCache.RemoveEvent(actor.ActorNr, evCode); return true; case CacheOperation.ReplaceCache: this.ActorEventCache.ReplaceEvent(actor.ActorNr, evCode, eventData); return true; default: msg = string.Format("Unknown cache operation '{0}'.", cacheOp); return false; } }
protected virtual void DeactivateActor(Actor actor) { }
protected override void CleanupActor(Actor actor) { base.CleanupActor(actor); this.NotifyMasterUserLeft(actor.UserId); }
public void OnActorRemoved(Actor actor) { this.CleanupActor(actor); }
public virtual void RemoveInactiveActor(Actor actor) { this.ActorsManager.RemoveInactiveActor(this, actor); }
private bool ProcessRemoveInactiveActor(Actor actor) { base.RemoveInactiveActor(actor); return true; }
public override void RemoveInactiveActor(Actor actor) { RequestHandler handler = () => { try { return this.ProcessRemoveInactiveActor(actor); } catch (Exception e) { Log.ErrorFormat("Exception: {0}", e); throw; } }; var info = new LeaveGameCallInfo(this.PendingPluginContinue, this.callEnv) { ActorNr = actor.ActorNr, UserId = actor.UserId, Nickname = actor.Nickname, IsInactive = false, Reason = LeaveReason.PlayerTtlTimedOut, Request = null, Handler = handler, Peer = null, SendParams = new SendParameters(), }; try { this.Plugin.OnLeave(info); } catch (Exception e) { this.Plugin.ReportError(Photon.Hive.Plugin.ErrorCodes.UnhandledException, e); } }
protected virtual bool ProcessRaiseEvent(HivePeer peer, RaiseEventRequest raiseEventRequest, SendParameters sendParameters, Actor actor) { return this.RaiseEventOperationHandler(peer, raiseEventRequest, sendParameters, actor); }
private void ApplyBanning(Actor actor) { this.ActorsManager.AddToExcludeList(actor.UserId, RemoveActorReason.Banned); this.OnActorBanned(actor); }
protected virtual void OnActorBanned(Actor actor) { }
protected override void OnActorBanned(Actor actor) { if (Log.IsDebugEnabled) { Log.DebugFormat("User {0} will be banned", actor.UserId); } var updateGameEvent = this.GetUpdateGameEvent(); updateGameEvent.ExcludedUsers = new ExcludedActorInfo[] { new ExcludedActorInfo { UserId = actor.UserId ?? string.Empty, Reason = RemoveActorReason.Banned, } }; this.UpdateGameStateOnMaster(updateGameEvent); }
protected override void DeactivateActor(Actor actor) { base.DeactivateActor(actor); // The room was not disposed because there are either players left or the // room has and EmptyRoomLiveTime set -> update game state on master. this.NotifyMasterUserDeactivated(actor.UserId); }
private int? UpdateMasterClientId(Actor actor) { if (this.MasterClientId == actor.ActorNr) { this.UpdateMasterClientId(); if (Log.IsDebugEnabled) { Log.DebugFormat("Actor {0} left. MasterClientId is {1}", actor.ActorNr, this.MasterClientId); } return this.MasterClientId; } return null; }
/// <summary> /// Sends a <see cref = "LeaveEvent" /> to all <see cref = "Actor" />s. /// </summary> /// <param name = "actor"> /// The actor which sents the event. /// </param> /// <param name="newMasterClientId"></param> protected virtual void PublishLeaveEvent(Actor actor, int? newMasterClientId) { if (this.SuppressRoomEvents) { return; } if (this.ActorsManager.ActorsCount > 0 && actor != null) { var actorNumbers = this.ActorsManager.ActorsGetActorNumbers(); var leaveEvent = new LeaveEvent(actor.ActorNr, actorNumbers.ToArray()) { MasterClientId = newMasterClientId }; if (actor.Peer == null || actor.Peer.JoinStage >= HivePeer.JoinStages.EventsPublished) { this.PublishEvent(leaveEvent, this.Actors, new SendParameters()); } } }
public void OnActorDeactivated(Actor actor) { // player disconnected this.PublishEventDiconnected(actor, this.UpdateMasterClientId(actor)); this.DeactivateActor(actor); }
protected bool RaiseEventOperationHandler(HivePeer peer, RaiseEventRequest raiseEventRequest, SendParameters sendParameters, Actor actor) { sendParameters.Flush = raiseEventRequest.Flush; if (raiseEventRequest.IsCacheSliceIndexOperation) { var msg = string.Empty; if (!this.UpdateCacheSlice(actor.Peer, raiseEventRequest.Cache, raiseEventRequest.CacheSliceIndex, ref msg)) { this.SendErrorResponse(peer, raiseEventRequest.OperationCode, ErrorCode.OperationInvalid, msg, sendParameters); if (Log.IsWarnEnabled) { Log.WarnFormat("Game '{0}' userId '{1}' failed to update Cache Slice. msg:{2} -- peer:{3}", this.Name, peer.UserId, msg, peer); } if (Log.IsWarnEnabled) { Log.Warn(msg); } } return false; } if (raiseEventRequest.IsCacheOpRemoveFromCache) { this.EventCache.RemoveEventsFromCache(raiseEventRequest); var response = new OperationResponse(raiseEventRequest.OperationRequest.OperationCode); peer.SendOperationResponse(response, sendParameters); return false; } if (raiseEventRequest.IsCacheOpRemoveFromCacheForActorsLeft) { var currentActorNumbers = this.ActorsManager.ActorsGetActorNumbers(); this.EventCache.RemoveEventsForActorsNotInList(currentActorNumbers); var response = new OperationResponse(raiseEventRequest.OperationRequest.OperationCode); peer.SendOperationResponse(response, sendParameters); return false; } // publish the custom event var customEvent = new CustomEvent(actor.ActorNr, raiseEventRequest.EvCode, raiseEventRequest.Data); var updateEventCache = false; IEnumerable<Actor> recipients; if (raiseEventRequest.Actors != null && raiseEventRequest.Actors.Length > 0) { recipients = this.ActorsManager.ActorsGetActorsByNumbers(raiseEventRequest.Actors); } else if (raiseEventRequest.Group != 0) { var group = this.GroupManager.GetActorGroup(raiseEventRequest.Group); if (group != null) { recipients = group.GetExcludedList(actor); } else { // group does not exists yet because no one joined it yet. // it's not an error to sent events to empty groups so no error response will be sent return false; } } else { switch ((ReceiverGroup)raiseEventRequest.ReceiverGroup) { case ReceiverGroup.All: recipients = this.Actors; updateEventCache = true; break; case ReceiverGroup.Others: recipients = this.ActorsManager.ActorsGetExcludedList(actor); updateEventCache = true; break; case ReceiverGroup.MasterClient: recipients = new[] { this.ActorsManager.ActorsGetActorByNumber(this.MasterClientId) }; break; default: this.SendErrorResponse(peer, raiseEventRequest.OperationCode, ErrorCode.OperationInvalid, HiveErrorMessages.InvalidReceiverGroup + raiseEventRequest.ReceiverGroup, sendParameters); if (Log.IsWarnEnabled) { Log.WarnFormat("Game '{0}' user '{1}' sent wrong receiver group. msg:{2} -- peer:{3}", this.Name, peer.UserId, HiveErrorMessages.InvalidReceiverGroup + raiseEventRequest.ReceiverGroup, peer); } return false; } } if (updateEventCache && raiseEventRequest.Cache != (byte)CacheOperation.DoNotCache) { string msg; if (!this.UpdateEventCache(actor, raiseEventRequest, out msg)) { this.SendErrorResponse(peer, raiseEventRequest.OperationCode, ErrorCode.OperationInvalid, msg, sendParameters); if (Log.IsWarnEnabled) { Log.WarnFormat("Game '{0}' user '{1}' failed to update EventCache. msg:{2} -- peer:{3}", this.Name, peer.UserId, msg, peer); } return false; } } this.PublishEvent(customEvent, recipients, sendParameters); return true; }
public void PublishEventDiconnected(Actor actor, int? newMasterClientId) { if (this.SuppressRoomEvents) { return; } if (this.ActorsManager.ActorsCount > 0 && actor != null) { // instead of ev disconnect we discussed a prop. change // decided for ev because for clients its an important state change // and they would have to filter property changes ... //var propertiesChangedEvent = new PropertiesChangedEvent(0) //{ // TargetActorNumber = actor.ActorNr, // Properties = new Hashtable() // { // {(byte)ActorParameter.IsInactive, true} // } //}; var disconnectEvent = new LeaveEvent(actor.ActorNr, isInactive: true) { MasterClientId = newMasterClientId }; this.PublishEvent(disconnectEvent, this.Actors, new SendParameters()); } }
/// <summary> /// Tries to add a <see cref="HivePeer"/> to this game instance. /// </summary> /// <param name="peer"> /// The peer to add. /// </param> /// <param name="actorNr"> /// The actor Nr. /// </param> /// <param name="actor"> /// When this method returns this out param contains the <see cref="Actor"/> associated with the <paramref name="peer"/>. /// </param> /// <param name="errorcode">returns error code if we fail to add actor</param> /// <param name="reason"> /// reason why player can not be added /// </param> /// <param name="isNewActor">returns true if actor is new</param> /// <param name="joinRequest">join request which was sent by client</param> /// <returns> /// Returns true if no actor exists for the specified peer and a new actor for the peer has been successfully added. /// The actor parameter is set to the newly created <see cref="Actor"/> instance. /// Returns false if an actor for the specified peer already exists. /// The actor parameter is set to the existing <see cref="Actor"/> for the specified peer. /// </returns> protected virtual bool TryAddPeerToGame(HivePeer peer, int actorNr, out Actor actor, out bool isNewActor, out ErrorCode errorcode, out string reason, JoinGameRequest joinRequest) { return this.ActorsManager.TryAddPeerToGame(this, peer, actorNr, out actor, out isNewActor, out errorcode, out reason, joinRequest); }
protected virtual void CleanupActor(Actor actor) { if (this.DeleteCacheOnLeave) { if (Log.IsDebugEnabled) { Log.DebugFormat("Clean up actor {0} - DeleteCacheOnLeave:", actor); } this.ActorEventCache.RemoveEventCache(actor.ActorNr); this.EventCache.RemoveEventsByActor(actor.ActorNr); } actor.RemoveGroups(new byte[0]); // raise leave event this.PublishLeaveEvent(actor, this.UpdateMasterClientId(actor)); }
/// <summary> /// Helper method of <see cref = "HandleRaiseEventOperation" />. /// Stores an event for new actors. /// </summary> /// <param name = "actor"> /// The actor. /// </param> /// <param name = "raiseEventRequest"> /// The raise event request. /// </param> /// <param name="msg"> /// Contains an error message if the method returns false. /// </param> /// <returns> /// True if <see cref = "RaiseEventRequest.Cache" /> is valid. /// </returns> protected bool UpdateEventCache(Actor actor, RaiseEventRequest raiseEventRequest, out string msg) { return this.UpdateEventCache(actor, raiseEventRequest.EvCode, raiseEventRequest.Data, raiseEventRequest.Cache, out msg); }
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; }
/// <summary> /// Publishes an event to a single actor on a specified channel. /// </summary> /// <param name = "e"> /// The event to publish. /// </param> /// <param name = "actor"> /// The <see cref = "Actor" /> who should receive the event. /// </param> /// <param name = "sendParameters"> /// The send Parameters. /// </param> protected void PublishEvent(HiveEventBase e, Actor actor, SendParameters sendParameters) { var eventData = new EventData(e.Code, e); actor.Peer.SendEvent(eventData, sendParameters); }