Rename Lookup functions for clarity

- EntityPath.Lookup can now optionally throw exception
wip/bindgen
copygirl 2 years ago
parent 8097f233ff
commit 7b380fd059
  1. 2
      README.md
  2. 44
      src/gaemstone.ECS/EntityBase.cs
  3. 27
      src/gaemstone.ECS/EntityPath.cs
  4. 12
      src/gaemstone.ECS/EntityRef.cs
  5. 6
      src/gaemstone.ECS/IdentifierRef.cs
  6. 2
      src/gaemstone.ECS/Iterator.cs
  7. 54
      src/gaemstone.ECS/World+Lookup.cs
  8. 6
      src/gaemstone.ECS/World.cs

@ -59,7 +59,7 @@ foreach (var child in entities.GetChildren()) {
pos = new(pos.X * 10, pos.Y * 10); pos = new(pos.X * 10, pos.Y * 10);
} }
var onUpdate = world.LookupOrThrow("/flecs/pipeline/OnUpdate"); var onUpdate = world.LookupByPathOrThrow("/flecs/pipeline/OnUpdate");
// Create a system that will move all entities with // Create a system that will move all entities with
// the "Position" component downwards by 2 every frame. // the "Position" component downwards by 2 every frame.

@ -9,23 +9,23 @@ public abstract class EntityBase<TReturn>
public abstract TReturn Remove(Identifier id); public abstract TReturn Remove(Identifier id);
public abstract bool Has(Identifier id); public abstract bool Has(Identifier id);
public TReturn Add(string symbol) => Add(World.LookupSymbolOrThrow(symbol)); public TReturn Add(string symbol) => Add(World.LookupBySymbolOrThrow(symbol));
public TReturn Add<T>() => Add(World.LookupOrThrow(typeof(T))); public TReturn Add<T>() => Add(World.LookupByTypeOrThrow(typeof(T)));
public TReturn Add(Entity relation, Entity target) => Add(Identifier.Pair(relation, target)); public TReturn Add(Entity relation, Entity target) => Add(Identifier.Pair(relation, target));
public TReturn Add<TRelation>(Entity target) => Add(World.LookupOrThrow<TRelation>(), target); public TReturn Add<TRelation>(Entity target) => Add(World.LookupByTypeOrThrow<TRelation>(), target);
public TReturn Add<TRelation, TTarget>() => Add(World.LookupOrThrow<TRelation>(), World.LookupOrThrow<TTarget>()); public TReturn Add<TRelation, TTarget>() => Add(World.LookupByTypeOrThrow<TRelation>(), World.LookupByTypeOrThrow<TTarget>());
public TReturn Remove(string symbol) => Remove(World.LookupSymbolOrThrow(symbol)); public TReturn Remove(string symbol) => Remove(World.LookupBySymbolOrThrow(symbol));
public TReturn Remove<T>() => Remove(World.LookupOrThrow(typeof(T))); public TReturn Remove<T>() => Remove(World.LookupByTypeOrThrow(typeof(T)));
public TReturn Remove(Entity relation, Entity target) => Remove(Identifier.Pair(relation, target)); public TReturn Remove(Entity relation, Entity target) => Remove(Identifier.Pair(relation, target));
public TReturn Remove<TRelation>(Entity target) => Remove(World.LookupOrThrow<TRelation>(), target); public TReturn Remove<TRelation>(Entity target) => Remove(World.LookupByTypeOrThrow<TRelation>(), target);
public TReturn Remove<TRelation, TTarget>() => Remove(World.LookupOrThrow<TRelation>(), World.LookupOrThrow<TTarget>()); public TReturn Remove<TRelation, TTarget>() => Remove(World.LookupByTypeOrThrow<TRelation>(), World.LookupByTypeOrThrow<TTarget>());
public bool Has(string symbol) => Has(World.LookupSymbolOrThrow(symbol)); public bool Has(string symbol) => Has(World.LookupBySymbolOrThrow(symbol));
public bool Has<T>() => Has(World.LookupOrThrow(typeof(T))); public bool Has<T>() => Has(World.LookupByTypeOrThrow(typeof(T)));
public bool Has(Entity relation, Entity target) => Has(Identifier.Pair(relation, target)); public bool Has(Entity relation, Entity target) => Has(Identifier.Pair(relation, target));
public bool Has<TRelation>(Entity target) => Has(World.LookupOrThrow<TRelation>(), target); public bool Has<TRelation>(Entity target) => Has(World.LookupByTypeOrThrow<TRelation>(), target);
public bool Has<TRelation, TTarget>() => Has(World.LookupOrThrow<TRelation>(), World.LookupOrThrow<TTarget>()); public bool Has<TRelation, TTarget>() => Has(World.LookupByTypeOrThrow<TRelation>(), World.LookupByTypeOrThrow<TTarget>());
public abstract T Get<T>(Identifier id); public abstract T Get<T>(Identifier id);
@ -36,24 +36,24 @@ public abstract class EntityBase<TReturn>
public abstract ref T GetRefOrThrow<T>(Identifier id) where T : unmanaged; public abstract ref T GetRefOrThrow<T>(Identifier id) where T : unmanaged;
public abstract void Modified<T>(Identifier id); public abstract void Modified<T>(Identifier id);
public T Get<T>() => Get<T>(World.LookupOrThrow<T>()); public T Get<T>() => Get<T>(World.LookupByTypeOrThrow<T>());
public T? GetOrNull<T>() where T : unmanaged => GetOrNull<T>(World.LookupOrThrow<T>()); public T? GetOrNull<T>() where T : unmanaged => GetOrNull<T>(World.LookupByTypeOrThrow<T>());
public T? GetOrNull<T>(T _ = null!) where T : class => GetOrNull<T>(World.LookupOrThrow<T>()); public T? GetOrNull<T>(T _ = null!) where T : class => GetOrNull<T>(World.LookupByTypeOrThrow<T>());
public ref T GetMut<T>() where T : unmanaged => ref GetMut<T>(World.LookupOrThrow<T>()); public ref T GetMut<T>() where T : unmanaged => ref GetMut<T>(World.LookupByTypeOrThrow<T>());
public ref T GetRefOrNull<T>() where T : unmanaged => ref GetRefOrNull<T>(World.LookupOrThrow<T>()); public ref T GetRefOrNull<T>() where T : unmanaged => ref GetRefOrNull<T>(World.LookupByTypeOrThrow<T>());
public ref T GetRefOrThrow<T>() where T : unmanaged => ref GetRefOrThrow<T>(World.LookupOrThrow<T>()); public ref T GetRefOrThrow<T>() where T : unmanaged => ref GetRefOrThrow<T>(World.LookupByTypeOrThrow<T>());
public void Modified<T>() => Modified<T>(World.LookupOrThrow<T>()); public void Modified<T>() => Modified<T>(World.LookupByTypeOrThrow<T>());
public abstract TReturn Set<T>(Identifier id, in T value) where T : unmanaged; public abstract TReturn Set<T>(Identifier id, in T value) where T : unmanaged;
public abstract TReturn Set<T>(Identifier id, T obj) where T : class; public abstract TReturn Set<T>(Identifier id, T obj) where T : class;
public TReturn Set<T>(in T value) where T : unmanaged => Set(World.LookupOrThrow<T>(), value); public TReturn Set<T>(in T value) where T : unmanaged => Set(World.LookupByTypeOrThrow<T>(), value);
public TReturn Set<T>(T obj) where T : class => Set(World.LookupOrThrow<T>(), obj); public TReturn Set<T>(T obj) where T : class => Set(World.LookupByTypeOrThrow<T>(), obj);
public TReturn ChildOf(Entity parent) => Add(World.ChildOf, parent); public TReturn ChildOf(Entity parent) => Add(World.ChildOf, parent);
public TReturn ChildOf<TParent>() => Add(World.ChildOf, World.LookupOrThrow<TParent>()); public TReturn ChildOf<TParent>() => Add(World.ChildOf, World.LookupByTypeOrThrow<TParent>());
public TReturn Disable() => Add(World.Disabled); public TReturn Disable() => Add(World.Disabled);
public TReturn Enable() => Remove(World.Disabled); public TReturn Enable() => Remove(World.Disabled);

