using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using gaemstone.ECS.Utility; using static flecs_hub.flecs; namespace gaemstone.ECS.Internal; public unsafe static class EntityAccess { public static bool IsValid(World world, Entity entity) => ecs_is_valid(world, entity); public static bool IsAlive(World world, Entity entity) => ecs_is_alive(world, entity); public static string? GetName(World world, Entity entity) => ecs_get_name(world, entity).FlecsToString()!; public static void SetName(World world, Entity entity, string? value) { using var alloc = TempAllocator.Use(); ecs_set_name(world, entity, alloc.AllocateCString(value)); } public static string? GetSymbol(World world, Entity entity) => ecs_get_symbol(world, entity).FlecsToString()!; public static void SetSymbol(World world, Entity entity, string? value) { using var alloc = TempAllocator.Use(); ecs_set_symbol(world, entity, alloc.AllocateCString(value)); } public static void Add(World world, Entity entity, Id id) => ecs_add_id(world, entity, id); public static void Remove(World world, Entity entity, Id id) => ecs_remove_id(world, entity, id); public static bool Has(World world, Entity entity, Id id) => ecs_has_id(world, entity, id); public static IEnumerable GetTargets(World world, Entity entity, Entity relation) { Entity GetTarget(int index) => new(ecs_get_target(world, entity, relation, index)); for (var i = 0; GetTarget(i) is { IsSome: true } target; i++) yield return target; } public static T? GetOrNull(World world, Entity entity, Id id) where T : unmanaged { var ptr = ecs_get_id(world, entity, id); return (ptr != null) ? Unsafe.Read(ptr) : null; } public static T? GetOrNull(World world, Entity entity, Id id, T _ = null!) where T : class { var ptr = ecs_get_id(world, entity, id); return (T?)Unsafe.Read(ptr).Target; } public static T GetOrThrow(World world, Entity entity, Id id) { var ptr = ecs_get_id(world, entity, id); if (ptr == null) throw new ComponentNotFoundException($"Component {id} not found on {entity}"); if (typeof(T).IsValueType) return Unsafe.Read(ptr); else return (T)Unsafe.Read(ptr).Target!; } public static ref T GetMut(World world, Entity entity, Id id) where T : unmanaged { var ptr = ecs_get_mut_id(world, entity, id); // NOTE: Value is added if it doesn't exist on the entity. return ref Unsafe.AsRef(ptr); } public static ref T GetRefOrNull(World world, Entity entity, Id id) where T : unmanaged { var @ref = ecs_ref_init_id(world, entity, id); var ptr = ecs_ref_get_id(world, &@ref, id); return ref (ptr != null) ? ref Unsafe.AsRef(ptr) : ref Unsafe.NullRef(); } public static ref T GetRefOrThrow(World world, Entity entity, Id id) where T : unmanaged { ref var ptr = ref GetRefOrNull(world, entity, id); if (Unsafe.IsNullRef(ref ptr)) throw new Exception( $"Component {typeof(T)} not found on {entity}"); return ref ptr; } public static void Modified(World world, Entity entity, Id id) => ecs_modified_id(world, entity, id); public static Entity Set(World world, Entity entity, Id id, in T value) where T : unmanaged { var size = (ulong)Unsafe.SizeOf(); fixed (T* ptr = &value) if (ecs_set_id(world, entity, id, size, ptr).Data == 0) throw new InvalidOperationException(); return entity; } public static Entity Set(World world, Entity entity, Id id, T value) where T : class { if (value == null) throw new ArgumentNullException(nameof(value)); var size = (ulong)sizeof(ReferenceHandle); // Dispose entity handle afterwards, since Flecs clones it. using var handle = ReferenceHandle.Alloc(value); if (ecs_set_id(world, entity, id, size, &handle).Data == 0) throw new InvalidOperationException(); return entity; } }