diff --git a/src/world.zig b/src/world.zig index 09d0237..8f55240 100644 --- a/src/world.zig +++ b/src/world.zig @@ -10,6 +10,7 @@ const Lookup = @import("./main.zig").Lookup; const Entity = @import("./entity.zig").Entity; const EntityError = @import("./entity.zig").EntityError; const Iter = @import("./iter.zig").Iter; +const Path = @import("./path.zig").Path; pub fn World(comptime ctx: anytype) type { return struct { @@ -59,6 +60,29 @@ pub fn World(comptime ctx: anytype) type { return result; } + // TODO: Reconsider whether lookup functions should return errors or just optionals. + // TODO: Reconsider whether "Entity" should always be in backticks in our doc comments. + // TODO: We really need tests for this function. + /// Returns the `Entity` at the specified path, or an error if the + /// entity does not exist. If the path is not absolute, the operation + /// will use the current scope, or the world root. + pub fn lookupByPath(self: *Self, path: Path) !Entity(ctx) { + var parent = if (path.absolute) 0 else c.ecs_get_scope(self.raw); + var current: c.ecs_entity_t = undefined; + for (path.parts) |part| { + current = switch (part) { + .id => |i| c.ecs_get_alive(self.raw, i), + .name => |n| c.ecs_lookup_child(self.raw, parent, n.ptr), + }; + if (current == 0) return error.EntityNotFound; + // If a part is looked up by ID, parent must match. + // If a part is looked up by name, this check isn't necessary. + if (part == .id and parent != c.ecs_get_parent(self.raw, current)) return error.ParentMismatch; + parent = current; + } + return Entity(ctx).fromRaw(self, current); + } + /// Returns the component `Entity` registered for the specified /// type `T`, or an error if an association has not been made. pub fn lookupByType(self: *Self, comptime T: type) !Entity(ctx) {