co_ecs 0.9.0
Cobalt ECS
Loading...
Searching...
No Matches
command.hpp
Go to the documentation of this file.
1#pragma once
2
4#include <co_ecs/registry.hpp>
5
6#include <deque>
7#include <mutex>
8#include <variant>
9
10namespace co_ecs {
11
17public:
20 static auto get() -> command_buffer& {
21 static thread_local command_buffer buf;
22 return buf;
23 }
24
27 static void flush(registry& registry) {
28 registry.sync();
29
30 std::lock_guard lk{ _mutex };
31 for (auto* command_buffer : _command_buffers) {
32 command_buffer->play_commands(registry);
33 }
34 }
35
36private:
37 static inline std::mutex _mutex;
38 static inline std::vector<command_buffer*>
39 _command_buffers;
40
41 friend class command_writer;
42 friend class command_entity_ref;
43
45 std::lock_guard lk{ _mutex };
46 _command_buffers.push_back(this);
47 }
48
49 template<typename T>
50 void push(auto&&... args) {
51 _commands.emplace_back(T{ std::forward<decltype(args)>(args)... });
52 }
53
54 auto staging() noexcept -> registry& {
55 return _staging;
56 }
57
58 void play_commands(registry& registry) {
59 while (!_commands.empty()) {
60 auto command = std::move(_commands.front());
61 _commands.pop_front();
62
63 std::visit([&](auto&& cmd) { cmd.execute(_staging, registry); }, command);
64 }
65 }
66
67 class command_create {
68 public:
69 command_create(entity ent, placeholder_entity reserved) : _staging_entity(ent), _reserved(reserved) {
70 }
71
72 void execute(registry& staging, registry& destination) {
73 staging.get_entity(_staging_entity).move(destination, _reserved);
74 }
75
76 private:
77 entity _staging_entity;
78 placeholder_entity _reserved;
79 };
80
81 class command_clone {
82 public:
83 command_clone(entity ent, placeholder_entity reserved) : _entity(ent), _reserved(reserved) {
84 }
85
86 void execute(registry& staging, registry& destination) {
87 destination.get_entity(_entity).clone(_reserved);
88 }
89
90 private:
91 entity _entity;
92 placeholder_entity _reserved;
93 };
94
95 class command_set {
96 public:
97 using set_fn_t = std::function<void(registry&, entity, registry&, entity)>;
98
99 command_set(entity ent, entity dest, set_fn_t fn) :
100 _staging_entity(ent), _destination_entity(dest), _set_fn(std::move(fn)) {
101 }
102
103 void execute(registry& staging, registry& destination) {
104 _set_fn(staging, _staging_entity, destination, _destination_entity);
105 }
106
107 private:
108 entity _staging_entity;
109 entity _destination_entity;
110 set_fn_t _set_fn;
111 };
112
113 class command_remove {
114 public:
115 using remove_fn_t = std::function<void(registry&, entity)>;
116
117 command_remove(entity ent, remove_fn_t fn) : _entity(ent), _remove_fn(std::move(fn)) {
118 }
119
120 void execute(registry& staging, registry& destination) {
121 _remove_fn(destination, _entity);
122 }
123
124 private:
125 entity _entity;
126 remove_fn_t _remove_fn;
127 };
128
129 class command_destroy {
130 public:
131 command_destroy(entity ent) : _entity(ent) {
132 }
133
134 void execute(registry& staging, registry& registry) {
135 registry.get_entity(_entity).destroy();
136 }
137
138 private:
139 entity _entity;
140 };
141
142 using command = std::variant< //
143 command_create,
144 command_clone,
145 command_set,
146 command_remove,
147 command_destroy>;
148
149private:
150 registry _staging;
151 std::deque<command> _commands;
152};
153
154
159public:
165 template<component C, typename... Args>
166 auto set(Args&&... args) -> command_entity_ref& {
167 auto staging_entity = _commands.staging().template create<C>(C{ std::forward<Args>(args)... });
168 _commands.push<command_buffer::command_set>(staging_entity,
169 _entity,
170 [](auto& staging_registry, auto staging_entity, auto& dest_registry, auto dest_entity) {
171 dest_registry.get_entity(dest_entity)
172 .template set<C>(std::move(staging_registry.get_entity(staging_entity).template get<C>()));
173 });
174 return *this;
175 }
176
180 template<component C>
182 _commands.push<command_buffer::command_remove>(
183 _entity, [](auto& registry, auto entity) { registry.get_entity(entity).template remove<C>(); });
184 return *this;
185 }
186
188 void destroy() {
189 _commands.push<command_buffer::command_destroy>(_entity);
190 }
191
194 auto clone() const -> command_entity_ref {
195 auto entity = _registry.reserve();
196 _commands.push<command_buffer::command_clone>(_entity, entity);
197 return command_entity_ref{ _commands, _registry, entity.get_entity() };
198 }
199
202 [[nodiscard]] operator entity() const noexcept {
203 return _entity;
204 }
205
206private:
207 friend class command_writer;
208
210 _commands(commands), _registry(registry), _entity(entity) {
211 }
212
213private:
214 command_buffer& _commands;
215 registry& _registry;
216 entity _entity;
217};
218
236public:
239 command_writer(registry& reg) : _reg(reg), _cmds(command_buffer::get()) {
240 }
241
246 return command_entity_ref{ _cmds, _reg, ent };
247 }
248
253 template<component... Args>
254 auto create(Args&&... args) -> command_entity_ref {
255 auto entity = _reg.reserve();
256 auto staging_entity = _cmds.staging().template create<Args...>(std::forward<Args>(args)...);
257 _cmds.push<command_buffer::command_create>(staging_entity, entity);
258 return command_entity_ref{ _cmds, _reg, entity.get_entity() };
259 }
260
263 void destroy(entity ent) {
264 _cmds.push<command_buffer::command_destroy>(ent);
265 };
266
267private:
268 registry& _reg;
269 command_buffer& _cmds;
270};
271
272
273} // namespace co_ecs
constexpr void sync()
Synchronizes concurently reserved entities.
Definition base_registry.hpp:104
constexpr auto reserve() -> placeholder_entity
Reserves an entity in a thread-safe manner.
Definition base_registry.hpp:98
This class manages command buffers and facilitates command execution.
Definition command.hpp:16
static void flush(registry &registry)
Flushes all commands in the command buffers to the given registry.
Definition command.hpp:27
static auto get() -> command_buffer &
Retrieves the thread-local command buffer instance.
Definition command.hpp:20
This class provides a reference to a command entity, allowing operations such as setting,...
Definition command.hpp:158
auto set(Args &&... args) -> command_entity_ref &
Sets a component of type C for the entity.
Definition command.hpp:166
void destroy()
Destroys the entity.
Definition command.hpp:188
auto remove() -> command_entity_ref &
Removes a component of type C from the entity.
Definition command.hpp:181
auto clone() const -> command_entity_ref
Clones the entity.
Definition command.hpp:194
This class is responsible for writing commands to a command_buffer.
Definition command.hpp:235
auto get_entity(entity ent) -> command_entity_ref
Retrieves a reference to a command entity.
Definition command.hpp:245
void destroy(entity ent)
Destroys an existing entity.
Definition command.hpp:263
auto create(Args &&... args) -> command_entity_ref
Creates a new entity with the given components.
Definition command.hpp:254
command_writer(registry &reg)
Constructs a command_writer with a given registry.
Definition command.hpp:239
Registry is a container for all our entities and components. Components are stored in continuously in...
Definition registry.hpp:13
constexpr auto get_entity(entity ent) noexcept -> entity_ref
Retrieves a mutable reference to an entity.
Definition registry.hpp:51
Component concept. The component must be a struct/class that can be move constructed and move assigna...
Definition component.hpp:86
Definition archetype.hpp:11
detail::handle< struct entity_tag_t > entity
Represents an entity, consisting of an ID and generation.
Definition entity.hpp:13
STL namespace.