High-level wrapper around Flecs, a powerful ECS (Entity Component System) library, written in Zig language
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.

165 lines
6.5 KiB

const c = @import("./c.zig");
pub const IdError = error{
/// Id is `0`.
IsNone,
/// Id is or contains wildcards.
IsWildcard,
/// Id is not valid.
IsInvalid,
};
/// `Id`s are the things that can be added to an `Entity`.
/// It can be an `Entity` or `Pair`, and can have optional id flags.
pub fn Id(comptime ctx: anytype) type {
return struct {
const Self = @This();
const Context = @import("./context.zig").Context(ctx);
const World = Context.World;
const Entity = Context.Entity;
const Pair = Context.Pair;
world: *World,
raw: c.ecs_id_t,
pub fn fromRaw(world: *World, raw: c.ecs_id_t) Self {
return .{ .world = world, .raw = raw };
}
/// Ensures this `Id` is valid.
/// That is, it can be added to an entity.
///
/// An `Id` is valid if ..
/// - .. it is not `0`.
/// - .. it does not contain wildcards.
/// - .. it does not contain invalid entities.
pub fn ensureValid(self: Self) !void {
if (self.raw == 0) return IdError.IsNone;
if (c.ecs_id_is_wildcard(self.raw)) return IdError.IsWildcard;
if (self.asPairUnsafe()) |p|
try p.ensureValid()
else if (!self.isEntity())
if (!c.ecs_is_valid(self.raw & c.ECS_COMPONENT_MASK))
return IdError.IsInvalid;
}
pub fn isEntity(self: Self) bool {
return (self.raw & c.ECS_ID_FLAGS_MASK) != 0;
}
/// Attempts to return this `Id` as an `Entity`, or an error if it's
/// not an entity, not a valid entity or not alive in the world.
pub fn asEntityAlive(self: Self) !Entity {
const result = self.asEntityUnsafe();
try result.ensureAlive();
return result;
}
/// Returns this `Id` as an `Entity`, or `null` otherwise.
/// This assumes the `Id` is valid, or an invalid result could be returned.
pub fn asEntityUnsafe(self: Self) ?Entity {
return if (isEntity(self)) .{ .world = self.world, .raw = self.raw } else null;
}
pub fn isPair(self: Self) bool {
return c.ecs_id_is_pair(self.raw);
}
/// Attempts to return this `Id` as a `Pair`, or an error if it's not
/// a pair, or either of its elements are not valid or not alive in
/// the world.
pub fn asPairAlive(self: Self) !Pair {
const result = Pair{ .world = self.world, .raw = self.raw };
try result.ensureAlive();
return result;
}
/// Attempts to return this `Id` as a `Pair`, or an error if it's not
/// a pair, or either of its elements are not valid.
pub fn asPairValid(self: Self) !Pair {
const result = Pair{ .world = self.world, .raw = self.raw };
try result.ensureValid();
return result;
}
/// Returns this `Id` as a `Pair`, or `null` otherwise.
/// This assumes the `Id` is valid, or an invalid result could be returned.
pub fn asPairUnsafe(self: Self) ?Pair {
return if (isPair(self)) .{ .world = self.world, .raw = self.raw } else null;
}
pub fn isWildcard(self: Self) bool {
return c.ecs_id_is_wildcard(self.raw);
}
/// Returns whether this `Id` a tag.
/// That is, a component without data / size.
///
/// An `Id` is a tag when it ..
/// - .. is an entity without the `Component` component.
/// - .. has an `Component` with size member set to 0.
/// - .. is a `Pair` where both elements are a tag.
/// - .. is a `Pair` where `.relation` has the `Tag` tag.
pub fn isTag(self: Self) bool {
return c.ecs_id_is_tag(self.world.raw, self.raw);
}
/// Returns whether this `Id` represents a union.
/// Only `Pair`s can be unions.
///
/// An `Id` represents a union when ..
/// - .. the `.relation` of the pair is `Union`.
/// - .. the `.relation` of the pair has `Union`.
pub fn isUnion(self: Self) bool {
return c.ecs_id_is_union(self.world.raw, self.raw);
}
/// Returns whether this `Id` is in use in the world.
/// That is, if it has been added to one or more tables.
///
/// Note that empty tables may reference this `Id`, in which case
/// this function can return `true`. Consider using `count()` instead.
pub fn isInUse(self: Self) bool {
return c.ecs_id_in_use(self.world.raw, self.raw);
}
/// Gets the number of entities in the world that have this `Id`.
pub fn count(self: Self) usize {
return @intCast(c.ecs_count_id(self.world.raw, self.raw));
}
// Get the type for an id.
// This function returns the type information for an id. The specified id can be
// any valid id. For the rules on how type information is determined based on
// id, see ecs_get_typeid.
// TODO: const ecs_type_info_t* ecs_get_type_info(const ecs_world_t *world, ecs_id_t id);
/// Returns the entity representing the component type for this `Id`,
/// if it is associated with a type, or `null` otherwise.
///
/// For a regular component with a non-zero size (an entity with the
/// `flecs.core.Component` component) the operation will return the
/// entity itself.
///
/// For an entity that does not have the `Component` component, or
/// its component is zero-sized, the operation will return `null`.
///
/// For a `Pair`, the operation will return the type associated with
/// the pair, by applying the following rules in order:
/// - If `.relation` is a component, it is returned.
/// - If `.relation` has `flecs.core.Tag`, `null` is returned.
/// - If `.target` is a component, it is returned.
/// - Otherwise, `null` is returned.
pub fn typeId(self: Self) ?Entity {
const raw = c.ecs_get_typeid(self.world.raw, self.raw);
return if (raw != 0) Entity.fromRaw(self.world, raw);
}
/// Returns if the provided `pattern` matches this `Id`.
/// The pattern may contain a wildcard (or wildcards, if a `Pair`).
pub fn matches(self: Self, pattern: Self) bool {
return c.ecs_id_match(self.raw, pattern.raw);
}
};
}