start of owning groups
This commit is contained in:
parent
1d1c761c15
commit
df29819b11
@ -29,6 +29,7 @@ pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type, comptime D
|
|||||||
instances: std.ArrayList(CompOrAlmostEmptyT),
|
instances: std.ArrayList(CompOrAlmostEmptyT),
|
||||||
allocator: ?*std.mem.Allocator,
|
allocator: ?*std.mem.Allocator,
|
||||||
safe_deinit: fn (*Self) void,
|
safe_deinit: fn (*Self) void,
|
||||||
|
safe_swap: fn (*Self, EntityT, EntityT) void,
|
||||||
construction: Signal(EntityT),
|
construction: Signal(EntityT),
|
||||||
update: Signal(EntityT),
|
update: Signal(EntityT),
|
||||||
destruction: Signal(EntityT),
|
destruction: Signal(EntityT),
|
||||||
@ -43,6 +44,13 @@ pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type, comptime D
|
|||||||
self.instances.deinit();
|
self.instances.deinit();
|
||||||
}
|
}
|
||||||
}.deinit,
|
}.deinit,
|
||||||
|
.safe_swap = struct {
|
||||||
|
fn swap(self: *Self, lhs: EntityT, rhs: EntityT) void {
|
||||||
|
if (!is_empty_struct)
|
||||||
|
std.mem.swap(CompT, &self.instances.items[self.set.index(lhs)], &self.instances.items[self.set.index(rhs)]);
|
||||||
|
self.set.swap(lhs, rhs);
|
||||||
|
}
|
||||||
|
}.swap,
|
||||||
.allocator = null,
|
.allocator = null,
|
||||||
.construction = Signal(EntityT).init(allocator),
|
.construction = Signal(EntityT).init(allocator),
|
||||||
.update = Signal(EntityT).init(allocator),
|
.update = Signal(EntityT).init(allocator),
|
||||||
@ -73,6 +81,14 @@ pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type, comptime D
|
|||||||
}
|
}
|
||||||
}.deinit;
|
}.deinit;
|
||||||
|
|
||||||
|
store.safe_swap = struct {
|
||||||
|
fn swap(self: *Self, lhs: EntityT, rhs: EntityT) void {
|
||||||
|
if (!is_empty_struct)
|
||||||
|
std.mem.swap(CompT, &self.instances.items[self.set.index(lhs)], &self.instances.items[self.set.index(rhs)]);
|
||||||
|
self.set.swap(lhs, rhs);
|
||||||
|
}
|
||||||
|
}.swap;
|
||||||
|
|
||||||
return store;
|
return store;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,9 +135,9 @@ pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type, comptime D
|
|||||||
|
|
||||||
/// Removes an entity from a storage
|
/// Removes an entity from a storage
|
||||||
pub fn remove(self: *Self, entity: EntityT) void {
|
pub fn remove(self: *Self, entity: EntityT) void {
|
||||||
|
self.destruction.publish(entity);
|
||||||
if (!is_empty_struct)
|
if (!is_empty_struct)
|
||||||
_ = self.instances.swapRemove(self.set.index(entity));
|
_ = self.instances.swapRemove(self.set.index(entity));
|
||||||
self.destruction.publish(entity);
|
|
||||||
self.set.remove(entity);
|
self.set.remove(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,9 +192,7 @@ pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type, comptime D
|
|||||||
|
|
||||||
/// Swaps entities and objects in the internal packed arrays
|
/// Swaps entities and objects in the internal packed arrays
|
||||||
pub fn swap(self: *Self, lhs: EntityT, rhs: EntityT) void {
|
pub fn swap(self: *Self, lhs: EntityT, rhs: EntityT) void {
|
||||||
if (!is_empty_struct)
|
self.safe_swap(self, lhs, rhs);
|
||||||
std.mem.swap(CompT, &self.instances[self.set.index(lhs)], &self.instances[self.set.index(rhs)]);
|
|
||||||
self.set.swap(lhs, rhs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(self: *Self) void {
|
pub fn clear(self: *Self) void {
|
||||||
|
@ -73,6 +73,32 @@ pub fn BasicGroup(comptime n_includes: usize, comptime n_excludes: usize) type {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn OwningGroup(comptime n_owned: usize, comptime n_includes: usize, comptime n_excludes: usize) type {
|
||||||
|
return struct {
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
current: *usize,
|
||||||
|
registry: *Registry,
|
||||||
|
owned_type_ids: [n_owned]u32,
|
||||||
|
include_type_ids: [n_includes]u32,
|
||||||
|
exclude_type_ids: [n_excludes]u32,
|
||||||
|
|
||||||
|
pub fn init(current: *usize, registry: *Registry, owned_type_ids: [n_owned]u32, include_type_ids: [n_includes]u32, exclude_type_ids: [n_excludes]u32) Self {
|
||||||
|
return Self{
|
||||||
|
.current = current,
|
||||||
|
.registry = registry,
|
||||||
|
.owned_type_ids = owned_type_ids,
|
||||||
|
.include_type_ids = include_type_ids,
|
||||||
|
.exclude_type_ids = exclude_type_ids,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(self: Self) usize {
|
||||||
|
return self.current.*;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
test "BasicGroup creation" {
|
test "BasicGroup creation" {
|
||||||
var reg = Registry.init(std.testing.allocator);
|
var reg = Registry.init(std.testing.allocator);
|
||||||
defer reg.deinit();
|
defer reg.deinit();
|
||||||
@ -131,3 +157,30 @@ test "BasicGroup create late" {
|
|||||||
var group = reg.group(.{}, .{ i32, u32 }, .{});
|
var group = reg.group(.{}, .{ i32, u32 }, .{});
|
||||||
std.testing.expectEqual(group.len(), 1);
|
std.testing.expectEqual(group.len(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "OwningGroup" {
|
||||||
|
var reg = Registry.init(std.testing.allocator);
|
||||||
|
defer reg.deinit();
|
||||||
|
|
||||||
|
var group = reg.group(.{i32, u32}, .{}, .{});
|
||||||
|
|
||||||
|
var e0 = reg.create();
|
||||||
|
reg.add(e0, @as(i32, 44));
|
||||||
|
reg.add(e0, @as(u32, 55));
|
||||||
|
std.testing.expectEqual(group.len(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "OwningGroup add/remove" {
|
||||||
|
var reg = Registry.init(std.testing.allocator);
|
||||||
|
defer reg.deinit();
|
||||||
|
|
||||||
|
var group = reg.group(.{i32, u32}, .{}, .{});
|
||||||
|
|
||||||
|
var e0 = reg.create();
|
||||||
|
reg.add(e0, @as(i32, 44));
|
||||||
|
reg.add(e0, @as(u32, 55));
|
||||||
|
std.testing.expectEqual(group.len(), 1);
|
||||||
|
|
||||||
|
reg.remove(i32, e0);
|
||||||
|
std.testing.expectEqual(group.len(), 0);
|
||||||
|
}
|
@ -19,6 +19,7 @@ pub const Entity = entity_traits.entity_type;
|
|||||||
pub const BasicView = @import("views.zig").BasicView;
|
pub const BasicView = @import("views.zig").BasicView;
|
||||||
pub const MultiView = @import("views.zig").MultiView;
|
pub const MultiView = @import("views.zig").MultiView;
|
||||||
pub const BasicGroup = @import("groups.zig").BasicGroup;
|
pub const BasicGroup = @import("groups.zig").BasicGroup;
|
||||||
|
pub const OwningGroup = @import("groups.zig").OwningGroup;
|
||||||
|
|
||||||
/// Stores an ArrayList of components. The max amount that can be stored is based on the type below
|
/// 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 {
|
pub fn Storage(comptime CompT: type) type {
|
||||||
@ -39,11 +40,12 @@ pub const Registry = struct {
|
|||||||
/// internal, persistant data structure to manage the entities in a group
|
/// internal, persistant data structure to manage the entities in a group
|
||||||
const GroupData = struct {
|
const GroupData = struct {
|
||||||
hash: u32,
|
hash: u32,
|
||||||
entity_set: SparseSet(Entity, u16), // TODO: dont hardcode this. put it in EntityTraits maybe. All SparseSets would need to use the value.
|
entity_set: SparseSet(Entity, u16) = undefined, // TODO: dont hardcode this. put it in EntityTraits maybe. All SparseSets would need to use the value.
|
||||||
owned: []u32,
|
owned: []u32,
|
||||||
include: []u32,
|
include: []u32,
|
||||||
exclude: []u32,
|
exclude: []u32,
|
||||||
registry: *Registry,
|
registry: *Registry,
|
||||||
|
current: usize,
|
||||||
|
|
||||||
pub fn initPtr(allocator: *std.mem.Allocator, registry: *Registry, hash: u32, owned: []u32, include: []u32, exclude: []u32) *GroupData {
|
pub fn initPtr(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, include) == null);
|
||||||
@ -52,17 +54,23 @@ pub const Registry = struct {
|
|||||||
|
|
||||||
var group_data = allocator.create(GroupData) catch unreachable;
|
var group_data = allocator.create(GroupData) catch unreachable;
|
||||||
group_data.hash = hash;
|
group_data.hash = hash;
|
||||||
group_data.entity_set = SparseSet(Entity, u16).init(allocator);
|
if (owned.len == 0) {
|
||||||
|
group_data.entity_set = SparseSet(Entity, u16).init(allocator);
|
||||||
|
}
|
||||||
group_data.owned = std.mem.dupe(allocator, u32, owned) catch unreachable;
|
group_data.owned = std.mem.dupe(allocator, u32, owned) catch unreachable;
|
||||||
group_data.include = std.mem.dupe(allocator, u32, include) catch unreachable;
|
group_data.include = std.mem.dupe(allocator, u32, include) catch unreachable;
|
||||||
group_data.exclude = std.mem.dupe(allocator, u32, exclude) catch unreachable;
|
group_data.exclude = std.mem.dupe(allocator, u32, exclude) catch unreachable;
|
||||||
group_data.registry = registry;
|
group_data.registry = registry;
|
||||||
|
group_data.current = 0;
|
||||||
|
|
||||||
return group_data;
|
return group_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *GroupData, allocator: *std.mem.Allocator) void {
|
pub fn deinit(self: *GroupData, allocator: *std.mem.Allocator) void {
|
||||||
self.entity_set.deinit();
|
// only deinit th SparseSet for non-owning groups
|
||||||
|
if (self.owned.len == 0) {
|
||||||
|
self.entity_set.deinit();
|
||||||
|
}
|
||||||
allocator.free(self.owned);
|
allocator.free(self.owned);
|
||||||
allocator.free(self.include);
|
allocator.free(self.include);
|
||||||
allocator.free(self.exclude);
|
allocator.free(self.exclude);
|
||||||
@ -95,6 +103,17 @@ pub const Registry = struct {
|
|||||||
if (isValid and !self.entity_set.contains(entity))
|
if (isValid and !self.entity_set.contains(entity))
|
||||||
self.entity_set.add(entity);
|
self.entity_set.add(entity);
|
||||||
} else {
|
} else {
|
||||||
|
if (isValid) {
|
||||||
|
const ptr = self.registry.components.getValue(@intCast(u8, self.owned[0])).?;
|
||||||
|
if (!(@intToPtr(*Storage(u1), ptr).set.index(entity) < self.current)) {
|
||||||
|
for (self.owned) |tid| {
|
||||||
|
const store_ptr = self.registry.components.getValue(@intCast(u8, tid)).?;
|
||||||
|
var store = @intToPtr(*Storage(u1), store_ptr);
|
||||||
|
store.swap(store.data().*[self.current], entity);
|
||||||
|
}
|
||||||
|
self.current += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
std.debug.assert(self.owned.len >= 0);
|
std.debug.assert(self.owned.len >= 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -104,7 +123,17 @@ pub const Registry = struct {
|
|||||||
if (self.entity_set.contains(entity))
|
if (self.entity_set.contains(entity))
|
||||||
self.entity_set.remove(entity);
|
self.entity_set.remove(entity);
|
||||||
} else {
|
} else {
|
||||||
std.debug.assert(self.owned.len == 0);
|
const ptr = self.registry.components.getValue(@intCast(u8, self.owned[0])).?;
|
||||||
|
var store = @intToPtr(*Storage(u1), ptr);
|
||||||
|
if (store.contains(entity) and store.set.index(entity) < self.current) {
|
||||||
|
self.current -= 1;
|
||||||
|
for (self.owned) |tid| {
|
||||||
|
const store_ptr = self.registry.components.getValue(@intCast(u8, tid)).?;
|
||||||
|
store = @intToPtr(*Storage(u1), store_ptr);
|
||||||
|
std.debug.warn("\n-------- len: {}, curr: {}, ent: {} \n", .{store.data().*.len, self.current, entity});
|
||||||
|
store.swap(store.data().*[self.current], entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -336,6 +365,11 @@ pub const Registry = struct {
|
|||||||
null;
|
null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks whether the given component belongs to any group
|
||||||
|
pub fn sortable(self: Registry, comptime T: type) bool {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn view(self: *Registry, comptime includes: var, comptime excludes: var) ViewType(includes, excludes) {
|
pub fn view(self: *Registry, comptime includes: var, comptime excludes: var) ViewType(includes, excludes) {
|
||||||
if (@typeInfo(@TypeOf(includes)) != .Struct)
|
if (@typeInfo(@TypeOf(includes)) != .Struct)
|
||||||
@compileError("Expected tuple or struct argument, found " ++ @typeName(@TypeOf(args)));
|
@compileError("Expected tuple or struct argument, found " ++ @typeName(@TypeOf(args)));
|
||||||
@ -412,12 +446,12 @@ pub const Registry = struct {
|
|||||||
if (owned.len == 0) {
|
if (owned.len == 0) {
|
||||||
return BasicGroup(includes.len, excludes.len).init(&group_data.entity_set, self, includes_arr, excludes_arr);
|
return BasicGroup(includes.len, excludes.len).init(&group_data.entity_set, self, includes_arr, excludes_arr);
|
||||||
} else {
|
} else {
|
||||||
@compileLog("owned groups not implemented");
|
return OwningGroup(owned.len, includes.len, excludes.len).init(&group_data.current, self, owned_arr, includes_arr, excludes_arr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// we need to create a new GroupData
|
// we need to create a new GroupData
|
||||||
var new_group_data = GroupData.initPtr(self.allocator, self, hash, &[_]u32{}, includes_arr[0..], excludes_arr[0..]);
|
var new_group_data = GroupData.initPtr(self.allocator, self, hash, owned_arr[0..], includes_arr[0..], excludes_arr[0..]);
|
||||||
self.groups.append(new_group_data) catch unreachable;
|
self.groups.append(new_group_data) catch unreachable;
|
||||||
|
|
||||||
// wire up our listeners
|
// wire up our listeners
|
||||||
@ -437,15 +471,19 @@ pub const Registry = struct {
|
|||||||
new_group_data.entity_set.add(entity);
|
new_group_data.entity_set.add(entity);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unreachable;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return BasicGroup(includes.len, excludes.len).init(&new_group_data.entity_set, self, includes_arr, excludes_arr);
|
if (owned.len == 0) {
|
||||||
|
return BasicGroup(includes.len, excludes.len).init(&new_group_data.entity_set, self, includes_arr, excludes_arr);
|
||||||
|
} else {
|
||||||
|
return OwningGroup(owned.len, includes.len, excludes.len).init(&new_group_data.current, self, owned_arr, includes_arr, excludes_arr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// returns the Type that a view will be based on the includes and excludes
|
/// 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 {
|
fn GroupType(comptime owned: var, comptime includes: var, comptime excludes: var) type {
|
||||||
if (owned.len == 0) return BasicGroup(includes.len, excludes.len);
|
if (owned.len == 0) return BasicGroup(includes.len, excludes.len);
|
||||||
unreachable;
|
return OwningGroup(owned.len, includes.len, excludes.len);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user