#pragma once #include #include #define NK_HASHED_STATIC_STR(name) inline static constexpr entt::hashed_string name = entt::hashed_string(#name); namespace Nuake { struct HashedFnName { NK_HASHED_STATIC_STR(GetComponentName) NK_HASHED_STATIC_STR(AddToEntity) }; struct HashedFieldPropName { NK_HASHED_STATIC_STR(FloatStep) NK_HASHED_STATIC_STR(FloatMin) NK_HASHED_STATIC_STR(FloatMax) NK_HASHED_STATIC_STR(ResourceFileType) }; struct HashedName { NK_HASHED_STATIC_STR(DisplayName) }; enum class ComponentTypeTrait : uint16_t { None = 0, // Exposes the component to be added via the inspector InspectorExposed = 1 << 0, }; enum class ComponentFieldTrait : uint16_t { None = 0, // Stops field from showing up in the editor inspector Internal = 1 << 0, // Marks the field as temporary (ie, do not serialize) Transient = 1 << 1, }; template constexpr std::underlying_type_t ToUnderlying(Enum e) { return static_cast>(e); } inline ComponentTypeTrait operator|(ComponentTypeTrait lhs, ComponentTypeTrait rhs) { return static_cast(ToUnderlying(lhs) | ToUnderlying(rhs)); } inline ComponentTypeTrait operator&(ComponentTypeTrait lhs, ComponentTypeTrait rhs) { return static_cast(ToUnderlying(lhs) & ToUnderlying(rhs)); } } #define NUAKECOMPONENT(klass, componentName) \ public: \ static std::string ClassName() \ { \ static std::string className = #klass; \ return className; \ } \ \ static std::string ComponentName() \ { \ static std::string name = componentName; \ return name; \ } \ \ static void AddToEntity(entt::entity entity, entt::registry* enttRegistry) \ { \ enttRegistry->emplace_or_replace(entity); \ } \ \ \ static void (*GetInitializeComponentClass())() \ { \ return &klass::InitializeComponentClass; \ } \ \ inline static auto ComponentFactory = entt::meta(); \ static void InternalInitializeClass() \ { \ static bool initialized = false; \ if (initialized) \ return; \ \ ComponentFactory.type(entt::hashed_string(#klass)) \ .traits(ComponentTypeTrait::InspectorExposed); \ ComponentFactory.func<&klass::ComponentName>(HashedFnName::GetComponentName); \ ComponentFactory.func<&klass::AddToEntity>(HashedFnName::AddToEntity); \ \ if (klass::GetInitializeComponentClass() != Component::GetInitializeComponentClass()) \ { \ GetInitializeComponentClass()(); \ } \ \ initialized = true; \ \ } \ \ template \ static auto BindComponentField(const char* varName, const char* displayName) \ { \ return ComponentFactory \ .data(entt::hashed_string(varName)) \ .prop(HashedName::DisplayName, displayName); \ } \ \ template \ static auto BindComponentProperty(const char* varName, const char* displayName) \ { \ return ComponentFactory \ .data(entt::hashed_string(varName)) \ .prop(HashedName::DisplayName, displayName); \ } \ \ static auto FieldFloatLimits(float stepSize, float min, float max) \ { \ return ComponentFactory \ .prop(HashedFieldPropName::FloatStep, stepSize) \ .prop(HashedFieldPropName::FloatMin, min) \ .prop(HashedFieldPropName::FloatMax, max); \ } \ \ static auto ResourceFileRestriction(const char* fileType) \ { \ return ComponentFactory \ .prop(HashedFieldPropName::ResourceFileType, fileType); \ } \ \ template \ static auto SetFlags(Enums... enums) \ { \ static_assert((std::is_enum_v && ...), "All arguments must be of enum class type"); \ return ComponentFactory.traits((static_cast(enums) | ...)); \ }