You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
110 lines
3.0 KiB
110 lines
3.0 KiB
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 class Iterator |
|
: IDisposable |
|
{ |
|
public ecs_iter_t* Handle; |
|
private readonly bool _handleIsOwned; |
|
|
|
public World World => new(Handle->world); |
|
public int Count => Handle->count; |
|
|
|
public IteratorFlags Flags => (IteratorFlags)(uint)Handle->flags; |
|
public bool IsValid => (Flags & IteratorFlags.IsValid) != 0; |
|
|
|
public TimeSpan DeltaTime => TimeSpan.FromSeconds(Handle->delta_time); |
|
public TimeSpan DeltaSystemTime => TimeSpan.FromSeconds(Handle->delta_system_time); |
|
|
|
public Iterator(ecs_iter_t* handle) |
|
{ |
|
Handle = handle; |
|
_handleIsOwned = false; |
|
} |
|
public Iterator(ecs_iter_t value) |
|
{ |
|
Handle = GlobalHeapAllocator.Instance.AllocateCopy(value); |
|
_handleIsOwned = true; |
|
} |
|
|
|
public void Dispose() |
|
{ |
|
if (Handle == null) return; |
|
|
|
// When an iterator is iterated until completion, |
|
// ecs_iter_fini will be called automatically. |
|
if (IsValid) ecs_iter_fini(Handle); |
|
|
|
if (_handleIsOwned) |
|
GlobalHeapAllocator.Instance.Free(Handle); |
|
Handle = null; |
|
} |
|
|
|
|
|
public Entity GetVar(Variable var) |
|
=> new(ecs_iter_get_var(Handle, var.Index)); |
|
public Iterator SetVar(Variable var, Entity entity) |
|
{ ecs_iter_set_var(Handle, var.Index, entity); return this; } |
|
|
|
|
|
public virtual bool Next() |
|
=> ecs_iter_next(Handle); |
|
|
|
public Entity First() |
|
=> new(ecs_iter_first(Handle)); |
|
|
|
public IEnumerable<Entity> GetAllEntities() |
|
{ |
|
while (Next()) |
|
for (var i = 0; i < Count; i++) |
|
yield return Entity(i); |
|
} |
|
|
|
|
|
public bool FieldIsSet(int index) |
|
=> ecs_field_is_set(Handle, index); |
|
public Id FieldId(int index) |
|
=> new(ecs_field_id(Handle, index)); |
|
public bool FieldIs(int index, Id id) |
|
=> ecs_field_id(Handle, index) == id.Value; |
|
|
|
|
|
public Entity Entity(int index) |
|
=> new(Handle->entities[index]); |
|
|
|
public Span<T> Field<T>(int index) |
|
where T : unmanaged |
|
{ |
|
var size = (ulong)Unsafe.SizeOf<T>(); |
|
var isSelf = ecs_field_is_self(Handle, index); |
|
var pointer = ecs_field_w_size(Handle, size, index); |
|
return new(pointer, isSelf ? Count : 1); |
|
} |
|
public Span<T> FieldOrEmpty<T>(int index) where T : unmanaged |
|
=> FieldIsSet(index) ? Field<T>(index) : Span<T>.Empty; |
|
|
|
public SpanToRef<T> Field<T>(int index, T _ = null!) where T : class |
|
=> new(Field<ReferenceHandle>(index)); |
|
public SpanToRef<T> FieldOrEmpty<T>(int index, T _ = null!) where T : class |
|
=> FieldIsSet(index) ? Field<T>(index) : SpanToRef<T>.Empty; |
|
|
|
|
|
public override string ToString() |
|
=> ecs_iter_str(Handle).FlecsToStringAndFree()!; |
|
} |
|
|
|
public readonly ref struct SpanToRef<T> |
|
where T : class |
|
{ |
|
public static SpanToRef<T> Empty => default; |
|
private readonly Span<ReferenceHandle> _span; |
|
public int Length => _span.Length; |
|
public T this[int index] => (T)_span[index].Target!; |
|
public T? GetOrNull(int index) => ((index >= 0) && (index < Length)) ? this[index] : null; |
|
internal SpanToRef(Span<ReferenceHandle> span) => _span = span; |
|
}
|
|
|