diff --git a/src/ObjLoading/Asset/AssetCreationContext.cpp b/src/ObjLoading/Asset/AssetCreationContext.cpp index b06886e8..deb08b5a 100644 --- a/src/ObjLoading/Asset/AssetCreationContext.cpp +++ b/src/ObjLoading/Asset/AssetCreationContext.cpp @@ -65,8 +65,10 @@ std::unique_ptr GenericAssetRegistration::CreateXAssetInfo() AssetCreationContext::AssetCreationContext(Zone& zone, const AssetCreatorCollection* creators, const IgnoredAssetLookup* ignoredAssetLookup) : ZoneAssetCreationStateContainer(zone), m_zone(zone), + m_forced_asset_pools(ZoneAssetPools::CreateForGame(zone.m_game->GetId(), &zone, zone.m_priority)), m_creators(creators), - m_ignored_asset_lookup(ignoredAssetLookup) + m_ignored_asset_lookup(ignoredAssetLookup), + m_forced_load_depth(0u) { } @@ -78,10 +80,14 @@ XAssetInfoGeneric* AssetCreationContext::AddAssetGeneric(GenericAssetRegistratio const auto assetType = xAssetInfo->m_type; const auto* pAssetName = xAssetInfo->m_name.c_str(); - auto* addedAsset = m_zone.m_pools->AddAsset(std::move(xAssetInfo)); + XAssetInfoGeneric* addedAsset; + if (m_forced_load_depth > 0) + addedAsset = m_forced_asset_pools->AddAsset(std::move(xAssetInfo)); + else + addedAsset = m_zone.m_pools->AddAsset(std::move(xAssetInfo)); + if (addedAsset == nullptr) std::cerr << std::format("Failed to add asset of type \"{}\" to pool: \"{}\"\n", *m_zone.m_pools->GetAssetTypeName(assetType), pAssetName); - return addedAsset; } @@ -102,6 +108,16 @@ XAssetInfoGeneric* AssetCreationContext::LoadDependencyGeneric(const asset_type_ if (alreadyLoadedAsset) return alreadyLoadedAsset; + if (m_forced_load_depth > 0) + { + alreadyLoadedAsset = m_forced_asset_pools->GetAssetOrAssetReference(assetType, assetName); + if (alreadyLoadedAsset) + return alreadyLoadedAsset; + + // If we are already force loading an asset we should not load its dependencies + return LoadDefaultAssetDependency(assetType, std::format(",{}", assetName)); + } + if (m_ignored_asset_lookup->IsAssetIgnored(assetType, assetName)) return LoadDefaultAssetDependency(assetType, std::format(",{}", assetName)); @@ -121,9 +137,9 @@ XAssetInfoGeneric* AssetCreationContext::LoadDependencyGeneric(const asset_type_ return nullptr; } -IndirectAssetReference AssetCreationContext::LoadIndirectAssetReferenceGeneric(asset_type_t assetType, const std::string& assetName) +IndirectAssetReference AssetCreationContext::LoadIndirectAssetReferenceGeneric(const asset_type_t assetType, const std::string& assetName) { - auto* alreadyLoadedAsset = m_zone.m_pools->GetAssetOrAssetReference(assetType, assetName); + const auto* alreadyLoadedAsset = m_zone.m_pools->GetAssetOrAssetReference(assetType, assetName); if (alreadyLoadedAsset) return IndirectAssetReference(assetType, assetName); @@ -137,3 +153,44 @@ IndirectAssetReference AssetCreationContext::LoadIndirectAssetReferenceGeneric(a } return IndirectAssetReference(assetType, assetName); } + +XAssetInfoGeneric* AssetCreationContext::ForceLoadDependencyGeneric(const asset_type_t assetType, const std::string& assetName) +{ + auto* alreadyLoadedAsset = m_zone.m_pools->GetAssetOrAssetReference(assetType, assetName); + if (alreadyLoadedAsset && !alreadyLoadedAsset->IsReference()) + return alreadyLoadedAsset; + alreadyLoadedAsset = m_forced_asset_pools->GetAssetOrAssetReference(assetType, assetName); + if (alreadyLoadedAsset && !alreadyLoadedAsset->IsReference()) + return alreadyLoadedAsset; + + auto result = AssetCreationResult::NoAction(); + if (m_ignored_asset_lookup->IsAssetIgnored(assetType, assetName)) + { + // Load default asset to zone + if (!LoadDefaultAssetDependency(assetType, std::format(",{}", assetName))) + return nullptr; + + ++m_forced_load_depth; + + result = m_creators->CreateAsset(assetType, assetName, *this); + + assert(m_forced_load_depth > 0); + m_forced_load_depth = std::min(m_forced_load_depth - 1u, 0u); + } + else + result = m_creators->CreateAsset(assetType, assetName, *this); + + if (result.HasTakenAction()) + { + if (!result.HasFailed()) + return result.GetAssetInfo(); + + std::cerr << std::format("Could not load asset \"{}\" of type \"{}\"\n", assetName, *m_zone.m_pools->GetAssetTypeName(assetType)); + } + else + { + std::cerr << std::format("Missing asset \"{}\" of type \"{}\"\n", assetName, *m_zone.m_pools->GetAssetTypeName(assetType)); + } + + return nullptr; +} diff --git a/src/ObjLoading/Asset/AssetCreationContext.h b/src/ObjLoading/Asset/AssetCreationContext.h index 0dca991c..59c00098 100644 --- a/src/ObjLoading/Asset/AssetCreationContext.h +++ b/src/ObjLoading/Asset/AssetCreationContext.h @@ -65,12 +65,31 @@ public: IndirectAssetReference LoadIndirectAssetReferenceGeneric(asset_type_t assetType, const std::string& assetName); + /** + * \brief Loads an asset dependency like \c LoadDependency but guarantees that the returned asset is not a reference. + * If normally a reference would be created, the actual asset is loaded but a reference is added to the zone. + * \tparam AssetType The type of the asset + * \param assetName The name of the asset + * \return XAssetInfo of the asset that is guaranteed to not be a reference or \c nullptr + */ + template XAssetInfo* ForceLoadDependency(const std::string& assetName) + { + static_assert(std::is_base_of_v); + + return static_cast*>(ForceLoadDependencyGeneric(AssetType::EnumEntry, assetName)); + } + + XAssetInfoGeneric* ForceLoadDependencyGeneric(asset_type_t assetType, const std::string& assetName); + private: [[nodiscard]] XAssetInfoGeneric* LoadDefaultAssetDependency(asset_type_t assetType, const std::string& assetName); Zone& m_zone; + std::unique_ptr m_forced_asset_pools; const AssetCreatorCollection* m_creators; const IgnoredAssetLookup* m_ignored_asset_lookup; + + unsigned m_forced_load_depth; }; #include "AssetCreatorCollection.h" diff --git a/src/ZoneCommon/Pool/XAssetInfo.cpp b/src/ZoneCommon/Pool/XAssetInfo.cpp index 6448c962..c9d94955 100644 --- a/src/ZoneCommon/Pool/XAssetInfo.cpp +++ b/src/ZoneCommon/Pool/XAssetInfo.cpp @@ -93,6 +93,11 @@ XAssetInfoGeneric::XAssetInfoGeneric(const asset_type_t type, { } +bool XAssetInfoGeneric::IsReference() const +{ + return !m_name.empty() && m_name[0] == ','; +} + std::string XAssetInfoGeneric::NormalizeAssetName(std::string input) { utils::MakeStringLowerCase(input); diff --git a/src/ZoneCommon/Pool/XAssetInfo.h b/src/ZoneCommon/Pool/XAssetInfo.h index fa77ea10..16a3edbb 100644 --- a/src/ZoneCommon/Pool/XAssetInfo.h +++ b/src/ZoneCommon/Pool/XAssetInfo.h @@ -54,6 +54,8 @@ public: XAssetInfoGeneric& operator=(const XAssetInfoGeneric& other) = default; XAssetInfoGeneric& operator=(XAssetInfoGeneric&& other) noexcept = default; + [[nodiscard]] bool IsReference() const; + static std::string NormalizeAssetName(std::string input); asset_type_t m_type; @@ -87,7 +89,7 @@ public: std::vector usedScriptStrings, std::vector indirectAssetReferences) : XAssetInfoGeneric( - type, std::move(name), static_cast(ptr), std::move(dependencies), std::move(usedScriptStrings), std::move(indirectAssetReferences)) + type, std::move(name), static_cast(ptr), std::move(dependencies), std::move(usedScriptStrings), std::move(indirectAssetReferences)) { } @@ -99,7 +101,7 @@ public: std::vector indirectAssetReferences, Zone* zone) : XAssetInfoGeneric( - type, std::move(name), static_cast(ptr), std::move(dependencies), std::move(usedScriptStrings), std::move(indirectAssetReferences), zone) + type, std::move(name), static_cast(ptr), std::move(dependencies), std::move(usedScriptStrings), std::move(indirectAssetReferences), zone) { }