|
|
@ -3,7 +3,11 @@ const warn = std.debug.warn;
|
|
|
|
const utils = @import("utils.zig");
|
|
|
|
const utils = @import("utils.zig");
|
|
|
|
|
|
|
|
|
|
|
|
const SparseSet = @import("sparse_set.zig").SparseSet;
|
|
|
|
const SparseSet = @import("sparse_set.zig").SparseSet;
|
|
|
|
|
|
|
|
const Signal = @import("../signals/signal.zig").Signal;
|
|
|
|
|
|
|
|
const Sink = @import("../signals/sink.zig").Sink;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Stores an ArrayList of components along with a SparseSet of entities. The max amount that can be stored is
|
|
|
|
|
|
|
|
/// based on the max value of DenseT
|
|
|
|
pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type, comptime DenseT: type) type {
|
|
|
|
pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type, comptime DenseT: type) type {
|
|
|
|
std.debug.assert(!utils.isComptime(CompT));
|
|
|
|
std.debug.assert(!utils.isComptime(CompT));
|
|
|
|
|
|
|
|
|
|
|
@ -25,6 +29,9 @@ 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,
|
|
|
|
|
|
|
|
construction: Signal(EntityT),
|
|
|
|
|
|
|
|
update: Signal(EntityT),
|
|
|
|
|
|
|
|
destruction: Signal(EntityT),
|
|
|
|
|
|
|
|
|
|
|
|
pub fn init(allocator: *std.mem.Allocator) Self {
|
|
|
|
pub fn init(allocator: *std.mem.Allocator) Self {
|
|
|
|
var store = Self{
|
|
|
|
var store = Self{
|
|
|
@ -37,6 +44,9 @@ pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type, comptime D
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}.deinit,
|
|
|
|
}.deinit,
|
|
|
|
.allocator = null,
|
|
|
|
.allocator = null,
|
|
|
|
|
|
|
|
.construction = Signal(EntityT).init(allocator),
|
|
|
|
|
|
|
|
.update = Signal(EntityT).init(allocator),
|
|
|
|
|
|
|
|
.destruction = Signal(EntityT).init(allocator),
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
if (!is_empty_struct)
|
|
|
|
if (!is_empty_struct)
|
|
|
@ -51,6 +61,9 @@ pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type, comptime D
|
|
|
|
if (!is_empty_struct)
|
|
|
|
if (!is_empty_struct)
|
|
|
|
store.instances = std.ArrayList(CompOrAlmostEmptyT).init(allocator);
|
|
|
|
store.instances = std.ArrayList(CompOrAlmostEmptyT).init(allocator);
|
|
|
|
store.allocator = allocator;
|
|
|
|
store.allocator = allocator;
|
|
|
|
|
|
|
|
store.construction = Signal(EntityT).init(allocator);
|
|
|
|
|
|
|
|
store.update = Signal(EntityT).init(allocator);
|
|
|
|
|
|
|
|
store.destruction = Signal(EntityT).init(allocator);
|
|
|
|
|
|
|
|
|
|
|
|
// since we are stored as a pointer, we need to catpure this
|
|
|
|
// since we are stored as a pointer, we need to catpure this
|
|
|
|
store.safe_deinit = struct {
|
|
|
|
store.safe_deinit = struct {
|
|
|
@ -69,11 +82,26 @@ pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type, comptime D
|
|
|
|
// will allways be false here so we have to deinit the instances no matter what.
|
|
|
|
// will allways be false here so we have to deinit the instances no matter what.
|
|
|
|
self.safe_deinit(self);
|
|
|
|
self.safe_deinit(self);
|
|
|
|
self.set.deinit();
|
|
|
|
self.set.deinit();
|
|
|
|
|
|
|
|
self.construction.deinit();
|
|
|
|
|
|
|
|
self.update.deinit();
|
|
|
|
|
|
|
|
self.destruction.deinit();
|
|
|
|
|
|
|
|
|
|
|
|
if (self.allocator) |allocator|
|
|
|
|
if (self.allocator) |allocator|
|
|
|
|
allocator.destroy(self);
|
|
|
|
allocator.destroy(self);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn onConstruct(self: *Self) Sink(EntityT) {
|
|
|
|
|
|
|
|
return self.construction.sink();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn onUpdate(self: *Self) Sink(EntityT) {
|
|
|
|
|
|
|
|
return self.update.sink();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn onDestruct(self: *Self) Sink(EntityT) {
|
|
|
|
|
|
|
|
return self.destruction.sink();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Increases the capacity of a component storage
|
|
|
|
/// Increases the capacity of a component storage
|
|
|
|
pub fn reserve(self: *Self, cap: usize) void {
|
|
|
|
pub fn reserve(self: *Self, cap: usize) void {
|
|
|
|
self.set.reserve(cap);
|
|
|
|
self.set.reserve(cap);
|
|
|
@ -81,11 +109,20 @@ pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type, comptime D
|
|
|
|
self.instances.items.reserve(cap);
|
|
|
|
self.instances.items.reserve(cap);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Assigns an entity to a storage and constructs its object
|
|
|
|
/// Assigns an entity to a storage and assigns its object
|
|
|
|
pub fn add(self: *Self, entity: EntityT, value: CompT) void {
|
|
|
|
pub fn add(self: *Self, entity: EntityT, value: CompT) void {
|
|
|
|
if (!is_empty_struct)
|
|
|
|
if (!is_empty_struct)
|
|
|
|
_ = self.instances.append(value) catch unreachable;
|
|
|
|
_ = self.instances.append(value) catch unreachable;
|
|
|
|
self.set.add(entity);
|
|
|
|
self.set.add(entity);
|
|
|
|
|
|
|
|
self.construction.publish(entity);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Removes an entity from a storage
|
|
|
|
|
|
|
|
pub fn remove(self: *Self, entity: EntityT) void {
|
|
|
|
|
|
|
|
if (!is_empty_struct)
|
|
|
|
|
|
|
|
_ = self.instances.swapRemove(self.set.index(entity));
|
|
|
|
|
|
|
|
self.destruction.publish(entity);
|
|
|
|
|
|
|
|
self.set.remove(entity);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Checks if a view contains an entity
|
|
|
|
/// Checks if a view contains an entity
|
|
|
@ -106,6 +143,12 @@ pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type, comptime D
|
|
|
|
return self.instances.items;
|
|
|
|
return self.instances.items;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Replaces the given component for an entity
|
|
|
|
|
|
|
|
pub fn replace(self: *Self, entity: EntityT, value: CompT) void {
|
|
|
|
|
|
|
|
self.get(entity).* = value;
|
|
|
|
|
|
|
|
self.update.publish(entity);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns the object associated with an entity
|
|
|
|
/// Returns the object associated with an entity
|
|
|
|
pub fn get(self: *Self, entity: EntityT) *CompT {
|
|
|
|
pub fn get(self: *Self, entity: EntityT) *CompT {
|
|
|
|
std.debug.assert(self.contains(entity));
|
|
|
|
std.debug.assert(self.contains(entity));
|
|
|
@ -131,13 +174,6 @@ pub fn ComponentStorage(comptime CompT: type, comptime EntityT: type, comptime D
|
|
|
|
return self.set.data();
|
|
|
|
return self.set.data();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Removes an entity from a storage
|
|
|
|
|
|
|
|
pub fn remove(self: *Self, entity: EntityT) void {
|
|
|
|
|
|
|
|
if (!is_empty_struct)
|
|
|
|
|
|
|
|
_ = self.instances.swapRemove(self.set.index(entity));
|
|
|
|
|
|
|
|
self.set.remove(entity);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// 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)
|
|
|
|
if (!is_empty_struct)
|
|
|
@ -208,3 +244,34 @@ test "empty component" {
|
|
|
|
store.add(3, Empty{});
|
|
|
|
store.add(3, Empty{});
|
|
|
|
store.remove(3);
|
|
|
|
store.remove(3);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn construct(e: u32) void {
|
|
|
|
|
|
|
|
std.debug.assert(e == 3);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
fn update(e: u32) void {
|
|
|
|
|
|
|
|
std.debug.assert(e == 3);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
fn destruct(e: u32) void {
|
|
|
|
|
|
|
|
std.debug.assert(e == 3);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
test "signals" {
|
|
|
|
|
|
|
|
var store = ComponentStorage(f32, u32, u8).init(std.testing.allocator);
|
|
|
|
|
|
|
|
defer store.deinit();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
store.onConstruct().connect(construct);
|
|
|
|
|
|
|
|
store.onUpdate().connect(update);
|
|
|
|
|
|
|
|
store.onDestruct().connect(destruct);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
store.add(3, 66.45);
|
|
|
|
|
|
|
|
store.replace(3, 45.64);
|
|
|
|
|
|
|
|
store.remove(3);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
store.onConstruct().disconnect(construct);
|
|
|
|
|
|
|
|
store.onUpdate().disconnect(update);
|
|
|
|
|
|
|
|
store.onDestruct().disconnect(destruct);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
store.add(4, 66.45);
|
|
|
|
|
|
|
|
store.replace(4, 45.64);
|
|
|
|
|
|
|
|
store.remove(4);
|
|
|
|
|
|
|
|
}
|
|
|
|