From d7a209d9b0a9e2a79eb6914face3a2fca48175dd Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Tue, 20 Jun 2023 23:34:51 +0800 Subject: [PATCH] update expand functionality of WorldComponents change interface of pools --- src/EcsSubject.cs | 5 +-- src/EcsWorld.cs | 62 ++++++++++++++++++++++++++++++----- src/Pools/EcsPool.cs | 6 ++-- src/Pools/EcsPoolBase.cs | 11 +++---- src/Pools/EcsTagPool.cs | 8 ++--- src/Utils/WorldMetaStorage.cs | 49 ++++++++++++++++----------- 6 files changed, 96 insertions(+), 45 deletions(-) diff --git a/src/EcsSubject.cs b/src/EcsSubject.cs index 5f5b414..fd1b1d1 100644 --- a/src/EcsSubject.cs +++ b/src/EcsSubject.cs @@ -18,11 +18,8 @@ namespace DCFApixels.DragonECS private bool _isInit; #region Properties - [EditorBrowsable(EditorBrowsableState.Never)] public EcsMask Mask => mask; - [EditorBrowsable(EditorBrowsableState.Never)] public EcsWorld World => source; - [EditorBrowsable(EditorBrowsableState.Never)] public bool IsInit => _isInit; #endregion @@ -169,7 +166,7 @@ namespace DCFApixels.DragonECS #region Iterator public EcsSubjectIterator GetIterator() { - return new EcsSubjectIterator(this, World.Entities); + return new EcsSubjectIterator(this, source.Entities); } public EcsSubjectIterator GetIteratorFor(EcsReadonlyGroup sourceGroup) { diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs index 4ea19e2..5f6206f 100644 --- a/src/EcsWorld.cs +++ b/src/EcsWorld.cs @@ -2,6 +2,7 @@ using DCFApixels.DragonECS.Utils; using System; using System.Collections.Generic; +using System.Reflection; using System.Runtime.CompilerServices; namespace DCFApixels.DragonECS @@ -54,7 +55,10 @@ namespace DCFApixels.DragonECS #endregion #region Constructors/Destroy - static EcsWorld() => Worlds[0] = new EcsNullWorld(); + static EcsWorld() + { + Worlds[0] = new EcsNullWorld(); + } public EcsWorld() : this(true) { } internal EcsWorld(bool isIndexable) { @@ -155,14 +159,44 @@ namespace DCFApixels.DragonECS #endregion #region WorldComponents + public EcsWorld SetupComponents(IEnumerable components, params object[] componentsParams) + { + foreach (var component in components) + SetComponent(component); + foreach (var component in componentsParams) + SetComponent(component); + return this; + } + public EcsWorld SetupComponents(params object[] components) + { + foreach (var component in components) + SetComponent(component); + return this; + } + public void SetComponent(object component) + { + Type componentType = component.GetType(); + if (componentType.IsValueType || componentType.IsPrimitive) + throw new ArgumentException(); + SetComponentInternal(WorldMetaStorage.GetWorldComponentID(componentType, _worldTypeID), component); + } public void SetComponent(T component) where T : class { - int index = WorldMetaStorage.GetWorldComponentID(_worldTypeID); + SetComponentInternal(WorldMetaStorage.GetWorldComponentID(_worldTypeID), component); + } + private void SetComponentInternal(int index, object component) + { if (index >= _components.Length) Array.Resize(ref _components, _components.Length << 1); - _components[index] = component; - if (component is IEcsWorldComponent intr) - intr.Init(this); + + ref var currentComponent = ref _components[index]; + if (currentComponent == component) + return; + if (currentComponent != null && currentComponent is IEcsWorldComponent oldComponentInterface) + oldComponentInterface.OnRemovedFromWorld(this); + currentComponent = component; + if (component is IEcsWorldComponent newComponentInterface) + newComponentInterface.OnAddedToWorld(this); } public T GetComponent() where T : class { @@ -174,7 +208,10 @@ namespace DCFApixels.DragonECS { int index = WorldMetaStorage.GetWorldComponentID(_worldTypeID); if (index >= _components.Length) - Array.Resize(ref _components, _components.Length << 1); + { + component = null; + return false; + } component = (T)_components[index]; return component != null; } @@ -183,7 +220,15 @@ namespace DCFApixels.DragonECS int index = WorldMetaStorage.GetWorldComponentID(_worldTypeID); if (index >= _components.Length) return false; - return _components[index] == null; + return _components[index] != null; + } + public void RemoveComponent() + { + int index = WorldMetaStorage.GetWorldComponentID(_worldTypeID); + ref var currentComponent = ref _components[index]; + if (currentComponent is IEcsWorldComponent componentInterface) + componentInterface.OnRemovedFromWorld(this); + currentComponent = null; } #endregion @@ -412,7 +457,8 @@ namespace DCFApixels.DragonECS #region Callbacks Interface public interface IEcsWorldComponent { - void Init(EcsWorld world); + void OnAddedToWorld(EcsWorld world); + void OnRemovedFromWorld(EcsWorld world); } public interface IEcsWorldEventListener { diff --git a/src/Pools/EcsPool.cs b/src/Pools/EcsPool.cs index 81724d7..71f64c1 100644 --- a/src/Pools/EcsPool.cs +++ b/src/Pools/EcsPool.cs @@ -7,7 +7,7 @@ using static DCFApixels.DragonECS.EcsPoolThrowHalper; namespace DCFApixels.DragonECS { /// Pool for IEcsComponent components - public sealed class EcsPool : IEcsPoolImplementation, IEnumerable //IEnumerable - IntelliSense hack + public sealed class EcsPool : IEcsPoolImplementation, IEcsStructsPool, IEnumerable //IEnumerable - IntelliSense hack where T : struct, IEcsComponent { private EcsWorld _source; @@ -171,8 +171,8 @@ namespace DCFApixels.DragonECS void IEcsPool.AddRaw(int entityID, object dataRaw) => Add(entityID) = (T)dataRaw; object IEcsPool.GetRaw(int entityID) => Read(entityID); void IEcsPool.SetRaw(int entityID, object dataRaw) => Get(entityID) = (T)dataRaw; - ref readonly T IEcsPool.Read(int entityID) => ref Read(entityID); - ref T IEcsPool.Get(int entityID) => ref Get(entityID); + ref readonly T IEcsStructsPool.Read(int entityID) => ref Read(entityID); + ref T IEcsStructsPool.Get(int entityID) => ref Get(entityID); #endregion #region Listeners diff --git a/src/Pools/EcsPoolBase.cs b/src/Pools/EcsPoolBase.cs index ebe41b4..909629d 100644 --- a/src/Pools/EcsPoolBase.cs +++ b/src/Pools/EcsPoolBase.cs @@ -31,7 +31,7 @@ namespace DCFApixels.DragonECS void RemoveListener(IEcsPoolEventListener listener); #endregion } - public interface IEcsPool + public interface IEcsStructsPool { ref T Add(int entityID); ref readonly T Read(int entityID); @@ -47,7 +47,7 @@ namespace DCFApixels.DragonECS } /// Only used to implement a custom pool. In other contexts use IEcsPool or IEcsPool. /// Component type - public interface IEcsPoolImplementation : IEcsPool, IEcsPoolImplementation { } + public interface IEcsPoolImplementation : IEcsPoolImplementation { } public static class EcsPoolThrowHalper { @@ -104,9 +104,6 @@ namespace DCFApixels.DragonECS void IEcsPool.SetRaw(int entity, object dataRaw) => throw new NotImplementedException(); void IEcsPool.Copy(int fromEntityID, int toEntityID) => throw new NotImplementedException(); void IEcsPool.Copy(int fromEntityID, EcsWorld toWorld, int toEntityID) => throw new NotImplementedException(); - ref NullComponent IEcsPool.Add(int entityID) => throw new NotImplementedException(); - ref readonly NullComponent IEcsPool.Read(int entityID) => throw new NotImplementedException(); - ref NullComponent IEcsPool.Get(int entityID) => throw new NotImplementedException(); #endregion #region Callbacks @@ -117,8 +114,8 @@ namespace DCFApixels.DragonECS #endregion #region Listeners - public void AddListener(IEcsPoolEventListener listener) { } - public void RemoveListener(IEcsPoolEventListener listener) { } + void IEcsPool.AddListener(IEcsPoolEventListener listener) { } + void IEcsPool.RemoveListener(IEcsPoolEventListener listener) { } #endregion } } diff --git a/src/Pools/EcsTagPool.cs b/src/Pools/EcsTagPool.cs index 342de05..a7f752a 100644 --- a/src/Pools/EcsTagPool.cs +++ b/src/Pools/EcsTagPool.cs @@ -6,7 +6,7 @@ using static DCFApixels.DragonECS.EcsPoolThrowHalper; namespace DCFApixels.DragonECS { - public sealed class EcsTagPool : IEcsPoolImplementation, IEnumerable //IEnumerable - IntelliSense hack + public sealed class EcsTagPool : IEcsPoolImplementation, IEcsStructsPool, IEnumerable //IEnumerable - IntelliSense hack where T : struct, IEcsTagComponent { private EcsWorld _source; @@ -131,19 +131,19 @@ namespace DCFApixels.DragonECS #endregion #region Other - ref T IEcsPool.Add(int entityID) + ref T IEcsStructsPool.Add(int entityID) { Add(entityID); return ref _fakeComponent; } - ref readonly T IEcsPool.Read(int entityID) + ref readonly T IEcsStructsPool.Read(int entityID) { #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS if (!Has(entityID)) ThrowNotHaveComponent(entityID); #endif return ref _fakeComponent; } - ref T IEcsPool.Get(int entityID) + ref T IEcsStructsPool.Get(int entityID) { #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS if (!Has(entityID)) ThrowNotHaveComponent(entityID); diff --git a/src/Utils/WorldMetaStorage.cs b/src/Utils/WorldMetaStorage.cs index 3eca92b..3156ea2 100644 --- a/src/Utils/WorldMetaStorage.cs +++ b/src/Utils/WorldMetaStorage.cs @@ -44,6 +44,8 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int GetComponentID(int worldID) => Component.Get(worldID); public static int GetComponentID(Type type, int worldID) => _metas[worldID].GetComponentID(type); + public static bool IsComponentTypeDeclared(int worldID, Type type) => _metas[worldID].IsDeclaredComponentType(type); + public static Type GetComponentType(int worldID, int componentID) => _metas[worldID].GetComponentType(componentID); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int GetPoolID(int worldID) => Pool.Get(worldID); [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -52,8 +54,7 @@ namespace DCFApixels.DragonECS public static int GetExecutorID(int worldID) => Executor.Get(worldID); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int GetWorldComponentID(int worldID) => WorldComponent.Get(worldID); - public static bool IsComponentTypeDeclared(int worldID, Type type) => _metas[worldID].IsDeclaredType(type); - public static Type GetComponentType(int worldID, int componentID) => _metas[worldID].GetComponentType(componentID); + public static int GetWorldComponentID(Type type, int worldID) => _metas[worldID].GetWorldComponentID(type); private abstract class ResizerBase @@ -97,11 +98,7 @@ namespace DCFApixels.DragonECS GetIdsArray(type); ref int id = ref _componentTypeArrayPairs[type][token]; if (id < 0) - { - var meta = _metas[token]; - id = meta.componentCount++; - meta.AddType(id, type); - } + id = _metas[token].DeclareComponentType(type); return id; } } @@ -237,7 +234,7 @@ namespace DCFApixels.DragonECS { ref int id = ref ids[token]; if (id < 0) - id = _metas[token].worldComponentCount++; + id = _metas[token].GetWorldComponentID(typeof(T)); return id; } private sealed class Resizer : ResizerBase @@ -263,27 +260,41 @@ namespace DCFApixels.DragonECS public int subjectsCount; public int executorsCount; public int worldComponentCount; - private Type[] _types; - private Dictionary _declaredComponentTypes; - public void AddType(int id, Type type) + private Type[] _types = new Type[10]; + private Dictionary _declaredComponentTypes = new Dictionary(); + private Dictionary _declaredWorldComponentTypes = new Dictionary(); + + public WorldTypeMeta(Type worldType) { + this.worldType = worldType; + } + + public int DeclareComponentType(Type type) + { + int id = componentCount++; if (_types.Length <= id) Array.Resize(ref _types, id + 10); _types[id] = type; - _declaredComponentTypes.Add(type, id); + return id; } + public bool IsDeclaredComponentType(Type type) => _declaredComponentTypes.ContainsKey(type); public Type GetComponentType(int componentID) => _types[componentID]; - public bool IsDeclaredType(Type type) => _declaredComponentTypes.ContainsKey(type); - public int GetComponentID(Type type) + public int GetComponentID(Type type) => PoolComponentIdArrays.GetComponentID(type, id); + + + public int DeclareWorldComponentType(Type type) { - return PoolComponentIdArrays.GetComponentID(type, id); + int id = worldComponentCount++; + _declaredWorldComponentTypes.Add(type, id); + return id; } - public WorldTypeMeta(Type worldType) + public bool IsDeclaredWorldComponentType(Type type) => _declaredWorldComponentTypes.ContainsKey(type); + public int GetWorldComponentID(Type type) { - _types = new Type[10]; - _declaredComponentTypes = new Dictionary(); - this.worldType = worldType; + if(!_declaredWorldComponentTypes.TryGetValue(type, out int id)) + id = DeclareWorldComponentType(type); + return id; } } }