Exemple #1
0
        /// <inheritdoc />
        public async Task <IDisposable> AquireEntityLockAsync(NetworkEntityGuid guid)
        {
            //basically, root lock so nobody can change the entity state until we're done.
            //We lock read globally and then write for the entity

            IDisposable root  = null;
            IDisposable child = null;

            try
            {
                //TODO: It's POSSIBLE, but unlikely that the entity was removed. Or that they didn't check?
                root = await InternalGlobalLock.ReaderLockAsync().ConfigureAwait(false);

                if (!EntityRefCountingMap.ContainsKey(guid.RawGuidValue))
                {
                    throw new InvalidOperationException($"Entity: {guid} does not exist in the locking service.");
                }

                //TODO: Should we do a write lock?
                child = await EntityLockingObjectMap[guid.RawGuidValue].WriterLockAsync().ConfigureAwait(false);
            }
            catch (Exception)
            {
                throw;
            }
            finally
            {
                child?.Dispose();
                root?.Dispose();
            }

            //MUST dispose this to dispose the locks.
            return(new AggregateDisposableLock(root, child));
        }
        private static void DequeueAddAllEntities([NotNull] IDequeable <NetworkEntityGuid> interestDequeueable, [NotNull] IEntityInterestSet interestSet, bool add = true)
        {
            if (interestDequeueable == null)
            {
                throw new ArgumentNullException(nameof(interestDequeueable));
            }
            if (interestSet == null)
            {
                throw new ArgumentNullException(nameof(interestSet));
            }

            while (!interestDequeueable.isEmpty)
            {
                NetworkEntityGuid entityGuid = interestDequeueable.Dequeue();

                if (add)
                {
                    interestSet.Add(entityGuid);
                }
                else
                {
                    interestSet.Remove(entityGuid);
                }
            }
        }
Exemple #3
0
        private void InterestTriggerExit([NotNull] object sender, [NotNull] PhysicsTriggerEventArgs args)
        {
            if (sender == null)
            {
                throw new ArgumentNullException(nameof(sender));
            }
            if (args == null)
            {
                throw new ArgumentNullException(nameof(args));
            }

            GameObject rootObject = args.ColliderThatTriggered.GetRootGameObject();

            NetworkEntityGuid me = ObjectToEntityMapper.ObjectToEntityMap[args.GameObjectTriggered.transform.GetRootGameObject()];

            if (!ObjectToEntityMapper.ObjectToEntityMap.ContainsKey(rootObject))
            {
                if (Logger.IsWarnEnabled)
                {
                    Logger.Warn($"Tried to remove Entity: {rootObject.name} from Entity interest ID: {me} but does not exist. Is not owned.");
                }

                return;
            }

            OnEntityInterestChanged?.Invoke(this, new EntityInterestChangeEventArgs(me, ObjectToEntityMapper.ObjectToEntityMap[rootObject], EntityInterestChangeEventArgs.ChangeType.Exit));
        }
Exemple #4
0
        private void InterestTriggerEnter([NotNull] object sender, [NotNull] PhysicsTriggerEventArgs args)
        {
            if (sender == null)
            {
                throw new ArgumentNullException(nameof(sender));
            }
            if (args == null)
            {
                throw new ArgumentNullException(nameof(args));
            }

            GameObject rootObject = args.ColliderThatTriggered.GetRootGameObject();

            //TODO: This WON'T work if you parent the object. We NEED a better way to handle looking up the guid from collision
            //TODO: Should entites be interested in themselves?
            //Right now the way this is set up we don't check if this is the entity itself.
            //Which means an entity is always interested in itself, unless manually removed
            //because when it enters the world it will enter its own interest radius
            //This behavior MAY change.
            NetworkEntityGuid me = ObjectToEntityMapper.ObjectToEntityMap[args.GameObjectTriggered.transform.GetRootGameObject()];

            if (!ObjectToEntityMapper.ObjectToEntityMap.ContainsKey(rootObject))
            {
                if (Logger.IsWarnEnabled)
                {
                    Logger.Warn($"Tried to enter Entity: {rootObject.name} to Entity interest ID: {me} but does not exist. Is not owned.");
                }

                return;
            }

            OnEntityInterestChanged?.Invoke(this, new EntityInterestChangeEventArgs(me, ObjectToEntityMapper.ObjectToEntityMap[rootObject], EntityInterestChangeEventArgs.ChangeType.Enter));
        }
 private void ThrowIfNoEntityInterestManaged(NetworkEntityGuid entryContext, NetworkEntityGuid entityGuid)
 {
     if (!ManagedInterestCollections.ContainsKey(entryContext))
     {
         throw new InvalidOperationException($"Guid: {entityGuid} tried to enter Entity: {entryContext} interest. But Entity does not maintain interest. Does not exist in interest collection.");
     }
 }
        /// <inheritdoc />
        public bool Destroy([NotNull] PlayerSessionDeconstructionContext obj)
        {
            if (obj == null)
            {
                throw new ArgumentNullException(nameof(obj));
            }

            //If the connection doesn't own an entity then we have nothing to do here.
            if (!OwnsEntityToDestruct(obj.ConnectionId))
            {
                return(false);
            }

            NetworkEntityGuid entityGuid = ConnectionToEntityMap[obj.ConnectionId];

            //An entity exists, so we just pass it along but we also must remove it from the map afterwards.
            bool result = PlayerEntityDestructor.Destroy(new PlayerEntityDestructionContext(entityGuid));

            //We need to unregister BOTH of these collections, session collection orginally was cleanedup
            //immediately on disconnect. Now it is not and must be done here.
            ConnectionToEntityMap.Remove(obj.ConnectionId);
            SessionCollection.Unregister(obj.ConnectionId);

            return(result);
        }
