using Misaki.HighPerformance.Collections; using Misaki.HighPerformance.Utilities; namespace Ghost.Entities; public partial class EntityManager { private readonly SlotMap> _scriptComponents; internal SlotMap> ScriptComponents => _scriptComponents; /// /// Creates a new ManagedEntity and associates it with the given Entity. /// /// The Entity to associate with the ManagedEntity. /// The created ManagedEntity. public ManagedEntity CreateManagedEntity(Entity entity) { var managedEntity = CreateManagedEntity(); AddComponent(entity, new ManagedEntityRef { entity = managedEntity }); return managedEntity; } /// /// Creates a new ManagedEntity. /// /// /// You must call this if you add manually to an entity. /// Otherwise, use . /// /// The created ManagedEntity. public ManagedEntity CreateManagedEntity() { var id = _scriptComponents.Add(new(8), out var generation); var managedEntity = new ManagedEntity { id = id, generation = generation }; return managedEntity; } /// /// Destroys the given ManagedEntity and calls OnDestroy on all associated ScriptComponents. /// /// The ManagedEntity to destroy. public void DestroyManagedEntity(ManagedEntity managedEntity) { if (_scriptComponents.TryGetElement(managedEntity.id, managedEntity.generation, out var scripts)) { foreach (var script in scripts) { script.OnDestroy(); } _scriptComponents.Remove(managedEntity.id, managedEntity.generation); } } /// /// Checks if the given ManagedEntity exists. /// /// The ManagedEntity to check. /// True if the ManagedEntity exists, false otherwise. public bool Exists(ManagedEntity managedEntity) { return _scriptComponents.Contains(managedEntity.id, managedEntity.generation); } /// /// Adds a ScriptComponent of type T to the given ManagedEntity and Entity. /// /// The type of ScriptComponent to add. /// The ManagedEntity to add the ScriptComponent to.The Entity associated with the ManagedEntity. public void AddScriptComponent(ManagedEntity managedEntity, Entity entity) where T : ScriptComponent, new() { if (_scriptComponents.TryGetElement(managedEntity.id, managedEntity.generation, out var scripts)) { var script = new T { _world = _world, _entity = entity, _managedEntity = managedEntity }; scripts.Add(script); script.OnCreate(); return; } throw new InvalidOperationException($"ManagedEntity {managedEntity} does not exist."); } /// /// Adds a ScriptComponent of type T to the given Entity. /// /// The type of ScriptComponent to add. /// The Entity to add the ScriptComponent to. public unsafe void AddScriptComponent(Entity entity) where T : ScriptComponent, new() { var location = _entityLocations.GetElementAt(entity.ID, entity.Generation); ref var archetype = ref _world.GetArchetypeReference(location.archetypeID); var pManagedEntityRef = (ManagedEntityRef*)archetype.GetComponentData(location.chunkIndex, location.rowIndex, ComponentTypeID.value); if (pManagedEntityRef == null) { throw new InvalidOperationException($"Entity {entity} does not have ManagedEntityRef component."); } AddScriptComponent(pManagedEntityRef->entity, entity); } /// /// Destroys the ScriptComponent of type T associated with the given ManagedEntity. /// /// The type of ScriptComponent to destroy. /// The ManagedEntity whose ScriptComponent is to be destroyed /// True if the ScriptComponent was found and destroyed, false otherwise.(ManagedEntity managedEntity) where T : ScriptComponent { if (_scriptComponents.TryGetElement(managedEntity.id, managedEntity.generation, out var scripts)) { for (var i = 0; i < scripts.Count; i++) { if (scripts[i] is T script) { script.OnDestroy(); scripts.RemoveAndSwapBack(i); return true; } } return false; } throw new InvalidOperationException($"ManagedEntity {managedEntity} does not exist."); } /// /// Checks if the given ManagedEntity has a ScriptComponent of type T. /// /// The type of ScriptComponent to check for. /// The ManagedEntity to check. /// True if the ManagedEntity has a ScriptComponent of type T, false public bool HasScriptComponent(ManagedEntity managedEntity) where T : ScriptComponent { if (_scriptComponents.TryGetElement(managedEntity.id, managedEntity.generation, out var scripts)) { foreach (var script in scripts) { if (script is T) { return true; } } return false; } throw new InvalidOperationException($"ManagedEntity {managedEntity} does not exist."); } /// /// Gets the ScriptComponent of type T associated with the given ManagedEntity. /// /// The type of ScriptComponent to get. /// The ManagedEntity whose ScriptComponent is to be retrieved /// The ScriptComponent of type T. public T GetScriptComponent(ManagedEntity managedEntity) where T : ScriptComponent { if (_scriptComponents.TryGetElement(managedEntity.id, managedEntity.generation, out var scripts)) { foreach (var script in scripts) { if (script is T typedScript) { return typedScript; } } throw new InvalidOperationException($"ManagedEntity {managedEntity} does not have script component of type {typeof(T)}."); } throw new InvalidOperationException($"ManagedEntity {managedEntity} does not exist."); } /// /// Gets all ScriptComponents of type T associated with the given ManagedEntity. /// /// The type of ScriptComponent to get. /// The ManagedEntity whose ScriptComponents are to be retrieved /// The list of ScriptComponents of type T. public List GetScriptComponents(ManagedEntity managedEntity) where T : ScriptComponent { if (_scriptComponents.TryGetElement(managedEntity.id, managedEntity.generation, out var scripts)) { var result = new List(); foreach (var script in scripts) { if (script is T typedScript) { result.Add(typedScript); } } return result; } throw new InvalidOperationException($"ManagedEntity {managedEntity} does not exist."); } }