Add Entity.getPath

main
copygirl 1 year ago
parent 4dbb7b84a8
commit d639e8e5a9
  1. 15
      src/entity.zig
  2. 35
      src/path.zig
  3. 20
      test/entity.zig

@ -1,4 +1,5 @@
const std = @import("std"); const std = @import("std");
const Allocator = std.mem.Allocator;
const c = @import("./c.zig"); const c = @import("./c.zig");
const err = @import("./error.zig"); const err = @import("./error.zig");
@ -6,6 +7,7 @@ const util = @import("./util.zig");
const Id = @import("./id.zig").Id; const Id = @import("./id.zig").Id;
const Lookup = @import("./main.zig").Lookup; const Lookup = @import("./main.zig").Lookup;
const Path = @import("./path.zig").Path;
const World = @import("./world.zig").World; const World = @import("./world.zig").World;
pub const EntityError = error{ pub const EntityError = error{
@ -141,6 +143,13 @@ pub fn Entity(comptime ctx: anytype) type {
c.ecs_delete(self.world.raw, self.raw); c.ecs_delete(self.world.raw, self.raw);
} }
/// Returns the full, absolute `Path` of this `Entity`.
/// The entity is assumed to be alive.
/// See also: `Path.fromEntity(...)`.
pub fn getPath(self: Self, alloc: Allocator) !Path {
return Path.fromEntity(ctx, null, self, alloc);
}
/// Gets the name of this `Entity`, or `null` if none. /// Gets the name of this `Entity`, or `null` if none.
pub fn getName(self: Self) ?[:0]const u8 { pub fn getName(self: Self) ?[:0]const u8 {
const result = c.ecs_get_name(self.world.raw, self.raw); const result = c.ecs_get_name(self.world.raw, self.raw);
@ -163,6 +172,12 @@ pub fn Entity(comptime ctx: anytype) type {
_ = c.ecs_set_symbol(self.world.raw, self.raw, value); _ = c.ecs_set_symbol(self.world.raw, self.raw, value);
} }
/// Gets the parent of this `Entity`, or `null` if it has none.
pub fn getParent(self: Self) ?Self {
const result = c.ecs_get_parent(self.world.raw, self.raw);
return if (result != 0) fromRaw(self.world, result) else null;
}
pub fn get(self: Self, comptime T: type) ?*const T { pub fn get(self: Self, comptime T: type) ?*const T {
const id = Lookup(ctx, T).id; const id = Lookup(ctx, T).id;
return @alignCast(@ptrCast(c.ecs_get_id(self.world.raw, self.raw, id))); return @alignCast(@ptrCast(c.ecs_get_id(self.world.raw, self.raw, id)));

@ -1,6 +1,8 @@
const std = @import("std"); const std = @import("std");
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const Entity = @import("./entity.zig").Entity;
// TODO: Do something better than just `std.debug.assert`. // TODO: Do something better than just `std.debug.assert`.
// TODO: Offer a way to validate paths, like checking for empty parts. // TODO: Offer a way to validate paths, like checking for empty parts.
@ -103,6 +105,39 @@ pub const Path = struct {
}; };
} }
pub fn fromEntity(comptime ctx: type, parent: ?Entity(ctx), child: Entity(ctx), alloc: Allocator) !Path {
if (parent) |p| std.debug.assert(p.raw != 0);
std.debug.assert(child.raw != 0);
const starting_capacity: usize = 12;
var parts = try alloc.alloc(EntityPart, starting_capacity);
var num_parts: usize = 0;
// Traverse up the entity hierarchy starting from the specified child
// entity up until either the specified parent or root of the hierarchy.
var current = child;
while (true) {
std.debug.assert(num_parts == 0 or current.raw != child.raw); // Cycle detected.
parts[num_parts] = if (current.getName()) |name|
.{ .name = name }
else
.{ .id = current.getEntityId() };
num_parts += 1;
current = current.getParent() orelse break;
if (parent != null and current.raw == parent.?.raw) break;
}
parts = try alloc.realloc(parts, num_parts);
std.mem.reverse(EntityPart, parts);
return .{
.absolute = parent != null,
.parts = parts,
.alloc = alloc,
.owns_array = true,
};
}
/// Creates a deep clone of this `Path` using the specified `Allocator`. /// Creates a deep clone of this `Path` using the specified `Allocator`.
pub fn clone(orig: Path, alloc: Allocator) !Path { pub fn clone(orig: Path, alloc: Allocator) !Path {
var parts = try alloc.dupe(EntityPart, orig.parts); var parts = try alloc.dupe(EntityPart, orig.parts);

@ -2,9 +2,11 @@
// https://github.com/SanderMertens/flecs/blob/master/test/api/src/Entity.c // https://github.com/SanderMertens/flecs/blob/master/test/api/src/Entity.c
const std = @import("std"); const std = @import("std");
const alloc = std.testing.allocator;
const expect = std.testing.expect; const expect = std.testing.expect;
const expectEql = std.testing.expectEqual; const expectFmt = std.testing.expectFmt;
const expectStrEql = std.testing.expectEqualStrings; const expectEqual = std.testing.expectEqual;
const expectEqualStrings = std.testing.expectEqualStrings;
const util = @import("./util.zig"); const util = @import("./util.zig");
@ -16,7 +18,7 @@ const World = context.World;
const Entity = context.Entity; const Entity = context.Entity;
test "Entity_init_id" { test "Entity_init_id" {
var world = try World.initMinimal(std.testing.allocator); var world = try World.initMinimal(alloc);
defer world.deinit(); defer world.deinit();
const e = try world.entity(.{}, .{}); const e = try world.entity(.{}, .{});
@ -25,16 +27,14 @@ test "Entity_init_id" {
} }
test "Entity_init_id_name" { test "Entity_init_id_name" {
var world = try World.initMinimal(std.testing.allocator); var world = try World.initMinimal(alloc);
defer world.deinit(); defer world.deinit();
const e = try world.entity(.{ .name = "foo" }, .{}); const e = try world.entity(.{ .name = "foo" }, .{});
// try expect(e.raw != 0); -- Not necessary, world.entity() returns error if result would be 0. // try expect(e.raw != 0); -- Not necessary, world.entity() returns error if result would be 0.
try expectStrEql("foo", e.getName().?); try expectEqualStrings("foo", e.getName().?);
// TODO: Implement EntityPath. const path2 = try e.getPath(alloc);
const path = c.ecs_get_fullpath(world.raw, e.raw); defer path2.deinit();
defer c.ecs_os_api.free_.?(path); try expectFmt("foo", "{}", .{path2});
try expect(path != null);
try expectStrEql("foo", std.mem.sliceTo(path.?, 0));
} }

Loading…
Cancel
Save