Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement reflection for all components #694

Merged
merged 18 commits into from
Oct 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ set(CUBOS_CORE_SOURCE
"src/cubos/core/reflection/traits/array.cpp"
"src/cubos/core/reflection/traits/dictionary.cpp"
"src/cubos/core/reflection/external/primitives.cpp"
"src/cubos/core/reflection/external/uuid.cpp"
"src/cubos/core/reflection/external/glm.cpp"

"src/cubos/core/data/old/serializer.cpp"
Expand Down Expand Up @@ -82,6 +83,9 @@ set(CUBOS_CORE_SOURCE
"src/cubos/core/ecs/system/commands.cpp"
"src/cubos/core/ecs/blueprint.cpp"
"src/cubos/core/ecs/world.cpp"

"src/cubos/core/geom/box.cpp"
"src/cubos/core/geom/capsule.cpp"
)

# Create core library
Expand Down
56 changes: 56 additions & 0 deletions core/include/cubos/core/ecs/component/reflection.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/// @file
/// @brief Class @ref cubos::core::ecs::ComponentTypeBuilder.
/// @ingroup core-ecs-component

#pragma once

#include <cubos/core/reflection/traits/constructible.hpp>
#include <cubos/core/reflection/traits/fields.hpp>
#include <cubos/core/reflection/type.hpp>

namespace cubos::core::ecs
{
/// @brief Builder for @ref reflection::Type objects which represent component types.
///
/// Used to reduce the amount of boilerplate code required to define a component type.
/// Automatically adds the @ref reflection::ConstructibleTrait and @ref reflection::FieldsTrait.
/// The type @p T must be default-constructible, copy-constructible and move-constructible.
///
/// @tparam T Component type.
template <typename T>
class ComponentTypeBuilder
{
public:
/// @brief Constructs.
/// @param name Component type name, including namespace.
ComponentTypeBuilder(std::string name)
: mType(reflection::Type::create(std::move(name)))
{
mType.with(reflection::ConstructibleTrait::typed<T>().withBasicConstructors().build());
}

/// @brief Adds a field to the component type.
/// @tparam F Field type.
/// @param name Field name.
/// @param pointer Field pointer.
/// @return Builder.
template <typename F>
ComponentTypeBuilder&& withField(std::string name, F T::*pointer) &&
{
mFields.addField(std::move(name), pointer);
return std::move(*this);
}

/// @brief Builds the component type.
/// @return Component type.
reflection::Type& build() &&
{
mType.with(std::move(mFields));
return mType;
}

private:
reflection::Type& mType;
reflection::FieldsTrait mFields;
};
} // namespace cubos::core::ecs
3 changes: 3 additions & 0 deletions core/include/cubos/core/geom/box.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@

#include <cubos/core/data/old/deserializer.hpp>
#include <cubos/core/data/old/serializer.hpp>
#include <cubos/core/reflection/reflect.hpp>

namespace cubos::core::geom
{
/// @brief Represents a box shape.
/// @ingroup core-geom
struct Box
{
CUBOS_REFLECT;

glm::vec3 halfSize{0.5F}; ///< Half size of the box.

/// @brief Computes two opposite corners of the box on the major diagonal.
Expand Down
3 changes: 3 additions & 0 deletions core/include/cubos/core/geom/capsule.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@
#include <cubos/core/data/old/deserializer.hpp>
#include <cubos/core/data/old/serializer.hpp>
#include <cubos/core/geom/aabb.hpp>
#include <cubos/core/reflection/reflect.hpp>

namespace cubos::core::geom
{
/// @brief Represents a capsule or sphere shape.
/// @ingroup core-geom
struct Capsule
{
CUBOS_REFLECT;

float radius = 1.0F; ///< Radius of the capsule.
float length = 0.0F; ///< Length of the capsule.

Expand Down
11 changes: 11 additions & 0 deletions core/include/cubos/core/reflection/external/uuid.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/// @file
/// @brief Reflection declaration for uuids::uuid.
/// @ingroup core-reflection

#pragma once

#include <uuid.h>

#include <cubos/core/reflection/reflect.hpp>

CUBOS_REFLECT_EXTERNAL_DECL(uuids::uuid);
8 changes: 8 additions & 0 deletions core/include/cubos/core/reflection/reflect.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,14 @@ namespace cubos::core::reflection
static const Type& type = Reflect<T>::type();
return type;
}

/// @brief Checks whether the given type @p T is reflectable.
/// @tparam T %Type to check.
template <typename T>
concept Reflectable = requires
{
reflect<T>();
};
} // namespace cubos::core::reflection

/// @brief Helper macro used to pass arguments with commas to other macros, wrapped in parentheses.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ namespace cubos::core::reflection
return mTrait;
}

/// @brief Sets the copy constructor of the type.
/// @brief Sets the default constructor of the type.
/// @return Builder.
Builder&& withDefaultConstructor() &&
{
Expand All @@ -168,6 +168,13 @@ namespace cubos::core::reflection
return memory::move(*this);
}

/// @brief Sets the default, copy and move constructors of the type.
/// @return Builder.
Builder&& withBasicConstructors() &&
{
return memory::move(*this).withDefaultConstructor().withCopyConstructor().withMoveConstructor();
}

private:
ConstructibleTrait mTrait;
};
Expand Down
19 changes: 15 additions & 4 deletions core/include/cubos/core/reflection/traits/fields.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,19 +54,30 @@ namespace cubos::core::reflection
/// @param type Field type.
/// @param name Field name.
/// @param addressOf Getter for the address of the field on a given instance.
void addField(const Type& type, std::string name, AddressOf* addressOf);

/// @copydoc addField(const Type&, std::string, AddressOf*)
/// @return Trait.
FieldsTrait&& withField(const Type& type, std::string name, AddressOf* addressOf) &&;
RiscadoA marked this conversation as resolved.
Show resolved Hide resolved

/// @brief Sets the copy constructor of the type.
/// @brief Adds a field to the type.
/// @tparam O Object type.
/// @tparam F Field type.
/// @param field Field name.
/// @param name Field name.
/// @param pointer Field pointer.
template <typename O, typename F>
void addField(std::string name, F O::*pointer)
{
this->addField(reflect<F>(), std::move(name), new AddressOfImpl<O, F>(pointer));
}

/// @copydoc addField(std::string, F O::*)
/// @return Trait.
template <typename O, typename F>
FieldsTrait&& withField(const std::string& field, F O::*pointer) &&
FieldsTrait&& withField(std::string name, F O::*pointer) &&
{
return std::move(*this).withField(reflect<F>(), field, new AddressOfImpl<O, F>(pointer));
this->addField(std::move(name), pointer);
return std::move(*this);
}

/// @brief Gets the field with the given name.
Expand Down
32 changes: 32 additions & 0 deletions core/samples/ecs/general/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,60 @@
#include <cubos/core/ecs/system/dispatcher.hpp>
#include <cubos/core/ecs/system/system.hpp>
#include <cubos/core/ecs/world.hpp>
#include <cubos/core/reflection/traits/constructible.hpp>
#include <cubos/core/reflection/type.hpp>

using namespace cubos::core;

using reflection::ConstructibleTrait;
using reflection::Type;

struct Player
{
CUBOS_REFLECT;
};

struct Position
{
CUBOS_REFLECT;

float x, y, z;
};

struct Velocity
{
CUBOS_REFLECT;

float x, y, z;
};

struct Parent
{
CUBOS_REFLECT;

ecs::Entity entity;
};

CUBOS_REFLECT_IMPL(Player)
{
return Type::create("Player").with(ConstructibleTrait::typed<Player>().withMoveConstructor().build());
}

CUBOS_REFLECT_IMPL(Position)
{
return Type::create("Position").with(ConstructibleTrait::typed<Position>().withMoveConstructor().build());
}

CUBOS_REFLECT_IMPL(Velocity)
{
return Type::create("Velocity").with(ConstructibleTrait::typed<Velocity>().withMoveConstructor().build());
}

CUBOS_REFLECT_IMPL(Parent)
{
return Type::create("Parent").with(ConstructibleTrait::typed<Parent>().withMoveConstructor().build());
}

namespace cubos::core::data::old
{
void serialize(Serializer& /*unused*/, const Player& /*unused*/, const char* /*unused*/)
Expand Down
6 changes: 1 addition & 5 deletions core/src/cubos/core/ecs/entity/entity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,7 @@ using cubos::core::reflection::Type;
CUBOS_REFLECT_IMPL(Entity)
{
return Type::create("cubos::core::ecs::Entity")
.with(ConstructibleTrait::typed<Entity>()
.withCopyConstructor()
.withMoveConstructor()
.withDefaultConstructor()
.build())
.with(ConstructibleTrait::typed<Entity>().withBasicConstructors().build())
.with(FieldsTrait().withField("index", &Entity::index).withField("generation", &Entity::generation));
}

Expand Down
14 changes: 14 additions & 0 deletions core/src/cubos/core/geom/box.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#include <cubos/core/geom/box.hpp>
#include <cubos/core/reflection/external/glm.hpp>
#include <cubos/core/reflection/traits/constructible.hpp>
#include <cubos/core/reflection/traits/fields.hpp>
#include <cubos/core/reflection/type.hpp>

CUBOS_REFLECT_IMPL(cubos::core::geom::Box)
{
using namespace core::reflection;

return Type::create("cubos::core::geom::Box")
.with(ConstructibleTrait::typed<Box>().withBasicConstructors().build())
.with(FieldsTrait().withField("halfSize", &Box::halfSize));
}
14 changes: 14 additions & 0 deletions core/src/cubos/core/geom/capsule.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#include <cubos/core/geom/capsule.hpp>
#include <cubos/core/reflection/external/primitives.hpp>
#include <cubos/core/reflection/traits/constructible.hpp>
#include <cubos/core/reflection/traits/fields.hpp>
#include <cubos/core/reflection/type.hpp>

CUBOS_REFLECT_IMPL(cubos::core::geom::Capsule)
{
using namespace core::reflection;

return Type::create("cubos::core::geom::Capsule")
.with(ConstructibleTrait::typed<Capsule>().withBasicConstructors().build())
.with(FieldsTrait().withField("radius", &Capsule::radius).withField("length", &Capsule::length));
}
3 changes: 1 addition & 2 deletions core/src/cubos/core/reflection/external/glm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ class AddressOfImpl final : public FieldsTrait::AddressOf
glm::length_t mColumn;
};

#define AUTO_CONSTRUCTIBLE(type) \
ConstructibleTrait::typed<type>().withDefaultConstructor().withCopyConstructor().withMoveConstructor().build()
#define AUTO_CONSTRUCTIBLE(type) ConstructibleTrait::typed<type>().withBasicConstructors().build()

#define AUTO_VEC1(type) FieldsTrait().withField("x", &type::x)
#define AUTO_VEC2(type) AUTO_VEC1(type).withField("y", &type::y)
Expand Down
6 changes: 1 addition & 5 deletions core/src/cubos/core/reflection/external/primitives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,7 @@
#define AUTO_IMPL(type, name) \
CUBOS_REFLECT_EXTERNAL_IMPL(type) \
{ \
return Type::create(name).with(ConstructibleTrait::typed<type>() \
.withDefaultConstructor() \
.withCopyConstructor() \
.withMoveConstructor() \
.build()); \
return Type::create(name).with(ConstructibleTrait::typed<type>().withBasicConstructors().build()); \
}

AUTO_IMPL(bool, "bool")
Expand Down
10 changes: 10 additions & 0 deletions core/src/cubos/core/reflection/external/uuid.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include <cubos/core/reflection/external/uuid.hpp>
#include <cubos/core/reflection/traits/constructible.hpp>
#include <cubos/core/reflection/type.hpp>

CUBOS_REFLECT_EXTERNAL_IMPL(uuids::uuid)
{
using namespace cubos::core::reflection;

return Type::create("uuids::uuid").with(ConstructibleTrait::typed<uuids::uuid>().withBasicConstructors().build());
}
6 changes: 5 additions & 1 deletion core/src/cubos/core/reflection/traits/fields.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ FieldsTrait::~FieldsTrait()
}
}

