diff --git a/src/EcsSubject.cs b/src/EcsSubject.cs index beb2df8..1dfcd45 100644 --- a/src/EcsSubject.cs +++ b/src/EcsSubject.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using System.Diagnostics; +using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Text; @@ -134,6 +136,7 @@ namespace DCFApixels.DragonECS #endregion #region Mask + [DebuggerTypeProxy(typeof(DebuggerProxy))] public sealed class EcsMask { internal readonly Type _worldType; @@ -145,9 +148,36 @@ namespace DCFApixels.DragonECS _inc = inc; _exc = exc; } - public override string ToString() + public override string ToString() => CreateLogString(_worldType, _inc, _exc); + private static string CreateLogString(Type worldType, int[] inc, int[] exc) { - return $"Inc({string.Join(", ", _inc)}) Exc({string.Join(", ", _exc)})"; +#if DEBUG + int worldID = WorldMetaStorage.GetWorldID(worldType); + string converter(int o) => EcsDebugUtility.GetGenericTypeName(WorldMetaStorage.GetComponentType(worldID, o), 1); + return $"Inc({string.Join(", ", inc.Select(converter))}) Exc({string.Join(", ", exc.Select(converter))})"; +#else + return $"Inc({string.Join(", ", inc)}) Exc({string.Join(", ", exc)})"; // Release optimization +#endif + } + + internal class DebuggerProxy + { + public readonly Type worldType; + public readonly int[] inc; + public readonly int[] exc; + public readonly Type[] incTypes; + public readonly Type[] excTypes; + public DebuggerProxy(EcsMask mask) + { + worldType = mask._worldType; + int worldID = WorldMetaStorage.GetWorldID(worldType); + inc = mask._inc; + exc = mask._exc; + Type converter(int o) => WorldMetaStorage.GetComponentType(worldID, o); + incTypes = inc.Select(converter).ToArray(); + excTypes = exc.Select(converter).ToArray(); + } + public override string ToString() => CreateLogString(worldType, inc, exc); } } #endregion diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs index e5ff6e6..c9f833b 100644 --- a/src/EcsWorld.cs +++ b/src/EcsWorld.cs @@ -72,7 +72,7 @@ namespace DCFApixels.DragonECS Worlds[uniqueID] = this; } - _worldTypeID = WorldMetaStorage.GetWorldId(Archetype); + _worldTypeID = WorldMetaStorage.GetWorldID(Archetype); _entityDispenser = new IntDispenser(0); _nullPool = EcsNullPool.instance; @@ -376,31 +376,33 @@ namespace DCFApixels.DragonECS internal EcsWorld(bool isIndexable) : base(isIndexable) { } } - #region Utils + #region WorldMetaStorage public static class WorldMetaStorage { private static List _resizer = new List(); private static int _tokenCount = 0; - private static int[] _componentCounts = new int[0]; - private static int[] _subjectsCounts = new int[0]; + + private static WorldMeta[] _metas = new WorldMeta[0]; private static Dictionary _worldIds = new Dictionary(); private static class WorldIndex { - public static int id = GetWorldId(typeof(TWorldArchetype)); + public static int id = GetWorldID(typeof(TWorldArchetype)); } private static int GetToken() { - _tokenCount++; - Array.Resize(ref _componentCounts, _tokenCount); - Array.Resize(ref _subjectsCounts, _tokenCount); + WorldMeta meta = new WorldMeta(); + meta.id = _tokenCount; + Array.Resize(ref _metas, ++_tokenCount); + _metas[_tokenCount - 1] = meta; + foreach (var item in _resizer) item.Resize(_tokenCount); return _tokenCount - 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int GetWorldId(Type archetype) + public static int GetWorldID(Type archetype) { - if(_worldIds.TryGetValue(archetype, out int id) == false) + if(!_worldIds.TryGetValue(archetype, out int id)) { id = GetToken(); _worldIds.Add(archetype, id); @@ -415,6 +417,11 @@ namespace DCFApixels.DragonECS public static int GetSubjectId(int worldID) => Subject.Get(worldID); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int GetExecutorId(int worldID) => Executor.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); + + #region Resizer private abstract class Resizer { public abstract void Resize(int size); @@ -428,6 +435,7 @@ namespace DCFApixels.DragonECS Array.Resize(ref Executor.ids, size); } } + #endregion private static class Component { public static int[] ids; @@ -443,7 +451,11 @@ namespace DCFApixels.DragonECS { ref int id = ref ids[token]; if (id < 0) - id = _componentCounts[token]++; + { + var meta = _metas[token]; + id = meta.componentCount++; + meta.AddType(id, typeof(T)); + } return id; } } @@ -462,7 +474,7 @@ namespace DCFApixels.DragonECS { ref int id = ref ids[token]; if (id < 0) - id = _subjectsCounts[token]++; + id = _metas[token].subjectsCount++; return id; } } @@ -481,10 +493,40 @@ namespace DCFApixels.DragonECS { ref int id = ref ids[token]; if (id < 0) - id = _subjectsCounts[token]++; + id = _metas[token].executorsCount++; return id; } } + + private class WorldMeta + { + public int id; + + public int componentCount; + public int subjectsCount; + public int executorsCount; + + private Type[] types; + private HashSet declaredComponentTypes; + + public void AddType(int id, Type type) + { + if(types.Length <= id) + Array.Resize(ref types, id + 10); + types[id] = type; + + declaredComponentTypes.Add(type); + } + + public Type GetComponentType(int componentID) => types[componentID]; + public bool IsDeclaredType(Type type) => declaredComponentTypes.Contains(type); + + public WorldMeta() + { + types = new Type[10]; + declaredComponentTypes = new HashSet(); + } + } } #endregion