start of groups

master
Mike 5 years ago
parent b280002223
commit 2ed3be236b

@ -0,0 +1,37 @@
const std = @import("std");
const utils = @import("utils.zig");
const Registry = @import("registry.zig").Registry;
const Storage = @import("registry.zig").Storage;
const Entity = @import("registry.zig").Entity;
pub fn NonOwningGroup(comptime n_includes: usize, comptime n_excludes: usize) type {
return struct {
const Self = @This();
registry: *Registry,
type_ids: [n_includes]u32,
exclude_type_ids: [n_excludes]u32,
pub fn init(registry: *Registry, type_ids: [n_includes]u32, exclude_type_ids: [n_excludes]u32) Self {
return Self{
.registry = registry,
.type_ids = type_ids,
.exclude_type_ids = exclude_type_ids,
};
}
};
}
test "group creation" {
var reg = Registry.init(std.testing.allocator);
defer reg.deinit();
var e0 = reg.create();
reg.add(e0, @as(i32, -0));
reg.add(e0, @as(u32, 0));
var group = reg.group(.{}, .{i32}, .{});
var group2 = reg.group(.{}, .{u32}, .{});
var group23 = reg.group(.{}, .{i32}, .{});
}

@ -15,8 +15,9 @@ 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("view.zig").BasicView;
pub const BasicMultiView = @import("view.zig").BasicMultiView;
pub const BasicView = @import("views.zig").BasicView;
pub const BasicMultiView = @import("views.zig").BasicMultiView;
pub const NonOwningGroup = @import("groups.zig").NonOwningGroup;
/// 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 {
@ -31,14 +32,51 @@ pub const Registry = struct {
handles: EntityHandles,
components: std.AutoHashMap(u8, usize),
contexts: std.AutoHashMap(u8, usize),
groups: std.ArrayList(GroupData),
allocator: *std.mem.Allocator,
const GroupData = struct {
hash: u32,
entity_set: SparseSet(Entity, u16) = undefined,
owned: []u32,
include: []u32,
exclude: []u32,
pub fn init(allocator: *std.mem.Allocator, registry: *Registry, hash: u32, owned: []u32, include: []u32, exclude: []u32) GroupData {
std.debug.assert(std.mem.indexOfAny(u32, owned, include) == null);
std.debug.assert(std.mem.indexOfAny(u32, owned, exclude) == null);
std.debug.assert(std.mem.indexOfAny(u32, include, exclude) == null);
const group_data = GroupData{
.hash = hash,
.entity_set = SparseSet(Entity, u16).init(allocator),
.owned = std.mem.dupe(allocator, u32, owned) catch unreachable,
.include = std.mem.dupe(allocator, u32, include) catch unreachable,
.exclude = std.mem.dupe(allocator, u32, exclude) catch unreachable,
};
return group_data;
}
pub fn deinit(self: *GroupData, allocator: *std.mem.Allocator) void {
self.entity_set.deinit();
allocator.free(self.owned);
allocator.free(self.include);
allocator.free(self.exclude);
}
pub fn hasSameConstraints(self: *GroupData, owned: []u32, include: []u32, exclude: []u32) bool {
return std.mem.eql(u32, self.owned, owned) and std.mem.eql(u32, self.include, include) and std.mem.eql(u32, self.exclude, exclude);
}
};
pub fn init(allocator: *std.mem.Allocator) Registry {
return Registry{
.typemap = TypeMap.init(allocator),
.handles = EntityHandles.init(allocator),
.components = std.AutoHashMap(u8, usize).init(allocator),
.contexts = std.AutoHashMap(u8, usize).init(allocator),
.groups = std.ArrayList(GroupData).init(allocator),
.allocator = allocator,
};
}
@ -51,8 +89,13 @@ pub const Registry = struct {
storage.deinit();
}
for (self.groups.items) |*grp| {
grp.deinit(self.allocator);
}
self.components.deinit();
self.contexts.deinit();
self.groups.deinit();
self.typemap.deinit();
self.handles.deinit();
}
@ -276,95 +319,73 @@ pub const Registry = struct {
excludes_arr[i] = @as(u32, self.typemap.get(t));
}
return BasicMultiView(includes.len, excludes.len).init(includes_arr, excludes_arr, self);
return BasicMultiView(includes.len, excludes.len).init(self, includes_arr, excludes_arr);
}
/// returns the Type that a view will be based on the includes and excludes
fn ViewType(comptime includes: var, comptime excludes: var) type {
if (includes.len == 1 and excludes.len == 0) return BasicView(includes[0]);
return BasicMultiView(includes.len, excludes.len);
}
};
const Position = struct { x: f32, y: f32 };
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();
pub fn group(self: *Registry, comptime owned: var, comptime includes: var, comptime excludes: var) GroupType(owned, includes, excludes) {
if (@typeInfo(@TypeOf(owned)) != .Struct)
@compileError("Expected tuple or struct argument, found " ++ @typeName(@TypeOf(owned)));
if (@typeInfo(@TypeOf(includes)) != .Struct)
@compileError("Expected tuple or struct argument, found " ++ @typeName(@TypeOf(includes)));
if (@typeInfo(@TypeOf(excludes)) != .Struct)
@compileError("Expected tuple or struct argument, found " ++ @typeName(@TypeOf(excludes)));
std.debug.assert(includes.len + owned.len > 0);
std.debug.assert(includes.len + owned.len + excludes.len >= 1);
var pos = Position{ .x = 5, .y = 5 };
// reg.setContext(pos);
var owned_arr: [owned.len]u32 = undefined;
inline for (owned) |t, i| {
_ = self.assure(t);
owned_arr[i] = @as(u32, self.typemap.get(t));
}
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);
var includes_arr: [includes.len]u32 = undefined;
inline for (includes) |t, i| {
_ = self.assure(t);
includes_arr[i] = @as(u32, self.typemap.get(t));
}
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) });
var excludes_arr: [excludes.len]u32 = undefined;
inline for (excludes) |t, i| {
_ = self.assure(t);
excludes_arr[i] = @as(u32, self.typemap.get(t));
}
reg.destroy(3);
reg.destroy(4);
// create a unique hash to identify the group
var group_data: ?*GroupData = null;
comptime const hash = owned.len + (31 * includes.len) + (31 * 31 * excludes.len);
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));
for (self.groups.items) |*grp| {
if (grp.hash == hash and grp.hasSameConstraints(owned_arr[0..], includes_arr[0..], excludes_arr[0..])) {
group_data = grp;
break;
}
}
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);
// non-owning groups
if (owned.len == 0) {
if (group_data != null) {
return NonOwningGroup(includes.len, excludes.len).init(self, includes_arr, excludes_arr);
}
std.testing.expect(reg.has(Position, e));
std.testing.expect(reg.has(u32, e));
var new_group_data = GroupData.init(self.allocator, self, hash, &[_]u32{}, includes_arr[0..], excludes_arr[0..]);
new_group_data.entity_set.reserve(5);
self.groups.append(new_group_data) catch unreachable;
return NonOwningGroup(includes.len, excludes.len).init(self, includes_arr, excludes_arr);
}
reg.removeAll(e);
@compileLog("owned groups not implemented");
}
std.testing.expect(!reg.has(Position, e));
std.testing.expect(!reg.has(u32, e));
/// returns the Type that a view will be based on the includes and excludes
fn GroupType(comptime owned: var, comptime includes: var, comptime excludes: var) type {
if (owned.len == 0) return NonOwningGroup(includes.len, excludes.len);
unreachable;
}
};