@ -134,22 +134,29 @@ public class EntityPath
} }
internal static unsafe Entity Lookup(World world, Entity parent, EntityPath path) internal static unsafe Entity Lookup(
World world, Entity parent, EntityPath path, bool throwOnNotFound)
{ {
// If path is absolute, ignore parent and start at root. var start = path.IsAbsolute ? Entity.None // If path is absolute, ignore parent and use root.
if (path.IsAbsolute) parent = default; : parent.IsNone ? new(ecs_get_scope(world)) // If no parent is specified, use the current scope.
// Otherwise, if no parent is specified, use the current scope. : parent; // Otherwise just use the specified parent.
else if (parent.IsNone) parent = new(ecs_get_scope(world));
var current = start;
foreach (var part in path) foreach (var part in path)
fixed (byte* ptr = part.AsSpan()) { fixed (byte* ptr = part.AsSpan()) {
// FIXME: This breaks when using large entity Ids. current = new(ecs_lookup_child(world, current, ptr));
parent = new(ecs_lookup_child(world, parent, ptr)); if (current.IsSome && ecs_is_alive(world, current)) continue;
if (parent.IsNone || !ecs_is_alive(world, parent)) if (!throwOnNotFound) return Entity.None;
return Entity.None;
var startStr = EntityRef.CreateOrNull(world, start)?.GetFullPath().ToString() ?? start.ToString();
throw new World.EntityNotFoundException(
(start == parent) ? $"Child entity of '{startStr}' at '{path}' not found"
: start.IsSome ? $"Entity at scope '{startStr}' at '{path}' not found"
: $"Entity at '{path}' not found"
);
} }
return parent; return current;
} }
/// <summary> Used by <see cref="EntityBuilder.Build"/>. </summary> /// <summary> Used by <see cref="EntityBuilder.Build"/>. </summary>

