Alternative managed wrapper around flecs-cs bindings for using the ECS framework Flecs in modern .NET.
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.

113 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 bool Any()
=> ecs_iter_is_true(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;
}