Ejemplo n.º 1
0
        void UpdateFilters(int entity, EcsComponentMask oldMask, EcsComponentMask newMask)
        {
            for (var i = _filtersCount - 1; i >= 0; i--)
            {
                var filter = _filters[i];
                var isNewMaskCompatible = newMask.IsCompatible(filter);
                if (oldMask.IsCompatible(filter))
                {
                    if (!isNewMaskCompatible)
                    {
#if DEBUG
                        var ii = filter.EntitiesCount - 1;
                        for (; ii >= 0; ii--)
                        {
                            if (filter.Entities[ii] == entity)
                            {
                                break;
                            }
                        }
                        EcsHelpers.Assert(ii != -1, string.Format("Something wrong - entity {0} should be in filter {1}, but not exits.", entity, filter));
#endif
                        filter.RaiseOnRemoveEvent(entity);
                    }
                }
                else
                {
                    if (isNewMaskCompatible)
                    {
                        filter.RaiseOnAddEvent(entity);
                    }
                }
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Gets exist one or adds new component to entity.
        /// </summary>
        /// <param name="entity">Entity.</param>
        /// <param name="isNew">Is component was added in this call?</param>
        public T EnsureComponent <T> (int entity, out bool isNew) where T : class, new ()
        {
            EcsHelpers.Assert(entity >= 0 && entity < _entitiesCount, string.Format("Invalid entity: {0}", entity));
            var entityData = _entities[entity];

            EcsHelpers.Assert(!entityData.IsReserved, string.Format("\"{0}\" component cant be added to removed entity {1}", typeof(T).Name, entity));
            var pool = EcsComponentPool <T> .Instance;

            for (var i = 0; i < entityData.ComponentsCount; i++)
            {
                if (entityData.Components[i].Pool == pool)
                {
                    isNew = false;
                    return((T)entityData.Components[i].Pool.GetExistItemById(entityData.Components[i].ItemId));
                }
            }

            var link = new ComponentLink(pool, pool.RequestNewId());

            if (entityData.ComponentsCount == entityData.Components.Length)
            {
                Array.Resize(ref entityData.Components, entityData.ComponentsCount << 1);
            }
            entityData.Components[entityData.ComponentsCount++] = link;
            AddDelayedUpdate(DelayedUpdate.Op.AddComponent, entity, pool, link.ItemId);
#if DEBUG
            var component = pool.Items[link.ItemId];
            for (var ii = 0; ii < _debugListeners.Count; ii++)
            {
                _debugListeners[ii].OnComponentAdded(entity, component);
            }
#endif
            isNew = true;
            return(pool.Items[link.ItemId]);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Gets filter with specific include / exclude masks.
        /// </summary>
        /// <param name="filterType">Type of filter.</param>
        public EcsFilter GetFilter(Type filterType)
        {
            EcsHelpers.Assert(filterType != null, "filterType is null");
            EcsHelpers.Assert(filterType.IsSubclassOf(typeof(EcsFilter)), string.Format("Invalid filter-type: {0}", filterType));
            var i = _filtersCount - 1;

            for (; i >= 0; i--)
            {
                if (this._filters[i].GetType() == filterType)
                {
                    break;
                }
            }
            if (i == -1)
            {
                i = _filtersCount;

                var filter = Activator.CreateInstance(filterType, true) as EcsFilter;
                filter.SetWorld(this);
#if DEBUG
                for (var j = 0; j < _filtersCount; j++)
                {
                    EcsHelpers.Assert(!_filters[j].IncludeMask.IsEquals(filter.IncludeMask) || !_filters[j].ExcludeMask.IsEquals(filter.ExcludeMask),
                                      string.Format("Duplicate filter type \"{0}\": filter type \"{1}\" already has same types in different order.", filterType, _filters[j].GetType()));
                }
#endif
                if (_filtersCount == _filters.Length)
                {
                    Array.Resize(ref _filters, _filtersCount << 1);
                }

                _filters[_filtersCount++] = filter;
            }
            return(_filters[i]);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Removes component from entity.
        /// </summary>
        /// <param name="entity">Entity.</param>
        /// <param name="noerror">Suppress error if component not exists.</param>
        public void RemoveComponent <T> (int entity, bool noError = false) where T : class, new ()
        {
            EcsHelpers.Assert(entity >= 0 && entity < _entitiesCount, string.Format("Invalid entity: {0}", entity));
            var           entityData = _entities[entity];
            var           pool       = EcsComponentPool <T> .Instance;
            ComponentLink link;

            link.ItemId = -1;
            var i = entityData.ComponentsCount - 1;

            for (; i >= 0; i--)
            {
                link = entityData.Components[i];
                if (link.Pool == pool)
                {
                    break;
                }
            }
            if (noError && i == -1)
            {
                return;
            }
            EcsHelpers.Assert(i != -1, string.Format("\"{0}\" component not exists on entity {1}", typeof(T).Name, entity));
            AddDelayedUpdate(DelayedUpdate.Op.RemoveComponent, entity, pool, link.ItemId);
            entityData.ComponentsCount--;
            Array.Copy(entityData.Components, i + 1, entityData.Components, i, entityData.ComponentsCount - i);
        }
Ejemplo n.º 5
0
 /// <summary>
 /// Removes exists entity or throws exception on invalid one.
 /// </summary>
 /// <param name="entity">Entity.</param>
 public void RemoveEntity(int entity)
 {
     EcsHelpers.Assert(entity >= 0 && entity < _entitiesCount, string.Format("Invalid entity: {0}", entity));
     if (!_entities[entity].IsReserved)
     {
         AddDelayedUpdate(DelayedUpdate.Op.RemoveEntity, entity, null, -1);
     }
 }
Ejemplo n.º 6
0
        /// <summary>
        /// Creates new entity and adds component to it.
        /// Faster than CreateEntity() and multiple AddComponent() calls sequence.
        /// </summary>
        /// <param name="c1">Added component of type T1.</param>
        /// <param name="c2">Added component of type T2.</param>
        /// <param name="c3">Added component of type T3.</param>
        /// <returns>New entity Id.</returns>
        public int CreateEntityWith <T1, T2, T3> (out T1 c1, out T2 c2, out T3 c3) where T1 : class, new () where T2 : class, new () where T3 : class, new ()
        {
            EcsHelpers.Assert(typeof(T1) != typeof(T2), string.Format("Cant create entity with multiple components of same type \"{0}\"", typeof(T1).Name));
            EcsHelpers.Assert(typeof(T1) != typeof(T3) && typeof(T2) != typeof(T3), string.Format("Cant create entity with multiple components of same type \"{0}\"", typeof(T3).Name));
            var entity     = CreateEntityInternal();
            var pool1      = EcsComponentPool <T1> .Instance;
            var pool2      = EcsComponentPool <T2> .Instance;
            var pool3      = EcsComponentPool <T3> .Instance;
            var entityData = _entities[entity];

            while ((entityData.ComponentsCount + 3) > entityData.Components.Length)
            {
                Array.Resize(ref entityData.Components, entityData.ComponentsCount << 1);
            }
            ComponentLink link;

            link.Pool   = pool1;
            link.ItemId = pool1.RequestNewId();
            c1          = pool1.Items[link.ItemId];
            entityData.Components[entityData.ComponentsCount++] = link;
            AddDelayedUpdate(DelayedUpdate.Op.AddComponent, entity, pool1, link.ItemId);
            link.Pool   = pool2;
            link.ItemId = pool2.RequestNewId();
            c2          = pool2.Items[link.ItemId];
            entityData.Components[entityData.ComponentsCount++] = link;
            AddDelayedUpdate(DelayedUpdate.Op.AddComponent, entity, pool2, link.ItemId);
            link.Pool   = pool3;
            link.ItemId = pool3.RequestNewId();
            c3          = pool3.Items[link.ItemId];
            entityData.Components[entityData.ComponentsCount++] = link;
            AddDelayedUpdate(DelayedUpdate.Op.AddComponent, entity, pool3, link.ItemId);
#if DEBUG
            for (var ii = 0; ii < _debugListeners.Count; ii++)
            {
                _debugListeners[ii].OnComponentAdded(entity, c1);
            }
            for (var ii = 0; ii < _debugListeners.Count; ii++)
            {
                _debugListeners[ii].OnComponentAdded(entity, c2);
            }
            for (var ii = 0; ii < _debugListeners.Count; ii++)
            {
                _debugListeners[ii].OnComponentAdded(entity, c3);
            }
#endif
            return(entity);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Gets all components on entity.
        /// </summary>
        /// <param name="entity">Entity.</param>
        /// <param name="list">List to put results in it. if null - will be created.</param>
        /// <returns>Amount of components in list.</returns>
        public int GetComponents(int entity, ref object[] list)
        {
            EcsHelpers.Assert(entity >= 0 && entity < _entitiesCount, string.Format("Invalid entity: {0}", entity));
            var entityData = _entities[entity];
            var count      = entityData.ComponentsCount;

            if (list == null || list.Length < count)
            {
                list = new object[entityData.ComponentsCount];
            }
            for (var i = 0; i < count; i++)
            {
                var link = entityData.Components[i];
                list[i] = link.Pool.GetExistItemById(link.ItemId);
            }
            return(count);
        }
Ejemplo n.º 8
0
        public T GetComponent <T> (int entity) where T : class, new ()
        {
            EcsHelpers.Assert(entity >= 0 && entity < _entitiesCount, string.Format("Invalid entity: {0}", entity));
            var entityData = _entities[entity];

            EcsHelpers.Assert(!entityData.IsReserved, string.Format("\"{0}\" component cant be obtained from removed entity {1}", typeof(T).Name, entity));
            var pool = EcsComponentPool <T> .Instance;

            for (var i = 0; i < entityData.ComponentsCount; i++)
            {
                if (entityData.Components[i].Pool == pool)
                {
                    return(pool.Items[entityData.Components[i].ItemId]);
                }
            }
            return(null);
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Destroys all registered external data, full cleanup for internal data.
        /// </summary>
        public void Dispose()
        {
#if DEBUG
            EcsHelpers.Assert(!_isDisposed, "World already disposed");
            _isDisposed = true;
            for (var i = _debugListeners.Count - 1; i >= 0; i--)
            {
                _debugListeners[i].OnWorldDestroyed(this);
            }
#endif
            if (this == Active)
            {
                Active = null;
            }
            for (var i = 0; i < _entitiesCount; i++)
            {
                // already reserved entities cant contains components.
                if (_entities[i].ComponentsCount > 0)
                {
                    var entity = _entities[i];
                    for (var ii = 0; ii < entity.ComponentsCount; ii++)
                    {
                        entity.Components[ii].Pool.RecycleById(entity.Components[ii].ItemId);
                    }
                }
            }
            // any next usage of this EcsWorld instance will throw exception.
            _entities              = null;
            _entitiesCount         = 0;
            _filters               = null;
            _filtersCount          = 0;
            _reservedEntities      = null;
            _reservedEntitiesCount = 0;
            _delayedUpdates        = null;
            _delayedUpdatesCount   = 0;
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Manually processes delayed updates. Use carefully!
        /// </summary>
        public void ProcessDelayedUpdates()
        {
            if (_delayedUpdatesCount > 0)
            {
                for (var i = 0; i < _delayedUpdatesCount; i++)
                {
                    var op         = _delayedUpdates[i];
                    var entityData = _entities[op.Entity];
                    _delayedOpMask.CopyFrom(entityData.Mask);
                    switch (op.Type)
                    {
                    case DelayedUpdate.Op.RemoveEntity:
                        EcsHelpers.Assert(!entityData.IsReserved, string.Format("Entity {0} already removed", op.Entity));
                        while (entityData.ComponentsCount > 0)
                        {
                            var link        = entityData.Components[entityData.ComponentsCount - 1];
                            var componentId = link.Pool.GetComponentTypeIndex();
                            entityData.Mask.SetBit(componentId, false);
#if DEBUG
                            var componentToRemove = link.Pool.GetExistItemById(link.ItemId);
                            for (var ii = 0; ii < _debugListeners.Count; ii++)
                            {
                                _debugListeners[ii].OnComponentRemoved(op.Entity, componentToRemove);
                            }
#endif
                            UpdateFilters(op.Entity, _delayedOpMask, entityData.Mask);
                            link.Pool.RecycleById(link.ItemId);
                            _delayedOpMask.SetBit(componentId, false);
                            entityData.ComponentsCount--;
                        }
                        ReserveEntity(op.Entity, entityData);
                        break;

                    case DelayedUpdate.Op.SafeRemoveEntity:
                        if (!entityData.IsReserved && entityData.ComponentsCount == 0)
                        {
                            ReserveEntity(op.Entity, entityData);
                        }
                        break;

                    case DelayedUpdate.Op.AddComponent:
                        var bit = op.Pool.GetComponentTypeIndex();
                        EcsHelpers.Assert(!entityData.Mask.GetBit(bit), string.Format("Cant add component on entity {0}, already marked as added in mask", op.Entity));
                        entityData.Mask.SetBit(bit, true);
                        UpdateFilters(op.Entity, _delayedOpMask, entityData.Mask);
                        break;

                    case DelayedUpdate.Op.RemoveComponent:
                        var bitRemove = op.Pool.GetComponentTypeIndex();
                        EcsHelpers.Assert(entityData.Mask.GetBit(bitRemove), string.Format("Cant remove component on entity {0}, marked as not exits in mask", op.Entity));
#if DEBUG
                        var componentInstance = op.Pool.GetExistItemById(op.ComponentId);
                        for (var ii = 0; ii < _debugListeners.Count; ii++)
                        {
                            _debugListeners[ii].OnComponentRemoved(op.Entity, componentInstance);
                        }
#endif
                        entityData.Mask.SetBit(bitRemove, false);
                        UpdateFilters(op.Entity, _delayedOpMask, entityData.Mask);
                        op.Pool.RecycleById(op.ComponentId);
                        if (entityData.ComponentsCount == 0)
                        {
                            AddDelayedUpdate(DelayedUpdate.Op.SafeRemoveEntity, op.Entity, null, -1);
                        }
                        break;
                    }
                }
                _delayedUpdatesCount = 0;
            }
        }
Ejemplo n.º 11
0
 /// <summary>
 /// Removes external event listener.
 /// </summary>
 /// <param name="observer">Event listener.</param>
 public void RemoveDebugListener(IEcsWorldDebugListener observer)
 {
     EcsHelpers.Assert(observer != null, "observer is null");
     _debugListeners.Remove(observer);
 }
Ejemplo n.º 12
0
 /// <summary>
 /// Adds external event listener.
 /// </summary>
 /// <param name="observer">Event listener.</param>
 public void AddDebugListener(IEcsWorldDebugListener observer)
 {
     EcsHelpers.Assert(observer != null, "observer is null");
     EcsHelpers.Assert(!_debugListeners.Contains(observer), "Listener already exists");
     _debugListeners.Add(observer);
 }