Exemple #7
0
        /// <inheritdoc />
        public void RegisterCallback <TCallbackValueCastType>(NetworkEntityGuid entity, EntityDataFieldType dataField, Action <NetworkEntityGuid, EntityDataChangedArgs <TCallbackValueCastType> > callback)
            where TCallbackValueCastType : struct
        {
            //TODO: Anyway we can avoid this for registering callbacks, wasted cycles kinda
            if (!CallbackMap.ContainsKey(entity))
            {
                CallbackMap.Add(entity, new Dictionary <EntityDataFieldType, Action <int> >());
            }

            //TODO: This isn't thread safe, this whole thinjg isn't. That could be problematic
            Action <int> dataChangeEvent = newValue =>
            {
                //TODO: If we ever support original value we should change this
                //So, the callback needs to send the entity guid and the entity data change args which contain the original (not working yet) and new value.
                callback(entity, new EntityDataChangedArgs <TCallbackValueCastType>(default(TCallbackValueCastType), Unsafe.As <int, TCallbackValueCastType>(ref newValue)));
            };

            //We need to add a null action here or it will throw when we try to add the action. But if one exists we need to Delegate.Combine
            if (!CallbackMap[entity].ContainsKey(dataField))
            {
                CallbackMap[entity].Add(dataField, dataChangeEvent);
            }
            else
            {
                CallbackMap[entity][dataField] += dataChangeEvent;
            }
        }
Exemple #8
0
        /// <inheritdoc />
        public void Tick()
        {
            if (Input.GetMouseButtonDown(0))
            {
                Ray ray = CameraReference.ScreenPointToRay(Input.mousePosition);

                //TODO: We should enumerate the layers
                //5 is UI right now.
                int resultCount = Physics.RaycastNonAlloc(ray, CachedHitResults, 1000.0f, 1 << 5);                 //5th

                if (resultCount == 0)
                {
                    Debug.Log($"No clicked on entities");
                    return;
                }

                //Otherwise, we have some hits. Let's check them.
                //TODO: This is kind of slow.
                GameObject rootGameObject = CachedHitResults[0].transform.GetRootGameObject();

                if (GameObjectToEntityMappable.ObjectToEntityMap.ContainsKey(rootGameObject))
                {
                    NetworkEntityGuid entity = GameObjectToEntityMappable.ObjectToEntityMap[rootGameObject];

                    //If we actually have interacted with an entity that is on the UI layer
                    //then we need to dispatch the event.
                    Debug.Log($"Clicked on Entity: {entity.EntityType}:{entity.EntityId}");
                }
                else
                {
                    Debug.Log($"No entity. Clicked on: {rootGameObject.name}");
                }
            }
        }
