sigh mixin: automatic signal registration for components (#1168)

This commit is contained in:
Terens
2024-09-11 08:26:54 +02:00
committed by Michele Caini
parent 6d03f4d6f2
commit 42a1905690
2 changed files with 113 additions and 1 deletions

View File

@@ -11,6 +11,42 @@
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename T, typename Reg, typename = void>
struct has_on_construct final: std::false_type {};
template<typename T, typename Reg>
struct has_on_construct<
T, Reg,
std::void_t<decltype(T::on_construct(std::declval<Reg &>(),
std::declval<Reg &>().create()))>>
: std::true_type {};
template<typename T, typename Reg, typename = void>
struct has_on_update final: std::false_type {};
template<typename T, typename Reg>
struct has_on_update<
T, Reg,
std::void_t<decltype(T::on_update(std::declval<Reg &>(),
std::declval<Reg &>().create()))>>
: std::true_type {};
template<typename T, typename Reg, typename = void>
struct has_on_destroy final: std::false_type {};
template<typename T, typename Reg>
struct has_on_destroy<
T, Reg,
std::void_t<decltype(T::on_destroy(std::declval<Reg &>(),
std::declval<Reg &>().create()))>>
: std::true_type {};
} // namespace internal
/*! @endcond */
/**
* @brief Mixin type used to add signal support to storage types.
*
@@ -108,7 +144,21 @@ public:
owner{},
construction{allocator},
destruction{allocator},
update{allocator} {}
update{allocator} {
using element_type = typename Type::element_type;
if constexpr(internal::has_on_construct<element_type, Registry>::value) {
entt::sink{construction}.template connect<&element_type::on_construct>();
}
if constexpr(internal::has_on_update<element_type, Registry>::value) {
entt::sink{update}.template connect<&element_type::on_update>();
}
if constexpr(internal::has_on_destroy<element_type, Registry>::value) {
entt::sink{destruction}.template connect<&element_type::on_destroy>();
}
}
/*! @brief Default copy constructor, deleted on purpose. */
basic_sigh_mixin(const basic_sigh_mixin &) = delete;

View File

@@ -0,0 +1,62 @@
#include <gtest/gtest.h>
#include <entt/entity/registry.hpp>
struct count_tracker final {
inline static void on_construct(entt::registry &, entt::entity) {
++created;
}
inline static void on_update(entt::registry &, entt::entity) {
++updated;
}
inline static void on_destroy(entt::registry &, entt::entity) {
++destroyed;
}
inline static std::size_t created = 0;
inline static std::size_t updated = 0;
inline static std::size_t destroyed = 0;
inline static std::size_t alive() {
return created - destroyed;
}
};
template<typename Type>
struct StorageSignals: testing::Test {
using type = Type;
};
using StorageSignalsTypes = ::testing::Types<count_tracker>;
TYPED_TEST_SUITE(StorageSignals, StorageSignalsTypes, );
TYPED_TEST(StorageSignals, AutoSignals) {
using value_type = typename TestFixture::type;
entt::registry registry;
auto const id = registry.create();
registry.emplace<count_tracker>(id);
ASSERT_EQ(count_tracker::created, 1);
ASSERT_EQ(count_tracker::updated, 0);
ASSERT_EQ(count_tracker::destroyed, 0);
ASSERT_EQ(count_tracker::alive(), 1);
registry.replace<count_tracker>(id);
ASSERT_EQ(count_tracker::created, 1);
ASSERT_EQ(count_tracker::updated, 1);
ASSERT_EQ(count_tracker::destroyed, 0);
ASSERT_EQ(count_tracker::alive(), 1);
registry.remove<count_tracker>(id);
ASSERT_EQ(count_tracker::created, 1);
ASSERT_EQ(count_tracker::updated, 1);
ASSERT_EQ(count_tracker::destroyed, 1);
ASSERT_EQ(count_tracker::alive(), 0);
}