const ComponentStore = @import("component_store.zig").ComponentStore; const TypeStore = @import("type_store.zig").TypeStore; const Entity = @import("entity.zig").Entity; const std = @import("std"); const mem = std.mem; const testing = std.testing; const Allocator = mem.Allocator; pub const ComponentManager = struct { const Self = @This(); allocator: *Allocator, component_stores: TypeStore, pub fn init(allocator: *Allocator) Self { return Self { .allocator = allocator, .component_stores = TypeStore.init(allocator), }; } pub fn deinit(self: *Self) void { var iter = self.component_stores.map.iterator(); while (iter.next()) |ptr| { // HACK: we dont know the Type here but we need to call deinit var storage = @intToPtr(*ComponentStore(u1), ptr.value); storage.deinit(); self.allocator.destroy(storage); } self.component_stores.deinit(); } pub fn register(self: *Self, comptime TComponent: type) void { const ptr = ComponentStore(TComponent).heapInit(self.allocator); self.component_stores.add(ptr.*); } pub fn set_component(self: *Self, entityID: usize, component: anytype) void { self.component_stores.get(ComponentStore(@TypeOf(component))).*.set(entityID, component); } pub fn get_component(self: *Self, comptime TComponent: type, entityID: usize) !TComponent { return self.component_stores.get(ComponentStore(TComponent)).*.get(entityID) catch |err| return err; } pub fn has_component(self: *Self, comptime TComponent: type, entityID: usize) bool { return self.component_stores.get(ComponentStore(TComponent)).*.has(entityID); } pub fn remove_component(self: *Self, comptime TComponent: type, entityID: usize) void { return self.component_stores.get(ComponentStore(TComponent)).*.remove(entityID); } pub fn read_components(self: *Self, comptime TComponent: type) []TComponent { return self.component_stores.get(ComponentStore(TComponent)).*.all_components(); } pub fn read_entities(self: *Self, comptime TComponent: type) []Entity { return self.component_stores.get(ComponentStore(TComponent)).*.all_entities(); } }; const TestComponent = struct { number: i32, }; test "add component" { const component = TestComponent { .number = 3 }; var component_manager = ComponentManager.init(std.testing.allocator); defer component_manager.deinit(); component_manager.register(TestComponent); component_manager.set_component(2, component); var expectedComponent = try component_manager.get_component(TestComponent, 2); expectedComponent.number = 5; // should be immutable! expectedComponent = try component_manager.get_component(TestComponent, 2); testing.expect(expectedComponent.number == 3); } test "has component" { const component = TestComponent { .number = 69 }; var component_manager = ComponentManager.init(std.testing.allocator); defer component_manager.deinit(); component_manager.register(TestComponent); component_manager.set_component(420, component); testing.expect(component_manager.has_component(TestComponent, 420)); testing.expect(!component_manager.has_component(TestComponent, 39)); } test "remove component" { const component = TestComponent { .number = 3 }; const componentTwo = TestComponent { .number = 8 }; const componentThree = TestComponent { .number = 14 }; var component_manager = ComponentManager.init(std.testing.allocator); defer component_manager.deinit(); component_manager.register(TestComponent); component_manager.set_component(2, component); component_manager.set_component(5, componentTwo); component_manager.set_component(52, componentThree); var components = component_manager.remove_component(TestComponent, 5); testing.expect(!component_manager.has_component(TestComponent, 5)); testing.expect(component_manager.has_component(TestComponent, 52)); } test "read components" { const component = TestComponent { .number = 3 }; const componentTwo = TestComponent { .number = 8 }; const componentThree = TestComponent { .number = 14 }; var component_manager = ComponentManager.init(std.testing.allocator); defer component_manager.deinit(); component_manager.register(TestComponent); component_manager.set_component(2, component); component_manager.set_component(5, componentTwo); component_manager.set_component(52, componentThree); var components = component_manager.read_components(TestComponent); testing.expect(components[0].number == 3); testing.expect(components[1].number == 8); testing.expect(components[2].number == 14); } test "read entities" { const component = TestComponent { .number = 3 }; const componentTwo = TestComponent { .number = 8 }; const componentThree = TestComponent { .number = 14 }; var component_manager = ComponentManager.init(std.testing.allocator); defer component_manager.deinit(); component_manager.register(TestComponent); component_manager.set_component(2, component); component_manager.set_component(5, componentTwo); component_manager.set_component(52, componentThree); var entities = component_manager.read_entities(TestComponent); testing.expect(entities[0].ID == 2); testing.expect(entities[1].ID == 5); testing.expect(entities[2].ID == 52); }