diff --git a/Bigfoot/Sources/Engine/Asset/Asset.cpp b/Bigfoot/Sources/Engine/Asset/Asset.cpp new file mode 100644 index 0000000..950a1bc --- /dev/null +++ b/Bigfoot/Sources/Engine/Asset/Asset.cpp @@ -0,0 +1,69 @@ +/********************************************************************* + * \file Asset.cpp + * + * \author Romain BOULLARD + * \date April 2026 + *********************************************************************/ +#include + +#include + +namespace Bigfoot +{ +void AssetBase::HardReferenceVisitor::Field([[maybe_unused]] size_t p_fieldIndex, + [[maybe_unused]] size_t p_setIndex, + const flatbuffers::ElementaryType p_type, + const bool p_isVector, + const flatbuffers::TypeTable* p_typeTable, + [[maybe_unused]] const char* p_name, + const std::uint8_t* p_val) +{ + if (!p_isVector) + { + Visit(p_type, p_typeTable, p_val); + } +} + +/****************************************************************************************/ + +void AssetBase::HardReferenceVisitor::Element([[maybe_unused]] size_t p_index, + const flatbuffers::ElementaryType p_type, + const flatbuffers::TypeTable* p_typeTable, + const std::uint8_t* p_val) +{ + Visit(p_type, p_typeTable, p_val); +} + +/****************************************************************************************/ + +eastl::vector AssetBase::HardReferenceVisitor::GetUUIDs() const +{ + eastl::vector uuids; + uuids.reserve(m_uuids.size()); + + std::transform(m_uuids.begin(), + m_uuids.end(), + eastl::back_inserter(uuids), + [](const UUID& p_uuid) + { + return p_uuid; + }); + return uuids; +} + +/****************************************************************************************/ + +void AssetBase::HardReferenceVisitor::Visit(const flatbuffers::ElementaryType p_type, + const flatbuffers::TypeTable* p_typeTable, + const std::uint8_t* p_val) +{ + if (p_val == nullptr || p_type != flatbuffers::ET_SEQUENCE || + p_typeTable != ::Flat::Bigfoot::HardReference::MiniReflectTypeTable()) + { + return; + } + + const ::Flat::Bigfoot::HardReference* hardReference = std::bit_cast(p_val); + m_uuids.emplace(flatbuffers::UnPack(hardReference->uuid())); +} +} // namespace Bigfoot diff --git a/Bigfoot/Sources/Engine/Include/Engine/Asset/Asset.hpp b/Bigfoot/Sources/Engine/Include/Engine/Asset/Asset.hpp index 6ace46a..42c0212 100644 --- a/Bigfoot/Sources/Engine/Include/Engine/Asset/Asset.hpp +++ b/Bigfoot/Sources/Engine/Include/Engine/Asset/Asset.hpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include namespace Bigfoot @@ -23,6 +23,38 @@ class AssetBase public: virtual ~AssetBase() = default; + /** + * Get the HardReferences the flatbuffer has + * + * \tparam ASSET The asset to walk + * \param p_flatbuffer The flatbuffer + * \return The UUIDs of the HardReferences + */ + template + requires AssetTraits + [[nodiscard]] + static eastl::vector GetHardReferences(const eastl::span p_flatbuffer) + { +#ifdef BIGFOOT_NOT_OPTIMIZED + flatbuffers::Verifier verifier {std::bit_cast(p_flatbuffer.data()), p_flatbuffer.size()}; + const bool assetVerified = ::Flat::Bigfoot::VerifyAssetBuffer(verifier); + CRITICAL_ASSERT(EngineAssertHandler, assetVerified, "Given asset could not be verified!"); +#endif + + const ::Flat::Bigfoot::Asset* asset = flatbuffers::GetRoot<::Flat::Bigfoot::Asset>(p_flatbuffer.data()); + +#ifdef BIGFOOT_NOT_OPTIMIZED + flatbuffers::Verifier innerAssetVerifier {asset->inner_asset()->data(), asset->inner_asset()->size()}; + const bool innerAssetVerified = innerAssetVerifier.VerifyBuffer(); + CRITICAL_ASSERT(EngineAssertHandler, innerAssetVerified, "Given asset could not be verified!"); +#endif + + HardReferenceVisitor visitor; + + flatbuffers::IterateFlatBuffer(asset->inner_asset()->data(), ASSET::FLAT::MiniReflectTypeTable(), &visitor); + return visitor.GetUUIDs(); + } + protected: AssetBase() = default; @@ -31,6 +63,49 @@ class AssetBase AssetBase& operator=(const AssetBase& p_asset) = delete; AssetBase& operator=(AssetBase&& p_asset) = default; + + private: + class HardReferenceVisitor: public flatbuffers::IterationVisitor + { + public: + void Field(size_t p_fieldIndex, + size_t p_setIndex, + const flatbuffers::ElementaryType p_type, + const bool p_isVector, + const flatbuffers::TypeTable* p_typeTable, + const char* p_name, + const std::uint8_t* p_val) override; + + void Element(size_t p_index, + const flatbuffers::ElementaryType p_type, + const flatbuffers::TypeTable* p_typeTable, + const std::uint8_t* p_val) override; + + /** + * Get the visited HardReference + * + * \return The visited HardReferences + */ + [[nodiscard]] + eastl::vector GetUUIDs() const; + + private: + /** + * Visit an element in the flatbuffer + * + * \param p_type The element type + * \param p_typeTable The element typetable + * \param p_val The element + */ + void Visit(const flatbuffers::ElementaryType p_type, + const flatbuffers::TypeTable* p_typeTable, + const std::uint8_t* p_val); + + /** + * The HardReferences visited so far + */ + ankerl::unordered_dense::set m_uuids; + }; }; template @@ -116,14 +191,14 @@ class Asset: public AssetBase flatbuffers::Verifier verifier {std::bit_cast(p_flatbuffer.data()), p_flatbuffer.size()}; const bool assetVerified = ::Flat::Bigfoot::VerifyAssetBuffer(verifier); CRITICAL_ASSERT(EngineAssertHandler, assetVerified, "Given asset could not be verified!"); +#endif const ::Flat::Bigfoot::Asset* asset = flatbuffers::GetRoot<::Flat::Bigfoot::Asset>(p_flatbuffer.data()); +#ifdef BIGFOOT_NOT_OPTIMIZED flatbuffers::Verifier innerAssetVerifier {asset->inner_asset()->data(), asset->inner_asset()->size()}; const bool innerAssetVerified = innerAssetVerifier.VerifyBuffer(); CRITICAL_ASSERT(EngineAssertHandler, innerAssetVerified, "Given asset could not be verified!"); -#else - const ::Flat::Bigfoot::Asset* asset = flatbuffers::GetRoot<::Flat::Bigfoot::Asset>(p_flatbuffer.data()); #endif asset->header()->UnPackTo(&m_header); @@ -150,6 +225,18 @@ class Asset: public AssetBase std::bit_cast(assetFbb.GetBufferPointer() + assetFbb.GetSize())}; } + /** + * Get the HardReferences the flatbuffer has + * + * \param p_flatbuffer The flatbuffer + * \return The UUIDs of the HardReferences + */ + [[nodiscard]] + static eastl::vector GetHardReferences(const eastl::span p_flatbuffer) + { + return AssetBase::GetHardReferences(p_flatbuffer); + } + /** * Get the AssetTypeID * diff --git a/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetConcepts.hpp b/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetConcepts.hpp index 57a42ee..6321e72 100644 --- a/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetConcepts.hpp +++ b/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetConcepts.hpp @@ -10,6 +10,8 @@ #include +#include + #include namespace Bigfoot @@ -25,6 +27,7 @@ concept AssetTraits = requires { typename TRAITS::FLAT; typename TRAITS::FLAT::NativeTableType; { TRAITS::FLAT::GetFullyQualifiedName() } -> std::convertible_to; + { TRAITS::FLAT::MiniReflectTypeTable() } -> std::convertible_to; }; /** diff --git a/Bigfoot/Tests/Engine/Asset/Asset.cpp b/Bigfoot/Tests/Engine/Asset/Asset.cpp index de5b4da..c705fd6 100644 --- a/Bigfoot/Tests/Engine/Asset/Asset.cpp +++ b/Bigfoot/Tests/Engine/Asset/Asset.cpp @@ -17,43 +17,62 @@ namespace Bigfoot class AssetFixture: public ::testing::Test { protected: - AssetA m_asset; + void SetUp() override + { + const UUID uuidA = m_assetA.GetHeader().uuid; + const UUID uuidB = m_assetB.GetHeader().uuid; + + m_assetA.GetAsset().ref_a = SoftReference {uuidA}; + + m_assetB.GetAsset().ref_a = HardReference {uuidA}; + m_assetB.GetAsset().refs_a.push_back(SoftReference {uuidA}); + + m_assetC.GetAsset().inner_table->asset_a_ref = HardReference {uuidA}; + m_assetC.GetAsset().inner_table->asset_a_refs.push_back(HardReference {uuidA}); + m_assetC.GetAsset().inner_table->asset_a_refs.push_back(HardReference {uuidA}); + m_assetC.GetAsset().asset_b_ref = HardReference {uuidB}; + m_assetC.GetAsset().asset_b_refs.push_back(SoftReference {uuidB}); + } + + AssetA m_assetA; + AssetB m_assetB; + AssetC m_assetC; }; /****************************************************************************************/ TEST_F(AssetFixture, Constructor_ShouldInitializeHeaderTypeIdAndTypeName) { - EXPECT_EQ(m_asset.GetHeader().type_id, AssetA::GetTypeID()); - EXPECT_EQ(m_asset.GetHeader().type_name, eastl::string {AssetA::GetTypeName()}); + EXPECT_EQ(m_assetA.GetHeader().type_id, AssetA::GetTypeID()); + EXPECT_EQ(m_assetA.GetHeader().type_name, eastl::string {AssetA::GetTypeName()}); } /****************************************************************************************/ TEST_F(AssetFixture, SetName_ShouldSetTheName) { - m_asset.SetName("MyAsset"); + m_assetA.SetName("MyAsset"); - EXPECT_STREQ(m_asset.GetHeader().name.c_str(), "MyAsset"); + EXPECT_STREQ(m_assetA.GetHeader().name.c_str(), "MyAsset"); } /****************************************************************************************/ TEST_F(AssetFixture, SetVersion_ShouldSetTheVersion) { - m_asset.SetVersion(5); + m_assetA.SetVersion(5); - EXPECT_EQ(m_asset.GetHeader().version, 5); + EXPECT_EQ(m_assetA.GetHeader().version, 5); } /****************************************************************************************/ TEST_F(AssetFixture, GetAsset_ShouldReturnAMutableReferenceToTheUnderlyingAsset) { - m_asset.GetAsset().health = 10; + m_assetA.GetAsset().health = 10; - EXPECT_EQ(m_asset.GetAsset().health, 10); - EXPECT_EQ(std::as_const(m_asset).GetAsset().health, 10); + EXPECT_EQ(m_assetA.GetAsset().health, 10); + EXPECT_EQ(std::as_const(m_assetA).GetAsset().health, 10); } /****************************************************************************************/ @@ -83,20 +102,33 @@ TEST_F(AssetFixture, GetTypeName_ShouldReturnTheFlatbufferFullyQualifiedName) TEST_F(AssetFixture, PackThenUnpack_ShouldRoundTripTheHeaderAndTheAsset) { - m_asset.SetName("MyAsset"); - m_asset.SetVersion(3); - m_asset.GetAsset().health = 42; - m_asset.GetAsset().mana = 7; + m_assetA.SetName("MyAsset"); + m_assetA.SetVersion(3); + m_assetA.GetAsset().health = 42; + m_assetA.GetAsset().mana = 7; AssetA unpacked; - unpacked.Unpack(m_asset.Pack()); + unpacked.Unpack(m_assetA.Pack()); - EXPECT_EQ(unpacked.GetHeader().uuid, m_asset.GetHeader().uuid); - EXPECT_STREQ(unpacked.GetHeader().name.c_str(), m_asset.GetHeader().name.c_str()); - EXPECT_EQ(unpacked.GetHeader().version, m_asset.GetHeader().version); - EXPECT_EQ(unpacked.GetHeader().type_id, m_asset.GetHeader().type_id); - EXPECT_STREQ(unpacked.GetHeader().type_name.c_str(), m_asset.GetHeader().type_name.c_str()); - EXPECT_EQ(unpacked.GetAsset().health, m_asset.GetAsset().health); - EXPECT_EQ(unpacked.GetAsset().mana, m_asset.GetAsset().mana); + EXPECT_EQ(unpacked.GetHeader().uuid, m_assetA.GetHeader().uuid); + EXPECT_STREQ(unpacked.GetHeader().name.c_str(), m_assetA.GetHeader().name.c_str()); + EXPECT_EQ(unpacked.GetHeader().version, m_assetA.GetHeader().version); + EXPECT_EQ(unpacked.GetHeader().type_id, m_assetA.GetHeader().type_id); + EXPECT_STREQ(unpacked.GetHeader().type_name.c_str(), m_assetA.GetHeader().type_name.c_str()); + EXPECT_EQ(unpacked.GetAsset().health, m_assetA.GetAsset().health); + EXPECT_EQ(unpacked.GetAsset().mana, m_assetA.GetAsset().mana); +} + +/****************************************************************************************/ + +TEST_F(AssetFixture, GetHardReferences_ShouldReturnTheHardReferencesOfTheAsset) +{ + const eastl::vector hardReferences = AssetC::GetHardReferences(m_assetC.Pack()); + + EXPECT_EQ(hardReferences.size(), 2); + EXPECT_TRUE(std::find(hardReferences.begin(), hardReferences.end(), m_assetA.GetHeader().uuid) != + hardReferences.end()); + EXPECT_TRUE(std::find(hardReferences.begin(), hardReferences.end(), m_assetB.GetHeader().uuid) != + hardReferences.end()); } } // namespace Bigfoot