diff --git a/zig-ecs/src/ecs.zig b/zig-ecs/src/ecs.zig index 24c2edb..62c55e1 100644 --- a/zig-ecs/src/ecs.zig +++ b/zig-ecs/src/ecs.zig @@ -3,8 +3,8 @@ pub const EntityTraitsType = @import("ecs/entity.zig").EntityTraitsType; pub const Entity = @import("ecs/registry.zig").Entity; pub const Registry = @import("ecs/registry.zig").Registry; -pub const BasicView = @import("ecs/view.zig").BasicView; -pub const BasicMultiView = @import("ecs/view.zig").BasicMultiView; +pub const BasicView = @import("ecs/views.zig").BasicView; +pub const BasicMultiView = @import("ecs/views.zig").BasicMultiView; // signals pub const Signal = @import("signals/signal.zig").Signal; diff --git a/zig-ecs/src/ecs/component_storage.zig b/zig-ecs/src/ecs/component_storage.zig index 09d37a0..217a9a4 100644 --- a/zig-ecs/src/ecs/component_storage.zig +++ b/zig-ecs/src/ecs/component_storage.zig @@ -35,7 +35,7 @@ pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type, comptime D pub fn init(allocator: *std.mem.Allocator) Self { var store = Self{ - .set = SparseSet(EntityT, DenseT).init(allocator), + .set = SparseSet(EntityT, DenseT).initPtr(allocator), .instances = undefined, .safe_deinit = struct { fn deinit(self: *Self) void { @@ -57,7 +57,7 @@ pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type, comptime D pub fn initPtr(allocator: *std.mem.Allocator) *Self { var store = allocator.create(Self) catch unreachable; - store.set = SparseSet(EntityT, DenseT).init(allocator); + store.set = SparseSet(EntityT, DenseT).initPtr(allocator); if (!is_empty_struct) store.instances = std.ArrayList(CompOrAlmostEmptyT).init(allocator); store.allocator = allocator; diff --git a/zig-ecs/src/ecs/sparse_set.zig b/zig-ecs/src/ecs/sparse_set.zig index fcf2967..2147fda 100644 --- a/zig-ecs/src/ecs/sparse_set.zig +++ b/zig-ecs/src/ecs/sparse_set.zig @@ -58,23 +58,32 @@ pub fn SparseSet(comptime SparseT: type, comptime DenseT: type) type { sparse: std.ArrayList(DenseT), dense: std.ArrayList(SparseT), entity_mask: SparseT, - allocator: *std.mem.Allocator, + allocator: ?*std.mem.Allocator, - pub fn init(allocator: *std.mem.Allocator) *Self { + pub fn initPtr(allocator: *std.mem.Allocator) *Self { var set = allocator.create(Self) catch unreachable; - set.sparse = std.ArrayList(DenseT).init(allocator); set.dense = std.ArrayList(SparseT).init(allocator); set.entity_mask = std.math.maxInt(SparseT); set.allocator = allocator; - return set; } + pub fn init(allocator: *std.mem.Allocator) Self { + return Self{ + .sparse = std.ArrayList(DenseT).init(allocator), + .dense = std.ArrayList(SparseT).init(allocator), + .entity_mask = std.math.maxInt(SparseT), + .allocator = null, + }; + } + pub fn deinit(self: *Self) void { self.dense.deinit(); self.sparse.deinit(); - self.allocator.destroy(self); + + if (self.allocator) |allocator| + allocator.destroy(self); } fn page(self: Self, sparse: SparseT) usize { @@ -106,7 +115,7 @@ pub fn SparseSet(comptime SparseT: type, comptime DenseT: type) type { /// Increases the capacity of a sparse set. pub fn reserve(self: *Self, cap: usize) void { - self.dense.resize(cap); + self.dense.resize(cap) catch unreachable; } /// Returns the number of elements that a sparse set has currently allocated space for @@ -197,7 +206,7 @@ pub fn SparseSet(comptime SparseT: type, comptime DenseT: type) type { } test "add/remove/clear" { - var set = SparseSet(u32, u8).init(std.testing.allocator); + var set = SparseSet(u32, u8).initPtr(std.testing.allocator); defer set.deinit(); set.add(4); @@ -214,7 +223,7 @@ test "add/remove/clear" { } test "grow" { - var set = SparseSet(u32, u8).init(std.testing.allocator); + var set = SparseSet(u32, u8).initPtr(std.testing.allocator); defer set.deinit(); var i = @as(usize, std.math.maxInt(u8)); @@ -226,7 +235,7 @@ test "grow" { } test "swap" { - var set = SparseSet(u32, u8).init(std.testing.allocator); + var set = SparseSet(u32, u8).initPtr(std.testing.allocator); defer set.deinit(); set.add(4); @@ -240,7 +249,7 @@ test "swap" { } test "data() synced" { - var set = SparseSet(u32, u8).init(std.testing.allocator); + var set = SparseSet(u32, u8).initPtr(std.testing.allocator); defer set.deinit(); set.add(0); diff --git a/zig-ecs/src/tests.zig b/zig-ecs/src/tests.zig index 391c5f8..8cd5be4 100644 --- a/zig-ecs/src/tests.zig +++ b/zig-ecs/src/tests.zig @@ -7,7 +7,8 @@ comptime { _ = @import("ecs/handles.zig"); _ = @import("ecs/sparse_set.zig"); _ = @import("ecs/type_map.zig"); - _ = @import("ecs/view.zig"); + _ = @import("ecs/views.zig"); + _ = @import("ecs/groups.zig"); // signals _ = @import("signals/delegate.zig"); diff --git a/zig-ecs/tests/registry_test.zig b/zig-ecs/tests/registry_test.zig index 9a118f2..2488772 100644 --- a/zig-ecs/tests/registry_test.zig +++ b/zig-ecs/tests/registry_test.zig @@ -26,3 +26,85 @@ test "Registry" { reg.remove(Empty, e1); std.testing.expect(!reg.has(Empty, e1)); } + +test "context get/set/unset" { + var reg = Registry.init(std.testing.allocator); + defer reg.deinit(); + + var ctx = reg.getContext(Position); + std.testing.expectEqual(ctx, null); + + var pos = Position{ .x = 5, .y = 5 }; + reg.setContext(&pos); + ctx = reg.getContext(Position); + std.testing.expectEqual(ctx.?, &pos); + + reg.unsetContext(Position); + ctx = reg.getContext(Position); + std.testing.expectEqual(ctx, null); +} + +// this test should fail +test "context not pointer" { + var reg = Registry.init(std.testing.allocator); + defer reg.deinit(); + + var pos = Position{ .x = 5, .y = 5 }; + // reg.setContext(pos); +} + +test "component context get/set/unset" { + const SomeType = struct { dummy: u1 }; + + var reg = Registry.init(std.testing.allocator); + defer reg.deinit(); + + var ctx = reg.getContext(SomeType); + std.testing.expectEqual(ctx, null); + + var pos = SomeType{ .dummy = 0 }; + reg.setContext(&pos); + ctx = reg.getContext(SomeType); + std.testing.expectEqual(ctx.?, &pos); + + reg.unsetContext(SomeType); + ctx = reg.getContext(SomeType); + std.testing.expectEqual(ctx, null); +} + +test "destroy" { + var reg = Registry.init(std.testing.allocator); + defer reg.deinit(); + + var i = @as(u8, 0); + while (i < 255) : (i += 1) { + const e = reg.create(); + reg.add(e, Position{ .x = @intToFloat(f32, i), .y = @intToFloat(f32, i) }); + } + + reg.destroy(3); + reg.destroy(4); + + i = 0; + while (i < 6) : (i += 1) { + if (i != 3 and i != 4) + std.testing.expectEqual(Position{ .x = @intToFloat(f32, i), .y = @intToFloat(f32, i) }, reg.getConst(Position, i)); + } +} + +test "remove all" { + var reg = Registry.init(std.testing.allocator); + defer reg.deinit(); + + var e = reg.create(); + reg.add(e, Position{ .x = 1, .y = 1 }); + reg.addTyped(u32, e, 666); + + std.testing.expect(reg.has(Position, e)); + std.testing.expect(reg.has(u32, e)); + + reg.removeAll(e); + + std.testing.expect(!reg.has(Position, e)); + std.testing.expect(!reg.has(u32, e)); +}