1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
const std = @import("std");
const Allocator = std.mem.Allocator;
const components = @import("components.zig");
const sparse = @import("sparse.zig");
const System = *const fn (*Pool) void;
const SystemGroup = std.ArrayList(System);
pub const Pool = struct {
// Components
position: sparse.SparseSet(components.Position),
speed: sparse.SparseSet(components.Speed),
system_groups: std.ArrayList(SystemGroup),
thread_pool: *std.Thread.Pool,
wait_group: std.Thread.WaitGroup,
mutex: std.Thread.Mutex,
last_entity: usize,
free_ids: std.ArrayList(usize),
component_flags: std.AutoHashMap(usize, usize),
pub fn init(allocator: Allocator) !@This() {
var pool = @This(){
.position = sparse.SparseSet(components.Position).init(allocator),
.speed = sparse.SparseSet(components.Speed).init(allocator),
.system_groups = std.ArrayList(SystemGroup).init(allocator),
.thread_pool = try allocator.create(std.Thread.Pool),
.wait_group = .{},
.mutex = .{},
.last_entity = 0,
.free_ids = std.ArrayList(usize).init(allocator),
.component_flags = std.AutoHashMap(usize, usize).init(allocator),
};
try pool.thread_pool.init(.{
.allocator = allocator,
.n_jobs = 4,
});
return pool;
}
pub fn deinit(self: *@This(), allocator: Allocator) void {
self.position.deinit();
self.speed.deinit();
self.system_groups.deinit();
self.thread_pool.deinit();
allocator.destroy(self.thread_pool);
self.free_ids.deinit();
self.component_flags.deinit();
}
pub fn tick(self: *@This()) void {
for (self.system_groups) |group| {
self.thread_pool.spawnWg(&self.wait_group, struct {
fn run(pool: *Pool) void {
for (group) |system| {
system(pool);
}
}
}.run, .{self});
}
self.wait_group.wait();
}
pub fn createEntity(self: *@This()) !usize {
const id = self.free_ids.pop() orelse self.last_entity;
self.last_entity += 1;
try self.component_flags.put(id, 0x0);
return id;
}
pub fn destroyEntity(self: *@This(), entity: usize) void {
self.free_ids.append(entity);
const flags = self.component_flags.get(entity);
for (0..components.COMPONENT_NUMBER) |i| {
if (((flags >> i) & 0x1) != 0x0) {
self.removeComponent(entity, i);
}
}
}
pub fn addComponent(self: *@This(), entity: usize, component: anytype) !void {
var set = switch (@TypeOf(component)) {
components.Speed => self.speed,
components.Position => self.position,
else => unreachable,
};
try self.component_flags.put(entity, self.component_flags.get(entity).? | (0x1 << @TypeOf(component).id));
try set.addEntity(entity, component);
}
pub fn removeComponent(self: *@This(), entity: usize, component_id: usize) void {
const set = switch (component_id) {
components.Speed.id => self.speed,
components.Position.id => self.position,
};
self.component_flags.put(entity, self.component_flags.get(entity) & ~(0x1 << component_id));
set.removeEntity(entity);
}
};
|