using System; using gaemstone.Utility; using static flecs_hub.flecs; namespace gaemstone.ECS; public class Term { public Identifier ID { get; set; } public TermID? Source { get; set; } public TermID? Relation { get; set; } public TermID? Target { get; set; } public TermInOutKind InOut { get; set; } public TermOperKind Oper { get; set; } public IdentifierFlags Flags { get; set; } public Term() { } public Term(Identifier id) => ID = id; public Term(TermID relation, TermID target) { Relation = relation; Target = target; } public static implicit operator Term(EntityRef entity) => new(entity); public static implicit operator Term(Entity entity) => new(entity); public static implicit operator Term(IdentifierRef id) => new(id); public static implicit operator Term(Identifier id) => new(id); public Term None { get { InOut = TermInOutKind.None; return this; } } public Term In { get { InOut = TermInOutKind.In; return this; } } public Term Out { get { InOut = TermInOutKind.Out; return this; } } public Term Or { get { Oper = TermOperKind.Or; return this; } } public Term Not { get { Oper = TermOperKind.Not; return this; } } public Term Optional { get { Oper = TermOperKind.Optional; return this; } } public ecs_term_t ToFlecs(IAllocator allocator) => new() { id = ID, src = Source?.ToFlecs(allocator) ?? default, first = Relation?.ToFlecs(allocator) ?? default, second = Target?.ToFlecs(allocator) ?? default, inout = (ecs_inout_kind_t)InOut, oper = (ecs_oper_kind_t)Oper, id_flags = (ecs_id_t)(ulong)Flags, }; } public enum TermInOutKind { Default = ecs_inout_kind_t.EcsInOutDefault, None = ecs_inout_kind_t.EcsInOutNone, InOut = ecs_inout_kind_t.EcsInOut, In = ecs_inout_kind_t.EcsIn, Out = ecs_inout_kind_t.EcsOut, } public enum TermOperKind { And = ecs_oper_kind_t.EcsAnd, Or = ecs_oper_kind_t.EcsOr, Not = ecs_oper_kind_t.EcsNot, Optional = ecs_oper_kind_t.EcsOptional, AndFrom = ecs_oper_kind_t.EcsAndFrom, OrFrom = ecs_oper_kind_t.EcsOrFrom, NotFrom = ecs_oper_kind_t.EcsNotFrom, } public class TermID { public static TermID This { get; } = new("$This"); public Entity ID { get; } public string? Name { get; } public Entity Traverse { get; set; } public TermTraversalFlags Flags { get; set; } public TermID(Entity id) => ID = id; public TermID(string name) { if (name[0] == '$') { Name = name[1..]; Flags = TermTraversalFlags.IsVariable; } else Name = name; } public static implicit operator TermID(EntityRef entity) => new(entity); public static implicit operator TermID(Entity entity) => new(entity); public static implicit operator TermID(string name) => new(name); public ecs_term_id_t ToFlecs(IAllocator allocator) => new() { id = ID, name = allocator.AllocateCString(Name), trav = Traverse, flags = (ecs_flags32_t)(uint)Flags }; } [Flags] public enum TermTraversalFlags : uint { /// Match on self. Self = EcsSelf, /// Match by traversing upwards. Up = EcsUp, /// Match by traversing downwards (derived, cannot be set). Down = EcsDown, /// Sort results breadth first. Cascade = EcsCascade, /// Short for up(ChildOf). Parent = EcsParent, /// Term id is a variable. IsVariable = EcsIsVariable, /// Term id is an entity. IsEntity = EcsIsEntity, /// Prevent observer from triggering on term. Filter = EcsFilter, }