Exemple #9
0
 /// <inheritdoc />
 public async Task <bool> ContainsLockingServiceForAsync(NetworkEntityGuid guid)
 {
     using (await InternalGlobalLock.ReaderLockAsync().ConfigureAwait(false))
     {
         //We don't need to check value.
         return(EntityRefCountingMap.ContainsKey(guid.RawGuidValue));
     }
 }
        /// <inheritdoc />
        protected override void HandleMovement(NetworkEntityGuid entityGuid, PathBasedMovementData data)
        {
            MovementDataMap[entityGuid]   = data;
            MovementGenerator[entityGuid] = new PathMovementGenerator(data);

            //TODO: We may not be on the main thread, so we might not be able to do this.
            MovementGenerator[entityGuid].Update(GameObjectMap[entityGuid], TimeService.CurrentRemoteTime);
        }
        /// <inheritdoc />
        public bool Remove([NotNull] NetworkEntityGuid guid)
        {
            if (guid == null)
            {
                throw new ArgumentNullException(nameof(guid));
            }

            return(_ContainedEntities.Remove(guid));
        }
        /// <inheritdoc />
        public NetworkEntityGuid Retrieve(NetworkEntityGuid key)
        {
            if (!_ContainedEntities.Contains(key))
            {
                throw new InvalidOperationException($"Provided Key: {key} does not exist in the tile.");
            }

            return(key);
        }
Exemple #13
0
 private async Task RegisterGuildOnExistingResponse(NetworkEntityGuid guid, IGroupManager groupManager, string connectionId)
 {
     if (GuildStatusMappable[guid].isSuccessful)
     {
         //TODO: don't hardcode
         await groupManager.AddToGroupAsync(connectionId, $"guild:{GuildStatusMappable[guid].GuildId}")
         .ConfigureAwait(false);
     }
 }
        /// <inheritdoc />
        public bool Contains([NotNull] NetworkEntityGuid key)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }

            return(_ContainedEntities.Contains(key));
        }
Exemple #15
0
 /// <inheritdoc />
 public TextChatEventData([NotNull] string message, [NotNull] NetworkEntityGuid sender, ChatMessageType messageType)
 {
     if (!Enum.IsDefined(typeof(ChatMessageType), messageType))
     {
         throw new InvalidEnumArgumentException(nameof(messageType), (int)messageType, typeof(ChatMessageType));
     }
     Message     = message ?? throw new ArgumentNullException(nameof(message));
     Sender      = sender ?? throw new ArgumentNullException(nameof(sender));
     MessageType = messageType;
 }
 //TODO: We need to filter in ONLY dirty movement data. Right now it resends movement data every packet but we only want to update if the data has changed.
 private AssociatedMovementData[] BuildMovementBlocks(NetworkEntityGuid guid)
 {
     return(GuidToInterestCollectionMappable[guid]
            .ContainedEntities
            //TODO: Temporarily we are not sending movement data about ourselves.
            //We also only send information about movement that is dirty from the last update we sent out.
            .Where(e => MovementDataMap.isEntryDirty(e))
            .Select(e => new AssociatedMovementData(e, MovementDataMap[e]))
            .ToArray());
 }
        /// <inheritdoc />
        public bool Unregister([NotNull] NetworkEntityGuid key)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }

            _LeavingQueue.Enqueue(key);
            return(true);
        }
        /// <inheritdoc />
        public EntityInterestChangeEventArgs([NotNull] NetworkEntityGuid enterableEntity, [NotNull] NetworkEntityGuid enteringEntity, ChangeType changingType)
        {
            if (!Enum.IsDefined(typeof(ChangeType), changingType))
            {
                throw new InvalidEnumArgumentException(nameof(changingType), (int)changingType, typeof(ChangeType));
            }

            EnterableEntity = enterableEntity ?? throw new ArgumentNullException(nameof(enterableEntity));
            EnteringEntity  = enteringEntity ?? throw new ArgumentNullException(nameof(enteringEntity));
            ChangingType    = changingType;
        }
