diff --git a/zig-ecs/examples/view_vs_group.zig b/zig-ecs/examples/view_vs_group.zig index b7f84a2..94eaf8c 100644 --- a/zig-ecs/examples/view_vs_group.zig +++ b/zig-ecs/examples/view_vs_group.zig @@ -28,6 +28,7 @@ fn createEntities(reg: *ecs.Registry) void { reg.add(e1, Position{ .x = 1, .y = 1 }); reg.add(e1, Velocity{ .x = 1, .y = 1 }); } + var end = timer.lap(); std.debug.warn("create entities: \t{d}\n", .{@intToFloat(f64, end) / 1000000000}); } @@ -104,11 +105,8 @@ fn owningGroup(reg: *ecs.Registry) void { if (index == 0) break; index -= 1; - const ent = storage.set.dense.items[index]; - const entity_index = storage.set.index(ent); - - pos[entity_index].x += pos[entity_index].x; - pos[entity_index].y += pos[entity_index].y; + pos[index].x += pos[index].x; + pos[index].y += pos[index].y; } end = timer.lap(); diff --git a/zig-ecs/src/ecs/component_storage.zig b/zig-ecs/src/ecs/component_storage.zig index 7de8234..8190545 100644 --- a/zig-ecs/src/ecs/component_storage.zig +++ b/zig-ecs/src/ecs/component_storage.zig @@ -27,8 +27,9 @@ pub fn ComponentStorage(comptime Component: type, comptime Entity: type) type { allocator: ?*std.mem.Allocator, /// doesnt really belong here...used to denote group ownership super: usize = 0, - safe_deinit: fn (*Self) void, - safe_swap: fn (*Self, Entity, Entity, bool) void, + safeDeinit: fn (*Self) void, + safeSwap: fn (*Self, Entity, Entity, bool) void, + safeRemoveIfContains: fn (*Self, Entity) void, construction: Signal(Entity), update: Signal(Entity), destruction: Signal(Entity), @@ -37,14 +38,14 @@ pub fn ComponentStorage(comptime Component: type, comptime Entity: type) type { var store = Self{ .set = SparseSet(Entity).initPtr(allocator), .instances = undefined, - .safe_deinit = struct { + .safeDeinit = struct { fn deinit(self: *Self) void { if (!is_empty_struct) { self.instances.deinit(); } } }.deinit, - .safe_swap = struct { + .safeSwap = struct { fn swap(self: *Self, lhs: Entity, rhs: Entity, instances_only: bool) void { if (!is_empty_struct) { std.mem.swap(Component, &self.instances.items[self.set.index(lhs)], &self.instances.items[self.set.index(rhs)]); @@ -52,6 +53,13 @@ pub fn ComponentStorage(comptime Component: type, comptime Entity: type) type { if (!instances_only) self.set.swap(lhs, rhs); } }.swap, + .safeRemoveIfContains = struct { + fn removeIfContains(self: *Self, entity: Entity) void { + if (self.contains(entity)) { + self.remove(entity); + } + } + }.removeIfContains, .allocator = null, .construction = Signal(Entity).init(allocator), .update = Signal(Entity).init(allocator), @@ -78,7 +86,7 @@ pub fn ComponentStorage(comptime Component: type, comptime Entity: type) type { store.destruction = Signal(Entity).init(allocator); // since we are stored as a pointer, we need to catpure this - store.safe_deinit = struct { + store.safeDeinit = struct { fn deinit(self: *Self) void { if (!is_empty_struct) { self.instances.deinit(); @@ -86,7 +94,7 @@ pub fn ComponentStorage(comptime Component: type, comptime Entity: type) type { } }.deinit; - store.safe_swap = struct { + store.safeSwap = struct { fn swap(self: *Self, lhs: Entity, rhs: Entity, instances_only: bool) void { if (!is_empty_struct) { std.mem.swap(Component, &self.instances.items[self.set.index(lhs)], &self.instances.items[self.set.index(rhs)]); @@ -95,6 +103,14 @@ pub fn ComponentStorage(comptime Component: type, comptime Entity: type) type { } }.swap; + store.safeRemoveIfContains = struct { + fn removeIfContains(self: *Self, entity: Entity) void { + if (self.contains(entity)) { + self.remove(entity); + } + } + }.removeIfContains; + return store; } @@ -102,7 +118,7 @@ pub fn ComponentStorage(comptime Component: type, comptime Entity: type) type { // great care must be taken here. Due to how Registry keeps this struct as pointers anything touching a type // will be wrong since it has to cast to a random struct when deiniting. Because of all that, is_empty_struct // will allways be false here so we have to deinit the instances no matter what. - self.safe_deinit(self); + self.safeDeinit(self); self.set.deinit(); self.construction.deinit(); self.update.deinit(); @@ -156,6 +172,14 @@ pub fn ComponentStorage(comptime Component: type, comptime Entity: type) type { return self.set.contains(entity); } + pub fn removeIfContains(self: *Self, entity: Entity) void { + if (Component == u1) { + self.safeRemoveIfContains(self, entity); + } else if (self.contains(entity)) { + self.remove(entity); + } + } + pub fn len(self: Self) usize { return self.set.len(); } @@ -213,10 +237,10 @@ pub fn ComponentStorage(comptime Component: type, comptime Entity: type) type { storage: *Self, pub fn swap(this: @This(), a: Entity, b: Entity) void { - this.storage.safe_swap(this.storage, a, b, true); + this.storage.safeSwap(this.storage, a, b, true); } }; - const swap_context = SortContext{.storage = self}; + const swap_context = SortContext{ .storage = self }; self.set.arrange(length, context, lessThan, swap_context); } else { const SortContext = struct { @@ -231,11 +255,11 @@ pub fn ComponentStorage(comptime Component: type, comptime Entity: type) type { } pub fn swap(this: @This(), a: Entity, b: Entity) void { - this.storage.safe_swap(this.storage, a, b, true); + this.storage.safeSwap(this.storage, a, b, true); } }; - const swap_context = SortContext{.storage = self, .wrapped_context = context, .lessThan = lessThan}; + const swap_context = SortContext{ .storage = self, .wrapped_context = context, .lessThan = lessThan }; self.set.arrange(length, swap_context, SortContext.sort, swap_context); } } @@ -253,7 +277,7 @@ pub fn ComponentStorage(comptime Component: type, comptime Entity: type) type { /// Swaps entities and objects in the internal packed arrays pub fn swap(self: *Self, lhs: Entity, rhs: Entity) void { - self.safe_swap(self, lhs, rhs, false); + self.safeSwap(self, lhs, rhs, false); } pub fn clear(self: *Self) void { diff --git a/zig-ecs/src/ecs/groups.zig b/zig-ecs/src/ecs/groups.zig index ef55d71..9c558d9 100644 --- a/zig-ecs/src/ecs/groups.zig +++ b/zig-ecs/src/ecs/groups.zig @@ -101,14 +101,11 @@ pub const OwningGroup = struct { if (it.index == 0) return null; it.index -= 1; - const ent = it.storage.set.dense.items[it.index]; - const entity_index = it.storage.set.index(ent); - // fill and return the struct var comps: Components = undefined; inline for (@typeInfo(Components).Struct.fields) |field, i| { const typed_ptr = @ptrCast([*]field.field_type.Child, @alignCast(@alignOf(field.field_type.Child), it.component_ptrs[i])); - @field(comps, field.name) = &typed_ptr[entity_index]; + @field(comps, field.name) = &typed_ptr[it.index]; } return comps; } @@ -200,36 +197,9 @@ pub const OwningGroup = struct { self.validate(Components); // optionally we could just use an Iterator here and pay for some slight indirection for code sharing - // var iter = self.iterator(Components); - // while (iter.next()) |comps| { - // @call(.{ .modifier = .always_inline }, func, .{comps}); - // } - - const component_info = @typeInfo(Components).Struct; - - // get the data pointers for the requested component types - var component_ptrs: [component_info.fields.len][*]u8 = undefined; - inline for (component_info.fields) |field, i| { - const storage = self.registry.assure(field.field_type.Child); - component_ptrs[i] = @ptrCast([*]u8, storage.instances.items.ptr); - } - - var storage = self.firstOwnedStorage(); - var index: usize = self.group_data.current; - while (true) { - if (index == 0) return; - index -= 1; - - const ent = storage.set.dense.items[index]; - const entity_index = storage.set.index(ent); - - var comps: Components = undefined; - inline for (component_info.fields) |field, i| { - const typed_ptr = @ptrCast([*]field.field_type.Child, @alignCast(@alignOf(field.field_type.Child), component_ptrs[i])); - @field(comps, field.name) = &typed_ptr[entity_index]; - } - - func(comps); + var iter = self.iterator(Components); + while (iter.next()) |comps| { + @call(.{ .modifier = .always_inline }, func, .{comps}); } } diff --git a/zig-ecs/src/ecs/registry.zig b/zig-ecs/src/ecs/registry.zig index dbadfb7..16e4939 100644 --- a/zig-ecs/src/ecs/registry.zig +++ b/zig-ecs/src/ecs/registry.zig @@ -334,8 +334,9 @@ pub const Registry = struct { pub fn removeIfExists(self: *Registry, comptime T: type, entity: Entity) void { assert(self.valid(entity)); var store = self.assure(T); - if (store.contains(entity)) + if (store.contains(entity)) { store.remove(entity); + } } /// Removes all the components from an entity and makes it orphaned @@ -345,8 +346,8 @@ pub const Registry = struct { var it = self.components.iterator(); while (it.next()) |ptr| { // HACK: we dont know the Type here but we need to be able to call methods on the Storage(T) - var store = @intToPtr(*Storage(u128), ptr.value); - if (store.contains(entity)) store.remove(entity); + var store = @intToPtr(*Storage(u1), ptr.value); + store.removeIfContains(entity); } }