示例#1
0
        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);
        }
示例#2
0
        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);
        }
示例#3
0
        //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;
            }
        }
示例#4
0
 protected virtual void DeactivateActor(Actor actor)
 {
 }
示例#5
0
 protected override void CleanupActor(Actor actor)
 {
     base.CleanupActor(actor);
     this.NotifyMasterUserLeft(actor.UserId);
 }
示例#6
0
 public void OnActorRemoved(Actor actor)
 {
     this.CleanupActor(actor);
 }
示例#7
0
 public virtual void RemoveInactiveActor(Actor actor)
 {
     this.ActorsManager.RemoveInactiveActor(this, actor);
 }
示例#8
0
 private bool ProcessRemoveInactiveActor(Actor actor)
 {
     base.RemoveInactiveActor(actor);
     return true;
 }
示例#9
0
        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);
            }
        }
示例#10
0
 protected virtual bool ProcessRaiseEvent(HivePeer peer, RaiseEventRequest raiseEventRequest, SendParameters sendParameters, Actor actor)
 {
     return this.RaiseEventOperationHandler(peer, raiseEventRequest, sendParameters, actor);
 }
示例#11
0
 private void ApplyBanning(Actor actor)
 {
     this.ActorsManager.AddToExcludeList(actor.UserId, RemoveActorReason.Banned);
     this.OnActorBanned(actor);
 }
示例#12
0
 protected virtual void OnActorBanned(Actor actor)
 {
 }
示例#13
0
        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);
        }
示例#14
0
 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);
 }
示例#15
0
 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;
 }
示例#16
0
        /// <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());
                }
            }
        }
示例#17
0
 public void OnActorDeactivated(Actor actor)
 {
     // player disconnected
     this.PublishEventDiconnected(actor, this.UpdateMasterClientId(actor));
     this.DeactivateActor(actor);
 }
示例#18
0
        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;
        }
示例#19
0
        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());
            }
        }
示例#20
0
 /// <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);
 }
示例#21
0
        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));
        }
示例#22
0
 /// <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);
 }
示例#23
0
        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;
        }
示例#24
0
 /// <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);
 }