From 972fec57ebb8286fd0f92191e613c52df2bbca20 Mon Sep 17 00:00:00 2001 From: John Kindem <461425614@qq.com> Date: Mon, 14 Oct 2024 21:47:43 +0800 Subject: [PATCH 01/22] feat: misc runtime update --- CMake/Target.cmake | 6 +- .../Source/Common/Include/Common/Container.h | 194 ++++++++++--- Engine/Source/Mirror/Include/Mirror/Meta.h | 8 +- Engine/Source/Mirror/Include/Mirror/Mirror.h | 102 +++---- .../Source/Mirror/Include/Mirror/Registry.h | 38 ++- Engine/Source/Mirror/Src/Mirror.cpp | 62 ++++- .../Source/Mirror/Test/SerializationTest.cpp | 7 + Engine/Source/Mirror/Test/SerializationTest.h | 6 + Engine/Source/Render/Include/Render/Scene.h | 13 +- .../Render/Include/Render/SceneProxy/Light.h | 29 +- .../Include/Render/SceneProxy/Primitive.h | 13 - Engine/Source/Render/Src/SceneProxy/Light.cpp | 37 --- .../Render/Src/SceneProxy/Primitive.cpp | 11 - .../Rendering/Include/Rendering/Scene.h | 10 +- Engine/Source/Rendering/Src/Scene.cpp | 26 +- Engine/Source/Runtime/CMakeLists.txt | 2 +- .../Runtime/Include/Runtime/Component/Light.h | 43 +++ .../Include/Runtime/Component/Transform.h | 20 ++ .../Runtime/Include/Runtime/Component/View.h | 34 +++ .../Runtime/Include/Runtime/System/Scene.h | 25 ++ Engine/Source/Runtime/Include/Runtime/World.h | 261 ++++++++++++------ Engine/Source/Runtime/Src/Component/Light.cpp | 13 + .../Runtime/Src/Component/Transform.cpp | 14 + Engine/Source/Runtime/Src/Component/View.cpp | 37 +++ Engine/Source/Runtime/Src/System/Scene.cpp | 26 ++ Engine/Source/Runtime/Src/World.cpp | 70 +++-- Engine/Source/Runtime/Test/WorldTest.cpp | 11 +- Engine/Source/Runtime/Test/WorldTest.h | 2 +- Tool/MirrorTool/Include/MirrorTool/Parser.h | 5 + Tool/MirrorTool/Src/Generator.cpp | 40 ++- Tool/MirrorTool/Src/Parser.cpp | 16 +- 31 files changed, 834 insertions(+), 347 deletions(-) delete mode 100644 Engine/Source/Render/Include/Render/SceneProxy/Primitive.h delete mode 100644 Engine/Source/Render/Src/SceneProxy/Light.cpp delete mode 100644 Engine/Source/Render/Src/SceneProxy/Primitive.cpp create mode 100644 Engine/Source/Runtime/Include/Runtime/Component/Light.h create mode 100644 Engine/Source/Runtime/Include/Runtime/Component/Transform.h create mode 100644 Engine/Source/Runtime/Include/Runtime/Component/View.h create mode 100644 Engine/Source/Runtime/Include/Runtime/System/Scene.h create mode 100644 Engine/Source/Runtime/Src/Component/Light.cpp create mode 100644 Engine/Source/Runtime/Src/Component/Transform.cpp create mode 100644 Engine/Source/Runtime/Src/Component/View.cpp create mode 100644 Engine/Source/Runtime/Src/System/Scene.cpp diff --git a/CMake/Target.cmake b/CMake/Target.cmake index f88869d5..9fc75294 100644 --- a/CMake/Target.cmake +++ b/CMake/Target.cmake @@ -245,9 +245,11 @@ function(AddMirrorInfoSourceGenerationTarget) foreach (SEARCH_DIR ${PARAMS_SEARCH_DIR}) file(GLOB_RECURSE INPUT_HEADER_FILES "${SEARCH_DIR}/*.h") foreach (INPUT_HEADER_FILE ${INPUT_HEADER_FILES}) - get_filename_component(FILENAME ${INPUT_HEADER_FILE} NAME_WE) + string(REPLACE "${CMAKE_SOURCE_DIR}/" "" TEMP ${INPUT_HEADER_FILE}) + get_filename_component(DIR ${TEMP} DIRECTORY) + get_filename_component(FILENAME ${TEMP} NAME_WE) - set(OUTPUT_SOURCE "${CMAKE_BINARY_DIR}/Generated/MirrorInfoSource/${PARAMS_NAME}/${FILENAME}.generated.cpp") + set(OUTPUT_SOURCE "${CMAKE_BINARY_DIR}/Generated/MirrorInfoSource/${DIR}/${FILENAME}.generated.cpp") list(APPEND OUTPUT_SOURCES ${OUTPUT_SOURCE}) add_custom_command( diff --git a/Engine/Source/Common/Include/Common/Container.h b/Engine/Source/Common/Include/Common/Container.h index f062cbc9..72487ecb 100644 --- a/Engine/Source/Common/Include/Common/Container.h +++ b/Engine/Source/Common/Include/Common/Container.h @@ -4,13 +4,16 @@ #pragma once +#include #include #include #include #include +#include #include #include +#include namespace Common { class VectorUtils { @@ -27,11 +30,8 @@ namespace Common { template static void GetUnionInline(std::unordered_set& lhs, const std::unordered_set& rhs); }; - template - class InplaceVectorIter; - - template - concept ValidInplaceVectorIter = std::is_same_v> || std::is_same_v>; + template class InplaceVectorIter; + template concept ValidInplaceVectorIter = std::is_same_v> || std::is_same_v>; template class InplaceVectorIter { @@ -40,6 +40,11 @@ namespace Common { explicit InplaceVectorIter(T* inPtr); + InplaceVectorIter(const InplaceVectorIter& inOther); + InplaceVectorIter(InplaceVectorIter&& inOther) noexcept; + InplaceVectorIter& operator=(const InplaceVectorIter& inOther); + InplaceVectorIter& operator=(InplaceVectorIter&& inOther) noexcept; + template T2> Offset operator-(const T2& inOther) const; template T2> bool operator==(const T2& inOther) const; template T2> bool operator!=(const T2& inOther) const; @@ -126,14 +131,14 @@ namespace Common { static constexpr size_t memorySize = elementSize * N; template I> void CheckIterValid(const I& inIter) const; - template void EmplaceConstruct(size_t inIndex, Args&&... inArgs); - template I, typename... Args> void EmplaceConstruct(const I& inIter, Args&&... inArgs); - template I> void EmplaceDestruct(const I& inIter); + template void InplaceConstruct(size_t inIndex, Args&&... inArgs); + template I, typename... Args> void InplaceConstruct(const I& inIter, Args&&... inArgs); + template I> void InplaceDestruct(const I& inIter); template T& InsertInternal(size_t inIndex, T2&& inElement); template I, typename T2> T& InsertInternal(const I& inIter, T2&& inElement); template I> void EraseInternal(const I& inIter); template I> void EraseSwapLastInternal(const I& inIter); - void EmplaceDestruct(size_t inIndex); + void InplaceDestruct(size_t inIndex); T& TypedMemory(size_t inIndex); const T& TypedMemory(size_t inIndex) const; void CheckIndexValid(size_t inIndex) const; @@ -142,6 +147,91 @@ namespace Common { size_t size; std::array memory; }; + + // TODO trunk handle + // TODO trunk list handle + + template + class TrunkHandle { + public: + TrunkHandle(); + ~TrunkHandle(); + + NonCopyable(TrunkHandle) + TrunkHandle(TrunkHandle&& inOther) noexcept; + TrunkHandle& operator=(TrunkHandle&& inOther) noexcept; + + // TODO + + private: + T* ptr; + }; + + template + class Trunk { + public: + using TraverseFunc = std::function; + using ConstTraverseFunc = std::function; + + Trunk(); + ~Trunk(); + + Trunk(const Trunk& inOther); + Trunk(Trunk&& inOther) noexcept; + Trunk& operator=(const Trunk& inOther); + Trunk& operator=(Trunk&& inOther) noexcept; + + // TODO use handle version + template T& Allocate(Args&&... inArgs); + bool HasFree() const; + bool Valid(const T& inObj) const; + void Erase(const T& inObj); + void Each(const TraverseFunc& inFunc); + void Each(const ConstTraverseFunc& inFunc) const; + size_t Free() const; + size_t Used() const; + + private: + static constexpr size_t elemMemSize = sizeof(T); + static constexpr size_t totalMemSize = elemMemSize * ElemNumPerTrunk; + + bool CheckContains(const T& inObj); + T& TypedMemory(size_t inIndex); + const T& TypedMemory(size_t inIndex) const; + + std::bitset allocated; + std::array memory; + }; + + // pointer stable + template + class TrunkList { + public: + using TraverseFunc = typename Trunk::TraverseFunc; + using ConstTraverseFunc = typename Trunk::ConstTraverseFunc; + + TrunkList(); + ~TrunkList(); + + TrunkList(const TrunkList& inOther); + TrunkList(TrunkList&& inOther) noexcept; + TrunkList& operator=(const TrunkList& inOther); + TrunkList& operator=(TrunkList&& inOther) noexcept; + + // TODO use handle version + template T& Emplace(Args&&... inArgs); + void Erase(const T& inObj); + bool Valid(const T& inObj) const; + void Each(const TraverseFunc& inFunc); + void Each(const ConstTraverseFunc& inFunc) const; + size_t Size() const; + size_t Capacity() const; + void Reserve(size_t inSize); + void Clear(); + + private: + std::list> trunks; + }; } namespace Common { // NOLINT @@ -214,6 +304,38 @@ namespace Common { } } + template + InplaceVectorIter::InplaceVectorIter(T* inPtr) + : ptr(inPtr) + { + } + + template + InplaceVectorIter::InplaceVectorIter(const InplaceVectorIter& inOther) + : ptr(inOther.ptr) + { + } + + template + InplaceVectorIter::InplaceVectorIter(InplaceVectorIter&& inOther) noexcept + : ptr(inOther.ptr) + { + } + + template + InplaceVectorIter& InplaceVectorIter::operator=(const InplaceVectorIter& inOther) + { + ptr = inOther.ptr; + return *this; + } + + template + InplaceVectorIter& InplaceVectorIter::operator=(InplaceVectorIter&& inOther) noexcept + { + ptr = inOther.ptr; + return *this; + } + template template T2> typename InplaceVectorIter::Offset InplaceVectorIter::operator-(const T2& inOther) const @@ -263,12 +385,6 @@ namespace Common { return ptr <= inOther.Ptr(); } - template - InplaceVectorIter::InplaceVectorIter(T* inPtr) - : ptr(inPtr) - { - } - template T& InplaceVectorIter::operator*() const { @@ -361,7 +477,7 @@ namespace Common { : size(inSize) { for (auto i = 0; i < size; i++) { - EmplaceConstruct(i, inDefault); + InplaceConstruct(i, inDefault); } } @@ -369,7 +485,7 @@ namespace Common { InplaceVector::~InplaceVector() { for (auto i = 0; i < size; i++) { - EmplaceDestruct(i); + InplaceDestruct(i); } } @@ -379,7 +495,7 @@ namespace Common { { static_assert(std::is_copy_constructible_v); for (auto i = 0; i < size; i++) { - EmplaceConstruct(i, inOther.TypedMemory(i)); + InplaceConstruct(i, inOther.TypedMemory(i)); } } @@ -389,7 +505,7 @@ namespace Common { { static_assert(std::is_move_constructible_v); for (auto i = 0; i < size; i++) { - EmplaceConstruct(i, std::move(inOther.TypedMemory(i))); + InplaceConstruct(i, std::move(inOther.TypedMemory(i))); } } @@ -400,14 +516,14 @@ namespace Common { const auto oldSize = size; size = inOther.size; for (auto i = size; i < oldSize; i++) { - EmplaceDestruct(i); + InplaceDestruct(i); } for (auto i = 0; i < size; i++) { if (i < oldSize) { TypedMemory(i) = inOther.TypedMemory(i); } else { - EmplaceConstruct(i, inOther.TypedMemory(i)); + InplaceConstruct(i, inOther.TypedMemory(i)); } } return *this; @@ -420,14 +536,14 @@ namespace Common { const auto oldSize = size; size = inOther.size; for (auto i = size; i < oldSize; i++) { - EmplaceDestruct(i); + InplaceDestruct(i); } for (auto i = 0; i < size; i++) { if (i < oldSize) { TypedMemory(i) = std::move(inOther.TypedMemory(i)); } else { - EmplaceConstruct(i, std::move(inOther.TypedMemory(i))); + InplaceConstruct(i, std::move(inOther.TypedMemory(i))); } } return *this; @@ -439,7 +555,7 @@ namespace Common { { CheckInsertible(); auto lastIndex = size++; - EmplaceConstruct(lastIndex, std::forward(inArgs)...); + InplaceConstruct(lastIndex, std::forward(inArgs)...); return TypedMemory(lastIndex); } @@ -494,7 +610,7 @@ namespace Common { template void InplaceVector::PopBack() { - EmplaceDestruct(size - 1); + InplaceDestruct(size - 1); size--; } @@ -513,7 +629,7 @@ namespace Common { Assert(false); } } - EmplaceDestruct(size - 1); + InplaceDestruct(size - 1); size--; } @@ -542,7 +658,7 @@ namespace Common { } else { Assert(false); } - EmplaceDestruct(size - 1); + InplaceDestruct(size - 1); size--; } @@ -594,14 +710,14 @@ namespace Common { const auto oldSize = size; size = inSize; for (auto i = size; i < oldSize; i++) { - EmplaceDestruct(i); + InplaceDestruct(i); } for (auto i = 0; i < size; i++) { if (i < oldSize) { TypedMemory(i) = inDefault; } else { - EmplaceConstruct(i, inDefault); + InplaceConstruct(i, inDefault); } } } @@ -732,7 +848,7 @@ namespace Common { template template - void InplaceVector::EmplaceConstruct(size_t inIndex, Args&&... inArgs) + void InplaceVector::InplaceConstruct(size_t inIndex, Args&&... inArgs) { CheckIndexValid(inIndex); new(reinterpret_cast(memory.data()) + inIndex) T(std::forward(inArgs)...); @@ -740,7 +856,7 @@ namespace Common { template template I, typename ... Args> - void InplaceVector::EmplaceConstruct(const I& inIter, Args&&... inArgs) + void InplaceVector::InplaceConstruct(const I& inIter, Args&&... inArgs) { CheckIterValid(inIter); new(&*inIter) T(std::forward(inArgs)...); @@ -748,7 +864,7 @@ namespace Common { template template I> - void InplaceVector::EmplaceDestruct(const I& inIter) + void InplaceVector::InplaceDestruct(const I& inIter) { CheckIterValid(inIter); inIter->~T(); @@ -771,9 +887,9 @@ namespace Common { for (auto i = size - 1; i > inIndex; i--) { if (i == size - 1) { if constexpr (std::is_move_constructible_v) { - EmplaceConstruct(i, std::move(TypedMemory(i - 1))); + InplaceConstruct(i, std::move(TypedMemory(i - 1))); } else if constexpr (std::is_copy_constructible_v) { - EmplaceConstruct(i, TypedMemory(i - 1)); + InplaceConstruct(i, TypedMemory(i - 1)); } else { Assert(false); } @@ -809,9 +925,9 @@ namespace Common { for (auto iter = End() - 1; iter > inIter; --iter) { if (iter == End() - 1) { if constexpr (std::is_move_constructible_v) { - EmplaceConstruct(iter, std::move(*(iter - 1))); + InplaceConstruct(iter, std::move(*(iter - 1))); } else if constexpr (std::is_copy_constructible_v) { - EmplaceConstruct(iter, TypedMemory(*(iter - 1))); + InplaceConstruct(iter, TypedMemory(*(iter - 1))); } else { Assert(false); } @@ -846,7 +962,7 @@ namespace Common { Assert(false); } } - EmplaceDestruct(End() - 1); + InplaceDestruct(End() - 1); size--; } @@ -864,12 +980,12 @@ namespace Common { } else { Assert(false); } - EmplaceDestruct(End() - 1); + InplaceDestruct(End() - 1); size--; } template - void InplaceVector::EmplaceDestruct(size_t inIndex) + void InplaceVector::InplaceDestruct(size_t inIndex) { CheckIndexValid(inIndex); TypedMemory(inIndex).~T(); diff --git a/Engine/Source/Mirror/Include/Mirror/Meta.h b/Engine/Source/Mirror/Include/Mirror/Meta.h index 39bb2e22..ebfbad28 100644 --- a/Engine/Source/Mirror/Include/Mirror/Meta.h +++ b/Engine/Source/Mirror/Include/Mirror/Meta.h @@ -5,10 +5,10 @@ #pragma once #if __clang__ -#define EProperty(...) __attribute__((annotate("property;" #__VA_ARGS__))) -#define EFunc(...) __attribute__((annotate("func;" #__VA_ARGS__))) -#define EClass(...) __attribute__((annotate("class;" #__VA_ARGS__))) -#define EEnum(...) __attribute__((annotate("enum;" #__VA_ARGS__))) +#define EProperty(...) __attribute__((annotate("property," #__VA_ARGS__))) +#define EFunc(...) __attribute__((annotate("func," #__VA_ARGS__))) +#define EClass(...) __attribute__((annotate("class," #__VA_ARGS__))) +#define EEnum(...) __attribute__((annotate("enum," #__VA_ARGS__))) #define EMeta(...) __attribute__((annotate(#__VA_ARGS__))) #else #define EProperty(...) diff --git a/Engine/Source/Mirror/Include/Mirror/Mirror.h b/Engine/Source/Mirror/Include/Mirror/Mirror.h index 8f2d8875..bee3ac9b 100644 --- a/Engine/Source/Mirror/Include/Mirror/Mirror.h +++ b/Engine/Source/Mirror/Include/Mirror/Mirror.h @@ -384,6 +384,13 @@ namespace Mirror { std::unordered_map metas; }; + enum class FieldAccess : uint8_t { + faPrivate, + faProtected, + faPublic, + max + }; + class MIRROR_API Variable final : public ReflNode { public: ~Variable() override; @@ -394,6 +401,7 @@ namespace Mirror { const std::string& GetOwnerName() const; const Id& GetOwnerId() const; const Class* GetOwner() const; + FieldAccess GetAccess() const; const TypeInfo* GetTypeInfo() const; void SetDyn(const Argument& inArgument) const; Any GetDyn() const; @@ -410,6 +418,7 @@ namespace Mirror { struct ConstructParams { Id id; Id owner; + FieldAccess access; size_t memorySize; const TypeInfo* typeInfo; Setter setter; @@ -419,6 +428,7 @@ namespace Mirror { explicit Variable(ConstructParams&& params); Id owner; + FieldAccess access; size_t memorySize; const TypeInfo* typeInfo; Setter setter; @@ -432,6 +442,7 @@ namespace Mirror { const std::string& GetOwnerName() const; const Id& GetOwnerId() const; const Class* GetOwner() const; + FieldAccess GetAccess() const; template Any Invoke(Args&&... args) const; uint8_t GetArgsNum() const; const TypeInfo* GetRetTypeInfo() const; @@ -450,6 +461,7 @@ namespace Mirror { struct ConstructParams { Id id; Id owner; + FieldAccess access; uint8_t argsNum; const TypeInfo* retTypeInfo; std::vector argTypeInfos; @@ -459,6 +471,7 @@ namespace Mirror { explicit Function(ConstructParams&& params); Id owner; + FieldAccess access; uint8_t argsNum; const TypeInfo* retTypeInfo; std::vector argTypeInfos; @@ -474,7 +487,8 @@ namespace Mirror { const std::string& GetOwnerName() const; const Id& GetOwnerId() const; - const Class* GetOwner() const; + const Class& GetOwner() const; + FieldAccess GetAccess() const; uint8_t GetArgsNum() const; const TypeInfo* GetArgTypeInfo(uint8_t argIndex) const; const std::vector& GetArgTypeInfos() const; @@ -496,6 +510,7 @@ namespace Mirror { struct ConstructParams { Id id; Id owner; + FieldAccess access; uint8_t argsNum; std::vector argTypeInfos; std::vector argRemoveRefTypeInfos; @@ -507,6 +522,7 @@ namespace Mirror { explicit Constructor(ConstructParams&& params); Id owner; + FieldAccess access; uint8_t argsNum; std::vector argTypeInfos; std::vector argRemoveRefTypeInfos; @@ -523,7 +539,8 @@ namespace Mirror { const std::string& GetOwnerName() const; const Id& GetOwnerId() const; - const Class* GetOwner() const; + const Class& GetOwner() const; + FieldAccess GetAccess() const; void InvokeDyn(const Argument& argument) const; private: @@ -535,12 +552,14 @@ namespace Mirror { struct ConstructParams { Id owner; + FieldAccess access; Invoker destructor; }; explicit Destructor(ConstructParams&& params); Id owner; + FieldAccess access; Invoker destructor; }; @@ -553,7 +572,8 @@ namespace Mirror { const std::string& GetOwnerName() const; const Id& GetOwnerId() const; - const Class* GetOwner() const; + const Class& GetOwner() const; + FieldAccess GetAccess() const; uint32_t SizeOf() const; const TypeInfo* GetTypeInfo() const; void SetDyn(const Argument& object, const Argument& value) const; @@ -570,6 +590,7 @@ namespace Mirror { struct ConstructParams { Id id; Id owner; + FieldAccess access; uint32_t memorySize; const TypeInfo* typeInfo; Setter setter; @@ -579,6 +600,7 @@ namespace Mirror { explicit MemberVariable(ConstructParams&& params); Id owner; + FieldAccess access; uint32_t memorySize; const TypeInfo* typeInfo; Setter setter; @@ -593,7 +615,8 @@ namespace Mirror { const std::string& GetOwnerName() const; const Id& GetOwnerId() const; - const Class* GetOwner() const; + const Class& GetOwner() const; + FieldAccess GetAccess() const; uint8_t GetArgsNum() const; const TypeInfo* GetRetTypeInfo() const; const TypeInfo* GetArgTypeInfo(uint8_t argIndex) const; @@ -609,6 +632,7 @@ namespace Mirror { struct ConstructParams { Id id; Id owner; + FieldAccess access; uint8_t argsNum; const TypeInfo* retTypeInfo; std::vector argTypeInfos; @@ -618,6 +642,7 @@ namespace Mirror { explicit MemberFunction(ConstructParams&& params); Id owner; + FieldAccess access; uint8_t argsNum; const TypeInfo* retTypeInfo; std::vector argTypeInfos; @@ -1361,24 +1386,18 @@ namespace Common { // NOLINT struct JsonSerializer { static void JsonSerializeDyn(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const Mirror::Class& clazz, const Mirror::Argument& inObj) { - const auto& className = clazz.GetName(); const auto* baseClass = clazz.GetBaseClass(); const auto& memberVariables = clazz.GetMemberVariables(); const auto defaultObject = clazz.GetDefaultObject(); - rapidjson::Value classNameJson; - JsonSerializer::JsonSerialize(classNameJson, inAllocator, className); + if (!outJsonValue.IsObject()) { + outJsonValue.SetObject(); + } - rapidjson::Value baseClassJson; if (baseClass != nullptr) { - JsonSerializeDyn(baseClassJson, inAllocator, *baseClass, inObj); - } else { - baseClassJson.SetNull(); + JsonSerializeDyn(outJsonValue, inAllocator, *baseClass, inObj); } - rapidjson::Value membersJson; - membersJson.SetObject(); - for (const auto& memberVariable : memberVariables | std::views::values) { if (memberVariable.IsTransient()) { continue; @@ -1391,24 +1410,17 @@ namespace Common { // NOLINT rapidjson::Value memberNameJson; JsonSerializer::JsonSerialize(memberNameJson, inAllocator, memberVariable.GetName()); - rapidjson::Value memberContentJson; if (sameAsDefault) { - memberContentJson.SetNull(); - } else { - memberVariable.GetDyn(inObj).JsonSerialize(memberContentJson, inAllocator); + continue; } - membersJson.AddMember(memberNameJson, memberContentJson, inAllocator); + rapidjson::Value memberContentJson; + memberVariable.GetDyn(inObj).JsonSerialize(memberContentJson, inAllocator); + outJsonValue.AddMember(memberNameJson, memberContentJson, inAllocator); } - - outJsonValue.SetObject(); - outJsonValue.AddMember("className", classNameJson, inAllocator); - outJsonValue.AddMember("baseClass", baseClassJson, inAllocator); - outJsonValue.AddMember("members", membersJson, inAllocator); } static void JsonDeserializeDyn(const rapidjson::Value& inJsonValue, const Mirror::Class& clazz, const Mirror::Argument& outObj) { - const auto& className = clazz.GetName(); const auto* baseClass = clazz.GetBaseClass(); const auto defaultObject = clazz.GetDefaultObject(); @@ -1416,44 +1428,18 @@ namespace Common { // NOLINT return; } - if (!inJsonValue.HasMember("className")) { - return; - } - std::string aspectClassName; - JsonSerializer::JsonDeserialize(inJsonValue["className"], aspectClassName); - if (aspectClassName != className) { - return; - } - - if (inJsonValue.HasMember("baseClass") && baseClass != nullptr) { - JsonDeserializeDyn(inJsonValue["baseClass"], *baseClass, outObj); - } - - if (!inJsonValue.HasMember("members")) { - return; - } - - const auto& membersJson = inJsonValue["members"]; - if (!membersJson.IsObject()) { - return; + if (baseClass != nullptr) { + JsonDeserializeDyn(inJsonValue, *baseClass, outObj); } - for (auto iter = membersJson.MemberBegin(); iter != membersJson.MemberEnd(); ++iter) { - std::string memberName; - JsonSerializer::JsonDeserialize(iter->name, memberName); - - if (!clazz.HasMemberVariable(memberName)) { - continue; - } - const auto& memberVariable = clazz.GetMemberVariable(memberName); - - if ( const auto& valueJson = iter->value; - valueJson.IsNull()) { + for (const auto& memberVariable : clazz.GetMemberVariables() | std::views::values) { + const auto& memberName = memberVariable.GetName(); + if (inJsonValue.HasMember(memberName.c_str())) { + memberVariable.GetDyn(outObj).JsonDeserialize(inJsonValue[memberName.c_str()]); + } else { if (!defaultObject.Empty()) { memberVariable.SetDyn(outObj, memberVariable.GetDyn(defaultObject)); } - } else { - memberVariable.GetDyn(outObj).JsonDeserialize(valueJson); } } } diff --git a/Engine/Source/Mirror/Include/Mirror/Registry.h b/Engine/Source/Mirror/Include/Mirror/Registry.h index a603b312..352a11c1 100644 --- a/Engine/Source/Mirror/Include/Mirror/Registry.h +++ b/Engine/Source/Mirror/Include/Mirror/Registry.h @@ -46,12 +46,12 @@ namespace Mirror { public: ~ClassRegistry() override; - template ClassRegistry& Constructor(const Id& inId); - template ClassRegistry& StaticVariable(const Id& inId); - template ClassRegistry& StaticFunction(const Id& inId); - template ClassRegistry& MemberVariable(const Id& inId); + template ClassRegistry& Constructor(const Id& inId); + template ClassRegistry& StaticVariable(const Id& inId); + template ClassRegistry& StaticFunction(const Id& inId); + template ClassRegistry& MemberVariable(const Id& inId); // TODO support overload - template ClassRegistry& MemberFunction(const Id& inId); + template ClassRegistry& MemberFunction(const Id& inId); private: friend class Registry; @@ -102,8 +102,11 @@ namespace Mirror { GlobalRegistry Global(); - template B = void> ClassRegistry Class(const Id& inId); - template EnumRegistry Enum(const Id& inId); + template B = void, FieldAccess DefaultCtorAccess = FieldAccess::faPublic, FieldAccess DetorAccess = FieldAccess::faPublic> + ClassRegistry Class(const Id& inId); + + template EnumRegistry + Enum(const Id& inId); private: friend class GlobalScope; @@ -226,7 +229,7 @@ namespace Mirror { ClassRegistry::~ClassRegistry() = default; template - template + template ClassRegistry& ClassRegistry::Constructor(const Id& inId) { using ArgsTupleType = std::tuple; @@ -238,6 +241,7 @@ namespace Mirror { Constructor::ConstructParams params; params.id = inId; params.owner = clazz.GetId(); + params.access = Access; params.argsNum = sizeof...(Args); params.argTypeInfos = { GetTypeInfo()... }; params.argRemoveRefTypeInfos = { GetTypeInfo>()... }; @@ -257,7 +261,7 @@ namespace Mirror { } template - template + template ClassRegistry& ClassRegistry::StaticVariable(const Id& inId) { using ValueType = typename Internal::VariableTraits::ValueType; @@ -268,6 +272,7 @@ namespace Mirror { Variable::ConstructParams params; params.id = inId; params.owner = clazz.GetId(); + params.access = Access; params.memorySize = sizeof(ValueType); params.typeInfo = GetTypeInfo(); params.setter = [](const Argument& value) -> void { @@ -285,7 +290,7 @@ namespace Mirror { } template - template + template ClassRegistry& ClassRegistry::StaticFunction(const Id& inId) { using ArgsTupleType = typename Internal::FunctionTraits::ArgsTupleType; @@ -299,6 +304,7 @@ namespace Mirror { Function::ConstructParams params; params.id = inId; params.owner = clazz.GetId(); + params.access = Access; params.retTypeInfo = GetTypeInfo(); params.argsNum = argsTupleSize; params.argTypeInfos = Internal::GetArgTypeInfosByArgsTuple(std::make_index_sequence {}); @@ -318,7 +324,7 @@ namespace Mirror { } template - template + template ClassRegistry& ClassRegistry::MemberVariable(const Id& inId) { using ClassType = typename Internal::MemberVariableTraits::ClassType; @@ -330,6 +336,7 @@ namespace Mirror { MemberVariable::ConstructParams params; params.id = inId; params.owner = clazz.GetId(); + params.access = Access; params.memorySize = sizeof(ValueType); params.typeInfo = GetTypeInfo(); params.setter = [](const Argument& object, const Argument& value) -> void { @@ -346,7 +353,7 @@ namespace Mirror { } template - template + template ClassRegistry& ClassRegistry::MemberFunction(const Id& inId) { // ClassType here contains const, #see Internal::MemberFunctionTraits @@ -362,6 +369,7 @@ namespace Mirror { MemberFunction::ConstructParams params; params.id = inId; params.owner = clazz.GetId(); + params.access = Access; params.retTypeInfo = GetTypeInfo(); params.argsNum = argsTupleSize; params.argTypeInfos = Internal::GetArgTypeInfosByArgsTuple(std::make_index_sequence {}); @@ -391,6 +399,7 @@ namespace Mirror { Variable::ConstructParams params; params.id = inId; params.owner = Id::null; + params.access = FieldAccess::max; params.memorySize = sizeof(ValueType); params.typeInfo = GetTypeInfo(); params.setter = [](const Argument& argument) -> void { @@ -420,6 +429,7 @@ namespace Mirror { Function::ConstructParams params; params.id = inId; params.owner = Id::null; + params.access = FieldAccess::max; params.retTypeInfo = GetTypeInfo(); params.argsNum = argsTupleSize; params.argTypeInfos = Internal::GetArgTypeInfosByArgsTuple(std::make_index_sequence {}); @@ -473,7 +483,7 @@ namespace Mirror { return MetaDataRegistry>::SetContext(&enumInfo.EmplaceElement(inId, std::move(params))); } - template B> + template B, FieldAccess DefaultCtorAccess, FieldAccess DetorAccess> ClassRegistry Registry::Class(const Id& inId) { const auto typeId = GetTypeInfo()->id; @@ -498,6 +508,7 @@ namespace Mirror { if constexpr (std::is_destructible_v) { Destructor::ConstructParams detorParams; detorParams.owner = inId; + detorParams.access = DetorAccess; detorParams.destructor = [](const Argument& object) -> void { Assert(!object.IsConstRef()); object.As().~C(); @@ -508,6 +519,7 @@ namespace Mirror { Constructor::ConstructParams ctorParams; ctorParams.id = IdPresets::defaultCtor.name; ctorParams.owner = inId; + ctorParams.access = DefaultCtorAccess; ctorParams.argsNum = 0; ctorParams.argTypeInfos = {}; ctorParams.stackConstructor = [](const ArgumentList& args) -> Any { diff --git a/Engine/Source/Mirror/Src/Mirror.cpp b/Engine/Source/Mirror/Src/Mirror.cpp index 9e66f654..1ec9d8d2 100644 --- a/Engine/Source/Mirror/Src/Mirror.cpp +++ b/Engine/Source/Mirror/Src/Mirror.cpp @@ -804,6 +804,7 @@ namespace Mirror { Variable::Variable(ConstructParams&& params) : ReflNode(std::move(params.id)) , owner(std::move(params.owner)) + , access(params.access) , memorySize(params.memorySize) , typeInfo(params.typeInfo) , setter(std::move(params.setter)) @@ -833,6 +834,12 @@ namespace Mirror { return owner.IsNull() ? nullptr : Class::Find(owner); } + FieldAccess Variable::GetAccess() const + { + Assert(!owner.IsNull()); + return access; + } + const TypeInfo* Variable::GetTypeInfo() const { return typeInfo; @@ -851,6 +858,7 @@ namespace Mirror { Function::Function(ConstructParams&& params) : ReflNode(std::move(params.id)) , owner(std::move(params.owner)) + , access(params.access) , argsNum(params.argsNum) , retTypeInfo(params.retTypeInfo) , argTypeInfos(std::move(params.argTypeInfos)) @@ -875,6 +883,12 @@ namespace Mirror { return owner.IsNull() ? nullptr : Class::Find(owner); } + FieldAccess Function::GetAccess() const + { + Assert(!owner.IsNull()); + return access; + } + uint8_t Function::GetArgsNum() const { return argsNum; @@ -903,6 +917,7 @@ namespace Mirror { Constructor::Constructor(ConstructParams&& params) : ReflNode(std::move(params.id)) , owner(std::move(params.owner)) + , access(params.access) , argsNum(params.argsNum) , argTypeInfos(std::move(params.argTypeInfos)) , argRemoveRefTypeInfos(std::move(params.argRemoveRefTypeInfos)) @@ -924,9 +939,16 @@ namespace Mirror { return owner; } - const Class* Constructor::GetOwner() const + const Class& Constructor::GetOwner() const { - return owner.IsNull() ? nullptr : Class::Find(owner); + Assert(!owner.IsNull()); + return Class::Get(owner); + } + + FieldAccess Constructor::GetAccess() const + { + Assert(!owner.IsNull()); + return access; } uint8_t Constructor::GetArgsNum() const @@ -977,6 +999,7 @@ namespace Mirror { Destructor::Destructor(ConstructParams&& params) : ReflNode(std::string(IdPresets::detor.name)) , owner(std::move(params.owner)) + , access(params.access) , destructor(std::move(params.destructor)) { } @@ -993,9 +1016,16 @@ namespace Mirror { return owner; } - const Class* Destructor::GetOwner() const + const Class& Destructor::GetOwner() const { - return owner.IsNull() ? nullptr : Class::Find(owner); + Assert(!owner.IsNull()); + return Class::Get(owner); + } + + FieldAccess Destructor::GetAccess() const + { + Assert(!owner.IsNull()); + return access; } void Destructor::InvokeDyn(const Argument& argument) const @@ -1006,6 +1036,7 @@ namespace Mirror { MemberVariable::MemberVariable(ConstructParams&& params) : ReflNode(std::move(params.id)) , owner(std::move(params.owner)) + , access(params.access) , memorySize(params.memorySize) , typeInfo(params.typeInfo) , setter(std::move(params.setter)) @@ -1025,9 +1056,16 @@ namespace Mirror { return owner; } - const Class* MemberVariable::GetOwner() const + const Class& MemberVariable::GetOwner() const { - return owner.IsNull() ? nullptr : Class::Find(owner); + Assert(!owner.IsNull()); + return Class::Get(owner); + } + + FieldAccess MemberVariable::GetAccess() const + { + Assert(!owner.IsNull()); + return access; } uint32_t MemberVariable::SizeOf() const @@ -1058,6 +1096,7 @@ namespace Mirror { MemberFunction::MemberFunction(ConstructParams&& params) : ReflNode(std::move(params.id)) , owner(std::move(params.owner)) + , access(params.access) , argsNum(params.argsNum) , retTypeInfo(params.retTypeInfo) , argTypeInfos(std::move(params.argTypeInfos)) @@ -1077,9 +1116,16 @@ namespace Mirror { return owner; } - const Class* MemberFunction::GetOwner() const + const Class& MemberFunction::GetOwner() const { - return owner.IsNull() ? nullptr : Class::Find(owner); + Assert(!owner.IsNull()); + return Class::Get(owner); + } + + FieldAccess MemberFunction::GetAccess() const + { + Assert(!owner.IsNull()); + return access; } uint8_t MemberFunction::GetArgsNum() const diff --git a/Engine/Source/Mirror/Test/SerializationTest.cpp b/Engine/Source/Mirror/Test/SerializationTest.cpp index e3071bda..1c61c895 100644 --- a/Engine/Source/Mirror/Test/SerializationTest.cpp +++ b/Engine/Source/Mirror/Test/SerializationTest.cpp @@ -188,6 +188,13 @@ TEST(SerializationTest, ReflNodeSerializationTest) PerformSerializationTest(fileName, &enun->GetValue("a")); } +TEST(SerializationTest, MetaObjectSerializationTest) +{ + PerformJsonSerializationTest( + SerializationTestStruct2 { 1, 2.0f, "3", 4.0 }, + ""); +} + TEST(SerializationTest, EnumJsonSerializationTest) { PerformJsonSerializationTest( diff --git a/Engine/Source/Mirror/Test/SerializationTest.h b/Engine/Source/Mirror/Test/SerializationTest.h index fdd7784b..54e84d26 100644 --- a/Engine/Source/Mirror/Test/SerializationTest.h +++ b/Engine/Source/Mirror/Test/SerializationTest.h @@ -61,6 +61,12 @@ struct EClass() SerializationTestStruct2 : SerializationTestStruct0 { EClassBody(SerializationTestStruct2); EProperty() double d; + + bool operator==(const SerializationTestStruct2& rhs) const + { + return SerializationTestStruct0::operator==(rhs) + && d == rhs.d; + } }; struct EClass() SerializationTestStruct3 { diff --git a/Engine/Source/Render/Include/Render/Scene.h b/Engine/Source/Render/Include/Render/Scene.h index bda4749c..1cd02ef9 100644 --- a/Engine/Source/Render/Include/Render/Scene.h +++ b/Engine/Source/Render/Include/Render/Scene.h @@ -4,16 +4,19 @@ #pragma once +#include + #include -#include namespace Render { + template + using SceneProxyPatcher = std::function; + class IScene { public: virtual ~IScene() = default; - virtual void AddLight(ILightSceneProxy* inProxy) = 0; - virtual void RemoveLight(ILightSceneProxy* inProxy) = 0; - virtual void AddPrimitive(IPrimitiveSceneProxy* inProxy) = 0; - virtual void RemovePrimitive(IPrimitiveSceneProxy* inProxy) = 0; + virtual size_t GAddLight(const LightSceneProxy& inLight) = 0; + virtual void GRemoveLight(size_t inLightIndex) = 0; + virtual void GPatchLight(size_t inLightIndex, const SceneProxyPatcher& inPatcher) = 0; }; } diff --git a/Engine/Source/Render/Include/Render/SceneProxy/Light.h b/Engine/Source/Render/Include/Render/SceneProxy/Light.h index a6bb11b5..33c2b325 100644 --- a/Engine/Source/Render/Include/Render/SceneProxy/Light.h +++ b/Engine/Source/Render/Include/Render/SceneProxy/Light.h @@ -4,6 +4,8 @@ #pragma once +#include + #include #include @@ -15,19 +17,24 @@ namespace Render { max }; - class ILightSceneProxy { - public: - ILightSceneProxy(); - virtual ~ILightSceneProxy(); - virtual Common::FMat4x4 RGetLocalToWorld() const; - virtual LightType RGetLightType() const; - virtual Common::Color RGetColor() const; - virtual float RGetIntensity() const; - - protected: - Common::FMat4x4 worldMatrix; + struct DirectionalLightSceneProxyPart { + // TODO + }; + + struct PointLightSceneProxyPart { + float radius; + // TODO + }; + + struct SpotLightSceneProxyPart { + // TODO + }; + + struct LightSceneProxy { LightType type; + Common::FMat4x4 localToWorld; Common::Color color; float intensity; + std::variant typedPart; }; } diff --git a/Engine/Source/Render/Include/Render/SceneProxy/Primitive.h b/Engine/Source/Render/Include/Render/SceneProxy/Primitive.h deleted file mode 100644 index 81b61ac6..00000000 --- a/Engine/Source/Render/Include/Render/SceneProxy/Primitive.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// Created by johnk on 2023/8/16. -// - -#pragma once - -namespace Render { - class IPrimitiveSceneProxy { - public: - IPrimitiveSceneProxy(); - virtual ~IPrimitiveSceneProxy(); - }; -} diff --git a/Engine/Source/Render/Src/SceneProxy/Light.cpp b/Engine/Source/Render/Src/SceneProxy/Light.cpp deleted file mode 100644 index 75c8a2c2..00000000 --- a/Engine/Source/Render/Src/SceneProxy/Light.cpp +++ /dev/null @@ -1,37 +0,0 @@ -// -// Created by johnk on 2023/8/14. -// - -#include - -namespace Render { - ILightSceneProxy::ILightSceneProxy() - : worldMatrix(Common::FMat4x4Consts::identity) - , type(LightType::max) - , color(Common::ColorConsts::white) - , intensity(0.f) - { - } - - ILightSceneProxy::~ILightSceneProxy() = default; - - Common::FMat4x4 ILightSceneProxy::RGetLocalToWorld() const - { - return worldMatrix; - } - - LightType ILightSceneProxy::RGetLightType() const - { - return type; - } - - Common::Color ILightSceneProxy::RGetColor() const - { - return color; - } - - float ILightSceneProxy::RGetIntensity() const - { - return intensity; - } -} diff --git a/Engine/Source/Render/Src/SceneProxy/Primitive.cpp b/Engine/Source/Render/Src/SceneProxy/Primitive.cpp deleted file mode 100644 index c6a4895f..00000000 --- a/Engine/Source/Render/Src/SceneProxy/Primitive.cpp +++ /dev/null @@ -1,11 +0,0 @@ -// -// Created by johnk on 2023/8/16. -// - -#include - -namespace Render { - IPrimitiveSceneProxy::IPrimitiveSceneProxy() = default; - - IPrimitiveSceneProxy::~IPrimitiveSceneProxy() = default; -} diff --git a/Engine/Source/Rendering/Include/Rendering/Scene.h b/Engine/Source/Rendering/Include/Rendering/Scene.h index 6604d7e0..b3dde9bd 100644 --- a/Engine/Source/Rendering/Include/Rendering/Scene.h +++ b/Engine/Source/Rendering/Include/Rendering/Scene.h @@ -11,14 +11,12 @@ namespace Rendering { class Scene final : public Render::IScene { public: + Scene(); ~Scene() override; - void AddLight(Render::ILightSceneProxy* inProxy) override; - void RemoveLight(Render::ILightSceneProxy* inProxy) override; - void AddPrimitive(Render::IPrimitiveSceneProxy* inProxy) override; - void RemovePrimitive(Render::IPrimitiveSceneProxy* inProxy) override; + + // TODO AddLight/RemoveLight/PatchLight private: - std::unordered_set lights; - std::unordered_set primitives; + // TODO use object tool }; } diff --git a/Engine/Source/Rendering/Src/Scene.cpp b/Engine/Source/Rendering/Src/Scene.cpp index 08c5b8e4..7bff35ca 100644 --- a/Engine/Source/Rendering/Src/Scene.cpp +++ b/Engine/Source/Rendering/Src/Scene.cpp @@ -6,29 +6,7 @@ #include namespace Rendering { - Scene::~Scene() = default; - - void Scene::AddLight(Render::ILightSceneProxy* inProxy) - { - Assert(!lights.contains(inProxy)); - lights.emplace(inProxy); - } - - void Scene::RemoveLight(Render::ILightSceneProxy* inProxy) - { - Assert(lights.contains(inProxy)); - lights.erase(inProxy); - } + Scene::Scene() = default; - void Scene::AddPrimitive(Render::IPrimitiveSceneProxy* inProxy) - { - Assert(!primitives.contains(inProxy)); - primitives.erase(inProxy); - } - - void Scene::RemovePrimitive(Render::IPrimitiveSceneProxy* inProxy) - { - Assert(primitives.contains(inProxy)); - primitives.emplace(inProxy); - } + Scene::~Scene() = default; } diff --git a/Engine/Source/Runtime/CMakeLists.txt b/Engine/Source/Runtime/CMakeLists.txt index cb051bfd..0f75af92 100644 --- a/Engine/Source/Runtime/CMakeLists.txt +++ b/Engine/Source/Runtime/CMakeLists.txt @@ -5,7 +5,7 @@ AddLibrary( SRC ${SOURCES} PUBLIC_INC Include REFLECT Include - LIB Core Mirror assimp-lib Render EnTT + LIB Core Mirror assimp-lib Render Rendering EnTT ) file(GLOB TEST_SOURCES Test/*.cpp) diff --git a/Engine/Source/Runtime/Include/Runtime/Component/Light.h b/Engine/Source/Runtime/Include/Runtime/Component/Light.h new file mode 100644 index 00000000..67ca0ce5 --- /dev/null +++ b/Engine/Source/Runtime/Include/Runtime/Component/Light.h @@ -0,0 +1,43 @@ +// +// Created by johnk on 2024/10/14. +// + +#pragma once + +#include +#include +#include + +namespace Runtime { + struct RUNTIME_API EClass() DirectionalLight final { + EClassBody(DirectionalLight) + + DirectionalLight(); + + EProperty() Common::Color color; + EProperty() float intensity; + EProperty() bool castShadows; + }; + + struct RUNTIME_API EClass() PointLight final { + EClassBody(PointLight) + + PointLight(); + + EProperty() Common::Color color; + EProperty() float intensity; + EProperty() bool castShadows; + EProperty() float radius; + }; + + struct RUNTIME_API EClass() SpotLight final { + EClassBody(SpotLight) + + SpotLight(); + + EProperty() Common::Color color; + EProperty() float intensity; + EProperty() bool castShadows; + // TODO + }; +} diff --git a/Engine/Source/Runtime/Include/Runtime/Component/Transform.h b/Engine/Source/Runtime/Include/Runtime/Component/Transform.h new file mode 100644 index 00000000..8f5bf2bb --- /dev/null +++ b/Engine/Source/Runtime/Include/Runtime/Component/Transform.h @@ -0,0 +1,20 @@ +// +// Created by johnk on 2024/10/14. +// + +#pragma once + +#include +#include +#include + +namespace Runtime { + struct RUNTIME_API EClass() Transform final { + EClassBody(Transform) + + Transform(); + explicit Transform(const Common::FTransform& inLocalToWorld); + + EProperty() Common::FTransform localToWorld; + }; +} diff --git a/Engine/Source/Runtime/Include/Runtime/Component/View.h b/Engine/Source/Runtime/Include/Runtime/Component/View.h new file mode 100644 index 00000000..22e6f11c --- /dev/null +++ b/Engine/Source/Runtime/Include/Runtime/Component/View.h @@ -0,0 +1,34 @@ +// +// Created by johnk on 2024/10/14. +// + +#pragma once + +#include + +#include +#include +#include + +namespace Runtime { + struct RUNTIME_API EClass() Camera final { + EClassBody(Camera) + + Camera(); + explicit Camera(const Common::FReversedZOrthoProjection& inProjection); + explicit Camera(const Common::FReversedZPerspectiveProjection& inProjection); + + EProperty() std::variant projection; + }; + + struct RUNTIME_API EClass() SceneCapture final { + EClassBody(SceneCapture) + + SceneCapture(); + explicit SceneCapture(const Common::FReversedZOrthoProjection& inProjection); + explicit SceneCapture(const Common::FReversedZPerspectiveProjection& inProjection); + + EProperty() std::variant projection; + // TODO texture render target + }; +} diff --git a/Engine/Source/Runtime/Include/Runtime/System/Scene.h b/Engine/Source/Runtime/Include/Runtime/System/Scene.h new file mode 100644 index 00000000..76d85df7 --- /dev/null +++ b/Engine/Source/Runtime/Include/Runtime/System/Scene.h @@ -0,0 +1,25 @@ +// +// Created by johnk on 2024/10/15. +// + +#pragma once + +#include +#include +#include + +namespace Runtime { + struct SceneState { + Render::IScene* scene; + }; + + class EClass() SceneSystem final : public System { + EPolyClassBody(SceneSystem) + + SceneSystem(); + ~SceneSystem() override; + + void Setup(Commands& inCommands) const override; + void Tick(Commands& inCommands, float inTimeMs) const override; + }; +} diff --git a/Engine/Source/Runtime/Include/Runtime/World.h b/Engine/Source/Runtime/Include/Runtime/World.h index 5f9d2bfc..a11f6df7 100644 --- a/Engine/Source/Runtime/Include/Runtime/World.h +++ b/Engine/Source/Runtime/Include/Runtime/World.h @@ -21,16 +21,6 @@ namespace Runtime { using Entity = entt::entity; constexpr auto entityNull = entt::null; - class RUNTIME_API EClass() Component { - EClassBody(Component) - Component(); - }; - - class RUNTIME_API EClass() State { - EClassBody(State) - State(); - }; - class Commands; class RUNTIME_API EClass() System { @@ -38,12 +28,11 @@ namespace Runtime { System(); virtual ~System(); - EFunc() virtual void Setup(Commands& commands) const; - EFunc() virtual void Tick(Commands& commands, float inTimeMs) const; + virtual void Setup(Commands& inCommands) const; + virtual void Tick(Commands& inCommands, float inTimeMs) const; + virtual void Stop(Commands& inCommands) const; }; - template concept StateDerived = std::is_base_of_v; - template concept CompDerived = std::is_base_of_v; template concept SystemDerived = std::is_base_of_v; template struct Exclude {}; } @@ -52,6 +41,9 @@ namespace Runtime { class World; class Ticker; + template class BasicCollector; + using Collector = BasicCollector<>; + template class CompView { public: @@ -75,38 +67,61 @@ namespace Runtime { // TODO runtime view using StateClass = const Mirror::Class*; + using CompClass = const Mirror::Class*; using SystemClass = const Mirror::Class*; + class Commands; + + class RUNTIME_API Observer { + public: + using Iterator = entt::observer::iterator; + + template Observer(Commands& inCommands, const BasicCollector& inCollector); + + template void Each(F&& inFunc); + void Clear(); + Iterator Begin() const; + Iterator End() const; + Iterator begin() const; + Iterator end() const; + + private: + entt::observer observer; + }; + class RUNTIME_API Commands { public: ~Commands(); Entity CreateEntity(); void DestroyEntity(Entity inEntity); - - template bool HasState() const; - template S& EmplaceState(Args&&... inArgs); - template S* FindState(); - template const S* FindState() const; - template S& GetState(); - template const S& GetState() const; - template bool HasComp(Entity inEntity) const; - template C& EmplaceComp(Entity inEntity, Args&&... inArgs); - template C* FindComp(Entity inEntity); - template const C* FindComp(Entity inEntity) const; - template C& GetComp(Entity inEntity); - template const C& GetComp(Entity inEntity) const; - + bool HasEntity(Entity inEntity) const; + + template bool HasState() const; + template const S& EmplaceState(Args&&... inArgs); + template const S* FindState() const; + template const S& GetState() const; + template void RemoveState(); + template void PatchState(F&& inFunc); + template bool HasComp(Entity inEntity) const; + template const C& EmplaceComp(Entity inEntity, Args&&... inArgs); + template const C* FindComp(Entity inEntity) const; + template const C& GetComp(Entity inEntity) const; + template void RemoveComp(Entity inEntity); + template void PatchComp(Entity inEntity, F&& inFunc); template auto View(Exclude = {}); template auto View(Exclude = {}) const; // TODO runtime view + template Observer CreateObserver(const BasicCollector& inCollector); + // TODO component lifecycle listeners private: friend class World; + friend class Observer; - explicit Commands(World& inWorld); + explicit Commands(entt::registry& inRegistry); - World& world; + entt::registry& registry; }; // world is fully runtime structure, we use level to perform persist storage @@ -131,18 +146,20 @@ namespace Runtime { private: friend class Commands; + friend class Observer; using SystemOp = std::function; + + // TODO we not want read-write in a barrier time, so we maybe need runtime read-write check void ExecuteSystemGraph(const SystemOp& inOp); - bool setuped; + bool setup; bool playing; std::string name; - std::unordered_map states; + entt::registry registry; std::unordered_map systems; std::vector> systemsGraph; std::vector systemsInBarriers; - entt::registry registry; }; } @@ -152,9 +169,97 @@ namespace Runtime::Internal { { return &Mirror::Class::Get(); } + + template + struct CollectorConverter {}; + + template <> + struct CollectorConverter> { + using EngineType = BasicCollector<>; + }; + + template + struct CollectorConverter, entt::type_list, Rule...>, Other...>> { + using EngineType = BasicCollector, entt::type_list, Rule...>, Other...>; + }; } namespace Runtime { + template <> + class BasicCollector<> { + public: + BasicCollector() = default; + + template + static constexpr auto Group(Exclude = {}) noexcept + { + using LibRetType = decltype(entt::basic_collector<>::group(entt::exclude)); + return typename Internal::CollectorConverter::EngineType {}; + } + + template + static constexpr auto Update() noexcept + { + using LibRetType = decltype(entt::basic_collector<>::update()); + return typename Internal::CollectorConverter::EngineType {}; + } + + private: + friend class Observer; + + static auto Final() noexcept + { + return entt::basic_collector<> {}; + } + }; + + template + class BasicCollector { + public: + BasicCollector() = default; + + template + static constexpr auto Group(Exclude = {}) noexcept + { + using LibRetType = decltype(entt::basic_collector::template group(entt::exclude)); + return typename Internal::CollectorConverter::EngineType {}; + } + + template + static constexpr auto Update() noexcept + { + using LibRetType = decltype(entt::basic_collector::template update()); + return typename Internal::CollectorConverter::EngineType {}; + } + + template + static constexpr auto Where(Exclude = {}) noexcept + { + using LibRetType = decltype(entt::basic_collector::template where(entt::exclude)); + return typename Internal::CollectorConverter::EngineType {}; + } + + private: + friend class Observer; + + static auto Final() noexcept + { + return entt::basic_collector {}; + } + }; + + template + Observer::Observer(Commands& inCommands, const BasicCollector& inCollector) + : observer(inCommands.registry, inCollector.Final()) + { + } + + template + void Observer::Each(F&& inFunc) + { + observer.each(std::forward(inFunc)); + } + template CompView::CompView(const entt::basic_view& inView) : view(inView) @@ -204,99 +309,97 @@ namespace Runtime { return End(); } - template + template bool Commands::HasState() const { - return world.states.contains(Internal::GetClassChecked()); + return registry.try_ctx() != nullptr; } - template - S& Commands::EmplaceState(Args&&... inArgs) + template + const S& Commands::EmplaceState(Args&&... inArgs) { - world.states.emplace(Internal::GetClassChecked(), Mirror::Any(S(std::forward(inArgs)...))); - return GetState(); + return registry.set(std::forward(inArgs)...); } - template - S* Commands::FindState() + template + const S* Commands::FindState() const { - auto* clazz = Internal::GetClassChecked(); - auto iter = world.states.find(clazz); - return iter == world.states.end() ? nullptr : &iter->second.template As(); + return registry.try_ctx(); } - template - const S* Commands::FindState() const + template + const S& Commands::GetState() const { - auto* clazz = Internal::GetClassChecked(); - auto iter = world.states.find(clazz); - return iter == world.states.end() ? nullptr : &iter->second.template As(); + return registry.ctx(); } - template - S& Commands::GetState() + template + void Commands::RemoveState() // NOLINT { - Assert(HasState()); - return world.states.at(Internal::GetClassChecked()).template As(); + registry.unset(); } - template - const S& Commands::GetState() const + template + void Commands::PatchState(F&& inFunc) { Assert(HasState()); - return world.states.at(Internal::GetClassChecked()).template As(); + inFunc(registry.ctx()); } - template + template bool Commands::HasComp(Entity inEntity) const { - return world.registry.try_get(inEntity) != nullptr; - } - - template - C& Commands::EmplaceComp(Entity inEntity, Args&&... inArgs) - { - return world.registry.emplace(inEntity, std::forward(inArgs)...); + return registry.try_get(inEntity) != nullptr; } - template - C* Commands::FindComp(Entity inEntity) + template + const C& Commands::EmplaceComp(Entity inEntity, Args&&... inArgs) { - return world.registry.try_get(inEntity); + return registry.emplace(inEntity, std::forward(inArgs)...); } - template + template const C* Commands::FindComp(Entity inEntity) const { - return world.registry.try_get(inEntity); + return registry.try_get(inEntity); } - template - C& Commands::GetComp(Entity inEntity) + template + const C& Commands::GetComp(Entity inEntity) const { - auto* result = world.registry.try_get(inEntity); + auto* result = registry.try_get(inEntity); Assert(result != nullptr); return *result; } - template - const C& Commands::GetComp(Entity inEntity) const + template + void Commands::RemoveComp(Entity inEntity) // NOLINT { - auto* result = world.registry.try_get(inEntity); - Assert(result != nullptr); - return *result; + registry.erase(inEntity); + } + + template + void Commands::PatchComp(Entity inEntity, F&& inFunc) + { + registry.patch(inEntity, std::forward(inFunc)); } template auto Commands::View(Exclude) { - return CompView, C...>(world.registry.view(entt::exclude_t {})); + return CompView, C...>(registry.view(entt::exclude_t {})); } template auto Commands::View(Exclude) const { - return CompView, std::add_const_t...>(world.registry.view(entt::exclude_t {})); + return CompView, std::add_const_t...>(registry.view(entt::exclude_t {})); + } + + template + Observer Commands::CreateObserver(const BasicCollector& inCollector) + { + return { *this, inCollector }; } template diff --git a/Engine/Source/Runtime/Src/Component/Light.cpp b/Engine/Source/Runtime/Src/Component/Light.cpp new file mode 100644 index 00000000..f3a17394 --- /dev/null +++ b/Engine/Source/Runtime/Src/Component/Light.cpp @@ -0,0 +1,13 @@ +// +// Created by johnk on 2024/10/14. +// + +#include + +namespace Runtime { + DirectionalLight::DirectionalLight() = default; + + PointLight::PointLight() = default; + + SpotLight::SpotLight() = default; +} diff --git a/Engine/Source/Runtime/Src/Component/Transform.cpp b/Engine/Source/Runtime/Src/Component/Transform.cpp new file mode 100644 index 00000000..cc9ff5a4 --- /dev/null +++ b/Engine/Source/Runtime/Src/Component/Transform.cpp @@ -0,0 +1,14 @@ +// +// Created by johnk on 2024/10/14. +// + +#include + +namespace Runtime { + Transform::Transform() = default; + + Transform::Transform(const Common::FTransform& inLocalToWorld) + : localToWorld(inLocalToWorld) + { + } +} diff --git a/Engine/Source/Runtime/Src/Component/View.cpp b/Engine/Source/Runtime/Src/Component/View.cpp new file mode 100644 index 00000000..bbb5510a --- /dev/null +++ b/Engine/Source/Runtime/Src/Component/View.cpp @@ -0,0 +1,37 @@ +// +// Created by johnk on 2024/10/14. +// + +#include + +namespace Runtime { + Camera::Camera() + : projection(Common::FReversedZPerspectiveProjection()) + { + } + + Camera::Camera(const Common::FReversedZOrthoProjection& inProjection) + : projection(inProjection) + { + } + + Camera::Camera(const Common::FReversedZPerspectiveProjection& inProjection) + : projection(inProjection) + { + } + + SceneCapture::SceneCapture() + : projection(Common::FReversedZPerspectiveProjection()) + { + } + + SceneCapture::SceneCapture(const Common::FReversedZOrthoProjection& inProjection) + : projection(inProjection) + { + } + + SceneCapture::SceneCapture(const Common::FReversedZPerspectiveProjection& inProjection) + : projection(inProjection) + { + } +} diff --git a/Engine/Source/Runtime/Src/System/Scene.cpp b/Engine/Source/Runtime/Src/System/Scene.cpp new file mode 100644 index 00000000..10e34d6f --- /dev/null +++ b/Engine/Source/Runtime/Src/System/Scene.cpp @@ -0,0 +1,26 @@ +// +// Created by johnk on 2024/10/15. +// + +#include +#include + +namespace Runtime { + SceneSystem::SceneSystem() = default; + + SceneSystem::~SceneSystem() = default; + + void SceneSystem::Setup(Commands& inCommands) const + { + inCommands.EmplaceState(); + inCommands.PatchState([](auto& state) -> void { + auto& renderingModule = Core::ModuleManager::Get().GetOrLoadTyped("Rendering"); + state.scene = renderingModule.AllocateScene(); + }); + } + + void SceneSystem::Tick(Commands& inCommands, float inTimeMs) const + { + // TODO + } +} diff --git a/Engine/Source/Runtime/Src/World.cpp b/Engine/Source/Runtime/Src/World.cpp index 07ba4fe7..ad36bde5 100644 --- a/Engine/Source/Runtime/Src/World.cpp +++ b/Engine/Source/Runtime/Src/World.cpp @@ -11,20 +11,43 @@ namespace Runtime { return &Mirror::Class::Get(inName); } - Component::Component() = default; - - State::State() = default; - System::System() = default; System::~System() = default; - void System::Setup(Commands& commands) const {} + void System::Setup(Commands& inCommands) const {} + + void System::Tick(Commands& inCommands, float inTimeMs) const {} - void System::Tick(Commands& commands, float inTimeMs) const {} + void System::Stop(Commands& inCommands) const {} + + void Observer::Clear() + { + observer.clear(); + } - Commands::Commands(World& inWorld) - : world(inWorld) + Observer::Iterator Observer::Begin() const + { + return observer.begin(); + } + + Observer::Iterator Observer::End() const + { + return observer.end(); + } + + Observer::Iterator Observer::begin() const + { + return Begin(); + } + + Observer::Iterator Observer::end() const + { + return End(); + } + + Commands::Commands(entt::registry& inRegistry) + : registry(inRegistry) { } @@ -32,16 +55,21 @@ namespace Runtime { Entity Commands::CreateEntity() // NOLINT { - return world.registry.create(); + return registry.create(); } void Commands::DestroyEntity(Entity inEntity) // NOLINT { - world.registry.destroy(inEntity); + registry.destroy(inEntity); + } + + bool Commands::HasEntity(Entity inEntity) const + { + return registry.valid(inEntity); } World::World(std::string inName) - : setuped(false) + : setup(false) , playing(false) , name(std::move(inName)) { @@ -61,46 +89,46 @@ namespace Runtime { void World::Play() { - Assert(!setuped && systemsInBarriers.empty()); - setuped = true; + Assert(!setup && systemsInBarriers.empty()); + setup = true; playing = true; ExecuteSystemGraph([&](const System& inSystem) -> void { - Commands commands(*this); + Commands commands(registry); inSystem.Setup(commands); }); } void World::Stop() { - Assert(setuped); - setuped = false; + Assert(setup); + setup = false; playing = false; } void World::Pause() { - Assert(setuped && playing); + Assert(setup && playing); playing = false; } void World::Resume() { - Assert(setuped && !playing); + Assert(setup && !playing); playing = true; } void World::Tick(float inFrameTimeMs) { - Assert(setuped && playing); + Assert(setup && playing); ExecuteSystemGraph([&](const System& inSystem) -> void { - Commands commands(*this); + Commands commands(registry); inSystem.Tick(commands, inFrameTimeMs); }); } bool World::Started() const { - return setuped; + return setup; } bool World::Playing() const diff --git a/Engine/Source/Runtime/Test/WorldTest.cpp b/Engine/Source/Runtime/Test/WorldTest.cpp index 06dc173a..c0fce414 100644 --- a/Engine/Source/Runtime/Test/WorldTest.cpp +++ b/Engine/Source/Runtime/Test/WorldTest.cpp @@ -25,9 +25,10 @@ ParralCountSystemA::~ParralCountSystemA() = default; void ParralCountSystemA::Tick(Commands& commands, float inTimeMs) const { - auto& globalCounter = commands.GetState(); - globalCounter.tickTime += 1; - globalCounter.value += 2; + commands.PatchState([](auto& state) -> void { + state.tickTime += 1; + state.value += 2; + }); } ParralCountSystemB::ParralCountSystemB() = default; @@ -36,7 +37,9 @@ ParralCountSystemB::~ParralCountSystemB() = default; void ParralCountSystemB::Tick(Commands& commands, float inTimeMs) const { - commands.GetState().value += 3; + commands.PatchState([](auto& state) -> void { + state.value += 3; + }); } GlobalCounterVerifySystem::GlobalCounterVerifySystem() = default; diff --git a/Engine/Source/Runtime/Test/WorldTest.h b/Engine/Source/Runtime/Test/WorldTest.h index db03802e..12641215 100644 --- a/Engine/Source/Runtime/Test/WorldTest.h +++ b/Engine/Source/Runtime/Test/WorldTest.h @@ -9,7 +9,7 @@ using namespace Runtime; -class EClass() GlobalCounter final : public State { +class EClass() GlobalCounter { EClassBody(GlobalCounter) GlobalCounter(); diff --git a/Tool/MirrorTool/Include/MirrorTool/Parser.h b/Tool/MirrorTool/Include/MirrorTool/Parser.h index e81fd34e..ca997078 100644 --- a/Tool/MirrorTool/Include/MirrorTool/Parser.h +++ b/Tool/MirrorTool/Include/MirrorTool/Parser.h @@ -52,9 +52,14 @@ namespace MirrorTool { FieldAccess fieldAccess; }; + struct ClassDestructorInfo : Node { + FieldAccess fieldAccess; + }; + struct ClassInfo : Node { FieldAccess lastFieldAccess; std::string baseClassName; + std::optional destructor; std::vector classes; std::vector constructors; std::vector staticVariables; diff --git a/Tool/MirrorTool/Src/Generator.cpp b/Tool/MirrorTool/Src/Generator.cpp index 96b31be0..c8560549 100644 --- a/Tool/MirrorTool/Src/Generator.cpp +++ b/Tool/MirrorTool/Src/Generator.cpp @@ -97,9 +97,30 @@ namespace MirrorTool { return stream.str(); } + static std::string GetFieldAccessStr(FieldAccess access) + { + static const std::unordered_map map = { + { FieldAccess::pri, "Mirror::FieldAccess::faPrivate" }, + { FieldAccess::pro, "Mirror::FieldAccess::faProtected" }, + { FieldAccess::pub, "Mirror::FieldAccess::faPublic" }, + }; + return map.at(access); + } + static std::string GetClassCode(const ClassInfo& clazz) // NOLINT { const std::string fullName = GetFullName(clazz); + auto defaultCtorFieldAccess = FieldAccess::pub; + for (const auto& constructor : clazz.constructors) { + if (constructor.parameters.empty()) { + defaultCtorFieldAccess = constructor.fieldAccess; + } + } + auto detorFieldAccess = clazz.destructor.has_value() ? clazz.destructor->fieldAccess : FieldAccess::pub; + + std::string defaultCtorAndDetorFieldAccessParams = defaultCtorFieldAccess != FieldAccess::pub || detorFieldAccess != FieldAccess::pub + ? fmt::format(", {}, {}", GetFieldAccessStr(defaultCtorFieldAccess), GetFieldAccessStr(detorFieldAccess)) + : ""; std::stringstream stream; stream << Common::newline; @@ -107,34 +128,39 @@ namespace MirrorTool { stream << "{" << Common::newline; stream << Common::tab<1> << "Mirror::Registry::Get()"; if (clazz.baseClassName.empty()) { - stream << Common::newline << Common::tab<2> << fmt::format(R"(.Class<{}>("{}"))", fullName, fullName); + stream << Common::newline << Common::tab<2> << fmt::format(R"(.Class<{}, void{}>("{}"))", fullName, defaultCtorAndDetorFieldAccessParams, fullName); } else { - stream << Common::newline << Common::tab<2> << fmt::format(R"(.Class<{}, {}>("{}"))", fullName, clazz.baseClassName, fullName); + stream << Common::newline << Common::tab<2> << fmt::format(R"(.Class<{}, {}{}>("{}"))", fullName, clazz.baseClassName, defaultCtorAndDetorFieldAccessParams, fullName); } stream << GetMetaDataCode<3>(clazz); for (const auto& constructor : clazz.constructors) { - stream << Common::newline << Common::tab<3> << fmt::format(R"(.Constructor<{}>("{}"))", constructor.name, constructor.name); + const std::string fieldAccessStr = constructor.fieldAccess != FieldAccess::pub ? fmt::format(", {}", GetFieldAccessStr(constructor.fieldAccess)) : ""; + stream << Common::newline << Common::tab<3> << fmt::format(R"(.Constructor<{}{}>("{}"))", constructor.name, fieldAccessStr, constructor.name); stream << GetMetaDataCode<4>(constructor); } for (const auto& staticVariable : clazz.staticVariables) { const std::string variableName = GetFullName(staticVariable); - stream << Common::newline << Common::tab<3> << fmt::format(R"(.StaticVariable<&{}>("{}"))", variableName, staticVariable.name); + const std::string fieldAccessStr = staticVariable.fieldAccess != FieldAccess::pub ? fmt::format(", {}", GetFieldAccessStr(staticVariable.fieldAccess)) : ""; + stream << Common::newline << Common::tab<3> << fmt::format(R"(.StaticVariable<&{}{}>("{}"))", variableName, fieldAccessStr, staticVariable.name); stream << GetMetaDataCode<4>(staticVariable); } for (const auto& staticFunction : clazz.staticFunctions) { const std::string functionName = GetFullName(staticFunction); - stream << Common::newline << Common::tab<3> << fmt::format(R"(.StaticFunction<&{}>("{}"))", functionName, staticFunction.name); + const std::string fieldAccessStr = staticFunction.fieldAccess != FieldAccess::pub ? fmt::format(", {}", GetFieldAccessStr(staticFunction.fieldAccess)) : ""; + stream << Common::newline << Common::tab<3> << fmt::format(R"(.StaticFunction<&{}{}>("{}"))", functionName, fieldAccessStr, staticFunction.name); stream << GetMetaDataCode<4>(staticFunction); } // TODO overload support for (const auto& variable : clazz.variables) { const std::string variableName = GetFullName(variable); - stream << Common::newline << Common::tab<3> << fmt::format(R"(.MemberVariable<&{}>("{}"))", variableName, variable.name); + const std::string fieldAccessStr = variable.fieldAccess != FieldAccess::pub ? fmt::format(", {}", GetFieldAccessStr(variable.fieldAccess)) : ""; + stream << Common::newline << Common::tab<3> << fmt::format(R"(.MemberVariable<&{}{}>("{}"))", variableName, fieldAccessStr, variable.name); stream << GetMetaDataCode<4>(variable); } for (const auto& function : clazz.functions) { const std::string functionName = GetFullName(function); - stream << Common::newline << Common::tab<3> << fmt::format(R"(.MemberFunction<&{}>("{}"))", functionName, function.name); + const std::string fieldAccessStr = function.fieldAccess != FieldAccess::pub ? fmt::format(", {}", GetFieldAccessStr(function.fieldAccess)) : ""; + stream << Common::newline << Common::tab<3> << fmt::format(R"(.MemberFunction<&{}{}>("{}"))", functionName, fieldAccessStr, function.name); stream << GetMetaDataCode<4>(function); } // TODO overload support diff --git a/Tool/MirrorTool/Src/Parser.cpp b/Tool/MirrorTool/Src/Parser.cpp index 121fac48..5ff6be84 100644 --- a/Tool/MirrorTool/Src/Parser.cpp +++ b/Tool/MirrorTool/Src/Parser.cpp @@ -86,15 +86,20 @@ namespace MirrorTool { return Common::StringUtils::Replace(result, "struct", ""); } + static std::string RemoveStrSpace(const std::string& value) + { + return Common::StringUtils::Replace(value, " ", ""); + } + static void ParseMetaDatas(Node& node, const std::string& metaDataStr) { - for (const auto metaDatas = Common::StringUtils::Split(metaDataStr, ";"); + for (const auto metaDatas = Common::StringUtils::Split(metaDataStr, ","); const auto& metaData : metaDatas) { if (auto keyValue = Common::StringUtils::Split(metaData, "="); keyValue.size() == 1) { - node.metaDatas.emplace(std::make_pair(keyValue[0], "true")); + node.metaDatas.emplace(std::make_pair(RemoveStrSpace(keyValue[0]), "true")); } else if (keyValue.size() == 2) { - node.metaDatas.emplace(std::make_pair(keyValue[0], keyValue[1])); + node.metaDatas.emplace(std::make_pair(RemoveStrSpace(keyValue[0]), RemoveStrSpace(keyValue[1]))); } } } @@ -235,6 +240,11 @@ namespace MirrorTool { context.constructors.emplace_back(std::move(constructorInfo)); VisitChildren(ClassConstructorVisitor, ClassConstructorInfo, cursor, context.constructors.back()); UpdateConstructorName(context.constructors.back()); + } else if (kind == CXCursor_Destructor) { + ClassDestructorInfo destructorInfo; + destructorInfo.outerName = GetOuterName(context.outerName, context.name); + destructorInfo.fieldAccess = context.lastFieldAccess; + context.destructor = std::move(destructorInfo); } else if (kind == CXCursor_StructDecl || kind == CXCursor_ClassDecl) { ClassInfo classInfo; classInfo.outerName = GetOuterName(context.outerName, context.name); From fa80ecb354dd43fcd9acb60e027f09401ee09b97 Mon Sep 17 00:00:00 2001 From: John Kindem <461425614@qq.com> Date: Fri, 18 Oct 2024 20:13:09 +0800 Subject: [PATCH 02/22] feat: trunk and trunk list container --- .../Source/Common/Include/Common/Container.h | 531 ++++++++++++++++-- Engine/Source/Common/Test/ContainerTest.cpp | 10 + 2 files changed, 496 insertions(+), 45 deletions(-) diff --git a/Engine/Source/Common/Include/Common/Container.h b/Engine/Source/Common/Include/Common/Container.h index 72487ecb..feecdbc9 100644 --- a/Engine/Source/Common/Include/Common/Container.h +++ b/Engine/Source/Common/Include/Common/Container.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -148,31 +149,15 @@ namespace Common { std::array memory; }; - // TODO trunk handle - // TODO trunk list handle - - template - class TrunkHandle { - public: - TrunkHandle(); - ~TrunkHandle(); - - NonCopyable(TrunkHandle) - TrunkHandle(TrunkHandle&& inOther) noexcept; - TrunkHandle& operator=(TrunkHandle&& inOther) noexcept; - - // TODO - - private: - T* ptr; - }; - - template + // container which perform inplace destruct and leave a slot for re-alloc when erase + template class Trunk { public: using TraverseFunc = std::function; using ConstTraverseFunc = std::function; + static constexpr size_t Capacity(); + Trunk(); ~Trunk(); @@ -181,56 +166,99 @@ namespace Common { Trunk& operator=(const Trunk& inOther); Trunk& operator=(Trunk&& inOther) noexcept; - // TODO use handle version - template T& Allocate(Args&&... inArgs); - bool HasFree() const; - bool Valid(const T& inObj) const; - void Erase(const T& inObj); + template size_t Allocate(Args&&... inArgs); + bool Valid(size_t inIndex) const; + void Erase(size_t inIndex); + T* Try(size_t inIndex); + const T* Try(size_t inIndex) const; + T* At(size_t inIndex); + const T* At(size_t inIndex) const; void Each(const TraverseFunc& inFunc); void Each(const ConstTraverseFunc& inFunc) const; + bool HasFree() const; size_t Free() const; - size_t Used() const; + size_t Allocated() const; + bool Empty() const; + void Clear(); + explicit operator bool() const; + T& operator[](size_t inIndex); + const T& operator[](size_t inIndex) const; private: static constexpr size_t elemMemSize = sizeof(T); - static constexpr size_t totalMemSize = elemMemSize * ElemNumPerTrunk; + static constexpr size_t totalMemSize = elemMemSize * N; + static bool Contains(size_t inIndex); - bool CheckContains(const T& inObj); T& TypedMemory(size_t inIndex); const T& TypedMemory(size_t inIndex) const; + template void InplaceConstruct(size_t inIndex, Args&&... inArgs); + void InplaceDestruct(size_t inIndex); - std::bitset allocated; + std::bitset allocated; std::array memory; }; // pointer stable - template + template class TrunkList { public: - using TraverseFunc = typename Trunk::TraverseFunc; - using ConstTraverseFunc = typename Trunk::ConstTraverseFunc; + using TraverseFunc = typename Trunk::TraverseFunc; + using ConstTraverseFunc = typename Trunk::ConstTraverseFunc; + + class ConstHandle { + public: + ConstHandle(const TrunkList* inOwner, const Trunk* inTrunk, size_t inIndex); + + explicit operator bool() const; + T* operator->() const; + T& operator*() const; + + private: + friend class TrunkList; + + void Valid(); + + const TrunkList* owner; + const Trunk* trunk; + size_t index; + }; + + class Handle { + public: + Handle(TrunkList* inOwner, Trunk* inTrunk, size_t inIndex); + + ConstHandle Const() const; + explicit operator bool() const; + const T* operator->() const; + const T& operator*() const; + + private: + friend class TrunkList; + + void Valid(); + + TrunkList* owner; + Trunk* trunk; + size_t index; + }; TrunkList(); ~TrunkList(); - TrunkList(const TrunkList& inOther); - TrunkList(TrunkList&& inOther) noexcept; - TrunkList& operator=(const TrunkList& inOther); - TrunkList& operator=(TrunkList&& inOther) noexcept; - - // TODO use handle version - template T& Emplace(Args&&... inArgs); - void Erase(const T& inObj); - bool Valid(const T& inObj) const; + template Handle Allocate(Args&&... inArgs) const; + void Erase(const Handle& inHandle); + void Erase(const ConstHandle& inHandle); void Each(const TraverseFunc& inFunc); void Each(const ConstTraverseFunc& inFunc) const; - size_t Size() const; + void Reserve(size_t inIndex) const; + size_t Allocated() const; size_t Capacity() const; - void Reserve(size_t inSize); - void Clear(); + size_t Free() const; + bool Empty() const; + explicit operator bool() const; private: - std::list> trunks; + std::list> trunks; }; } @@ -1016,4 +1044,417 @@ namespace Common { { Assert(size + inNum <= N); } + + template + constexpr size_t Trunk::Capacity() + { + return N; + } + + template + Trunk::Trunk() = default; + + template + Trunk::~Trunk() + { + Clear(); + } + + template + Trunk::Trunk(const Trunk& inOther) + : allocated(inOther.allocated) + , memory() + { + for (auto i = 0; i < allocated.size(); i++) { + if (allocated.test(i)) { + InplaceConstruct(i, inOther.TypedMemory(i)); + } + } + } + + template + Trunk::Trunk(Trunk&& inOther) noexcept + : allocated(std::move(inOther.allocated)) + , memory() + { + for (auto i = 0; i < allocated.size(); i++) { + if (allocated.test(i)) { + InplaceConstruct(i, std::move(inOther.TypedMemory(i))); + } + } + } + + template + Trunk& Trunk::operator=(const Trunk& inOther) + { + auto oldAllocated = allocated; + allocated = inOther.allocated; + + for (auto i = 0; i < allocated.size(); i++) { + if (oldAllocated.test(i) && !allocated.test(i)) { + InplaceDestruct(i); + } + if (!oldAllocated.test(i) && allocated.test(i)) { + InplaceConstruct(i, inOther.TypedMemory(i)); + } + if (oldAllocated.test(i) && allocated.test(i)) { + TypedMemory(i) = inOther.TypedMemory(i); + } + } + return *this; + } + + template + Trunk& Trunk::operator=(Trunk&& inOther) noexcept + { + auto oldAllocated = allocated; + allocated = inOther.allocated; + + for (auto i = 0; i < allocated.size(); i++) { + if (oldAllocated.test(i) && !allocated.test(i)) { + InplaceDestruct(i); + } + if (!oldAllocated.test(i) && allocated.test(i)) { + InplaceConstruct(i, std::move(inOther.TypedMemory(i))); + } + if (oldAllocated.test(i) && allocated.test(i)) { + TypedMemory(i) = std::move(inOther.TypedMemory(i)); + } + } + return *this; + } + + template + template + size_t Trunk::Allocate(Args&&... inArgs) + { + for (auto i = 0; i < allocated.size(); i++) { + if (!allocated.test(i)) { + allocated.set(i, true); + InplaceConstruct(i, std::forward(inArgs)...); + return i; + } + } + QuickFailWithReason("container is full"); + return 0; + } + + template + bool Trunk::Valid(size_t inIndex) const + { + if (!Contains(inIndex)) { + return false; + } + return allocated.test(inIndex); + } + + template + void Trunk::Erase(size_t inIndex) + { + Assert(Valid(inIndex)); + allocated.set(inIndex, false); + InplaceDestruct(inIndex); + } + + template + T* Trunk::Try(size_t inIndex) + { + return Valid(inIndex) ? &TypedMemory(inIndex) : nullptr; + } + + template + const T* Trunk::Try(size_t inIndex) const + { + return Valid(inIndex) ? &TypedMemory(inIndex) : nullptr; + } + + template + T* Trunk::At(size_t inIndex) + { + Assert(Valid(inIndex)); + return &TypedMemory(inIndex); + } + + template + const T* Trunk::At(size_t inIndex) const + { + Assert(Valid(inIndex)); + return &TypedMemory(inIndex); + } + + template + void Trunk::Each(const TraverseFunc& inFunc) + { + for (auto i = 0; i < allocated.size(); i++) { + if (allocated.test(i)) { + inFunc(TypedMemory(i)); + } + } + } + + template + void Trunk::Each(const ConstTraverseFunc& inFunc) const + { + for (auto i = 0; i < allocated.size(); i++) { + if (allocated.test(i)) { + inFunc(TypedMemory(i)); + } + } + } + + template + bool Trunk::HasFree() const + { + return Free() > 0; + } + + template + size_t Trunk::Free() const + { + return Capacity() - Allocated(); + } + + template + size_t Trunk::Allocated() const + { + return allocated.count(); + } + + template + bool Trunk::Empty() const + { + return Allocated() > 0; + } + + template + void Trunk::Clear() + { + for (auto i = 0; i < allocated.size(); i++) { + if (allocated.test(i)) { + InplaceDestruct(i); + } + } + } + + template + Trunk::operator bool() const + { + return !Empty(); + } + + template + T& Trunk::operator[](size_t inIndex) + { + return At(inIndex); + } + + template + const T& Trunk::operator[](size_t inIndex) const + { + return At(inIndex); + } + + template + bool Trunk::Contains(size_t inIndex) + { + return inIndex < Capacity(); + } + + template + T& Trunk::TypedMemory(size_t inIndex) + { + Assert(Contains(inIndex)); + auto* data = reinterpret_cast(memory.data()); + return data[inIndex]; + } + + template + const T& Trunk::TypedMemory(size_t inIndex) const + { + Assert(Contains(inIndex)); + const auto* data = reinterpret_cast(memory.data()); + return data[inIndex]; + } + + template + template + void Trunk::InplaceConstruct(size_t inIndex, Args&&... inArgs) + { + new(&TypedMemory(inIndex)) T(std::forward(inArgs)...); + } + + template + void Trunk::InplaceDestruct(size_t inIndex) + { + TypedMemory(inIndex).~T(); + } + + template + TrunkList::ConstHandle::ConstHandle(const TrunkList* inOwner, const Trunk* inTrunk, size_t inIndex) + : owner(inOwner) + , trunk(inTrunk) + , index(inIndex) + { + } + + template + TrunkList::ConstHandle::operator bool() const + { + return Valid(); + } + + template + T* TrunkList::ConstHandle::operator->() const + { + return trunk->Try(index); + } + + template + T& TrunkList::ConstHandle::operator*() const + { + return trunk->At(index); + } + + template + void TrunkList::ConstHandle::Valid() + { + return trunk->Valid(index); + } + + template + TrunkList::Handle::Handle(TrunkList* inOwner, Trunk* inTrunk, size_t inIndex) + : owner(inOwner) + , trunk(inTrunk) + , index(inIndex) + { + } + + template + typename TrunkList::ConstHandle TrunkList::Handle::Const() const + { + return { trunk, index }; + } + + template + TrunkList::Handle::operator bool() const + { + return Valid(); + } + + template + const T* TrunkList::Handle::operator->() const + { + return trunk->Try(index); + } + + template + const T& TrunkList::Handle::operator*() const + { + return trunk->At(index); + } + + template + void TrunkList::Handle::Valid() + { + return trunk->Valid(index); + } + + template + TrunkList::TrunkList() = default; + + template + TrunkList::~TrunkList() = default; + + template + template + typename TrunkList::Handle TrunkList::Allocate(Args&&... inArgs) const + { + Trunk* allocator = nullptr; + for (auto& trunk : trunks) { + if (trunk.HasFree()) { + allocator = &trunk; + break; + } + } + allocator = &trunks.emplace_back(); + return { allocator, allocator->Allocate(std::forward(inArgs)...) }; + } + + template + void TrunkList::Erase(const Handle& inHandle) + { + Assert(this == inHandle.owner); + inHandle.trunk->Erase(inHandle.index); + } + + template + void TrunkList::Erase(const ConstHandle& inHandle) + { + Assert(this == inHandle.owner); + inHandle.trunk->Erase(inHandle.index); + } + + template + void TrunkList::Each(const TraverseFunc& inFunc) + { + for (auto& trunk : trunks) { + trunk.Each(inFunc); + } + } + + template + void TrunkList::Each(const ConstTraverseFunc& inFunc) const + { + for (auto& trunk : trunks) { + trunk.Each(inFunc); + } + } + + template + void TrunkList::Reserve(size_t inIndex) const + { + auto trunkNum = DivideAndRoundUp(inIndex, N); + if (trunkNum <= trunks.size()) { + return; + } + trunks.reserve(trunkNum); + } + + template + size_t TrunkList::Allocated() const + { + size_t result = 0; + for (const auto& trunk : trunks) { + result += trunk.Allocated(); + } + return result; + } + + template + size_t TrunkList::Capacity() const + { + return trunks.size() * N; + } + + template + size_t TrunkList::Free() const + { + size_t result = 0; + for (const auto& trunk : trunks) { + result += trunk.Free(); + } + return result; + } + + template + bool TrunkList::Empty() const + { + return Allocated() == 0; + } + + template + TrunkList::operator bool() const + { + return Empty(); + } } diff --git a/Engine/Source/Common/Test/ContainerTest.cpp b/Engine/Source/Common/Test/ContainerTest.cpp index eba61b06..9013be97 100644 --- a/Engine/Source/Common/Test/ContainerTest.cpp +++ b/Engine/Source/Common/Test/ContainerTest.cpp @@ -288,3 +288,13 @@ TEST(ContainerTest, InplaceVectorCopyAndMove) ASSERT_EQ(t5[2], temp1); ASSERT_EQ(t5[3], temp1); } + +TEST(ContainerTest, TrunkTest) +{ + // TODO +} + +TEST(ContainerTest, TrunkListTest) +{ + // TODO +} From 970857ab025676097aabab70d36c40b0bb814e86 Mon Sep 17 00:00:00 2001 From: John Kindem <461425614@qq.com> Date: Fri, 18 Oct 2024 20:13:30 +0800 Subject: [PATCH 03/22] refactor: update render module structure --- Editor/Source/CMakeLists.txt | 2 +- Editor/Source/Include/Editor/Core.h | 5 ++-- Editor/Source/Src/Core.cpp | 16 ++++------ Engine/Source/CMakeLists.txt | 1 - Engine/Source/Render/CMakeLists.txt | 17 +++++++---- Engine/Source/Render/Include/Render/Canvas.h | 13 -------- .../Include/Render}/RenderGraph.h | 6 ++-- .../Include/Render/RenderModule.h} | 18 +++++------ .../Include/Render}/Renderer.h | 5 +--- .../Include/Render}/RenderingCache.h | 2 +- .../Include/Render}/ResourcePool.h | 4 +-- Engine/Source/Render/Include/Render/Scene.h | 22 +++++++------- .../SharedSrc/RenderModule.cpp} | 30 +++++++++---------- Engine/Source/Render/Src/Canvas.cpp | 12 -------- .../{Rendering => Render}/Src/RenderGraph.cpp | 8 ++--- Engine/Source/Render/Src/Renderer.cpp | 9 ++++++ .../Src/RenderingCache.cpp | 6 ++-- .../{Rendering => Render}/Src/Scene.cpp | 4 +-- .../Test/ResourcePoolTest.cpp | 4 +-- Engine/Source/Rendering/CMakeLists.txt | 23 -------------- .../Rendering/Include/Rendering/Scene.h | 22 -------------- Engine/Source/Rendering/Src/Renderer.cpp | 9 ------ Engine/Source/Runtime/CMakeLists.txt | 2 +- .../Runtime/Include/Runtime/System/Scene.h | 3 +- Engine/Source/Runtime/Src/System/Scene.cpp | 6 ++-- Sample/CMakeLists.txt | 2 +- Sample/Rendering-Triangle/Triangle.cpp | 5 ++-- 27 files changed, 91 insertions(+), 165 deletions(-) delete mode 100644 Engine/Source/Render/Include/Render/Canvas.h rename Engine/Source/{Rendering/Include/Rendering => Render/Include/Render}/RenderGraph.h (99%) rename Engine/Source/{Rendering/Include/Rendering/RenderingModule.h => Render/Include/Render/RenderModule.h} (72%) rename Engine/Source/{Rendering/Include/Rendering => Render/Include/Render}/Renderer.h (57%) rename Engine/Source/{Rendering/Include/Rendering => Render/Include/Render}/RenderingCache.h (99%) rename Engine/Source/{Rendering/Include/Rendering => Render/Include/Render}/ResourcePool.h (99%) rename Engine/Source/{Rendering/SharedSrc/RenderingModule.cpp => Render/SharedSrc/RenderModule.cpp} (59%) delete mode 100644 Engine/Source/Render/Src/Canvas.cpp rename Engine/Source/{Rendering => Render}/Src/RenderGraph.cpp (99%) create mode 100644 Engine/Source/Render/Src/Renderer.cpp rename Engine/Source/{Rendering => Render}/Src/RenderingCache.cpp (99%) rename Engine/Source/{Rendering => Render}/Src/Scene.cpp (72%) rename Engine/Source/{Rendering => Render}/Test/ResourcePoolTest.cpp (96%) delete mode 100644 Engine/Source/Rendering/CMakeLists.txt delete mode 100644 Engine/Source/Rendering/Include/Rendering/Scene.h delete mode 100644 Engine/Source/Rendering/Src/Renderer.cpp diff --git a/Editor/Source/CMakeLists.txt b/Editor/Source/CMakeLists.txt index 78c41d40..67bc6f3a 100644 --- a/Editor/Source/CMakeLists.txt +++ b/Editor/Source/CMakeLists.txt @@ -9,7 +9,7 @@ AddExecutable( NAME Editor SRC ${SOURCES} INC Include - LIB Qt Core RHI Rendering Runtime + LIB Qt Core RHI Runtime RES ${FINAL_RESOURCES} ) diff --git a/Editor/Source/Include/Editor/Core.h b/Editor/Source/Include/Editor/Core.h index a9372862..9747ce37 100644 --- a/Editor/Source/Include/Editor/Core.h +++ b/Editor/Source/Include/Editor/Core.h @@ -5,7 +5,7 @@ #pragma once #include -#include +#include namespace Editor { class Core { @@ -17,7 +17,6 @@ namespace Editor { void Initialize(int argc, char** argv); void Cleanup(); bool ProjectHasSet() const; - Rendering::RenderingModule* GetRenderingModule() const; Runtime::Engine* GetEngine() const; private: @@ -27,7 +26,7 @@ namespace Editor { void InitializeRuntime(); void InitializeRendering(); - Rendering::RenderingModule* renderingModule; + Render::RenderModule* renderModule; Runtime::Engine* engine; }; } diff --git a/Editor/Source/Src/Core.cpp b/Editor/Source/Src/Core.cpp index ea60c5f7..6f72c3f9 100644 --- a/Editor/Source/Src/Core.cpp +++ b/Editor/Source/Src/Core.cpp @@ -21,7 +21,7 @@ namespace Editor { } Core::Core() - : renderingModule(nullptr) + : renderModule(nullptr) , engine(nullptr) { } @@ -51,11 +51,6 @@ namespace Editor { return !caProjectFile.GetValue().empty(); } - Rendering::RenderingModule* Core::GetRenderingModule() const - { - return renderingModule; - } - void Core::ParseCommandLineArgs(int argc, char** argv) const // NOLINT { ::Core::Cli::Get().Parse(argc, argv); @@ -71,11 +66,12 @@ namespace Editor { void Core::InitializeRendering() { - renderingModule = ::Core::ModuleManager::Get().FindOrLoadTyped("Rendering"); - Assert(renderingModule != nullptr); + // TODO move render module initialize to engine internal + renderModule = ::Core::ModuleManager::Get().FindOrLoadTyped("Render"); + Assert(renderModule != nullptr); - Rendering::RenderingModuleInitParams initParams; + Render::RenderModuleInitParams initParams; initParams.rhiType = RHI::RHIAbbrStringToRHIType(caRhiType.GetValue()); - renderingModule->Initialize(initParams); + renderModule->Initialize(initParams); } } diff --git a/Engine/Source/CMakeLists.txt b/Engine/Source/CMakeLists.txt index 98b21b72..5cd23a69 100644 --- a/Engine/Source/CMakeLists.txt +++ b/Engine/Source/CMakeLists.txt @@ -8,7 +8,6 @@ add_subdirectory(Mirror) add_subdirectory(Core) add_subdirectory(Render) add_subdirectory(Runtime) -add_subdirectory(Rendering) add_subdirectory(RHI-Dummy) add_subdirectory(RHI-Vulkan) diff --git a/Engine/Source/Render/CMakeLists.txt b/Engine/Source/Render/CMakeLists.txt index f05a258f..3efbf662 100644 --- a/Engine/Source/Render/CMakeLists.txt +++ b/Engine/Source/Render/CMakeLists.txt @@ -1,20 +1,27 @@ -# TODO for dxc, replace this with real dxc lib someday ? if (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") set(PLATFORM_LIBS VulkanSDK) endif() -file(GLOB_RECURSE SOURCES Src/*.cpp) +file(GLOB SOURCES Src/*.cpp) AddLibrary( - NAME Render + NAME Render.Static TYPE STATIC SRC ${SOURCES} PUBLIC_INC Include - LIB RHI ${PLATFORM_LIBS} dxc spirv-cross + LIB Core RHI ${PLATFORM_LIBS} dxc spirv-cross +) + +file(GLOB SHARED_SOURCES SharedSrc/*.cpp) +AddLibrary( + NAME Render + TYPE SHARED + SRC ${SHARED_SOURCES} + LIB Render.Static ) file(GLOB TEST_SOURCES Test/*.cpp) AddTest( NAME Render.Test SRC ${TEST_SOURCES} - LIB Render + LIB RHI Render.Static ) diff --git a/Engine/Source/Render/Include/Render/Canvas.h b/Engine/Source/Render/Include/Render/Canvas.h deleted file mode 100644 index 6ae6f61a..00000000 --- a/Engine/Source/Render/Include/Render/Canvas.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// Created by johnk on 2022/8/3. -// - -#pragma once - -namespace Render { - class Canvas { - public: - void Destroy() const; - // TODO - }; -} diff --git a/Engine/Source/Rendering/Include/Rendering/RenderGraph.h b/Engine/Source/Render/Include/Render/RenderGraph.h similarity index 99% rename from Engine/Source/Rendering/Include/Rendering/RenderGraph.h rename to Engine/Source/Render/Include/Render/RenderGraph.h index 24a02272..afd71db1 100644 --- a/Engine/Source/Rendering/Include/Rendering/RenderGraph.h +++ b/Engine/Source/Render/Include/Render/RenderGraph.h @@ -10,10 +10,10 @@ #include #include -#include -#include +#include +#include -namespace Rendering { +namespace Render { class RGBuilder; enum class RGResType : uint8_t { diff --git a/Engine/Source/Rendering/Include/Rendering/RenderingModule.h b/Engine/Source/Render/Include/Render/RenderModule.h similarity index 72% rename from Engine/Source/Rendering/Include/Rendering/RenderingModule.h rename to Engine/Source/Render/Include/Render/RenderModule.h index 5a511145..8770131c 100644 --- a/Engine/Source/Rendering/Include/Rendering/RenderingModule.h +++ b/Engine/Source/Render/Include/Render/RenderModule.h @@ -9,27 +9,27 @@ #include #include #include -#include +#include #include -namespace Rendering { - struct RenderingModuleInitParams { +namespace Render { + struct RenderModuleInitParams { RHI::RHIType rhiType; }; - class RENDERING_API RenderingModule final : public Core::Module { + class RENDER_API RenderModule final : public Core::Module { public: - RenderingModule(); - ~RenderingModule() override; + RenderModule(); + ~RenderModule() override; void OnLoad() override; void OnUnload() override; Core::ModuleType Type() const override; - void Initialize(const RenderingModuleInitParams& inParams); + void Initialize(const RenderModuleInitParams& inParams); RHI::Device* GetDevice() const; - Render::IScene* AllocateScene(); - void DestroyScene(Render::IScene* inScene); + Scene* AllocateScene(); + void DestroyScene(Scene* inScene); void ShutdownRenderingThread(); void FlushAllRenderingCommands() const; diff --git a/Engine/Source/Rendering/Include/Rendering/Renderer.h b/Engine/Source/Render/Include/Render/Renderer.h similarity index 57% rename from Engine/Source/Rendering/Include/Rendering/Renderer.h rename to Engine/Source/Render/Include/Render/Renderer.h index 959df5d3..b7873aab 100644 --- a/Engine/Source/Rendering/Include/Rendering/Renderer.h +++ b/Engine/Source/Render/Include/Render/Renderer.h @@ -7,9 +7,6 @@ #include #include -#include -#include - -namespace Rendering { +namespace Render { // TODO } diff --git a/Engine/Source/Rendering/Include/Rendering/RenderingCache.h b/Engine/Source/Render/Include/Render/RenderingCache.h similarity index 99% rename from Engine/Source/Rendering/Include/Rendering/RenderingCache.h rename to Engine/Source/Render/Include/Render/RenderingCache.h index 9747d55c..15284225 100644 --- a/Engine/Source/Rendering/Include/Rendering/RenderingCache.h +++ b/Engine/Source/Render/Include/Render/RenderingCache.h @@ -9,7 +9,7 @@ #include #include -namespace Rendering { +namespace Render { class PipelineLayout; class ComputePipelineState; class RasterPipelineState; diff --git a/Engine/Source/Rendering/Include/Rendering/ResourcePool.h b/Engine/Source/Render/Include/Render/ResourcePool.h similarity index 99% rename from Engine/Source/Rendering/Include/Rendering/ResourcePool.h rename to Engine/Source/Render/Include/Render/ResourcePool.h index 1f183fe6..68733e91 100644 --- a/Engine/Source/Rendering/Include/Rendering/ResourcePool.h +++ b/Engine/Source/Render/Include/Render/ResourcePool.h @@ -11,7 +11,7 @@ #include #include -namespace Rendering { +namespace Render { template struct RHIResTraits {}; @@ -63,7 +63,7 @@ namespace Rendering { using TexturePool = RGResourcePool; } -namespace Rendering { +namespace Render { template <> struct RHIResTraits { using DescType = RHI::BufferCreateInfo; diff --git a/Engine/Source/Render/Include/Render/Scene.h b/Engine/Source/Render/Include/Render/Scene.h index 1cd02ef9..3b9ed8d6 100644 --- a/Engine/Source/Render/Include/Render/Scene.h +++ b/Engine/Source/Render/Include/Render/Scene.h @@ -1,22 +1,20 @@ // -// Created by johnk on 2022/8/3. +// Created by johnk on 2023/7/22. // #pragma once -#include - -#include +#include namespace Render { - template - using SceneProxyPatcher = std::function; - - class IScene { + class Scene final { public: - virtual ~IScene() = default; - virtual size_t GAddLight(const LightSceneProxy& inLight) = 0; - virtual void GRemoveLight(size_t inLightIndex) = 0; - virtual void GPatchLight(size_t inLightIndex, const SceneProxyPatcher& inPatcher) = 0; + Scene(); + ~Scene(); + + // TODO AddLight/RemoveLight/PatchLight + + private: + // TODO use object tool }; } diff --git a/Engine/Source/Rendering/SharedSrc/RenderingModule.cpp b/Engine/Source/Render/SharedSrc/RenderModule.cpp similarity index 59% rename from Engine/Source/Rendering/SharedSrc/RenderingModule.cpp rename to Engine/Source/Render/SharedSrc/RenderModule.cpp index c70d4782..190a387a 100644 --- a/Engine/Source/Rendering/SharedSrc/RenderingModule.cpp +++ b/Engine/Source/Render/SharedSrc/RenderModule.cpp @@ -2,34 +2,34 @@ // Created by johnk on 2023/8/4. // -#include -#include +#include +#include -namespace Rendering { - RenderingModule::RenderingModule() +namespace Render { + RenderModule::RenderModule() : initialized(false) , rhiInstance(nullptr) { } - RenderingModule::~RenderingModule() = default; + RenderModule::~RenderModule() = default; - void RenderingModule::OnLoad() + void RenderModule::OnLoad() { Module::OnLoad(); } - void RenderingModule::OnUnload() + void RenderModule::OnUnload() { Module::OnUnload(); } - Core::ModuleType RenderingModule::Type() const + Core::ModuleType RenderModule::Type() const { return Core::ModuleType::mDynamic; } - void RenderingModule::Initialize(const RenderingModuleInitParams& inParams) + void RenderModule::Initialize(const RenderModuleInitParams& inParams) { Assert(!initialized); @@ -45,31 +45,31 @@ namespace Rendering { initialized = true; } - RHI::Device* RenderingModule::GetDevice() const + RHI::Device* RenderModule::GetDevice() const { return rhiDevice.Get(); } - Render::IScene* RenderingModule::AllocateScene() // NOLINT + Render::Scene* RenderModule::AllocateScene() // NOLINT { return new Scene(); } - void RenderingModule::DestroyScene(Render::IScene* inScene) // NOLINT + void RenderModule::DestroyScene(Render::Scene* inScene) // NOLINT { delete inScene; } - void RenderingModule::ShutdownRenderingThread() + void RenderModule::ShutdownRenderingThread() { renderingThread = nullptr; } - void RenderingModule::FlushAllRenderingCommands() const + void RenderModule::FlushAllRenderingCommands() const { Assert(renderingThread != nullptr); renderingThread->Flush(); } } -IMPLEMENT_DYNAMIC_MODULE(RENDERING_API, Rendering::RenderingModule); +IMPLEMENT_DYNAMIC_MODULE(RENDER_API, Render::RenderModule); diff --git a/Engine/Source/Render/Src/Canvas.cpp b/Engine/Source/Render/Src/Canvas.cpp deleted file mode 100644 index 63ba6a78..00000000 --- a/Engine/Source/Render/Src/Canvas.cpp +++ /dev/null @@ -1,12 +0,0 @@ -// -// Created by johnk on 2022/8/4. -// - -#include - -namespace Render { - void Canvas::Destroy() const - { - delete this; - } -} diff --git a/Engine/Source/Rendering/Src/RenderGraph.cpp b/Engine/Source/Render/Src/RenderGraph.cpp similarity index 99% rename from Engine/Source/Rendering/Src/RenderGraph.cpp rename to Engine/Source/Render/Src/RenderGraph.cpp index 4ac1dbf4..bebb6ba8 100644 --- a/Engine/Source/Rendering/Src/RenderGraph.cpp +++ b/Engine/Source/Render/Src/RenderGraph.cpp @@ -4,11 +4,11 @@ #include -#include -#include +#include +#include #include -namespace Rendering::Internal { +namespace Render::Internal { static void ComputeReadsWritesForBindGroup(const RGBindGroupDesc& inDesc, std::unordered_set& outReads, std::unordered_set& outWrites) { for (const auto& [name, item] : inDesc.items) { @@ -55,7 +55,7 @@ namespace Rendering::Internal { } } -namespace Rendering { +namespace Render { RGResource::RGResource(const RGResType inType) : type(inType) , forceUsed(false) diff --git a/Engine/Source/Render/Src/Renderer.cpp b/Engine/Source/Render/Src/Renderer.cpp new file mode 100644 index 00000000..0472ce3b --- /dev/null +++ b/Engine/Source/Render/Src/Renderer.cpp @@ -0,0 +1,9 @@ +// +// Created by johnk on 2022/8/3. +// + +#include + +namespace Render { + +} diff --git a/Engine/Source/Rendering/Src/RenderingCache.cpp b/Engine/Source/Render/Src/RenderingCache.cpp similarity index 99% rename from Engine/Source/Rendering/Src/RenderingCache.cpp rename to Engine/Source/Render/Src/RenderingCache.cpp index bc479587..272ebbac 100644 --- a/Engine/Source/Rendering/Src/RenderingCache.cpp +++ b/Engine/Source/Render/Src/RenderingCache.cpp @@ -2,13 +2,13 @@ // Created by johnk on 2023/3/11. // -#include +#include #include #include -namespace Rendering { +namespace Render { class PipelineLayoutCache { public: static PipelineLayoutCache& Get(RHI::Device& device); @@ -58,7 +58,7 @@ namespace Rendering { } } -namespace Rendering { +namespace Render { RVertexBinding::RVertexBinding() : semanticName() , semanticIndex(0) diff --git a/Engine/Source/Rendering/Src/Scene.cpp b/Engine/Source/Render/Src/Scene.cpp similarity index 72% rename from Engine/Source/Rendering/Src/Scene.cpp rename to Engine/Source/Render/Src/Scene.cpp index 7bff35ca..62f2bf6f 100644 --- a/Engine/Source/Rendering/Src/Scene.cpp +++ b/Engine/Source/Render/Src/Scene.cpp @@ -3,9 +3,9 @@ // #include -#include +#include -namespace Rendering { +namespace Render { Scene::Scene() = default; Scene::~Scene() = default; diff --git a/Engine/Source/Rendering/Test/ResourcePoolTest.cpp b/Engine/Source/Render/Test/ResourcePoolTest.cpp similarity index 96% rename from Engine/Source/Rendering/Test/ResourcePoolTest.cpp rename to Engine/Source/Render/Test/ResourcePoolTest.cpp index 47c1b21b..2e07f3df 100644 --- a/Engine/Source/Rendering/Test/ResourcePoolTest.cpp +++ b/Engine/Source/Render/Test/ResourcePoolTest.cpp @@ -4,9 +4,9 @@ #include -#include +#include -using namespace Rendering; +using namespace Render; struct ResourcePoolTest : testing::Test { void SetUp() override diff --git a/Engine/Source/Rendering/CMakeLists.txt b/Engine/Source/Rendering/CMakeLists.txt deleted file mode 100644 index c03250d8..00000000 --- a/Engine/Source/Rendering/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -file(GLOB SOURCES Src/*.cpp) -AddLibrary( - NAME Rendering.Static - TYPE STATIC - SRC ${SOURCES} - PUBLIC_INC Include - LIB Render Core -) - -file(GLOB SHARED_SOURCES SharedSrc/*.cpp) -AddLibrary( - NAME Rendering - TYPE SHARED - SRC ${SHARED_SOURCES} - LIB Rendering.Static -) - -file(GLOB TEST_SOURCES Test/*.cpp) -AddTest( - NAME Rendering.Test - SRC ${TEST_SOURCES} - LIB RHI Rendering.Static -) diff --git a/Engine/Source/Rendering/Include/Rendering/Scene.h b/Engine/Source/Rendering/Include/Rendering/Scene.h deleted file mode 100644 index b3dde9bd..00000000 --- a/Engine/Source/Rendering/Include/Rendering/Scene.h +++ /dev/null @@ -1,22 +0,0 @@ -// -// Created by johnk on 2023/7/22. -// - -#pragma once - -#include - -#include - -namespace Rendering { - class Scene final : public Render::IScene { - public: - Scene(); - ~Scene() override; - - // TODO AddLight/RemoveLight/PatchLight - - private: - // TODO use object tool - }; -} diff --git a/Engine/Source/Rendering/Src/Renderer.cpp b/Engine/Source/Rendering/Src/Renderer.cpp deleted file mode 100644 index d56a9e16..00000000 --- a/Engine/Source/Rendering/Src/Renderer.cpp +++ /dev/null @@ -1,9 +0,0 @@ -// -// Created by johnk on 2022/8/3. -// - -#include - -namespace Rendering { - -} diff --git a/Engine/Source/Runtime/CMakeLists.txt b/Engine/Source/Runtime/CMakeLists.txt index 0f75af92..cb051bfd 100644 --- a/Engine/Source/Runtime/CMakeLists.txt +++ b/Engine/Source/Runtime/CMakeLists.txt @@ -5,7 +5,7 @@ AddLibrary( SRC ${SOURCES} PUBLIC_INC Include REFLECT Include - LIB Core Mirror assimp-lib Render Rendering EnTT + LIB Core Mirror assimp-lib Render EnTT ) file(GLOB TEST_SOURCES Test/*.cpp) diff --git a/Engine/Source/Runtime/Include/Runtime/System/Scene.h b/Engine/Source/Runtime/Include/Runtime/System/Scene.h index 76d85df7..e8b6ed6d 100644 --- a/Engine/Source/Runtime/Include/Runtime/System/Scene.h +++ b/Engine/Source/Runtime/Include/Runtime/System/Scene.h @@ -10,7 +10,8 @@ namespace Runtime { struct SceneState { - Render::IScene* scene; + Render::Scene* scene; + // TODO views }; class EClass() SceneSystem final : public System { diff --git a/Engine/Source/Runtime/Src/System/Scene.cpp b/Engine/Source/Runtime/Src/System/Scene.cpp index 10e34d6f..74ce0472 100644 --- a/Engine/Source/Runtime/Src/System/Scene.cpp +++ b/Engine/Source/Runtime/Src/System/Scene.cpp @@ -3,7 +3,7 @@ // #include -#include +#include namespace Runtime { SceneSystem::SceneSystem() = default; @@ -14,8 +14,8 @@ namespace Runtime { { inCommands.EmplaceState(); inCommands.PatchState([](auto& state) -> void { - auto& renderingModule = Core::ModuleManager::Get().GetOrLoadTyped("Rendering"); - state.scene = renderingModule.AllocateScene(); + auto& renderModule = Core::ModuleManager::Get().GetTyped("Render"); + state.scene = renderModule.AllocateScene(); }); } diff --git a/Sample/CMakeLists.txt b/Sample/CMakeLists.txt index a3009873..0d2461da 100644 --- a/Sample/CMakeLists.txt +++ b/Sample/CMakeLists.txt @@ -48,7 +48,7 @@ Addlibrary( NAME Sample-Base SRC ${SOURCES} PUBLIC_INC Base - LIB RHI glfw clipp ${PLATFORM_EXT_LIBS} Render stb assimp-lib Rendering.Static + LIB RHI glfw clipp ${PLATFORM_EXT_LIBS} Render.Static stb assimp-lib ) file(GLOB SOURCES RHI-Triangle/*.cpp) diff --git a/Sample/Rendering-Triangle/Triangle.cpp b/Sample/Rendering-Triangle/Triangle.cpp index 0ed6468a..7ecc2b1f 100644 --- a/Sample/Rendering-Triangle/Triangle.cpp +++ b/Sample/Rendering-Triangle/Triangle.cpp @@ -5,12 +5,11 @@ #include #include #include -#include -#include +#include +#include using namespace Common; using namespace Render; -using namespace Rendering; using namespace RHI; struct Vertex { From b3b2016d740e67d3c7d0641e29f1589b8cb6567d Mon Sep 17 00:00:00 2001 From: John Kindem <461425614@qq.com> Date: Sat, 19 Oct 2024 11:59:41 +0800 Subject: [PATCH 04/22] refactor: move render module initialization to engine internal --- Editor/Source/Include/Editor/Core.h | 2 - Editor/Source/Src/Core.cpp | 18 +- .../Source/Common/Include/Common/Container.h | 24 +-- Engine/Source/Common/Src/DynamicLibrary.cpp | 16 +- Engine/Source/Common/Test/ContainerTest.cpp | 172 +++++++++++------- .../Source/Runtime/Include/Runtime/Engine.h | 5 + .../Runtime/Include/Runtime/System/Scene.h | 1 + Engine/Source/Runtime/Src/Engine.cpp | 24 ++- Engine/Source/Runtime/Src/System/Scene.cpp | 10 +- Engine/Source/Runtime/Test/WorldTest.cpp | 5 +- Tool/MirrorTool/Src/Parser.cpp | 6 +- 11 files changed, 172 insertions(+), 111 deletions(-) diff --git a/Editor/Source/Include/Editor/Core.h b/Editor/Source/Include/Editor/Core.h index 9747ce37..1149f9f5 100644 --- a/Editor/Source/Include/Editor/Core.h +++ b/Editor/Source/Include/Editor/Core.h @@ -24,9 +24,7 @@ namespace Editor { void ParseCommandLineArgs(int argc, char** argv) const; void InitializeRuntime(); - void InitializeRendering(); - Render::RenderModule* renderModule; Runtime::Engine* engine; }; } diff --git a/Editor/Source/Src/Core.cpp b/Editor/Source/Src/Core.cpp index 6f72c3f9..d958b563 100644 --- a/Editor/Source/Src/Core.cpp +++ b/Editor/Source/Src/Core.cpp @@ -21,8 +21,7 @@ namespace Editor { } Core::Core() - : renderModule(nullptr) - , engine(nullptr) + : engine(nullptr) { } @@ -32,13 +31,11 @@ namespace Editor { { ParseCommandLineArgs(argc, argv); InitializeRuntime(); - InitializeRendering(); } void Core::Cleanup() // NOLINT { ::Core::ModuleManager::Get().Unload("Runtime"); - ::Core::ModuleManager::Get().Unload("Rendering"); } Runtime::Engine* Core::GetEngine() const @@ -60,18 +57,9 @@ namespace Editor { { Runtime::EngineInitParams params {}; params.projectFile = caProjectFile.GetValue(); + params.rhiType = caRhiType.GetValue(); + Runtime::EngineHolder::Load("Editor", params); engine = &Runtime::EngineHolder::Get(); } - - void Core::InitializeRendering() - { - // TODO move render module initialize to engine internal - renderModule = ::Core::ModuleManager::Get().FindOrLoadTyped("Render"); - Assert(renderModule != nullptr); - - Render::RenderModuleInitParams initParams; - initParams.rhiType = RHI::RHIAbbrStringToRHIType(caRhiType.GetValue()); - renderModule->Initialize(initParams); - } } diff --git a/Engine/Source/Common/Include/Common/Container.h b/Engine/Source/Common/Include/Common/Container.h index feecdbc9..771be769 100644 --- a/Engine/Source/Common/Include/Common/Container.h +++ b/Engine/Source/Common/Include/Common/Container.h @@ -166,13 +166,13 @@ namespace Common { Trunk& operator=(const Trunk& inOther); Trunk& operator=(Trunk&& inOther) noexcept; - template size_t Allocate(Args&&... inArgs); + template size_t Emplace(Args&&... inArgs); bool Valid(size_t inIndex) const; void Erase(size_t inIndex); T* Try(size_t inIndex); const T* Try(size_t inIndex) const; - T* At(size_t inIndex); - const T* At(size_t inIndex) const; + T& At(size_t inIndex); + const T& At(size_t inIndex) const; void Each(const TraverseFunc& inFunc); void Each(const ConstTraverseFunc& inFunc) const; bool HasFree() const; @@ -245,7 +245,7 @@ namespace Common { TrunkList(); ~TrunkList(); - template Handle Allocate(Args&&... inArgs) const; + template Handle Emplace(Args&&... inArgs) const; void Erase(const Handle& inHandle); void Erase(const ConstHandle& inHandle); void Each(const TraverseFunc& inFunc); @@ -1126,7 +1126,7 @@ namespace Common { template template - size_t Trunk::Allocate(Args&&... inArgs) + size_t Trunk::Emplace(Args&&... inArgs) { for (auto i = 0; i < allocated.size(); i++) { if (!allocated.test(i)) { @@ -1169,17 +1169,17 @@ namespace Common { } template - T* Trunk::At(size_t inIndex) + T& Trunk::At(size_t inIndex) { Assert(Valid(inIndex)); - return &TypedMemory(inIndex); + return TypedMemory(inIndex); } template - const T* Trunk::At(size_t inIndex) const + const T& Trunk::At(size_t inIndex) const { Assert(Valid(inIndex)); - return &TypedMemory(inIndex); + return TypedMemory(inIndex); } template @@ -1223,7 +1223,7 @@ namespace Common { template bool Trunk::Empty() const { - return Allocated() > 0; + return Allocated() == 0; } template @@ -1367,7 +1367,7 @@ namespace Common { template template - typename TrunkList::Handle TrunkList::Allocate(Args&&... inArgs) const + typename TrunkList::Handle TrunkList::Emplace(Args&&... inArgs) const { Trunk* allocator = nullptr; for (auto& trunk : trunks) { @@ -1377,7 +1377,7 @@ namespace Common { } } allocator = &trunks.emplace_back(); - return { allocator, allocator->Allocate(std::forward(inArgs)...) }; + return { allocator, allocator->Emplace(std::forward(inArgs)...) }; } template diff --git a/Engine/Source/Common/Src/DynamicLibrary.cpp b/Engine/Source/Common/Src/DynamicLibrary.cpp index 6df1a2e4..c6e2c149 100644 --- a/Engine/Source/Common/Src/DynamicLibrary.cpp +++ b/Engine/Source/Common/Src/DynamicLibrary.cpp @@ -2,6 +2,8 @@ // Created by johnk on 28/12/2021. // +#include + #include #include @@ -38,19 +40,17 @@ namespace Common { } DynamicLibrary::DynamicLibrary(DynamicLibrary&& inOther) noexcept - : loaded(inOther.loaded) - , fullPath(std::move(inOther.fullPath)) - , handle(inOther.handle) + : loaded(std::exchange(inOther.loaded, false)) + , fullPath(std::exchange(inOther.fullPath, "")) + , handle(std::exchange(inOther.handle, nullptr)) { - inOther.loaded = false; } DynamicLibrary& DynamicLibrary::operator=(DynamicLibrary&& inOther) noexcept { - loaded = inOther.loaded; - fullPath = std::move(inOther.fullPath); - handle = inOther.handle; - inOther.loaded = false; + loaded = std::exchange(inOther.loaded, false); + fullPath = std::exchange(inOther.fullPath, ""); + handle = std::exchange(inOther.handle, nullptr); return *this; } diff --git a/Engine/Source/Common/Test/ContainerTest.cpp b/Engine/Source/Common/Test/ContainerTest.cpp index 9013be97..c851a882 100644 --- a/Engine/Source/Common/Test/ContainerTest.cpp +++ b/Engine/Source/Common/Test/ContainerTest.cpp @@ -6,6 +6,66 @@ #include using namespace Common; +enum class ConstructType : uint8_t { + cDefault, + cCopy, + cMove, + max +}; + +struct CopyAndMoveTest { + ConstructType constructType; + bool copyAssigned; + bool moveAssigned; + + CopyAndMoveTest() + : constructType(ConstructType::cDefault) + , copyAssigned(false) + , moveAssigned(false) + { + } + + CopyAndMoveTest(ConstructType inType, bool inCopyAssigned, bool inMoveAssigned) + : constructType(inType) + , copyAssigned(inCopyAssigned) + , moveAssigned(inMoveAssigned) + { + } + + CopyAndMoveTest(const CopyAndMoveTest& inOther) + : constructType(ConstructType::cCopy) + , copyAssigned(false) + , moveAssigned(false) + { + } + + CopyAndMoveTest(CopyAndMoveTest&& inOther) noexcept + : constructType(ConstructType::cMove) + , copyAssigned(false) + , moveAssigned(false) + { + } + + CopyAndMoveTest& operator=(const CopyAndMoveTest& inOther) + { + copyAssigned = true; + return *this; + } + + CopyAndMoveTest& operator=(CopyAndMoveTest&& inOther) noexcept + { + moveAssigned = true; + return *this; + } + + bool operator==(const CopyAndMoveTest& inOther) const + { + return constructType == inOther.constructType + && copyAssigned == inOther.copyAssigned + && moveAssigned == inOther.moveAssigned; + } +}; + TEST(ContainerTest, VectorSwapDeleteTest) { std::vector vec0 = { 1, 2, 3, 4, 5 }; @@ -164,86 +224,26 @@ TEST(ContainerTest, InplaceVectorIter) TEST(ContainerTest, InplaceVectorCopyAndMove) { - enum class ConstructType : uint8_t { - cDefault, - cCopy, - cMove, - max - }; - - struct S0 { - ConstructType constructType; - bool copyAssigned; - bool moveAssigned; - - S0() - : constructType(ConstructType::cDefault) - , copyAssigned(false) - , moveAssigned(false) - { - } - - S0(ConstructType inType, bool inCopyAssigned, bool inMoveAssigned) - : constructType(inType) - , copyAssigned(inCopyAssigned) - , moveAssigned(inMoveAssigned) - { - } - - S0(const S0& inOther) - : constructType(ConstructType::cCopy) - , copyAssigned(false) - , moveAssigned(false) - { - } - - S0(S0&& inOther) noexcept - : constructType(ConstructType::cMove) - , copyAssigned(false) - , moveAssigned(false) - { - } - - S0& operator=(const S0& inOther) - { - copyAssigned = true; - return *this; - } - - S0& operator=(S0&& inOther) noexcept - { - moveAssigned = true; - return *this; - } - - bool operator==(const S0& inOther) const - { - return constructType == inOther.constructType - && copyAssigned == inOther.copyAssigned - && moveAssigned == inOther.moveAssigned; - } - }; - - InplaceVector t0; + InplaceVector t0; t0.EmplaceBack(); t0.EmplaceBack(); ASSERT_EQ(t0[0].constructType, ConstructType::cDefault); ASSERT_EQ(t0[1].constructType, ConstructType::cDefault); - t0.PushBack(S0()); + t0.PushBack(CopyAndMoveTest()); ASSERT_EQ(t0[2].constructType, ConstructType::cMove); - const S0 temp0; + const CopyAndMoveTest temp0; t0.PushBack(temp0); ASSERT_EQ(t0[3].constructType, ConstructType::cCopy); // copy assign - InplaceVector t2; + InplaceVector t2; t2.Resize(2); ASSERT_EQ(t2[0].constructType, ConstructType::cCopy); ASSERT_EQ(t2[1].constructType, ConstructType::cCopy); t2 = t0; - S0 temp1; + CopyAndMoveTest temp1; temp1.constructType = ConstructType::cCopy; temp1.copyAssigned = true; temp1.moveAssigned = false; @@ -254,7 +254,7 @@ TEST(ContainerTest, InplaceVectorCopyAndMove) ASSERT_EQ(t2[3], temp1); // move assign - InplaceVector t3; + InplaceVector t3; t3.Resize(1); t3 = std::move(t2); temp1.constructType = ConstructType::cCopy; @@ -269,7 +269,7 @@ TEST(ContainerTest, InplaceVectorCopyAndMove) ASSERT_EQ(t3[3], temp1); // copy construct - InplaceVector t4 = t3; + InplaceVector t4 = t3; temp1.constructType = ConstructType::cCopy; temp1.copyAssigned = false; temp1.moveAssigned = false; @@ -279,7 +279,7 @@ TEST(ContainerTest, InplaceVectorCopyAndMove) ASSERT_EQ(t4[3], temp1); // move construct - InplaceVector t5 = std::move(t4); + InplaceVector t5 = std::move(t4); temp1.constructType = ConstructType::cMove; temp1.copyAssigned = false; temp1.moveAssigned = false; @@ -289,7 +289,41 @@ TEST(ContainerTest, InplaceVectorCopyAndMove) ASSERT_EQ(t5[3], temp1); } -TEST(ContainerTest, TrunkTest) +TEST(ContainerTest, TrunkBasic) +{ + Trunk t0; + ASSERT_TRUE(t0.HasFree()); + ASSERT_TRUE(t0.Empty()); + ASSERT_EQ(t0.Free(), 4); + ASSERT_EQ(t0.Allocated(), 0); + ASSERT_EQ(t0.Capacity(), 4); // NOLINT + + const size_t v0 = t0.Emplace(1); + ASSERT_TRUE(t0.HasFree()); + ASSERT_FALSE(t0.Empty()); + ASSERT_EQ(t0.Free(), 3); + ASSERT_EQ(t0.Allocated(), 1); + ASSERT_EQ(t0[v0], 1); + + const size_t v1 = t0.Emplace(2); + ASSERT_TRUE(t0.HasFree()); + ASSERT_FALSE(t0.Empty()); + ASSERT_EQ(t0.Free(), 2); + ASSERT_EQ(t0.Allocated(), 2); + ASSERT_EQ(t0[v1], 2); + + t0.Erase(v0); + ASSERT_EQ(t0.Free(), 3); + ASSERT_EQ(t0.Allocated(), 1); + + const size_t v2 = t0.Emplace(3); + ASSERT_EQ(t0.Free(), 2); + ASSERT_EQ(t0.Allocated(), 2); + ASSERT_EQ(v0, v2); + ASSERT_EQ(t0[v2], 3); +} + +TEST(ContainerTest, TrunkCopyAndMove) { // TODO } diff --git a/Engine/Source/Runtime/Include/Runtime/Engine.h b/Engine/Source/Runtime/Include/Runtime/Engine.h index 5152040e..8535a197 100644 --- a/Engine/Source/Runtime/Include/Runtime/Engine.h +++ b/Engine/Source/Runtime/Include/Runtime/Engine.h @@ -8,12 +8,14 @@ #include #include +#include namespace Runtime { class World; struct EngineInitParams { std::string projectFile; + std::string rhiType; }; class RUNTIME_API Engine { // NOLINT @@ -24,11 +26,14 @@ namespace Runtime { void MountWorld(World* inWorld); void UnmountWorld(World* inWorld); + Render::RenderModule& GetRenderModule() const; + void Tick(float inTimeMs) const; protected: explicit Engine(const EngineInitParams& inParams); std::unordered_set worlds; + Render::RenderModule* renderModule; }; class RUNTIME_API MinEngine final : public Engine { diff --git a/Engine/Source/Runtime/Include/Runtime/System/Scene.h b/Engine/Source/Runtime/Include/Runtime/System/Scene.h index e8b6ed6d..31c6fa9d 100644 --- a/Engine/Source/Runtime/Include/Runtime/System/Scene.h +++ b/Engine/Source/Runtime/Include/Runtime/System/Scene.h @@ -22,5 +22,6 @@ namespace Runtime { void Setup(Commands& inCommands) const override; void Tick(Commands& inCommands, float inTimeMs) const override; + void Stop(Commands& inCommands) const override; }; } diff --git a/Engine/Source/Runtime/Src/Engine.cpp b/Engine/Source/Runtime/Src/Engine.cpp index 32f4c5ad..cf4663de 100644 --- a/Engine/Source/Runtime/Src/Engine.cpp +++ b/Engine/Source/Runtime/Src/Engine.cpp @@ -13,9 +13,19 @@ namespace Runtime { if (!inParams.projectFile.empty()) { Core::Paths::SetCurrentProjectFile(inParams.projectFile); } + + renderModule = ::Core::ModuleManager::Get().FindOrLoadTyped("Render"); + Assert(renderModule != nullptr); + + Render::RenderModuleInitParams initParams; + initParams.rhiType = RHI::RHIAbbrStringToRHIType(inParams.rhiType); + renderModule->Initialize(initParams); } - Engine::~Engine() = default; + Engine::~Engine() + { + ::Core::ModuleManager::Get().Unload("Render"); + } void Engine::MountWorld(World* inWorld) { @@ -27,6 +37,18 @@ namespace Runtime { worlds.erase(inWorld); } + Render::RenderModule& Engine::GetRenderModule() const + { + return *renderModule; + } + + void Engine::Tick(float inTimeMs) const + { + // TODO tick each playing world + // TODO fetch each scene + // TODO traverse each view in scene, create a renderer, perform rendering + } + Engine* EngineHolder::engine = nullptr; MinEngine::MinEngine(const EngineInitParams& inParams) diff --git a/Engine/Source/Runtime/Src/System/Scene.cpp b/Engine/Source/Runtime/Src/System/Scene.cpp index 74ce0472..11ddb8e7 100644 --- a/Engine/Source/Runtime/Src/System/Scene.cpp +++ b/Engine/Source/Runtime/Src/System/Scene.cpp @@ -3,7 +3,7 @@ // #include -#include +#include namespace Runtime { SceneSystem::SceneSystem() = default; @@ -14,7 +14,7 @@ namespace Runtime { { inCommands.EmplaceState(); inCommands.PatchState([](auto& state) -> void { - auto& renderModule = Core::ModuleManager::Get().GetTyped("Render"); + auto& renderModule = EngineHolder::Get().GetRenderModule(); state.scene = renderModule.AllocateScene(); }); } @@ -23,4 +23,10 @@ namespace Runtime { { // TODO } + + void SceneSystem::Stop(Commands& inCommands) const + { + auto& renderModule = EngineHolder::Get().GetRenderModule(); + renderModule.DestroyScene(inCommands.GetState().scene); + } } diff --git a/Engine/Source/Runtime/Test/WorldTest.cpp b/Engine/Source/Runtime/Test/WorldTest.cpp index c0fce414..149fa71d 100644 --- a/Engine/Source/Runtime/Test/WorldTest.cpp +++ b/Engine/Source/Runtime/Test/WorldTest.cpp @@ -9,7 +9,10 @@ struct WorldTest : testing::Test { void SetUp() override { - EngineHolder::Load("RuntimeTest", {}); + EngineInitParams initParams; + initParams.projectFile = ""; + initParams.rhiType = RHI::GetPlatformDefaultRHIAbbrString(); + EngineHolder::Load("RuntimeTest", initParams); } }; diff --git a/Tool/MirrorTool/Src/Parser.cpp b/Tool/MirrorTool/Src/Parser.cpp index 5ff6be84..93b2df44 100644 --- a/Tool/MirrorTool/Src/Parser.cpp +++ b/Tool/MirrorTool/Src/Parser.cpp @@ -406,15 +406,19 @@ namespace MirrorTool { "-std=c++20", #if BUILD_CONFIG_DEBUG "-DBUILD_CONFIG_DEBUG=1", +#else + "-DBUILD_CONFIG_DEBUG=0", #endif #if BUILD_EDITOR "-DBUILD_EDITOR=1", +#else + "-DBUILD_EDITOR=0", #endif #if PLATFORM_WINDOWS "-DPLATFORM_WINDOWS=1", + "-DNOMINMAX=1", #elif PLATFORM_MACOS "-DPLATFORM_MACOS=1", -// "-I/Library/Developer/CommandLineTools/usr/include/c++/v1", fmt::format("-I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX{}.sdk/usr/include/c++/v1", MACOS_SDK_VERSION), fmt::format("-I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX{}.sdk/usr/include", MACOS_SDK_VERSION), fmt::format("-I/Library/Developer/CommandLineTools/usr/lib/clang/{}.{}.{}/include", __clang_major__, __clang_minor__, __clang_patchlevel__), From 05e3e59024389770026ffaf9a3807ae3daf5da5e Mon Sep 17 00:00:00 2001 From: John Kindem <461425614@qq.com> Date: Wed, 23 Oct 2024 21:54:39 +0800 Subject: [PATCH 05/22] feat: trunk and trunk list test --- Engine/Source/Common/CMakeLists.txt | 2 +- .../Source/Common/Include/Common/Container.h | 14 ++- Engine/Source/Common/Include/Common/Debug.h | 5 +- Engine/Source/Common/Test/ContainerTest.cpp | 103 +++++++++++++++++- ThirdParty/CMakeLists.txt | 9 -- 5 files changed, 112 insertions(+), 21 deletions(-) diff --git a/Engine/Source/Common/CMakeLists.txt b/Engine/Source/Common/CMakeLists.txt index 9d14ceb0..2f0855bf 100644 --- a/Engine/Source/Common/CMakeLists.txt +++ b/Engine/Source/Common/CMakeLists.txt @@ -4,7 +4,7 @@ AddLibrary( TYPE STATIC SRC ${SOURCES} PUBLIC_INC Include - LIB debugbreak cityhash taskflow fmt-lib rapidjson + LIB debugbreak cityhash taskflow rapidjson ) file(GLOB TEST_SOURCES Test/*.cpp) diff --git a/Engine/Source/Common/Include/Common/Container.h b/Engine/Source/Common/Include/Common/Container.h index 771be769..90979a8a 100644 --- a/Engine/Source/Common/Include/Common/Container.h +++ b/Engine/Source/Common/Include/Common/Container.h @@ -245,12 +245,12 @@ namespace Common { TrunkList(); ~TrunkList(); - template Handle Emplace(Args&&... inArgs) const; + template Handle Emplace(Args&&... inArgs); void Erase(const Handle& inHandle); void Erase(const ConstHandle& inHandle); void Each(const TraverseFunc& inFunc); void Each(const ConstTraverseFunc& inFunc) const; - void Reserve(size_t inIndex) const; + void Reserve(size_t inIndex); size_t Allocated() const; size_t Capacity() const; size_t Free() const; @@ -1367,7 +1367,7 @@ namespace Common { template template - typename TrunkList::Handle TrunkList::Emplace(Args&&... inArgs) const + typename TrunkList::Handle TrunkList::Emplace(Args&&... inArgs) { Trunk* allocator = nullptr; for (auto& trunk : trunks) { @@ -1376,8 +1376,10 @@ namespace Common { break; } } - allocator = &trunks.emplace_back(); - return { allocator, allocator->Emplace(std::forward(inArgs)...) }; + if (allocator == nullptr) { + allocator = &trunks.emplace_back(); + } + return { this, allocator, allocator->Emplace(std::forward(inArgs)...) }; } template @@ -1411,7 +1413,7 @@ namespace Common { } template - void TrunkList::Reserve(size_t inIndex) const + void TrunkList::Reserve(size_t inIndex) { auto trunkNum = DivideAndRoundUp(inIndex, N); if (trunkNum <= trunks.size()) { diff --git a/Engine/Source/Common/Include/Common/Debug.h b/Engine/Source/Common/Include/Common/Debug.h index 595f91e4..52c7fb97 100644 --- a/Engine/Source/Common/Include/Common/Debug.h +++ b/Engine/Source/Common/Include/Common/Debug.h @@ -6,9 +6,10 @@ #include #include +#include -#define Assert(expression) Common::Debug::AssertImpl(expression, #expression, __FILE__, __LINE__) -#define AssertWithReason(expression, reason) Common::Debug::AssertImpl(expression, #expression, __FILE__, __LINE__, reason) +#define Assert(expression) Common::Debug::AssertImpl(expression, #expression, std::source_location::current().file_name(), std::source_location::current().line()) +#define AssertWithReason(expression, reason) Common::Debug::AssertImpl(expression, #expression, std::source_location::current().file_name(), std::source_location::current().line(), reason) #define Unimplement() Assert(false) #define QuickFail() Assert(false) #define QuickFailWithReason(reason) AssertWithReason(false, reason) diff --git a/Engine/Source/Common/Test/ContainerTest.cpp b/Engine/Source/Common/Test/ContainerTest.cpp index c851a882..98932189 100644 --- a/Engine/Source/Common/Test/ContainerTest.cpp +++ b/Engine/Source/Common/Test/ContainerTest.cpp @@ -323,12 +323,109 @@ TEST(ContainerTest, TrunkBasic) ASSERT_EQ(t0[v2], 3); } +TEST(ContainerTest, TrunkEachTest) +{ + Trunk t0; + constexpr auto count = 2; + for (auto i = 0; i < count; i++) { + t0.Emplace(i + 1); + } + + int i = 0; + t0.Each([&](auto elem) -> void { + ASSERT_EQ(elem, ++i); + }); + ASSERT_EQ(i, 2); +} + TEST(ContainerTest, TrunkCopyAndMove) { - // TODO + Trunk t0; + t0.Emplace(); + t0.Emplace(); + ASSERT_EQ(t0[0].constructType, ConstructType::cDefault); + ASSERT_EQ(t0[1].constructType, ConstructType::cDefault); + + t0.Emplace(CopyAndMoveTest()); + ASSERT_EQ(t0[2].constructType, ConstructType::cMove); + + CopyAndMoveTest temp0; + t0.Emplace(temp0); + ASSERT_EQ(t0[3].constructType, ConstructType::cCopy); + + // copy assign + Trunk t1; + t1.Emplace(); + t1 = t0; + ASSERT_EQ(t1.Allocated(), 4); + ASSERT_TRUE(t1[0].copyAssigned); + ASSERT_TRUE(!t1[1].copyAssigned && t1[1].constructType == ConstructType::cCopy); + ASSERT_TRUE(!t1[2].copyAssigned && t1[2].constructType == ConstructType::cCopy); + ASSERT_TRUE(!t1[3].copyAssigned && t1[3].constructType == ConstructType::cCopy); + + Trunk t2; + t2.Emplace(); + t2.Emplace(); + t2.Emplace(); + t2.Emplace(); + t2.Emplace(); + t2 = t0; + ASSERT_EQ(t2.Allocated(), 4); + ASSERT_TRUE(t2[0].copyAssigned); + ASSERT_TRUE(t2[0].copyAssigned); + ASSERT_TRUE(t2[0].copyAssigned); + ASSERT_TRUE(t2[0].copyAssigned); + + // move assign + Trunk t3; + t3.Emplace(); + t3 = std::move(t1); + ASSERT_EQ(t3.Allocated(), 4); + ASSERT_TRUE(t3[0].moveAssigned); + ASSERT_TRUE(!t3[1].moveAssigned && t3[1].constructType == ConstructType::cMove); + ASSERT_TRUE(!t3[2].moveAssigned && t3[2].constructType == ConstructType::cMove); + ASSERT_TRUE(!t3[3].moveAssigned && t3[3].constructType == ConstructType::cMove); + + // copy ctor + Trunk t4(t3); + ASSERT_EQ(t4.Allocated(), 4); + ASSERT_TRUE(!t4[0].copyAssigned && t4[0].constructType == ConstructType::cCopy); + ASSERT_TRUE(!t4[1].copyAssigned && t4[1].constructType == ConstructType::cCopy); + ASSERT_TRUE(!t4[2].copyAssigned && t4[2].constructType == ConstructType::cCopy); + ASSERT_TRUE(!t4[3].copyAssigned && t4[3].constructType == ConstructType::cCopy); + + // move ctor + Trunk t5(std::move(t4)); + ASSERT_EQ(t5.Allocated(), 4); + ASSERT_TRUE(!t5[0].moveAssigned && t5[0].constructType == ConstructType::cMove); + ASSERT_TRUE(!t5[1].moveAssigned && t5[1].constructType == ConstructType::cMove); + ASSERT_TRUE(!t5[2].moveAssigned && t5[2].constructType == ConstructType::cMove); + ASSERT_TRUE(!t5[3].moveAssigned && t5[3].constructType == ConstructType::cMove); } -TEST(ContainerTest, TrunkListTest) +TEST(ContainerTest, TrunkListBasic) { - // TODO + TrunkList t0; + const auto i0 = t0.Emplace(1); + t0.Emplace(2); + t0.Emplace(3); + ASSERT_EQ(t0.Allocated(), 3); + ASSERT_EQ(t0.Free(), 1); + ASSERT_EQ(t0.Capacity(), 4); + + t0.Emplace(4); + t0.Emplace(5); + ASSERT_EQ(t0.Allocated(), 5); + ASSERT_EQ(t0.Free(), 3); + ASSERT_EQ(t0.Capacity(), 8); + + t0.Erase(i0); + ASSERT_EQ(t0.Allocated(), 4); + ASSERT_EQ(t0.Free(), 4); + ASSERT_EQ(t0.Capacity(), 8); + + int count = 2; + t0.Each([&](auto elem) -> void { + ASSERT_EQ(elem, count++); + }); } diff --git a/ThirdParty/CMakeLists.txt b/ThirdParty/CMakeLists.txt index 9183d343..6802794a 100644 --- a/ThirdParty/CMakeLists.txt +++ b/ThirdParty/CMakeLists.txt @@ -165,15 +165,6 @@ Add3rdHeaderOnlyPackage( INCLUDE $ ) -# fmt-lib -Add3rdHeaderOnlyPackage( - NAME fmt-lib - PLATFORM All - VERSION 9.1.0 - HASH 09fb58ad10d1071ca8dbe0dc02b64fac6b2f4d4ba626b6d21a67d5b60ffe9f95 - INCLUDE $/include -) - # spirv-cross Add3rdCMakeProject( NAME spirv-cross From 27945758e6a5c7194cd448bb621bd191b8ec6195 Mon Sep 17 00:00:00 2001 From: John Kindem <461425614@qq.com> Date: Mon, 28 Oct 2024 18:58:12 +0800 Subject: [PATCH 06/22] fix: fix serialize stream endian issue refactor: replace fmt::format with std::format --- .../Source/Common/Include/Common/Container.h | 1 + .../Source/Common/Include/Common/Math/Box.h | 2 +- .../Source/Common/Include/Common/Math/Color.h | 4 +- .../Common/Include/Common/Math/Projection.h | 4 +- .../Common/Include/Common/Math/Quaternion.h | 4 +- .../Source/Common/Include/Common/Math/Rect.h | 2 +- .../Common/Include/Common/Math/Sphere.h | 2 +- .../Common/Include/Common/Math/Transform.h | 2 +- .../Common/Include/Common/Serialization.h | 132 ++++++++++++------ Engine/Source/Common/Include/Common/String.h | 6 +- Engine/Source/Common/Test/MathTest.cpp | 52 +++---- .../Source/Common/Test/SerializationTest.cpp | 8 +- Engine/Source/Common/Test/SerializationTest.h | 12 +- Engine/Source/Core/Src/Module.cpp | 2 +- Engine/Source/Mirror/Include/Mirror/Mirror.h | 24 ++-- Engine/Source/Mirror/Src/Mirror.cpp | 2 +- .../Source/Mirror/Test/SerializationTest.cpp | 1 + Engine/Source/Render/Include/Render/Scene.h | 17 ++- Engine/Source/Runtime/Include/Runtime/World.h | 52 ++++--- Engine/Source/Runtime/Src/World.cpp | 22 +-- Tool/MirrorTool/Src/Generator.cpp | 56 ++++---- 21 files changed, 239 insertions(+), 168 deletions(-) diff --git a/Engine/Source/Common/Include/Common/Container.h b/Engine/Source/Common/Include/Common/Container.h index 90979a8a..82e3d098 100644 --- a/Engine/Source/Common/Include/Common/Container.h +++ b/Engine/Source/Common/Include/Common/Container.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include diff --git a/Engine/Source/Common/Include/Common/Math/Box.h b/Engine/Source/Common/Include/Common/Math/Box.h index 72540c80..39e644ce 100644 --- a/Engine/Source/Common/Include/Common/Math/Box.h +++ b/Engine/Source/Common/Include/Common/Math/Box.h @@ -76,7 +76,7 @@ namespace Common { // NOLINT struct StringConverter> { static std::string ToString(const Box& inValue) { - return fmt::format( + return std::format( "{}min={}, max={}{}", "{", StringConverter>::ToString(inValue.min), diff --git a/Engine/Source/Common/Include/Common/Math/Color.h b/Engine/Source/Common/Include/Common/Math/Color.h index ed66412f..0511eaad 100644 --- a/Engine/Source/Common/Include/Common/Math/Color.h +++ b/Engine/Source/Common/Include/Common/Math/Color.h @@ -115,7 +115,7 @@ namespace Common { struct StringConverter { static std::string ToString(const Color& inValue) { - return fmt::format( + return std::format( "{}r={}, g={}, b={}, a={}{}", "{", StringConverter::ToString(inValue.r), @@ -130,7 +130,7 @@ namespace Common { struct StringConverter { static std::string ToString(const LinearColor& inValue) { - return fmt::format( + return std::format( "{}r={}, g={}, b={}, a={}{}", "{", StringConverter::ToString(inValue.r), diff --git a/Engine/Source/Common/Include/Common/Math/Projection.h b/Engine/Source/Common/Include/Common/Math/Projection.h index 553481a8..8a68ead1 100644 --- a/Engine/Source/Common/Include/Common/Math/Projection.h +++ b/Engine/Source/Common/Include/Common/Math/Projection.h @@ -111,7 +111,7 @@ namespace Common { struct StringConverter> { static std::string ToString(const ReversedZOrthogonalProjection& inValue) { - return fmt::format( + return std::format( "{}width={}, height={}, near={}, far={}{}", "{", StringConverter::ToString(inValue.width), @@ -126,7 +126,7 @@ namespace Common { struct StringConverter> { static std::string ToString(const ReversedZPerspectiveProjection& inValue) { - return fmt::format( + return std::format( "{}fov={}, width={}, height={}, near={}, far={}{}", "{", StringConverter::ToString(inValue.fov), diff --git a/Engine/Source/Common/Include/Common/Math/Quaternion.h b/Engine/Source/Common/Include/Common/Math/Quaternion.h index 9def2483..761ed579 100644 --- a/Engine/Source/Common/Include/Common/Math/Quaternion.h +++ b/Engine/Source/Common/Include/Common/Math/Quaternion.h @@ -184,7 +184,7 @@ namespace Common { struct StringConverter> { static std::string ToString(const Angle& inValue) { - return fmt::format("a{}", StringConverter::ToString(inValue.value)); + return std::format("a{}", StringConverter::ToString(inValue.value)); } }; @@ -200,7 +200,7 @@ namespace Common { struct StringConverter> { static std::string ToString(const Quaternion& inValue) { - return fmt::format( + return std::format( "({}, {}, {}, {})", StringConverter::ToString(inValue.w), StringConverter::ToString(inValue.x), diff --git a/Engine/Source/Common/Include/Common/Math/Rect.h b/Engine/Source/Common/Include/Common/Math/Rect.h index 723859b5..170a0d92 100644 --- a/Engine/Source/Common/Include/Common/Math/Rect.h +++ b/Engine/Source/Common/Include/Common/Math/Rect.h @@ -74,7 +74,7 @@ namespace Common { struct StringConverter> { static std::string ToString(const Rect& inValue) { - return fmt::format( + return std::format( "{}min={}, max={}{}", "{", StringConverter>::ToString(inValue.min), diff --git a/Engine/Source/Common/Include/Common/Math/Sphere.h b/Engine/Source/Common/Include/Common/Math/Sphere.h index bdf106ed..da447fb0 100644 --- a/Engine/Source/Common/Include/Common/Math/Sphere.h +++ b/Engine/Source/Common/Include/Common/Math/Sphere.h @@ -62,7 +62,7 @@ namespace Common { struct StringConverter> { static std::string ToString(const Sphere& inValue) { - return fmt::format( + return std::format( "{}center={}, radius={}{}", "{", StringConverter>::ToString(inValue.center), diff --git a/Engine/Source/Common/Include/Common/Math/Transform.h b/Engine/Source/Common/Include/Common/Math/Transform.h index 315095dd..5b991b36 100644 --- a/Engine/Source/Common/Include/Common/Math/Transform.h +++ b/Engine/Source/Common/Include/Common/Math/Transform.h @@ -92,7 +92,7 @@ namespace Common { struct StringConverter> { static std::string ToString(const Transform& inValue) { - return fmt::format( + return std::format( "{}scale={}, rotation={}, translation={}{}", "{", StringConverter>::ToString(inValue.scale), diff --git a/Engine/Source/Common/Include/Common/Serialization.h b/Engine/Source/Common/Include/Common/Serialization.h index 746259ba..38c317d4 100644 --- a/Engine/Source/Common/Include/Common/Serialization.h +++ b/Engine/Source/Common/Include/Common/Serialization.h @@ -30,13 +30,15 @@ namespace Common { NonCopyable(BinarySerializeStream) virtual ~BinarySerializeStream(); - virtual void Write(const void* data, size_t size) = 0; + template void Write(const T& value); virtual void Seek(int64_t offset) = 0; virtual size_t Loc() = 0; virtual std::endian Endian() = 0; protected: BinarySerializeStream(); + + virtual void WriteInternal(const void* data, size_t size) = 0; }; class BinaryDeserializeStream { @@ -44,13 +46,15 @@ namespace Common { NonCopyable(BinaryDeserializeStream); virtual ~BinaryDeserializeStream(); - virtual void Read(void* data, size_t size) = 0; + template void Read(T& value); virtual void Seek(int64_t offset) = 0; virtual size_t Loc() = 0; virtual std::endian Endian() = 0; protected: BinaryDeserializeStream(); + + virtual void ReadInternal(void* data, size_t size) = 0; }; template @@ -59,12 +63,15 @@ namespace Common { NonCopyable(BinaryFileSerializeStream) explicit BinaryFileSerializeStream(const std::string& inFileName); ~BinaryFileSerializeStream() override; - void Write(const void* data, size_t size) override; + void Seek(int64_t offset) override; size_t Loc() override; std::endian Endian() override; void Close(); + protected: + void WriteInternal(const void* data, size_t size) override; + private: std::ofstream file; }; @@ -75,12 +82,15 @@ namespace Common { NonCopyable(BinaryFileDeserializeStream) explicit BinaryFileDeserializeStream(const std::string& inFileName); ~BinaryFileDeserializeStream() override; - void Read(void* data, size_t size) override; + void Seek(int64_t offset) override; size_t Loc() override; std::endian Endian() override; void Close(); + protected: + void ReadInternal(void* data, size_t size) override; + private: std::ifstream file; size_t fileSize; @@ -92,11 +102,14 @@ namespace Common { NonCopyable(MemorySerializeStream) explicit MemorySerializeStream(std::vector& inBytes, size_t pointerBegin = 0); ~MemorySerializeStream() override; - void Write(const void* data, size_t size) override; + void Seek(int64_t offset) override; size_t Loc() override; std::endian Endian() override; + protected: + void WriteInternal(const void* data, size_t size) override; + private: size_t pointer; std::vector& bytes; @@ -108,11 +121,13 @@ namespace Common { NonCopyable(MemoryDeserializeStream) explicit MemoryDeserializeStream(const std::vector& inBytes, size_t pointerBegin = 0); ~MemoryDeserializeStream() override; - void Read(void* data, size_t size) override; void Seek(int64_t offset) override; std::endian Endian() override; size_t Loc() override; + protected: + void ReadInternal(void* data, size_t size) override; + private: size_t pointer; const std::vector& bytes; @@ -152,13 +167,13 @@ namespace Common { \ static size_t Serialize(BinarySerializeStream& stream, const typeName& value) \ { \ - stream.Write(&value, sizeof(typeName)); \ + stream.Write(value); \ return sizeof(typeName); \ } \ \ static size_t Deserialize(BinaryDeserializeStream& stream, typeName& value) \ { \ - stream.Read(&value, sizeof(typeName)); \ + stream.Read(value); \ return sizeof(typeName); \ } \ }; \ @@ -186,6 +201,26 @@ namespace Common::Internal { } namespace Common { + template + void BinarySerializeStream::Write(const T& value) + { + if (std::endian::native == Endian()) { + WriteInternal(&value, sizeof(T)); + } else { + const auto swapped = Internal::SwapEndian(&value, sizeof(T)); + WriteInternal(reinterpret_cast(swapped.data()), static_cast(swapped.size())); + } + } + + template + void BinaryDeserializeStream::Read(T& value) + { + ReadInternal(&value, sizeof(T)); + if (std::endian::native != Endian()) { + Internal::SwapEndianInplace(&value, sizeof(T)); + } + } + template BinaryFileSerializeStream::BinaryFileSerializeStream(const std::string& inFileName) { @@ -203,14 +238,9 @@ namespace Common { } template - void BinaryFileSerializeStream::Write(const void* data, const size_t size) + void BinaryFileSerializeStream::WriteInternal(const void* data, const size_t size) { - if (std::endian::native == E) { - file.write(static_cast(data), static_cast(size)); - } else { - const auto swapped = Internal::SwapEndian(data, size); - file.write(reinterpret_cast(swapped.data()), static_cast(swapped.size())); - } + file.write(static_cast(data), static_cast(size)); } template @@ -260,13 +290,10 @@ namespace Common { } template - void BinaryFileDeserializeStream::Read(void* data, const size_t size) + void BinaryFileDeserializeStream::ReadInternal(void* data, const size_t size) { Assert(static_cast(file.tellg()) + size <= fileSize); file.read(static_cast(data), static_cast(size)); - if (std::endian::native != E) { - Internal::SwapEndianInplace(data, size); - } } template @@ -312,7 +339,7 @@ namespace Common { MemorySerializeStream::~MemorySerializeStream() = default; template - void MemorySerializeStream::Write(const void* data, const size_t size) + void MemorySerializeStream::WriteInternal(const void* data, const size_t size) { const auto newPointer = pointer + size; if (newPointer > bytes.size()) { @@ -321,12 +348,7 @@ namespace Common { } bytes.resize(newPointer); } - if (std::endian::native == E) { - memcpy(bytes.data() + pointer, data, size); - } else { - const auto swaped = Internal::SwapEndian(data, size); - memcpy(bytes.data() + pointer, swaped.data(), swaped.size()); - } + memcpy(bytes.data() + pointer, data, size); pointer = newPointer; } @@ -360,14 +382,11 @@ namespace Common { MemoryDeserializeStream::~MemoryDeserializeStream() = default; template - void MemoryDeserializeStream::Read(void* data, const size_t size) + void MemoryDeserializeStream::ReadInternal(void* data, const size_t size) { const auto newPointer = pointer + size; Assert(newPointer <= bytes.size()); memcpy(data, bytes.data() + pointer, size); - if (std::endian::native != E) { - Internal::SwapEndianInplace(data, size); - } pointer = newPointer; } @@ -436,6 +455,23 @@ namespace Common { struct Header { size_t typeId; size_t contentSize; + + void Serialize(BinarySerializeStream& stream) const + { + stream.Write(static_cast(typeId)); + stream.Write(static_cast(contentSize)); + } + + void Deserialize(BinaryDeserializeStream& stream) + { + uint64_t tempTypeId; + stream.Read(tempTypeId); + typeId = static_cast(tempTypeId); + + uint64_t tempContentSize; + stream.Read(tempContentSize); + contentSize = static_cast(tempContentSize); + } }; static size_t Serialize(BinarySerializeStream& stream, const T& value) @@ -446,7 +482,7 @@ namespace Common { stream.Seek(sizeof(Header)); header.contentSize = Serializer::Serialize(stream, value); stream.Seek(-static_cast(sizeof(Header)) - static_cast(header.contentSize)); - stream.Write(&header, sizeof(Header)); + header.Serialize(stream); stream.Seek(header.contentSize); return sizeof(Header) + header.contentSize; } @@ -454,7 +490,7 @@ namespace Common { static std::pair Deserialize(BinaryDeserializeStream& stream, T& value) { Header header {}; - stream.Read(&header, sizeof(Header)); + header.Deserialize(stream); if (header.typeId != Serializer::typeId) { stream.Seek(header.contentSize); @@ -493,7 +529,11 @@ namespace Common { const uint64_t size = value.size(); serialized += Serializer::Serialize(stream, size); - stream.Write(value.data(), value.size()); + const auto* data = reinterpret_cast(value.data()); + for (auto i = 0; i < size; i++) { + stream.Write(data[i]); + } + serialized += size; return serialized; } @@ -506,7 +546,11 @@ namespace Common { deserialized += Serializer::Deserialize(stream, size); value.resize(size); - stream.Read(value.data(), size); + auto* data = reinterpret_cast(value.data()); + for (auto i = 0; i < size; i++) { + stream.Read(data[i]); + } + deserialized += size; return deserialized; } @@ -520,11 +564,15 @@ namespace Common { { size_t serialized = 0; - const uint64_t size = value.size() * sizeof(std::wstring::value_type); + const uint64_t size = value.size(); serialized += Serializer::Serialize(stream, size); - stream.Write(value.data(), size); - serialized += size; + const auto* data = reinterpret_cast(value.data()); + for (auto i = 0; i < size; i++) { + stream.Write(data[i]); + } + + serialized += size * sizeof(std::wstring::value_type); return serialized; } @@ -535,9 +583,13 @@ namespace Common { uint64_t size; deserialized += Serializer::Deserialize(stream, size); - value.resize(size / sizeof(std::wstring::value_type)); - stream.Read(value.data(), size); - deserialized += size; + value.resize(size); + auto* data = reinterpret_cast(value.data()); + for (auto i = 0; i < size; i++) { + stream.Read(data[i]); + } + + deserialized += size * sizeof(std::wstring::value_type); return deserialized; } }; diff --git a/Engine/Source/Common/Include/Common/String.h b/Engine/Source/Common/Include/Common/String.h index 22d42e0c..a67d3fdb 100644 --- a/Engine/Source/Common/Include/Common/String.h +++ b/Engine/Source/Common/Include/Common/String.h @@ -15,9 +15,7 @@ #include #include #include - -#define FMT_HEADER_ONLY 1 -#include +#include #include #include @@ -95,7 +93,7 @@ namespace Common { struct StringConverter> { static std::string ToString(const std::pair& inValue) { - return fmt::format( + return std::format( "{}: {}", StringConverter::ToString(inValue.first), StringConverter::ToString(inValue.second)); diff --git a/Engine/Source/Common/Test/MathTest.cpp b/Engine/Source/Common/Test/MathTest.cpp index bc571298..e66d9634 100644 --- a/Engine/Source/Common/Test/MathTest.cpp +++ b/Engine/Source/Common/Test/MathTest.cpp @@ -674,27 +674,27 @@ TEST(MathTest, ToStringTest) // mat ASSERT_EQ( ToString(HMat2x3(2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f)), - fmt::format("({}, {}, {}, {}, {}, {})", + std::format("({}, {}, {}, {}, {}, {})", std::to_string(2.0f), std::to_string(3.0f), std::to_string(4.0f), std::to_string(5.0f), std::to_string(6.0f), std::to_string(7.0f))); // angle/radian - ASSERT_EQ(ToString(FAngle(75.0f)), fmt::format("a{}", std::to_string(75.0f))); + ASSERT_EQ(ToString(FAngle(75.0f)), std::format("a{}", std::to_string(75.0f))); ASSERT_EQ(ToString(FRadian(1.5f * pi)), std::to_string(1.5f * pi)); // quaternion ASSERT_EQ( ToString(FQuat(1.0f, 0.1f, 0.2f, 0.5f)), - fmt::format("({}, {}, {}, {})", + std::format("({}, {}, {}, {})", std::to_string(1.0f), std::to_string(0.1f), std::to_string(0.2f), std::to_string(0.5f))); // color ASSERT_EQ( ToString(Color(1, 2, 3, 1)), - fmt::format("{}r={}, g={}, b={}, a={}{}", "{", 1, 2, 3, 1, "}")); + std::format("{}r={}, g={}, b={}, a={}{}", "{", 1, 2, 3, 1, "}")); ASSERT_EQ( ToString(LinearColor(1.0f, 0.5f, 0.2f, 1.0f)), - fmt::format("{}r={}, g={}, b={}, a={}{}", + std::format("{}r={}, g={}, b={}, a={}{}", "{", std::to_string(1.0f), std::to_string(0.5f), std::to_string(0.2f), std::to_string(1.0f), @@ -703,7 +703,7 @@ TEST(MathTest, ToStringTest) // react ASSERT_EQ( ToString(FRect(1.0f, 2.0f, 3.0f, 4.0f)), - fmt::format("{}min=({}, {}), max=({}, {}){}", + std::format("{}min=({}, {}), max=({}, {}){}", "{", std::to_string(1.0f), std::to_string(2.0f), std::to_string(3.0f), std::to_string(4.0f), @@ -712,7 +712,7 @@ TEST(MathTest, ToStringTest) // box ASSERT_EQ( ToString(FBox(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f)), - fmt::format("{}min=({}, {}, {}), max=({}, {}, {}){}", + std::format("{}min=({}, {}, {}), max=({}, {}, {}){}", "{", std::to_string(1.0f), std::to_string(2.0f), std::to_string(3.0f), std::to_string(4.0f), std::to_string(5.0f), std::to_string(6.0f), @@ -721,7 +721,7 @@ TEST(MathTest, ToStringTest) // sphere ASSERT_EQ( ToString(FSphere(1.0f, 2.0f, 3.0f, 1.0f)), - fmt::format("{}center=({}, {}, {}), radius={}{}", + std::format("{}center=({}, {}, {}), radius={}{}", "{", std::to_string(1.0f), std::to_string(2.0f), std::to_string(3.0f), std::to_string(1.0f), "}")); @@ -729,7 +729,7 @@ TEST(MathTest, ToStringTest) // transform ASSERT_EQ( ToString(FTransform(FVec3(2.0f, 2.0f, 2.0f), FQuat(0.5f, 0.2f, 0.1f, 0.3f), FVec3(1.0f, 2.0f, 3.0f))), - fmt::format("{}scale=({}, {}, {}), rotation=({}, {}, {}, {}), translation=({}, {}, {}){}", + std::format("{}scale=({}, {}, {}), rotation=({}, {}, {}, {}), translation=({}, {}, {}){}", "{", std::to_string(2.0f), std::to_string(2.0f), std::to_string(2.0f), std::to_string(0.5f), std::to_string(0.2f), std::to_string(0.1f), std::to_string(0.3f), @@ -739,7 +739,7 @@ TEST(MathTest, ToStringTest) // view transform ASSERT_EQ( ToString(FViewTransform(FQuat(0.5f, 0.2f, 0.1f, 0.3f), FVec3(1.0f, 2.0f, 3.0f))), - fmt::format("{}scale=({}, {}, {}), rotation=({}, {}, {}, {}), translation=({}, {}, {}){}", + std::format("{}scale=({}, {}, {}), rotation=({}, {}, {}, {}), translation=({}, {}, {}){}", "{", std::to_string(1.0f), std::to_string(1.0f), std::to_string(1.0f), std::to_string(0.5f), std::to_string(0.2f), std::to_string(0.1f), std::to_string(0.3f), @@ -749,13 +749,13 @@ TEST(MathTest, ToStringTest) // projection ASSERT_EQ( ToString(FReversedZOrthoProjection(1024.0f, 768.0f, 1.0f, 500.0f)), - fmt::format("{}width={}, height={}, near={}, far={}{}", + std::format("{}width={}, height={}, near={}, far={}{}", "{", std::to_string(1024.0f), std::to_string(768.0f), std::to_string(1.0f), std::to_string(500.0f), "}")); ASSERT_EQ( ToString(FReversedZPerspectiveProjection(90.0f, 1024.0f, 768.0f, 1.0f, 500.0f)), - fmt::format("{}fov={}, width={}, height={}, near={}, far={}{}", + std::format("{}fov={}, width={}, height={}, near={}, far={}{}", "{", std::to_string(90.0f), std::to_string(1024.0f), std::to_string(768.0f), std::to_string(1.0f), std::to_string(500.0f), "}")); @@ -767,22 +767,22 @@ TEST(MathTest, JsonSerializationTest) PerformJsonSerializationTest(HFloat(1.0f), FltToJson(1.0f)); // vec - PerformJsonSerializationTest(FVec1(1.0f), fmt::format("[{}]", FltToJson(1.0f))); - PerformJsonSerializationTest(HVec2(2.0f, 3.0f), fmt::format("[{},{}]", FltToJson(2.0f), FltToJson(3.0f))); + PerformJsonSerializationTest(FVec1(1.0f), std::format("[{}]", FltToJson(1.0f))); + PerformJsonSerializationTest(HVec2(2.0f, 3.0f), std::format("[{},{}]", FltToJson(2.0f), FltToJson(3.0f))); PerformJsonSerializationTest(IVec3(1, 2, 3), "[1,2,3]"); PerformJsonSerializationTest(UVec4(1, 2, 3, 4), "[1,2,3,4]"); // mat - PerformJsonSerializationTest(FMat1x1(1.0f), fmt::format("[{}]", FltToJson(1.0f))); + PerformJsonSerializationTest(FMat1x1(1.0f), std::format("[{}]", FltToJson(1.0f))); PerformJsonSerializationTest( HMat2x3(2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f), - fmt::format("[{},{},{},{},{},{}]", FltToJson(2.0f), FltToJson(3.0f), FltToJson(4.0f), FltToJson(5.0f), FltToJson(6.0f), FltToJson(7.0f))); + std::format("[{},{},{},{},{},{}]", FltToJson(2.0f), FltToJson(3.0f), FltToJson(4.0f), FltToJson(5.0f), FltToJson(6.0f), FltToJson(7.0f))); PerformJsonSerializationTest( IMat3x4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12), "[1,2,3,4,5,6,7,8,9,10,11,12]"); PerformJsonSerializationTest( FMat4x4(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f), - fmt::format("[{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}]", + std::format("[{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}]", FltToJson(1.0f), FltToJson(2.0f), FltToJson(3.0f), FltToJson(4.0f), FltToJson(5.0f), FltToJson(6.0f), FltToJson(7.0f), FltToJson(8.0f), FltToJson(9.0f), FltToJson(10.0f), FltToJson(11.0f), FltToJson(12.0f), @@ -793,13 +793,13 @@ TEST(MathTest, JsonSerializationTest) PerformJsonSerializationTest(FRadian(1.0f), FltToJson(1.0f)); // quaternion - PerformJsonSerializationTest(FQuat(1.0f, 0.1f, 0.2f, 0.5f), fmt::format("[{},{},{},{}]", FltToJson(1.0f), FltToJson(0.1f), FltToJson(0.2f), FltToJson(0.5f))); + PerformJsonSerializationTest(FQuat(1.0f, 0.1f, 0.2f, 0.5f), std::format("[{},{},{},{}]", FltToJson(1.0f), FltToJson(0.1f), FltToJson(0.2f), FltToJson(0.5f))); // color PerformJsonSerializationTest(Color(1, 2, 3, 1), R"({"r":1,"g":2,"b":3,"a":1})"); PerformJsonSerializationTest( LinearColor(1.0f, 0.5f, 0.2f, 1.0f), - fmt::format(R"({}"r":{},"g":{},"b":{},"a":{}{})", + std::format(R"({}"r":{},"g":{},"b":{},"a":{}{})", "{", FltToJson(1.0f), FltToJson(0.5f), FltToJson(0.2f), FltToJson(1.0f), "}")); @@ -807,7 +807,7 @@ TEST(MathTest, JsonSerializationTest) // rect PerformJsonSerializationTest( FRect(1.0f, 2.0f, 3.0f, 4.0f), - fmt::format(R"({}"min":[{},{}],"max":[{},{}]{})", + std::format(R"({}"min":[{},{}],"max":[{},{}]{})", "{", FltToJson(1.0f), FltToJson(2.0f), FltToJson(3.0f), FltToJson(4.0f), @@ -816,7 +816,7 @@ TEST(MathTest, JsonSerializationTest) // box PerformJsonSerializationTest( FBox(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f), - fmt::format(R"({}"min":[{},{},{}],"max":[{},{},{}]{})", + std::format(R"({}"min":[{},{},{}],"max":[{},{},{}]{})", "{", FltToJson(1.0f), FltToJson(2.0f), FltToJson(3.0f), FltToJson(4.0f), FltToJson(5.0f), FltToJson(6.0f), @@ -825,7 +825,7 @@ TEST(MathTest, JsonSerializationTest) // sphere PerformJsonSerializationTest( FSphere(1.0f, 2.0f, 3.0f, 1.0f), - fmt::format(R"({}"center":[{},{},{}],"radius":{}{})", + std::format(R"({}"center":[{},{},{}],"radius":{}{})", "{", FltToJson(1.0f), FltToJson(2.0f), FltToJson(3.0f), FltToJson(1.0f), @@ -835,7 +835,7 @@ TEST(MathTest, JsonSerializationTest) const FTransform transform(FVec3(2.0f, 2.0f, 2.0f), FQuat(1.0f, 0.2f, 0.3f, 0.4f), FVec3(1.0f, 2.0f, 3.0f)); PerformJsonSerializationTest( transform, - fmt::format(R"({}"scale":[{},{},{}],"rotation":[{},{},{},{}],"translation":[{},{},{}]{})", + std::format(R"({}"scale":[{},{},{}],"rotation":[{},{},{},{}],"translation":[{},{},{}]{})", "{", FltToJson(2.0f), FltToJson(2.0f), FltToJson(2.0f), FltToJson(1.0f), FltToJson(0.2f), FltToJson(0.3f), FltToJson(0.4f), @@ -845,7 +845,7 @@ TEST(MathTest, JsonSerializationTest) // view transform PerformJsonSerializationTest( FViewTransform(transform), - fmt::format(R"({}"scale":[{},{},{}],"rotation":[{},{},{},{}],"translation":[{},{},{}]{})", + std::format(R"({}"scale":[{},{},{}],"rotation":[{},{},{},{}],"translation":[{},{},{}]{})", "{", FltToJson(2.0f), FltToJson(2.0f), FltToJson(2.0f), FltToJson(1.0f), FltToJson(0.2f), FltToJson(0.3f), FltToJson(0.4f), @@ -855,13 +855,13 @@ TEST(MathTest, JsonSerializationTest) // projection PerformJsonSerializationTest( FReversedZOrthoProjection(512.0f, 1024.0f, 1.0f), - fmt::format(R"({}"width":{},"height":{},"near":{},"far":{}{})", + std::format(R"({}"width":{},"height":{},"near":{},"far":{}{})", "{", FltToJson(512.0f), FltToJson(1024.0f), FltToJson(1.0f), "null", "}")); PerformJsonSerializationTest( FReversedZPerspectiveProjection(90.0f, 512.0f, 1024.0f, 1.0f, 500.0f), - fmt::format(R"({}"fov":{},"width":{},"height":{},"near":{},"far":{}{})", + std::format(R"({}"fov":{},"width":{},"height":{},"near":{},"far":{}{})", "{", FltToJson(90.0f), FltToJson(512.0f), FltToJson(1024.0f), FltToJson(1.0f), FltToJson(500.0f), "}")); diff --git a/Engine/Source/Common/Test/SerializationTest.cpp b/Engine/Source/Common/Test/SerializationTest.cpp index 55f9d019..32bd7819 100644 --- a/Engine/Source/Common/Test/SerializationTest.cpp +++ b/Engine/Source/Common/Test/SerializationTest.cpp @@ -19,7 +19,7 @@ TEST(SerializationTest, FileStreamTest) BinaryFileSerializeStream stream(fileName.string()); stream.Seek(3); - stream.Write(&value, sizeof(uint32_t)); + stream.Write(value); } { @@ -27,7 +27,7 @@ TEST(SerializationTest, FileStreamTest) BinaryFileDeserializeStream stream(fileName.string()); stream.Seek(3); - stream.Read(&value, sizeof(uint32_t)); + stream.Read(value); ASSERT_EQ(value, 5); } } @@ -42,14 +42,14 @@ TEST(SerializationTest, ByteStreamTest) const uint32_t value = 5; // NOLINT MemorySerializeStream stream(memory); stream.Seek(3); - stream.Write(&value, sizeof(uint32_t)); + stream.Write(value); } { uint32_t value; MemoryDeserializeStream stream(memory); stream.Seek(3); - stream.Read(&value, sizeof(uint32_t)); + stream.Read(value); ASSERT_EQ(value, 5); } } diff --git a/Engine/Source/Common/Test/SerializationTest.h b/Engine/Source/Common/Test/SerializationTest.h index b0eca051..120a022d 100644 --- a/Engine/Source/Common/Test/SerializationTest.h +++ b/Engine/Source/Common/Test/SerializationTest.h @@ -25,8 +25,8 @@ inline std::string FltToJson(float value) template void PerformTypedSerializationTestWithStream( - const std::function()>& createSerializeStream, - const std::function()>& createDeserializeStream, + const std::function()>& createSerializeStream, + const std::function()>& createDeserializeStream, const T& inValue) { { @@ -50,14 +50,14 @@ void PerformTypedSerializationTestWithEndian(const T& inValue) std::filesystem::create_directories(fileName.parent_path()); PerformTypedSerializationTestWithStream( - []() -> Common::UniqueRef { return { new BinaryFileSerializeStream(fileName.string()) }; }, - []() -> Common::UniqueRef { return { new BinaryFileDeserializeStream(fileName.string()) }; }, + []() -> Common::UniqueRef { return { new Common::BinaryFileSerializeStream(fileName.string()) }; }, + []() -> Common::UniqueRef { return { new Common::BinaryFileDeserializeStream(fileName.string()) }; }, inValue); std::vector buffer; PerformTypedSerializationTestWithStream( - [&]() -> Common::UniqueRef { return { new MemorySerializeStream(buffer) }; }, - [&]() -> Common::UniqueRef { return { new MemoryDeserializeStream(buffer) }; }, + [&]() -> Common::UniqueRef { return { new Common::MemorySerializeStream(buffer) }; }, + [&]() -> Common::UniqueRef { return { new Common::MemoryDeserializeStream(buffer) }; }, inValue); } diff --git a/Engine/Source/Core/Src/Module.cpp b/Engine/Source/Core/Src/Module.cpp index dee1a5e1..19d70606 100644 --- a/Engine/Source/Core/Src/Module.cpp +++ b/Engine/Source/Core/Src/Module.cpp @@ -151,7 +151,7 @@ namespace Core { if (auto extension = path.extension().string(); (extension == ".dll" || extension == ".so" || extension == ".dylib") - && (fileName == fmt::format("{}{}", moduleName, extension) || fileName == fmt::format("lib{}{}", moduleName, extension))) + && (fileName == std::format("{}{}", moduleName, extension) || fileName == std::format("lib{}{}", moduleName, extension))) { return path.string(); } diff --git a/Engine/Source/Mirror/Include/Mirror/Mirror.h b/Engine/Source/Mirror/Include/Mirror/Mirror.h index bee3ac9b..282e466d 100644 --- a/Engine/Source/Mirror/Include/Mirror/Mirror.h +++ b/Engine/Source/Mirror/Include/Mirror/Mirror.h @@ -1802,7 +1802,7 @@ namespace Common { // NOLINT stream << "{ "; auto count = 0; for (const auto& [id, var] : memberVariables) { - stream << fmt::format("{}: {}", id.name, var.GetDyn(argument).ToString()); + stream << std::format("{}: {}", id.name, var.GetDyn(argument).ToString()); if (count++ != memberVariables.size() - 1) { stream << ", "; } @@ -1823,7 +1823,7 @@ namespace Common { // NOLINT { if (const Mirror::Enum* metaEnum = Mirror::Enum::Find(); metaEnum != nullptr) { - return fmt::format( + return std::format( "{}::{}", StringConverter::ToString(metaEnum->GetName()), StringConverter::ToString(metaEnum->GetValue(inValue).GetName())); @@ -1843,7 +1843,7 @@ namespace Common { // NOLINT ownerName = inValue->GetOwnerName(); name = inValue->GetName(); } - return fmt::format("{}{}{}", ownerName, ownerName.empty() ? "" : ":", name); + return std::format("{}{}{}", ownerName, ownerName.empty() ? "" : ":", name); } }; @@ -1857,7 +1857,7 @@ namespace Common { // NOLINT ownerName = inValue->GetOwnerName(); name = inValue->GetName(); } - return fmt::format("{}{}{}{}", ownerName, ownerName.empty() ? "" : ":", name, name.empty() ? "" : "()"); + return std::format("{}{}{}{}", ownerName, ownerName.empty() ? "" : ":", name, name.empty() ? "" : "()"); } }; @@ -1871,7 +1871,7 @@ namespace Common { // NOLINT ownerName = inValue->GetOwnerName(); name = inValue->GetName(); } - return fmt::format("{}::{}({})", ownerName, StringUtils::AfterLast(ownerName, "::"), name); + return std::format("{}::{}({})", ownerName, StringUtils::AfterLast(ownerName, "::"), name); } }; @@ -1880,7 +1880,7 @@ namespace Common { // NOLINT static std::string ToString(const Mirror::Destructor* inValue) { const std::string ownerName = inValue != nullptr ? inValue->GetOwnerName() : ""; - return fmt::format("{}::~{}()", ownerName, StringUtils::AfterLast(ownerName, "::")); + return std::format("{}::~{}()", ownerName, StringUtils::AfterLast(ownerName, "::")); } }; @@ -1894,7 +1894,7 @@ namespace Common { // NOLINT ownerName = inValue->GetOwnerName(); name = inValue->GetName(); } - return fmt::format("{}::{}", ownerName, name); + return std::format("{}::{}", ownerName, name); } }; @@ -1908,7 +1908,7 @@ namespace Common { // NOLINT ownerName = inValue->GetOwnerName(); name = inValue->GetName(); } - return fmt::format("{}::{}()", ownerName, name); + return std::format("{}::{}()", ownerName, name); } }; @@ -1930,7 +1930,7 @@ namespace Common { // NOLINT ownerName = inValue->GetOwnerName(); name = inValue->GetName(); } - return fmt::format("{}::{}", ownerName, name); + return std::format("{}::{}", ownerName, name); } }; @@ -1987,7 +1987,7 @@ namespace Mirror { if constexpr (std::is_copy_constructible_v) { new(inThis) T(*static_cast(inOther)); } else { - QuickFailWithReason(fmt::format("type {} is no support copy construct", GetTypeInfo()->name)); + QuickFailWithReason(std::format("type {} is no support copy construct", GetTypeInfo()->name)); } } @@ -1997,7 +1997,7 @@ namespace Mirror { if constexpr (std::is_move_constructible_v) { new(inThis) T(std::move(*static_cast(inOther))); } else { - QuickFailWithReason(fmt::format("type {} is no support move construct", GetTypeInfo()->name)); + QuickFailWithReason(std::format("type {} is no support move construct", GetTypeInfo()->name)); } } @@ -2007,7 +2007,7 @@ namespace Mirror { if constexpr (Common::EqualComparable) { return *static_cast(inThis) == *static_cast(inOther); } else { - QuickFailWithReason(fmt::format("type {} is no support equal compare", GetTypeInfo()->name)); + QuickFailWithReason(std::format("type {} is no support equal compare", GetTypeInfo()->name)); return false; } } diff --git a/Engine/Source/Mirror/Src/Mirror.cpp b/Engine/Source/Mirror/Src/Mirror.cpp index 1ec9d8d2..eeedf037 100644 --- a/Engine/Source/Mirror/Src/Mirror.cpp +++ b/Engine/Source/Mirror/Src/Mirror.cpp @@ -759,7 +759,7 @@ namespace Mirror { std::stringstream stream; uint32_t count = 0; for (const auto& [key, value] : metas) { - stream << fmt::format("{}={}", key.name, value); + stream << std::format("{}={}", key.name, value); count++; if (count != metas.size()) { diff --git a/Engine/Source/Mirror/Test/SerializationTest.cpp b/Engine/Source/Mirror/Test/SerializationTest.cpp index 1c61c895..530c8b2e 100644 --- a/Engine/Source/Mirror/Test/SerializationTest.cpp +++ b/Engine/Source/Mirror/Test/SerializationTest.cpp @@ -10,6 +10,7 @@ #include #include #include +using namespace Mirror; int ga = 1; float gb = 2.0f; diff --git a/Engine/Source/Render/Include/Render/Scene.h b/Engine/Source/Render/Include/Render/Scene.h index 3b9ed8d6..d34a69f2 100644 --- a/Engine/Source/Render/Include/Render/Scene.h +++ b/Engine/Source/Render/Include/Render/Scene.h @@ -4,17 +4,28 @@ #pragma once -#include +#include +#include namespace Render { + template using SPPool = Common::TrunkList; + template using SPHandle = typename SPPool::Handle; + template using SPPatcher = std::function; + + using LightSPPool = SPPool; + using LightSPH = SPHandle; + using LightSPPatcher = SPPatcher; + class Scene final { public: Scene(); ~Scene(); - // TODO AddLight/RemoveLight/PatchLight + LightSPH AddLight(const LightSceneProxy& inLight); + void RemoveLight(const LightSPH& inHandle); + void PatchLight(const LightSPH& inHandle, const LightSPPatcher& inPatcher); private: - // TODO use object tool + LightSPPool lights; }; } diff --git a/Engine/Source/Runtime/Include/Runtime/World.h b/Engine/Source/Runtime/Include/Runtime/World.h index a11f6df7..9f682de1 100644 --- a/Engine/Source/Runtime/Include/Runtime/World.h +++ b/Engine/Source/Runtime/Include/Runtime/World.h @@ -89,6 +89,10 @@ namespace Runtime { entt::observer observer; }; + struct EntityCompRegistry { + entt::registry native; + }; + class RUNTIME_API Commands { public: ~Commands(); @@ -119,9 +123,15 @@ namespace Runtime { friend class World; friend class Observer; - explicit Commands(entt::registry& inRegistry); + explicit Commands(EntityCompRegistry& inRegistry); - entt::registry& registry; + EntityCompRegistry& registry; + }; + + struct SystemRegistry { + std::unordered_map systems; + std::vector> systemsGraph; + std::vector systemsInBarriers; }; // world is fully runtime structure, we use level to perform persist storage @@ -156,10 +166,8 @@ namespace Runtime { bool setup; bool playing; std::string name; - entt::registry registry; - std::unordered_map systems; - std::vector> systemsGraph; - std::vector systemsInBarriers; + EntityCompRegistry entityCompRegistry; + SystemRegistry systemRegistry; }; } @@ -312,62 +320,62 @@ namespace Runtime { template bool Commands::HasState() const { - return registry.try_ctx() != nullptr; + return registry.native.try_ctx() != nullptr; } template const S& Commands::EmplaceState(Args&&... inArgs) { - return registry.set(std::forward(inArgs)...); + return registry.native.set(std::forward(inArgs)...); } template const S* Commands::FindState() const { - return registry.try_ctx(); + return registry.native.try_ctx(); } template const S& Commands::GetState() const { - return registry.ctx(); + return registry.native.ctx(); } template void Commands::RemoveState() // NOLINT { - registry.unset(); + registry.native.unset(); } template void Commands::PatchState(F&& inFunc) { Assert(HasState()); - inFunc(registry.ctx()); + inFunc(registry.native.ctx()); } template bool Commands::HasComp(Entity inEntity) const { - return registry.try_get(inEntity) != nullptr; + return registry.native.try_get(inEntity) != nullptr; } template const C& Commands::EmplaceComp(Entity inEntity, Args&&... inArgs) { - return registry.emplace(inEntity, std::forward(inArgs)...); + return registry.native.emplace(inEntity, std::forward(inArgs)...); } template const C* Commands::FindComp(Entity inEntity) const { - return registry.try_get(inEntity); + return registry.native.try_get(inEntity); } template const C& Commands::GetComp(Entity inEntity) const { - auto* result = registry.try_get(inEntity); + auto* result = registry.native.try_get(inEntity); Assert(result != nullptr); return *result; } @@ -375,25 +383,25 @@ namespace Runtime { template void Commands::RemoveComp(Entity inEntity) // NOLINT { - registry.erase(inEntity); + registry.native.erase(inEntity); } template void Commands::PatchComp(Entity inEntity, F&& inFunc) { - registry.patch(inEntity, std::forward(inFunc)); + registry.native.patch(inEntity, std::forward(inFunc)); } template auto Commands::View(Exclude) { - return CompView, C...>(registry.view(entt::exclude_t {})); + return CompView, C...>(registry.native.view(entt::exclude_t {})); } template auto Commands::View(Exclude) const { - return CompView, std::add_const_t...>(registry.view(entt::exclude_t {})); + return CompView, std::add_const_t...>(registry.native.view(entt::exclude_t {})); } template @@ -406,7 +414,7 @@ namespace Runtime { void World::AddSystem(Args&&... inSystemArgs) { SystemClass clazz = Internal::GetClassChecked(); - systems.emplace(clazz, System(std::forward(inSystemArgs)...)); - systemsInBarriers.emplace_back(clazz); + systemRegistry.systems.emplace(clazz, System(std::forward(inSystemArgs)...)); + systemRegistry.systemsInBarriers.emplace_back(clazz); } }; diff --git a/Engine/Source/Runtime/Src/World.cpp b/Engine/Source/Runtime/Src/World.cpp index ad36bde5..3baa5411 100644 --- a/Engine/Source/Runtime/Src/World.cpp +++ b/Engine/Source/Runtime/Src/World.cpp @@ -46,7 +46,7 @@ namespace Runtime { return End(); } - Commands::Commands(entt::registry& inRegistry) + Commands::Commands(EntityCompRegistry& inRegistry) : registry(inRegistry) { } @@ -55,17 +55,17 @@ namespace Runtime { Entity Commands::CreateEntity() // NOLINT { - return registry.create(); + return registry.native.create(); } void Commands::DestroyEntity(Entity inEntity) // NOLINT { - registry.destroy(inEntity); + registry.native.destroy(inEntity); } bool Commands::HasEntity(Entity inEntity) const { - return registry.valid(inEntity); + return registry.native.valid(inEntity); } World::World(std::string inName) @@ -83,17 +83,17 @@ namespace Runtime { void World::AddBarrier() { - systemsGraph.emplace_back(systemsInBarriers); - systemsInBarriers.clear(); + systemRegistry.systemsGraph.emplace_back(systemRegistry.systemsInBarriers); + systemRegistry.systemsInBarriers.clear(); } void World::Play() { - Assert(!setup && systemsInBarriers.empty()); + Assert(!setup && systemRegistry.systemsInBarriers.empty()); setup = true; playing = true; ExecuteSystemGraph([&](const System& inSystem) -> void { - Commands commands(registry); + Commands commands(entityCompRegistry); inSystem.Setup(commands); }); } @@ -121,7 +121,7 @@ namespace Runtime { { Assert(setup && playing); ExecuteSystemGraph([&](const System& inSystem) -> void { - Commands commands(registry); + Commands commands(entityCompRegistry); inSystem.Tick(commands, inFrameTimeMs); }); } @@ -144,11 +144,11 @@ namespace Runtime { }; tf::Task barrierTask = newBarrierTask(); - for (const auto& systemSet : systemsGraph) { + for (const auto& systemSet : systemRegistry.systemsGraph) { std::vector tasks; for (const auto& systemClass : systemSet) { auto& addedTask = tasks.emplace_back(taskFlow.emplace([&]() -> void { - inOp(systems.at(systemClass).As()); + inOp(systemRegistry.systems.at(systemClass).As()); })); addedTask.succeed(barrierTask); } diff --git a/Tool/MirrorTool/Src/Generator.cpp b/Tool/MirrorTool/Src/Generator.cpp index c8560549..c5b245b3 100644 --- a/Tool/MirrorTool/Src/Generator.cpp +++ b/Tool/MirrorTool/Src/Generator.cpp @@ -16,7 +16,7 @@ namespace MirrorTool { { std::string outerName = node.outerName; const std::string name = node.name; - return outerName.empty() ? name : fmt::format("{}::{}", outerName, name); + return outerName.empty() ? name : std::format("{}::{}", outerName, name); } template @@ -24,7 +24,7 @@ namespace MirrorTool { { std::stringstream stream; for (const auto& [key, value] : node.metaDatas) { - stream << Common::newline << Common::tab << fmt::format(R"(.MetaData("{}", "{}"))", key, value); + stream << Common::newline << Common::tab << std::format(R"(.MetaData("{}", "{}"))", key, value); } return stream.str(); } @@ -56,13 +56,13 @@ namespace MirrorTool { std::stringstream stream; stream << Common::newline; - stream << Common::tab<1> << fmt::format("Mirror::Registry::Get()") << Common::newline; - stream << Common::tab<2> << fmt::format(R"(.Enum<{}>("{}"))", fullName, fullName); + stream << Common::tab<1> << std::format("Mirror::Registry::Get()") << Common::newline; + stream << Common::tab<2> << std::format(R"(.Enum<{}>("{}"))", fullName, fullName); stream << GetMetaDataCode<3>(enumInfo); for (const auto& element : enumInfo.elements) { const auto elementFullName = GetFullName(element); stream << Common::newline; - stream << Common::tab<3> << fmt::format(R"(.Value<{}>("{}"))", elementFullName, element.name); + stream << Common::tab<3> << std::format(R"(.Value<{}>("{}"))", elementFullName, element.name); stream << GetMetaDataCode<4>(element); } stream << ";" << Common::newline; @@ -85,7 +85,7 @@ namespace MirrorTool { { std::stringstream stream; stream << Common::newline; - stream << fmt::format("int _mirrorEnumRegistry_{} = []() -> int", uniqueId) << Common::newline; + stream << std::format("int _mirrorEnumRegistry_{} = []() -> int", uniqueId) << Common::newline; stream << "{"; stream << GetNamespaceEnumsCode(metaInfo.global); for (const auto& ns : metaInfo.namespaces) { @@ -119,48 +119,48 @@ namespace MirrorTool { auto detorFieldAccess = clazz.destructor.has_value() ? clazz.destructor->fieldAccess : FieldAccess::pub; std::string defaultCtorAndDetorFieldAccessParams = defaultCtorFieldAccess != FieldAccess::pub || detorFieldAccess != FieldAccess::pub - ? fmt::format(", {}, {}", GetFieldAccessStr(defaultCtorFieldAccess), GetFieldAccessStr(detorFieldAccess)) + ? std::format(", {}, {}", GetFieldAccessStr(defaultCtorFieldAccess), GetFieldAccessStr(detorFieldAccess)) : ""; std::stringstream stream; stream << Common::newline; - stream << fmt::format("int {}::_mirrorRegistry = []() -> int ", fullName) << Common::newline; + stream << std::format("int {}::_mirrorRegistry = []() -> int ", fullName) << Common::newline; stream << "{" << Common::newline; stream << Common::tab<1> << "Mirror::Registry::Get()"; if (clazz.baseClassName.empty()) { - stream << Common::newline << Common::tab<2> << fmt::format(R"(.Class<{}, void{}>("{}"))", fullName, defaultCtorAndDetorFieldAccessParams, fullName); + stream << Common::newline << Common::tab<2> << std::format(R"(.Class<{}, void{}>("{}"))", fullName, defaultCtorAndDetorFieldAccessParams, fullName); } else { - stream << Common::newline << Common::tab<2> << fmt::format(R"(.Class<{}, {}{}>("{}"))", fullName, clazz.baseClassName, defaultCtorAndDetorFieldAccessParams, fullName); + stream << Common::newline << Common::tab<2> << std::format(R"(.Class<{}, {}{}>("{}"))", fullName, clazz.baseClassName, defaultCtorAndDetorFieldAccessParams, fullName); } stream << GetMetaDataCode<3>(clazz); for (const auto& constructor : clazz.constructors) { - const std::string fieldAccessStr = constructor.fieldAccess != FieldAccess::pub ? fmt::format(", {}", GetFieldAccessStr(constructor.fieldAccess)) : ""; - stream << Common::newline << Common::tab<3> << fmt::format(R"(.Constructor<{}{}>("{}"))", constructor.name, fieldAccessStr, constructor.name); + const std::string fieldAccessStr = constructor.fieldAccess != FieldAccess::pub ? std::format(", {}", GetFieldAccessStr(constructor.fieldAccess)) : ""; + stream << Common::newline << Common::tab<3> << std::format(R"(.Constructor<{}{}>("{}"))", constructor.name, fieldAccessStr, constructor.name); stream << GetMetaDataCode<4>(constructor); } for (const auto& staticVariable : clazz.staticVariables) { const std::string variableName = GetFullName(staticVariable); - const std::string fieldAccessStr = staticVariable.fieldAccess != FieldAccess::pub ? fmt::format(", {}", GetFieldAccessStr(staticVariable.fieldAccess)) : ""; - stream << Common::newline << Common::tab<3> << fmt::format(R"(.StaticVariable<&{}{}>("{}"))", variableName, fieldAccessStr, staticVariable.name); + const std::string fieldAccessStr = staticVariable.fieldAccess != FieldAccess::pub ? std::format(", {}", GetFieldAccessStr(staticVariable.fieldAccess)) : ""; + stream << Common::newline << Common::tab<3> << std::format(R"(.StaticVariable<&{}{}>("{}"))", variableName, fieldAccessStr, staticVariable.name); stream << GetMetaDataCode<4>(staticVariable); } for (const auto& staticFunction : clazz.staticFunctions) { const std::string functionName = GetFullName(staticFunction); - const std::string fieldAccessStr = staticFunction.fieldAccess != FieldAccess::pub ? fmt::format(", {}", GetFieldAccessStr(staticFunction.fieldAccess)) : ""; - stream << Common::newline << Common::tab<3> << fmt::format(R"(.StaticFunction<&{}{}>("{}"))", functionName, fieldAccessStr, staticFunction.name); + const std::string fieldAccessStr = staticFunction.fieldAccess != FieldAccess::pub ? std::format(", {}", GetFieldAccessStr(staticFunction.fieldAccess)) : ""; + stream << Common::newline << Common::tab<3> << std::format(R"(.StaticFunction<&{}{}>("{}"))", functionName, fieldAccessStr, staticFunction.name); stream << GetMetaDataCode<4>(staticFunction); } // TODO overload support for (const auto& variable : clazz.variables) { const std::string variableName = GetFullName(variable); - const std::string fieldAccessStr = variable.fieldAccess != FieldAccess::pub ? fmt::format(", {}", GetFieldAccessStr(variable.fieldAccess)) : ""; - stream << Common::newline << Common::tab<3> << fmt::format(R"(.MemberVariable<&{}{}>("{}"))", variableName, fieldAccessStr, variable.name); + const std::string fieldAccessStr = variable.fieldAccess != FieldAccess::pub ? std::format(", {}", GetFieldAccessStr(variable.fieldAccess)) : ""; + stream << Common::newline << Common::tab<3> << std::format(R"(.MemberVariable<&{}{}>("{}"))", variableName, fieldAccessStr, variable.name); stream << GetMetaDataCode<4>(variable); } for (const auto& function : clazz.functions) { const std::string functionName = GetFullName(function); - const std::string fieldAccessStr = function.fieldAccess != FieldAccess::pub ? fmt::format(", {}", GetFieldAccessStr(function.fieldAccess)) : ""; - stream << Common::newline << Common::tab<3> << fmt::format(R"(.MemberFunction<&{}{}>("{}"))", functionName, fieldAccessStr, function.name); + const std::string fieldAccessStr = function.fieldAccess != FieldAccess::pub ? std::format(", {}", GetFieldAccessStr(function.fieldAccess)) : ""; + stream << Common::newline << Common::tab<3> << std::format(R"(.MemberFunction<&{}{}>("{}"))", functionName, fieldAccessStr, function.name); stream << GetMetaDataCode<4>(function); } // TODO overload support @@ -168,14 +168,14 @@ namespace MirrorTool { stream << Common::tab<1> << "return 0;" << Common::newline; stream << "}();" << Common::newline; stream << Common::newline; - stream << fmt::format("const Mirror::Class& {}::GetStaticClass()", fullName) << Common::newline; + stream << std::format("const Mirror::Class& {}::GetStaticClass()", fullName) << Common::newline; stream << "{" << Common::newline; - stream << Common::tab<1> << fmt::format("static const Mirror::Class& clazz = Mirror::Class::Get<{}>();", fullName) << Common::newline; + stream << Common::tab<1> << std::format("static const Mirror::Class& clazz = Mirror::Class::Get<{}>();", fullName) << Common::newline; stream << Common::tab<1> << "return clazz;" << Common::newline; stream << "}" << Common::newline; - stream << fmt::format("const Mirror::Class& {}::GetClass()", fullName) << Common::newline; + stream << std::format("const Mirror::Class& {}::GetClass()", fullName) << Common::newline; stream << "{" << Common::newline; - stream << Common::tab<1> << fmt::format("static const Mirror::Class& clazz = Mirror::Class::Get<{}>();", fullName) << Common::newline; + stream << Common::tab<1> << std::format("static const Mirror::Class& clazz = Mirror::Class::Get<{}>();", fullName) << Common::newline; stream << Common::tab<1> << "return clazz;" << Common::newline; stream << "}" << Common::newline; stream << Common::newline; @@ -217,7 +217,7 @@ namespace MirrorTool { stream << Common::newline; stream << Common::tab<1> << "Mirror::Registry::Get()" << Common::newline; stream << Common::tab<2> << ".Global()" << Common::newline; - stream << Common::tab<3> << fmt::format(R"(.Variable<&{}>("{}"))", fullName, fullName); + stream << Common::tab<3> << std::format(R"(.Variable<&{}>("{}"))", fullName, fullName); stream << GetMetaDataCode<4>(var); stream << ";" << Common::newline; } @@ -227,7 +227,7 @@ namespace MirrorTool { stream << Common::newline; stream << Common::tab<1> << "Mirror::Registry::Get()" << Common::newline; stream << Common::tab<2> << ".Global()" << Common::newline; - stream << Common::tab<3> << fmt::format(R"(.Function<&{}>("{}"))", fullName, fullName); + stream << Common::tab<3> << std::format(R"(.Function<&{}>("{}"))", fullName, fullName); stream << GetMetaDataCode<4>(func); stream << ";" << Common::newline; } @@ -243,7 +243,7 @@ namespace MirrorTool { { std::stringstream stream; stream << Common::newline; - stream << fmt::format("int _globalRegistry_{} = []() -> int", uniqueId) << Common::newline; + stream << std::format("int _globalRegistry_{} = []() -> int", uniqueId) << Common::newline; stream << "{"; stream << GetNamespaceGlobalCode(metaInfo.global); for (const auto& ns : metaInfo.namespaces) { @@ -297,7 +297,7 @@ namespace MirrorTool { } outFile << GetHeaderNote() << Common::newline; - outFile << fmt::format("#include <{}>", bestMatchHeaderPath) << Common::newline; + outFile << std::format("#include <{}>", bestMatchHeaderPath) << Common::newline; outFile << "#include " << Common::newline; outFile << GetGlobalCode(metaInfo, uniqueId); outFile << GetEnumsCode(metaInfo, uniqueId); From 343054f34b4d274f510aa47f4ec3db16467efe0b Mon Sep 17 00:00:00 2001 From: John Kindem <461425614@qq.com> Date: Tue, 29 Oct 2024 19:52:38 +0800 Subject: [PATCH 07/22] feat: gameplay framework update --- .../Render/Include/Render/RenderModule.h | 2 +- .../Source/Render/SharedSrc/RenderModule.cpp | 13 +- Engine/Source/Runtime/CMakeLists.txt | 2 +- Engine/Source/Runtime/Include/Runtime/ECS.h | 56 +++ .../Source/Runtime/Include/Runtime/Engine.h | 1 + .../Runtime/Include/Runtime/System/Scene.h | 27 -- Engine/Source/Runtime/Include/Runtime/World.h | 410 +----------------- Engine/Source/Runtime/Src/ECS.cpp | 17 + Engine/Source/Runtime/Src/Engine.cpp | 9 +- Engine/Source/Runtime/Src/System/Scene.cpp | 32 -- Engine/Source/Runtime/Src/World.cpp | 156 +------ Engine/Source/Runtime/Test/WorldTest.cpp | 76 ---- Engine/Source/Runtime/Test/WorldTest.h | 47 -- ThirdParty/CMakeLists.txt | 9 - 14 files changed, 102 insertions(+), 755 deletions(-) create mode 100644 Engine/Source/Runtime/Include/Runtime/ECS.h delete mode 100644 Engine/Source/Runtime/Include/Runtime/System/Scene.h create mode 100644 Engine/Source/Runtime/Src/ECS.cpp delete mode 100644 Engine/Source/Runtime/Src/System/Scene.cpp delete mode 100644 Engine/Source/Runtime/Test/WorldTest.cpp delete mode 100644 Engine/Source/Runtime/Test/WorldTest.h diff --git a/Engine/Source/Render/Include/Render/RenderModule.h b/Engine/Source/Render/Include/Render/RenderModule.h index 8770131c..c7890183 100644 --- a/Engine/Source/Render/Include/Render/RenderModule.h +++ b/Engine/Source/Render/Include/Render/RenderModule.h @@ -27,9 +27,9 @@ namespace Render { Core::ModuleType Type() const override; void Initialize(const RenderModuleInitParams& inParams); + void DeInitialize(); RHI::Device* GetDevice() const; Scene* AllocateScene(); - void DestroyScene(Scene* inScene); void ShutdownRenderingThread(); void FlushAllRenderingCommands() const; diff --git a/Engine/Source/Render/SharedSrc/RenderModule.cpp b/Engine/Source/Render/SharedSrc/RenderModule.cpp index 190a387a..1d4cfe5b 100644 --- a/Engine/Source/Render/SharedSrc/RenderModule.cpp +++ b/Engine/Source/Render/SharedSrc/RenderModule.cpp @@ -45,6 +45,14 @@ namespace Render { initialized = true; } + void RenderModule::DeInitialize() + { + renderingThread = nullptr; + rhiInstance = nullptr; + rhiDevice = nullptr; + initialized = false; + } + RHI::Device* RenderModule::GetDevice() const { return rhiDevice.Get(); @@ -55,11 +63,6 @@ namespace Render { return new Scene(); } - void RenderModule::DestroyScene(Render::Scene* inScene) // NOLINT - { - delete inScene; - } - void RenderModule::ShutdownRenderingThread() { renderingThread = nullptr; diff --git a/Engine/Source/Runtime/CMakeLists.txt b/Engine/Source/Runtime/CMakeLists.txt index cb051bfd..3e127d5b 100644 --- a/Engine/Source/Runtime/CMakeLists.txt +++ b/Engine/Source/Runtime/CMakeLists.txt @@ -5,7 +5,7 @@ AddLibrary( SRC ${SOURCES} PUBLIC_INC Include REFLECT Include - LIB Core Mirror assimp-lib Render EnTT + LIB Core Mirror assimp-lib Render ) file(GLOB TEST_SOURCES Test/*.cpp) diff --git a/Engine/Source/Runtime/Include/Runtime/ECS.h b/Engine/Source/Runtime/Include/Runtime/ECS.h new file mode 100644 index 00000000..1fbb407a --- /dev/null +++ b/Engine/Source/Runtime/Include/Runtime/ECS.h @@ -0,0 +1,56 @@ +// +// Created by johnk on 2024/10/31. +// + +#pragma once + +#include + +namespace Runtime { + using Entity = size_t; + using CompTypeId = size_t; + + class CompPacket { + public: + virtual ~CompPacket(); + + protected: + CompPacket(); + }; + + template + class TypedCompPacket final : public CompPacket { + public: + ~TypedCompPacket() override; + + private: + friend class ECRegistry; + + using CompIndex = size_t; + + TypedCompPacket(); + + std::unordered_map entityMap; + std::vector storage; + }; + + class EntityContainer { + public: + + private: + }; + + class ECRegistry { + public: + + private: + EntityContainer entities; + std::unordered_map> compPackets; + }; + + class SystemRegistry { + public: + + private: + }; +} diff --git a/Engine/Source/Runtime/Include/Runtime/Engine.h b/Engine/Source/Runtime/Include/Runtime/Engine.h index 8535a197..a0fae201 100644 --- a/Engine/Source/Runtime/Include/Runtime/Engine.h +++ b/Engine/Source/Runtime/Include/Runtime/Engine.h @@ -28,6 +28,7 @@ namespace Runtime { void UnmountWorld(World* inWorld); Render::RenderModule& GetRenderModule() const; void Tick(float inTimeMs) const; + Common::UniqueRef CreateWorld(const std::string& inName = "") const; protected: explicit Engine(const EngineInitParams& inParams); diff --git a/Engine/Source/Runtime/Include/Runtime/System/Scene.h b/Engine/Source/Runtime/Include/Runtime/System/Scene.h deleted file mode 100644 index 31c6fa9d..00000000 --- a/Engine/Source/Runtime/Include/Runtime/System/Scene.h +++ /dev/null @@ -1,27 +0,0 @@ -// -// Created by johnk on 2024/10/15. -// - -#pragma once - -#include -#include -#include - -namespace Runtime { - struct SceneState { - Render::Scene* scene; - // TODO views - }; - - class EClass() SceneSystem final : public System { - EPolyClassBody(SceneSystem) - - SceneSystem(); - ~SceneSystem() override; - - void Setup(Commands& inCommands) const override; - void Tick(Commands& inCommands, float inTimeMs) const override; - void Stop(Commands& inCommands) const override; - }; -} diff --git a/Engine/Source/Runtime/Include/Runtime/World.h b/Engine/Source/Runtime/Include/Runtime/World.h index 9f682de1..3eb44ff1 100644 --- a/Engine/Source/Runtime/Include/Runtime/World.h +++ b/Engine/Source/Runtime/Include/Runtime/World.h @@ -1,420 +1,22 @@ // -// Created by johnk on 2024/8/2. +// Created by johnk on 2024/10/31. // #pragma once -#include -#include - -#include -#include -#include -#include - -namespace Runtime::Internal { - template const Mirror::Class* GetClassChecked(); - const Mirror::Class* GetClassChecked(const std::string& inName); -} - namespace Runtime { - using Entity = entt::entity; - constexpr auto entityNull = entt::null; - - class Commands; - - class RUNTIME_API EClass() System { - EPolyClassBody(System) - System(); - virtual ~System(); - - virtual void Setup(Commands& inCommands) const; - virtual void Tick(Commands& inCommands, float inTimeMs) const; - virtual void Stop(Commands& inCommands) const; - }; - - template concept SystemDerived = std::is_base_of_v; - template struct Exclude {}; -} - -namespace Runtime { - class World; - class Ticker; - - template class BasicCollector; - using Collector = BasicCollector<>; - - template - class CompView { - public: - using Iterator = entt::basic_view; - - explicit CompView(const entt::basic_view& inView); - - template void Each(F&& inFunc); - - Iterator Begin() const; - Iterator End() const; - Iterator ReverseBegin() const; - Iterator ReverseEnd() const; - Iterator begin() const; - Iterator end() const; - - private: - entt::basic_view view; - }; - - // TODO runtime view - - using StateClass = const Mirror::Class*; - using CompClass = const Mirror::Class*; - using SystemClass = const Mirror::Class*; - - class Commands; - - class RUNTIME_API Observer { + class World { public: - using Iterator = entt::observer::iterator; - - template Observer(Commands& inCommands, const BasicCollector& inCollector); - - template void Each(F&& inFunc); - void Clear(); - Iterator Begin() const; - Iterator End() const; - Iterator begin() const; - Iterator end() const; - - private: - entt::observer observer; - }; - - struct EntityCompRegistry { - entt::registry native; - }; - - class RUNTIME_API Commands { - public: - ~Commands(); - - Entity CreateEntity(); - void DestroyEntity(Entity inEntity); - bool HasEntity(Entity inEntity) const; - - template bool HasState() const; - template const S& EmplaceState(Args&&... inArgs); - template const S* FindState() const; - template const S& GetState() const; - template void RemoveState(); - template void PatchState(F&& inFunc); - template bool HasComp(Entity inEntity) const; - template const C& EmplaceComp(Entity inEntity, Args&&... inArgs); - template const C* FindComp(Entity inEntity) const; - template const C& GetComp(Entity inEntity) const; - template void RemoveComp(Entity inEntity); - template void PatchComp(Entity inEntity, F&& inFunc); - template auto View(Exclude = {}); - template auto View(Exclude = {}) const; - // TODO runtime view - template Observer CreateObserver(const BasicCollector& inCollector); - // TODO component lifecycle listeners - - private: - friend class World; - friend class Observer; - - explicit Commands(EntityCompRegistry& inRegistry); - - EntityCompRegistry& registry; - }; - - struct SystemRegistry { - std::unordered_map systems; - std::vector> systemsGraph; - std::vector systemsInBarriers; - }; - - // world is fully runtime structure, we use level to perform persist storage - class RUNTIME_API World { - public: - explicit World(std::string inName = ""); + NonCopyable(World) ~World(); - DefaultCopyable(World) - DefaultMovable(World) - - template void AddSystem(Args&&... inSystemArgs); - void AddBarrier(); - - void Play(); - void Stop(); - void Pause(); - void Resume(); - void Tick(float inFrameTimeMs); - bool Started() const; - bool Playing() const; - private: - friend class Commands; - friend class Observer; - - using SystemOp = std::function; + friend class Engine; - // TODO we not want read-write in a barrier time, so we maybe need runtime read-write check - void ExecuteSystemGraph(const SystemOp& inOp); + explicit World(const std::string& inName = ""); + // TODO play/stop/pause/status - bool setup; - bool playing; std::string name; - EntityCompRegistry entityCompRegistry; - SystemRegistry systemRegistry; }; } -namespace Runtime::Internal { - template - const Mirror::Class* GetClassChecked() - { - return &Mirror::Class::Get(); - } - - template - struct CollectorConverter {}; - - template <> - struct CollectorConverter> { - using EngineType = BasicCollector<>; - }; - - template - struct CollectorConverter, entt::type_list, Rule...>, Other...>> { - using EngineType = BasicCollector, entt::type_list, Rule...>, Other...>; - }; -} - -namespace Runtime { - template <> - class BasicCollector<> { - public: - BasicCollector() = default; - - template - static constexpr auto Group(Exclude = {}) noexcept - { - using LibRetType = decltype(entt::basic_collector<>::group(entt::exclude)); - return typename Internal::CollectorConverter::EngineType {}; - } - - template - static constexpr auto Update() noexcept - { - using LibRetType = decltype(entt::basic_collector<>::update()); - return typename Internal::CollectorConverter::EngineType {}; - } - - private: - friend class Observer; - - static auto Final() noexcept - { - return entt::basic_collector<> {}; - } - }; - - template - class BasicCollector { - public: - BasicCollector() = default; - - template - static constexpr auto Group(Exclude = {}) noexcept - { - using LibRetType = decltype(entt::basic_collector::template group(entt::exclude)); - return typename Internal::CollectorConverter::EngineType {}; - } - - template - static constexpr auto Update() noexcept - { - using LibRetType = decltype(entt::basic_collector::template update()); - return typename Internal::CollectorConverter::EngineType {}; - } - - template - static constexpr auto Where(Exclude = {}) noexcept - { - using LibRetType = decltype(entt::basic_collector::template where(entt::exclude)); - return typename Internal::CollectorConverter::EngineType {}; - } - - private: - friend class Observer; - - static auto Final() noexcept - { - return entt::basic_collector {}; - } - }; - - template - Observer::Observer(Commands& inCommands, const BasicCollector& inCollector) - : observer(inCommands.registry, inCollector.Final()) - { - } - - template - void Observer::Each(F&& inFunc) - { - observer.each(std::forward(inFunc)); - } - - template - CompView::CompView(const entt::basic_view& inView) - : view(inView) - { - } - - template - template - void CompView::Each(F&& inFunc) - { - view.each(std::forward(inFunc)); - } - - template - typename CompView::Iterator CompView::Begin() const - { - return view.begin(); - } - - template - typename CompView::Iterator CompView::End() const - { - return view.end(); - } - - template - typename CompView::Iterator CompView::ReverseBegin() const - { - return view.rbegin(); - } - - template - typename CompView::Iterator CompView::ReverseEnd() const - { - return view.rend(); - } - - template - typename CompView::Iterator CompView::begin() const - { - return Begin(); - } - - template - typename CompView::Iterator CompView::end() const - { - return End(); - } - - template - bool Commands::HasState() const - { - return registry.native.try_ctx() != nullptr; - } - - template - const S& Commands::EmplaceState(Args&&... inArgs) - { - return registry.native.set(std::forward(inArgs)...); - } - - template - const S* Commands::FindState() const - { - return registry.native.try_ctx(); - } - - template - const S& Commands::GetState() const - { - return registry.native.ctx(); - } - - template - void Commands::RemoveState() // NOLINT - { - registry.native.unset(); - } - - template - void Commands::PatchState(F&& inFunc) - { - Assert(HasState()); - inFunc(registry.native.ctx()); - } - - template - bool Commands::HasComp(Entity inEntity) const - { - return registry.native.try_get(inEntity) != nullptr; - } - - template - const C& Commands::EmplaceComp(Entity inEntity, Args&&... inArgs) - { - return registry.native.emplace(inEntity, std::forward(inArgs)...); - } - - template - const C* Commands::FindComp(Entity inEntity) const - { - return registry.native.try_get(inEntity); - } - - template - const C& Commands::GetComp(Entity inEntity) const - { - auto* result = registry.native.try_get(inEntity); - Assert(result != nullptr); - return *result; - } - - template - void Commands::RemoveComp(Entity inEntity) // NOLINT - { - registry.native.erase(inEntity); - } - - template - void Commands::PatchComp(Entity inEntity, F&& inFunc) - { - registry.native.patch(inEntity, std::forward(inFunc)); - } - - template - auto Commands::View(Exclude) - { - return CompView, C...>(registry.native.view(entt::exclude_t {})); - } - - template - auto Commands::View(Exclude) const - { - return CompView, std::add_const_t...>(registry.native.view(entt::exclude_t {})); - } - - template - Observer Commands::CreateObserver(const BasicCollector& inCollector) - { - return { *this, inCollector }; - } - - template - void World::AddSystem(Args&&... inSystemArgs) - { - SystemClass clazz = Internal::GetClassChecked(); - systemRegistry.systems.emplace(clazz, System(std::forward(inSystemArgs)...)); - systemRegistry.systemsInBarriers.emplace_back(clazz); - } -}; diff --git a/Engine/Source/Runtime/Src/ECS.cpp b/Engine/Source/Runtime/Src/ECS.cpp new file mode 100644 index 00000000..b46b1327 --- /dev/null +++ b/Engine/Source/Runtime/Src/ECS.cpp @@ -0,0 +1,17 @@ +// +// Created by johnk on 2024/10/31. +// + +#include + +namespace Runtime { + CompPacket::~CompPacket() = default; + + CompPacket::CompPacket() = default; + + template + TypedCompPacket::~TypedCompPacket() = default; + + template + TypedCompPacket::TypedCompPacket() = default; +} diff --git a/Engine/Source/Runtime/Src/Engine.cpp b/Engine/Source/Runtime/Src/Engine.cpp index cf4663de..4fae8ff3 100644 --- a/Engine/Source/Runtime/Src/Engine.cpp +++ b/Engine/Source/Runtime/Src/Engine.cpp @@ -3,9 +3,10 @@ // #include -#include #include +#include #include +#include namespace Runtime { Engine::Engine(const EngineInitParams& inParams) @@ -24,6 +25,7 @@ namespace Runtime { Engine::~Engine() { + renderModule->DeInitialize(); ::Core::ModuleManager::Get().Unload("Render"); } @@ -49,6 +51,11 @@ namespace Runtime { // TODO traverse each view in scene, create a renderer, perform rendering } + Common::UniqueRef Engine::CreateWorld(const std::string& inName) const // NOLINT + { + return new World(inName); + } + Engine* EngineHolder::engine = nullptr; MinEngine::MinEngine(const EngineInitParams& inParams) diff --git a/Engine/Source/Runtime/Src/System/Scene.cpp b/Engine/Source/Runtime/Src/System/Scene.cpp deleted file mode 100644 index 11ddb8e7..00000000 --- a/Engine/Source/Runtime/Src/System/Scene.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// -// Created by johnk on 2024/10/15. -// - -#include -#include - -namespace Runtime { - SceneSystem::SceneSystem() = default; - - SceneSystem::~SceneSystem() = default; - - void SceneSystem::Setup(Commands& inCommands) const - { - inCommands.EmplaceState(); - inCommands.PatchState([](auto& state) -> void { - auto& renderModule = EngineHolder::Get().GetRenderModule(); - state.scene = renderModule.AllocateScene(); - }); - } - - void SceneSystem::Tick(Commands& inCommands, float inTimeMs) const - { - // TODO - } - - void SceneSystem::Stop(Commands& inCommands) const - { - auto& renderModule = EngineHolder::Get().GetRenderModule(); - renderModule.DestroyScene(inCommands.GetState().scene); - } -} diff --git a/Engine/Source/Runtime/Src/World.cpp b/Engine/Source/Runtime/Src/World.cpp index 3baa5411..69d34181 100644 --- a/Engine/Source/Runtime/Src/World.cpp +++ b/Engine/Source/Runtime/Src/World.cpp @@ -1,77 +1,13 @@ // -// Created by johnk on 2024/8/2. +// Created by johnk on 2024/10/31. // #include #include namespace Runtime { - const Mirror::Class* Internal::GetClassChecked(const std::string& inName) - { - return &Mirror::Class::Get(inName); - } - - System::System() = default; - - System::~System() = default; - - void System::Setup(Commands& inCommands) const {} - - void System::Tick(Commands& inCommands, float inTimeMs) const {} - - void System::Stop(Commands& inCommands) const {} - - void Observer::Clear() - { - observer.clear(); - } - - Observer::Iterator Observer::Begin() const - { - return observer.begin(); - } - - Observer::Iterator Observer::End() const - { - return observer.end(); - } - - Observer::Iterator Observer::begin() const - { - return Begin(); - } - - Observer::Iterator Observer::end() const - { - return End(); - } - - Commands::Commands(EntityCompRegistry& inRegistry) - : registry(inRegistry) - { - } - - Commands::~Commands() = default; - - Entity Commands::CreateEntity() // NOLINT - { - return registry.native.create(); - } - - void Commands::DestroyEntity(Entity inEntity) // NOLINT - { - registry.native.destroy(inEntity); - } - - bool Commands::HasEntity(Entity inEntity) const - { - return registry.native.valid(inEntity); - } - - World::World(std::string inName) - : setup(false) - , playing(false) - , name(std::move(inName)) + World::World(const std::string& inName) + : name(inName) { EngineHolder::Get().MountWorld(this); } @@ -80,88 +16,4 @@ namespace Runtime { { EngineHolder::Get().UnmountWorld(this); } - - void World::AddBarrier() - { - systemRegistry.systemsGraph.emplace_back(systemRegistry.systemsInBarriers); - systemRegistry.systemsInBarriers.clear(); - } - - void World::Play() - { - Assert(!setup && systemRegistry.systemsInBarriers.empty()); - setup = true; - playing = true; - ExecuteSystemGraph([&](const System& inSystem) -> void { - Commands commands(entityCompRegistry); - inSystem.Setup(commands); - }); - } - - void World::Stop() - { - Assert(setup); - setup = false; - playing = false; - } - - void World::Pause() - { - Assert(setup && playing); - playing = false; - } - - void World::Resume() - { - Assert(setup && !playing); - playing = true; - } - - void World::Tick(float inFrameTimeMs) - { - Assert(setup && playing); - ExecuteSystemGraph([&](const System& inSystem) -> void { - Commands commands(entityCompRegistry); - inSystem.Tick(commands, inFrameTimeMs); - }); - } - - bool World::Started() const - { - return setup; - } - - bool World::Playing() const - { - return playing; - } - - void World::ExecuteSystemGraph(const SystemOp& inOp) - { - tf::Taskflow taskFlow; - auto newBarrierTask = [&]() -> decltype(auto) { - return taskFlow.emplace([]() -> void {}); - }; - - tf::Task barrierTask = newBarrierTask(); - for (const auto& systemSet : systemRegistry.systemsGraph) { - std::vector tasks; - for (const auto& systemClass : systemSet) { - auto& addedTask = tasks.emplace_back(taskFlow.emplace([&]() -> void { - inOp(systemRegistry.systems.at(systemClass).As()); - })); - addedTask.succeed(barrierTask); - } - - barrierTask = newBarrierTask(); - for (const auto& task : tasks) { - barrierTask.succeed(task); - } - } - - tf::Executor executor; - executor - .run(taskFlow) - .wait(); - } -} +} // namespace Runtime diff --git a/Engine/Source/Runtime/Test/WorldTest.cpp b/Engine/Source/Runtime/Test/WorldTest.cpp deleted file mode 100644 index 149fa71d..00000000 --- a/Engine/Source/Runtime/Test/WorldTest.cpp +++ /dev/null @@ -1,76 +0,0 @@ -// -// Created by johnk on 2024/8/20. -// - -#include -#include -#include - -struct WorldTest : testing::Test { - void SetUp() override - { - EngineInitParams initParams; - initParams.projectFile = ""; - initParams.rhiType = RHI::GetPlatformDefaultRHIAbbrString(); - EngineHolder::Load("RuntimeTest", initParams); - } -}; - -GlobalCounter::GlobalCounter() - : tickTime(0) - , value(0) -{ -} - -ParralCountSystemA::ParralCountSystemA() = default; - -ParralCountSystemA::~ParralCountSystemA() = default; - -void ParralCountSystemA::Tick(Commands& commands, float inTimeMs) const -{ - commands.PatchState([](auto& state) -> void { - state.tickTime += 1; - state.value += 2; - }); -} - -ParralCountSystemB::ParralCountSystemB() = default; - -ParralCountSystemB::~ParralCountSystemB() = default; - -void ParralCountSystemB::Tick(Commands& commands, float inTimeMs) const -{ - commands.PatchState([](auto& state) -> void { - state.value += 3; - }); -} - -GlobalCounterVerifySystem::GlobalCounterVerifySystem() = default; - -GlobalCounterVerifySystem::~GlobalCounterVerifySystem() = default; - -void GlobalCounterVerifySystem::Setup(Commands& commands) const -{ - commands.EmplaceState(); -} - -void GlobalCounterVerifySystem::Tick(Commands& commands, float inTimeMs) const -{ - const auto& globalCounter = commands.GetState(); - ASSERT_EQ(globalCounter.value, globalCounter.tickTime * 5); -} - -TEST_F(WorldTest, ECSBasic) -{ - World world; - world.AddSystem(); - world.AddSystem(); - world.AddBarrier(); - world.AddSystem(); - world.AddBarrier(); - - world.Play(); - world.Tick(3.0f); - world.Tick(3.0f); - world.Stop(); -} diff --git a/Engine/Source/Runtime/Test/WorldTest.h b/Engine/Source/Runtime/Test/WorldTest.h deleted file mode 100644 index 12641215..00000000 --- a/Engine/Source/Runtime/Test/WorldTest.h +++ /dev/null @@ -1,47 +0,0 @@ -// -// Created by johnk on 2024/8/20. -// - -#pragma once - -#include -#include - -using namespace Runtime; - -class EClass() GlobalCounter { - EClassBody(GlobalCounter) - - GlobalCounter(); - - EProperty() uint32_t tickTime; - EProperty() uint32_t value; -}; - -class EClass() ParralCountSystemA final : public System { - EPolyClassBody(ParralCountSystemA) - - ParralCountSystemA(); - ~ParralCountSystemA() override; - - EFunc() void Tick(Commands& commands, float inTimeMs) const override; -}; - -class EClass() ParralCountSystemB final : public System { - EPolyClassBody(ParralCountSystemB) - - ParralCountSystemB(); - ~ParralCountSystemB() override; - - EFunc() void Tick(Commands& commands, float inTimeMs) const override; -}; - -class EClass() GlobalCounterVerifySystem final : public System { - EPolyClassBody(GlobalCounterVerifySystem) - - GlobalCounterVerifySystem(); - ~GlobalCounterVerifySystem() override; - - EFunc() void Setup(Commands& commands) const override; - EFunc() void Tick(Commands& commands, float inTimeMs) const override; -}; diff --git a/ThirdParty/CMakeLists.txt b/ThirdParty/CMakeLists.txt index 6802794a..8d4e5a43 100644 --- a/ThirdParty/CMakeLists.txt +++ b/ThirdParty/CMakeLists.txt @@ -1,12 +1,3 @@ -# EnTT -Add3rdHeaderOnlyPackage( - NAME EnTT - PLATFORM All - VERSION 3.8.1 - HASH abe24e5da599ef9f172c25f68f3b777dd404896b06e500742ecc88bbfef2216c - INCLUDE $/single_include -) - # DirectX 12 Headers Add3rdHeaderOnlyPackage( NAME DirectXHeaders From 870a1d15925f15dd92191adad4802342b59d2d47 Mon Sep 17 00:00:00 2001 From: John Kindem <461425614@qq.com> Date: Sat, 2 Nov 2024 18:54:47 +0800 Subject: [PATCH 08/22] fix: macos build issue --- CMake/Target.cmake | 18 ++++++++++-------- Engine/Source/Runtime/Include/Runtime/World.h | 2 ++ Tool/MirrorTool/Src/Parser.cpp | 9 +++++---- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/CMake/Target.cmake b/CMake/Target.cmake index 9fc75294..4a9c33b5 100644 --- a/CMake/Target.cmake +++ b/CMake/Target.cmake @@ -291,10 +291,10 @@ function(AddExecutable) ) endif() - add_executable( + add_executable(${PARAMS_NAME}) + target_sources( ${PARAMS_NAME} - ${PARAMS_SRC} - ${GENERATED_SRC} + PRIVATE ${PARAMS_SRC} ${GENERATED_SRC} ) target_include_directories( ${PARAMS_NAME} @@ -353,8 +353,10 @@ function(AddLibrary) add_library( ${PARAMS_NAME} ${PARAMS_TYPE} - ${PARAMS_SRC} - ${GENERATED_SRC} + ) + target_sources( + ${PARAMS_NAME} + PRIVATE ${PARAMS_SRC} ${GENERATED_SRC} ) target_include_directories( ${PARAMS_NAME} @@ -416,10 +418,10 @@ function(AddTest) ) endif() - add_executable( + add_executable(${PARAMS_NAME}) + target_sources( ${PARAMS_NAME} - ${PARAMS_SRC} - ${GENERATED_SRC} + PRIVATE ${PARAMS_SRC} ${GENERATED_SRC} ) target_include_directories( ${PARAMS_NAME} diff --git a/Engine/Source/Runtime/Include/Runtime/World.h b/Engine/Source/Runtime/Include/Runtime/World.h index 3eb44ff1..661c6e65 100644 --- a/Engine/Source/Runtime/Include/Runtime/World.h +++ b/Engine/Source/Runtime/Include/Runtime/World.h @@ -4,6 +4,8 @@ #pragma once +#include + namespace Runtime { class World { public: diff --git a/Tool/MirrorTool/Src/Parser.cpp b/Tool/MirrorTool/Src/Parser.cpp index 93b2df44..bb4c6cc8 100644 --- a/Tool/MirrorTool/Src/Parser.cpp +++ b/Tool/MirrorTool/Src/Parser.cpp @@ -3,6 +3,7 @@ // #include +#include #include #include @@ -419,10 +420,10 @@ namespace MirrorTool { "-DNOMINMAX=1", #elif PLATFORM_MACOS "-DPLATFORM_MACOS=1", - fmt::format("-I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX{}.sdk/usr/include/c++/v1", MACOS_SDK_VERSION), - fmt::format("-I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX{}.sdk/usr/include", MACOS_SDK_VERSION), - fmt::format("-I/Library/Developer/CommandLineTools/usr/lib/clang/{}.{}.{}/include", __clang_major__, __clang_minor__, __clang_patchlevel__), - fmt::format("-I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/{}.{}.{}/include", __clang_major__, __clang_minor__, __clang_patchlevel__), + std::format("-I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX{}.sdk/usr/include/c++/v1", MACOS_SDK_VERSION), + std::format("-I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX{}.sdk/usr/include", MACOS_SDK_VERSION), + std::format("-I/Library/Developer/CommandLineTools/usr/lib/clang/{}.{}.{}/include", __clang_major__, __clang_minor__, __clang_patchlevel__), + std::format("-I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/{}.{}.{}/include", __clang_major__, __clang_minor__, __clang_patchlevel__), #elif DPLATFORM_LINUX "-DPLATFORM_LINUX=1", #endif From 32319b607d360c1c6f8cd97085404de3e221581f Mon Sep 17 00:00:00 2001 From: John Kindem <461425614@qq.com> Date: Mon, 4 Nov 2024 21:38:37 +0800 Subject: [PATCH 09/22] feat: gameplay framework update --- .../Source/Common/Include/Common/Container.h | 13 +- Engine/Source/Common/Include/Common/Debug.h | 10 +- Engine/Source/Common/Include/Common/Event.h | 151 +++++ Engine/Source/Common/Src/Event.cpp | 5 + Engine/Source/Common/Test/ContainerTest.cpp | 13 + Engine/Source/Common/Test/EventTest.cpp | 43 ++ .../Source/Mirror/Include/Mirror/Registry.h | 1 + Engine/Source/Render/Src/RenderGraph.cpp | 4 +- Engine/Source/Runtime/Include/Runtime/ECS.h | 547 +++++++++++++++++- Engine/Source/Runtime/Include/Runtime/World.h | 2 + Engine/Source/Runtime/Src/ECS.cpp | 344 ++++++++++- 11 files changed, 1104 insertions(+), 29 deletions(-) create mode 100644 Engine/Source/Common/Include/Common/Event.h create mode 100644 Engine/Source/Common/Src/Event.cpp create mode 100644 Engine/Source/Common/Test/EventTest.cpp diff --git a/Engine/Source/Common/Include/Common/Container.h b/Engine/Source/Common/Include/Common/Container.h index 82e3d098..814dbdfa 100644 --- a/Engine/Source/Common/Include/Common/Container.h +++ b/Engine/Source/Common/Include/Common/Container.h @@ -23,13 +23,14 @@ namespace Common { template static typename std::vector::iterator SwapWithLastAndDelete(std::vector& vector, const typename std::vector::iterator& iterator); template static size_t SwapWithLastAndDelete(std::vector& vector, size_t index); template static std::vector GetIntersection(const std::vector& lhs, const std::vector& rhs); + template static std::vector GetDifferences(const std::vector& lhs, const std::vector& rhs); }; class SetUtils { public: template static std::unordered_set GetIntersection(const std::unordered_set& lhs, const std::unordered_set& rhs); template static std::unordered_set GetUnion(const std::unordered_set& lhs, const std::unordered_set& rhs); - template static void GetUnionInline(std::unordered_set& lhs, const std::unordered_set& rhs); + template static void GetUnionInplace(std::unordered_set& lhs, const std::unordered_set& rhs); }; template class InplaceVectorIter; @@ -295,6 +296,14 @@ namespace Common { return result; } + template + std::vector VectorUtils::GetDifferences(const std::vector& lhs, const std::vector& rhs) + { + std::vector result; + std::set_difference(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), std::back_inserter(result)); + return result; + } + template std::unordered_set SetUtils::GetIntersection(const std::unordered_set& lhs, const std::unordered_set& rhs) { @@ -325,7 +334,7 @@ namespace Common { } template - void SetUtils::GetUnionInline(std::unordered_set& lhs, const std::unordered_set& rhs) + void SetUtils::GetUnionInplace(std::unordered_set& lhs, const std::unordered_set& rhs) { lhs.reserve(lhs.size() + rhs.size()); for (const auto& element : rhs) { diff --git a/Engine/Source/Common/Include/Common/Debug.h b/Engine/Source/Common/Include/Common/Debug.h index 52c7fb97..df754bd3 100644 --- a/Engine/Source/Common/Include/Common/Debug.h +++ b/Engine/Source/Common/Include/Common/Debug.h @@ -6,10 +6,9 @@ #include #include -#include -#define Assert(expression) Common::Debug::AssertImpl(expression, #expression, std::source_location::current().file_name(), std::source_location::current().line()) -#define AssertWithReason(expression, reason) Common::Debug::AssertImpl(expression, #expression, std::source_location::current().file_name(), std::source_location::current().line(), reason) +#define Assert(expression) Common::Debug::AssertImpl(expression, #expression, __FILE__, __LINE__) +#define AssertWithReason(expression, reason) Common::Debug::AssertImpl(expression, #expression, __FILE__, __LINE__, reason) #define Unimplement() Assert(false) #define QuickFail() Assert(false) #define QuickFailWithReason(reason) AssertWithReason(false, reason) @@ -24,4 +23,9 @@ namespace Common { private: Debug(); }; + + // for compile-time check type from compile error + // sample: + // TypeDiagnosis xType; + template class TypeDiagnosis; } diff --git a/Engine/Source/Common/Include/Common/Event.h b/Engine/Source/Common/Include/Common/Event.h new file mode 100644 index 00000000..4bd10dca --- /dev/null +++ b/Engine/Source/Common/Include/Common/Event.h @@ -0,0 +1,151 @@ +// +// Created by johnk on 2024/11/5. +// + +#pragma once + +#include +#include +#include + +#include + +#define IMPL_INDEX_TO_STD_PLACEHOLDER(I) \ + template <> struct IndexToStdPlaceholder { static constexpr auto value = std::placeholders::_##I; }; \ + +namespace Common::Internal { + template struct IndexToStdPlaceholder {}; + + IMPL_INDEX_TO_STD_PLACEHOLDER(1) + IMPL_INDEX_TO_STD_PLACEHOLDER(2) + IMPL_INDEX_TO_STD_PLACEHOLDER(3) + IMPL_INDEX_TO_STD_PLACEHOLDER(4) + IMPL_INDEX_TO_STD_PLACEHOLDER(5) + IMPL_INDEX_TO_STD_PLACEHOLDER(6) + IMPL_INDEX_TO_STD_PLACEHOLDER(7) + IMPL_INDEX_TO_STD_PLACEHOLDER(8) + IMPL_INDEX_TO_STD_PLACEHOLDER(9) + IMPL_INDEX_TO_STD_PLACEHOLDER(10) + IMPL_INDEX_TO_STD_PLACEHOLDER(11) + IMPL_INDEX_TO_STD_PLACEHOLDER(12) + IMPL_INDEX_TO_STD_PLACEHOLDER(13) + IMPL_INDEX_TO_STD_PLACEHOLDER(14) + IMPL_INDEX_TO_STD_PLACEHOLDER(15) + IMPL_INDEX_TO_STD_PLACEHOLDER(16) + IMPL_INDEX_TO_STD_PLACEHOLDER(17) + IMPL_INDEX_TO_STD_PLACEHOLDER(18) + IMPL_INDEX_TO_STD_PLACEHOLDER(19) + IMPL_INDEX_TO_STD_PLACEHOLDER(20) +} + +namespace Common { + using ReceiverHandle = size_t; + + template + class Event { + public: + Event(); + + template ReceiverHandle BindStatic(); + template ReceiverHandle BindMember(C&& inObj); + template ReceiverHandle BindLambda(F&& inLambda); + template void Broadcast(Args&&... inArgs) const; + void Unbind(ReceiverHandle inHandle); + size_t ReceiversCount() const; + void Reset(); + + private: + template void BindStaticInternal(ReceiverHandle inHandle, std::index_sequence); + template void BindMemberInternal(ReceiverHandle inHandle, C&& inObj, std::index_sequence); + template void BindLambdaInternal(ReceiverHandle inHandle, F&& inLambda, std::index_sequence); + + ReceiverHandle counter; + std::vector>> receivers; + }; +} + +namespace Common { + template + Event::Event() + : counter(0) + { + } + + template + template + ReceiverHandle Event::BindStatic() + { + const auto handle = counter++; + BindStaticInternal(handle, std::make_index_sequence()); + return handle; + } + + template + template + ReceiverHandle Event::BindMember(C&& inObj) + { + const auto handle = counter++; + BindMemberInternal(handle, std::forward(inObj), std::make_index_sequence()); + return handle; + } + + template + template + ReceiverHandle Event::BindLambda(F&& inLambda) + { + const auto handle = counter++; + BindLambdaInternal(handle, std::forward(inLambda), std::make_index_sequence()); + return handle; + } + + template + template + void Event::Broadcast(Args&&... inArgs) const + { + for (const auto& [_, receiver] : receivers) { + receiver(std::forward(inArgs)...); + } + } + + template + void Event::Unbind(ReceiverHandle inHandle) + { + auto iter = std::find_if(receivers.begin(), receivers.end(), [&](const auto& pair) -> bool { return pair.first == inHandle; }); + Assert(iter != receivers.end()); + receivers.erase(iter); + } + + template + size_t Event::ReceiversCount() const + { + return receivers.size(); + } + + template + void Event::Reset() + { + counter = 0; + receivers.clear(); + } + + template + template + void Event::BindStaticInternal(ReceiverHandle inHandle, std::index_sequence) + { + receivers.emplace_back(inHandle, std::bind(F, Internal::IndexToStdPlaceholder::value...)); + } + + template + template + void Event::BindMemberInternal(ReceiverHandle inHandle, C&& inObj, std::index_sequence) + { + receivers.emplace_back(inHandle, std::bind(F, std::forward(inObj), Internal::IndexToStdPlaceholder::value...)); + } + + template + template + void Event::BindLambdaInternal(ReceiverHandle inHandle, F&& inLambda, std::index_sequence) + { + receivers.emplace_back(inHandle, std::bind(inLambda, Internal::IndexToStdPlaceholder::value...)); + } +} // namespace Common diff --git a/Engine/Source/Common/Src/Event.cpp b/Engine/Source/Common/Src/Event.cpp new file mode 100644 index 00000000..84430cae --- /dev/null +++ b/Engine/Source/Common/Src/Event.cpp @@ -0,0 +1,5 @@ +// +// Created by johnk on 2024/11/5. +// + +#include diff --git a/Engine/Source/Common/Test/ContainerTest.cpp b/Engine/Source/Common/Test/ContainerTest.cpp index 98932189..36d12fad 100644 --- a/Engine/Source/Common/Test/ContainerTest.cpp +++ b/Engine/Source/Common/Test/ContainerTest.cpp @@ -104,6 +104,19 @@ TEST(ContainerTest, VectorGetIntersection) ASSERT_EQ(result, (std::vector { 3, 4, 5 })); } +TEST(ContainerTest, VectorGetDifferences) +{ + std::vector a = { 1, 2, 5, 5, 5, 9 }; + std::vector b = { 2, 5, 7 }; + auto result = VectorUtils::GetDifferences(a, b); + ASSERT_EQ(result, (std::vector { 1, 5, 5, 9 })); + + a = { 1, 2, 3, 4, 5 }; + b = { 4, 5, 6, 7, 8 }; + result = VectorUtils::GetDifferences(a, b); + ASSERT_EQ(result, (std::vector { 1, 2, 3 })); +} + TEST(ContainerTest, SetGetIntersection) { const std::unordered_set a = { 1, 2, 3, 4, 5 }; diff --git a/Engine/Source/Common/Test/EventTest.cpp b/Engine/Source/Common/Test/EventTest.cpp new file mode 100644 index 00000000..fd94a5da --- /dev/null +++ b/Engine/Source/Common/Test/EventTest.cpp @@ -0,0 +1,43 @@ +// +// Created by johnk on 2024/11/5. +// + +#include + +static int counter = 0; + +static void StaticReceiver(int a, bool b) +{ + counter++; + ASSERT_EQ(a, 1); + ASSERT_EQ(b, true); +} + +class Receiver { +public: + Receiver() = default; + + void Receive(int a, bool b) // NOLINT + { + counter++; + ASSERT_EQ(a, 1); + ASSERT_EQ(b, true); + } +}; + +TEST(EventTest, BasicTest) +{ + Receiver receiver; + + Event event; + ASSERT_EQ(event.BindStatic<&StaticReceiver>(), 0); + ASSERT_EQ(event.BindMember<&Receiver::Receive>(receiver), 1); + ASSERT_EQ(event.BindLambda([](int a, bool b) -> void { + counter++; + ASSERT_EQ(a, 1); + ASSERT_EQ(b, true); + }), 2); + + event.Broadcast(1, true); + ASSERT_EQ(counter, 3); +} diff --git a/Engine/Source/Mirror/Include/Mirror/Registry.h b/Engine/Source/Mirror/Include/Mirror/Registry.h index 352a11c1..4713a365 100644 --- a/Engine/Source/Mirror/Include/Mirror/Registry.h +++ b/Engine/Source/Mirror/Include/Mirror/Registry.h @@ -51,6 +51,7 @@ namespace Mirror { template ClassRegistry& StaticFunction(const Id& inId); template ClassRegistry& MemberVariable(const Id& inId); // TODO support overload + // TODO virtual function support template ClassRegistry& MemberFunction(const Id& inId); private: diff --git a/Engine/Source/Render/Src/RenderGraph.cpp b/Engine/Source/Render/Src/RenderGraph.cpp index bebb6ba8..bb421d4e 100644 --- a/Engine/Source/Render/Src/RenderGraph.cpp +++ b/Engine/Source/Render/Src/RenderGraph.cpp @@ -644,8 +644,8 @@ namespace Render { { auto collectQueueReadWrites = [this](const std::vector& passes, std::unordered_set& outReads, std::unordered_set& outWrites) -> void { for (auto* pass : passes) { - Common::SetUtils::GetUnionInline(outReads, passReadsMap.at(pass)); - Common::SetUtils::GetUnionInline(outWrites, passWritesMap.at(pass)); + Common::SetUtils::GetUnionInplace(outReads, passReadsMap.at(pass)); + Common::SetUtils::GetUnionInplace(outWrites, passWritesMap.at(pass)); } }; diff --git a/Engine/Source/Runtime/Include/Runtime/ECS.h b/Engine/Source/Runtime/Include/Runtime/ECS.h index 1fbb407a..272555ac 100644 --- a/Engine/Source/Runtime/Include/Runtime/ECS.h +++ b/Engine/Source/Runtime/Include/Runtime/ECS.h @@ -4,48 +4,256 @@ #pragma once +#include #include +#include +#include + namespace Runtime { using Entity = size_t; - using CompTypeId = size_t; +} - class CompPacket { +namespace Runtime::Internal { + using ArchetypeId = size_t; + using CompId = size_t; + + class CompOp { public: - virtual ~CompPacket(); + template static CompOp From(); + + void SetOffset(size_t inOffset); + void* Emplace(void* inElem, void* inOther) const; + void Destruct(void* inElem) const; + void* Get(void* inElem) const; + CompId GetCompId() const; + size_t GetOffset() const; + size_t GetSize() const; + + private: + using EmplaceFunc = void*(void*, size_t, void*); + using DestructFunc = void(void*, size_t); + using GetFunc = void*(void*, size_t); + + template static void* EmplaceImpl(void* inElem, size_t inOffset, void* inOther); + template static void DestructImpl(void* inElem, size_t inOffset); + template static void* GetImpl(void* inElem, size_t inOffset); - protected: - CompPacket(); + CompOp(); + + CompId compId; + size_t offset; + size_t size; + EmplaceFunc* emplace; + DestructFunc* destruct; + GetFunc* get; }; + class Archetype { + public: + explicit Archetype(const std::vector& inCompOps); + + bool Contains(CompId inCompId) const; + bool ContainsAll(const std::vector& inCompIds) const; + bool NotContainsAny(const std::vector& inCompIds) const; + void* Emplace(Entity inEntity); + void* Emplace(Entity inEntity, void* inSourceElem, const std::vector& inSourceCompOps); + void* EmplaceComp(Entity inEntity, CompId inCompId, void* inComp); + void Erase(Entity inEntity); + void* Get(Entity inEntity); + void* GetComp(Entity inEntity, CompId inCompId); + size_t Size() const; + std::vector All() const; + const std::vector& GetCompOps() const; + ArchetypeId GetArchetypeId() const; + std::vector NewArchetypeAddComp(const CompOp& inOp); + std::vector NewArchetypeRemoveComp(const CompOp& inOp); + + private: + using ElemIndex = size_t; + + const CompOp* FindCompOp(CompId inCompId) const; + size_t Capacity() const; + void Reserve(float inRatio = 1.5f); + void* AllocateNewElemBack(); + ElemIndex BackElemIndex() const; + void* GetElement(size_t inIndex); + + ArchetypeId archetypeId; + size_t size; + size_t elemSize; + std::vector compOps; + std::unordered_map entityMap; + std::unordered_map elemMap; + std::vector memory; + }; + + class EntityPool { + public: + using EntityTraverseFunc = std::function; + using ConstIter = std::set::const_iterator; + + EntityPool(); + + size_t Size() const; + bool Valid(Entity inEntity) const; + Entity Allocate(); + void Free(Entity inEntity); + void Clear(); + void Each(const EntityTraverseFunc& inFunc) const; + void SetArchetype(Entity inEntity, ArchetypeId inArchetypeId); + ArchetypeId GetArchetype(Entity inEntity) const; + ConstIter Begin() const; + ConstIter End() const; + + private: + size_t counter; + std::set free; + std::set allocated; + std::unordered_map archetypeMap; + }; +} + +namespace Runtime { + class ECRegistry; + template - class TypedCompPacket final : public CompPacket { + class ScopedUpdater { public: - ~TypedCompPacket() override; + ScopedUpdater(ECRegistry& inRegistry, Entity inEntity, C& inCompRef); + ~ScopedUpdater(); + + NonCopyable(ScopedUpdater) + NonMovable(ScopedUpdater) + + C* operator->() const; private: - friend class ECRegistry; + ECRegistry& registry; + Entity entity; + C& compRef; + }; + + template + struct Contains {}; + + template + struct Exclude {}; + + template + class View; + + template + class View, C...> { + public: + using Iter = typename std::vector>::iterator; + using ConstIter = typename std::vector>::const_iterator; - using CompIndex = size_t; + explicit View(ECRegistry& inRegistry); + NonCopyable(View) + NonMovable(View) - TypedCompPacket(); + template void Each(F&& inFunc) const; + Iter Begin(); + ConstIter Begin() const; + Iter End(); + ConstIter End() const; + Iter begin(); + ConstIter begin() const; + Iter end(); + ConstIter end() const; - std::unordered_map entityMap; - std::vector storage; + private: + void Evaluate(ECRegistry& inRegistry); + + std::vector> result; }; - class EntityContainer { + class Observer { public: + using ConstIter = std::vector::const_iterator; + using EntityTraverseFunc = Internal::EntityPool::EntityTraverseFunc; + using ReceiverDeleter = std::function; + + explicit Observer(ECRegistry& inRegistry); + ~Observer(); + NonCopyable(Observer) + NonMovable(Observer) + + template void ObConstructed(); + template void ObUpdated(); + template void ObRemove(); + void Each(const EntityTraverseFunc& inFunc) const; + void Clear(); + void Reset(); + ConstIter Begin() const; + ConstIter End() const; + ConstIter begin() const; + ConstIter end() const; private: + void OnEvent(Common::Event& inEvent); + void RecordEntity(ECRegistry& inRegistry, Entity inEntity); + + ECRegistry& registry; + std::vector> receiverHandles; + std::vector entities; }; class ECRegistry { public: + using EntityTraverseFunc = Internal::EntityPool::EntityTraverseFunc; + using ConstIter = Internal::EntityPool::ConstIter; + using CompEvent = Common::Event; + struct CompEvents { + CompEvent onConstructed; + CompEvent onUpdated; + CompEvent onRemove; + }; + + ECRegistry(); + ~ECRegistry(); + + ECRegistry(const ECRegistry& inOther); + ECRegistry(ECRegistry&& inOther) noexcept; + ECRegistry& operator=(const ECRegistry& inOther); + ECRegistry& operator=(ECRegistry&& inOther) noexcept; + + Entity Create(); + void Destroy(Entity inEntity); + bool Valid(Entity inEntity) const; + size_t Size() const; + void Clear(); + void Each(const EntityTraverseFunc& inFunc) const; + ConstIter Begin() const; + ConstIter End() const; + ConstIter begin() const; + ConstIter end() const; + + template C& Emplace(Entity inEntity, Args&&... inArgs); + template void Remove(Entity inEntity); + template void NotifyUpdated(Entity inEntity) const; + template void Update(Entity inEntity, F&& inFunc); + template ScopedUpdater Update(Entity inEntity); + template bool Has(Entity inEntity) const; + template C* Find(Entity inEntity); + template const C* Find(Entity inEntity) const; + template C& Get(Entity inEntity); + template const C& Get(Entity inEntity) const; + template View, C...> View(Exclude); + template CompEvents& Events(); + Observer Observer(); + // TODO states private: - EntityContainer entities; - std::unordered_map> compPackets; + template friend class View; + + template void NotifyConstructed(Entity inEntity) const; + template void NotifyRemove(Entity inEntity) const; + + Internal::EntityPool entities; + std::unordered_map archetypes; + std::unordered_map compEvents; }; class SystemRegistry { @@ -54,3 +262,312 @@ namespace Runtime { private: }; } + +namespace Runtime::Internal { + template + CompOp CompOp::From() + { + CompOp result; + result.compId = typeid(C).hash_code(); + result.offset = 0; + result.size = sizeof(C); + result.emplace = &EmplaceImpl; + result.destruct = &DestructImpl; + result.get = &GetImpl; + return result; + } + + template + void* CompOp::EmplaceImpl(void* inElem, size_t inOffset, void* inOther) + { + void* compBegin = static_cast(inElem) + inOffset; + new(compBegin) T(std::move(*static_cast(inOffset))); + return compBegin; + } + + template + void CompOp::DestructImpl(void* inElem, size_t inOffset) + { + void* compBegin = static_cast(inElem) + inOffset; + *static_cast(compBegin).~T(); + } + + template + void* CompOp::GetImpl(void* inElem, size_t inOffset) + { + return static_cast(inElem) + inOffset; + } +} // namespace Runtime::Internal + +namespace Runtime { + template + ScopedUpdater::ScopedUpdater(ECRegistry& inRegistry, Entity inEntity, C& inCompRef) + : registry(inRegistry) + , entity(inEntity) + , compRef(inCompRef) + { + } + + template + ScopedUpdater::~ScopedUpdater() + { + registry.NotifyUpdated(entity); + } + + template + C* ScopedUpdater::operator->() const + { + return &compRef; + } + + template + View, C...>::View(ECRegistry& inRegistry) + { + Evaluate(inRegistry); + } + + template + template + void View, C...>::Each(F&& inFunc) const + { + for (const auto& entity : result) { + std::apply(inFunc, entity); + } + } + + template + typename View, C...>::Iter View, C...>::Begin() + { + return result.begin(); + } + + template + typename View, C...>::ConstIter View, C...>::Begin() const + { + return result.begin(); + } + + template + typename View, C...>::Iter View, C...>::End() + { + return result.end(); + } + + template + typename View, C...>::ConstIter View, C...>::End() const + { + return result.end(); + } + + template + typename View, C...>::Iter View, C...>::begin() + { + return Begin(); + } + + template + typename View, C...>::ConstIter View, C...>::begin() const + { + return Begin(); + } + + template + typename View, C...>::Iter View, C...>::end() + { + return End(); + } + + template + typename View, C...>::ConstIter View, C...>::end() const + { + return End(); + } + + template + void View, C...>::Evaluate(ECRegistry& inRegistry) + { + std::vector includeCompIds; + includeCompIds.reserve(sizeof...(C)); + (void) std::initializer_list { ([&]() -> void { + includeCompIds.emplace_back(typeid(C).hash_code()); + }(), 0)... }; + + std::vector excludeCompIds; + excludeCompIds.reserve(sizeof...(E)); + (void) std::initializer_list { ([&]() -> void { + excludeCompIds.emplace_back(typeid(E).hash_code()); + }(), 0)... }; + + for (auto& [_, archetype] : inRegistry.archetypes) { + if (!archetype.ContainsAll(includeCompIds) || !archetype.NotContainsAny(excludeCompIds)) { + continue; + } + + result.reserve(result.size() + archetype.Size()); + for (auto entity : archetype.All()) { + result.emplace_back(entity, inRegistry.Get(entity)...); + } + } + } + + template + void Observer::ObConstructed() + { + OnEvent(registry.Events().onConstructed); + } + + template + void Observer::ObUpdated() + { + OnEvent(registry.Events().onUpdated); + } + + template + void Observer::ObRemove() + { + OnEvent(registry.Events().onRemove); + } + + template + C& ECRegistry::Emplace(Entity inEntity, Args&&... inArgs) + { + Assert(Valid(inEntity)); + const Internal::CompId compId = typeid(C).hash_code(); + const Internal::ArchetypeId archetypeId = entities.GetArchetype(inEntity); + Internal::Archetype& archetype = archetypes.at(archetypeId); + + const Internal::ArchetypeId newArchetypeId = archetypeId + compId; + entities.SetArchetype(inEntity, newArchetypeId); + + Internal::Archetype* newArchetype; + if (archetypes.contains(newArchetypeId)) { + newArchetype = &archetypes.at(newArchetypeId); + newArchetype->Emplace(inEntity, archetype.Get(inEntity), archetype.GetCompOps()); + archetype.Erase(inEntity); + } else { + archetypes.emplace(newArchetypeId, Internal::Archetype(archetype.NewArchetypeAddComp(Internal::CompOp::From()))); + newArchetype = &archetypes.at(newArchetypeId); + newArchetype->Emplace(inEntity); + } + + C tempObj(std::forward(inArgs)...); + return *static_cast(newArchetype->EmplaceComp(inEntity, compId, &tempObj)); + } + + template + void ECRegistry::Remove(Entity inEntity) + { + Assert(Valid(inEntity) && Has(inEntity)); + const Internal::CompId compId = typeid(C).hash_code(); + const Internal::ArchetypeId archetypeId = entities.GetArchetype(inEntity); + Internal::Archetype& archetype = archetypes.at(archetypeId); + + const Internal::ArchetypeId newArchetypeId = archetypeId - compId; + entities.SetArchetype(inEntity, newArchetypeId); + + if (!archetypes.contains(newArchetypeId)) { + archetypes.emplace(newArchetypeId, Internal::Archetype(archetype.NewArchetypeRemoveComp(Internal::CompOp::From()))); + } + Internal::Archetype& newArchetype = archetypes.at(newArchetypeId); + newArchetype.Emplace(inEntity, archetype.Get(inEntity), archetype.GetCompOps()); + archetype.Erase(inEntity); + } + + template + void ECRegistry::Update(Entity inEntity, F&& inFunc) + { + Assert(Valid(inEntity) && Has()); + inFunc(Get(inEntity)); + NotifyUpdated(inEntity); + } + + template + ScopedUpdater ECRegistry::Update(Entity inEntity) + { + Assert(Valid(inEntity) && Has()); + return ScopedUpdater(*this, inEntity, Get(inEntity)); + } + + template + bool ECRegistry::Has(Entity inEntity) const + { + Assert(Valid(inEntity)); + return archetypes + .at(entities.GetArchetype(inEntity)) + .Contains(typeid(C).hash_code()); + } + + template + C* ECRegistry::Find(Entity inEntity) + { + return Has() ? &Get(inEntity) : nullptr; + } + + template + const C* ECRegistry::Find(Entity inEntity) const + { + return Has() ? &Get(inEntity) : nullptr; + } + + template + C& ECRegistry::Get(Entity inEntity) + { + Assert(Valid(inEntity) && Has()); + void* ptr = archetypes + .at(entities.GetArchetype(inEntity)) + .GetComp(inEntity, typeid(C).hash_code()); + return *static_cast(ptr); + } + + template + const C& ECRegistry::Get(Entity inEntity) const + { + Assert(Valid(inEntity) && Has()); + const void* ptr = archetypes + .at(entities.GetArchetype(inEntity)) + .GetComp(inEntity, typeid(C).hash_code()); + return *static_cast(ptr); + } + + template + void ECRegistry::NotifyUpdated(Entity inEntity) const + { + const auto iter = compEvents.find(typeid(C).hash_code()); + if (iter == compEvents.end()) { + return; + } + iter->second.onUpdated.Broadcast(inEntity); + } + + template + void ECRegistry::NotifyConstructed(Entity inEntity) const + { + const auto iter = compEvents.find(typeid(C).hash_code()); + if (iter == compEvents.end()) { + return; + } + iter->second.onConstructed.Broadcast(inEntity); + } + + template + void ECRegistry::NotifyRemove(Entity inEntity) const + { + const auto iter = compEvents.find(typeid(C).hash_code()); + if (iter == compEvents.end()) { + return; + } + iter->second.onRemove.Broadcast(inEntity); + } + + template + View, C...> ECRegistry::View(Exclude) + { + return { *this }; + } + + template + ECRegistry::CompEvents& ECRegistry::Events() + { + return compEvents[typeid(C).hash_code()]; + } +} // namespace Runtime diff --git a/Engine/Source/Runtime/Include/Runtime/World.h b/Engine/Source/Runtime/Include/Runtime/World.h index 661c6e65..d4152313 100644 --- a/Engine/Source/Runtime/Include/Runtime/World.h +++ b/Engine/Source/Runtime/Include/Runtime/World.h @@ -4,6 +4,8 @@ #pragma once +#include + #include namespace Runtime { diff --git a/Engine/Source/Runtime/Src/ECS.cpp b/Engine/Source/Runtime/Src/ECS.cpp index b46b1327..14df2311 100644 --- a/Engine/Source/Runtime/Src/ECS.cpp +++ b/Engine/Source/Runtime/Src/ECS.cpp @@ -4,14 +4,344 @@ #include +namespace Runtime::Internal { + void CompOp::SetOffset(size_t inOffset) + { + offset = inOffset; + } + + void* CompOp::Emplace(void* inElem, void* inOther) const + { + return emplace(inElem, offset, inOther); + } + + void CompOp::Destruct(void* inElem) const + { + destruct(inElem, offset); + } + + void* CompOp::Get(void* inElem) const + { + return get(inElem, offset); + } + + CompId CompOp::GetCompId() const + { + return compId; + } + + size_t CompOp::GetOffset() const + { + return offset; + } + + size_t CompOp::GetSize() const + { + return size; + } + + CompOp::CompOp() + : compId(0) + , offset(0) + , size(0) + , emplace(nullptr) + , destruct(nullptr) + , get(nullptr) + { + } + + Archetype::Archetype(const std::vector& inCompOps) + : archetypeId(0) + , size(0) + , elemSize(0) + , compOps(inCompOps) + { + for (auto& compOp : compOps) { + archetypeId += compOp.GetCompId(); + compOp.SetOffset(elemSize); + elemSize += compOp.GetSize(); + } + } + + bool Archetype::Contains(CompId inCompId) const + { + for (const auto& compOp : compOps) { + if (compOp.GetCompId() == inCompId) { + return true; + } + } + return false; + } + + bool Archetype::ContainsAll(const std::vector& inCompIds) const + { + for (const auto& compId : inCompIds) { + if (!Contains(compId)) { + return false; + } + } + return true; + } + + bool Archetype::NotContainsAny(const std::vector& inCompIds) const + { + for (const auto& compId : inCompIds) { + if (Contains(compId)) { + return false; + } + } + return true; + } + + void* Archetype::Emplace(Entity inEntity) + { + if (Size() == Capacity()) { + Reserve(); + } + auto* result = AllocateNewElemBack(); + auto backElem = BackElemIndex(); + entityMap.emplace(inEntity, backElem); + elemMap.emplace(backElem, inEntity); + return result; + } + + void* Archetype::Emplace(Entity inEntity, void* inSourceElem, const std::vector& inSourceCompOps) + { + void* newElem = Emplace(inEntity); + for (const auto& sourceCompOp : inSourceCompOps) { + const auto* newCompOp = FindCompOp(sourceCompOp.GetCompId()); + if (newCompOp == nullptr) { + continue; + } + newCompOp->Emplace(newElem, sourceCompOp.Get(inSourceElem)); + } + return newElem; + } + + EntityPool::EntityPool() + : counter() + { + } + + size_t EntityPool::Size() const + { + return allocated.size(); + } + + bool EntityPool::Valid(Entity inEntity) const + { + return allocated.contains(inEntity); + } + + Entity EntityPool::Allocate() + { + if (!free.empty()) { + const Entity result = *free.begin(); + free.erase(result); + return result; + } else { + const Entity result = counter++; + allocated.emplace(result); + return result; + } + } + + void EntityPool::Free(Entity inEntity) + { + Assert(Valid(inEntity)); + allocated.erase(inEntity); + free.emplace(inEntity); + } + + void EntityPool::Clear() + { + counter = 0; + free.clear(); + allocated.clear(); + } + + void EntityPool::Each(const EntityTraverseFunc& inFunc) const + { + for (const auto& entity : allocated) { + inFunc(entity); + } + } + + void EntityPool::SetArchetype(Entity inEntity, ArchetypeId inArchetypeId) + { + archetypeMap[inEntity] = inArchetypeId; + } + + ArchetypeId EntityPool::GetArchetype(Entity inEntity) const + { + return archetypeMap.at(inEntity); + } + + EntityPool::ConstIter EntityPool::Begin() const + { + return allocated.begin(); + } + + EntityPool::ConstIter EntityPool::End() const + { + return allocated.end(); + } +} // namespace Runtime::Internal + namespace Runtime { - CompPacket::~CompPacket() = default; + Observer::Observer(ECRegistry& inRegistry) + : registry(inRegistry) + { + } + + Observer::~Observer() + { + Reset(); + } + + void Observer::Each(const EntityTraverseFunc& inFunc) const + { + for (const auto& entity : entities) { + inFunc(entity); + } + } + + void Observer::Clear() + { + entities.clear(); + } + + void Observer::Reset() + { + for (auto& [handle, deleter] : receiverHandles) { + deleter(); + } + receiverHandles.clear(); + } + + Observer::ConstIter Observer::Begin() const + { + return entities.begin(); + } + + Observer::ConstIter Observer::End() const + { + return entities.end(); + } + + Observer::ConstIter Observer::begin() const + { + return Begin(); + } + + Observer::ConstIter Observer::end() const + { + return End(); + } + + void Observer::RecordEntity(ECRegistry& inRegistry, Entity inEntity) + { + entities.emplace_back(inEntity); + } + + void Observer::OnEvent(Common::Event& inEvent) + { + const auto handle = inEvent.BindMember<&Observer::RecordEntity>(*this); + receiverHandles.emplace_back( + handle, + [&]() -> void { + inEvent.Unbind(handle); + }); + } + + ECRegistry::ECRegistry() = default; + + ECRegistry::~ECRegistry() = default; + + ECRegistry::ECRegistry(const ECRegistry& inOther) + : entities(inOther.entities) + , archetypes(inOther.archetypes) + , compEvents(inOther.compEvents) + { + } + + ECRegistry::ECRegistry(ECRegistry&& inOther) noexcept + : entities(std::move(inOther.entities)) + , archetypes(std::move(inOther.archetypes)) + , compEvents(std::move(inOther.compEvents)) + { + } + + ECRegistry& ECRegistry::operator=(const ECRegistry& inOther) + { + entities = inOther.entities; + archetypes = inOther.archetypes; + compEvents = inOther.compEvents; + return *this; + } + + ECRegistry& ECRegistry::operator=(ECRegistry&& inOther) noexcept + { + entities = std::move(inOther.entities); + archetypes = std::move(inOther.archetypes); + compEvents = std::move(inOther.compEvents); + return *this; + } + + Entity ECRegistry::Create() + { + return entities.Allocate(); + } + + void ECRegistry::Destroy(Entity inEntity) + { + entities.Free(inEntity); + } + + bool ECRegistry::Valid(Entity inEntity) const + { + return entities.Valid(inEntity); + } + + size_t ECRegistry::Size() const + { + return entities.Size(); + } + + void ECRegistry::Clear() + { + entities.Clear(); + archetypes.clear(); + compEvents.clear(); + } + + void ECRegistry::Each(const EntityTraverseFunc& inFunc) const + { + return entities.Each(inFunc); + } + + ECRegistry::ConstIter ECRegistry::Begin() const + { + return entities.Begin(); + } + + ECRegistry::ConstIter ECRegistry::End() const + { + return entities.End(); + } - CompPacket::CompPacket() = default; + ECRegistry::ConstIter ECRegistry::begin() const + { + return Begin(); + } - template - TypedCompPacket::~TypedCompPacket() = default; + ECRegistry::ConstIter ECRegistry::end() const + { + return End(); + } - template - TypedCompPacket::TypedCompPacket() = default; -} + Observer ECRegistry::Observer() + { + return Runtime::Observer { *this }; + } +} // namespace Runtime From 9ac919394f0990a384d5b12acfc645ed6e589bc7 Mon Sep 17 00:00:00 2001 From: John Kindem <461425614@qq.com> Date: Sun, 10 Nov 2024 19:12:20 +0800 Subject: [PATCH 10/22] feat: delete x86_64 macos support --- CMake/ThirdParty.cmake | 2 +- README.md | 2 +- ThirdParty/CMakeLists.txt | 3 --- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/CMake/ThirdParty.cmake b/CMake/ThirdParty.cmake index 4bb15159..0c9b910c 100644 --- a/CMake/ThirdParty.cmake +++ b/CMake/ThirdParty.cmake @@ -66,7 +66,7 @@ function(Get3rdPlatformValue) cmake_parse_arguments(PARAMS "ARCH" "OUTPUT" "INPUT" ${ARGN}) if (${PARAMS_ARCH}) - set(PLATFORM_KEYWORDS "Windows-AMD64;Darwin-arm64;Darwin-x86_64") + set(PLATFORM_KEYWORDS "Windows-AMD64;Darwin-arm64") set(CURRENT_KEYWORDS "${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}") else() set(PLATFORM_KEYWORDS "Windows;Darwin;Linux") diff --git a/README.md b/README.md index e6c8c741..daa6a59e 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ We use cmake as build tool, the following table contains supported platform, too macOS - x64 / arm64 + arm64 Apple Clang Unix Makefiles diff --git a/ThirdParty/CMakeLists.txt b/ThirdParty/CMakeLists.txt index 8d4e5a43..88eacc71 100644 --- a/ThirdParty/CMakeLists.txt +++ b/ThirdParty/CMakeLists.txt @@ -99,17 +99,14 @@ Add3rdBinaryPackage( ARCH VERSION Windows-AMD64 17.0.4 - Darwin-x86_64 15.0.7 Darwin-arm64 15.0.7 HASH Windows-AMD64 3443a2259d092797521bde0c4b6e402ddeca4beb0abd87274ece91ac44b178ce - Darwin-x86_64 75b45dda76d52fcf7f3253aedea1f7327eb2aca37871b287d89234b55bde5504 Darwin-arm64 99a4884945674163374d99c2220cadbfe20a947b1217193140c6b6638a3b0627 INCLUDE $/include LINK $/lib LIB Windows-AMD64 libclang - Darwin-x86_64 clang Darwin-arm64 clang RUNTIME_DEP Windows $/bin/libclang.dll From 7d2c9bc250e9b7fd5ef6a9ef2d1360f95a97d4bf Mon Sep 17 00:00:00 2001 From: John Kindem <461425614@qq.com> Date: Sun, 10 Nov 2024 20:46:49 +0800 Subject: [PATCH 11/22] feat: new gameplay framework --- Engine/Source/Common/Include/Common/Event.h | 12 +- Engine/Source/Mirror/Include/Mirror/Mirror.h | 9 +- .../Source/Mirror/Include/Mirror/Registry.h | 1 + Engine/Source/Mirror/Src/Mirror.cpp | 8 +- Engine/Source/Runtime/Include/Runtime/ECS.h | 505 ++++++++++++++---- Engine/Source/Runtime/Src/ECS.cpp | 310 +++++++++-- 6 files changed, 673 insertions(+), 172 deletions(-) diff --git a/Engine/Source/Common/Include/Common/Event.h b/Engine/Source/Common/Include/Common/Event.h index 4bd10dca..3633babd 100644 --- a/Engine/Source/Common/Include/Common/Event.h +++ b/Engine/Source/Common/Include/Common/Event.h @@ -47,7 +47,7 @@ namespace Common { Event(); template ReceiverHandle BindStatic(); - template ReceiverHandle BindMember(C&& inObj); + template ReceiverHandle BindMember(C& inObj); template ReceiverHandle BindLambda(F&& inLambda); template void Broadcast(Args&&... inArgs) const; void Unbind(ReceiverHandle inHandle); @@ -56,7 +56,7 @@ namespace Common { private: template void BindStaticInternal(ReceiverHandle inHandle, std::index_sequence); - template void BindMemberInternal(ReceiverHandle inHandle, C&& inObj, std::index_sequence); + template void BindMemberInternal(ReceiverHandle inHandle, C& inObj, std::index_sequence); template void BindLambdaInternal(ReceiverHandle inHandle, F&& inLambda, std::index_sequence); ReceiverHandle counter; @@ -82,10 +82,10 @@ namespace Common { template template - ReceiverHandle Event::BindMember(C&& inObj) + ReceiverHandle Event::BindMember(C& inObj) { const auto handle = counter++; - BindMemberInternal(handle, std::forward(inObj), std::make_index_sequence()); + BindMemberInternal(handle, inObj, std::make_index_sequence()); return handle; } @@ -137,9 +137,9 @@ namespace Common { template template - void Event::BindMemberInternal(ReceiverHandle inHandle, C&& inObj, std::index_sequence) + void Event::BindMemberInternal(ReceiverHandle inHandle, C& inObj, std::index_sequence) { - receivers.emplace_back(inHandle, std::bind(F, std::forward(inObj), Internal::IndexToStdPlaceholder::value...)); + receivers.emplace_back(inHandle, std::bind(F, &inObj, Internal::IndexToStdPlaceholder::value...)); } template diff --git a/Engine/Source/Mirror/Include/Mirror/Mirror.h b/Engine/Source/Mirror/Include/Mirror/Mirror.h index 282e466d..8cb2b336 100644 --- a/Engine/Source/Mirror/Include/Mirror/Mirror.h +++ b/Engine/Source/Mirror/Include/Mirror/Mirror.h @@ -574,7 +574,7 @@ namespace Mirror { const Id& GetOwnerId() const; const Class& GetOwner() const; FieldAccess GetAccess() const; - uint32_t SizeOf() const; + size_t SizeOf() const; const TypeInfo* GetTypeInfo() const; void SetDyn(const Argument& object, const Argument& value) const; Any GetDyn(const Argument& object) const; @@ -591,7 +591,7 @@ namespace Mirror { Id id; Id owner; FieldAccess access; - uint32_t memorySize; + size_t memorySize; const TypeInfo* typeInfo; Setter setter; Getter getter; @@ -601,7 +601,7 @@ namespace Mirror { Id owner; FieldAccess access; - uint32_t memorySize; + size_t memorySize; const TypeInfo* typeInfo; Setter setter; Getter getter; @@ -710,6 +710,7 @@ namespace Mirror { void ForEachMemberVariable(const MemberVariableTraverser& func) const; void ForEachMemberFunction(const MemberFunctionTraverser& func) const; const TypeInfo* GetTypeInfo() const; + size_t SizeOf() const; bool HasDefaultConstructor() const; const Class* GetBaseClass() const; bool IsBaseOf(const Class* derivedClass) const; @@ -752,6 +753,7 @@ namespace Mirror { struct ConstructParams { Id id; const TypeInfo* typeInfo; + size_t memorySize; BaseClassGetter baseClassGetter; std::function defaultObjectCreator; std::optional destructorParams; @@ -769,6 +771,7 @@ namespace Mirror { MemberFunction& EmplaceMemberFunction(const Id& inId, MemberFunction::ConstructParams&& inParams); const TypeInfo* typeInfo; + size_t memorySize; BaseClassGetter baseClassGetter; Any defaultObject; std::optional destructor; diff --git a/Engine/Source/Mirror/Include/Mirror/Registry.h b/Engine/Source/Mirror/Include/Mirror/Registry.h index 4713a365..e00e6ca8 100644 --- a/Engine/Source/Mirror/Include/Mirror/Registry.h +++ b/Engine/Source/Mirror/Include/Mirror/Registry.h @@ -494,6 +494,7 @@ namespace Mirror { Class::ConstructParams params; params.id = inId; params.typeInfo = GetTypeInfo(); + params.memorySize = sizeof(C); params.baseClassGetter = []() -> const Mirror::Class* { if constexpr (std::is_void_v) { return nullptr; diff --git a/Engine/Source/Mirror/Src/Mirror.cpp b/Engine/Source/Mirror/Src/Mirror.cpp index eeedf037..3a612e5f 100644 --- a/Engine/Source/Mirror/Src/Mirror.cpp +++ b/Engine/Source/Mirror/Src/Mirror.cpp @@ -1068,7 +1068,7 @@ namespace Mirror { return access; } - uint32_t MemberVariable::SizeOf() const + size_t MemberVariable::SizeOf() const { return memorySize; } @@ -1231,6 +1231,7 @@ namespace Mirror { Class::Class(ConstructParams&& params) : ReflNode(std::move(params.id)) , typeInfo(params.typeInfo) + , memorySize(params.memorySize) , baseClassGetter(std::move(params.baseClassGetter)) { CreateDefaultObject(params.defaultObjectCreator); @@ -1414,6 +1415,11 @@ namespace Mirror { return typeInfo; } + size_t Class::SizeOf() const + { + return memorySize; + } + bool Class::HasDefaultConstructor() const { return HasConstructor(IdPresets::defaultCtor); diff --git a/Engine/Source/Runtime/Include/Runtime/ECS.h b/Engine/Source/Runtime/Include/Runtime/ECS.h index 272555ac..2088d7c9 100644 --- a/Engine/Source/Runtime/Include/Runtime/ECS.h +++ b/Engine/Source/Runtime/Include/Runtime/ECS.h @@ -9,80 +9,94 @@ #include #include +#include namespace Runtime { using Entity = size_t; } namespace Runtime::Internal { - using ArchetypeId = size_t; - using CompId = size_t; + using ArchetypeId = Mirror::TypeId; + using CompClass = const Mirror::Class*; + using GlobalCompClass = const Mirror::Class*; + using ElemPtr = void*; - class CompOp { - public: - template static CompOp From(); + template const Mirror::Class* GetClass(); + template struct LambdaTraits; - void SetOffset(size_t inOffset); - void* Emplace(void* inElem, void* inOther) const; - void Destruct(void* inElem) const; - void* Get(void* inElem) const; - CompId GetCompId() const; - size_t GetOffset() const; - size_t GetSize() const; + class CompRtti { + public: + template CompRtti From(); + + void Bind(size_t inOffset); + Mirror::Any MoveConstruct(ElemPtr inElem, const Mirror::Argument& inOther) const; + Mirror::Any MoveAssign(ElemPtr inElem, const Mirror::Argument& inOther) const; + void Destruct(ElemPtr inElem) const; + Mirror::Any Get(ElemPtr inElem) const; + CompClass Class() const; + size_t Offset() const; + size_t Size() const; private: - using EmplaceFunc = void*(void*, size_t, void*); - using DestructFunc = void(void*, size_t); - using GetFunc = void*(void*, size_t); - - template static void* EmplaceImpl(void* inElem, size_t inOffset, void* inOther); - template static void DestructImpl(void* inElem, size_t inOffset); - template static void* GetImpl(void* inElem, size_t inOffset); - - CompOp(); - - CompId compId; - size_t offset; - size_t size; - EmplaceFunc* emplace; - DestructFunc* destruct; + using MoveConstructFunc = Mirror::Any(ElemPtr, size_t, const Mirror::Argument&); + using MoveAssignFunc = Mirror::Any(ElemPtr, size_t, const Mirror::Argument&); + using DestructorFunc = void(ElemPtr, size_t); + using GetFunc = Mirror::Any(ElemPtr, size_t); + + template static Mirror::Any MoveConstructImpl(ElemPtr inElem, size_t inOffset, const Mirror::Argument& inOther); + template static Mirror::Any MoveAssignImpl(ElemPtr inElem, size_t inOffset, const Mirror::Argument& inOther); + template static void DestructImpl(ElemPtr inElem, size_t inOffset); + template static Mirror::Any GetImpl(ElemPtr inElem, size_t inOffset); + + CompRtti(); + + CompClass clazz; + MoveConstructFunc* moveConstruct; + MoveAssignFunc* moveAssign; + DestructorFunc* destructor; GetFunc* get; + // runtime, need Bind() + bool bound; + size_t offset; }; class Archetype { public: - explicit Archetype(const std::vector& inCompOps); - - bool Contains(CompId inCompId) const; - bool ContainsAll(const std::vector& inCompIds) const; - bool NotContainsAny(const std::vector& inCompIds) const; - void* Emplace(Entity inEntity); - void* Emplace(Entity inEntity, void* inSourceElem, const std::vector& inSourceCompOps); - void* EmplaceComp(Entity inEntity, CompId inCompId, void* inComp); - void Erase(Entity inEntity); - void* Get(Entity inEntity); - void* GetComp(Entity inEntity, CompId inCompId); + explicit Archetype(const std::vector& inRttiVec); + + bool Contains(CompClass inClazz) const; + bool ContainsAll(const std::vector& inClasses) const; + bool NotContainsAny(const std::vector& inCompClasses) const; + ElemPtr EmplaceElem(Entity inEntity); + ElemPtr EmplaceElem(Entity inEntity, ElemPtr inSrcElem, const std::vector& inSrcRttiVec); + Mirror::Any EmplaceComp(Entity inEntity, CompClass inCompClass, Mirror::Any inComp); + void EraseElem(Entity inEntity); + ElemPtr GetElem(Entity inEntity); + Mirror::Any GetComp(Entity inEntity, CompClass inCompClass); size_t Size() const; - std::vector All() const; - const std::vector& GetCompOps() const; - ArchetypeId GetArchetypeId() const; - std::vector NewArchetypeAddComp(const CompOp& inOp); - std::vector NewArchetypeRemoveComp(const CompOp& inOp); + auto All() const; + const std::vector& GetRttiVec() const; + ArchetypeId Id() const; + std::vector NewRttiVecByAdd(const CompRtti& inRtti) const; + std::vector NewRttiVecByRemove(const CompRtti& inRtti) const; private: + using CompRttiIndex = size_t; using ElemIndex = size_t; - const CompOp* FindCompOp(CompId inCompId) const; + const CompRtti* FindCompRtti(CompClass clazz) const; + const CompRtti& GetCompRtti(CompClass clazz) const; size_t Capacity() const; void Reserve(float inRatio = 1.5f); - void* AllocateNewElemBack(); - ElemIndex BackElemIndex() const; - void* GetElement(size_t inIndex); + ElemPtr AllocateNewElemBack(); + ElemPtr ElemAt(std::vector& inMemory, size_t inIndex); + ElemPtr ElemAt(size_t inIndex); - ArchetypeId archetypeId; + ArchetypeId id; size_t size; size_t elemSize; - std::vector compOps; + std::vector rttiVec; + std::unordered_map rttiMap; std::unordered_map entityMap; std::unordered_map elemMap; std::vector memory; @@ -134,6 +148,22 @@ namespace Runtime { C& compRef; }; + template + class GScopedUpdater { + public: + GScopedUpdater(ECRegistry& inRegistry, G& inGlobalCompRef); + ~GScopedUpdater(); + + NonCopyable(GScopedUpdater) + NonMovable(GScopedUpdater) + + G* operator->() const; + + private: + ECRegistry& registry; + G& globalCompRef; + }; + template struct Contains {}; @@ -146,22 +176,19 @@ namespace Runtime { template class View, C...> { public: - using Iter = typename std::vector>::iterator; - using ConstIter = typename std::vector>::const_iterator; - explicit View(ECRegistry& inRegistry); NonCopyable(View) NonMovable(View) template void Each(F&& inFunc) const; - Iter Begin(); - ConstIter Begin() const; - Iter End(); - ConstIter End() const; - Iter begin(); - ConstIter begin() const; - Iter end(); - ConstIter end() const; + auto Begin(); + auto Begin() const; + auto End(); + auto End() const; + auto begin(); + auto begin() const; + auto end(); + auto end() const; private: void Evaluate(ECRegistry& inRegistry); @@ -169,6 +196,45 @@ namespace Runtime { std::vector> result; }; + class RuntimeViewRule { + public: + RuntimeViewRule(); + template RuntimeViewRule& Include(); + template RuntimeViewRule& Exclude(); + + private: + friend class RuntimeView; + + std::unordered_set includes; + std::unordered_set excludes; + }; + + class RuntimeView { + public: + explicit RuntimeView(ECRegistry& inRegistry, const RuntimeViewRule& inArgs); + NonCopyable(RuntimeView) + NonMovable(RuntimeView) + + template void Each(F&& inFunc) const; + auto Begin(); + auto Begin() const; + auto End(); + auto End() const; + auto begin(); + auto begin() const; + auto end(); + auto end() const; + + private: + template void InvokeTraverseFuncInternal(F&& inFunc, std::pair>& inEntityAndComps, std::index_sequence) const; + template decltype(auto) GetCompRef(std::vector& inComps) const; + void Evaluate(ECRegistry& inRegistry, const RuntimeViewRule& inArgs); + + std::unordered_map slotMap; + std::vector resultEntities; + std::vector>> result; + }; + class Observer { public: using ConstIter = std::vector::const_iterator; @@ -205,12 +271,20 @@ namespace Runtime { using EntityTraverseFunc = Internal::EntityPool::EntityTraverseFunc; using ConstIter = Internal::EntityPool::ConstIter; using CompEvent = Common::Event; + using GCompEvent = Common::Event; + struct CompEvents { CompEvent onConstructed; CompEvent onUpdated; CompEvent onRemove; }; + struct GCompEvents { + GCompEvent onConstructed; + GCompEvent onUpdated; + GCompEvent onRemove; + }; + ECRegistry(); ~ECRegistry(); @@ -219,6 +293,7 @@ namespace Runtime { ECRegistry& operator=(const ECRegistry& inOther); ECRegistry& operator=(ECRegistry&& inOther) noexcept; + // entity Entity Create(); void Destroy(Entity inEntity); bool Valid(Entity inEntity) const; @@ -230,6 +305,7 @@ namespace Runtime { ConstIter begin() const; ConstIter end() const; + // component template C& Emplace(Entity inEntity, Args&&... inArgs); template void Remove(Entity inEntity); template void NotifyUpdated(Entity inEntity) const; @@ -242,18 +318,36 @@ namespace Runtime { template const C& Get(Entity inEntity) const; template View, C...> View(Exclude); template CompEvents& Events(); + RuntimeView RuntimeView(const RuntimeViewRule& inRule); Observer Observer(); - // TODO states + + // global component + template void GEmplace(Args&&... inArgs); + template void GRemove(); + template void GNotifyUpdated() const; + template void GUpdate(F&& inFunc); + template GScopedUpdater GUpdate(); + template bool GHas() const; + template G* GFind(); + template const G* GFind() const; + template G& GGet(); + template const G& GGet() const; + template GCompEvents& GEvents(); private: template friend class View; + friend class RuntimeView; template void NotifyConstructed(Entity inEntity) const; template void NotifyRemove(Entity inEntity) const; + template void GNotifyConstructed() const; + template void GNotifyRemove() const; Internal::EntityPool entities; + std::unordered_map globalComps; std::unordered_map archetypes; - std::unordered_map compEvents; + std::unordered_map compEvents; + std::unordered_map globalCompEvents; }; class SystemRegistry { @@ -264,38 +358,60 @@ namespace Runtime { } namespace Runtime::Internal { + template + const Mirror::Class* GetClass() + { + return &Mirror::Class::Get(); + } + + template + struct LambdaTraits> { + static constexpr auto ArgSize = sizeof...(T); + using ArgsTupleType = std::tuple; + }; + template - CompOp CompOp::From() + CompRtti CompRtti::From() { - CompOp result; - result.compId = typeid(C).hash_code(); - result.offset = 0; - result.size = sizeof(C); - result.emplace = &EmplaceImpl; - result.destruct = &DestructImpl; + CompRtti result; + result.clazz = Internal::GetClass(); + result.moveConstruct = &MoveConstructImpl; + result.moveAssign = &MoveAssignImpl; + result.destructor = &DestructImpl; result.get = &GetImpl; + result.bound = false; + result.offset = 0; return result; } template - void* CompOp::EmplaceImpl(void* inElem, size_t inOffset, void* inOther) + Mirror::Any CompRtti::MoveConstructImpl(ElemPtr inElem, size_t inOffset, const Mirror::Argument& inOther) { void* compBegin = static_cast(inElem) + inOffset; - new(compBegin) T(std::move(*static_cast(inOffset))); - return compBegin; + new(compBegin) T(std::move(inOther.As())); + return GetImpl(inElem, inOffset); } template - void CompOp::DestructImpl(void* inElem, size_t inOffset) + Mirror::Any CompRtti::MoveAssignImpl(ElemPtr inElem, size_t inOffset, const Mirror::Argument& inOther) { - void* compBegin = static_cast(inElem) + inOffset; - *static_cast(compBegin).~T(); + auto compRef = GetImpl(inElem, inOffset); + compRef.template As() = std::move(inOther.As()); + return compRef; } template - void* CompOp::GetImpl(void* inElem, size_t inOffset) + void CompRtti::DestructImpl(ElemPtr inElem, size_t inOffset) { - return static_cast(inElem) + inOffset; + auto compRef = GetImpl(inElem, inOffset); + compRef.template As().~T(); + } + + template + Mirror::Any CompRtti::GetImpl(ElemPtr inElem, size_t inOffset) + { + void* compBegin = static_cast(inElem) + inOffset; + return { std::ref(*static_cast(compBegin)) }; } } // namespace Runtime::Internal @@ -320,6 +436,25 @@ namespace Runtime { return &compRef; } + template + GScopedUpdater::GScopedUpdater(ECRegistry& inRegistry, G& inGlobalCompRef) + : registry(inRegistry) + , globalCompRef(inGlobalCompRef) + { + } + + template + GScopedUpdater::~GScopedUpdater() + { + registry.GNotifyUpdated(); + } + + template + G* GScopedUpdater::operator->() const + { + return &globalCompRef; + } + template View, C...>::View(ECRegistry& inRegistry) { @@ -336,49 +471,49 @@ namespace Runtime { } template - typename View, C...>::Iter View, C...>::Begin() + auto View, C...>::Begin() { return result.begin(); } template - typename View, C...>::ConstIter View, C...>::Begin() const + auto View, C...>::Begin() const { return result.begin(); } template - typename View, C...>::Iter View, C...>::End() + auto View, C...>::End() { return result.end(); } template - typename View, C...>::ConstIter View, C...>::End() const + auto View, C...>::End() const { return result.end(); } template - typename View, C...>::Iter View, C...>::begin() + auto View, C...>::begin() { return Begin(); } template - typename View, C...>::ConstIter View, C...>::begin() const + auto View, C...>::begin() const { return Begin(); } template - typename View, C...>::Iter View, C...>::end() + auto View, C...>::end() { return End(); } template - typename View, C...>::ConstIter View, C...>::end() const + auto View, C...>::end() const { return End(); } @@ -386,16 +521,16 @@ namespace Runtime { template void View, C...>::Evaluate(ECRegistry& inRegistry) { - std::vector includeCompIds; + std::vector includeCompIds; includeCompIds.reserve(sizeof...(C)); (void) std::initializer_list { ([&]() -> void { - includeCompIds.emplace_back(typeid(C).hash_code()); + includeCompIds.emplace_back(Internal::GetClass()); }(), 0)... }; - std::vector excludeCompIds; + std::vector excludeCompIds; excludeCompIds.reserve(sizeof...(E)); (void) std::initializer_list { ([&]() -> void { - excludeCompIds.emplace_back(typeid(E).hash_code()); + excludeCompIds.emplace_back(Internal::GetClass()); }(), 0)... }; for (auto& [_, archetype] : inRegistry.archetypes) { @@ -410,6 +545,46 @@ namespace Runtime { } } + template + void RuntimeView::Each(F&& inFunc) const + { + for (const auto& pair : result) { + InvokeTraverseFuncInternal::ArgsTupleType>(std::forward(inFunc), pair, std::make_index_sequence::ArgSize> {}); + } + } + + template + void RuntimeView::InvokeTraverseFuncInternal(F&& inFunc, std::pair>& inEntityAndComps, std::index_sequence) const + { + inFunc(inEntityAndComps.first, GetCompRef>(inEntityAndComps.second)...); + } + + template + decltype(auto) RuntimeView::GetCompRef(std::vector& inComps) const + { + static_assert(std::is_reference_v); + const auto compIndex = slotMap.at(Internal::GetClass()); + return *static_cast>>(inComps[compIndex]); + } + + template + RuntimeViewRule& RuntimeViewRule::Include() + { + const auto* clazz = Internal::GetClass(); + Assert(!includes.contains(clazz)); + includes.emplace(clazz); + return *this; + } + + template + RuntimeViewRule& RuntimeViewRule::Exclude() + { + const auto* clazz = Internal::GetClass(); + Assert(!excludes.contains(clazz)); + excludes.emplace(clazz); + return *this; + } + template void Observer::ObConstructed() { @@ -432,45 +607,48 @@ namespace Runtime { C& ECRegistry::Emplace(Entity inEntity, Args&&... inArgs) { Assert(Valid(inEntity)); - const Internal::CompId compId = typeid(C).hash_code(); + const auto* clazz = Internal::GetClass(); const Internal::ArchetypeId archetypeId = entities.GetArchetype(inEntity); Internal::Archetype& archetype = archetypes.at(archetypeId); - const Internal::ArchetypeId newArchetypeId = archetypeId + compId; + const Internal::ArchetypeId newArchetypeId = archetypeId + clazz->GetTypeInfo()->id; entities.SetArchetype(inEntity, newArchetypeId); Internal::Archetype* newArchetype; if (archetypes.contains(newArchetypeId)) { newArchetype = &archetypes.at(newArchetypeId); - newArchetype->Emplace(inEntity, archetype.Get(inEntity), archetype.GetCompOps()); - archetype.Erase(inEntity); + newArchetype->EmplaceElem(inEntity, archetype.GetElem(inEntity), archetype.GetRttiVec()); + archetype.EraseElem(inEntity); } else { - archetypes.emplace(newArchetypeId, Internal::Archetype(archetype.NewArchetypeAddComp(Internal::CompOp::From()))); + archetypes.emplace(newArchetypeId, Internal::Archetype(archetype.NewRttiVecByAdd(Internal::CompRtti::From()))); newArchetype = &archetypes.at(newArchetypeId); - newArchetype->Emplace(inEntity); + newArchetype->EmplaceElem(inEntity); } C tempObj(std::forward(inArgs)...); - return *static_cast(newArchetype->EmplaceComp(inEntity, compId, &tempObj)); + auto& result = *static_cast(newArchetype->EmplaceComp(inEntity, clazz, &tempObj)); + NotifyConstructed(inEntity); + return result; } template void ECRegistry::Remove(Entity inEntity) { Assert(Valid(inEntity) && Has(inEntity)); - const Internal::CompId compId = typeid(C).hash_code(); + const auto* clazz = Internal::GetClass(); const Internal::ArchetypeId archetypeId = entities.GetArchetype(inEntity); Internal::Archetype& archetype = archetypes.at(archetypeId); - const Internal::ArchetypeId newArchetypeId = archetypeId - compId; + const Internal::ArchetypeId newArchetypeId = archetypeId - clazz->GetTypeInfo()->id; entities.SetArchetype(inEntity, newArchetypeId); if (!archetypes.contains(newArchetypeId)) { - archetypes.emplace(newArchetypeId, Internal::Archetype(archetype.NewArchetypeRemoveComp(Internal::CompOp::From()))); + archetypes.emplace(newArchetypeId, Internal::Archetype(archetype.NewRttiVecByRemove(Internal::CompRtti::From()))); } + NotifyRemove(inEntity); Internal::Archetype& newArchetype = archetypes.at(newArchetypeId); - newArchetype.Emplace(inEntity, archetype.Get(inEntity), archetype.GetCompOps()); - archetype.Erase(inEntity); + newArchetype.EmplaceElem(inEntity, archetype.GetElem(inEntity), archetype.GetRttiVec()); + archetype.EraseElem(inEntity); } template @@ -485,7 +663,7 @@ namespace Runtime { ScopedUpdater ECRegistry::Update(Entity inEntity) { Assert(Valid(inEntity) && Has()); - return ScopedUpdater(*this, inEntity, Get(inEntity)); + return { *this, inEntity, Get(inEntity) }; } template @@ -494,7 +672,7 @@ namespace Runtime { Assert(Valid(inEntity)); return archetypes .at(entities.GetArchetype(inEntity)) - .Contains(typeid(C).hash_code()); + .Contains(Internal::GetClass()); } template @@ -515,7 +693,7 @@ namespace Runtime { Assert(Valid(inEntity) && Has()); void* ptr = archetypes .at(entities.GetArchetype(inEntity)) - .GetComp(inEntity, typeid(C).hash_code()); + .GetComp(inEntity, Internal::GetClass()); return *static_cast(ptr); } @@ -525,14 +703,26 @@ namespace Runtime { Assert(Valid(inEntity) && Has()); const void* ptr = archetypes .at(entities.GetArchetype(inEntity)) - .GetComp(inEntity, typeid(C).hash_code()); + .GetComp(inEntity, Internal::GetClass()); return *static_cast(ptr); } + template + View, C...> ECRegistry::View(Exclude) + { + return { *this }; + } + + template + ECRegistry::CompEvents& ECRegistry::Events() + { + return compEvents[Internal::GetClass()]; + } + template void ECRegistry::NotifyUpdated(Entity inEntity) const { - const auto iter = compEvents.find(typeid(C).hash_code()); + const auto iter = compEvents.find(Internal::GetClass()); if (iter == compEvents.end()) { return; } @@ -542,7 +732,7 @@ namespace Runtime { template void ECRegistry::NotifyConstructed(Entity inEntity) const { - const auto iter = compEvents.find(typeid(C).hash_code()); + const auto iter = compEvents.find(Internal::GetClass()); if (iter == compEvents.end()) { return; } @@ -552,22 +742,109 @@ namespace Runtime { template void ECRegistry::NotifyRemove(Entity inEntity) const { - const auto iter = compEvents.find(typeid(C).hash_code()); + const auto iter = compEvents.find(Internal::GetClass()); if (iter == compEvents.end()) { return; } iter->second.onRemove.Broadcast(inEntity); } - template - View, C...> ECRegistry::View(Exclude) + template + void ECRegistry::GEmplace(Args&&... inArgs) { - return { *this }; + Assert(!GHas()); + globalComps.emplace(Internal::GetClass(), Mirror::Any(G(std::forward(inArgs))...)); + GNotifyConstructed(); } - template - ECRegistry::CompEvents& ECRegistry::Events() + template + void ECRegistry::GRemove() + { + Assert(GHas()); + GNotifyRemove(); + globalComps.erase(Internal::GetClass()); + } + + template + void ECRegistry::GUpdate(F&& inFunc) + { + Assert(GHas()); + inFunc(GGet()); + GNotifyUpdated(); + } + + template + GScopedUpdater ECRegistry::GUpdate() + { + Assert(GHas()); + return { *this, GGet() }; + } + + template + bool ECRegistry::GHas() const + { + return globalComps.contains(Internal::GetClass()); + } + + template + G* ECRegistry::GFind() + { + return GHas() ? &GGet() : nullptr; + } + + template + const G* ECRegistry::GFind() const + { + return GHas() ? &GGet() : nullptr; + } + + template + G& ECRegistry::GGet() { - return compEvents[typeid(C).hash_code()]; + Assert(GHas()); + return globalComps.at(Internal::GetClass()).template As(); + } + + template + const G& ECRegistry::GGet() const + { + Assert(GHas()); + return globalComps.at(Internal::GetClass()).template As(); + } + + template + ECRegistry::GCompEvents& ECRegistry::GEvents() + { + return globalCompEvents[Internal::GetClass()]; + } + + template + void ECRegistry::GNotifyUpdated() const + { + const auto iter = globalCompEvents.find(Internal::GetClass()); + if (iter == globalCompEvents.end()) { + return; + } + iter->second.onUpdated.Broadcast(); + } + + template + void ECRegistry::GNotifyConstructed() const + { + const auto iter = globalCompEvents.find(Internal::GetClass()); + if (iter == globalCompEvents.end()) { + return; + } + iter->second.onConstructed.Broadcast(); + } + + template + void ECRegistry::GNotifyRemove() const + { + const auto iter = globalCompEvents.find(Internal::GetClass()); + if (iter == globalCompEvents.end()) { + return; + } + iter->second.onRemove.Broadcast(); } } // namespace Runtime diff --git a/Engine/Source/Runtime/Src/ECS.cpp b/Engine/Source/Runtime/Src/ECS.cpp index 14df2311..40ae0f32 100644 --- a/Engine/Source/Runtime/Src/ECS.cpp +++ b/Engine/Source/Runtime/Src/ECS.cpp @@ -5,119 +5,241 @@ #include namespace Runtime::Internal { - void CompOp::SetOffset(size_t inOffset) + CompRtti::CompRtti() = default; + + void CompRtti::Bind(size_t inOffset) { + bound = true; offset = inOffset; } - void* CompOp::Emplace(void* inElem, void* inOther) const + Mirror::Any CompRtti::MoveConstruct(ElemPtr inElem, const Mirror::Argument& inOther) const { - return emplace(inElem, offset, inOther); + return moveConstruct(inElem, offset, inOther); } - void CompOp::Destruct(void* inElem) const + Mirror::Any CompRtti::MoveAssign(ElemPtr inElem, const Mirror::Argument& inOther) const { - destruct(inElem, offset); + return moveAssign(inElem, offset, inOther); } - void* CompOp::Get(void* inElem) const + void CompRtti::Destruct(ElemPtr inElem) const { - return get(inElem, offset); + return destructor(inElem, offset); } - CompId CompOp::GetCompId() const + Mirror::Any CompRtti::Get(ElemPtr inElem) const { - return compId; + return get(inElem, offset); } - size_t CompOp::GetOffset() const + CompClass CompRtti::Class() const { - return offset; + return clazz; } - size_t CompOp::GetSize() const + size_t CompRtti::Offset() const { - return size; + return offset; } - CompOp::CompOp() - : compId(0) - , offset(0) - , size(0) - , emplace(nullptr) - , destruct(nullptr) - , get(nullptr) + size_t CompRtti::Size() const { + return clazz->SizeOf(); } - Archetype::Archetype(const std::vector& inCompOps) - : archetypeId(0) + Archetype::Archetype(const std::vector& inRttiVec) + : id(0) , size(0) , elemSize(0) - , compOps(inCompOps) + , rttiVec(inRttiVec) { - for (auto& compOp : compOps) { - archetypeId += compOp.GetCompId(); - compOp.SetOffset(elemSize); - elemSize += compOp.GetSize(); + rttiMap.reserve(rttiVec.size()); + for (auto i = 0; i < rttiVec.size(); i++) { + auto& rtti = rttiVec[i]; + const auto clazz = rtti.Class(); + rttiMap.emplace(clazz, i); + + id += clazz->GetTypeInfo()->id; + rtti.Bind(elemSize); + elemSize += rtti.Size(); } } - bool Archetype::Contains(CompId inCompId) const + bool Archetype::Contains(CompClass inClazz) const { - for (const auto& compOp : compOps) { - if (compOp.GetCompId() == inCompId) { + for (const auto& rtti : rttiVec) { + if (rtti.Class() == inClazz) { return true; } } return false; } - bool Archetype::ContainsAll(const std::vector& inCompIds) const + bool Archetype::ContainsAll(const std::vector& inClasses) const { - for (const auto& compId : inCompIds) { - if (!Contains(compId)) { + for (const auto& rtti : rttiVec) { + if (!Contains(rtti.Class())) { return false; } } return true; } - bool Archetype::NotContainsAny(const std::vector& inCompIds) const + bool Archetype::NotContainsAny(const std::vector& inCompClasses) const { - for (const auto& compId : inCompIds) { - if (Contains(compId)) { + for (const auto& rtti : rttiVec) { + if (Contains(rtti.Class())) { return false; } } return true; } - void* Archetype::Emplace(Entity inEntity) + ElemPtr Archetype::EmplaceElem(Entity inEntity) { - if (Size() == Capacity()) { - Reserve(); - } - auto* result = AllocateNewElemBack(); - auto backElem = BackElemIndex(); + ElemPtr result = AllocateNewElemBack(); + auto backElem = size - 1; entityMap.emplace(inEntity, backElem); elemMap.emplace(backElem, inEntity); return result; } - void* Archetype::Emplace(Entity inEntity, void* inSourceElem, const std::vector& inSourceCompOps) + ElemPtr Archetype::EmplaceElem(Entity inEntity, ElemPtr inSrcElem, const std::vector& inSrcRttiVec) { - void* newElem = Emplace(inEntity); - for (const auto& sourceCompOp : inSourceCompOps) { - const auto* newCompOp = FindCompOp(sourceCompOp.GetCompId()); - if (newCompOp == nullptr) { + ElemPtr newElem = EmplaceElem(inEntity); + for (const auto& srcRtti : inSrcRttiVec) { + const auto* newRtti = FindCompRtti(srcRtti.Class()); + if (newRtti == nullptr) { continue; } - newCompOp->Emplace(newElem, sourceCompOp.Get(inSourceElem)); + newRtti->MoveConstruct(newElem, srcRtti.Get(inSrcElem)); } return newElem; } + Mirror::Any Archetype::EmplaceComp(Entity inEntity, CompClass inCompClass, Mirror::Any inComp) // NOLINT + { + ElemPtr elem = ElemAt(entityMap.at(inEntity)); + return GetCompRtti(inCompClass).MoveConstruct(elem, inComp); + } + + void Archetype::EraseElem(Entity inEntity) + { + const auto elemIndex = entityMap.at(inEntity); + ElemPtr elem = ElemAt(elemIndex); + const auto lastElemIndex = Size() - 1; + const auto entityToLastElem = elemMap.at(lastElemIndex); + ElemPtr lastElem = ElemAt(lastElemIndex); + for (const auto& rtti : rttiVec) { + rtti.MoveAssign(elem, rtti.Get(lastElem)); + } + entityMap.erase(inEntity); + entityMap.at(entityToLastElem) = elemIndex; + elemMap.erase(lastElemIndex); + elemMap.at(elemIndex) = entityToLastElem; + } + + ElemPtr Archetype::GetElem(Entity inEntity) + { + return ElemAt(entityMap.at(inEntity)); + } + + Mirror::Any Archetype::GetComp(Entity inEntity, CompClass inCompClass) + { + ElemPtr element = GetElem(inEntity); + return GetCompRtti(inCompClass).Get(element); + } + + size_t Archetype::Size() const + { + return size; + } + + auto Archetype::All() const + { + return elemMap | std::ranges::views::values; + } + + const std::vector& Archetype::GetRttiVec() const + { + return rttiVec; + } + + ArchetypeId Archetype::Id() const + { + return id; + } + + std::vector Archetype::NewRttiVecByAdd(const CompRtti& inRtti) const + { + auto result = rttiVec; + result.emplace_back(inRtti); + return result; + } + + std::vector Archetype::NewRttiVecByRemove(const CompRtti& inRtti) const + { + auto result = rttiVec; + const auto iter = std::ranges::find_if(result, [&](const CompRtti& rtti) -> bool { return rtti.Class() == inRtti.Class(); }); + Assert(iter != result.end()); + result.erase(iter); + return result; + } + + const CompRtti* Archetype::FindCompRtti(CompClass clazz) const + { + const auto iter = rttiMap.find(clazz); + return iter != rttiMap.end() ? &rttiVec[iter->second] : nullptr; + } + + const CompRtti& Archetype::GetCompRtti(CompClass clazz) const + { + Assert(rttiMap.contains(clazz)); + return rttiVec[rttiMap.at(clazz)]; + } + + ElemPtr Archetype::ElemAt(std::vector& inMemory, size_t inIndex) // NOLINT + { + return inMemory.data() + (inIndex * elemSize); + } + + ElemPtr Archetype::ElemAt(size_t inIndex) + { + return ElemAt(memory, inIndex); + } + + size_t Archetype::Capacity() const + { + return memory.size() / elemSize; + } + + void Archetype::Reserve(float inRatio) + { + Assert(inRatio > 1.0f); + const size_t newCapacity = static_cast(static_cast(Capacity()) * inRatio); + std::vector newMemory(newCapacity * elemSize); + + for (auto i = 0; i < size; i++) { + for (const auto& rtti : rttiVec) { + void* dstElem = ElemAt(newMemory, i); + void* srcElem = ElemAt(i); + rtti.MoveConstruct(dstElem, rtti.Get(srcElem)); + rtti.Destruct(srcElem); + } + } + memory = std::move(newMemory); + } + + void* Archetype::AllocateNewElemBack() + { + if (Size() == Capacity()) { + Reserve(); + } + size++; + return ElemAt(size - 1); + } + EntityPool::EntityPool() : counter() { @@ -189,6 +311,83 @@ namespace Runtime::Internal { } // namespace Runtime::Internal namespace Runtime { + RuntimeViewRule::RuntimeViewRule() = default; + + RuntimeView::RuntimeView(ECRegistry& inRegistry, const RuntimeViewRule& inArgs) + { + Evaluate(inRegistry, inArgs); + } + + auto RuntimeView::Begin() + { + return resultEntities.begin(); + } + + auto RuntimeView::Begin() const + { + return resultEntities.begin(); + } + + auto RuntimeView::End() + { + return resultEntities.end(); + } + + auto RuntimeView::End() const + { + return resultEntities.end(); + } + + auto RuntimeView::begin() + { + return Begin(); + } + + auto RuntimeView::begin() const + { + return Begin(); + } + + auto RuntimeView::end() + { + return End(); + } + + auto RuntimeView::end() const + { + return End(); + } + + void RuntimeView::Evaluate(ECRegistry& inRegistry, const RuntimeViewRule& inArgs) + { + const std::vector includes(inArgs.includes.begin(), inArgs.includes.end()); + const std::vector excludes(inArgs.excludes.begin(), inArgs.excludes.end()); + + slotMap.reserve(includes.size()); + for (auto i = 0; i < includes.size(); i++) { + slotMap.emplace(includes[i], i); + } + + for (auto& [_, archetype] : inRegistry.archetypes) { + if (!archetype.ContainsAll(includes) || !archetype.NotContainsAny(excludes)) { + continue; + } + + resultEntities.reserve(result.size() + archetype.Size()); + result.reserve(result.size() + archetype.Size()); + for (const auto entity : archetype.All()) { + std::vector comps; + comps.reserve(includes.size()); + for (const auto clazz : includes) { + comps.emplace_back(archetype.GetComp(entity, clazz)); + } + + resultEntities.emplace_back(entity); + result.emplace_back(entity, std::move(comps)); + } + } + } + Observer::Observer(ECRegistry& inRegistry) : registry(inRegistry) { @@ -260,31 +459,39 @@ namespace Runtime { ECRegistry::ECRegistry(const ECRegistry& inOther) : entities(inOther.entities) + , globalComps(inOther.globalComps) , archetypes(inOther.archetypes) , compEvents(inOther.compEvents) + , globalCompEvents(inOther.globalCompEvents) { } ECRegistry::ECRegistry(ECRegistry&& inOther) noexcept : entities(std::move(inOther.entities)) + , globalComps(std::move(inOther.globalComps)) , archetypes(std::move(inOther.archetypes)) , compEvents(std::move(inOther.compEvents)) + , globalCompEvents(std::move(inOther.globalCompEvents)) { } ECRegistry& ECRegistry::operator=(const ECRegistry& inOther) { entities = inOther.entities; + globalComps = inOther.globalComps; archetypes = inOther.archetypes; compEvents = inOther.compEvents; + globalCompEvents = inOther.globalCompEvents; return *this; } ECRegistry& ECRegistry::operator=(ECRegistry&& inOther) noexcept { entities = std::move(inOther.entities); + globalComps = std::move(inOther.globalComps); archetypes = std::move(inOther.archetypes); compEvents = std::move(inOther.compEvents); + globalCompEvents = std::move(inOther.globalCompEvents); return *this; } @@ -311,8 +518,10 @@ namespace Runtime { void ECRegistry::Clear() { entities.Clear(); + globalComps.clear(); archetypes.clear(); compEvents.clear(); + globalCompEvents.clear(); } void ECRegistry::Each(const EntityTraverseFunc& inFunc) const @@ -340,6 +549,11 @@ namespace Runtime { return End(); } + RuntimeView ECRegistry::RuntimeView(const RuntimeViewRule& inRule) + { + return Runtime::RuntimeView { *this, inRule }; + } + Observer ECRegistry::Observer() { return Runtime::Observer { *this }; From 7683e3601101cfe3c0964ae0b62d358f812d5b05 Mon Sep 17 00:00:00 2001 From: John Kindem <461425614@qq.com> Date: Sat, 16 Nov 2024 13:09:36 +0800 Subject: [PATCH 12/22] feat: new gameplay framework --- Engine/Source/Runtime/Include/Runtime/ECS.h | 121 ++++++++++++++++---- Engine/Source/Runtime/Src/ECS.cpp | 37 ++++++ 2 files changed, 137 insertions(+), 21 deletions(-) diff --git a/Engine/Source/Runtime/Include/Runtime/ECS.h b/Engine/Source/Runtime/Include/Runtime/ECS.h index 2088d7c9..56b3385e 100644 --- a/Engine/Source/Runtime/Include/Runtime/ECS.h +++ b/Engine/Source/Runtime/Include/Runtime/ECS.h @@ -13,12 +13,12 @@ namespace Runtime { using Entity = size_t; + using CompClass = const Mirror::Class*; + using GCompClass = const Mirror::Class*; } namespace Runtime::Internal { using ArchetypeId = Mirror::TypeId; - using CompClass = const Mirror::Class*; - using GlobalCompClass = const Mirror::Class*; using ElemPtr = void*; template const Mirror::Class* GetClass(); @@ -164,6 +164,39 @@ namespace Runtime { G& globalCompRef; }; + class ScopedUpdaterDyn { + public: + ScopedUpdaterDyn(ECRegistry& inRegistry, CompClass inClass, Entity inEntity, const Mirror::Any& inCompRef); + ~ScopedUpdaterDyn(); + + NonCopyable(ScopedUpdaterDyn) + NonMovable(ScopedUpdaterDyn) + + template T As() const; + + private: + ECRegistry& registry; + CompClass clazz; + Entity entity; + const Mirror::Any& compRef; + }; + + class GScopedUpdaterDyn { + public: + GScopedUpdaterDyn(ECRegistry& inRegistry, GCompClass inClass, const Mirror::Any& inGlobalCompRef); + ~GScopedUpdaterDyn(); + + NonCopyable(GScopedUpdaterDyn) + NonMovable(GScopedUpdaterDyn) + + template T As() const; + + private: + ECRegistry& registry; + GCompClass clazz; + const Mirror::Any& globalCompRef; + }; + template struct Contains {}; @@ -201,12 +234,14 @@ namespace Runtime { RuntimeViewRule(); template RuntimeViewRule& Include(); template RuntimeViewRule& Exclude(); + RuntimeViewRule& IncludeDyn(CompClass inClass); + RuntimeViewRule& ExcludeDyn(CompClass inClass); private: friend class RuntimeView; - std::unordered_set includes; - std::unordered_set excludes; + std::unordered_set includes; + std::unordered_set excludes; }; class RuntimeView { @@ -230,7 +265,7 @@ namespace Runtime { template decltype(auto) GetCompRef(std::vector& inComps) const; void Evaluate(ECRegistry& inRegistry, const RuntimeViewRule& inArgs); - std::unordered_map slotMap; + std::unordered_map slotMap; std::vector resultEntities; std::vector>> result; }; @@ -269,6 +304,7 @@ namespace Runtime { class ECRegistry { public: using EntityTraverseFunc = Internal::EntityPool::EntityTraverseFunc; + using DynUpdateFunc = std::function; using ConstIter = Internal::EntityPool::ConstIter; using CompEvent = Common::Event; using GCompEvent = Common::Event; @@ -305,7 +341,7 @@ namespace Runtime { ConstIter begin() const; ConstIter end() const; - // component + // component static template C& Emplace(Entity inEntity, Args&&... inArgs); template void Remove(Entity inEntity); template void NotifyUpdated(Entity inEntity) const; @@ -318,11 +354,24 @@ namespace Runtime { template const C& Get(Entity inEntity) const; template View, C...> View(Exclude); template CompEvents& Events(); - RuntimeView RuntimeView(const RuntimeViewRule& inRule); Observer Observer(); - // global component - template void GEmplace(Args&&... inArgs); + // component dynamic + Mirror::Any EmplaceDyn(CompClass inClass, Entity inEntity, const Mirror::ArgumentList& inArgs); + void RemoveDyn(CompClass inClass, Entity inEntity); + void NotifyUpdatedDyn(CompClass inClass, Entity inEntity) const; + void UpdateDyn(CompClass inClass, Entity inEntity, const DynUpdateFunc& inFunc); + ScopedUpdaterDyn UpdateDyn(CompClass inClass, Entity inEntity); + bool HasDyn(CompClass inClass, Entity inEntity) const; + Mirror::Any FindDyn(CompClass inClass, Entity inEntity); + Mirror::Any FindDyn(CompClass inClass, Entity inEntity) const; + Mirror::Any GetDyn(CompClass inClass, Entity inEntity); + Mirror::Any GetDyn(CompClass inClass, Entity inEntity) const; + CompEvents& EventsDyn(CompClass inClass, Entity inEntity); + RuntimeView RuntimeView(const RuntimeViewRule& inRule); + + // global component static + template G& GEmplace(Args&&... inArgs); template void GRemove(); template void GNotifyUpdated() const; template void GUpdate(F&& inFunc); @@ -334,6 +383,19 @@ namespace Runtime { template const G& GGet() const; template GCompEvents& GEvents(); + // global component dynamic + Mirror::Any GEmplaceDyn(GCompClass inClass, const Mirror::ArgumentList& inArgs); + void GRemoveDyn(GCompClass inClass); + void GNotifyUpdatedDyn(GCompClass inClass) const; + void GUpdateDyn(GCompClass inClass, const DynUpdateFunc& inFunc); + GScopedUpdaterDyn GUpdateDyn(GCompClass inClass); + bool GHasDyn(GCompClass inClass) const; + Mirror::Any GFindDyn(GCompClass inClass); + Mirror::Any GFindDyn(GCompClass inClass) const; + Mirror::Any GGetDyn(GCompClass inClass); + Mirror::Any GGetDyn(GCompClass inClass) const; + GCompEvents& GEventsDyn(GCompClass inClass); + private: template friend class View; friend class RuntimeView; @@ -342,12 +404,16 @@ namespace Runtime { template void NotifyRemove(Entity inEntity) const; template void GNotifyConstructed() const; template void GNotifyRemove() const; + void NotifyConstructedDyn(CompClass inClass, Entity inEntity) const; + void NotifyRemoveDyn(CompClass inClass, Entity inEntity) const; + void GNotifyConstructedDyn(GCompClass inClass) const; + void GNotifyRemoveDyn(CompClass inClass) const; Internal::EntityPool entities; - std::unordered_map globalComps; + std::unordered_map globalComps; std::unordered_map archetypes; - std::unordered_map compEvents; - std::unordered_map globalCompEvents; + std::unordered_map compEvents; + std::unordered_map globalCompEvents; }; class SystemRegistry { @@ -455,6 +521,18 @@ namespace Runtime { return &globalCompRef; } + template + T ScopedUpdaterDyn::As() const + { + return compRef.As(); + } + + template + T GScopedUpdaterDyn::As() const + { + return globalCompRef.As(); + } + template View, C...>::View(ECRegistry& inRegistry) { @@ -521,13 +599,13 @@ namespace Runtime { template void View, C...>::Evaluate(ECRegistry& inRegistry) { - std::vector includeCompIds; + std::vector includeCompIds; includeCompIds.reserve(sizeof...(C)); (void) std::initializer_list { ([&]() -> void { includeCompIds.emplace_back(Internal::GetClass()); }(), 0)... }; - std::vector excludeCompIds; + std::vector excludeCompIds; excludeCompIds.reserve(sizeof...(E)); (void) std::initializer_list { ([&]() -> void { excludeCompIds.emplace_back(Internal::GetClass()); @@ -626,9 +704,9 @@ namespace Runtime { } C tempObj(std::forward(inArgs)...); - auto& result = *static_cast(newArchetype->EmplaceComp(inEntity, clazz, &tempObj)); + Mirror::Any compRef = newArchetype->EmplaceComp(inEntity, clazz, &tempObj); NotifyConstructed(inEntity); - return result; + return compRef.As(); } template @@ -691,20 +769,20 @@ namespace Runtime { C& ECRegistry::Get(Entity inEntity) { Assert(Valid(inEntity) && Has()); - void* ptr = archetypes + Mirror::Any compRef = archetypes .at(entities.GetArchetype(inEntity)) .GetComp(inEntity, Internal::GetClass()); - return *static_cast(ptr); + return compRef.As(); } template const C& ECRegistry::Get(Entity inEntity) const { Assert(Valid(inEntity) && Has()); - const void* ptr = archetypes + Mirror::Any compRef = archetypes .at(entities.GetArchetype(inEntity)) .GetComp(inEntity, Internal::GetClass()); - return *static_cast(ptr); + return compRef.As(); } template @@ -750,11 +828,12 @@ namespace Runtime { } template - void ECRegistry::GEmplace(Args&&... inArgs) + G& ECRegistry::GEmplace(Args&&... inArgs) { Assert(!GHas()); globalComps.emplace(Internal::GetClass(), Mirror::Any(G(std::forward(inArgs))...)); GNotifyConstructed(); + return GGet(); } template diff --git a/Engine/Source/Runtime/Src/ECS.cpp b/Engine/Source/Runtime/Src/ECS.cpp index 40ae0f32..ea6c6142 100644 --- a/Engine/Source/Runtime/Src/ECS.cpp +++ b/Engine/Source/Runtime/Src/ECS.cpp @@ -311,8 +311,45 @@ namespace Runtime::Internal { } // namespace Runtime::Internal namespace Runtime { + ScopedUpdaterDyn::ScopedUpdaterDyn(ECRegistry& inRegistry, CompClass inClass, Entity inEntity, const Mirror::Any& inCompRef) + : registry(inRegistry) + , clazz(inClass) + , entity(inEntity) + , compRef(inCompRef) + { + } + + ScopedUpdaterDyn::~ScopedUpdaterDyn() + { + registry.NotifyUpdatedDyn(clazz, entity); + } + + GScopedUpdaterDyn::GScopedUpdaterDyn(ECRegistry& inRegistry, GCompClass inClass, const Mirror::Any& inGlobalCompRef) + : registry(inRegistry) + , clazz(inClass) + , globalCompRef(inGlobalCompRef) + { + } + + GScopedUpdaterDyn::~GScopedUpdaterDyn() + { + registry.GNotifyUpdatedDyn(clazz); + } + RuntimeViewRule::RuntimeViewRule() = default; + RuntimeViewRule& RuntimeViewRule::IncludeDyn(CompClass inClass) + { + includes.emplace(inClass); + return *this; + } + + RuntimeViewRule& RuntimeViewRule::ExcludeDyn(CompClass inClass) + { + excludes.emplace(inClass); + return *this; + } + RuntimeView::RuntimeView(ECRegistry& inRegistry, const RuntimeViewRule& inArgs) { Evaluate(inRegistry, inArgs); From a94ce791908e136f9398ad42a530d0ede246a33e Mon Sep 17 00:00:00 2001 From: John Kindem <461425614@qq.com> Date: Sat, 16 Nov 2024 20:12:20 +0800 Subject: [PATCH 13/22] feat: support rvalue for Mirror::Any --- Engine/Source/Mirror/Include/Mirror/Mirror.h | 6 +- .../Source/Mirror/Include/Mirror/Registry.h | 52 +++++------ Engine/Source/Mirror/Src/Mirror.cpp | 12 +-- Engine/Source/Mirror/Test/AnyTest.cpp | 14 +-- Engine/Source/Mirror/Test/RegistryTest.cpp | 12 +++ Engine/Source/Mirror/Test/RegistryTest.h | 1 + Engine/Source/Runtime/Include/Runtime/ECS.h | 88 +++++++------------ Engine/Source/Runtime/Src/ECS.cpp | 58 +++++++++++- 8 files changed, 136 insertions(+), 107 deletions(-) diff --git a/Engine/Source/Mirror/Include/Mirror/Mirror.h b/Engine/Source/Mirror/Include/Mirror/Mirror.h index 8cb2b336..c0fe2a85 100644 --- a/Engine/Source/Mirror/Include/Mirror/Mirror.h +++ b/Engine/Source/Mirror/Include/Mirror/Mirror.h @@ -48,6 +48,7 @@ namespace Mirror { const uint32_t isLValueReference : 1; const uint32_t isLValueConstReference : 1; const uint32_t isRValueReference : 1; + const uint32_t isReference : 1; const uint32_t isPointer : 1; const uint32_t isConstPointer : 1; const uint32_t isClass : 1; @@ -1961,6 +1962,7 @@ namespace Mirror { Common::CppLValueRef, Common::CppLValueConstRef, Common::CppRValueRef, + Common::CppRef, Common::CppPointer, Common::CppConstPointer, Common::CppClass, @@ -2268,14 +2270,14 @@ namespace Mirror { T Any::As() { Assert(Convertible()); - return *static_cast*>(Data()); + return static_cast(*static_cast*>(Data())); } template T Any::As() const { Assert(Convertible()); - return *static_cast*>(Data()); + return static_cast(*static_cast*>(Data())); } template diff --git a/Engine/Source/Mirror/Include/Mirror/Registry.h b/Engine/Source/Mirror/Include/Mirror/Registry.h index e00e6ca8..db6bffdb 100644 --- a/Engine/Source/Mirror/Include/Mirror/Registry.h +++ b/Engine/Source/Mirror/Include/Mirror/Registry.h @@ -17,11 +17,10 @@ namespace Mirror::Internal { template struct MemberFunctionTraits {}; template auto GetArgTypeInfosByArgsTuple(std::index_sequence); - template auto ForwardArgumentsListAsTuple(const ArgumentList& args, std::index_sequence); - template decltype(auto) InvokeFunction(ArgsTuple& args, std::index_sequence); - template decltype(auto) InvokeMemberFunction(Class& object, ArgsTuple& args, std::index_sequence); - template decltype(auto) InvokeConstructorStack(ArgsTuple& args, std::index_sequence); - template decltype(auto) InvokeConstructorNew(ArgsTuple& args, std::index_sequence); + template decltype(auto) InvokeFunction(const ArgumentList& args, std::index_sequence); + template decltype(auto) InvokeMemberFunction(Class& object, const ArgumentList& args, std::index_sequence); + template decltype(auto) InvokeConstructorStack(const ArgumentList& args, std::index_sequence); + template decltype(auto) InvokeConstructorNew(const ArgumentList& args, std::index_sequence); } namespace Mirror { @@ -163,34 +162,28 @@ namespace Mirror::Internal { return std::vector { GetTypeInfo>()... }; } - template - auto ForwardArgumentsListAsTuple(const ArgumentList& args, std::index_sequence) - { - return ArgsTuple { args[I].template As>()... }; - } - template - decltype(auto) InvokeFunction(ArgsTuple& args, std::index_sequence) + decltype(auto) InvokeFunction(const ArgumentList& args, std::index_sequence) { - return Ptr(std::get(args)...); + return Ptr(args[I].template As>()...); } template - decltype(auto) InvokeMemberFunction(Class& object, ArgsTuple& args, std::index_sequence) + decltype(auto) InvokeMemberFunction(Class& object, const ArgumentList& args, std::index_sequence) { - return (object.*Ptr)(std::get(args)...); + return (object.*Ptr)(args[I].template As>()...); } template - decltype(auto) InvokeConstructorStack(ArgsTuple& args, std::index_sequence) + decltype(auto) InvokeConstructorStack(const ArgumentList& args, std::index_sequence) { - return Class(std::get(args)...); + return Class(args[I].template As>()...); } template - decltype(auto) InvokeConstructorNew(ArgsTuple& args, std::index_sequence) + decltype(auto) InvokeConstructorNew(const ArgumentList& args, std::index_sequence) { - return new Class(std::get(args)...); + return new Class(args[I].template As>()...); } } @@ -249,13 +242,11 @@ namespace Mirror { params.argRemovePointerTypeInfos = { GetTypeInfo>()... }; params.stackConstructor = [](const ArgumentList& args) -> Any { Assert(argsTupleSize == args.size()); - auto argsTuple = Internal::ForwardArgumentsListAsTuple(args, std::make_index_sequence {}); - return Internal::ForwardAsAny(Internal::InvokeConstructorStack(argsTuple, std::make_index_sequence {})); + return Internal::ForwardAsAny(Internal::InvokeConstructorStack(args, std::make_index_sequence {})); }; params.heapConstructor = [](const ArgumentList& args) -> Any { Assert(argsTupleSize == args.size()); - auto argsTuple = Internal::ForwardArgumentsListAsTuple(args, std::make_index_sequence {}); - return Internal::ForwardAsAny(Internal::InvokeConstructorNew(argsTuple, std::make_index_sequence {})); + return Internal::ForwardAsAny(Internal::InvokeConstructorNew(args, std::make_index_sequence {})); }; return MetaDataRegistry::SetContext(&clazz.EmplaceConstructor(inId, std::move(params))); @@ -312,12 +303,11 @@ namespace Mirror { params.invoker = [](const ArgumentList& args) -> Any { Assert(argsTupleSize == args.size()); - auto argsTuple = Internal::ForwardArgumentsListAsTuple(args, std::make_index_sequence {}); if constexpr (std::is_void_v) { - Internal::InvokeFunction(argsTuple, std::make_index_sequence {}); + Internal::InvokeFunction(args, std::make_index_sequence {}); return {}; } else { - return Internal::ForwardAsAny(Internal::InvokeFunction(argsTuple, std::make_index_sequence {})); + return Internal::ForwardAsAny(Internal::InvokeFunction(args, std::make_index_sequence {})); } }; @@ -377,12 +367,11 @@ namespace Mirror { params.invoker = [](const Argument& object, const ArgumentList& args) -> Any { Assert(argsTupleSize == args.size()); - auto argsTuple = Internal::ForwardArgumentsListAsTuple(args, std::make_index_sequence {}); if constexpr (std::is_void_v) { - Internal::InvokeMemberFunction(object.As(), argsTuple, std::make_index_sequence {}); + Internal::InvokeMemberFunction(object.As(), args, std::make_index_sequence {}); return {}; } else { - return Internal::ForwardAsAny(Internal::InvokeMemberFunction(object.As(), argsTuple, std::make_index_sequence {})); + return Internal::ForwardAsAny(Internal::InvokeMemberFunction(object.As(), args, std::make_index_sequence {})); } }; @@ -437,12 +426,11 @@ namespace Mirror { params.invoker = [](const ArgumentList& args) -> Any { Assert(argsTupleSize == args.size()); - auto argsTuple = Internal::ForwardArgumentsListAsTuple(args, std::make_index_sequence {}); if constexpr (std::is_void_v) { - Internal::InvokeFunction(argsTuple, std::make_index_sequence {}); + Internal::InvokeFunction(args, std::make_index_sequence {}); return {}; } else { - return Internal::ForwardAsAny(Internal::InvokeFunction(argsTuple, std::make_index_sequence {})); + return Internal::ForwardAsAny(Internal::InvokeFunction(args, std::make_index_sequence {})); } }; diff --git a/Engine/Source/Mirror/Src/Mirror.cpp b/Engine/Source/Mirror/Src/Mirror.cpp index 3a612e5f..b09130bb 100644 --- a/Engine/Source/Mirror/Src/Mirror.cpp +++ b/Engine/Source/Mirror/Src/Mirror.cpp @@ -33,7 +33,7 @@ namespace Mirror { const auto [dstRaw, dstRemoveRef, dstRemovePointer] = inDstType; const bool checkPointer = srcRaw->isPointer && dstRaw->isPointer; - const bool checkRef = dstRaw->isLValueReference; + const bool checkRef = dstRaw->isReference; if (!checkPointer && !checkRef) { return false; @@ -56,7 +56,7 @@ namespace Mirror { if (srcClass == nullptr || dstClass == nullptr || !dstClass->IsBaseOf(srcClass)) { return false; } - return !srcRemoveRefOrPtr->isConst || dstRemoveRefOrPtr->isConst; + return !srcRemoveRefOrPtr->isConst || dstRaw->isRValueReference || dstRemoveRefOrPtr->isConst; } bool Convertible(const TypeInfoCompact& inSrcType, const TypeInfoCompact& inDstType) @@ -64,15 +64,11 @@ namespace Mirror { const auto [srcRaw, srcRemoveRef, srcRemovePointer] = inSrcType; const auto [dstRaw, dstRemoveRef, dstRemovePointer] = inDstType; - if (dstRaw->isRValueReference) { - return false; - } - if (srcRaw->id == dstRaw->id) { // NOLINT - if (!dstRaw->isLValueReference) { + if (!dstRaw->isReference) { return true; } - return !srcRemoveRef->isConst || dstRemoveRef->isConst; + return !srcRemoveRef->isConst || dstRaw->isRValueReference || dstRemoveRef->isConst; } return PointerConvertible(inSrcType, inDstType) || PolymorphismConvertible(inSrcType, inDstType); } diff --git a/Engine/Source/Mirror/Test/AnyTest.cpp b/Engine/Source/Mirror/Test/AnyTest.cpp index 31a489d9..03e913be 100644 --- a/Engine/Source/Mirror/Test/AnyTest.cpp +++ b/Engine/Source/Mirror/Test/AnyTest.cpp @@ -264,7 +264,7 @@ TEST(AnyTest, ConvertibleTest) ASSERT_TRUE(a0.Convertible()); ASSERT_TRUE(a0.Convertible()); ASSERT_TRUE(a0.Convertible()); - ASSERT_FALSE(a0.Convertible()); + ASSERT_TRUE(a0.Convertible()); const int v0 = 1; // NOLINT a0 = v0; @@ -272,7 +272,7 @@ TEST(AnyTest, ConvertibleTest) ASSERT_TRUE(a0.Convertible()); ASSERT_TRUE(a0.Convertible()); ASSERT_TRUE(a0.Convertible()); - ASSERT_FALSE(a0.Convertible()); + ASSERT_TRUE(a0.Convertible()); int v1 = 1; a0 = std::ref(v1); @@ -280,14 +280,14 @@ TEST(AnyTest, ConvertibleTest) ASSERT_TRUE(a0.Convertible()); ASSERT_TRUE(a0.Convertible()); ASSERT_TRUE(a0.Convertible()); - ASSERT_FALSE(a0.Convertible()); + ASSERT_TRUE(a0.Convertible()); a0 = std::ref(v0); ASSERT_TRUE(a0.Convertible()); ASSERT_TRUE(a0.Convertible()); ASSERT_FALSE(a0.Convertible()); ASSERT_TRUE(a0.Convertible()); - ASSERT_FALSE(a0.Convertible()); + ASSERT_TRUE(a0.Convertible()); a0 = 1; Any a1 = a0.Ref(); @@ -295,21 +295,21 @@ TEST(AnyTest, ConvertibleTest) ASSERT_TRUE(a1.Convertible()); ASSERT_TRUE(a1.Convertible()); ASSERT_TRUE(a1.Convertible()); - ASSERT_FALSE(a1.Convertible()); + ASSERT_TRUE(a1.Convertible()); a1 = a1.ConstRef(); ASSERT_TRUE(a1.Convertible()); ASSERT_TRUE(a1.Convertible()); ASSERT_FALSE(a1.Convertible()); ASSERT_TRUE(a1.Convertible()); - ASSERT_FALSE(a1.Convertible()); + ASSERT_TRUE(a1.Convertible()); a1 = a1.Value(); ASSERT_TRUE(a1.Convertible()); ASSERT_TRUE(a1.Convertible()); ASSERT_TRUE(a1.Convertible()); ASSERT_TRUE(a1.Convertible()); - ASSERT_FALSE(a1.Convertible()); + ASSERT_TRUE(a1.Convertible()); AnyDerivedClassTest derived {}; a0 = derived; diff --git a/Engine/Source/Mirror/Test/RegistryTest.cpp b/Engine/Source/Mirror/Test/RegistryTest.cpp index b0fc2b4b..a473dcc9 100644 --- a/Engine/Source/Mirror/Test/RegistryTest.cpp +++ b/Engine/Source/Mirror/Test/RegistryTest.cpp @@ -26,6 +26,11 @@ void F2(int& outValue) outValue = 1; } +int F3(int&& inValue) +{ + return std::move(inValue); +} + int C0::v0 = 0; int& C0::F0() @@ -105,6 +110,13 @@ TEST(RegistryTest, GlobalScopeTest) function.InvokeDyn({ Mirror::Any(std::ref(value)) }); ASSERT_EQ(value, 1); } + + { + const auto& function = globalScope.GetFunction("F3"); + int value = 1; + function.Invoke(std::ref(value)); + ASSERT_EQ(value, 1); + } } TEST(RegistryTest, ClassTest) diff --git a/Engine/Source/Mirror/Test/RegistryTest.h b/Engine/Source/Mirror/Test/RegistryTest.h index 6d801d92..2dce6c80 100644 --- a/Engine/Source/Mirror/Test/RegistryTest.h +++ b/Engine/Source/Mirror/Test/RegistryTest.h @@ -11,6 +11,7 @@ EProperty(testKey=v0) extern int v0; EFunc() int F0(const int a, const int b); EFunc() int& F1(); EFunc() void F2(int& outValue); +EFunc() int F3(int&& inValue); struct EClass(testKey=C0) C0 { EClassBody(C0) diff --git a/Engine/Source/Runtime/Include/Runtime/ECS.h b/Engine/Source/Runtime/Include/Runtime/ECS.h index 56b3385e..265454b8 100644 --- a/Engine/Source/Runtime/Include/Runtime/ECS.h +++ b/Engine/Source/Runtime/Include/Runtime/ECS.h @@ -69,7 +69,7 @@ namespace Runtime::Internal { bool NotContainsAny(const std::vector& inCompClasses) const; ElemPtr EmplaceElem(Entity inEntity); ElemPtr EmplaceElem(Entity inEntity, ElemPtr inSrcElem, const std::vector& inSrcRttiVec); - Mirror::Any EmplaceComp(Entity inEntity, CompClass inCompClass, Mirror::Any inComp); + Mirror::Any EmplaceComp(Entity inEntity, CompClass inCompClass, const Mirror::Argument& inCompRef); void EraseElem(Entity inEntity); ElemPtr GetElem(Entity inEntity); Mirror::Any GetComp(Entity inEntity, CompClass inCompClass); @@ -261,8 +261,8 @@ namespace Runtime { auto end() const; private: - template void InvokeTraverseFuncInternal(F&& inFunc, std::pair>& inEntityAndComps, std::index_sequence) const; - template decltype(auto) GetCompRef(std::vector& inComps) const; + template void InvokeTraverseFuncInternal(F&& inFunc, std::pair>& inEntityAndComps, std::index_sequence) const; + template decltype(auto) GetCompRef(std::vector& inComps) const; void Evaluate(ECRegistry& inRegistry, const RuntimeViewRule& inArgs); std::unordered_map slotMap; @@ -344,7 +344,7 @@ namespace Runtime { // component static template C& Emplace(Entity inEntity, Args&&... inArgs); template void Remove(Entity inEntity); - template void NotifyUpdated(Entity inEntity) const; + template void NotifyUpdated(Entity inEntity); template void Update(Entity inEntity, F&& inFunc); template ScopedUpdater Update(Entity inEntity); template bool Has(Entity inEntity) const; @@ -359,7 +359,7 @@ namespace Runtime { // component dynamic Mirror::Any EmplaceDyn(CompClass inClass, Entity inEntity, const Mirror::ArgumentList& inArgs); void RemoveDyn(CompClass inClass, Entity inEntity); - void NotifyUpdatedDyn(CompClass inClass, Entity inEntity) const; + void NotifyUpdatedDyn(CompClass inClass, Entity inEntity); void UpdateDyn(CompClass inClass, Entity inEntity, const DynUpdateFunc& inFunc); ScopedUpdaterDyn UpdateDyn(CompClass inClass, Entity inEntity); bool HasDyn(CompClass inClass, Entity inEntity) const; @@ -373,7 +373,7 @@ namespace Runtime { // global component static template G& GEmplace(Args&&... inArgs); template void GRemove(); - template void GNotifyUpdated() const; + template void GNotifyUpdated(); template void GUpdate(F&& inFunc); template GScopedUpdater GUpdate(); template bool GHas() const; @@ -386,7 +386,7 @@ namespace Runtime { // global component dynamic Mirror::Any GEmplaceDyn(GCompClass inClass, const Mirror::ArgumentList& inArgs); void GRemoveDyn(GCompClass inClass); - void GNotifyUpdatedDyn(GCompClass inClass) const; + void GNotifyUpdatedDyn(GCompClass inClass); void GUpdateDyn(GCompClass inClass, const DynUpdateFunc& inFunc); GScopedUpdaterDyn GUpdateDyn(GCompClass inClass); bool GHasDyn(GCompClass inClass) const; @@ -400,20 +400,20 @@ namespace Runtime { template friend class View; friend class RuntimeView; - template void NotifyConstructed(Entity inEntity) const; - template void NotifyRemove(Entity inEntity) const; - template void GNotifyConstructed() const; - template void GNotifyRemove() const; - void NotifyConstructedDyn(CompClass inClass, Entity inEntity) const; - void NotifyRemoveDyn(CompClass inClass, Entity inEntity) const; - void GNotifyConstructedDyn(GCompClass inClass) const; - void GNotifyRemoveDyn(CompClass inClass) const; + template void NotifyConstructed(Entity inEntity); + template void NotifyRemove(Entity inEntity); + template void GNotifyConstructed(); + template void GNotifyRemove(); + void NotifyConstructedDyn(CompClass inClass, Entity inEntity); + void NotifyRemoveDyn(CompClass inClass, Entity inEntity); + void GNotifyConstructedDyn(GCompClass inClass); + void GNotifyRemoveDyn(CompClass inClass); Internal::EntityPool entities; std::unordered_map globalComps; std::unordered_map archetypes; std::unordered_map compEvents; - std::unordered_map globalCompEvents; + std::unordered_map globalCompEvents; }; class SystemRegistry { @@ -632,17 +632,17 @@ namespace Runtime { } template - void RuntimeView::InvokeTraverseFuncInternal(F&& inFunc, std::pair>& inEntityAndComps, std::index_sequence) const + void RuntimeView::InvokeTraverseFuncInternal(F&& inFunc, std::pair>& inEntityAndComps, std::index_sequence) const { inFunc(inEntityAndComps.first, GetCompRef>(inEntityAndComps.second)...); } template - decltype(auto) RuntimeView::GetCompRef(std::vector& inComps) const + decltype(auto) RuntimeView::GetCompRef(std::vector& inComps) const { static_assert(std::is_reference_v); const auto compIndex = slotMap.at(Internal::GetClass()); - return *static_cast>>(inComps[compIndex]); + return inComps[compIndex].template As(); } template @@ -704,7 +704,7 @@ namespace Runtime { } C tempObj(std::forward(inArgs)...); - Mirror::Any compRef = newArchetype->EmplaceComp(inEntity, clazz, &tempObj); + Mirror::Any compRef = newArchetype->EmplaceComp(inEntity, clazz, std::ref(tempObj)); NotifyConstructed(inEntity); return compRef.As(); } @@ -798,33 +798,21 @@ namespace Runtime { } template - void ECRegistry::NotifyUpdated(Entity inEntity) const + void ECRegistry::NotifyUpdated(Entity inEntity) { - const auto iter = compEvents.find(Internal::GetClass()); - if (iter == compEvents.end()) { - return; - } - iter->second.onUpdated.Broadcast(inEntity); + NotifyUpdatedDyn(Internal::GetClass(), inEntity); } template - void ECRegistry::NotifyConstructed(Entity inEntity) const + void ECRegistry::NotifyConstructed(Entity inEntity) { - const auto iter = compEvents.find(Internal::GetClass()); - if (iter == compEvents.end()) { - return; - } - iter->second.onConstructed.Broadcast(inEntity); + NotifyConstructedDyn(Internal::GetClass(), inEntity); } template - void ECRegistry::NotifyRemove(Entity inEntity) const + void ECRegistry::NotifyRemove(Entity inEntity) { - const auto iter = compEvents.find(Internal::GetClass()); - if (iter == compEvents.end()) { - return; - } - iter->second.onRemove.Broadcast(inEntity); + NotifyRemoveDyn(Internal::GetClass(), inEntity); } template @@ -898,32 +886,20 @@ namespace Runtime { } template - void ECRegistry::GNotifyUpdated() const + void ECRegistry::GNotifyUpdated() { - const auto iter = globalCompEvents.find(Internal::GetClass()); - if (iter == globalCompEvents.end()) { - return; - } - iter->second.onUpdated.Broadcast(); + GNotifyUpdatedDyn(Internal::GetClass()); } template - void ECRegistry::GNotifyConstructed() const + void ECRegistry::GNotifyConstructed() { - const auto iter = globalCompEvents.find(Internal::GetClass()); - if (iter == globalCompEvents.end()) { - return; - } - iter->second.onConstructed.Broadcast(); + GNotifyConstructedDyn(Internal::GetClass()); } template - void ECRegistry::GNotifyRemove() const + void ECRegistry::GNotifyRemove() { - const auto iter = globalCompEvents.find(Internal::GetClass()); - if (iter == globalCompEvents.end()) { - return; - } - iter->second.onRemove.Broadcast(); + GNotifyRemoveDyn(Internal::GetClass()); } } // namespace Runtime diff --git a/Engine/Source/Runtime/Src/ECS.cpp b/Engine/Source/Runtime/Src/ECS.cpp index ea6c6142..e31888ca 100644 --- a/Engine/Source/Runtime/Src/ECS.cpp +++ b/Engine/Source/Runtime/Src/ECS.cpp @@ -118,10 +118,10 @@ namespace Runtime::Internal { return newElem; } - Mirror::Any Archetype::EmplaceComp(Entity inEntity, CompClass inCompClass, Mirror::Any inComp) // NOLINT + Mirror::Any Archetype::EmplaceComp(Entity inEntity, CompClass inCompClass, const Mirror::Argument& inCompRef) // NOLINT { ElemPtr elem = ElemAt(entityMap.at(inEntity)); - return GetCompRtti(inCompClass).MoveConstruct(elem, inComp); + return GetCompRtti(inCompClass).MoveConstruct(elem, inCompRef); } void Archetype::EraseElem(Entity inEntity) @@ -591,8 +591,62 @@ namespace Runtime { return Runtime::RuntimeView { *this, inRule }; } + void ECRegistry::NotifyUpdatedDyn(CompClass inClass, Entity inEntity) + { + const auto iter = compEvents.find(inClass); + if (iter == compEvents.end()) { + return; + } + iter->second.onUpdated.Broadcast(*this, inEntity); + } + + void ECRegistry::NotifyConstructedDyn(CompClass inClass, Entity inEntity) + { + const auto iter = compEvents.find(inClass); + if (iter == compEvents.end()) { + return; + } + iter->second.onConstructed.Broadcast(*this, inEntity); + } + + void ECRegistry::NotifyRemoveDyn(CompClass inClass, Entity inEntity) + { + const auto iter = compEvents.find(inClass); + if (iter == compEvents.end()) { + return; + } + iter->second.onRemove.Broadcast(*this, inEntity); + } + Observer ECRegistry::Observer() { return Runtime::Observer { *this }; } + + void ECRegistry::GNotifyUpdatedDyn(GCompClass inClass) + { + const auto iter = globalCompEvents.find(inClass); + if (iter == globalCompEvents.end()) { + return; + } + iter->second.onUpdated.Broadcast(*this); + } + + void ECRegistry::GNotifyConstructedDyn(GCompClass inClass) + { + const auto iter = globalCompEvents.find(inClass); + if (iter == globalCompEvents.end()) { + return; + } + iter->second.onConstructed.Broadcast(*this); + } + + void ECRegistry::GNotifyRemoveDyn(CompClass inClass) + { + const auto iter = globalCompEvents.find(inClass); + if (iter == globalCompEvents.end()) { + return; + } + iter->second.onRemove.Broadcast(*this); + } } // namespace Runtime From 3127ab7ba67a2180cc2eca6636c989926ad71a42 Mon Sep 17 00:00:00 2001 From: John Kindem <461425614@qq.com> Date: Sun, 17 Nov 2024 19:38:55 +0800 Subject: [PATCH 14/22] feat: support inplace new for Mirror::Any --- Engine/Source/Mirror/Include/Mirror/Mirror.h | 29 ++++++++++++++----- .../Source/Mirror/Include/Mirror/Registry.h | 12 ++++++++ Engine/Source/Mirror/Src/Mirror.cpp | 14 +++++++++ 3 files changed, 47 insertions(+), 8 deletions(-) diff --git a/Engine/Source/Mirror/Include/Mirror/Mirror.h b/Engine/Source/Mirror/Include/Mirror/Mirror.h index c0fe2a85..28f9acc0 100644 --- a/Engine/Source/Mirror/Include/Mirror/Mirror.h +++ b/Engine/Source/Mirror/Include/Mirror/Mirror.h @@ -485,6 +485,7 @@ namespace Mirror { template Any Construct(Args&&... args) const; template Any New(Args&&... args) const; + template Any InplaceNew(Args&&... args) const; const std::string& GetOwnerName() const; const Id& GetOwnerId() const; @@ -500,6 +501,7 @@ namespace Mirror { Any ConstructDyn(const ArgumentList& arguments) const; Any NewDyn(const ArgumentList& arguments) const; + Any InplaceNewDyn(void* ptr, const ArgumentList& arguments) const; private: friend class Registry; @@ -507,6 +509,7 @@ namespace Mirror { template friend class ClassRegistry; using Invoker = std::function; + using InplaceInvoker = std::function; struct ConstructParams { Id id; @@ -518,6 +521,7 @@ namespace Mirror { std::vector argRemovePointerTypeInfos; Invoker stackConstructor; Invoker heapConstructor; + InplaceInvoker inplaceConstructor; }; explicit Constructor(ConstructParams&& params); @@ -530,6 +534,7 @@ namespace Mirror { std::vector argRemovePointerTypeInfos; Invoker stackConstructor; Invoker heapConstructor; + InplaceInvoker inplaceConstructor; }; class MIRROR_API Destructor final : public ReflNode { @@ -705,6 +710,7 @@ namespace Mirror { template Any Construct(Args&&... args); template Any New(Args&&... args); + template Any InplaceNew(void* ptr, Args&&... args); void ForEachStaticVariable(const VariableTraverser& func) const; void ForEachStaticFunction(const FunctionTraverser& func) const; @@ -742,6 +748,7 @@ namespace Mirror { Any ConstructDyn(const ArgumentList& arguments) const; Any NewDyn(const ArgumentList& arguments) const; + Any InplaceNewDyn(void* ptr, const ArgumentList& arguments) const; private: static std::unordered_map typeToIdMap; @@ -2432,6 +2439,12 @@ namespace Mirror { return NewDyn(Internal::ForwardAsArgumentList(std::forward(args)...)); } + template + Any Constructor::InplaceNew(Args&&... args) const + { + return InplaceNewDyn(Internal::ForwardAsArgumentList(std::forward(args)...)); + } + template void Destructor::Invoke(C&& object) const { @@ -2477,19 +2490,19 @@ namespace Mirror { template Any Class::Construct(Args&&... args) { - auto arguments = Internal::ForwardAsArgumentList(std::forward(args)...); - const auto* constructor = FindSuitableConstructor(arguments); - Assert(constructor != nullptr); - return constructor->Construct(arguments); + return ConstructDyn(Internal::ForwardAsArgumentList(std::forward(args)...)); } template Any Class::New(Args&&... args) { - auto arguments = Internal::ForwardAsArgumentList(std::forward(args)...); - const auto* constructor = FindSuitableConstructor(arguments); - Assert(constructor != nullptr); - return constructor->New(arguments); + return NewDyn(Internal::ForwardAsArgumentList(std::forward(args)...)); + } + + template + Any Class::InplaceNew(void* ptr, Args&&... args) + { + return InplaceNewDyn(ptr, Internal::ForwardAsArgumentList(std::forward(args)...)); } template diff --git a/Engine/Source/Mirror/Include/Mirror/Registry.h b/Engine/Source/Mirror/Include/Mirror/Registry.h index db6bffdb..11a25d0f 100644 --- a/Engine/Source/Mirror/Include/Mirror/Registry.h +++ b/Engine/Source/Mirror/Include/Mirror/Registry.h @@ -21,6 +21,7 @@ namespace Mirror::Internal { template decltype(auto) InvokeMemberFunction(Class& object, const ArgumentList& args, std::index_sequence); template decltype(auto) InvokeConstructorStack(const ArgumentList& args, std::index_sequence); template decltype(auto) InvokeConstructorNew(const ArgumentList& args, std::index_sequence); + template decltype(auto) InvokeConstructorInplace(void* ptr, const ArgumentList& args, std::index_sequence); } namespace Mirror { @@ -185,6 +186,13 @@ namespace Mirror::Internal { { return new Class(args[I].template As>()...); } + + template + decltype(auto) InvokeConstructorInplace(void* ptr, const ArgumentList& args, std::index_sequence) + { + new(ptr) Class(args[I].template As>()...); + return *static_cast(ptr); + } } namespace Mirror { @@ -248,6 +256,10 @@ namespace Mirror { Assert(argsTupleSize == args.size()); return Internal::ForwardAsAny(Internal::InvokeConstructorNew(args, std::make_index_sequence {})); }; + params.inplaceConstructor = [](void* ptr, const ArgumentList& args) -> Any { + Assert(argsTupleSize == args.size()); + return Internal::ForwardAsAny(Internal::InvokeConstructorInplace(ptr, args, std::make_index_sequence {})); + }; return MetaDataRegistry::SetContext(&clazz.EmplaceConstructor(inId, std::move(params))); } diff --git a/Engine/Source/Mirror/Src/Mirror.cpp b/Engine/Source/Mirror/Src/Mirror.cpp index b09130bb..f769b4e5 100644 --- a/Engine/Source/Mirror/Src/Mirror.cpp +++ b/Engine/Source/Mirror/Src/Mirror.cpp @@ -920,6 +920,7 @@ namespace Mirror { , argRemovePointerTypeInfos(std::move(params.argRemovePointerTypeInfos)) , stackConstructor(std::move(params.stackConstructor)) , heapConstructor(std::move(params.heapConstructor)) + , inplaceConstructor(std::move(params.inplaceConstructor)) { } @@ -992,6 +993,11 @@ namespace Mirror { return heapConstructor(arguments); } + Any Constructor::InplaceNewDyn(void* ptr, const ArgumentList& arguments) const + { + return inplaceConstructor(ptr, arguments); + } + Destructor::Destructor(ConstructParams&& params) : ReflNode(std::string(IdPresets::detor.name)) , owner(std::move(params.owner)) @@ -1485,6 +1491,7 @@ namespace Mirror { continue; } + // TODO prefer rvalue params version bool bSuitable = true; for (auto i = 0; i < arguments.size(); i++) { const TypeInfoCompact srcType { arguments[i].Type(), arguments[i].RemoveRefType(), arguments[i].RemovePointerType() }; // NOLINT @@ -1518,6 +1525,13 @@ namespace Mirror { return constructor->NewDyn(arguments); } + Any Class::InplaceNewDyn(void* ptr, const ArgumentList& arguments) const + { + const auto* constructor = FindSuitableConstructor(arguments); + Assert(constructor != nullptr); + return constructor->InplaceNewDyn(ptr, arguments); + } + const Constructor* Class::FindConstructor(const Id& inId) const { const auto iter = constructors.find(inId); From e20d02a27fd934070a67a1c88d7a9ca8a0c04b9f Mon Sep 17 00:00:00 2001 From: FlyAntNotDown <461425614@qq.com> Date: Sat, 30 Nov 2024 11:27:07 +0800 Subject: [PATCH 15/22] fix: macos cmake issue --- ThirdParty/CMakeLists.txt | 51 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/ThirdParty/CMakeLists.txt b/ThirdParty/CMakeLists.txt index 88eacc71..db856480 100644 --- a/ThirdParty/CMakeLists.txt +++ b/ThirdParty/CMakeLists.txt @@ -26,6 +26,7 @@ Add3rdBinaryPackage( Darwin vulkan.1 ) if (NOT ${CI}) + #see https://github.com/KhronosGroup/Vulkan-Loader/blob/main/docs/LoaderLayerInterface.md if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") execute_process(COMMAND reg query "HKEY_LOCAL_MACHINE\\SOFTWARE\\Khronos\\Vulkan\\ExplicitLayers" OUTPUT_VARIABLE LAYERS) string(REGEX MATCH "VkLayer_khronos_validation\.json" MATCH_RESULT ${LAYERS}) @@ -39,8 +40,51 @@ if (NOT ${CI}) string(REPLACE "/" "\\" VALIDATION_LAYER_JSON ${VALIDATION_LAYER_JSON}) execute_process(COMMAND PowerShell -Command "Start-Process reg -ArgumentList 'add HKEY_LOCAL_MACHINE\\SOFTWARE\\Khronos\\Vulkan\\ExplicitLayers /v ${VALIDATION_LAYER_JSON} /t REG_DWORD /d 0' -Verb RunAs") endif () - else () - # TODO check macOS + else (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") + # check drivers + set(PLATFORM_VULKAN_SDK_DIR ${CMAKE_SOURCE_DIR}/ThirdParty/Lib/VulkanSDK-Darwin-${VULKAN_SDK_VERSION}/macOS) + execute_process(COMMAND ${PLATFORM_VULKAN_SDK_DIR}/bin/vulkaninfo OUTPUT_VARIABLE VULKAN_INFO ERROR_VARIABLE VULKAN_INFO) + string(REGEX MATCH "ERROR_INCOMPATIBLE_DRIVER" MATCH_RESULT ${VULKAN_INFO}) + list(LENGTH MATCH_RESULT MATCH_RESULT_LENGTH) + if (${MATCH_RESULT_LENGTH} GREATER 0) + message("there is no drivers found for vulkan, copy and rewrite driver files to ~/.config/vulkan/icd.d") + get_filename_component(DRIVERS_DIR_ABSOLUTE ~/.config/vulkan/icd.d ABSOLUTE) + if (NOT EXISTS ${DRIVERS_DIR_ABSOLUTE}) + file(MAKE_DIRECTORY ${DRIVERS_DIR_ABSOLUTE}) + endif () + + file(GLOB DRIVER_FILES ${PLATFORM_VULKAN_SDK_DIR}/share/vulkan/icd.d/*.json) + foreach (DRIVER_FILE ${DRIVER_FILES}) + file(READ ${DRIVER_FILE} FILE_CONTENT) + string(REPLACE "../../../lib" "${PLATFORM_VULKAN_SDK_DIR}/lib" FILE_CONTENT ${FILE_CONTENT}) + get_filename_component(FILE_NAME ${DRIVER_FILE} NAME) + file(WRITE ${DRIVERS_DIR_ABSOLUTE}/${FILE_NAME} ${FILE_CONTENT}) + endforeach () + else () + message("found vulkan drivers installed in system, will use it") + endif () + + # check layers + execute_process(COMMAND ${PLATFORM_VULKAN_SDK_DIR}/bin/vulkaninfo OUTPUT_VARIABLE VULKAN_INFO ERROR_VARIABLE VULKAN_INFO) + string(REGEX MATCH "Layers:\n=======" MATCH_RESULT ${VULKAN_INFO}) + list(LENGTH MATCH_RESULT MATCH_RESULT_LENGTH) + if (${MATCH_RESULT_LENGTH} GREATER 0) + message("there is no layers found for vulkan, copy and rewrite layer files to ~/.config/vulkan/explicit_layer.d") + get_filename_component(LAYERS_DIR_ABSOLUTE ~/.config/vulkan/explicit_layer.d ABSOLUTE) + if (NOT EXISTS ${LAYERS_DIR_ABSOLUTE}) + file(MAKE_DIRECTORY ${LAYERS_DIR_ABSOLUTE}) + endif () + + file(GLOB LAYER_FILES ${PLATFORM_VULKAN_SDK_DIR}/share/vulkan/explicit_layer.d/*.json) + foreach (LAYER_FILE ${LAYER_FILES}) + file(READ ${LAYER_FILE} FILE_CONTENT) + string(REPLACE "../../../lib" "${PLATFORM_VULKAN_SDK_DIR}/lib" FILE_CONTENT ${FILE_CONTENT}) + get_filename_component(FILE_NAME ${LAYER_FILE} NAME) + file(WRITE ${LAYERS_DIR_ABSOLUTE}/${FILE_NAME} ${FILE_CONTENT}) + endforeach () + else () + message("found vulkan layers installed in system, will use it") + endif () endif () endif () @@ -199,7 +243,7 @@ Find3rdPackage( VERSION 6.5.2 HASH Windows e2a573a53b6de88c0ce768868bd5a8258d432ad71c45a407afa55243b051668f - Darwin 4379592e8b3af8eb32f5d030608651da8dc59c30b9bfa7837b7ed17949ff3365 + Darwin 2fadcb1f07e5f11d4345e7d5631f35f8f4a8033c35901fb20a22c2feb7486e57 PREFIX Windows $/6.5.2/msvc2019_64 Darwin $/6.5.2/macos @@ -212,6 +256,7 @@ Find3rdPackage( $/6.5.2/msvc2019_64/bin/Qt6Gui$,d,>.dll $/6.5.2/msvc2019_64/bin/Qt6Widgets$,d,>.dll ) +set(Qt6Core_VERSION_MAJOR 6 CACHE STRING "" FORCE) # rapidjson Add3rdHeaderOnlyPackage( From 1e96a27e3a160a1d5117a3c115e6976fe497010a Mon Sep 17 00:00:00 2001 From: FlyAntNotDown <461425614@qq.com> Date: Sat, 30 Nov 2024 11:28:00 +0800 Subject: [PATCH 16/22] fix: macos mirror tool header path issue --- Tool/MirrorTool/Src/Parser.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Tool/MirrorTool/Src/Parser.cpp b/Tool/MirrorTool/Src/Parser.cpp index bb4c6cc8..942af005 100644 --- a/Tool/MirrorTool/Src/Parser.cpp +++ b/Tool/MirrorTool/Src/Parser.cpp @@ -420,10 +420,10 @@ namespace MirrorTool { "-DNOMINMAX=1", #elif PLATFORM_MACOS "-DPLATFORM_MACOS=1", - std::format("-I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX{}.sdk/usr/include/c++/v1", MACOS_SDK_VERSION), - std::format("-I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX{}.sdk/usr/include", MACOS_SDK_VERSION), - std::format("-I/Library/Developer/CommandLineTools/usr/lib/clang/{}.{}.{}/include", __clang_major__, __clang_minor__, __clang_patchlevel__), - std::format("-I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/{}.{}.{}/include", __clang_major__, __clang_minor__, __clang_patchlevel__), + "-I/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1", + std::format("-I/Library/Developer/CommandLineTools/usr/lib/clang/{}/include", __clang_major__), + "-I/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include", + "-I/Library/Developer/CommandLineTools/usr/include", #elif DPLATFORM_LINUX "-DPLATFORM_LINUX=1", #endif From 53a7ada96f56e334606b79802eadb27ad2c61759 Mon Sep 17 00:00:00 2001 From: FlyAntNotDown <461425614@qq.com> Date: Sat, 30 Nov 2024 11:28:24 +0800 Subject: [PATCH 17/22] feat: new gameplay framework --- Engine/Source/Common/Include/Common/Event.h | 10 - Engine/Source/Runtime/Include/Runtime/ECS.h | 164 +++------------ Engine/Source/Runtime/Src/ECS.cpp | 218 +++++++++++++++++--- 3 files changed, 224 insertions(+), 168 deletions(-) diff --git a/Engine/Source/Common/Include/Common/Event.h b/Engine/Source/Common/Include/Common/Event.h index 3633babd..cf8db02d 100644 --- a/Engine/Source/Common/Include/Common/Event.h +++ b/Engine/Source/Common/Include/Common/Event.h @@ -26,16 +26,6 @@ namespace Common::Internal { IMPL_INDEX_TO_STD_PLACEHOLDER(8) IMPL_INDEX_TO_STD_PLACEHOLDER(9) IMPL_INDEX_TO_STD_PLACEHOLDER(10) - IMPL_INDEX_TO_STD_PLACEHOLDER(11) - IMPL_INDEX_TO_STD_PLACEHOLDER(12) - IMPL_INDEX_TO_STD_PLACEHOLDER(13) - IMPL_INDEX_TO_STD_PLACEHOLDER(14) - IMPL_INDEX_TO_STD_PLACEHOLDER(15) - IMPL_INDEX_TO_STD_PLACEHOLDER(16) - IMPL_INDEX_TO_STD_PLACEHOLDER(17) - IMPL_INDEX_TO_STD_PLACEHOLDER(18) - IMPL_INDEX_TO_STD_PLACEHOLDER(19) - IMPL_INDEX_TO_STD_PLACEHOLDER(20) } namespace Common { diff --git a/Engine/Source/Runtime/Include/Runtime/ECS.h b/Engine/Source/Runtime/Include/Runtime/ECS.h index 265454b8..9b3d74d3 100644 --- a/Engine/Source/Runtime/Include/Runtime/ECS.h +++ b/Engine/Source/Runtime/Include/Runtime/ECS.h @@ -15,6 +15,7 @@ namespace Runtime { using Entity = size_t; using CompClass = const Mirror::Class*; using GCompClass = const Mirror::Class*; + using SystemClass = const Mirror::Class*; } namespace Runtime::Internal { @@ -26,11 +27,10 @@ namespace Runtime::Internal { class CompRtti { public: - template CompRtti From(); - + explicit CompRtti(CompClass inClass); void Bind(size_t inOffset); - Mirror::Any MoveConstruct(ElemPtr inElem, const Mirror::Argument& inOther) const; - Mirror::Any MoveAssign(ElemPtr inElem, const Mirror::Argument& inOther) const; + Mirror::Any MoveConstruct(ElemPtr inElem, const Mirror::Any& inOther) const; + Mirror::Any MoveAssign(ElemPtr inElem, const Mirror::Any& inOther) const; void Destruct(ElemPtr inElem) const; Mirror::Any Get(ElemPtr inElem) const; CompClass Class() const; @@ -38,23 +38,12 @@ namespace Runtime::Internal { size_t Size() const; private: - using MoveConstructFunc = Mirror::Any(ElemPtr, size_t, const Mirror::Argument&); - using MoveAssignFunc = Mirror::Any(ElemPtr, size_t, const Mirror::Argument&); + using MoveConstructFunc = Mirror::Any(ElemPtr, size_t, const Mirror::Any&); + using MoveAssignFunc = Mirror::Any(ElemPtr, size_t, const Mirror::Any&); using DestructorFunc = void(ElemPtr, size_t); using GetFunc = Mirror::Any(ElemPtr, size_t); - template static Mirror::Any MoveConstructImpl(ElemPtr inElem, size_t inOffset, const Mirror::Argument& inOther); - template static Mirror::Any MoveAssignImpl(ElemPtr inElem, size_t inOffset, const Mirror::Argument& inOther); - template static void DestructImpl(ElemPtr inElem, size_t inOffset); - template static Mirror::Any GetImpl(ElemPtr inElem, size_t inOffset); - - CompRtti(); - CompClass clazz; - MoveConstructFunc* moveConstruct; - MoveAssignFunc* moveAssign; - DestructorFunc* destructor; - GetFunc* get; // runtime, need Bind() bool bound; size_t offset; @@ -71,8 +60,9 @@ namespace Runtime::Internal { ElemPtr EmplaceElem(Entity inEntity, ElemPtr inSrcElem, const std::vector& inSrcRttiVec); Mirror::Any EmplaceComp(Entity inEntity, CompClass inCompClass, const Mirror::Argument& inCompRef); void EraseElem(Entity inEntity); - ElemPtr GetElem(Entity inEntity); + ElemPtr GetElem(Entity inEntity) const; Mirror::Any GetComp(Entity inEntity, CompClass inCompClass); + Mirror::Any GetComp(Entity inEntity, CompClass inCompClass) const; size_t Size() const; auto All() const; const std::vector& GetRttiVec() const; @@ -89,8 +79,8 @@ namespace Runtime::Internal { size_t Capacity() const; void Reserve(float inRatio = 1.5f); ElemPtr AllocateNewElemBack(); - ElemPtr ElemAt(std::vector& inMemory, size_t inIndex); - ElemPtr ElemAt(size_t inIndex); + ElemPtr ElemAt(std::vector& inMemory, size_t inIndex) const; + ElemPtr ElemAt(size_t inIndex) const; ArchetypeId id; size_t size; @@ -335,6 +325,7 @@ namespace Runtime { bool Valid(Entity inEntity) const; size_t Size() const; void Clear(); + void ResetRuntime(); void Each(const EntityTraverseFunc& inFunc) const; ConstIter Begin() const; ConstIter End() const; @@ -367,7 +358,7 @@ namespace Runtime { Mirror::Any FindDyn(CompClass inClass, Entity inEntity) const; Mirror::Any GetDyn(CompClass inClass, Entity inEntity); Mirror::Any GetDyn(CompClass inClass, Entity inEntity) const; - CompEvents& EventsDyn(CompClass inClass, Entity inEntity); + CompEvents& EventsDyn(CompClass inClass); RuntimeView RuntimeView(const RuntimeViewRule& inRule); // global component static @@ -412,12 +403,14 @@ namespace Runtime { Internal::EntityPool entities; std::unordered_map globalComps; std::unordered_map archetypes; + // transients std::unordered_map compEvents; std::unordered_map globalCompEvents; }; class SystemRegistry { public: + // TODO private: }; @@ -436,48 +429,9 @@ namespace Runtime::Internal { using ArgsTupleType = std::tuple; }; - template - CompRtti CompRtti::From() - { - CompRtti result; - result.clazz = Internal::GetClass(); - result.moveConstruct = &MoveConstructImpl; - result.moveAssign = &MoveAssignImpl; - result.destructor = &DestructImpl; - result.get = &GetImpl; - result.bound = false; - result.offset = 0; - return result; - } - - template - Mirror::Any CompRtti::MoveConstructImpl(ElemPtr inElem, size_t inOffset, const Mirror::Argument& inOther) - { - void* compBegin = static_cast(inElem) + inOffset; - new(compBegin) T(std::move(inOther.As())); - return GetImpl(inElem, inOffset); - } - - template - Mirror::Any CompRtti::MoveAssignImpl(ElemPtr inElem, size_t inOffset, const Mirror::Argument& inOther) - { - auto compRef = GetImpl(inElem, inOffset); - compRef.template As() = std::move(inOther.As()); - return compRef; - } - - template - void CompRtti::DestructImpl(ElemPtr inElem, size_t inOffset) - { - auto compRef = GetImpl(inElem, inOffset); - compRef.template As().~T(); - } - - template - Mirror::Any CompRtti::GetImpl(ElemPtr inElem, size_t inOffset) + inline auto Archetype::All() const { - void* compBegin = static_cast(inElem) + inOffset; - return { std::ref(*static_cast(compBegin)) }; + return elemMap | std::ranges::views::values; } } // namespace Runtime::Internal @@ -684,57 +638,19 @@ namespace Runtime { template C& ECRegistry::Emplace(Entity inEntity, Args&&... inArgs) { - Assert(Valid(inEntity)); - const auto* clazz = Internal::GetClass(); - const Internal::ArchetypeId archetypeId = entities.GetArchetype(inEntity); - Internal::Archetype& archetype = archetypes.at(archetypeId); - - const Internal::ArchetypeId newArchetypeId = archetypeId + clazz->GetTypeInfo()->id; - entities.SetArchetype(inEntity, newArchetypeId); - - Internal::Archetype* newArchetype; - if (archetypes.contains(newArchetypeId)) { - newArchetype = &archetypes.at(newArchetypeId); - newArchetype->EmplaceElem(inEntity, archetype.GetElem(inEntity), archetype.GetRttiVec()); - archetype.EraseElem(inEntity); - } else { - archetypes.emplace(newArchetypeId, Internal::Archetype(archetype.NewRttiVecByAdd(Internal::CompRtti::From()))); - newArchetype = &archetypes.at(newArchetypeId); - newArchetype->EmplaceElem(inEntity); - } - - C tempObj(std::forward(inArgs)...); - Mirror::Any compRef = newArchetype->EmplaceComp(inEntity, clazz, std::ref(tempObj)); - NotifyConstructed(inEntity); - return compRef.As(); + return EmplaceDyn(Internal::GetClass(), inEntity, Mirror::ForwardAsArgList(std::forward(inArgs)...)).template As(); } template void ECRegistry::Remove(Entity inEntity) { - Assert(Valid(inEntity) && Has(inEntity)); - const auto* clazz = Internal::GetClass(); - const Internal::ArchetypeId archetypeId = entities.GetArchetype(inEntity); - Internal::Archetype& archetype = archetypes.at(archetypeId); - - const Internal::ArchetypeId newArchetypeId = archetypeId - clazz->GetTypeInfo()->id; - entities.SetArchetype(inEntity, newArchetypeId); - - if (!archetypes.contains(newArchetypeId)) { - archetypes.emplace(newArchetypeId, Internal::Archetype(archetype.NewRttiVecByRemove(Internal::CompRtti::From()))); - } - NotifyRemove(inEntity); - Internal::Archetype& newArchetype = archetypes.at(newArchetypeId); - newArchetype.EmplaceElem(inEntity, archetype.GetElem(inEntity), archetype.GetRttiVec()); - archetype.EraseElem(inEntity); + RemoveDyn(Internal::GetClass(), inEntity); } template void ECRegistry::Update(Entity inEntity, F&& inFunc) { - Assert(Valid(inEntity) && Has()); - inFunc(Get(inEntity)); - NotifyUpdated(inEntity); + UpdateDyn(Internal::GetClass(), inEntity, std::forward(inFunc)); } template @@ -747,10 +663,7 @@ namespace Runtime { template bool ECRegistry::Has(Entity inEntity) const { - Assert(Valid(inEntity)); - return archetypes - .at(entities.GetArchetype(inEntity)) - .Contains(Internal::GetClass()); + return HasDyn(Internal::GetClass(), inEntity); } template @@ -768,21 +681,13 @@ namespace Runtime { template C& ECRegistry::Get(Entity inEntity) { - Assert(Valid(inEntity) && Has()); - Mirror::Any compRef = archetypes - .at(entities.GetArchetype(inEntity)) - .GetComp(inEntity, Internal::GetClass()); - return compRef.As(); + return GetDyn(Internal::GetClass(), inEntity).template As(); } template const C& ECRegistry::Get(Entity inEntity) const { - Assert(Valid(inEntity) && Has()); - Mirror::Any compRef = archetypes - .at(entities.GetArchetype(inEntity)) - .GetComp(inEntity, Internal::GetClass()); - return compRef.As(); + return GetDyn(Internal::GetClass(), inEntity).template As(); } template @@ -794,7 +699,7 @@ namespace Runtime { template ECRegistry::CompEvents& ECRegistry::Events() { - return compEvents[Internal::GetClass()]; + return EventsDyn(Internal::GetClass()); } template @@ -818,26 +723,19 @@ namespace Runtime { template G& ECRegistry::GEmplace(Args&&... inArgs) { - Assert(!GHas()); - globalComps.emplace(Internal::GetClass(), Mirror::Any(G(std::forward(inArgs))...)); - GNotifyConstructed(); - return GGet(); + return GEmplaceDyn(Internal::GetClass(), Mirror::ForwardAsArgList(std::forward(inArgs)...)); } template void ECRegistry::GRemove() { - Assert(GHas()); - GNotifyRemove(); - globalComps.erase(Internal::GetClass()); + return GRemoveDyn(Internal::GetClass()); } template void ECRegistry::GUpdate(F&& inFunc) { - Assert(GHas()); - inFunc(GGet()); - GNotifyUpdated(); + GUpdateDyn(Internal::GetClass(), std::forward(inFunc)); } template @@ -850,7 +748,7 @@ namespace Runtime { template bool ECRegistry::GHas() const { - return globalComps.contains(Internal::GetClass()); + return GHasDyn(Internal::GetClass()); } template @@ -868,21 +766,19 @@ namespace Runtime { template G& ECRegistry::GGet() { - Assert(GHas()); - return globalComps.at(Internal::GetClass()).template As(); + return GGetDyn(Internal::GetClass()).template As(); } template const G& ECRegistry::GGet() const { - Assert(GHas()); - return globalComps.at(Internal::GetClass()).template As(); + return GGetDyn(Internal::GetClass()).template As(); } template ECRegistry::GCompEvents& ECRegistry::GEvents() { - return globalCompEvents[Internal::GetClass()]; + return GEventsDyn(Internal::GetClass()); } template diff --git a/Engine/Source/Runtime/Src/ECS.cpp b/Engine/Source/Runtime/Src/ECS.cpp index e31888ca..3e8402c4 100644 --- a/Engine/Source/Runtime/Src/ECS.cpp +++ b/Engine/Source/Runtime/Src/ECS.cpp @@ -5,7 +5,12 @@ #include namespace Runtime::Internal { - CompRtti::CompRtti() = default; + CompRtti::CompRtti(CompClass inClass) + : clazz(inClass) + , bound(false) + , offset(0) + { + } void CompRtti::Bind(size_t inOffset) { @@ -13,24 +18,30 @@ namespace Runtime::Internal { offset = inOffset; } - Mirror::Any CompRtti::MoveConstruct(ElemPtr inElem, const Mirror::Argument& inOther) const + Mirror::Any CompRtti::MoveConstruct(ElemPtr inElem, const Mirror::Any& inOther) const { - return moveConstruct(inElem, offset, inOther); + auto* compBegin = static_cast(inElem) + offset; + return clazz->InplaceNewDyn(compBegin, { inOther }); } - Mirror::Any CompRtti::MoveAssign(ElemPtr inElem, const Mirror::Argument& inOther) const + Mirror::Any CompRtti::MoveAssign(ElemPtr inElem, const Mirror::Any& inOther) const { - return moveAssign(inElem, offset, inOther); + auto* compBegin = static_cast(inElem) + offset; + auto compRef = clazz->InplaceGetObject(compBegin); + compRef.MoveAssign(inOther); + return compRef; } void CompRtti::Destruct(ElemPtr inElem) const { - return destructor(inElem, offset); + auto* compBegin = static_cast(inElem) + offset; + clazz->DestructDyn(clazz->InplaceGetObject(compBegin)); } Mirror::Any CompRtti::Get(ElemPtr inElem) const { - return get(inElem, offset); + auto* compBegin = static_cast(inElem) + offset; + return clazz->InplaceGetObject(compBegin); } CompClass CompRtti::Class() const @@ -140,7 +151,7 @@ namespace Runtime::Internal { elemMap.at(elemIndex) = entityToLastElem; } - ElemPtr Archetype::GetElem(Entity inEntity) + ElemPtr Archetype::GetElem(Entity inEntity) const { return ElemAt(entityMap.at(inEntity)); } @@ -151,14 +162,15 @@ namespace Runtime::Internal { return GetCompRtti(inCompClass).Get(element); } - size_t Archetype::Size() const + Mirror::Any Archetype::GetComp(Entity inEntity, CompClass inCompClass) const { - return size; + ElemPtr element = GetElem(inEntity); + return GetCompRtti(inCompClass).Get(element).ConstRef(); } - auto Archetype::All() const + size_t Archetype::Size() const { - return elemMap | std::ranges::views::values; + return size; } const std::vector& Archetype::GetRttiVec() const @@ -199,14 +211,14 @@ namespace Runtime::Internal { return rttiVec[rttiMap.at(clazz)]; } - ElemPtr Archetype::ElemAt(std::vector& inMemory, size_t inIndex) // NOLINT + ElemPtr Archetype::ElemAt(std::vector& inMemory, size_t inIndex) const // NOLINT { return inMemory.data() + (inIndex * elemSize); } - ElemPtr Archetype::ElemAt(size_t inIndex) + ElemPtr Archetype::ElemAt(size_t inIndex) const { - return ElemAt(memory, inIndex); + return ElemAt(const_cast&>(memory), inIndex); } size_t Archetype::Capacity() const @@ -492,14 +504,15 @@ namespace Runtime { ECRegistry::ECRegistry() = default; - ECRegistry::~ECRegistry() = default; + ECRegistry::~ECRegistry() + { + ResetRuntime(); + } ECRegistry::ECRegistry(const ECRegistry& inOther) : entities(inOther.entities) , globalComps(inOther.globalComps) , archetypes(inOther.archetypes) - , compEvents(inOther.compEvents) - , globalCompEvents(inOther.globalCompEvents) { } @@ -507,8 +520,6 @@ namespace Runtime { : entities(std::move(inOther.entities)) , globalComps(std::move(inOther.globalComps)) , archetypes(std::move(inOther.archetypes)) - , compEvents(std::move(inOther.compEvents)) - , globalCompEvents(std::move(inOther.globalCompEvents)) { } @@ -517,8 +528,6 @@ namespace Runtime { entities = inOther.entities; globalComps = inOther.globalComps; archetypes = inOther.archetypes; - compEvents = inOther.compEvents; - globalCompEvents = inOther.globalCompEvents; return *this; } @@ -527,8 +536,6 @@ namespace Runtime { entities = std::move(inOther.entities); globalComps = std::move(inOther.globalComps); archetypes = std::move(inOther.archetypes); - compEvents = std::move(inOther.compEvents); - globalCompEvents = std::move(inOther.globalCompEvents); return *this; } @@ -557,6 +564,11 @@ namespace Runtime { entities.Clear(); globalComps.clear(); archetypes.clear(); + ResetRuntime(); + } + + void ECRegistry::ResetRuntime() + { compEvents.clear(); globalCompEvents.clear(); } @@ -623,6 +635,104 @@ namespace Runtime { return Runtime::Observer { *this }; } + Mirror::Any ECRegistry::EmplaceDyn(CompClass inClass, Entity inEntity, const Mirror::ArgumentList& inArgs) + { + Assert(Valid(inEntity)); + const Internal::ArchetypeId archetypeId = entities.GetArchetype(inEntity); + Internal::Archetype& archetype = archetypes.at(archetypeId); + + const Internal::ArchetypeId newArchetypeId = archetypeId + inClass->GetTypeInfo()->id; + entities.SetArchetype(inEntity, newArchetypeId); + + Internal::Archetype* newArchetype; + if (archetypes.contains(newArchetypeId)) { + newArchetype = &archetypes.at(newArchetypeId); + newArchetype->EmplaceElem(inEntity, archetype.GetElem(inEntity), archetype.GetRttiVec()); + archetype.EraseElem(inEntity); + } else { + archetypes.emplace(newArchetypeId, Internal::Archetype(archetype.NewRttiVecByAdd(Internal::CompRtti(inClass)))); + newArchetype = &archetypes.at(newArchetypeId); + newArchetype->EmplaceElem(inEntity); + } + + Mirror::Any tempObj = inClass->Construct(inArgs); + Mirror::Any compRef = newArchetype->EmplaceComp(inEntity, inClass, tempObj.Ref()); + NotifyConstructedDyn(inClass, inEntity); + return compRef; + } + + void ECRegistry::RemoveDyn(CompClass inClass, Entity inEntity) + { + Assert(Valid(inEntity) && HasDyn(inClass, inEntity)); + const Internal::ArchetypeId archetypeId = entities.GetArchetype(inEntity); + Internal::Archetype& archetype = archetypes.at(archetypeId); + + const Internal::ArchetypeId newArchetypeId = archetypeId - inClass->GetTypeInfo()->id; + entities.SetArchetype(inEntity, newArchetypeId); + + if (!archetypes.contains(newArchetypeId)) { + archetypes.emplace(newArchetypeId, Internal::Archetype(archetype.NewRttiVecByRemove(Internal::CompRtti(inClass)))); + } + NotifyRemoveDyn(inClass, inEntity); + Internal::Archetype& newArchetype = archetypes.at(newArchetypeId); + newArchetype.EmplaceElem(inEntity, archetype.GetElem(inEntity), archetype.GetRttiVec()); + archetype.EraseElem(inEntity); + } + + void ECRegistry::UpdateDyn(CompClass inClass, Entity inEntity, const DynUpdateFunc& inFunc) + { + Assert(Valid(inEntity) && HasDyn(inClass, inEntity)); + inFunc(GetDyn(inClass, inEntity)); + NotifyUpdatedDyn(inClass, inEntity); + } + + ScopedUpdaterDyn ECRegistry::UpdateDyn(CompClass inClass, Entity inEntity) + { + Assert(Valid(inEntity) && HasDyn(inClass, inEntity)); + return { *this, inClass, inEntity, GetDyn(inClass, inEntity) }; + } + + bool ECRegistry::HasDyn(CompClass inClass, Entity inEntity) const + { + Assert(Valid(inEntity)); + return archetypes + .at(entities.GetArchetype(inEntity)) + .Contains(inClass); + } + + Mirror::Any ECRegistry::FindDyn(CompClass inClass, Entity inEntity) + { + return HasDyn(inClass, inEntity) ? GetDyn(inClass, inEntity) : Mirror::Any(); + } + + Mirror::Any ECRegistry::FindDyn(CompClass inClass, Entity inEntity) const + { + return HasDyn(inClass, inEntity) ? GetDyn(inClass, inEntity) : Mirror::Any(); + } + + Mirror::Any ECRegistry::GetDyn(CompClass inClass, Entity inEntity) + { + Assert(Valid(inEntity) && HasDyn(inClass, inEntity)); + Mirror::Any compRef = archetypes + .at(entities.GetArchetype(inEntity)) + .GetComp(inEntity, inClass); + return compRef; + } + + Mirror::Any ECRegistry::GetDyn(CompClass inClass, Entity inEntity) const + { + Assert(Valid(inEntity) && HasDyn(inClass, inEntity)); + Mirror::Any compRef = archetypes + .at(entities.GetArchetype(inEntity)) + .GetComp(inEntity, inClass); + return compRef.ConstRef(); + } + + ECRegistry::CompEvents& ECRegistry::EventsDyn(CompClass inClass) + { + return compEvents[inClass]; + } + void ECRegistry::GNotifyUpdatedDyn(GCompClass inClass) { const auto iter = globalCompEvents.find(inClass); @@ -649,4 +759,64 @@ namespace Runtime { } iter->second.onRemove.Broadcast(*this); } + + Mirror::Any ECRegistry::GEmplaceDyn(GCompClass inClass, const Mirror::ArgumentList& inArgs) + { + Assert(!GHasDyn(inClass)); + globalComps.emplace(inClass, inClass->ConstructDyn(inArgs)); + GNotifyConstructedDyn(inClass); + return GGetDyn(inClass); + } + + void ECRegistry::GRemoveDyn(GCompClass inClass) + { + Assert(GHasDyn(inClass)); + GNotifyRemoveDyn(inClass); + globalComps.erase(inClass); + } + + void ECRegistry::GUpdateDyn(GCompClass inClass, const DynUpdateFunc& inFunc) + { + Assert(GHasDyn(inClass)); + inFunc(GGetDyn(inClass)); + GNotifyUpdatedDyn(inClass); + } + + GScopedUpdaterDyn ECRegistry::GUpdateDyn(GCompClass inClass) + { + Assert(GHasDyn(inClass)); + return { *this, inClass, GGetDyn(inClass) }; + } + + bool ECRegistry::GHasDyn(GCompClass inClass) const + { + return globalComps.contains(inClass); + } + + Mirror::Any ECRegistry::GFindDyn(GCompClass inClass) + { + return GHasDyn(inClass) ? GGetDyn(inClass) : Mirror::Any(); + } + + Mirror::Any ECRegistry::GFindDyn(GCompClass inClass) const + { + return GHasDyn(inClass) ? GGetDyn(inClass) : Mirror::Any(); + } + + Mirror::Any ECRegistry::GGetDyn(GCompClass inClass) + { + Assert(GHasDyn(inClass)); + return globalComps.at(inClass); + } + + Mirror::Any ECRegistry::GGetDyn(GCompClass inClass) const + { + Assert(GHasDyn(inClass)); + return globalComps.at(inClass).ConstRef(); + } + + ECRegistry::GCompEvents& ECRegistry::GEventsDyn(GCompClass inClass) + { + return globalCompEvents[inClass]; + } } // namespace Runtime From 14da8b3ebda69f4baa8238650621a43663d3b7d9 Mon Sep 17 00:00:00 2001 From: FlyAntNotDown <461425614@qq.com> Date: Sat, 30 Nov 2024 11:28:48 +0800 Subject: [PATCH 18/22] feat: support std templates for mirror --- .../Common/Include/Common/Serialization.h | 16 +- Engine/Source/Mirror/Include/Mirror/Mirror.h | 1499 ++++++++++++++++- .../Source/Mirror/Include/Mirror/Registry.h | 19 +- Engine/Source/Mirror/Src/Mirror.cpp | 514 +++++- Engine/Source/Mirror/Test/AnyTest.cpp | 254 +++ Engine/Source/Mirror/Test/AnyTest.h | 16 + Engine/Source/Mirror/Test/RegistryTest.cpp | 4 +- Engine/Source/Runtime/Include/Runtime/Asset.h | 2 +- 8 files changed, 2235 insertions(+), 89 deletions(-) diff --git a/Engine/Source/Common/Include/Common/Serialization.h b/Engine/Source/Common/Include/Common/Serialization.h index 38c317d4..995b80fa 100644 --- a/Engine/Source/Common/Include/Common/Serialization.h +++ b/Engine/Source/Common/Include/Common/Serialization.h @@ -559,6 +559,8 @@ namespace Common { template <> struct Serializer { static constexpr size_t typeId = HashUtils::StrCrc32("std::wstring"); + // windows: 16, macOS: 32 + static_assert(sizeof(std::wstring::value_type) <= sizeof(uint32_t)); static size_t Serialize(BinarySerializeStream& stream, const std::wstring& value) { @@ -567,12 +569,12 @@ namespace Common { const uint64_t size = value.size(); serialized += Serializer::Serialize(stream, size); - const auto* data = reinterpret_cast(value.data()); + const auto* data = static_cast(value.data()); for (auto i = 0; i < size; i++) { - stream.Write(data[i]); + stream.Write(static_cast(data[i])); } - serialized += size * sizeof(std::wstring::value_type); + serialized += size * sizeof(uint32_t); return serialized; } @@ -584,12 +586,14 @@ namespace Common { deserialized += Serializer::Deserialize(stream, size); value.resize(size); - auto* data = reinterpret_cast(value.data()); + auto* data = static_cast(value.data()); for (auto i = 0; i < size; i++) { - stream.Read(data[i]); + uint32_t tempValue; + stream.Read(tempValue); + data[i] = static_cast(tempValue); } - deserialized += size * sizeof(std::wstring::value_type); + deserialized += size * sizeof(uint32_t); return deserialized; } }; diff --git a/Engine/Source/Mirror/Include/Mirror/Mirror.h b/Engine/Source/Mirror/Include/Mirror/Mirror.h index 28f9acc0..12ff4fe2 100644 --- a/Engine/Source/Mirror/Include/Mirror/Mirror.h +++ b/Engine/Source/Mirror/Include/Mirror/Mirror.h @@ -85,10 +85,15 @@ namespace Mirror { class Any; + using TemplateViewId = uint32_t; + using TemplateViewRttiPtr = const void*; + struct AnyRtti { using DetorFunc = void(void*) noexcept; using CopyConstructFunc = void(void*, const void*); using MoveConstructFunc = void(void*, void*) noexcept; + using CopyAssignFunc = void(void*, const void*); + using MoveAssignFunc = void(void*, void*) noexcept; using EqualFunc = bool(const void*, const void*); using GetTypeInfoFunc = const TypeInfo*(); using GetPtrFunc = Any(void*); @@ -99,10 +104,13 @@ namespace Mirror { using JsonSerializeFunc = void(const void*, rapidjson::Value&, rapidjson::Document::AllocatorType&); using JsonDeserializeFunc = void(void*, const rapidjson::Value&); using ToStringFunc = std::string(const void*); + using GetTemplateViewRttiFunc = std::pair(); template static void Detor(void* inThis) noexcept; template static void CopyConstruct(void* inThis, const void* inOther); template static void MoveConstruct(void* inThis, void* inOther) noexcept; + template static void CopyAssign(void* inThis, const void* inOther); + template static void MoveAssign(void* inThis, void* inOther) noexcept; template static bool Equal(const void* inThis, const void* inOther) noexcept; template static const TypeInfo* GetValueType(); template static const TypeInfo* GetConstValueType(); @@ -119,10 +127,13 @@ namespace Mirror { template static void JsonSerialize(const void* inThis, rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator); template static void JsonDeserialize(void* inThis, const rapidjson::Value& inJsonValue); template static std::string ToString(const void* inThis); + template static std::pair GetTemplateViewRtti(); DetorFunc* detor; CopyConstructFunc* copyConstruct; MoveConstructFunc* moveConstruct; + CopyAssignFunc* copyAssign; + MoveAssignFunc* moveAssign; EqualFunc* equal; GetTypeInfoFunc* getValueType; GetTypeInfoFunc* getConstValueType; @@ -139,6 +150,7 @@ namespace Mirror { JsonSerializeFunc* jsonSerialize; JsonDeserializeFunc* jsonDeserialize; ToStringFunc* toString; + GetTemplateViewRttiFunc* getTemplateViewRtti; }; template @@ -146,6 +158,8 @@ namespace Mirror { &AnyRtti::Detor, &AnyRtti::CopyConstruct, &AnyRtti::MoveConstruct, + &AnyRtti::CopyAssign, + &AnyRtti::MoveAssign, &AnyRtti::Equal, &AnyRtti::GetValueType, &AnyRtti::GetConstValueType, @@ -161,7 +175,20 @@ namespace Mirror { &AnyRtti::Deserialize, &AnyRtti::JsonSerialize, &AnyRtti::JsonDeserialize, - &AnyRtti::ToString + &AnyRtti::ToString, + &AnyRtti::GetTemplateViewRtti + }; + + template + struct TemplateViewRttiGetter { + static constexpr TemplateViewId Id(); + static const void* Get(); + }; + + template + concept ValidTemplateView = requires(T object) + { + { T::id } -> std::convertible_to; }; class MIRROR_API Any { @@ -184,9 +211,10 @@ namespace Mirror { template Any(std::reference_wrapper&& inArrayRef); // NOLINT template Any(const std::reference_wrapper& inArrayRef); // NOLINT + // NOTICE: Any::operator=() is designed to reset this and re-construct from new value + // if you want to call assign operator, use CopyAssign() and MoveAssign() instead. Any& operator=(const Any& inOther); Any& operator=(Any&& inOther) noexcept; - template Any& operator=(T&& inValue); template Any& operator=(std::reference_wrapper& inRef); template Any& operator=(std::reference_wrapper&& inRef); @@ -197,6 +225,16 @@ namespace Mirror { template Any& operator=(std::reference_wrapper&& inArrayRef); // NOLINT template Any& operator=(const std::reference_wrapper& inArrayRef); // NOLINT + Any& CopyAssign(Any& inOther); + Any& CopyAssign(const Any& inOther); + Any& MoveAssign(Any& inOther) noexcept; + Any& MoveAssign(const Any& inOther) noexcept; + const Any& CopyAssign(Any& inOther) const; + const Any& CopyAssign(const Any& inOther) const; + const Any& MoveAssign(Any& inOther) const noexcept; + const Any& MoveAssign(const Any& inOther) const noexcept; + // TODO rvalue version CopyAssign/MoveAssign + template bool Convertible(); template bool Convertible() const; @@ -207,6 +245,9 @@ namespace Mirror { template T PolyAs(); template T PolyAs() const; + template bool CanAsTemplateView() const; + TemplateViewRttiPtr GetTemplateViewRtti() const; + bool IsArray() const; Any At(uint32_t inIndex); Any At(uint32_t inIndex) const; @@ -290,11 +331,12 @@ namespace Mirror { template void ConstructFromArrayValue(T (&inValue)[N]); template void ConstructFromArrayValue(T (&&inValue)[N]); template void ConstructFromArrayRef(std::reference_wrapper inRef); - void PerformCopyConstruct(const Any& inOther); void PerformCopyConstructWithPolicy(const Any& inOther, AnyPolicy inPolicy); void PerformCopyConstructForElementWithPolicy(const Any& inOther, AnyPolicy inPolicy, uint32_t inIndex); - void PerformMoveConstruct(Any&& inOther); + void PerformMoveConstruct(Any&& inOther) noexcept; + void PerformCopyAssign(const Any& inOther) const; + void PerformMoveAssign(const Any& inOther) const noexcept; uint32_t ElementNum() const; uint32_t arrayLength; @@ -320,6 +362,9 @@ namespace Mirror { template T As() const; + template bool CanAsTemplateView() const; + TemplateViewRttiPtr GetTemplateViewRtti() const; + bool IsMemoryHolder() const; bool IsRef() const; bool IsNonConstRef() const; @@ -329,6 +374,8 @@ namespace Mirror { const TypeInfo* AddPointerType() const; const TypeInfo* RemovePointerType() const; + // TODO more proxy func + private: template decltype(auto) Delegate(F&& inFunc) const; @@ -337,6 +384,13 @@ namespace Mirror { using ArgumentList = std::vector; + template Any ForwardAsAny(T&& value); + template Argument ForwardAsArg(T&& value); + template ArgumentList ForwardAsArgList(Args&&... args); + template Any ForwardAsAnyByValue(T&& value); + template Argument ForwardAsArgByValue(T&& value); + template ArgumentList ForwardAsArgListByValue(Args&&... args); + struct MIRROR_API Id { static Id null; @@ -541,13 +595,15 @@ namespace Mirror { public: ~Destructor() override; - template void Invoke(C&& object) const; + template void Destruct(C&& object) const; + template void Delete(C* object) const; const std::string& GetOwnerName() const; const Id& GetOwnerId() const; const Class& GetOwner() const; FieldAccess GetAccess() const; - void InvokeDyn(const Argument& argument) const; + void DestructDyn(const Argument& argument) const; + void DeleteDyn(const Argument& argument) const; private: friend class Registry; @@ -560,6 +616,7 @@ namespace Mirror { Id owner; FieldAccess access; Invoker destructor; + Invoker deleter; }; explicit Destructor(ConstructParams&& params); @@ -567,6 +624,7 @@ namespace Mirror { Id owner; FieldAccess access; Invoker destructor; + Invoker deleter; }; class MIRROR_API MemberVariable final : public ReflNode { @@ -708,9 +766,12 @@ namespace Mirror { ~Class() override; - template Any Construct(Args&&... args); - template Any New(Args&&... args); - template Any InplaceNew(void* ptr, Args&&... args); + template Any Construct(Args&&... args) const; + template Any New(Args&&... args) const; + template Any InplaceNew(void* ptr, Args&&... args) const; + template void Destruct(C&& object) const; + template void Delete(C* object) const; + Any InplaceGetObject(void* ptr) const; void ForEachStaticVariable(const VariableTraverser& func) const; void ForEachStaticFunction(const FunctionTraverser& func) const; @@ -749,6 +810,8 @@ namespace Mirror { Any ConstructDyn(const ArgumentList& arguments) const; Any NewDyn(const ArgumentList& arguments) const; Any InplaceNewDyn(void* ptr, const ArgumentList& arguments) const; + void DestructDyn(const Argument& argument) const; + void DeleteDyn(const Argument& argument) const; private: static std::unordered_map typeToIdMap; @@ -757,12 +820,14 @@ namespace Mirror { template friend class ClassRegistry; using BaseClassGetter = std::function; + using InplaceGetter = std::function; struct ConstructParams { Id id; const TypeInfo* typeInfo; size_t memorySize; BaseClassGetter baseClassGetter; + InplaceGetter inplaceGetter; std::function defaultObjectCreator; std::optional destructorParams; std::optional defaultConstructorParams; @@ -781,6 +846,7 @@ namespace Mirror { const TypeInfo* typeInfo; size_t memorySize; BaseClassGetter baseClassGetter; + InplaceGetter inplaceGetter; Any defaultObject; std::optional destructor; std::unordered_map constructors; @@ -890,6 +956,652 @@ namespace Mirror { }; } +namespace Mirror { + // ---------------- begin std::optional ---------------- + struct StdOptionalViewRtti { + static constexpr TemplateViewId id = Common::HashUtils::StrCrc32("Mirror::StdOptionalView"); + + using GetElementTypeFunc = const TypeInfo*(); + using HasValueFunc = bool(const Argument&); + using GetValueFunc = Any(const Argument&); + + template static const TypeInfo* GetElementType(); + template static bool HasValue(const Argument& inArg); + template static Any GetValue(const Argument& inArg); + + GetElementTypeFunc* getElementType; + HasValueFunc* hasValue; + GetValueFunc* getValue; + }; + + template + static constexpr StdOptionalViewRtti stdOptionalViewRttiImpl = { + &StdOptionalViewRtti::GetElementType, + &StdOptionalViewRtti::HasValue, + &StdOptionalViewRtti::GetValue + }; + + template + struct TemplateViewRttiGetter> { + static constexpr TemplateViewId Id(); + static const void* Get(); + }; + + class MIRROR_API StdOptionalView { + public: + static constexpr TemplateViewId id = StdOptionalViewRtti::id; + + explicit StdOptionalView(const Argument& inObj); + NonCopyable(StdOptionalView) + NonMovable(StdOptionalView) + + const TypeInfo* ElementType() const; + bool HasValue() const; + Any Value() const; + + private: + const Argument& obj; + const StdOptionalViewRtti* rtti; + }; + // ---------------- end std::optional-- ---------------- + + // ---------------- begin std::pair ----------------- + struct StdPairViewRtti { + static constexpr TemplateViewId id = Common::HashUtils::StrCrc32("Mirror::StdPairView"); + + using GetKeyTypeFunc = const TypeInfo*(); + using GetValueTypeFunc = const TypeInfo*(); + using GetKeyFunc = Any(const Argument&); + using GetValueFunc = Any(const Argument&); + + template static const TypeInfo* GetKeyType(); + template static const TypeInfo* GetValueType(); + template static Any GetKey(const Argument& inObj); + template static Any GetValue(const Argument& inObj); + template static Any GetConstKey(const Argument& inObj); + template static Any GetConstValue(const Argument& inObj); + + GetKeyTypeFunc* getKeyType; + GetValueTypeFunc* getValueType; + GetKeyFunc* getKey; + GetValueFunc* getValue; + GetKeyFunc* getConstKey; + GetValueFunc* getConstValue; + }; + + template + static constexpr StdPairViewRtti stdPairViewRttiImpl = { + &StdPairViewRtti::GetKeyType, + &StdPairViewRtti::GetValueType, + &StdPairViewRtti::GetKey, + &StdPairViewRtti::GetValue, + &StdPairViewRtti::GetConstKey, + &StdPairViewRtti::GetConstValue + }; + + template + struct TemplateViewRttiGetter> { + static constexpr TemplateViewId Id(); + static const void* Get(); + }; + + class MIRROR_API StdPairView { + public: + static constexpr TemplateViewId id = StdPairViewRtti::id; + + explicit StdPairView(const Argument& inObj); + NonCopyable(StdPairView) + NonMovable(StdPairView) + + const TypeInfo* KeyType() const; + const TypeInfo* ValueType() const; + Any Key() const; + Any Value() const; + Any ConstKey() const; + Any ConstValue() const; + + private: + const Argument& obj; + const StdPairViewRtti* rtti; + }; + // ---------------- end std::pair ------------------- + + // ---------------- begin std::array ------------------- + struct StdArrayViewRtti { + static constexpr TemplateViewId id = Common::HashUtils::StrCrc32("Mirror::StdArrayView"); + + using GetElementTypeFunc = const TypeInfo*(); + using GetSizeFunc = size_t(); + using GetElementFunc = Any(const Argument&, size_t); + using GetConstElementFunc = Any(const Argument&, size_t); + + template static const TypeInfo* GetElementType(); + template static size_t GetSize(); + template static Any GetElement(const Argument& inObj, size_t inIndex); + template static Any GetConstElement(const Argument& inObj, size_t inIndex); + + GetElementTypeFunc* getElementType; + GetSizeFunc* getSize; + GetElementFunc* getElement; + GetConstElementFunc* getConstElement; + }; + + template + static constexpr StdArrayViewRtti stdArrayViewRttiImpl = { + &StdArrayViewRtti::GetElementType, + &StdArrayViewRtti::GetSize, + &StdArrayViewRtti::GetElement, + &StdArrayViewRtti::GetConstElement, + }; + + template + struct TemplateViewRttiGetter> { + static constexpr TemplateViewId Id(); + static const void* Get(); + }; + + class MIRROR_API StdArrayView { + public: + static constexpr TemplateViewId id = StdArrayViewRtti::id; + + explicit StdArrayView(const Argument& inObj); + NonCopyable(StdArrayView) + NonMovable(StdArrayView) + + const TypeInfo* ElementType() const; + size_t Size() const; + Any At(size_t inIndex) const; + Any ConstAt(size_t inIndex) const; + + private: + const Argument& obj; + const StdArrayViewRtti* rtti; + }; + // ---------------- end std::array --------------------- + + // ---------------- begin std::vector ------------------ + struct StdVectorViewRtti { + static constexpr TemplateViewId id = Common::HashUtils::StrCrc32("Mirror::StdVectorView"); + + using GetElementTypeFunc = const TypeInfo*(); + using GetSizeFunc = size_t(const Argument&); + using GetElementFunc = Any(const Argument&, size_t); + using GetConstElementFunc = Any(const Argument&, size_t); + using EmplaceBackFunc = Any(const Argument&, const Argument&); + using EraseFunc = void(const Argument&, size_t); + + template static const TypeInfo* GetElementType(); + template static size_t GetSize(const Argument& inObj); + template static Any GetElement(const Argument& inObj, size_t inIndex); + template static Any GetConstElement(const Argument& inObj, size_t inIndex); + template static Any EmplaceBack(const Argument& inObj, const Argument& inTempObj); + template static void Erase(const Argument& inObj, size_t inIndex); + + GetElementTypeFunc* getElementType; + GetSizeFunc* getSize; + GetElementFunc* getElement; + GetConstElementFunc* getConstElement; + EmplaceBackFunc* emplaceBack; + EraseFunc* erase; + }; + + template + static constexpr StdVectorViewRtti stdVectorViewRttiImpl = { + &StdVectorViewRtti::GetElementType, + &StdVectorViewRtti::GetSize, + &StdVectorViewRtti::GetElement, + &StdVectorViewRtti::GetConstElement, + &StdVectorViewRtti::EmplaceBack, + &StdVectorViewRtti::Erase + }; + + template + struct TemplateViewRttiGetter> { + static constexpr TemplateViewId Id(); + static const void* Get(); + }; + + class MIRROR_API StdVectorView { + public: + static constexpr TemplateViewId id = StdVectorViewRtti::id; + + explicit StdVectorView(const Argument& inObj); + NonCopyable(StdVectorView) + NonMovable(StdVectorView) + + const TypeInfo* ElementType() const; + size_t Size() const; + Any At(size_t inIndex) const; + Any ConstAt(size_t inIndex) const; + Any EmplaceBack(const Argument& inNewObj) const; + void Erase(size_t inIndex) const; + + private: + const Argument& obj; + const StdVectorViewRtti* rtti; + }; + // ---------------- end std::vector -------------------- + + // ---------------- begin std::list -------------------- + struct StdListViewRtti { + static constexpr TemplateViewId id = Common::HashUtils::StrCrc32("Mirror::StdListViewRtti"); + + using GetElementTypeFunc = const TypeInfo*(); + using GetSizeFunc = size_t(const Argument&); + using TraverseFunc = void(const Argument&, const std::function&); + using ConstTraverseFunc = void(const Argument&, const std::function&); + using EmplaceFrontFunc = Any(const Argument&, const Argument&); + using EmplaceBackFunc = Any(const Argument&, const Argument&); + + template static const TypeInfo* GetElementType(); + template static size_t GetSize(const Argument& inObj); + template static void Traverse(const Argument& inObj, const std::function& inTraverser); + template static void ConstTraverse(const Argument& inObj, const std::function& inTraverser); + template static Any EmplaceFront(const Argument& inObj, const Argument& inTempObj); + template static Any EmplaceBack(const Argument& inObj, const Argument& inTempObj); + + GetElementTypeFunc* getElementType; + GetSizeFunc* getSize; + TraverseFunc* traverse; + ConstTraverseFunc* constTraverse; + EmplaceFrontFunc* emplaceFront; + EmplaceBackFunc* emplaceBack; + }; + + template + static constexpr StdListViewRtti stdListViewRttiImpl = { + &StdListViewRtti::GetElementType, + &StdListViewRtti::GetSize, + &StdListViewRtti::Traverse, + &StdListViewRtti::ConstTraverse, + &StdListViewRtti::EmplaceFront, + &StdListViewRtti::EmplaceBack + }; + + template + struct TemplateViewRttiGetter> { + static constexpr TemplateViewId Id(); + static const void* Get(); + }; + + class MIRROR_API StdListView { + public: + using ElementTraverser = std::function; + static constexpr TemplateViewId id = StdListViewRtti::id; + + explicit StdListView(const Argument& inObj); + NonCopyable(StdListView) + NonMovable(StdListView) + + const TypeInfo* ElementType() const; + size_t Size() const; + void Traverse(const ElementTraverser& inTraverser) const; + void ConstTraverse(const ElementTraverser& inTraverser) const; + Any EmplaceFront(const Argument& inTempObj) const; + Any EmplaceBack(const Argument& inTempObj) const; + + private: + const Argument& obj; + const StdListViewRtti* rtti; + }; + // ---------------- end std::list ---------------------- + + // ------------- begin std::unordered_set -------------- + struct StdUnorderedSetViewRtti { + static constexpr TemplateViewId id = Common::HashUtils::StrCrc32("Mirror::StdUnorderedSetView"); + + using GetElementTypeFunc = const TypeInfo*(); + using GetSizeFunc = size_t(const Argument&); + using TraverseFunc = void(const Argument&, const std::function&); + using ConstTraverseFunc = void(const Argument&, const std::function&); + using ContainsFunc = bool(const Argument&, const Argument&); + using EmplaceFunc = void(const Argument&, const Argument&); + using EraseFunc = void(const Argument&, const Argument&); + + template static const TypeInfo* GetElementType(); + template static size_t GetSize(const Argument& inObj); + template static void Traverse(const Argument& inObj, const std::function& inTraverser); + template static void ConstTraverse(const Argument& inObj, const std::function& inTraverser); + template static bool Contains(const Argument& inObj, const Argument& inElement); + template static void Emplace(const Argument& inObj, const Argument& inTempObj); + template static void Erase(const Argument& inObj, const Argument& inElement); + + GetElementTypeFunc* getElementType; + GetSizeFunc* getSize; + TraverseFunc* traverse; + ConstTraverseFunc* constTraverse; + ContainsFunc* contains; + EmplaceFunc* emplace; + EraseFunc* erase; + }; + + template + static constexpr StdUnorderedSetViewRtti stdUnorderedSetViewRttiImpl = { + &StdUnorderedSetViewRtti::GetElementType, + &StdUnorderedSetViewRtti::GetSize, + &StdUnorderedSetViewRtti::Traverse, + &StdUnorderedSetViewRtti::ConstTraverse, + &StdUnorderedSetViewRtti::Contains, + &StdUnorderedSetViewRtti::Emplace, + &StdUnorderedSetViewRtti::Erase, + }; + + template + struct TemplateViewRttiGetter> { + static constexpr TemplateViewId Id(); + static const void* Get(); + }; + + class MIRROR_API StdUnorderedSetView { + public: + using ElementTraverser = std::function; + static constexpr TemplateViewId id = StdUnorderedSetViewRtti::id; + + explicit StdUnorderedSetView(const Argument& inObj); + NonCopyable(StdUnorderedSetView) + NonMovable(StdUnorderedSetView) + + const TypeInfo* ElementType() const; + size_t Size() const; + void Traverse(const ElementTraverser& inTraverser) const; + void ConstTraverse(const ElementTraverser& inTraverser) const; + bool Contains(const Argument& inElement) const; + void Emplace(const Argument& inTempObj) const; + void Erase(const Argument& inElement) const; + + private: + const Argument& obj; + const StdUnorderedSetViewRtti* rtti; + }; + // ------------- end std::unordered_set ---------------- + + // ----------------- begin std::set -------------------- + struct StdSetViewRtti { + static constexpr TemplateViewId id = Common::HashUtils::StrCrc32("Mirror::StdSetView"); + + using GetElementTypeFunc = const TypeInfo*(); + using GetSizeFunc = size_t(const Argument&); + using TraverseFunc = void(const Argument&, const std::function&); + using ContainsFunc = bool(const Argument&, const Argument&); + using EmplaceFunc = void(const Argument&, const Argument&); + using EraseFunc = void(const Argument&, const Argument&); + + template static const TypeInfo* GetElementType(); + template static size_t GetSize(const Argument& inObj); + template static void Traverse(const Argument& inObj, const std::function& inTraverser); + template static bool Contains(const Argument& inObj, const Argument& inElement); + template static void Emplace(const Argument& inObj, const Argument& inTempObj); + template static void Erase(const Argument& inObj, const Argument& inElement); + + GetElementTypeFunc* getElementType; + GetSizeFunc* getSize; + TraverseFunc* traverse; + ContainsFunc* contains; + EmplaceFunc* emplace; + EraseFunc* erase; + }; + + template + static constexpr StdSetViewRtti stdSetViewRttiImpl = { + &StdSetViewRtti::GetElementType, + &StdSetViewRtti::GetSize, + &StdSetViewRtti::Traverse, + &StdSetViewRtti::Contains, + &StdSetViewRtti::Emplace, + &StdSetViewRtti::Erase + }; + + template + struct TemplateViewRttiGetter> { + static constexpr TemplateViewId Id(); + static const void* Get(); + }; + + class MIRROR_API StdSetView { + public: + using ElementTraverser = std::function; + static constexpr TemplateViewId id = StdSetViewRtti::id; + + explicit StdSetView(const Argument& inObj); + NonCopyable(StdSetView) + NonMovable(StdSetView) + + const TypeInfo* ElementType() const; + size_t Size() const; + void Traverse(const ElementTraverser& inTraverser) const; + bool Contains(const Argument& inElement) const; + void Emplace(const Argument& inTempObj) const; + void Erase(const Argument& inElement) const; + + private: + const Argument& obj; + const StdSetViewRtti* rtti; + }; + // ----------------- end std::set ---------------------- + + // ------------- begin std::unordered_map ----------- + struct StdUnorderedMapViewRtti { + static constexpr TemplateViewId id = Common::HashUtils::StrCrc32("Mirror::StdUnorderedMapView"); + + using GetKeyTypeFunc = const TypeInfo*(); + using GetValueTypeFunc = const TypeInfo*(); + using GetSizeFunc = size_t(const Argument&); + using AtFunc = Any(const Argument&, const Argument&); + using GetOrAddFunc = Any(const Argument&, const Argument&); + using TraverseFunc = void(const Argument&, const std::function&); + using ConstTraverseFunc = void(const Argument&, const std::function&); + using ContainsFunc = bool(const Argument&, const Argument&); + using EmplaceFunc = void(const Argument&, const Argument&, const Argument&); + using EraseFunc = void(const Argument&, const Argument&); + + template static const TypeInfo* GetKeyType(); + template static const TypeInfo* GetValueType(); + template static size_t GetSize(const Argument& inObj); + template static Any At(const Argument& inObj, const Argument& inKey); + template static Any GetOrAdd(const Argument& inObj, const Argument& inKey); + template static void Traverse(const Argument& inObj, const std::function& inTraverser); + template static void ConstTraverse(const Argument& inObj, const std::function& inTraverser); + template static bool Contains(const Argument& inObj, const Argument& inKey); + template static void Emplace(const Argument& inObj, const Argument& inTempKey, const Argument& inTempValue); + template static void Erase(const Argument& inObj, const Argument& inKey); + + GetKeyTypeFunc* getKeyType; + GetValueTypeFunc* getValueType; + GetSizeFunc* getSize; + AtFunc* at; + GetOrAddFunc* getOrAdd; + TraverseFunc* traverse; + ConstTraverseFunc* constTraverse; + ContainsFunc* contains; + EmplaceFunc* emplace; + EraseFunc* erase; + }; + + template + static constexpr StdUnorderedMapViewRtti stdUnorderedMapViewRttiImpl = { + &StdUnorderedMapViewRtti::GetKeyType, + &StdUnorderedMapViewRtti::GetValueType, + &StdUnorderedMapViewRtti::GetSize, + &StdUnorderedMapViewRtti::At, + &StdUnorderedMapViewRtti::GetOrAdd, + &StdUnorderedMapViewRtti::Traverse, + &StdUnorderedMapViewRtti::ConstTraverse, + &StdUnorderedMapViewRtti::Contains, + &StdUnorderedMapViewRtti::Emplace, + &StdUnorderedMapViewRtti::Erase + }; + + template + struct TemplateViewRttiGetter> { + static constexpr TemplateViewId Id(); + static const void* Get(); + };; + + class MIRROR_API StdUnorderedMapView { + public: + using PairTraverser = std::function; + static constexpr TemplateViewId id = StdUnorderedMapViewRtti::id; + + explicit StdUnorderedMapView(const Argument& inObj); + NonCopyable(StdUnorderedMapView) + NonMovable(StdUnorderedMapView) + + const TypeInfo* KeyType() const; + const TypeInfo* ValueType() const; + size_t Size() const; + Any At(const Argument& inKey) const; + Any GetOrAdd(const Argument& inKey) const; + void Traverse(const PairTraverser& inTraverser) const; + void ConstTraverse(const PairTraverser& inTraverser) const; + bool Contains(const Argument& inKey) const; + void Emplace(const Argument& inTempKey, const Argument& inTempValue) const; + void Erase(const Argument& inKey) const; + + private: + const Argument& obj; + const StdUnorderedMapViewRtti* rtti; + }; + // ------------- end std::unordered_map ------------- + + // ----------------- begin std::map ----------------- + struct StdMapViewRtti { + static constexpr TemplateViewId id = Common::HashUtils::StrCrc32("Mirror::StdMapView"); + + using GetKeyTypeFunc = const TypeInfo*(); + using GetValueTypeFunc = const TypeInfo*(); + using GetSizeFunc = size_t(const Argument&); + using AtFunc = Any(const Argument&, const Argument&); + using GetOrAddFunc = Any(const Argument&, const Argument&); + using TraverseFunc = void(const Argument&, const std::function&); + using ConstTraverseFunc = void(const Argument&, const std::function&); + using ContainsFunc = bool(const Argument&, const Argument&); + using EmplaceFunc = void(const Argument&, const Argument&, const Argument&); + using EraseFunc = void(const Argument&, const Argument&); + + template static const TypeInfo* GetKeyType(); + template static const TypeInfo* GetValueType(); + template static size_t GetSize(const Argument& inObj); + template static Any At(const Argument& inObj, const Argument& inKey); + template static Any GetOrAdd(const Argument& inObj, const Argument& inKey); + template static void Traverse(const Argument& inObj, const std::function& inTraverser); + template static void ConstTraverse(const Argument& inObj, const std::function& inTraverser); + template static bool Contains(const Argument& inObj, const Argument& inKey); + template static void Emplace(const Argument& inObj, const Argument& inTempKey, const Argument& inTempValue); + template static void Erase(const Argument& inObj, const Argument& inKey); + + GetKeyTypeFunc* getKeyType; + GetValueTypeFunc* getValueType; + GetSizeFunc* getSize; + AtFunc* at; + GetOrAddFunc* getOrAdd; + TraverseFunc* traverse; + ConstTraverseFunc* constTraverse; + ContainsFunc* contains; + EmplaceFunc* emplace; + EraseFunc* erase; + }; + + template + static constexpr StdMapViewRtti stdMapViewRttiImpl = { + &StdMapViewRtti::GetKeyType, + &StdMapViewRtti::GetValueType, + &StdMapViewRtti::GetSize, + &StdMapViewRtti::At, + &StdMapViewRtti::GetOrAdd, + &StdMapViewRtti::Traverse, + &StdMapViewRtti::ConstTraverse, + &StdMapViewRtti::Contains, + &StdMapViewRtti::Emplace, + &StdMapViewRtti::Erase + }; + + template + struct TemplateViewRttiGetter> { + static constexpr TemplateViewId Id(); + static const void* Get(); + }; + + class MIRROR_API StdMapView { + public: + using PairTraverser = std::function; + static constexpr TemplateViewId id = StdMapViewRtti::id; + + explicit StdMapView(const Argument& inObj); + NonCopyable(StdMapView) + NonMovable(StdMapView) + + const TypeInfo* KeyType() const; + const TypeInfo* ValueType() const; + size_t Size() const; + Any At(const Argument& inKey) const; + Any GetOrAdd(const Argument& inKey) const; + void Traverse(const PairTraverser& inTraverser) const; + void ConstTraverse(const PairTraverser& inTraverser) const; + bool Contains(const Argument& inKey) const; + void Emplace(const Argument& inTempKey, const Argument& inTempValue) const; + void Erase(const Argument& inKey) const; + + private: + const Argument& obj; + const StdMapViewRtti* rtti; + }; + // ----------------- end std::map ------------------- + + // --------------- begin std::tuple ----------------- + struct StdTupleRtti { + static constexpr TemplateViewId id = Common::HashUtils::StrCrc32("Mirror::StdTupleView"); + + using GetSizeFunc = size_t(); + using GetElementTypeFunc = const TypeInfo*(size_t); + using GetElementFunc = Any(const Argument&, size_t); + using TraverseFunc = void(const Argument&, const std::function&); + + template static size_t GetSize(); + template static const TypeInfo* GetElementType(size_t inIndex); + template static Any GetElement(const Argument&, size_t inIndex); + template static void Traverse(const Argument&, const std::function& inVisitor); + + GetSizeFunc* getSize; + GetElementTypeFunc* getElementType; + GetElementFunc* getElement; + TraverseFunc* traverse; + }; + + template + static constexpr StdTupleRtti stdTupleRttiImpl = { + &StdTupleRtti::GetSize, + &StdTupleRtti::GetElementType, + &StdTupleRtti::GetElement, + &StdTupleRtti::Traverse + }; + + template + struct TemplateViewRttiGetter> { + static constexpr TemplateViewId Id(); + static const void* Get(); + }; + + class MIRROR_API StdTupleView { + public: + using Visitor = std::function; + static constexpr TemplateViewId id = StdTupleRtti::id; + + explicit StdTupleView(const Argument& inObj); + NonCopyable(StdTupleView) + NonMovable(StdTupleView) + + size_t Size() const; + const TypeInfo* ElementType(size_t inIndex) const; + Any Get(size_t inIndex) const; + void Traverse(const Visitor& inVisitor) const; + + private: + const Argument& obj; + const StdTupleRtti* rtti; + }; + // --------------- end std::tuple ------------------- +} + namespace Mirror::Internal { template void StaticCheckArgumentType() @@ -900,34 +1612,23 @@ namespace Mirror::Internal { "static version reflection method do no support use Any/Any*/const Any*/Argument as argument, please check you arguments"); } - template - Any ForwardAsAny(T&& value) - { - StaticCheckArgumentType(); - - if constexpr (std::is_lvalue_reference_v) { - return { std::ref(std::forward(value)) }; - } else { - return { std::forward(value) }; - } - } - - template - Argument ForwardAsArgument(T&& value) + template + static std::array, sizeof...(T)> BuildTupleDynGetterArray(std::index_sequence) { - StaticCheckArgumentType(); - return ForwardAsAny(std::forward(value)); + return { + [](const Argument& inObj) -> Any { + return std::get(inObj.As&>()); + }... + }; } - template - ArgumentList ForwardAsArgumentList(Args&&... args) + template + static void TraverseTupleDyn(const Argument& inObj, const std::function& inVisitor, std::index_sequence) { - ArgumentList result; - result.reserve(sizeof...(args)); + auto& tuple = inObj.As&>(); (void) std::initializer_list { ([&]() -> void { - result.emplace_back(ForwardAsArgument(std::forward(args))); + inVisitor(std::ref(std::get(tuple))); }(), 0)... }; - return result; } } @@ -1056,12 +1757,12 @@ namespace Common { // NOLINT static size_t Serialize(BinarySerializeStream& stream, const T& value) { - return SerializeDyn(stream, Mirror::Class::Get(), Mirror::Internal::ForwardAsArgument(value)); + return SerializeDyn(stream, Mirror::Class::Get(), Mirror::ForwardAsArg(value)); } static size_t Deserialize(BinaryDeserializeStream& stream, T& value) { - return DeserializeDyn(stream, Mirror::Class::Get(), Mirror::Internal::ForwardAsArgument(value)); + return DeserializeDyn(stream, Mirror::Class::Get(), Mirror::ForwardAsArg(value)); } }; @@ -1457,12 +2158,12 @@ namespace Common { // NOLINT static void JsonSerialize(rapidjson::Value& outValue, rapidjson::Document::AllocatorType& inAllocator, const T& inValue) { - JsonSerializeDyn(outValue, inAllocator, Mirror::Class::Get(), Mirror::Internal::ForwardAsArgument(inValue)); + JsonSerializeDyn(outValue, inAllocator, Mirror::Class::Get(), Mirror::ForwardAsArg(inValue)); } static void JsonDeserialize(const rapidjson::Value& inValue, T& outValue) { - JsonDeserializeDyn(inValue, Mirror::Class::Get(), Mirror::Internal::ForwardAsArgument(outValue)); + JsonDeserializeDyn(inValue, Mirror::Class::Get(), Mirror::ForwardAsArg(outValue)); } }; @@ -1824,7 +2525,7 @@ namespace Common { // NOLINT static std::string ToString(const T& inValue) { - return ToStringDyn(Mirror::Class::Get(), Mirror::Internal::ForwardAsArgument(inValue)); + return ToStringDyn(Mirror::Class::Get(), Mirror::ForwardAsArg(inValue)); } }; @@ -2013,6 +2714,26 @@ namespace Mirror { } } + template + void AnyRtti::CopyAssign(void* inThis, const void* inOther) + { + if constexpr (std::is_copy_assignable_v) { + *static_cast(inThis) = *static_cast(inOther); + } else { + QuickFailWithReason(std::format("type {} is no support copy assign", GetTypeInfo()->name)); + } + } + + template + void AnyRtti::MoveAssign(void* inThis, void* inOther) noexcept + { + if constexpr (std::is_move_assignable_v) { + *static_cast(inThis) = std::move(*static_cast(inOther)); + } else { + QuickFailWithReason(std::format("type {} is no support move assign", GetTypeInfo()->name)); + } + } + template bool AnyRtti::Equal(const void* inThis, const void* inOther) noexcept { @@ -2129,6 +2850,27 @@ namespace Mirror { return Common::ToString(*static_cast(inThis)); } + template + std::pair AnyRtti::GetTemplateViewRtti() + { + return { + TemplateViewRttiGetter::Id(), + TemplateViewRttiGetter::Get() + }; + } + + template + constexpr TemplateViewId TemplateViewRttiGetter::Id() + { + return 0; + } + + template + const void* TemplateViewRttiGetter::Get() + { + return nullptr; + } + template Any::Any(T&& inValue) { @@ -2321,6 +3063,13 @@ namespace Mirror { return dynamic_cast(As()); } + template + bool Any::CanAsTemplateView() const + { + Assert(!Empty()); + return rtti->getTemplateViewRtti().first == V::id; + } + template void Any::ConstructFromValue(T&& inValue) { @@ -2341,7 +3090,7 @@ namespace Mirror { arrayLength = 0; policy = std::is_const_v ? AnyPolicy::constRef : AnyPolicy::nonConstRef; rtti = &anyRttiImpl; - info = RefInfo(const_cast(&inRef.get()), sizeof(RawType)); + info = RefInfo(const_cast(std::addressof(inRef.get())), sizeof(RawType)); } template @@ -2391,6 +3140,14 @@ namespace Mirror { }); } + template + bool Argument::CanAsTemplateView() const + { + return Delegate([](auto&& value) -> decltype(auto) { + return value.template CanAsTemplateView(); + }); + } + template decltype(auto) Argument::Delegate(F&& inFunc) const { @@ -2408,6 +3165,62 @@ namespace Mirror { return inFunc(Any {}); } + template + Any ForwardAsAny(T&& value) + { + Internal::StaticCheckArgumentType(); + + if constexpr (std::is_lvalue_reference_v) { + return { std::ref(std::forward(value)) }; + } else { + return { std::forward(value) }; + } + } + + template + Argument ForwardAsArg(T&& value) + { + Internal::StaticCheckArgumentType(); + return ForwardAsAny(std::forward(value)); + } + + template + ArgumentList ForwardAsArgList(Args&&... args) + { + ArgumentList result; + result.reserve(sizeof...(args)); + (void) std::initializer_list { ([&]() -> void { + result.emplace_back(ForwardAsArg(std::forward(args))); + }(), 0)... }; + return result; + } + + template + Any ForwardAsAnyByValue(T&& value) + { + Internal::StaticCheckArgumentType(); + auto any = ForwardAsAny(std::forward(value)); + return any.IsMemoryHolder() ? any : any.Value(); + } + + template + Argument ForwardAsArgByValue(T&& value) + { + Internal::StaticCheckArgumentType(); + return { ForwardAsAnyByValue(std::forward(value)) }; + } + + template + ArgumentList ForwardAsArgListByValue(Args&&... args) + { + ArgumentList result; + result.reserve(sizeof...(args)); + (void) std::initializer_list { ([&]() -> void { + result.emplace_back(ForwardAsArgByValue(std::forward(args))); + }(), 0)... }; + return result; + } + template Id::Id(const char(&inName)[N]) : hash(Common::HashUtils::StrCrc32(inName)) @@ -2418,55 +3231,61 @@ namespace Mirror { template void Variable::Set(T&& value) const { - SetDyn(Internal::ForwardAsArgument(std::forward(value))); + SetDyn(ForwardAsArg(std::forward(value))); } template Any Function::Invoke(Args&&... args) const { - return InvokeDyn(Internal::ForwardAsArgumentList(std::forward(args)...)); + return InvokeDyn(ForwardAsArgList(std::forward(args)...)); } template Any Constructor::Construct(Args&&... args) const { - return ConstructDyn(Internal::ForwardAsArgumentList(std::forward(args)...)); + return ConstructDyn(ForwardAsArgList(std::forward(args)...)); } template Any Constructor::New(Args&&... args) const { - return NewDyn(Internal::ForwardAsArgumentList(std::forward(args)...)); + return NewDyn(ForwardAsArgList(std::forward(args)...)); } template Any Constructor::InplaceNew(Args&&... args) const { - return InplaceNewDyn(Internal::ForwardAsArgumentList(std::forward(args)...)); + return InplaceNewDyn(ForwardAsArgList(std::forward(args)...)); + } + + template + void Destructor::Destruct(C&& object) const + { + DestructDyn(ForwardAsArg(std::forward(object))); } template - void Destructor::Invoke(C&& object) const + void Destructor::Delete(C* object) const { - InvokeDyn(Internal::ForwardAsArgument(std::forward(object))); + DeleteDyn(ForwardAsArg(object)); } template void MemberVariable::Set(C&& object, T&& value) const { - SetDyn(Internal::ForwardAsArgument(std::forward(object)), Internal::ForwardAsArgument(std::forward(value))); + SetDyn(ForwardAsArg(std::forward(object)), ForwardAsArg(std::forward(value))); } template Any MemberVariable::Get(C&& object) const { - return GetDyn(Internal::ForwardAsArgument(std::forward(object))); + return GetDyn(ForwardAsArg(std::forward(object))); } template Any MemberFunction::Invoke(C&& object, Args&&... args) const { - return InvokeDyn(Internal::ForwardAsArgument(std::forward(object)), Internal::ForwardAsArgumentList(std::forward(args)...)); + return InvokeDyn(ForwardAsArg(std::forward(object)), ForwardAsArgList(std::forward(args)...)); } template @@ -2488,30 +3307,42 @@ namespace Mirror { } template - Any Class::Construct(Args&&... args) + Any Class::Construct(Args&&... args) const { - return ConstructDyn(Internal::ForwardAsArgumentList(std::forward(args)...)); + return ConstructDyn(ForwardAsArgList(std::forward(args)...)); } template - Any Class::New(Args&&... args) + Any Class::New(Args&&... args) const { - return NewDyn(Internal::ForwardAsArgumentList(std::forward(args)...)); + return NewDyn(ForwardAsArgList(std::forward(args)...)); } template - Any Class::InplaceNew(void* ptr, Args&&... args) + Any Class::InplaceNew(void* ptr, Args&&... args) const { - return InplaceNewDyn(ptr, Internal::ForwardAsArgumentList(std::forward(args)...)); + return InplaceNewDyn(ptr, ForwardAsArgList(std::forward(args)...)); } - template - const Enum* Enum::Find() + template + void Class::Destruct(C&& object) const { - auto iter = typeToIdMap.find(Mirror::GetTypeInfo()->id); - if (iter == typeToIdMap.end()) { - return nullptr; - } + DestructDyn(ForwardAsArg(std::forward(object))); + } + + template + void Class::Delete(C* object) const + { + DeleteDyn(ForwardAsArg(object)); + } + + template + const Enum* Enum::Find() + { + auto iter = typeToIdMap.find(Mirror::GetTypeInfo()->id); + if (iter == typeToIdMap.end()) { + return nullptr; + } return Find(iter->second); } @@ -2526,30 +3357,568 @@ namespace Mirror { template void EnumValue::Set(E& value) const { - SetDyn(Internal::ForwardAsArgument(value)); + SetDyn(ForwardAsArg(value)); } template bool EnumValue::Compare(const E& value) const { - return Compare(Internal::ForwardAsArgument(value)); + return Compare(ForwardAsArg(value)); } template bool Enum::HasValue(E inValue) const { - return HasValue(Internal::ForwardAsArgument(inValue)); + return HasValue(ForwardAsArg(inValue)); } template const EnumValue* Enum::FindValue(E inValue) const { - return FindValue(Internal::ForwardAsArgument(inValue)); + return FindValue(ForwardAsArg(inValue)); } template const EnumValue& Enum::GetValue(E inValue) const { - return GetValue(Internal::ForwardAsArgument(inValue)); + return GetValue(ForwardAsArg(inValue)); } -} + + template + const TypeInfo* StdOptionalViewRtti::GetElementType() + { + return GetTypeInfo(); + } + + template + bool StdOptionalViewRtti::HasValue(const Argument& inArg) + { + return inArg.As&>().has_value(); + } + + template + Any StdOptionalViewRtti::GetValue(const Argument& inArg) + { + return std::ref(inArg.As&>().value()); + } + + template + constexpr TemplateViewId TemplateViewRttiGetter>::Id() + { + return StdOptionalViewRtti::id; + } + + template + const void* TemplateViewRttiGetter>::Get() + { + return &stdOptionalViewRttiImpl; + } + + template + const TypeInfo* StdPairViewRtti::GetKeyType() + { + return GetTypeInfo(); + } + + template + const TypeInfo* StdPairViewRtti::GetValueType() + { + return GetTypeInfo(); + } + + template + Any StdPairViewRtti::GetKey(const Argument& inObj) + { + return { std::ref(inObj.As&>().first) }; + } + + template + Any StdPairViewRtti::GetValue(const Argument& inObj) + { + return { std::ref(inObj.As&>().second) }; + } + + template + Any StdPairViewRtti::GetConstKey(const Argument& inObj) + { + return { std::ref(inObj.As&>().first) }; + } + + template + Any StdPairViewRtti::GetConstValue(const Argument& inObj) + { + return { std::ref(inObj.As&>().second) }; + } + + template + constexpr TemplateViewId TemplateViewRttiGetter>::Id() + { + return StdPairViewRtti::id; + } + + template + const void* TemplateViewRttiGetter>::Get() + { + return &stdPairViewRttiImpl; + } + + template + const TypeInfo* StdArrayViewRtti::GetElementType() + { + return GetTypeInfo(); + } + + template + size_t StdArrayViewRtti::GetSize() + { + return N; + } + + template + Any StdArrayViewRtti::GetElement(const Argument& inObj, size_t inIndex) + { + return { std::ref(inObj.As&>()[inIndex]) }; + } + + template + Any StdArrayViewRtti::GetConstElement(const Argument& inObj, size_t inIndex) + { + return { std::ref(inObj.As&>()[inIndex]) }; + } + + template + constexpr TemplateViewId TemplateViewRttiGetter>::Id() + { + return StdArrayViewRtti::id; + } + + template + const void* TemplateViewRttiGetter>::Get() + { + return &stdArrayViewRttiImpl; + } + + template + const TypeInfo* StdVectorViewRtti::GetElementType() + { + return GetTypeInfo(); + } + + template + size_t StdVectorViewRtti::GetSize(const Argument& inObj) + { + return inObj.As&>().size(); + } + + template + Any StdVectorViewRtti::GetElement(const Argument& inObj, size_t inIndex) + { + if constexpr (std::is_same_v) { + return { inObj.As&>()[inIndex] }; + } else { + return { std::ref(inObj.As&>()[inIndex]) }; + } + } + + template + Any StdVectorViewRtti::GetConstElement(const Argument& inObj, size_t inIndex) + { + if constexpr (std::is_same_v) { + return { inObj.As&>()[inIndex] }; + } else { + return { std::ref(inObj.As&>()[inIndex]) }; + } + } + + template + Any StdVectorViewRtti::EmplaceBack(const Argument& inObj, const Argument& inTempObj) + { + if constexpr (std::is_same_v) { + return { inObj.As&>().emplace_back(std::move(inTempObj.As())) }; + } else { + return { std::ref(inObj.As&>().emplace_back(std::move(inTempObj.As()))) }; + } + } + + template + void StdVectorViewRtti::Erase(const Argument& inObj, size_t inIndex) + { + auto& vec = inObj.As&>(); + vec.erase(vec.begin() + inIndex); + } + + template + constexpr TemplateViewId TemplateViewRttiGetter>::Id() + { + return StdVectorViewRtti::id; + } + + template + const void* TemplateViewRttiGetter>::Get() + { + return &stdVectorViewRttiImpl; + } + + template + const TypeInfo* StdListViewRtti::GetElementType() + { + return GetTypeInfo(); + } + + template + size_t StdListViewRtti::GetSize(const Argument& inObj) + { + return inObj.As&>().size(); + } + + template + void StdListViewRtti::Traverse(const Argument& inObj, const std::function& inTraverser) + { + auto& list = inObj.As&>(); // NOLINT + for (auto& element : list) { + inTraverser(std::ref(element)); + } + } + + template + void StdListViewRtti::ConstTraverse(const Argument& inObj, const std::function& inTraverser) + { + const auto& list = inObj.As&>(); // NOLINT + for (const auto& element : list) { + inTraverser(std::ref(element)); + } + } + + template + Any StdListViewRtti::EmplaceFront(const Argument& inObj, const Argument& inTempObj) + { + T& elemRef = inObj.As&>().emplace_front(std::move(inTempObj.As())); + return { std::ref(elemRef) }; + } + + template + Any StdListViewRtti::EmplaceBack(const Argument& inObj, const Argument& inTempObj) + { + T& elemRef = inObj.As&>().emplace_back(std::move(inTempObj.As())); + return { std::ref(elemRef) }; + } + + template + constexpr TemplateViewId TemplateViewRttiGetter>::Id() + { + return StdListViewRtti::id; + } + + template + const void* TemplateViewRttiGetter>::Get() + { + return &stdListViewRttiImpl; + } + + template + const TypeInfo* StdUnorderedSetViewRtti::GetElementType() + { + return GetTypeInfo(); + } + + template + size_t StdUnorderedSetViewRtti::GetSize(const Argument& inObj) + { + return inObj.As&>().size(); + } + + template + void StdUnorderedSetViewRtti::Traverse(const Argument& inObj, const std::function& inTraverser) + { + auto& set = inObj.As&>(); // NOLINT + for (auto& element : set) { + inTraverser(std::ref(element)); + } + } + + template + void StdUnorderedSetViewRtti::ConstTraverse(const Argument& inObj, const std::function& inTraverser) + { + const auto& set = inObj.As&>(); // NOLINT + for (const auto& element : set) { + inTraverser(std::ref(element)); + } + } + + template + bool StdUnorderedSetViewRtti::Contains(const Argument& inObj, const Argument& inElement) + { + return inObj.As&>().contains(inElement.As()); + } + + template + void StdUnorderedSetViewRtti::Emplace(const Argument& inObj, const Argument& inTempObj) + { + inObj.As&>().emplace(std::move(inTempObj.As())); + } + + template + void StdUnorderedSetViewRtti::Erase(const Argument& inObj, const Argument& inElement) + { + inObj.As&>().erase(inElement.As()); + } + + template + constexpr TemplateViewId TemplateViewRttiGetter>::Id() + { + return StdUnorderedSetViewRtti::id; + } + + template + const void* TemplateViewRttiGetter>::Get() + { + return &stdUnorderedSetViewRttiImpl; + } + + template + const TypeInfo* StdSetViewRtti::GetElementType() + { + return GetTypeInfo(); + } + + template + size_t StdSetViewRtti::GetSize(const Argument& inObj) + { + return inObj.As&>().size(); + } + + template + void StdSetViewRtti::Traverse(const Argument& inObj, const std::function& inTraverser) + { + const auto& set = inObj.As&>(); // NOLINT + for (const auto& element : set) { + inTraverser(std::ref(element)); + } + } + + template + bool StdSetViewRtti::Contains(const Argument& inObj, const Argument& inElement) + { + return inObj.As&>().contains(inElement.As()); + } + + template + void StdSetViewRtti::Emplace(const Argument& inObj, const Argument& inTempObj) + { + inObj.As&>().emplace(inTempObj.As()); + } + + template + void StdSetViewRtti::Erase(const Argument& inObj, const Argument& inElement) + { + inObj.As&>().erase(inElement.As()); + } + + template + constexpr TemplateViewId TemplateViewRttiGetter>::Id() + { + return StdSetViewRtti::id; + } + + template + const void* TemplateViewRttiGetter>::Get() + { + return &stdSetViewRttiImpl; + } + + template + const TypeInfo* StdUnorderedMapViewRtti::GetKeyType() + { + return GetTypeInfo(); + } + + template + const TypeInfo* StdUnorderedMapViewRtti::GetValueType() + { + return GetTypeInfo(); + } + + template + size_t StdUnorderedMapViewRtti::GetSize(const Argument& inObj) + { + return inObj.As&>().size(); + } + + template + Any StdUnorderedMapViewRtti::At(const Argument& inObj, const Argument& inKey) + { + return { std::ref(inObj.As&>().at(inKey.As())) }; + } + + template + Any StdUnorderedMapViewRtti::GetOrAdd(const Argument& inObj, const Argument& inKey) + { + return { std::ref(inObj.As&>()[inKey.As()]) }; + } + + template + void StdUnorderedMapViewRtti::Traverse(const Argument& inObj, const std::function& inTraverser) + { + auto& map = inObj.As&>(); // NOLINT + for (auto& pair : map) { + inTraverser(std::ref(pair.first), std::ref(pair.second)); + } + } + + template + void StdUnorderedMapViewRtti::ConstTraverse(const Argument& inObj, const std::function& inTraverser) + { + const auto& map = inObj.As&>(); // NOLINT + for (const auto& pair : map) { + inTraverser(std::ref(pair.first), std::ref(pair.second)); + } + } + + template + bool StdUnorderedMapViewRtti::Contains(const Argument& inObj, const Argument& inKey) + { + return inObj.As&>().contains(inKey.As()); + } + + template + void StdUnorderedMapViewRtti::Emplace(const Argument& inObj, const Argument& inTempKey, const Argument& inTempValue) + { + inObj.As&>().emplace(std::move(inTempKey.As()), std::move(inTempValue.As())); + } + + template + void StdUnorderedMapViewRtti::Erase(const Argument& inObj, const Argument& inKey) + { + inObj.As&>().erase(inKey.As()); + } + + template + constexpr TemplateViewId TemplateViewRttiGetter>::Id() + { + return StdUnorderedMapViewRtti::id; + } + + template + const void* TemplateViewRttiGetter>::Get() + { + return &stdUnorderedMapViewRttiImpl; + } + + template + const TypeInfo* StdMapViewRtti::GetKeyType() + { + return GetTypeInfo(); + } + + template + const TypeInfo* StdMapViewRtti::GetValueType() + { + return GetTypeInfo(); + } + + template + size_t StdMapViewRtti::GetSize(const Argument& inObj) + { + return inObj.As&>().size(); + } + + template + Any StdMapViewRtti::At(const Argument& inObj, const Argument& inKey) + { + return { std::ref(inObj.As&>().at(inKey.As())) }; + } + + template + Any StdMapViewRtti::GetOrAdd(const Argument& inObj, const Argument& inKey) + { + return { std::ref(inObj.As&>()[inKey.As()]) }; + } + + template + void StdMapViewRtti::Traverse(const Argument& inObj, const std::function& inTraverser) + { + auto& map = inObj.As&>(); // NOLINT + for (auto& pair : map) { + inTraverser(std::ref(pair.first), std::ref(pair.second)); + } + } + + template + void StdMapViewRtti::ConstTraverse(const Argument& inObj, const std::function& inTraverser) + { + const auto& map = inObj.As&>(); // NOLINT + for (const auto& pair : map) { + inTraverser(std::ref(pair.first), std::ref(pair.second)); + } + } + + template + bool StdMapViewRtti::Contains(const Argument& inObj, const Argument& inKey) + { + return inObj.As&>().contains(inKey.As()); + } + + template + void StdMapViewRtti::Emplace(const Argument& inObj, const Argument& inTempKey, const Argument& inTempValue) + { + inObj.As&>().emplace(std::move(inTempKey.As()), std::move(inTempValue.As())); + } + + template + void StdMapViewRtti::Erase(const Argument& inObj, const Argument& inKey) + { + inObj.As&>().erase(inKey.As()); + } + + template + constexpr TemplateViewId TemplateViewRttiGetter>::Id() + { + return StdMapViewRtti::id; + } + + template + const void* TemplateViewRttiGetter>::Get() + { + return &stdMapViewRttiImpl; + } + + template + size_t StdTupleRtti::GetSize() + { + return std::tuple_size_v>; + } + + template + const TypeInfo* StdTupleRtti::GetElementType(size_t inIndex) + { + static std::array types = { GetTypeInfo()... }; + Assert(inIndex < types.size()); + return types[inIndex]; + } + + template + Any StdTupleRtti::GetElement(const Argument& inObj, size_t inIndex) + { + static std::array, sizeof...(T)> getters = Internal::BuildTupleDynGetterArray(std::make_index_sequence {}); + Assert(inIndex < getters.size()); + return getters[inIndex](inObj); + } + + template + void StdTupleRtti::Traverse(const Argument& inObj, const std::function& inVisitor) + { + Internal::TraverseTupleDyn(inObj, inVisitor, std::make_index_sequence {}); + } + + template + constexpr TemplateViewId TemplateViewRttiGetter>::Id() + { + return StdTupleRtti::id; + } + + template + const void* TemplateViewRttiGetter>::Get() + { + return &stdTupleRttiImpl; + } +} // namespace Mirror diff --git a/Engine/Source/Mirror/Include/Mirror/Registry.h b/Engine/Source/Mirror/Include/Mirror/Registry.h index 11a25d0f..d9d0ce2c 100644 --- a/Engine/Source/Mirror/Include/Mirror/Registry.h +++ b/Engine/Source/Mirror/Include/Mirror/Registry.h @@ -250,15 +250,15 @@ namespace Mirror { params.argRemovePointerTypeInfos = { GetTypeInfo>()... }; params.stackConstructor = [](const ArgumentList& args) -> Any { Assert(argsTupleSize == args.size()); - return Internal::ForwardAsAny(Internal::InvokeConstructorStack(args, std::make_index_sequence {})); + return ForwardAsAny(Internal::InvokeConstructorStack(args, std::make_index_sequence {})); }; params.heapConstructor = [](const ArgumentList& args) -> Any { Assert(argsTupleSize == args.size()); - return Internal::ForwardAsAny(Internal::InvokeConstructorNew(args, std::make_index_sequence {})); + return ForwardAsAny(Internal::InvokeConstructorNew(args, std::make_index_sequence {})); }; params.inplaceConstructor = [](void* ptr, const ArgumentList& args) -> Any { Assert(argsTupleSize == args.size()); - return Internal::ForwardAsAny(Internal::InvokeConstructorInplace(ptr, args, std::make_index_sequence {})); + return ForwardAsAny(Internal::InvokeConstructorInplace(ptr, args, std::make_index_sequence {})); }; return MetaDataRegistry::SetContext(&clazz.EmplaceConstructor(inId, std::move(params))); @@ -319,7 +319,7 @@ namespace Mirror { Internal::InvokeFunction(args, std::make_index_sequence {}); return {}; } else { - return Internal::ForwardAsAny(Internal::InvokeFunction(args, std::make_index_sequence {})); + return ForwardAsAny(Internal::InvokeFunction(args, std::make_index_sequence {})); } }; @@ -383,7 +383,7 @@ namespace Mirror { Internal::InvokeMemberFunction(object.As(), args, std::make_index_sequence {}); return {}; } else { - return Internal::ForwardAsAny(Internal::InvokeMemberFunction(object.As(), args, std::make_index_sequence {})); + return ForwardAsAny(Internal::InvokeMemberFunction(object.As(), args, std::make_index_sequence {})); } }; @@ -442,7 +442,7 @@ namespace Mirror { Internal::InvokeFunction(args, std::make_index_sequence {}); return {}; } else { - return Internal::ForwardAsAny(Internal::InvokeFunction(args, std::make_index_sequence {})); + return ForwardAsAny(Internal::InvokeFunction(args, std::make_index_sequence {})); } }; @@ -502,6 +502,9 @@ namespace Mirror { return &Mirror::Class::Get(); } }; + params.inplaceGetter = [](void* ptr) -> Any { + return { std::ref(*static_cast(ptr)) }; + }; if constexpr (std::is_default_constructible_v) { params.defaultObjectCreator = []() -> Any { return { C() }; @@ -512,9 +515,11 @@ namespace Mirror { detorParams.owner = inId; detorParams.access = DetorAccess; detorParams.destructor = [](const Argument& object) -> void { - Assert(!object.IsConstRef()); object.As().~C(); }; + detorParams.deleter = [](const Argument& object) -> void { + delete object.As(); + }; params.destructorParams = detorParams; } if constexpr (std::is_default_constructible_v) { diff --git a/Engine/Source/Mirror/Src/Mirror.cpp b/Engine/Source/Mirror/Src/Mirror.cpp index f769b4e5..fb4d0032 100644 --- a/Engine/Source/Mirror/Src/Mirror.cpp +++ b/Engine/Source/Mirror/Src/Mirror.cpp @@ -130,6 +130,66 @@ namespace Mirror { return *this; } + Any& Any::CopyAssign(Any& inOther) + { + Assert(!IsConstRef()); + PerformCopyAssign(inOther); + return *this; + } + + Any& Any::CopyAssign(const Any& inOther) + { + Assert(!IsConstRef()); + PerformCopyAssign(inOther); + return *this; + } + + Any& Any::MoveAssign(Any& inOther) noexcept + { + Assert(!IsConstRef()); + Assert(!inOther.IsRef() || inOther.IsNonConstRef()); + PerformMoveAssign(inOther); + return *this; + } + + Any& Any::MoveAssign(const Any& inOther) noexcept + { + Assert(!IsConstRef()); + Assert(inOther.IsNonConstRef()); + PerformMoveAssign(inOther); + return *this; + } + + const Any& Any::CopyAssign(Any& inOther) const + { + Assert(IsNonConstRef()); + PerformCopyAssign(inOther); + return *this; + } + + const Any& Any::CopyAssign(const Any& inOther) const + { + Assert(IsNonConstRef()); + PerformCopyAssign(inOther); + return *this; + } + + const Any& Any::MoveAssign(Any& inOther) const noexcept + { + Assert(IsNonConstRef()); + Assert(!inOther.IsRef() || inOther.IsNonConstRef()); + PerformMoveAssign(inOther); + return *this; + } + + const Any& Any::MoveAssign(const Any& inOther) const noexcept + { + Assert(IsNonConstRef()); + Assert(inOther.IsNonConstRef()); + PerformMoveAssign(inOther); + return *this; + } + void Any::PerformCopyConstruct(const Any& inOther) { arrayLength = inOther.arrayLength; @@ -189,7 +249,7 @@ namespace Mirror { } } - void Any::PerformMoveConstruct(Any&& inOther) + void Any::PerformMoveConstruct(Any&& inOther) noexcept { arrayLength = inOther.arrayLength; policy = inOther.policy; @@ -210,11 +270,35 @@ namespace Mirror { } } + void Any::PerformCopyAssign(const Any& inOther) const + { + Assert(!Empty() && !inOther.Empty() && arrayLength == inOther.arrayLength && rtti == inOther.rtti); + + for (auto i = 0; i < ElementNum(); i++) { + rtti->copyAssign(Data(i), inOther.Data(i)); + } + } + + void Any::PerformMoveAssign(const Any& inOther) const noexcept + { + Assert(!Empty() && !inOther.Empty() && arrayLength == inOther.arrayLength && rtti == inOther.rtti); + + for (auto i = 0; i < ElementNum(); i++) { + rtti->moveAssign(Data(i), inOther.Data(i)); + } + } + uint32_t Any::ElementNum() const { return std::max(1u, arrayLength); } + TemplateViewRttiPtr Any::GetTemplateViewRtti() const + { + Assert(!Empty()); + return rtti->getTemplateViewRtti().second; + } + bool Any::IsArray() const { return arrayLength > 0; @@ -641,6 +725,13 @@ namespace Mirror { return *this; } + TemplateViewRttiPtr Argument::GetTemplateViewRtti() const + { + return Delegate([](auto&& value) -> decltype(auto) { + return value.GetTemplateViewRtti(); + }); + } + bool Argument::IsMemoryHolder() const { return Delegate([](auto&& value) -> decltype(auto) { @@ -1003,6 +1094,7 @@ namespace Mirror { , owner(std::move(params.owner)) , access(params.access) , destructor(std::move(params.destructor)) + , deleter(std::move(params.deleter)) { } @@ -1030,11 +1122,16 @@ namespace Mirror { return access; } - void Destructor::InvokeDyn(const Argument& argument) const + void Destructor::DestructDyn(const Argument& argument) const { destructor(argument); } + void Destructor::DeleteDyn(const Argument& argument) const + { + deleter(argument); + } + MemberVariable::MemberVariable(ConstructParams&& params) : ReflNode(std::move(params.id)) , owner(std::move(params.owner)) @@ -1235,6 +1332,7 @@ namespace Mirror { , typeInfo(params.typeInfo) , memorySize(params.memorySize) , baseClassGetter(std::move(params.baseClassGetter)) + , inplaceGetter(std::move(params.inplaceGetter)) { CreateDefaultObject(params.defaultObjectCreator); if (params.destructorParams.has_value()) { @@ -1245,6 +1343,8 @@ namespace Mirror { } } + Class::~Class() = default; + bool Class::Has(const Id& inId) { const auto& classes = Registry::Get().classes; @@ -1333,7 +1433,10 @@ namespace Mirror { return result; } - Class::~Class() = default; + Any Class::InplaceGetObject(void* ptr) const + { + return inplaceGetter(ptr); + } void Class::ForEachStaticVariable(const VariableTraverser& func) const { @@ -1482,7 +1585,10 @@ namespace Mirror { const Constructor* Class::FindSuitableConstructor(const ArgumentList& arguments) const { - for (const auto& [constructorName, constructor] : constructors) { + std::vector> candidateAndRates; + candidateAndRates.reserve(constructors.size()); + + for (const auto& constructor : constructors | std::views::values) { const auto& argTypeInfos = constructor.GetArgTypeInfos(); const auto& argRemoveRefTypeInfos = constructor.GetArgRemoveRefTypeInfos(); const auto& argRemovePointerTypeInfos = constructor.GetArgRemovePointerTypeInfos(); @@ -1491,12 +1597,13 @@ namespace Mirror { continue; } - // TODO prefer rvalue params version + uint32_t rate = 0; bool bSuitable = true; for (auto i = 0; i < arguments.size(); i++) { const TypeInfoCompact srcType { arguments[i].Type(), arguments[i].RemoveRefType(), arguments[i].RemovePointerType() }; // NOLINT const TypeInfoCompact dstType { argTypeInfos[i], argRemoveRefTypeInfos[i], argRemovePointerTypeInfos[i] }; // NOLINT if (Convertible(srcType, dstType)) { + rate += dstType.raw->isRValueReference ? 2 : 1; continue; } @@ -1505,10 +1612,11 @@ namespace Mirror { } if (bSuitable) { - return &constructor; + candidateAndRates.emplace_back(&constructor, rate); } } - return nullptr; + std::ranges::sort(candidateAndRates, [](const auto& lhs, const auto& rhs) -> bool { return lhs.second < rhs.second; }); + return candidateAndRates.empty() ? nullptr : candidateAndRates.back().first; } Any Class::ConstructDyn(const ArgumentList& arguments) const @@ -1532,6 +1640,16 @@ namespace Mirror { return constructor->InplaceNewDyn(ptr, arguments); } + void Class::DestructDyn(const Argument& argument) const + { + GetDestructor().DestructDyn(argument); + } + + void Class::DeleteDyn(const Argument& argument) const + { + GetDestructor().DeleteDyn(argument); + } + const Constructor* Class::FindConstructor(const Id& inId) const { const auto iter = constructors.find(inId); @@ -1798,4 +1916,384 @@ namespace Mirror { values.emplace(inId, EnumValue(std::move(inParams))); return values.at(inId); } -} + + StdOptionalView::StdOptionalView(const Argument& inObj) + : obj(inObj) + { + Assert(inObj.CanAsTemplateView()); + rtti = static_cast(inObj.GetTemplateViewRtti()); + } + + const TypeInfo* StdOptionalView::ElementType() const + { + return rtti->getElementType(); + } + + bool StdOptionalView::HasValue() const + { + return rtti->hasValue(obj); + } + + Any StdOptionalView::Value() const + { + return rtti->getValue(obj); + } + + StdPairView::StdPairView(const Argument& inObj) + : obj(inObj) + { + Assert(inObj.CanAsTemplateView()); + rtti = static_cast(inObj.GetTemplateViewRtti()); + } + + const TypeInfo* StdPairView::KeyType() const + { + return rtti->getKeyType(); + } + + const TypeInfo* StdPairView::ValueType() const + { + return rtti->getValueType(); + } + + Any StdPairView::Key() const + { + return rtti->getKey(obj); + } + + Any StdPairView::Value() const + { + return rtti->getValue(obj); + } + + Any StdPairView::ConstKey() const + { + return rtti->getConstKey(obj); + } + + Any StdPairView::ConstValue() const + { + return rtti->getConstValue(obj); + } + + StdArrayView::StdArrayView(const Argument& inObj) + : obj(inObj) + { + Assert(inObj.CanAsTemplateView()); + rtti = static_cast(inObj.GetTemplateViewRtti()); + } + + const TypeInfo* StdArrayView::ElementType() const + { + return rtti->getElementType(); + } + + size_t StdArrayView::Size() const + { + return rtti->getSize(); + } + + Any StdArrayView::At(size_t inIndex) const + { + return rtti->getElement(obj, inIndex); + } + + Any StdArrayView::ConstAt(size_t inIndex) const + { + return rtti->getConstElement(obj, inIndex); + } + + StdVectorView::StdVectorView(const Argument& inObj) + : obj(inObj) + { + Assert(inObj.CanAsTemplateView()); + rtti = static_cast(inObj.GetTemplateViewRtti()); + } + + const TypeInfo* StdVectorView::ElementType() const + { + return rtti->getElementType(); + } + + size_t StdVectorView::Size() const + { + return rtti->getSize(obj); + } + + Any StdVectorView::At(size_t inIndex) const + { + return rtti->getElement(obj, inIndex); + } + + Any StdVectorView::ConstAt(size_t inIndex) const + { + return rtti->getConstElement(obj, inIndex); + } + + Any StdVectorView::EmplaceBack(const Argument& inNewObj) const + { + return rtti->emplaceBack(obj, inNewObj); + } + + void StdVectorView::Erase(size_t inIndex) const + { + rtti->erase(obj, inIndex); + } + + StdListView::StdListView(const Argument& inObj) + : obj(inObj) + { + Assert(inObj.CanAsTemplateView()); + rtti = static_cast(inObj.GetTemplateViewRtti()); + } + + const TypeInfo* StdListView::ElementType() const + { + return rtti->getElementType(); + } + + size_t StdListView::Size() const + { + return rtti->getSize(obj); + } + + void StdListView::Traverse(const ElementTraverser& inTraverser) const + { + rtti->traverse(obj, inTraverser); + } + + void StdListView::ConstTraverse(const ElementTraverser& inTraverser) const + { + rtti->traverse(obj, inTraverser); + } + + Any StdListView::EmplaceFront(const Argument& inTempObj) const + { + return rtti->emplaceFront(obj, inTempObj); + } + + Any StdListView::EmplaceBack(const Argument& inTempObj) const + { + return rtti->emplaceBack(obj, inTempObj); + } + + StdUnorderedSetView::StdUnorderedSetView(const Argument& inObj) + : obj(inObj) + { + Assert(inObj.CanAsTemplateView()); + rtti = static_cast(inObj.GetTemplateViewRtti()); + } + + const TypeInfo* StdUnorderedSetView::ElementType() const + { + return rtti->getElementType(); + } + + size_t StdUnorderedSetView::Size() const + { + return rtti->getSize(obj); + } + + void StdUnorderedSetView::Traverse(const ElementTraverser& inTraverser) const + { + rtti->traverse(obj, inTraverser); + } + + void StdUnorderedSetView::ConstTraverse(const ElementTraverser& inTraverser) const + { + rtti->constTraverse(obj, inTraverser); + } + + bool StdUnorderedSetView::Contains(const Argument& inElement) const + { + return rtti->contains(obj, inElement); + } + + void StdUnorderedSetView::Emplace(const Argument& inTempObj) const + { + rtti->emplace(obj, inTempObj); + } + + void StdUnorderedSetView::Erase(const Argument& inElement) const + { + rtti->erase(obj, inElement); + } + + StdSetView::StdSetView(const Argument& inObj) + : obj(inObj) + { + Assert(inObj.CanAsTemplateView()); + rtti = static_cast(inObj.GetTemplateViewRtti()); + } + + const TypeInfo* StdSetView::ElementType() const + { + return rtti->getElementType(); + } + + size_t StdSetView::Size() const + { + return rtti->getSize(obj); + } + + void StdSetView::Traverse(const ElementTraverser& inTraverser) const + { + rtti->traverse(obj, inTraverser); + } + + bool StdSetView::Contains(const Argument& inElement) const + { + return rtti->contains(obj, inElement); + } + + void StdSetView::Emplace(const Argument& inTempObj) const + { + rtti->emplace(obj, inTempObj); + } + + void StdSetView::Erase(const Argument& inElement) const + { + rtti->erase(obj, inElement); + } + + StdUnorderedMapView::StdUnorderedMapView(const Argument& inObj) + : obj(inObj) + { + Assert(inObj.CanAsTemplateView()); + rtti = static_cast(inObj.GetTemplateViewRtti()); + } + + const TypeInfo* StdUnorderedMapView::KeyType() const + { + return rtti->getKeyType(); + } + + const TypeInfo* StdUnorderedMapView::ValueType() const + { + return rtti->getValueType(); + } + + size_t StdUnorderedMapView::Size() const + { + return rtti->getSize(obj); + } + + Any StdUnorderedMapView::At(const Argument& inKey) const + { + return rtti->at(obj, inKey); + } + + Any StdUnorderedMapView::GetOrAdd(const Argument& inKey) const + { + return rtti->getOrAdd(obj, inKey); + } + + void StdUnorderedMapView::Traverse(const PairTraverser& inTraverser) const + { + rtti->traverse(obj, inTraverser); + } + + void StdUnorderedMapView::ConstTraverse(const PairTraverser& inTraverser) const + { + rtti->constTraverse(obj, inTraverser); + } + + bool StdUnorderedMapView::Contains(const Argument& inKey) const + { + return rtti->contains(obj, inKey); + } + + void StdUnorderedMapView::Emplace(const Argument& inTempKey, const Argument& inTempValue) const + { + rtti->emplace(obj, inTempKey, inTempValue); + } + + void StdUnorderedMapView::Erase(const Argument& inKey) const + { + rtti->erase(obj, inKey); + } + + StdMapView::StdMapView(const Argument& inObj) + : obj(inObj) + { + Assert(inObj.CanAsTemplateView()); + rtti = static_cast(inObj.GetTemplateViewRtti()); + } + + const TypeInfo* StdMapView::KeyType() const + { + return rtti->getKeyType(); + } + + const TypeInfo* StdMapView::ValueType() const + { + return rtti->getValueType(); + } + + size_t StdMapView::Size() const + { + return rtti->getSize(obj); + } + + Any StdMapView::At(const Argument& inKey) const + { + return rtti->at(obj, inKey); + } + + Any StdMapView::GetOrAdd(const Argument& inKey) const + { + return rtti->getOrAdd(obj, inKey); + } + + void StdMapView::Traverse(const PairTraverser& inTraverser) const + { + rtti->traverse(obj, inTraverser); + } + + void StdMapView::ConstTraverse(const PairTraverser& inTraverser) const + { + rtti->constTraverse(obj, inTraverser); + } + + bool StdMapView::Contains(const Argument& inKey) const + { + return rtti->contains(obj, inKey); + } + + void StdMapView::Emplace(const Argument& inTempKey, const Argument& inTempValue) const + { + rtti->emplace(obj, inTempKey, inTempValue); + } + + void StdMapView::Erase(const Argument& inKey) const + { + rtti->erase(obj, inKey); + } + + StdTupleView::StdTupleView(const Argument& inObj) + : obj(inObj) + { + Assert(inObj.CanAsTemplateView()); + rtti = static_cast(inObj.GetTemplateViewRtti()); + } + + size_t StdTupleView::Size() const + { + return rtti->getSize(); + } + + const TypeInfo* StdTupleView::ElementType(size_t inIndex) const + { + return rtti->getElementType(inIndex); + } + + Any StdTupleView::Get(size_t inIndex) const + { + return rtti->getElement(obj, inIndex); + } + + void StdTupleView::Traverse(const Visitor& inVisitor) const + { + rtti->traverse(obj, inVisitor); + } +} // namespace Mirror diff --git a/Engine/Source/Mirror/Test/AnyTest.cpp b/Engine/Source/Mirror/Test/AnyTest.cpp index 03e913be..ff2718b3 100644 --- a/Engine/Source/Mirror/Test/AnyTest.cpp +++ b/Engine/Source/Mirror/Test/AnyTest.cpp @@ -69,6 +69,38 @@ AnyMoveCtorTest::AnyMoveCtorTest(AnyMoveCtorTest&& inOther) noexcept moveTime++; } +AnyCopyAssignTest::AnyCopyAssignTest() + : called(false) +{ +} + +AnyCopyAssignTest::AnyCopyAssignTest(AnyCopyAssignTest&& inOther) noexcept + : called(inOther.called) +{ +} + +AnyCopyAssignTest& AnyCopyAssignTest::operator=(const AnyCopyAssignTest& inOther) +{ + called = true; + return *this; +} + +AnyMoveAssignTest::AnyMoveAssignTest() + : called(false) +{ +} + +AnyMoveAssignTest::AnyMoveAssignTest(AnyMoveAssignTest&& inOther) noexcept + : called(inOther.called) +{ +} + +AnyMoveAssignTest& AnyMoveAssignTest::operator=(AnyMoveAssignTest&& inOther) noexcept +{ + called = true; + return *this; +} + bool AnyBasicTest::operator==(const AnyBasicTest& inRhs) const { return a == inRhs.a @@ -235,6 +267,26 @@ TEST(AnyTest, MoveAssignTest) ASSERT_EQ(a0.TypeId(), a1.TypeId()); } +TEST(AnyTest, ValueCopyAssignTest) +{ + Any a0 = AnyCopyAssignTest(); + ASSERT_EQ(a0.As().called, false); + + Any a1 = AnyCopyAssignTest(); + a0.CopyAssign(a1); + ASSERT_EQ(a0.As().called, true); +} + +TEST(AnyTest, ValueMoveAssignTest) +{ + Any a0 = AnyMoveAssignTest(); + ASSERT_EQ(a0.As().called, false); + + Any a1 = AnyMoveAssignTest(); + a0.MoveAssign(a1); + ASSERT_EQ(a0.As().called, true); +} + TEST(AnyTest, ValueAssignTest) { Any a0 = 1; @@ -1230,3 +1282,205 @@ TEST(AnyTest, ArrayTest) ASSERT_EQ(a6.ArrayLength(), sizeof(v0) / sizeof(int)); ASSERT_EQ(a6[1].As(), 2); } + +TEST(AnyTest, StdOptionalViewTest) +{ + Any a0 = std::optional {}; + const StdOptionalView v0(a0); + ASSERT_EQ(v0.ElementType(), GetTypeInfo()); + ASSERT_FALSE(v0.HasValue()); + + std::optional t0 = 1; + Any a1 = std::ref(t0); + const StdOptionalView v1(a1); + ASSERT_TRUE(v1.HasValue()); + ASSERT_EQ(v1.Value().As(), 1); +} + +TEST(AnyTest, StdPairViewTest) +{ + Any a0 = std::pair { 1, true }; + const StdPairView v0(a0); + ASSERT_EQ(v0.KeyType(), GetTypeInfo()); + ASSERT_EQ(v0.ValueType(), GetTypeInfo()); + ASSERT_EQ(v0.Key().As(), 1); + ASSERT_EQ(v0.Value().As(), true); +} + +TEST(AnyTest, StdArrayViewTest) +{ + Any a0 = std::array { 1, 2, 3 }; + const StdArrayView v0(a0); + ASSERT_EQ(v0.ElementType(), GetTypeInfo()); + ASSERT_EQ(v0.Size(), 3); + for (auto i = 0; i < 3; i++) { + ASSERT_EQ(v0.At(i).As(), i + 1); + ASSERT_EQ(v0.ConstAt(i).As(), i + 1); + }; +} + +TEST(AnyTest, StdVectorViewTest) +{ + Any a0 = std::vector { 1, 2, 3 }; + const StdVectorView v0(a0); + ASSERT_EQ(v0.ElementType(), GetTypeInfo()); + ASSERT_EQ(v0.Size(), 3); + for (auto i = 0; i < 3; i++) { + ASSERT_EQ(v0.At(i).As(), i + 1); + ASSERT_EQ(v0.ConstAt(i).As(), i + 1); + }; + v0.Erase(1); + ASSERT_EQ(v0.Size(), 2); + v0.EmplaceBack(Any(5)); + ASSERT_EQ(v0.Size(), 3); +} + +TEST(AnyTest, StdListViewTest) +{ + std::list t0 = { 1, 2, 3 }; + Any a0 = std::ref(t0); + const StdListView v0(a0); + ASSERT_EQ(v0.ElementType(), GetTypeInfo()); + ASSERT_EQ(v0.Size(), 3); + + int count = 0; + v0.Traverse([&count](const Any& inRef) -> void { + ASSERT_EQ(inRef.As(), ++count); + }); + + v0.EmplaceBack(Any(4)); + ASSERT_EQ(v0.Size(), 4); + v0.EmplaceFront(Any(0)); + ASSERT_EQ(v0.Size(), 5); + + count = 0; + v0.ConstTraverse([&count](const Any& inRef) -> void { + ASSERT_EQ(inRef.As(), count++); + }); +} + +TEST(AnyTest, StdunorderedSetViewTest) +{ + Any a0 = std::unordered_set { 1, 2, 3 }; + const StdUnorderedSetView v0(a0); + ASSERT_EQ(v0.ElementType(), GetTypeInfo()); + ASSERT_EQ(v0.Size(), 3); + + v0.Traverse([](const Any& inRef) -> void { + const int& valueRef = inRef.As(); + ASSERT_TRUE(valueRef >= 1 && valueRef <= 3); + }); + + v0.Emplace(Any(4)); + v0.ConstTraverse([](const Any& inRef) -> void { + const int& valueRef = inRef.As(); + ASSERT_TRUE(valueRef >= 1 && valueRef <= 4); + }); + v0.Erase(Any(1)); + for (auto i = 2; i <= 4; i++) { + v0.Contains(Any(std::ref(i))); + } +} + +TEST(AnyTest, StdSetViewTest) +{ + Any a0 = std::set { 1, 2, 3 }; + const StdSetView v0(a0); + ASSERT_EQ(v0.ElementType(), GetTypeInfo()); + ASSERT_EQ(v0.Size(), 3); + + v0.Traverse([](const Any& inRef) -> void { + const int& valueRef = inRef.As(); + ASSERT_TRUE(valueRef >= 1 && valueRef <= 3); + }); + + v0.Emplace(Any(4)); + v0.Traverse([](const Any& inRef) -> void { + const int& valueRef = inRef.As(); + ASSERT_TRUE(valueRef >= 1 && valueRef <= 4); + }); + v0.Erase(Any(1)); + for (auto i = 2; i <= 4; i++) { + v0.Contains(Any(std::ref(i))); + } +} + +TEST(AnyTest, StdUnorderedMapViewTest) +{ + Any a0 = std::unordered_map { + { 1, false }, + { 2, true } + }; + const StdUnorderedMapView v0(a0); + ASSERT_EQ(v0.KeyType(), GetTypeInfo()); + ASSERT_EQ(v0.ValueType(), GetTypeInfo()); + ASSERT_EQ(v0.Size(), 2); + ASSERT_TRUE(v0.At(Any(2)).As()); + v0.At(Any(1)).As() = true; + + v0.GetOrAdd(Any(3)).As() = true; + ASSERT_TRUE(v0.Contains(Any(3))); + ASSERT_TRUE(v0.At(Any(3)).As()); + v0.Emplace(Any(4), Any(true)); + + auto traverser = [](const Any& inKey, const Any& inValue) -> void { + const int keyNum = inKey.As(); + ASSERT_TRUE(keyNum >= 1 && keyNum <= 4); + ASSERT_TRUE(inValue.As()); + }; + v0.Traverse(traverser); + v0.ConstTraverse(traverser); +} + +TEST(AnyTest, StdMapViewTest) +{ + Any a0 = std::map { + { 1, false }, + { 2, true } + }; + const StdMapView v0(a0); + ASSERT_EQ(v0.KeyType(), GetTypeInfo()); + ASSERT_EQ(v0.ValueType(), GetTypeInfo()); + ASSERT_EQ(v0.Size(), 2); + ASSERT_TRUE(v0.At(Any(2)).As()); + v0.At(Any(1)).As() = true; + + v0.GetOrAdd(Any(3)).As() = true; + ASSERT_TRUE(v0.Contains(Any(3))); + ASSERT_TRUE(v0.At(Any(3)).As()); + v0.Emplace(Any(4), Any(true)); + + auto traverser = [](const Any& inKey, const Any& inValue) -> void { + const int keyNum = inKey.As(); + ASSERT_TRUE(keyNum >= 1 && keyNum <= 4); + ASSERT_TRUE(inValue.As()); + }; + v0.Traverse(traverser); + v0.ConstTraverse(traverser); +} + +TEST(AnyTest, StdTupleViewTest) +{ + Any a0 = std::tuple { 1, true, "2" }; + const StdTupleView v0(a0); + ASSERT_EQ(v0.Size(), 3); + ASSERT_EQ(v0.ElementType(0), GetTypeInfo()); + ASSERT_EQ(v0.ElementType(1), GetTypeInfo()); + ASSERT_EQ(v0.ElementType(2), GetTypeInfo()); + ASSERT_EQ(v0.Get(0).As(), 1); + ASSERT_TRUE(v0.Get(1).As()); + ASSERT_EQ(v0.Get(2).As(), "2"); + + int count = 0; + v0.Traverse([&](const Any& inRef) -> void { + if (count == 0) { + ASSERT_EQ(inRef.As(), 1); + } else if (count == 1) { + ASSERT_TRUE(inRef.As()); + } else if (count == 2) { + ASSERT_EQ(inRef.As(), "2"); + } + count++; + }); + ASSERT_EQ(count, 3); +} diff --git a/Engine/Source/Mirror/Test/AnyTest.h b/Engine/Source/Mirror/Test/AnyTest.h index cfd0d1d4..a91687be 100644 --- a/Engine/Source/Mirror/Test/AnyTest.h +++ b/Engine/Source/Mirror/Test/AnyTest.h @@ -34,6 +34,22 @@ struct AnyMoveCtorTest { uint8_t& moveTime; }; +struct AnyCopyAssignTest { + AnyCopyAssignTest(); + AnyCopyAssignTest(AnyCopyAssignTest&& inOther) noexcept; + AnyCopyAssignTest& operator=(const AnyCopyAssignTest& inOther); + + bool called; +}; + +struct AnyMoveAssignTest { + AnyMoveAssignTest(); + AnyMoveAssignTest(AnyMoveAssignTest&& inOther) noexcept; + AnyMoveAssignTest& operator=(AnyMoveAssignTest&& inOther) noexcept; + + bool called; +}; + struct AnyBasicTest { int a; float b; diff --git a/Engine/Source/Mirror/Test/RegistryTest.cpp b/Engine/Source/Mirror/Test/RegistryTest.cpp index a473dcc9..17afdce1 100644 --- a/Engine/Source/Mirror/Test/RegistryTest.cpp +++ b/Engine/Source/Mirror/Test/RegistryTest.cpp @@ -159,10 +159,10 @@ TEST(RegistryTest, ClassTest) const auto& b = clazz.GetMemberVariable("b"); auto object = constructor.New(1, 2); - Mirror::Any objectRef = *object.As(); + Mirror::Any objectRef = object.Deref(); ASSERT_EQ(a.GetDyn(objectRef).As(), 1); ASSERT_EQ(b.GetDyn(objectRef).As(), 2); - destructor.InvokeDyn(objectRef); + destructor.DeleteDyn(object); } { diff --git a/Engine/Source/Runtime/Include/Runtime/Asset.h b/Engine/Source/Runtime/Include/Runtime/Asset.h index 13aff30d..488f9c98 100644 --- a/Engine/Source/Runtime/Include/Runtime/Asset.h +++ b/Engine/Source/Runtime/Include/Runtime/Asset.h @@ -321,7 +321,7 @@ namespace Runtime { template void AsyncLoad(const Core::Uri& uri, const OnAssetLoaded& onAssetLoaded) { - threadPool.EmplaceTask([this, uri, onAssetLoaded]() -> void { + threadPool.EmplaceTask([=]() -> void { AssetRef result = nullptr; { std::unique_lock lock(mutex); From 7f286abda3cba3cb82a9f0f8eb48cb7618b0cad5 Mon Sep 17 00:00:00 2001 From: FlyAntNotDown <461425614@qq.com> Date: Fri, 6 Dec 2024 19:51:19 +0800 Subject: [PATCH 19/22] feat: gameplay framework update --- Engine/Source/Runtime/Include/Runtime/ECS.h | 80 ++++++++++++++++++--- Engine/Source/Runtime/Src/ECS.cpp | 49 ++++++++++++- 2 files changed, 116 insertions(+), 13 deletions(-) diff --git a/Engine/Source/Runtime/Include/Runtime/ECS.h b/Engine/Source/Runtime/Include/Runtime/ECS.h index 9b3d74d3..de2f0656 100644 --- a/Engine/Source/Runtime/Include/Runtime/ECS.h +++ b/Engine/Source/Runtime/Include/Runtime/ECS.h @@ -9,13 +9,28 @@ #include #include +#include #include +#include namespace Runtime { using Entity = size_t; using CompClass = const Mirror::Class*; using GCompClass = const Mirror::Class*; using SystemClass = const Mirror::Class*; + + class ECRegistry; + + class EClass() System { + public: + explicit System(ECRegistry& inRegistry); + virtual ~System(); + virtual void Setup(); + virtual void Execute(float inDeltaTimeMs); + + protected: + ECRegistry& registry; + }; } namespace Runtime::Internal { @@ -116,11 +131,22 @@ namespace Runtime::Internal { std::set allocated; std::unordered_map archetypeMap; }; + + class SystemFactory { + public: + explicit SystemFactory(SystemClass inClass); + Common::UniqueRef Build(ECRegistry& inRegistry) const; + const std::unordered_map& GetArguments() const; + + private: + void BuildArgumentLists(); + + SystemClass clazz; + std::unordered_map arguments; + }; } namespace Runtime { - class ECRegistry; - template class ScopedUpdater { public: @@ -325,7 +351,7 @@ namespace Runtime { bool Valid(Entity inEntity) const; size_t Size() const; void Clear(); - void ResetRuntime(); + void ResetTransients(); void Each(const EntityTraverseFunc& inFunc) const; ConstIter Begin() const; ConstIter End() const; @@ -408,11 +434,45 @@ namespace Runtime { std::unordered_map globalCompEvents; }; + class SystemGroup { + public: + explicit SystemGroup(std::string inName); + + void AddSystem(SystemClass inClass); + void RemoveSystem(SystemClass inClass); + const std::string& GetName() const; + auto GetSystems() const; + + private: + std::string name; + std::unordered_map systems; + }; + + class Feature { + public: + Feature(); + + SystemGroup& AddSystemGroup(const std::string& inName); + SystemGroup& GetSystemGroup(const std::string& inName); + + private: + std::vector systemGroups; + }; + class SystemRegistry { public: - // TODO + SystemRegistry(); + + SystemGroup& AddSystemGroup(const std::string& inName); + SystemGroup& GetSystemGroup(const std::string& inName); + void UseFeature(const Feature& inFeature); + + // TODO runtime private: + std::vector systemGroups; + // transients + // TODO }; } @@ -565,7 +625,7 @@ namespace Runtime { excludeCompIds.emplace_back(Internal::GetClass()); }(), 0)... }; - for (auto& [_, archetype] : inRegistry.archetypes) { + for (auto& archetype : inRegistry.archetypes | std::views::values) { if (!archetype.ContainsAll(includeCompIds) || !archetype.NotContainsAny(excludeCompIds)) { continue; } @@ -638,7 +698,7 @@ namespace Runtime { template C& ECRegistry::Emplace(Entity inEntity, Args&&... inArgs) { - return EmplaceDyn(Internal::GetClass(), inEntity, Mirror::ForwardAsArgList(std::forward(inArgs)...)).template As(); + return EmplaceDyn(Internal::GetClass(), inEntity, Mirror::ForwardAsArgList(std::forward(inArgs)...)).As(); } template @@ -681,13 +741,13 @@ namespace Runtime { template C& ECRegistry::Get(Entity inEntity) { - return GetDyn(Internal::GetClass(), inEntity).template As(); + return GetDyn(Internal::GetClass(), inEntity).As(); } template const C& ECRegistry::Get(Entity inEntity) const { - return GetDyn(Internal::GetClass(), inEntity).template As(); + return GetDyn(Internal::GetClass(), inEntity).As(); } template @@ -766,13 +826,13 @@ namespace Runtime { template G& ECRegistry::GGet() { - return GGetDyn(Internal::GetClass()).template As(); + return GGetDyn(Internal::GetClass()).As(); } template const G& ECRegistry::GGet() const { - return GGetDyn(Internal::GetClass()).template As(); + return GGetDyn(Internal::GetClass()).As(); } template diff --git a/Engine/Source/Runtime/Src/ECS.cpp b/Engine/Source/Runtime/Src/ECS.cpp index 3e8402c4..92316bd7 100644 --- a/Engine/Source/Runtime/Src/ECS.cpp +++ b/Engine/Source/Runtime/Src/ECS.cpp @@ -4,6 +4,19 @@ #include +namespace Runtime { + System::System(ECRegistry& inRegistry) + : registry(inRegistry) + { + } + + System::~System() = default; + + void System::Setup() {} + + void System::Execute(float inDeltaTimeMs) {} +} + namespace Runtime::Internal { CompRtti::CompRtti(CompClass inClass) : clazz(inClass) @@ -320,6 +333,36 @@ namespace Runtime::Internal { { return allocated.end(); } + + SystemFactory::SystemFactory(SystemClass inClass) + : clazz(inClass) + { + BuildArgumentLists(); + } + + Common::UniqueRef SystemFactory::Build(ECRegistry& inRegistry) const + { + const Mirror::Any system = clazz->New(inRegistry); + const Mirror::Any systemRef = system.Deref(); + for (const auto& [name, argument] : arguments) { + clazz->GetMemberVariable(name).Set(systemRef, argument.ConstRef()); + } + return system.As(); + } + + const std::unordered_map& SystemFactory::GetArguments() const + { + return arguments; + } + + void SystemFactory::BuildArgumentLists() + { + const auto& memberVariables = clazz->GetMemberVariables(); + arguments.reserve(memberVariables.size()); + for (const auto& [id, member] : memberVariables) { + arguments.emplace(id.name, member.Get(clazz->GetDefaultObject())); + } + } } // namespace Runtime::Internal namespace Runtime { @@ -506,7 +549,7 @@ namespace Runtime { ECRegistry::~ECRegistry() { - ResetRuntime(); + ResetTransients(); } ECRegistry::ECRegistry(const ECRegistry& inOther) @@ -564,10 +607,10 @@ namespace Runtime { entities.Clear(); globalComps.clear(); archetypes.clear(); - ResetRuntime(); + ResetTransients(); } - void ECRegistry::ResetRuntime() + void ECRegistry::ResetTransients() { compEvents.clear(); globalCompEvents.clear(); From 4925c8b0348c8ade98bb616746f1c620e92f7c7a Mon Sep 17 00:00:00 2001 From: FlyAntNotDown <461425614@qq.com> Date: Sat, 7 Dec 2024 12:23:42 +0800 Subject: [PATCH 20/22] feat: support github actions tmate debug --- .github/workflows/build.yml | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f6d83207..70d93707 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,6 +1,14 @@ name: Build -on: [pull_request, workflow_dispatch] +on: + pull_request: + workflow_dispatch: + inputs: + debug: + type: boolean + description: 'Enable TMate Debug' + required: false + default: false env: BUILD_TYPE: Release @@ -16,6 +24,12 @@ jobs: runs-on: ${{ matrix.os }} steps: + - name: Setup TMate Session + uses: mxschmitt/action-tmate@v3 + if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug }} + with: + detached: true + - name: Checkout Repo uses: actions/checkout@v2 From 23e0f27147dd085fa215bd5cab18fb24ab6139f3 Mon Sep 17 00:00:00 2001 From: FlyAntNotDown <461425614@qq.com> Date: Sat, 7 Dec 2024 18:46:26 +0800 Subject: [PATCH 21/22] fix: macos build issue --- .github/workflows/build.yml | 4 ++++ CMake/ThirdParty.cmake | 2 +- Engine/Source/Runtime/Include/Runtime/ECS.h | 12 +++++++----- Engine/Source/Runtime/Src/ECS.cpp | 4 ++-- README.md | 19 +++++++++++++++++++ 5 files changed, 33 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 70d93707..90183363 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -30,6 +30,10 @@ jobs: with: detached: true + - name: Set XCode Version + run: sudo xcode-select -s /Library/Developer/CommandLineTools + if: runner.os == 'macOS' + - name: Checkout Repo uses: actions/checkout@v2 diff --git a/CMake/ThirdParty.cmake b/CMake/ThirdParty.cmake index 0c9b910c..1e8a7cb8 100644 --- a/CMake/ThirdParty.cmake +++ b/CMake/ThirdParty.cmake @@ -331,7 +331,7 @@ function(Add3rdCMakeProject) SOURCE_DIR ${SOURCE_DIR} BINARY_DIR ${BINARY_DIR} CMAKE_ARGS ${CMAKE_BUILD_TYPE_ARGS} -DCMAKE_INSTALL_PREFIX=${INSTALL_DIR} ${PARAMS_CMAKE_ARG} - BUILD_COMMAND ${CMAKE_COMMAND} --build --config $ + BUILD_COMMAND ${CMAKE_COMMAND} --build --config $ -j 16 INSTALL_COMMAND ${CMAKE_COMMAND} --install --config $ ) set_target_properties( diff --git a/Engine/Source/Runtime/Include/Runtime/ECS.h b/Engine/Source/Runtime/Include/Runtime/ECS.h index de2f0656..d144dc09 100644 --- a/Engine/Source/Runtime/Include/Runtime/ECS.h +++ b/Engine/Source/Runtime/Include/Runtime/ECS.h @@ -23,6 +23,8 @@ namespace Runtime { class EClass() System { public: + EClassBody(System) + explicit System(ECRegistry& inRegistry); virtual ~System(); virtual void Setup(); @@ -698,7 +700,7 @@ namespace Runtime { template C& ECRegistry::Emplace(Entity inEntity, Args&&... inArgs) { - return EmplaceDyn(Internal::GetClass(), inEntity, Mirror::ForwardAsArgList(std::forward(inArgs)...)).As(); + return EmplaceDyn(Internal::GetClass(), inEntity, Mirror::ForwardAsArgList(std::forward(inArgs)...)).template As(); } template @@ -741,13 +743,13 @@ namespace Runtime { template C& ECRegistry::Get(Entity inEntity) { - return GetDyn(Internal::GetClass(), inEntity).As(); + return GetDyn(Internal::GetClass(), inEntity).template As(); } template const C& ECRegistry::Get(Entity inEntity) const { - return GetDyn(Internal::GetClass(), inEntity).As(); + return GetDyn(Internal::GetClass(), inEntity).template As(); } template @@ -826,13 +828,13 @@ namespace Runtime { template G& ECRegistry::GGet() { - return GGetDyn(Internal::GetClass()).As(); + return GGetDyn(Internal::GetClass()).template As(); } template const G& ECRegistry::GGet() const { - return GGetDyn(Internal::GetClass()).As(); + return GGetDyn(Internal::GetClass()).template As(); } template diff --git a/Engine/Source/Runtime/Src/ECS.cpp b/Engine/Source/Runtime/Src/ECS.cpp index 92316bd7..b54018f1 100644 --- a/Engine/Source/Runtime/Src/ECS.cpp +++ b/Engine/Source/Runtime/Src/ECS.cpp @@ -345,7 +345,7 @@ namespace Runtime::Internal { const Mirror::Any system = clazz->New(inRegistry); const Mirror::Any systemRef = system.Deref(); for (const auto& [name, argument] : arguments) { - clazz->GetMemberVariable(name).Set(systemRef, argument.ConstRef()); + clazz->GetMemberVariable(name).SetDyn(systemRef, argument.ConstRef()); } return system.As(); } @@ -360,7 +360,7 @@ namespace Runtime::Internal { const auto& memberVariables = clazz->GetMemberVariables(); arguments.reserve(memberVariables.size()); for (const auto& [id, member] : memberVariables) { - arguments.emplace(id.name, member.Get(clazz->GetDefaultObject())); + arguments.emplace(id.name, member.GetDyn(clazz->GetDefaultObject())); } } } // namespace Runtime::Internal diff --git a/README.md b/README.md index daa6a59e..3ebde826 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,25 @@ The parameters' meaning: After build the project, you can get all dist binaries in `/dist`. +## macOS Notice +If you have not installed xcode command line tools, you need install it: + +```shell +xcode-select --install +``` + +If xcode app or xcode command line tools installed on you system, you need check xcode path set to command line tools path, continue with this command: + +```shell +xcode-select -p +``` + +if the command print is not `/Library/Developer/CommandLineTools`, use this command to reset it: + +```shell +sudo xcode-select -s /Library/Developer/CommandLineTools +``` + # Third Party Project Usage Thanks all those following projects: From 2184198ba3827b8f044b987c1143129571452a3b Mon Sep 17 00:00:00 2001 From: FlyAntNotDown <461425614@qq.com> Date: Mon, 9 Dec 2024 21:03:28 +0800 Subject: [PATCH 22/22] feat: new gameplay framework --- Engine/Source/Runtime/Include/Runtime/ECS.h | 63 ++++-- Engine/Source/Runtime/Include/Runtime/World.h | 27 ++- Engine/Source/Runtime/Src/ECS.cpp | 193 +++++++++++++++++- Engine/Source/Runtime/Src/Engine.cpp | 9 +- Engine/Source/Runtime/Src/World.cpp | 61 ++++++ Engine/Source/Runtime/Test/ECSTest.cpp | 47 +++++ Engine/Source/Runtime/Test/ECSTest.h | 15 ++ 7 files changed, 385 insertions(+), 30 deletions(-) create mode 100644 Engine/Source/Runtime/Test/ECSTest.cpp create mode 100644 Engine/Source/Runtime/Test/ECSTest.h diff --git a/Engine/Source/Runtime/Include/Runtime/ECS.h b/Engine/Source/Runtime/Include/Runtime/ECS.h index d144dc09..17370003 100644 --- a/Engine/Source/Runtime/Include/Runtime/ECS.h +++ b/Engine/Source/Runtime/Include/Runtime/ECS.h @@ -27,7 +27,6 @@ namespace Runtime { explicit System(ECRegistry& inRegistry); virtual ~System(); - virtual void Setup(); virtual void Execute(float inDeltaTimeMs); protected: @@ -138,6 +137,7 @@ namespace Runtime::Internal { public: explicit SystemFactory(SystemClass inClass); Common::UniqueRef Build(ECRegistry& inRegistry) const; + std::unordered_map GetArguments(); const std::unordered_map& GetArguments() const; private: @@ -319,7 +319,7 @@ namespace Runtime { std::vector entities; }; - class ECRegistry { + class MIRROR_API ECRegistry { public: using EntityTraverseFunc = Internal::EntityPool::EntityTraverseFunc; using DynUpdateFunc = std::function; @@ -347,13 +347,14 @@ namespace Runtime { ECRegistry& operator=(const ECRegistry& inOther); ECRegistry& operator=(ECRegistry&& inOther) noexcept; + void ResetTransients(); + // entity Entity Create(); void Destroy(Entity inEntity); bool Valid(Entity inEntity) const; size_t Size() const; void Clear(); - void ResetTransients(); void Each(const EntityTraverseFunc& inFunc) const; ConstIter Begin() const; ConstIter End() const; @@ -440,41 +441,67 @@ namespace Runtime { public: explicit SystemGroup(std::string inName); - void AddSystem(SystemClass inClass); + Internal::SystemFactory& EmplaceSystem(SystemClass inClass); void RemoveSystem(SystemClass inClass); - const std::string& GetName() const; + bool HasSystem(SystemClass inClass) const; + Internal::SystemFactory& GetSystem(SystemClass inClass); + const Internal::SystemFactory& GetSystem(SystemClass inClass) const; + auto GetSystems(); auto GetSystems() const; + const std::string& GetName() const; private: std::string name; std::unordered_map systems; }; - class Feature { + class SystemGraph { public: - Feature(); + SystemGraph(); - SystemGroup& AddSystemGroup(const std::string& inName); - SystemGroup& GetSystemGroup(const std::string& inName); + SystemGroup& AddGroup(const std::string& inName); + void RemoveGroup(const std::string& inName); + bool HasGroup(const std::string& inName) const; + SystemGroup& GetGroup(const std::string& inName); + const SystemGroup& GetGroup(const std::string& inName) const; + const std::vector& GetGroups() const; private: std::vector systemGroups; }; - class SystemRegistry { + class SystemPipeline { + public: + explicit SystemPipeline(const SystemGraph& inGraph); + + private: + struct SystemContext { + const Internal::SystemFactory& factory; + Common::UniqueRef instance; + }; + using ActionFunc = std::function; + + void ParallelPerformAction(const ActionFunc& inActionFunc); + + friend class SystemGraphExecutor; + + std::vector> systemGraph; + }; + + class SystemGraphExecutor { public: - SystemRegistry(); + explicit SystemGraphExecutor(ECRegistry& inEcRegistry, const SystemGraph& inSystemGraph); + ~SystemGraphExecutor(); - SystemGroup& AddSystemGroup(const std::string& inName); - SystemGroup& GetSystemGroup(const std::string& inName); - void UseFeature(const Feature& inFeature); + NonCopyable(SystemGraphExecutor) + NonMovable(SystemGraphExecutor) - // TODO runtime + void Tick(float inDeltaTimeMs); private: - std::vector systemGroups; - // transients - // TODO + ECRegistry& ecRegistry; + SystemGraph systemGraph; + SystemPipeline pipeline; }; } diff --git a/Engine/Source/Runtime/Include/Runtime/World.h b/Engine/Source/Runtime/Include/Runtime/World.h index d4152313..976ae53d 100644 --- a/Engine/Source/Runtime/Include/Runtime/World.h +++ b/Engine/Source/Runtime/Include/Runtime/World.h @@ -4,23 +4,48 @@ #pragma once +#include #include #include +#include namespace Runtime { + enum class PlayStatus : uint8_t { + stopped, + playing, + paused, + max + }; + class World { public: NonCopyable(World) + NonMovable(World) ~World(); private: friend class Engine; explicit World(const std::string& inName = ""); - // TODO play/stop/pause/status + + void SetSystemGraph(const SystemGraph& inSystemGraph); + void Reset(); + PlayStatus PlayStatus() const; + bool Stopped() const; + bool Playing() const; + bool Paused() const; + void Play(); + void Resume(); + void Pause(); + void Stop(); + void Tick(float inTimeMs); std::string name; + Runtime::PlayStatus playStatus; + ECRegistry ecRegistry; + SystemGraph systemGraph; + std::optional executor; }; } diff --git a/Engine/Source/Runtime/Src/ECS.cpp b/Engine/Source/Runtime/Src/ECS.cpp index b54018f1..58ef5b39 100644 --- a/Engine/Source/Runtime/Src/ECS.cpp +++ b/Engine/Source/Runtime/Src/ECS.cpp @@ -2,6 +2,8 @@ // Created by johnk on 2024/10/31. // +#include + #include namespace Runtime { @@ -12,8 +14,6 @@ namespace Runtime { System::~System() = default; - void System::Setup() {} - void System::Execute(float inDeltaTimeMs) {} } @@ -350,6 +350,15 @@ namespace Runtime::Internal { return system.As(); } + std::unordered_map SystemFactory::GetArguments() + { + std::unordered_map result; + for (auto& [name, argument] : arguments) { + result.emplace(name, argument.Ref()); + } + return result; + } + const std::unordered_map& SystemFactory::GetArguments() const { return arguments; @@ -582,6 +591,12 @@ namespace Runtime { return *this; } + void ECRegistry::ResetTransients() + { + compEvents.clear(); + globalCompEvents.clear(); + } + Entity ECRegistry::Create() { return entities.Allocate(); @@ -610,12 +625,6 @@ namespace Runtime { ResetTransients(); } - void ECRegistry::ResetTransients() - { - compEvents.clear(); - globalCompEvents.clear(); - } - void ECRegistry::Each(const EntityTraverseFunc& inFunc) const { return entities.Each(inFunc); @@ -862,4 +871,172 @@ namespace Runtime { { return globalCompEvents[inClass]; } + + SystemGroup::SystemGroup(std::string inName) + : name(std::move(inName)) + { + } + + Internal::SystemFactory& SystemGroup::EmplaceSystem(SystemClass inClass) + { + systems.emplace(inClass, Internal::SystemFactory(inClass)); + return systems.at(inClass); + } + + void SystemGroup::RemoveSystem(SystemClass inClass) + { + systems.erase(inClass); + } + + bool SystemGroup::HasSystem(SystemClass inClass) const + { + return systems.contains(inClass); + } + + Internal::SystemFactory& SystemGroup::GetSystem(SystemClass inClass) + { + return systems.at(inClass); + } + + const Internal::SystemFactory& SystemGroup::GetSystem(SystemClass inClass) const + { + return systems.at(inClass); + } + + auto SystemGroup::GetSystems() + { + return systems | std::views::values; + } + + auto SystemGroup::GetSystems() const + { + return systems | std::views::values; + } + + const std::string& SystemGroup::GetName() const + { + return name; + } + + SystemGraph::SystemGraph() = default; + + SystemGroup& SystemGraph::AddGroup(const std::string& inName) + { + return systemGroups.emplace_back(inName); + } + + void SystemGraph::RemoveGroup(const std::string& inName) + { + const auto iter = std::ranges::find_if(systemGroups, [&](const SystemGroup& group) -> bool { + return group.GetName() == inName; + }); + Assert(iter != systemGroups.end()); + systemGroups.erase(iter); + } + + bool SystemGraph::HasGroup(const std::string& inName) const + { + for (const auto& group : systemGroups) { + if (group.GetName() == inName) { + return true; + } + } + return false; + } + + SystemGroup& SystemGraph::GetGroup(const std::string& inName) + { + for (auto& group : systemGroups) { + if (group.GetName() == inName) { + return group; + } + } + Assert(false); + return systemGroups.back(); + } + + const SystemGroup& SystemGraph::GetGroup(const std::string& inName) const + { + for (const auto& group : systemGroups) { + if (group.GetName() == inName) { + return group; + } + } + Assert(false); + return systemGroups.back(); + } + + const std::vector& SystemGraph::GetGroups() const + { + return systemGroups; + } + + SystemPipeline::SystemPipeline(const SystemGraph& inGraph) + { + const auto& systemGroups = inGraph.GetGroups(); + systemGraph.reserve(systemGroups.size()); + + for (const auto& group : systemGroups) { + auto& contexts = systemGraph.emplace_back(); + const auto& factories = group.GetSystems(); + contexts.reserve(factories.size()); + + for (const auto& factory : group.GetSystems()) { + contexts.emplace_back(factory, nullptr); + } + } + } + + void SystemPipeline::ParallelPerformAction(const ActionFunc& inActionFunc) + { + tf::Taskflow taskFlow; + auto lastBarrier = taskFlow.emplace([]() -> void {}); + + for (auto& contexts : systemGraph) { + std::vector tasks; + tasks.reserve(contexts.size()); + + for (auto& context : contexts) { + tasks.emplace_back(taskFlow.emplace([&]() -> void { + inActionFunc(context); + })); + tasks.back().succeed(lastBarrier); + } + + auto barrier = taskFlow.emplace([]() -> void {}); + for (const auto& task : tasks) { + barrier.succeed(task); + } + lastBarrier = barrier; + } + + tf::Executor executor; + executor + .run(taskFlow) + .wait(); + } + + SystemGraphExecutor::SystemGraphExecutor(ECRegistry& inEcRegistry, const SystemGraph& inSystemGraph) + : ecRegistry(inEcRegistry) + , systemGraph(inSystemGraph) + , pipeline(inSystemGraph) + { + pipeline.ParallelPerformAction([&](SystemPipeline::SystemContext& context) -> void { + context.instance = context.factory.Build(inEcRegistry); + }); + } + + SystemGraphExecutor::~SystemGraphExecutor() + { + pipeline.ParallelPerformAction([](SystemPipeline::SystemContext& context) -> void { + context.instance = nullptr; + }); + } + + void SystemGraphExecutor::Tick(float inDeltaTimeMs) + { + pipeline.ParallelPerformAction([&](const SystemPipeline::SystemContext& context) -> void { + context.instance->Execute(inDeltaTimeMs); + }); + } } // namespace Runtime diff --git a/Engine/Source/Runtime/Src/Engine.cpp b/Engine/Source/Runtime/Src/Engine.cpp index 4fae8ff3..c0a077ee 100644 --- a/Engine/Source/Runtime/Src/Engine.cpp +++ b/Engine/Source/Runtime/Src/Engine.cpp @@ -46,9 +46,12 @@ namespace Runtime { void Engine::Tick(float inTimeMs) const { - // TODO tick each playing world - // TODO fetch each scene - // TODO traverse each view in scene, create a renderer, perform rendering + for (auto* world : worlds) { + if (!world->Playing()) { + continue; + } + world->Tick(inTimeMs); + } } Common::UniqueRef Engine::CreateWorld(const std::string& inName) const // NOLINT diff --git a/Engine/Source/Runtime/Src/World.cpp b/Engine/Source/Runtime/Src/World.cpp index 69d34181..3c4b0af2 100644 --- a/Engine/Source/Runtime/Src/World.cpp +++ b/Engine/Source/Runtime/Src/World.cpp @@ -16,4 +16,65 @@ namespace Runtime { { EngineHolder::Get().UnmountWorld(this); } + + void World::SetSystemGraph(const SystemGraph& inSystemGraph) + { + systemGraph = inSystemGraph; + } + + void World::Reset() + { + playStatus = PlayStatus::stopped; + } + + PlayStatus World::PlayStatus() const + { + return playStatus; + } + + bool World::Stopped() const + { + return playStatus == PlayStatus::stopped; + } + + bool World::Playing() const + { + return playStatus == PlayStatus::playing; + } + + bool World::Paused() const + { + return playStatus == PlayStatus::paused; + } + + void World::Play() + { + Assert(Stopped() && !executor.has_value()); + playStatus = PlayStatus::playing; + executor.emplace(ecRegistry, systemGraph); + } + + void World::Resume() + { + Assert(Paused()); + playStatus = PlayStatus::playing; + } + + void World::Pause() + { + Assert(Playing()); + playStatus = PlayStatus::paused; + } + + void World::Stop() + { + Assert((Playing() || Paused()) && executor.has_value()); + playStatus = PlayStatus::stopped; + executor.reset(); + } + + void World::Tick(float inTimeMs) + { + executor->Tick(inTimeMs); + } } // namespace Runtime diff --git a/Engine/Source/Runtime/Test/ECSTest.cpp b/Engine/Source/Runtime/Test/ECSTest.cpp new file mode 100644 index 00000000..44eaeb91 --- /dev/null +++ b/Engine/Source/Runtime/Test/ECSTest.cpp @@ -0,0 +1,47 @@ +// +// Created by johnk on 2024/12/9. +// + +#include + +TEST(ECSTest, EntityTest) +{ + ECRegistry registry; + const auto entity0 = registry.Create(); + const auto entity1 = registry.Create(); + ASSERT_EQ(registry.Size(), 2); + ASSERT_TRUE(registry.Valid(entity0)); + ASSERT_TRUE(registry.Valid(entity1)); + ASSERT_FALSE(registry.Valid(99)); + + std::unordered_set cur = { entity0, entity1 }; + for (const auto e : registry) { + ASSERT_TRUE(cur.contains(e)); + } + + const auto entity2 = registry.Create(); + const auto entity3 = registry.Create(); + registry.Destroy(entity0); + const auto entity4 = registry.Create(); + cur = { entity1, entity2, entity3, entity4 }; + + registry.Each([&](const auto e) -> void { + ASSERT_TRUE(cur.contains(e)); + }); +} + +TEST(ECSTest, ComponentStaticTest) +{ + // ECRegistry registry; + // const auto entity0 = registry.Create(); + // const auto entity1 = registry.Create(); + // + // registry.Emplace(entity0, 1); + // registry.Emplace(entity1, 2); + // ASSERT_TRUE(registry.Has(entity0)); + // ASSERT_TRUE(registry.Has(entity1)); + + // TODO +} + +// TODO diff --git a/Engine/Source/Runtime/Test/ECSTest.h b/Engine/Source/Runtime/Test/ECSTest.h new file mode 100644 index 00000000..3152a077 --- /dev/null +++ b/Engine/Source/Runtime/Test/ECSTest.h @@ -0,0 +1,15 @@ +// +// Created by johnk on 2024/12/9. +// + +#pragma once + +#include +#include +using namespace Runtime; + +struct EClass() CompA { + EClassBody(CompA) + + int value; +};