Exemple #19
0
 /// <inheritdoc />
 public DefaultEntityCreationContext(NetworkEntityGuid entityGuid, IMovementData movementData, EntityPrefab prefabType, [NotNull] IEntityDataFieldContainer entityData)
 {
     if (!Enum.IsDefined(typeof(EntityPrefab), prefabType))
     {
         throw new InvalidEnumArgumentException(nameof(prefabType), (int)prefabType, typeof(EntityPrefab));
     }
     EntityGuid   = entityGuid ?? throw new ArgumentNullException(nameof(entityGuid));
     MovementData = movementData ?? throw new ArgumentNullException(nameof(movementData));
     PrefabType   = prefabType;
     EntityData   = entityData ?? throw new ArgumentNullException(nameof(entityData));
 }
        /// <inheritdoc />
        public bool TryHandleMovement(NetworkEntityGuid entityGuid, IMovementData data)
        {
            bool result = CanHandle(data);

            if (result)
            {
                HandleMovement(entityGuid, data as TSpecificMovementType);
            }

            return(result);
        }
        //TODO: Create a converter type
        private static ZoneServerNpcEntryModel BuildDatabaseNPCEntryToTransportNPC(NPCEntryModel npc)
        {
            NetworkEntityGuidBuilder guidBuilder = new NetworkEntityGuidBuilder();

            NetworkEntityGuid guid = guidBuilder.WithId(npc.EntryId)
                                     .WithType(EntityType.Npc)
                                     .Build();

            //TODO: Create a Vector3 converter
            return(new ZoneServerNpcEntryModel(guid, npc.NpcTemplateId, new Vector3(npc.SpawnPosition.X, npc.SpawnPosition.Y, npc.SpawnPosition.Z), npc.MovementType, npc.MovementData));
        }
 private InterestCollection GetEntityInterestCollection(NetworkEntityGuid guid)
 {
     try
     {
         return(GuidToInterestCollectionMappable[guid]);
     }
     catch (Exception e)
     {
         throw new InvalidOperationException($"Attempted to load Entity: {guid}'s interst collection From: {GuidToInterestCollectionMappable.GetType().Name} but failed. No interest collection matched the key. Exception: {e.Message}", e);
     }
 }
 private bool ChangeTrackerHasChangesForEntity(NetworkEntityGuid interestingEntityGuid)
 {
     try
     {
         return(ChangeTrackingCollections[interestingEntityGuid].HasPendingChanges);
     }
     catch (Exception e)
     {
         throw new InvalidOperationException($"Attempted to load Entity: {interestingEntityGuid}'s interst collection From: {ChangeTrackingCollections.GetType().Name} but failed. No entry matched the key. Exception: {e.Message}", e);
     }
 }
 private void SendUpdate(NetworkEntityGuid guid, List <EntityAssociatedData <FieldValueUpdate> > updates)
 {
     try
     {
         SessionMappable[guid].SendMessageImmediately(new FieldValueUpdateEvent(updates.ToArray()));
     }
     catch (Exception e)
     {
         throw new InvalidOperationException($"Failed to send update to session with Guid: {guid}. Exception: {e.Message}", e);
     }
 }
        private void LogNoSessionError([NotNull] NetworkEntityGuid guid)
        {
            if (guid == null)
            {
                throw new ArgumentNullException(nameof(guid));
            }

            if (Logger.IsErrorEnabled)
            {
                Logger.Error($"Cannot send message to: {guid}. No session associated with it.");
            }
        }
Exemple #26
0
        /// <inheritdoc />
        public bool TryHandleMovement(NetworkEntityGuid entityGuid, IMovementData data)
        {
            foreach (var handler in MovementHandlers)
            {
                if (handler.CanHandle(data))
                {
                    return(handler.TryHandleMovement(entityGuid, data));
                }
            }

            return(false);
        }
Exemple #27
0
        /// <inheritdoc />
        public ZoneServerNpcEntryModel([NotNull] NetworkEntityGuid guid, int templateId, Vector3 initialPosition, NpcMovementType movement, int movementData)
        {
            if (templateId <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(templateId));
            }

            Guid            = guid ?? throw new ArgumentNullException(nameof(guid));
            TemplateId      = templateId;
            InitialPosition = initialPosition;
            Movement        = movement;
            MovementData    = movementData;
        }
        /// <inheritdoc />
        public void Register([NotNull] NetworkEntityGuid key, [NotNull] NetworkEntityGuid value)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }
            if (value == null)
            {
                throw new ArgumentNullException(nameof(value));
            }

            //Both key and value are the same
            _EnteringQueue.Enqueue(value);
        }
Exemple #29
0
        private async Task <HubOnConnectionState> TryRegisterGuildStatus(NetworkEntityGuid guid, IGroupManager groups, string connectionId)
        {
            //It's possible we already maintain guild information for this entity
            //This can happen if multiple connections share an entity.
            if (GuildStatusMappable.ContainsKey(guid))
            {
                await RegisterGuildOnExistingResponse(guid, groups, connectionId)
                .ConfigureAwait(false);

                return(HubOnConnectionState.Success);
            }

            return(HubOnConnectionState.Error);
        }
Exemple #30
0
        /// <inheritdoc />
        public void InvokeChangeEvents(NetworkEntityGuid entity, EntityDataFieldType field, int newValueAsInt)
        {
            //We aren't watching ANY data changes for this particular entity.
            if (!CallbackMap.ContainsKey(entity))
            {
                return;
            }

            //If we have any registered callbacks for this entity's data change we should dispatch it (they will all be called)
            if (CallbackMap[entity].ContainsKey(field))
            {
                CallbackMap[entity][field]?.Invoke(newValueAsInt);
            }
        }