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.
172 lines
8.3 KiB
172 lines
8.3 KiB
using System; |
|
using System.Collections.Generic; |
|
using System.Linq; |
|
using gaemstone.ECS.Internal; |
|
using static flecs_hub.flecs; |
|
|
|
namespace gaemstone.ECS; |
|
|
|
public unsafe readonly partial struct Entity<TContext> |
|
: IEquatable<Entity<TContext>> |
|
{ |
|
public static readonly Entity<TContext> None = default; |
|
|
|
public readonly World<TContext> World; |
|
public readonly Entity Value; |
|
|
|
public uint NumericId => Value.NumericId; |
|
public bool IsNone => Value.IsNone; |
|
public bool IsSome => Value.IsSome; |
|
|
|
public bool IsValid => EntityAccess.IsValid(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? Symbol { get => EntityAccess.GetSymbol(World, this); set => EntityAccess.SetSymbol(World, this, value); } |
|
|
|
public EntityPath Path => EntityPath.From(World, this); |
|
public EntityType<TContext> Type => new(World, ecs_get_type(World, this)); |
|
|
|
public Entity<TContext>? Parent |
|
=> GetOrNull(World, GetTargets(FlecsBuiltIn.ChildOf).FirstOrDefault()); |
|
public IEnumerable<Entity<TContext>> Children |
|
=> World.Term(new(FlecsBuiltIn.ChildOf, this)).GetAllEntities(); |
|
|
|
|
|
private Entity(World<TContext> world, Entity value) |
|
{ World = world; Value = value; } |
|
|
|
public static Entity<TContext> GetOrInvalid(World<TContext> world, Entity value) |
|
=> new(world, value); |
|
public static Entity<TContext>? GetOrNull(World<TContext> world, Entity value) |
|
=> new Entity<TContext>(world, value).ValidOrNull(); |
|
public static Entity<TContext> GetOrThrow(World<TContext> world, Entity value) |
|
=> 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() |
|
=> ecs_delete(World, this); |
|
|
|
|
|
public Entity<TContext> CreateLookup<T>() |
|
{ |
|
ref var lookup = ref Lookup<TContext>.Entity<T>.Value; |
|
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}"); |
|
lookup = this; |
|
return this; |
|
} |
|
|
|
public EntityBuilder<TContext> NewChild(EntityPath? path = null) |
|
=> World.New(path?.ThrowIfAbsolute(), this); |
|
public Entity<TContext>? LookupChildOrNull(EntityPath path) |
|
=> World.LookupPathOrNull(path.ThrowIfAbsolute(), this); |
|
public Entity<TContext> LookupChildOrThrow(EntityPath path) |
|
=> World.LookupPathOrThrow(path.ThrowIfAbsolute()!, this); |
|
|
|
|
|
public Entity<TContext> ChildOf(Entity parent) |
|
=> Add(FlecsBuiltIn.ChildOf, parent); |
|
|
|
public bool IsDisabled => Has(FlecsBuiltIn.Disabled); |
|
public bool IsEnabled => !Has(FlecsBuiltIn.Disabled); |
|
public Entity<TContext> Disable() => Add(FlecsBuiltIn.Disabled); |
|
public Entity<TContext> Enable() => Remove(FlecsBuiltIn.Disabled); |
|
|
|
|
|
public Entity<TContext> Add(Id id) { EntityAccess.Add(World, this, id); return this; } |
|
public Entity<TContext> Add(string symbol) => Add(World.LookupSymbolOrThrow(symbol)); |
|
public Entity<TContext> Add(Entity relation, Entity target) => Add(Id.Pair(relation, target)); |
|
public Entity<TContext> Add<TEntity>() => Add(World.Entity<TEntity>()); |
|
public Entity<TContext> Add<TRelation>(Entity target) => Add(World.Entity<TRelation>(), target); |
|
public Entity<TContext> Add<TRelation, TTarget>() => Add(World.Entity<TRelation>(), World.Entity<TTarget>()); |
|
|
|
public Entity<TContext> Remove(Id id) { EntityAccess.Remove(World, this, id); return this; } |
|
public Entity<TContext> Remove(string symbol) => Remove(World.LookupSymbolOrThrow(symbol)); |
|
public Entity<TContext> Remove(Entity relation, Entity target) => Remove(Id.Pair(relation, target)); |
|
public Entity<TContext> Remove<TEntity>() => Remove(World.Entity<TEntity>()); |
|
public Entity<TContext> Remove<TRelation>(Entity target) => Remove(World.Entity<TRelation>(), target); |
|
public Entity<TContext> Remove<TRelation, TTarget>() => Remove(World.Entity<TRelation>(), World.Entity<TTarget>()); |
|
|
|
public bool Has(Id id) => EntityAccess.Has(World, this, id); |
|
public bool Has(string symbol) => Has(World.LookupSymbolOrThrow(symbol)); |
|
public bool Has(Entity relation, Entity target) => Has(Id.Pair(relation, target)); |
|
public bool Has<TEntity>() => Has(World.Entity<TEntity>()); |
|
public bool Has<TRelation>(Entity target) => Has(World.Entity<TRelation>(), target); |
|
public bool Has<TRelation, TTarget>() => Has(World.Entity<TRelation>(), World.Entity<TTarget>()); |
|
|
|
|
|
public T? GetOrNull<T>(Id id) where T : unmanaged => EntityAccess.GetOrNull<T>(World, this, id); |
|
public T? GetOrNull<T>(Id id, T _ = null!) where T : class => EntityAccess.GetOrNull<T>(World, this, id); |
|
public T GetOrThrow<T>(Id id) => EntityAccess.GetOrThrow<T>(World, this, id); |
|
public ref T GetMut<T>(Id id) where T : unmanaged => ref EntityAccess.GetMut<T>(World, this, id); |
|
public ref T GetRefOrNull<T>(Id id) where T : unmanaged => ref EntityAccess.GetRefOrNull<T>(World, this, id); |
|
public ref T GetRefOrThrow<T>(Id id) where T : unmanaged => ref EntityAccess.GetRefOrThrow<T>(World, this, id); |
|
|
|
public Entity<TContext> Modified(Id id) { EntityAccess.Modified(World, this, id); return this; } |
|
public Entity<TContext> Set<T>(Id id, in T value) where T : unmanaged { EntityAccess.Set(World, this, id, value); return this; } |
|
public Entity<TContext> Set<T>(Id id, T value) where T : class { EntityAccess.Set(World, this, id, value); return this; } |
|
|
|
|
|
public T? GetOrNull<T>() where T : unmanaged => GetOrNull<T>(World.Entity<T>()); |
|
public T? GetOrNull<T>(T _ = null!) where T : class => GetOrNull<T>(World.Entity<T>()); |
|
public T GetOrThrow<T>() => GetOrThrow<T>(World.Entity<T>()); |
|
public ref T GetMut<T>() where T : unmanaged => ref GetMut<T>(World.Entity<T>()); |
|
public ref T GetRefOrNull<T>() where T : unmanaged => ref GetRefOrNull<T>(World.Entity<T>()); |
|
public ref T GetRefOrThrow<T>() where T : unmanaged => ref GetRefOrThrow<T>(World.Entity<T>()); |
|
|
|
public Entity<TContext> Modified<T>() => Modified(World.Entity<T>()); |
|
public Entity<TContext> Set<T>(in T value) where T : unmanaged => Set(World.Entity<T>(), value); |
|
public Entity<TContext> Set<T>(T value) where T : class => Set(World.Entity<T>(), value); |
|
|
|
|
|
public IEnumerable<Entity<TContext>> GetTargets(Entity relation) |
|
{ |
|
foreach (var entity in EntityAccess.GetTargets(World, this, relation)) |
|
yield return new(World, entity); |
|
} |
|
public IEnumerable<Entity<TContext>> GetTargets(string symbol) |
|
=> GetTargets(World.LookupSymbolOrThrow(symbol)); |
|
public IEnumerable<Entity<TContext>> GetTargets<TRelation>() |
|
=> GetTargets(World.Entity<TRelation>()); |
|
|
|
|
|
public bool Equals(Entity<TContext> other) |
|
{ |
|
#if DEBUG |
|
// In DEBUG mode, we additionally check if the worlds the two compared |
|
// values are from the same world. This accounts for the world being a |
|
// stage, hence why it might not be the cheapest operation. |
|
if (World != other.World) throw new ArgumentException( |
|
"The specified values are not from the same world"); |
|
#endif |
|
return Value == other.Value; |
|
} |
|
public override bool Equals(object? obj) |
|
=> (obj is Entity<TContext> other) && Equals(other); |
|
public override int GetHashCode() |
|
=> Value.GetHashCode(); |
|
public override string? ToString() |
|
=> Value.ToString(); |
|
|
|
public static bool operator ==(Entity<TContext> left, Entity<TContext> right) => left.Equals(right); |
|
public static bool operator !=(Entity<TContext> left, Entity<TContext> right) => !left.Equals(right); |
|
|
|
public static implicit operator Entity (Entity<TContext> entity) => entity.Value; |
|
public static implicit operator ecs_entity_t(Entity<TContext> entity) => entity.Value.Value; |
|
|
|
public static implicit operator Id<TContext>(Entity<TContext> entity) => Id<TContext>.GetUnsafe(entity.World, entity); |
|
public static implicit operator Id (Entity<TContext> entity) => new(entity.Value.Value.Data); |
|
public static implicit operator ecs_id_t (Entity<TContext> entity) => entity.Value.Value.Data; |
|
|
|
public static implicit operator Term (Entity<TContext> entity) => new(entity.Value); |
|
public static implicit operator TermId(Entity<TContext> entity) => new(entity.Value); |
|
}
|
|
|