Skip to content

Commit e8eadfd

Browse files
authored
feat: add 'any' component callback to cpp wrapper (#238)
1 parent 51a8bab commit e8eadfd

File tree

1 file changed

+214
-18
lines changed

1 file changed

+214
-18
lines changed

ecsact/runtime/core.hh

Lines changed: 214 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <map>
66
#include <functional>
77
#include <optional>
8+
#include <cassert>
89
#include "ecsact/runtime/core.h"
910

1011
namespace ecsact::core {
@@ -173,10 +174,37 @@ private:
173174
std::vector<ecsact_action> actions;
174175
};
175176

177+
class any_component_view {
178+
ecsact_component_id _component_id;
179+
const void* _component_data;
180+
181+
public:
182+
inline any_component_view(ecsact_component_id id, const void* data)
183+
: _component_id(id), _component_data(data) {
184+
}
185+
186+
inline any_component_view(const any_component_view&) = default;
187+
inline ~any_component_view() = default;
188+
189+
template<typename C>
190+
auto is() const -> bool {
191+
return _component_id == C::id;
192+
}
193+
194+
template<typename C>
195+
auto as() const -> const C& {
196+
assert(is<C>());
197+
return *static_cast<const C*>(_component_data);
198+
}
199+
};
200+
176201
template<
177202
template<class R, class... Args> typename CallbackContainer = std::function>
178203
class execution_events_collector {
179204
public:
205+
using any_component_callback_t =
206+
CallbackContainer<void(ecsact_entity_id, any_component_view)>;
207+
180208
template<typename C>
181209
using init_component_callback_t =
182210
CallbackContainer<void(ecsact_entity_id, const C&)>;
@@ -202,6 +230,7 @@ public:
202230
auto set_init_callback( //
203231
init_component_callback_t<C> callback
204232
) -> execution_events_collector& {
233+
_current_init_callback = &execution_events_collector::typed_init_callback;
205234
_init_cb[C::id] = //
206235
[callback = std::move(callback)](
207236
ecsact_entity_id entity,
@@ -219,6 +248,8 @@ public:
219248
auto set_update_callback( //
220249
update_component_callback_t<C> callback
221250
) -> execution_events_collector& {
251+
_current_update_callback =
252+
&execution_events_collector::typed_update_callback;
222253
_update_cb[C::id] = //
223254
[callback = std::move(callback)](
224255
ecsact_entity_id entity,
@@ -236,6 +267,8 @@ public:
236267
auto set_remove_callback( //
237268
remove_component_callback_t<C> callback
238269
) -> execution_events_collector& {
270+
_current_remove_callback =
271+
&execution_events_collector::typed_remove_callback;
239272
_remove_cb[C::id] = //
240273
[callback = std::move(callback)](
241274
ecsact_entity_id entity,
@@ -259,20 +292,77 @@ public:
259292
return *this;
260293
}
261294

295+
/**
296+
* Set the init callback for when _any_ component is initialized. Overwrites
297+
* existing init callbacks, including the typed ones.
298+
*
299+
* NOTE: You should prefer @ref set_init_callback over this function.
300+
*/
301+
auto set_any_init_callback( //
302+
any_component_callback_t callback
303+
) -> execution_events_collector& {
304+
if constexpr(std::is_convertible_v<any_component_callback_t, bool>) {
305+
if(!callback) {
306+
return;
307+
}
308+
}
309+
_current_init_callback = &execution_events_collector::any_init_callback;
310+
_any_init_component_cb = callback;
311+
return *this;
312+
}
313+
314+
/**
315+
* Set the update callback for when _any_ component is updated. Overwrites
316+
* existing update callbacks, including the typed ones.
317+
*
318+
* NOTE: You should prefer @ref set_update_callback over this function.
319+
*/
320+
auto set_any_update_callback( //
321+
any_component_callback_t callback
322+
) -> execution_events_collector& {
323+
if constexpr(std::is_convertible_v<any_component_callback_t, bool>) {
324+
if(!callback) {
325+
return;
326+
}
327+
}
328+
_current_update_callback = &execution_events_collector::any_update_callback;
329+
_any_update_component_cb = callback;
330+
return *this;
331+
}
332+
333+
/**
334+
* Set the remove callback for when _any_ component is removed. Overwrites
335+
* existing remove callbacks, including the typed ones.
336+
*
337+
* NOTE: You should prefer @ref set_remove_callback over this function.
338+
*/
339+
auto set_any_remove_callback( //
340+
any_component_callback_t callback
341+
) -> execution_events_collector& {
342+
if constexpr(std::is_convertible_v<any_component_callback_t, bool>) {
343+
if(!callback) {
344+
return;
345+
}
346+
}
347+
_current_remove_callback = &execution_events_collector::any_remove_callback;
348+
_any_remove_component_cb = callback;
349+
return *this;
350+
}
351+
262352
auto c() const -> const ecsact_execution_events_collector {
263353
auto evc = ecsact_execution_events_collector{};
264354
auto user_data =
265355
static_cast<void*>(const_cast<execution_events_collector*>(this));
266356

267-
if(!_init_cb.empty()) {
357+
if(_current_init_callback != nullptr) {
268358
evc.init_callback = &execution_events_collector::init_callback;
269359
evc.init_callback_user_data = user_data;
270360
}
271-
if(!_update_cb.empty()) {
361+
if(_current_update_callback != nullptr) {
272362
evc.update_callback = &execution_events_collector::update_callback;
273363
evc.update_callback_user_data = user_data;
274364
}
275-
if(!_remove_cb.empty()) {
365+
if(_current_remove_callback != nullptr) {
276366
evc.remove_callback = &execution_events_collector::remove_callback;
277367
evc.remove_callback_user_data = user_data;
278368
}
@@ -291,6 +381,9 @@ public:
291381
}
292382

293383
auto clear() -> void {
384+
_current_init_callback = nullptr;
385+
_current_remove_callback = nullptr;
386+
_current_update_callback = nullptr;
294387
_init_cb.clear();
295388
_update_cb.clear();
296389
_remove_cb.clear();
@@ -299,34 +392,129 @@ public:
299392
}
300393

301394
auto empty() const noexcept -> bool {
302-
return _init_cb.empty() && _update_cb.empty() && _remove_cb.empty() &&
303-
!_entity_created_cb.has_value() && !_entity_destroyed_cb.has_value();
395+
return _current_init_callback == nullptr &&
396+
_current_remove_callback == nullptr &&
397+
_current_update_callback == nullptr && !_entity_created_cb.has_value() &&
398+
!_entity_destroyed_cb.has_value();
304399
}
305400

306401
private:
307402
// std::function is used here explicitly for type erasure
308403
using _component_cb_t =
309404
std::function<void(ecsact_entity_id, ecsact_component_id, const void*)>;
310405
using _component_cb_map_t = std::map<ecsact_component_id, _component_cb_t>;
406+
407+
void (execution_events_collector::*_current_init_callback)(
408+
ecsact_entity_id entity_id,
409+
ecsact_component_id component_id,
410+
const void* component_data
411+
) = nullptr;
412+
413+
void (execution_events_collector::*_current_update_callback)(
414+
ecsact_entity_id entity_id,
415+
ecsact_component_id component_id,
416+
const void* component_data
417+
) = nullptr;
418+
419+
void (execution_events_collector::*_current_remove_callback)(
420+
ecsact_entity_id entity_id,
421+
ecsact_component_id component_id,
422+
const void* component_data
423+
) = nullptr;
424+
425+
any_component_callback_t _any_init_component_cb;
426+
any_component_callback_t _any_update_component_cb;
427+
any_component_callback_t _any_remove_component_cb;
428+
311429
_component_cb_map_t _init_cb;
312430
_component_cb_map_t _update_cb;
313431
_component_cb_map_t _remove_cb;
314432

315433
std::optional<entity_created_callback_t> _entity_created_cb;
316434
std::optional<entity_destroyed_callback_t> _entity_destroyed_cb;
317435

436+
auto typed_init_callback(
437+
ecsact_entity_id entity_id,
438+
ecsact_component_id component_id,
439+
const void* component_data
440+
) -> void {
441+
auto itr = _init_cb.find(component_id);
442+
if(itr != _init_cb.end()) {
443+
itr->second(entity_id, component_id, component_data);
444+
}
445+
}
446+
447+
auto any_init_callback(
448+
ecsact_entity_id entity_id,
449+
ecsact_component_id component_id,
450+
const void* component_data
451+
) -> void {
452+
_any_init_component_cb(
453+
entity_id,
454+
any_component_view{component_id, component_data}
455+
);
456+
}
457+
458+
auto typed_update_callback(
459+
ecsact_entity_id entity_id,
460+
ecsact_component_id component_id,
461+
const void* component_data
462+
) -> void {
463+
auto itr = _update_cb.find(component_id);
464+
if(itr != _update_cb.end()) {
465+
itr->second(entity_id, component_id, component_data);
466+
}
467+
}
468+
469+
auto any_update_callback(
470+
ecsact_entity_id entity_id,
471+
ecsact_component_id component_id,
472+
const void* component_data
473+
) -> void {
474+
_any_update_component_cb(
475+
entity_id,
476+
any_component_view{component_id, component_data}
477+
);
478+
}
479+
480+
auto typed_remove_callback(
481+
ecsact_entity_id entity_id,
482+
ecsact_component_id component_id,
483+
const void* component_data
484+
) -> void {
485+
auto itr = _remove_cb.find(component_id);
486+
if(itr != _remove_cb.end()) {
487+
itr->second(entity_id, component_id, component_data);
488+
}
489+
}
490+
491+
auto any_remove_callback(
492+
ecsact_entity_id entity_id,
493+
ecsact_component_id component_id,
494+
const void* component_data
495+
) -> void {
496+
_any_remove_component_cb(
497+
entity_id,
498+
any_component_view{component_id, component_data}
499+
);
500+
}
501+
318502
static void init_callback(
319-
ecsact_event event,
503+
ecsact_event,
320504
ecsact_entity_id entity_id,
321505
ecsact_component_id component_id,
322506
const void* component_data,
323507
void* callback_user_data
324508
) {
325509
auto self = static_cast<execution_events_collector*>(callback_user_data);
326-
327-
auto itr = self->_init_cb.find(component_id);
328-
if(itr != self->_init_cb.end()) {
329-
itr->second(entity_id, component_id, component_data);
510+
if(self->_current_init_callback) {
511+
std::invoke(
512+
self->_current_init_callback,
513+
*self,
514+
entity_id,
515+
component_id,
516+
component_data
517+
);
330518
}
331519
}
332520

@@ -338,10 +526,14 @@ private:
338526
void* callback_user_data
339527
) {
340528
auto self = static_cast<execution_events_collector*>(callback_user_data);
341-
342-
auto itr = self->_update_cb.find(component_id);
343-
if(itr != self->_update_cb.end()) {
344-
itr->second(entity_id, component_id, component_data);
529+
if(self->_current_update_callback) {
530+
std::invoke(
531+
self->_current_update_callback,
532+
*self,
533+
entity_id,
534+
component_id,
535+
component_data
536+
);
345537
}
346538
}
347539

@@ -353,10 +545,14 @@ private:
353545
void* callback_user_data
354546
) {
355547
auto self = static_cast<execution_events_collector*>(callback_user_data);
356-
357-
auto itr = self->_remove_cb.find(component_id);
358-
if(itr != self->_remove_cb.end()) {
359-
itr->second(entity_id, component_id, component_data);
548+
if(self->_current_remove_callback) {
549+
std::invoke(
550+
self->_current_remove_callback,
551+
*self,
552+
entity_id,
553+
component_id,
554+
component_data
555+
);
360556
}
361557
}
362558

0 commit comments

Comments
 (0)