@ -50,10 +50,10 @@ public unsafe class EntityRef
public EntityBuilder NewChild(EntityPath? path = null) public EntityBuilder NewChild(EntityPath? path = null)
=> World.New(EnsureRelativePath(path)).ChildOf(this); => World.New(EnsureRelativePath(path)).ChildOf(this);
public EntityRef? Lookup(EntityPath path) public EntityRef? LookupChild(EntityPath path)
=> World.Lookup(this, EnsureRelativePath(path)!); => World.LookupByPath(this, EnsureRelativePath(path)!);
public EntityRef LookupOrThrow(EntityPath path) public EntityRef LookupChildOrThrow(EntityPath path)
=> World.LookupOrThrow(this, EnsureRelativePath(path)!); => World.LookupByPathOrThrow(this, EnsureRelativePath(path)!);
private static EntityPath? EnsureRelativePath(EntityPath? path) private static EntityPath? EnsureRelativePath(EntityPath? path)
{ if (path?.IsAbsolute == true) throw new ArgumentException("path must not be absolute", nameof(path)); return path; } { if (path?.IsAbsolute == true) throw new ArgumentException("path must not be absolute", nameof(path)); return path; }
@ -142,9 +142,9 @@ public unsafe class EntityRef
public EntityRef? GetTarget(Entity relation, int index = 0) public EntityRef? GetTarget(Entity relation, int index = 0)
=> CreateOrNull(World, new(ecs_get_target(World, this, relation, index))); => CreateOrNull(World, new(ecs_get_target(World, this, relation, index)));
public EntityRef? GetTarget(string symbol, int index = 0) public EntityRef? GetTarget(string symbol, int index = 0)
=> GetTarget(World.LookupSymbolOrThrow(symbol), index); => GetTarget(World.LookupBySymbolOrThrow(symbol), index);
public EntityRef? GetTarget<T>(int index = 0) public EntityRef? GetTarget<T>(int index = 0)
=> GetTarget(World.LookupOrThrow(typeof(T)), index); => GetTarget(World.LookupByTypeOrThrow(typeof(T)), index);
public bool Equals(EntityRef? other) => (other is not null) && (World == other.World) && (Entity == other.Entity); public bool Equals(EntityRef? other) => (other is not null) && (World == other.World) && (Entity == other.Entity);
public override bool Equals(object? obj) => Equals(obj as EntityRef); public override bool Equals(object? obj) => Equals(obj as EntityRef);

@ -27,10 +27,10 @@ public unsafe class IdentifierRef
=> new(target.World, Identifier.Pair(relation, target)); => new(target.World, Identifier.Pair(relation, target));
public EntityRef? AsEntity() public EntityRef? AsEntity()
=> (Flags == default) ? World.Lookup(new Entity(new() { Data = Id })) : null; => (Flags == default) ? World.LookupAlive(new Entity(new() { Data = Id })) : null;
public (EntityRef Relation, EntityRef Target)? AsPair() public (EntityRef Relation, EntityRef Target)? AsPair()
=> IsPair && (World.Lookup(Id.RelationUnsafe) is EntityRef relation) && => IsPair && (World.LookupAlive(Id.RelationUnsafe) is EntityRef relation) &&
(World.Lookup(Id.TargetUnsafe ) is EntityRef target ) (World.LookupAlive(Id.TargetUnsafe ) is EntityRef target )
? (relation, target) : null; ? (relation, target) : null;
public bool Equals(IdentifierRef? other) => (other is not null) && (World == other.World) && (Id == other.Id); public bool Equals(IdentifierRef? other) => (other is not null) && (World == other.World) && (Id == other.Id);