FieldsTrait&& FieldsTrait::withField(const Type& type, std::string name, AddressOf* addressOf) &&
void FieldsTrait::addField(const Type& type, std::string name, AddressOf* addressOf)
{
for (auto* field = mFirstField; field != nullptr; field = field->mNext)
{
Expand All @@ -106,7 +106,11 @@ FieldsTrait&& FieldsTrait::withField(const Type& type, std::string name, Address
mFirstField = field;
mLastField = field;
}
}

FieldsTrait&& FieldsTrait::withField(const Type& type, std::string name, AddressOf* addressOf) &&
{
this->addField(type, std::move(name), addressOf);
return std::move(*this);
}

Expand Down
3 changes: 3 additions & 0 deletions core/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ include(QuadradosGenerate)
add_executable(
cubos-core-tests
main.cpp
utils.cpp

reflection/reflect.cpp
reflection/type.cpp
reflection/traits/constructible.cpp
reflection/traits/fields.cpp
reflection/external/primitives.cpp
reflection/external/uuid.cpp
reflection/external/glm.cpp
reflection/external/vector.cpp
reflection/external/map.cpp
Expand All @@ -22,6 +24,7 @@ add_executable(
data/fs/file_system.cpp
data/context.cpp

ecs/utils.cpp
ecs/registry.cpp
ecs/world.cpp
ecs/query.cpp
Expand Down
Loading
Loading