@ -47,9 +47,9 @@ pub fn BasicMultiView(comptime n_includes: usize, comptime n_excludes: usize) ty
return struct {
const Self = @This();
registry: *Registry,
type_ids: [n_includes]u32,
exclude_type_ids: [n_excludes]u32,
registry: *Registry,
pub const Iterator = struct {
view: *Self,
@ -99,26 +99,20 @@ pub fn BasicMultiView(comptime n_includes: usize, comptime n_excludes: usize) ty
}
};
pub fn init(type_ids: [n_includes]u32, exclude_type_ids: [n_excludes]u32, registry: *Registry) Self {
pub fn init(registry: *Registry, type_ids: [n_includes]u32, exclude_type_ids: [n_excludes]u32) Self {
return Self{
.registry = registry,
.type_ids = type_ids,
.exclude_type_ids = exclude_type_ids,
.registry = registry,
};
}
pub fn get(self: *Self, comptime T: type, entity: Entity) *T {
const type_id = self.registry.typemap.get(T);
const ptr = self.registry.components.getValue(type_id).?;
const store = @intToPtr(*Storage(T), ptr);
return store.get(entity);
return self.registry.assure(T).get(entity);
}
pub fn getConst(self: *Self, comptime T: type, entity: Entity) T {
const type_id = self.registry.typemap.get(T);
const ptr = self.registry.components.getValue(type_id).?;
const store = @intToPtr(*Storage(T), ptr);
return store.getConst(entity);
return self.registry.assure(T).getConst(entity);
}
fn sort(self: *Self) void {
Loading…
Cancel
Save