@ -98,7 +98,7 @@ public unsafe class Iterator
{ {
fixed (ecs_iter_t* ptr = &Value) { fixed (ecs_iter_t* ptr = &Value) {
var id = ecs_field_id(ptr, index); var id = ecs_field_id(ptr, index);
var comp = World.LookupOrThrow<T>(); var comp = World.LookupByTypeOrThrow<T>();
return id == comp.Entity.Value.Data; return id == comp.Entity.Value.Data;
} }
} }

@ -20,38 +20,40 @@ public unsafe partial class World
$"Lookup for {type} does not exist"); } $"Lookup for {type} does not exist"); }
private EntityRef? CreateOrNull(Entity entity) public EntityRef? LookupByType<T>()
=> EntityRef.CreateOrNull(this, entity); => LookupByType(typeof(T));
public EntityRef? LookupByType(Type type)
=> LookupAlive(_lookupByType.GetValueOrDefault(type));
public EntityRef LookupByTypeOrThrow<T>()
=> LookupByTypeOrThrow(typeof(T));
public EntityRef LookupByTypeOrThrow(Type type)
=> LookupByType(type) ?? throw new EntityNotFoundException(
$"Entity of type {type} not found");
public EntityRef? Lookup<T>() public EntityRef? LookupAlive(Entity value)
=> Lookup(typeof(T)); => EntityRef.CreateOrNull(this, new(ecs_get_alive(this, value)));
public EntityRef? Lookup(Type type) public EntityRef LookupAliveOrThrow(Entity entity)
=> Lookup(_lookupByType.GetValueOrDefault(type)); => LookupAlive(entity) ?? throw new EntityNotFoundException(
$"Entity {entity} is not alive");
public EntityRef? Lookup(Entity value) public EntityRef? LookupByPath(EntityPath path)
=> CreateOrNull(new(ecs_get_alive(this, value))); => LookupByPath(default, path);
public EntityRef? LookupByPath(Entity parent, EntityPath path)
=> EntityRef.CreateOrNull(this, EntityPath.Lookup(this, parent, path, false));
public EntityRef LookupByPathOrThrow(EntityPath path)
=> LookupByPathOrThrow(default, path);
public EntityRef LookupByPathOrThrow(Entity parent, EntityPath path)
=> new(this, EntityPath.Lookup(this, parent, path, true));
public EntityRef? Lookup(EntityPath path) public EntityRef? LookupBySymbol(string symbol)
=> Lookup(default, path);
public EntityRef? Lookup(Entity parent, EntityPath path)
=> CreateOrNull(EntityPath.Lookup(this, parent, path));
public EntityRef? LookupSymbol(string symbol)
{ {
using var alloc = TempAllocator.Use(); using var alloc = TempAllocator.Use();
return CreateOrNull(new(ecs_lookup_symbol(this, alloc.AllocateCString(symbol), false))); var entity = ecs_lookup_symbol(this, alloc.AllocateCString(symbol), false);
return EntityRef.CreateOrNull(this, new(entity));
} }
public EntityRef LookupBySymbolOrThrow(string symbol)
public EntityRef LookupOrThrow<T>() => LookupOrThrow(typeof(T)); => LookupBySymbol(symbol) ?? throw new EntityNotFoundException(
public EntityRef LookupOrThrow(Type type) => Lookup(type) $"Entity with symbol '{symbol}' not found");
?? throw new EntityNotFoundException($"Entity of type {type} not found");
public EntityRef LookupOrThrow(Entity entity) => Lookup(entity)
?? throw new EntityNotFoundException($"Entity {entity} not alive");
public EntityRef LookupOrThrow(EntityPath path) => Lookup(default, path)
?? throw new EntityNotFoundException($"Entity '{path}' not found");
public EntityRef LookupOrThrow(Entity parent, EntityPath path) => Lookup(parent, path)
?? throw new EntityNotFoundException($"Child entity of {parent} '{path}' not found");
public EntityRef LookupSymbolOrThrow(string symbol) => LookupSymbol(symbol)
?? throw new EntityNotFoundException($"Entity with symbol '{symbol}' not found");
public class EntityNotFoundException : Exception public class EntityNotFoundException : Exception

@ -19,9 +19,9 @@ public unsafe partial class World
{ {
Handle = ecs_init_w_args(args.Length, null); Handle = ecs_init_w_args(args.Length, null);
ChildOf = LookupOrThrow("/flecs/core/ChildOf"); ChildOf = LookupByPathOrThrow("/flecs/core/ChildOf");
Disabled = LookupOrThrow("/flecs/core/Disabled"); Disabled = LookupByPathOrThrow("/flecs/core/Disabled");
DependsOn = LookupOrThrow("/flecs/core/DependsOn"); DependsOn = LookupByPathOrThrow("/flecs/core/DependsOn");
} }
public void Dispose() public void Dispose()

Loading…
Cancel
Save