Compare commits

...

6 Commits

  1. 2
      src/flecs-cs
  2. 17
      src/gaemstone.ECS/Entity.cs
  3. 3
      src/gaemstone.ECS/EntityPath.cs
  4. 2
      src/gaemstone.ECS/Id.cs
  5. 2
      src/gaemstone.ECS/Internal/FlecsBuiltIn.cs
  6. 10
      src/gaemstone.ECS/Iterator.cs
  7. 12
      src/gaemstone.ECS/Observer.cs
  8. 2
      src/gaemstone.ECS/System.cs
  9. 22
      src/gaemstone.ECS/Term.cs

@ -1 +1 @@
Subproject commit a2047983917aa462a8c2f34d5315aea48502f4d8 Subproject commit fcce5620d21fcd14c79d73a4406db8ce85f53dad

@ -19,7 +19,7 @@ public unsafe readonly partial struct Entity<TContext>
public bool IsSome => Value.IsSome; public bool IsSome => Value.IsSome;
public bool IsValid => EntityAccess.IsValid(World, this); public bool IsValid => EntityAccess.IsValid(World, this);
public bool IsAlive => EntityAccess.IsAlive(World, this); public bool IsAlive => IsSome && EntityAccess.IsAlive(World, this);
public string? Name { get => EntityAccess.GetName(World, this); set => EntityAccess.SetName(World, this, value); } public string? Name { get => EntityAccess.GetName(World, this); set => EntityAccess.SetName(World, this, value); }
public string? Symbol { get => EntityAccess.GetSymbol(World, this); set => EntityAccess.SetSymbol(World, this, value); } public string? Symbol { get => EntityAccess.GetSymbol(World, this); set => EntityAccess.SetSymbol(World, this, value); }
@ -39,9 +39,17 @@ public unsafe readonly partial struct Entity<TContext>
public static Entity<TContext> GetOrInvalid(World<TContext> world, Entity value) public static Entity<TContext> GetOrInvalid(World<TContext> world, Entity value)
=> new(world, value); => new(world, value);
public static Entity<TContext>? GetOrNull(World<TContext> world, Entity value) public static Entity<TContext>? GetOrNull(World<TContext> world, Entity value)
=> ecs_is_valid(world, value) ? new(world, value) : null; => new Entity<TContext>(world, value).ValidOrNull();
public static Entity<TContext> GetOrThrow(World<TContext> world, Entity value) public static Entity<TContext> GetOrThrow(World<TContext> world, Entity value)
=> ecs_is_valid(world, value) ? new(world, value) : throw new InvalidOperationException($"The entity {value} is not valid"); => new Entity<TContext>(world, value).ValidOrThrow();
public Entity<TContext>? ValidOrNull() => IsValid ? this : null;
public Entity<TContext> ValidOrThrow() => IsValid ? this
: throw new InvalidOperationException($"The entity {this} is not valid");
public Entity<TContext>? AliveOrNull() => IsAlive ? this : null;
public Entity<TContext> AliveOrThrow() => IsAlive ? this
: throw new InvalidOperationException($"The entity {this} is not alive");
public void Delete() public void Delete()
=> ecs_delete(World, this); => ecs_delete(World, this);
@ -50,7 +58,8 @@ public unsafe readonly partial struct Entity<TContext>
public Entity<TContext> CreateLookup<T>() public Entity<TContext> CreateLookup<T>()
{ {
ref var lookup = ref Lookup<TContext>.Entity<T>.Value; ref var lookup = ref Lookup<TContext>.Entity<T>.Value;
if (lookup.IsSome) throw new InvalidOperationException( if (lookup == this) { /* Don't throw if lookup already has the same entity set. */ }
else if (lookup.IsSome) throw new InvalidOperationException(
$"The lookup for type {typeof(T)} in context {typeof(TContext)} is already in use by {lookup}"); $"The lookup for type {typeof(T)} in context {typeof(TContext)} is already in use by {lookup}");
lookup = this; lookup = this;
return this; return this;

@ -52,6 +52,9 @@ public class EntityPath
public static unsafe EntityPath From(World world, Entity entity) public static unsafe EntityPath From(World world, Entity entity)
{ {
if (entity.IsNone) throw new ArgumentException(
"entity is Entity.None", nameof(entity));
var parts = new List<byte[]>(32); var parts = new List<byte[]>(32);
do { do {

@ -15,7 +15,7 @@ public unsafe struct Id<TContext>
public bool IsWildcard => Value.IsWildcard; public bool IsWildcard => Value.IsWildcard;
public bool IsValid => ecs_id_is_valid(World, this); public bool IsValid => ecs_id_is_valid(World, this);
public bool IsTag => ecs_id_is_tag(World, this).Data != default; public bool IsTag => ecs_id_is_tag(World, this);
public bool IsInUse => ecs_id_in_use(World, this); public bool IsInUse => ecs_id_in_use(World, this);
public int Count => ecs_count_id(World, this); public int Count => ecs_count_id(World, this);

@ -7,5 +7,5 @@ public static class FlecsBuiltIn
public static Entity ChildOf { get; } = new(pinvoke_EcsChildOf()); public static Entity ChildOf { get; } = new(pinvoke_EcsChildOf());
// FIXME: Hopefully flecs-cs will expose this one day. // FIXME: Hopefully flecs-cs will expose this one day.
public static Entity Disabled { get; } = new(new() { Data = ECS_HI_COMPONENT_ID + 7 }); public static Entity Disabled { get; } = new(new() { Data = FLECS_HI_COMPONENT_ID + 7 });
} }

@ -50,8 +50,8 @@ public enum IteratorFlags : uint
{ {
/// <summary> Does iterator contain valid result. </summary> /// <summary> Does iterator contain valid result. </summary>
IsValid = EcsIterIsValid, IsValid = EcsIterIsValid,
/// <summary> Is iterator filter (metadata only). </summary> /// <summary> Does iterator provide (component). </summary>
IsFilter = EcsIterIsFilter, NoData = EcsIterNoData,
/// <summary> Is iterator instanced. </summary> /// <summary> Is iterator instanced. </summary>
IsInstanced = EcsIterIsInstanced, IsInstanced = EcsIterIsInstanced,
/// <summary> Does result have shared terms. </summary> /// <summary> Does result have shared terms. </summary>
@ -64,8 +64,12 @@ public enum IteratorFlags : uint
NoResults = EcsIterNoResults, NoResults = EcsIterNoResults,
/// <summary> Only evaluate non-this terms. </summary> /// <summary> Only evaluate non-this terms. </summary>
IgnoreThis = EcsIterIgnoreThis, IgnoreThis = EcsIterIgnoreThis,
/// <summary> Does iterator have conditionally set fields. </summary>
MatchVar = EcsIterMatchVar, MatchVar = EcsIterMatchVar,
/// <summary> </summary>
HasCondSet = EcsIterHasCondSet,
/// <summary> Profile iterator performance. </summary>
Profile = EcsIterProfile,
} }
public class Variable public class Variable

@ -1,6 +1,5 @@
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using gaemstone.ECS.Internal;
using gaemstone.ECS.Utility; using gaemstone.ECS.Utility;
using static flecs_hub.flecs; using static flecs_hub.flecs;
@ -15,11 +14,12 @@ public static class ObserverExtensions
if (events.Length > 8) throw new ArgumentException("Must specify at most 8 events", nameof(events)); if (events.Length > 8) throw new ArgumentException("Must specify at most 8 events", nameof(events));
var world = entity.World; var world = entity.World;
var internalCallback = (nint iterPtr) => callback(new((ecs_iter_t*)iterPtr));
using var alloc = TempAllocator.Use(); using var alloc = TempAllocator.Use();
var desc = new ecs_observer_desc_t { var desc = new ecs_observer_desc_t {
entity = entity, entity = entity,
filter = filter.ToFlecs(alloc), filter = filter.ToFlecs(alloc),
binding_ctx = (void*)CallbackContextHelper.Create((world, callback)), binding_ctx = (void*)CallbackContextHelper.Create(internalCallback),
binding_ctx_free = new() { Data = new() { Pointer = &FreeContext } }, binding_ctx_free = new() { Data = new() { Pointer = &FreeContext } },
callback = new() { Data = new() { Pointer = &Callback } }, callback = new() { Data = new() { Pointer = &Callback } },
}; };
@ -33,11 +33,9 @@ public static class ObserverExtensions
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
private static unsafe void Callback(ecs_iter_t* iter) private static unsafe void Callback(ecs_iter_t* iter)
{ => CallbackContextHelper
var (world, callback) = CallbackContextHelper .Get<Action<nint>>((nint)iter->binding_ctx)
.Get<(World, Action<Iterator>)>((nint)iter->binding_ctx); .Invoke((nint)iter);
callback(new Iterator(iter));
}
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
private static unsafe void FreeContext(void* context) private static unsafe void FreeContext(void* context)

@ -12,7 +12,7 @@ public static class SystemExtensions
{ {
var world = entity.World; var world = entity.World;
var internalCallback = (nint iter) => var internalCallback = (nint iter) =>
callback(new Iterator<TContext>((ecs_iter_t*)iter)); callback(new((ecs_iter_t*)iter));
using var alloc = TempAllocator.Use(); using var alloc = TempAllocator.Use();
var desc = new ecs_system_desc_t { var desc = new ecs_system_desc_t {
entity = entity, entity = entity,

@ -90,19 +90,23 @@ public class TermId
public enum TermTraversalFlags : uint public enum TermTraversalFlags : uint
{ {
/// <summary> Match on self. </summary> /// <summary> Match on self. </summary>
Self = EcsSelf, Self = EcsSelf,
/// <summary> Match by traversing upwards. </summary> /// <summary> Match by traversing upwards. </summary>
Up = EcsUp, Up = EcsUp,
/// <summary> Match by traversing downwards (derived, cannot be set). </summary> /// <summary> Match by traversing downwards (derived, cannot be set). </summary>
Down = EcsDown, Down = EcsDown,
/// <summary> Match all entities encountered through traversal. </summary>
TraverseAll = EcsTraverseAll,
/// <summary> Sort results breadth first. </summary> /// <summary> Sort results breadth first. </summary>
Cascade = EcsCascade, Cascade = EcsCascade,
/// <summary> Short for up(ChildOf). </summary> /// <summary> Short for up(ChildOf). </summary>
Parent = EcsParent, Parent = EcsParent,
/// <summary> Term id is a variable. </summary> /// <summary> Term id is a variable. </summary>
IsVariable = EcsIsVariable, IsVariable = EcsIsVariable,
/// <summary> Term id is an entity. </summary> /// <summary> Term id is an entity. </summary>
IsEntity = EcsIsEntity, IsEntity = EcsIsEntity,
/// <summary> Prevent observer from triggering on term. </summary> /// <summary> Term id is a name (don't attempt to lookup as entity). </summary>
Filter = EcsFilter, IsName = EcsIsName,
/// <summary> revent observer from triggering on term. </summary>
Filter = EcsFilter,
} }

Loading…
Cancel
Save