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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
|
const std = @import("std");
const Allocator = std.mem.Allocator;
const components = @import("components.zig");
const sparse = @import("sparse.zig");
pub const System = *const fn (*Pool) void;
pub const SystemGroup = []const 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 getQuery(self: *@This(), comptime T: type) []T {
const set = switch (T) {
components.Speed => &self.speed,
components.Position => &self.position,
else => unreachable,
};
return set.components.items;
}
pub fn getEntity(self: *@This(), component: usize, comptime T: type) usize {
const set = switch (T) {
components.Speed => &self.speed,
components.Position => &self.position,
else => unreachable,
};
return set.dense.items[component];
}
pub fn getComponent(self: *@This(), entity: usize, comptime T: type) ?T {
const set = switch (T) {
components.Speed => &self.speed,
components.Position => &self.position,
else => unreachable,
};
if (self.hasComponent(entity, T)) {
return set.components.items[set.sparse.items[entity]];
} else {
return null;
}
}
pub fn hasComponent(self: *@This(), entity: usize, component: type) bool {
const set = switch (component) {
components.Speed => &self.speed,
components.Position => &self.position,
else => unreachable,
};
return set.dense.items[set.sparse.items[entity]] == entity;
}
pub fn addSystemGroup(self: *@This(), group: SystemGroup) !void {
try self.system_groups.append(group);
}
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 (0..self.system_groups.items.len) |i| {
self.thread_pool.spawnWg(&self.wait_group, struct {
fn run(pool: *Pool, index: usize) void {
const group = pool.system_groups.items[index];
for (group) |system| {
system(pool);
}
}
}.run, .{ self, i });
}
}
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);
}
};
|