using Ghost.Core; using Misaki.HighPerformance.LowLevel.Buffer; using Misaki.HighPerformance.LowLevel.Collections; using Misaki.HighPerformance.LowLevel.Utilities; using System.Runtime.CompilerServices; namespace Ghost.Entities; public interface IComponent { } public interface IEnableableComponent : IComponent { } internal struct ComponentInfo { // public string stableName; // Do we actually need this? public Identifier id; public int size; public int alignment; public bool isEnableable; public bool isShared; } /// /// Provides a unique identifier for the specified unmanaged component space. /// /// The component space for which to obtain an identifier. Must be unmanaged and implement . public static class ComponentTypeID where T : unmanaged, IComponent { public static readonly Identifier Value = ComponentRegistry.GetOrRegisterComponentID(); } internal static class ComponentRegistry { private static readonly List s_registeredComponents = new(); private static readonly Dictionary s_typeHandleToID = new(); private static readonly Dictionary s_nameToRuntimeID = new(); internal static readonly Dictionary s_runtimeIDToType = new(); public static unsafe Identifier GetOrRegisterComponentID() where T : unmanaged, IComponent { var type = typeof(T); var typeHandle = type.TypeHandle.Value; lock (s_registeredComponents) { if (s_typeHandleToID.TryGetValue(typeHandle, out var existingID)) { return existingID; } var newID = new Identifier(s_registeredComponents.Count); var stableName = typeof(T).FullName ?? typeof(T).Name; var info = new ComponentInfo { // stableName = new FixedText64(stableName), id = newID, size = sizeof(T), alignment = (int)MemoryUtility.AlignOf(), isEnableable = typeof(IEnableableComponent).IsAssignableFrom(type), //isShared = typeof(ISharedComponent).IsAssignableFrom(type), }; s_registeredComponents.Add(info); s_typeHandleToID[typeHandle] = newID; s_nameToRuntimeID[stableName] = newID; s_runtimeIDToType[newID.Value] = typeof(T); return newID; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Identifier GetComponentID(Type type) { var typeHandle = type.TypeHandle.Value; lock (s_registeredComponents) { if (s_typeHandleToID.TryGetValue(typeHandle, out var existingID)) { return existingID; } } return Identifier.Invalid; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComponentInfo GetComponentInfo(Identifier typeId) { lock (s_registeredComponents) { return s_registeredComponents[typeId]; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ComponentInfo GetComponentInfo(Type type) { lock (s_registeredComponents) { var typeId = GetComponentID(type); if (typeId.IsInvalid) { throw new KeyNotFoundException($"Component type {type.FullName} is not registered."); } return s_registeredComponents[typeId]; } } public static int GetHashCode(params ReadOnlySpan> componentTypeIDs) { var largestID = 0; foreach (var id in componentTypeIDs) { if (id.Value > largestID) { largestID = id.Value; } } var length = UnsafeBitSet.RequiredLength(largestID + 1); var bits = (Span)stackalloc uint[length]; bits.Clear(); var bitSet = new SpanBitSet(bits); foreach (var id in componentTypeIDs) { bitSet.SetBit(id.Value); } return bitSet.GetHashCode(); } } public class ComponentManager : IDisposable { private readonly World _world; private UnsafeList _archetypes; private UnsafeList _entityQueries; private UnsafeHashMap> _archetypeLookup; // Signature Hash to Archetype ID private UnsafeHashMap> _querieLookup; // Query Mask Hash to Query ID private bool _isDisposed; public int ArchetypeCount => _archetypes.Count; internal ComponentManager(World world) { _world = world; _archetypes = new UnsafeList(16, Allocator.Persistent); _entityQueries = new UnsafeList(16, Allocator.Persistent); _archetypeLookup = new UnsafeHashMap>(16, Allocator.Persistent); _querieLookup = new UnsafeHashMap>(16, Allocator.Persistent); // Create the empty archetype CreateArchetype(ReadOnlySpan>.Empty, 0); } ~ComponentManager() { Dispose(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal Identifier CreateArchetype(ReadOnlySpan> componentTypeIDs, int signatureHash) { var arcID = new Identifier(_archetypes.Count); _archetypes.Add(new Archetype(arcID, _world.ID, componentTypeIDs)); _archetypeLookup.Add(signatureHash, arcID); for (int i = 0; i < _entityQueries.Count; i++) { ref var query = ref _entityQueries[i]; query.AddArchetypeIfMatch(in _archetypes[arcID.Value]); } return arcID; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal Identifier GetArchetypeIDBySignatureHash(int signatureHash) { if (_archetypeLookup.TryGetValue(signatureHash, out var arcID)) { return arcID; } return Identifier.Invalid; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal ref Archetype GetArchetypeReference(Identifier id) { return ref _archetypes[id.Value]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal Identifier CreateEntityQuery(EntityQueryMask mask, int maskHash) { var queryID = new Identifier(_entityQueries.Count); _entityQueries.Add(new EntityQuery(queryID, _world.ID, mask)); _querieLookup.Add(maskHash, queryID); ref var query = ref _entityQueries[queryID.Value]; for (var i = 0; i < _archetypes.Count; i++) { query.AddArchetypeIfMatch(in _archetypes[i]); } return queryID; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal Identifier GetEntityQueryIDByMaskHash(int maskHash) { if (_querieLookup.TryGetValue(maskHash, out var queryID)) { return queryID; } return Identifier.Invalid; } /// /// Gets a reference to the entity query with the specified identifier. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public ref EntityQuery GetEntityQueryReference(Identifier id) { return ref _entityQueries[id.Value]; } public void Dispose() { if (_isDisposed) { return; } foreach (ref var archetype in _archetypes) { archetype.Dispose(); } foreach (ref var query in _entityQueries) { query.Dispose(); } _archetypes.Dispose(); _entityQueries.Dispose(); _archetypeLookup.Dispose(); _querieLookup.Dispose(); _isDisposed = true; GC.SuppressFinalize(this); } } /// /// Represents an immutable set of component identifiers used to define a group of components within an entity or system. /// public struct ComponentSet : IDisposable, IEquatable { private UnsafeArray> _components; private int _hashCode; public readonly ReadOnlySpan> Components => _components.AsSpan(); public ComponentSet(AllocationHandle allocationHandle, params ReadOnlySpan> components) { _components = new UnsafeArray>(components.Length, allocationHandle); components.CopyTo(_components.AsSpan()); _hashCode = -1; } public ComponentSet(Allocator allocator, params ReadOnlySpan> components) : this(AllocationManager.GetAllocationHandle(allocator), components) { } public readonly bool Equals(ComponentSet other) { return _hashCode == other._hashCode; } public override int GetHashCode() { if (_hashCode == -1) { _hashCode = ComponentRegistry.GetHashCode(_components.AsSpan()); } return _hashCode; } public override readonly bool Equals(object? obj) { return obj is ComponentSet set && Equals(set); } public static bool operator ==(ComponentSet left, ComponentSet right) { return left.Equals(right); } public static bool operator !=(ComponentSet left, ComponentSet right) { return !(left == right); } public void Dispose() { _components.Dispose(); } }