singletons
This commit is contained in:
parent
07905d0b09
commit
37af42daaa
@ -6,6 +6,7 @@ const Handles = @import("handles.zig").Handles;
|
||||
const SparseSet = @import("sparse_set.zig").SparseSet;
|
||||
const ComponentStorage = @import("component_storage.zig").ComponentStorage;
|
||||
const Sink = @import("../signals/sink.zig").Sink;
|
||||
const TypeStore = @import("type_store.zig").TypeStore;
|
||||
|
||||
// allow overriding EntityTraits by setting in root via: EntityTraits = EntityTraitsType(.medium);
|
||||
const root = @import("root");
|
||||
@ -15,10 +16,10 @@ const entity_traits = if (@hasDecl(root, "EntityTraits")) root.EntityTraits.init
|
||||
const EntityHandles = Handles(entity_traits.entity_type, entity_traits.index_type, entity_traits.version_type);
|
||||
pub const Entity = entity_traits.entity_type;
|
||||
|
||||
pub const BasicView = @import("views.zig").BasicView;
|
||||
pub const MultiView = @import("views.zig").MultiView;
|
||||
pub const BasicGroup = @import("groups.zig").BasicGroup;
|
||||
pub const OwningGroup = @import("groups.zig").OwningGroup;
|
||||
const BasicView = @import("views.zig").BasicView;
|
||||
const MultiView = @import("views.zig").MultiView;
|
||||
const BasicGroup = @import("groups.zig").BasicGroup;
|
||||
const OwningGroup = @import("groups.zig").OwningGroup;
|
||||
|
||||
/// Stores an ArrayList of components. The max amount that can be stored is based on the type below
|
||||
pub fn Storage(comptime CompT: type) type {
|
||||
@ -33,6 +34,7 @@ pub const Registry = struct {
|
||||
components: std.AutoHashMap(u32, usize),
|
||||
contexts: std.AutoHashMap(u32, usize),
|
||||
groups: std.ArrayList(*GroupData),
|
||||
singletons: TypeStore,
|
||||
allocator: *std.mem.Allocator,
|
||||
|
||||
/// internal, persistant data structure to manage the entities in a group
|
||||
@ -141,6 +143,7 @@ pub const Registry = struct {
|
||||
.components = std.AutoHashMap(u32, usize).init(allocator),
|
||||
.contexts = std.AutoHashMap(u32, usize).init(allocator),
|
||||
.groups = std.ArrayList(*GroupData).init(allocator),
|
||||
.singletons = TypeStore.init(allocator),
|
||||
.allocator = allocator,
|
||||
};
|
||||
}
|
||||
@ -160,6 +163,7 @@ pub const Registry = struct {
|
||||
self.components.deinit();
|
||||
self.contexts.deinit();
|
||||
self.groups.deinit();
|
||||
self.singletons.deinit();
|
||||
self.handles.deinit();
|
||||
}
|
||||
|
||||
@ -303,7 +307,7 @@ pub const Registry = struct {
|
||||
return self.assure(T).getConst(entity);
|
||||
}
|
||||
|
||||
/// Returns a reference to the given component for an entity
|
||||
/// Returns a reference to the given component for an entity creating it if necessary
|
||||
pub fn getOrAdd(self: *Registry, comptime T: type, entity: Entity) *T {
|
||||
if (self.has(T, entity)) return self.get(T, entity);
|
||||
self.add(T, entity, std.mem.zeros(T));
|
||||
@ -353,6 +357,11 @@ pub const Registry = struct {
|
||||
null;
|
||||
}
|
||||
|
||||
/// provides access to a TypeStore letting you add singleton components to the registry
|
||||
pub fn singletons(self: Registry) TypeStore {
|
||||
return self.singletons;
|
||||
}
|
||||
|
||||
/// Checks whether the given component belongs to any group
|
||||
pub fn sortable(self: Registry, comptime T: type) bool {
|
||||
return true;
|
||||
|
89
zig-ecs/src/ecs/type_store.zig
Normal file
89
zig-ecs/src/ecs/type_store.zig
Normal file
@ -0,0 +1,89 @@
|
||||
const std = @import("std");
|
||||
const utils = @import("utils.zig");
|
||||
|
||||
/// stores a single object of type T for each T added
|
||||
pub const TypeStore = struct {
|
||||
map: std.AutoHashMap(u32, []u8),
|
||||
allocator: *std.mem.Allocator,
|
||||
|
||||
pub fn init(allocator: *std.mem.Allocator) TypeStore {
|
||||
return TypeStore{
|
||||
.map = std.AutoHashMap(u32, []u8).init(allocator),
|
||||
.allocator = allocator,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: TypeStore) void {
|
||||
var iter = self.map.iterator();
|
||||
while (iter.next()) |kv| {
|
||||
self.allocator.free(kv.value);
|
||||
}
|
||||
self.map.deinit();
|
||||
}
|
||||
|
||||
/// adds instance, returning a pointer to the item as it lives in the store
|
||||
pub fn add(self: *TypeStore, instance: var) *@TypeOf(instance) {
|
||||
var bytes = self.allocator.alloc(u8, @sizeOf(@TypeOf(instance))) catch unreachable;
|
||||
var ptr = @ptrCast(*@TypeOf(instance), @alignCast(@alignOf(@TypeOf(instance)), bytes));
|
||||
ptr.* = instance;
|
||||
_ = self.map.put(utils.typeId(@TypeOf(instance)), bytes) catch unreachable;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
pub fn get(self: *TypeStore, comptime T: type) *T {
|
||||
if (self.map.getValue(utils.typeId(T))) |bytes| {
|
||||
return @ptrCast(*T, @alignCast(@alignOf(T), bytes));
|
||||
}
|
||||
unreachable;
|
||||
}
|
||||
|
||||
pub fn getConst(self: *TypeStore, comptime T: type) T {
|
||||
return self.get(T).*;
|
||||
}
|
||||
|
||||
pub fn getOrAdd(self: *TypeStore, comptime T: type) *T {
|
||||
if (self.has(T)) return self.get(T);
|
||||
var instance = std.mem.zeroes(T);
|
||||
return self.add(instance);
|
||||
}
|
||||
|
||||
pub fn remove(self: *TypeStore, comptime T: type) void {
|
||||
if (self.map.getValue(utils.typeId(T))) |bytes| {
|
||||
self.allocator.free(bytes);
|
||||
_ = self.map.remove(utils.typeId(T));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has(self: *TypeStore, comptime T: type) bool {
|
||||
return self.map.contains(utils.typeId(T));
|
||||
}
|
||||
};
|
||||
|
||||
test "TypeStore" {
|
||||
const Vector = struct { x: f32 = 0, y: f32 = 0, z: f32 = 0};
|
||||
|
||||
var store = TypeStore.init(std.testing.allocator);
|
||||
defer store.deinit();
|
||||
|
||||
var orig = Vector{.x = 5, .y = 6, .z = 8};
|
||||
var inserted = store.add(orig);
|
||||
std.testing.expect(store.has(Vector));
|
||||
std.testing.expectEqual(inserted.*, Vector{.x = 5, .y = 6, .z = 8});
|
||||
|
||||
var v = store.get(Vector);
|
||||
std.testing.expectEqual(v.*, Vector{.x = 5, .y = 6, .z = 8});
|
||||
v.*.x = 666;
|
||||
|
||||
var v2 = store.get(Vector);
|
||||
std.testing.expectEqual(v2.*, Vector{.x = 666, .y = 6, .z = 8});
|
||||
|
||||
store.remove(Vector);
|
||||
std.testing.expect(!store.has(Vector));
|
||||
|
||||
var v3 = store.getOrAdd(u32);
|
||||
std.testing.expectEqual(v3.*, 0);
|
||||
v3.* = 777;
|
||||
|
||||
var v4 = store.get(u32);
|
||||
std.testing.expectEqual(v3.*, 777);
|
||||
}
|
@ -8,6 +8,7 @@ comptime {
|
||||
_ = @import("ecs/sparse_set.zig");
|
||||
_ = @import("ecs/views.zig");
|
||||
_ = @import("ecs/groups.zig");
|
||||
_ = @import("ecs/type_store.zig");
|
||||
|
||||
// signals
|
||||
_ = @import("signals/delegate.zig");
|
||||
|
@ -53,7 +53,7 @@ test "context not pointer" {
|
||||
// reg.setContext(pos);
|
||||
}
|
||||
|
||||
test "component context get/set/unset" {
|
||||
test "context get/set/unset" {
|
||||
const SomeType = struct { dummy: u1 };
|
||||
|
||||
var reg = Registry.init(std.testing.allocator);
|
||||
@ -72,6 +72,19 @@ test "component context get/set/unset" {
|
||||
std.testing.expectEqual(ctx, null);
|
||||
}
|
||||
|
||||
test "singletons" {
|
||||
var reg = Registry.init(std.testing.allocator);
|
||||
defer reg.deinit();
|
||||
|
||||
var pos = Position{ .x = 5, .y = 5 };
|
||||
var inserted = reg.singletons.add(pos);
|
||||
std.testing.expect(reg.singletons.has(Position));
|
||||
std.testing.expectEqual(inserted.*, pos);
|
||||
|
||||
reg.singletons.remove(Position);
|
||||
std.testing.expect(!reg.singletons.has(Position));
|
||||
}
|
||||
|
||||
test "destroy" {
|
||||
var reg = Registry.init(std.testing.allocator);
|
||||
defer reg.deinit();
|
||||
|
Loading…
x
Reference in New Issue
Block a user