#include "AssetCreationContext.h" #include "Utils/Logging/Log.h" #include #include namespace { std::string GetAssetSourceDescription(const Zone& targetZone, const XAssetInfoGeneric& assetInfo) { assert(assetInfo.m_zone != nullptr); if (assetInfo.m_zone == &targetZone) return "(src: disk)"; return std::format("(src: {})", assetInfo.m_zone->m_name); } } // namespace IgnoredAssetLookup::IgnoredAssetLookup() = default; IgnoredAssetLookup::IgnoredAssetLookup(const AssetList& assetList) { m_ignored_asset_lookup.reserve(assetList.m_entries.size()); for (const auto& asset : assetList.m_entries) { m_ignored_asset_lookup.emplace(asset.m_name, asset.m_type); } } bool IgnoredAssetLookup::IsAssetIgnored(const asset_type_t assetType, const std::string& name) const { const auto entries = m_ignored_asset_lookup.equal_range(name); for (auto i = entries.first; i != entries.second; ++i) { if (i->second == assetType) return true; } return false; } GenericAssetRegistration::GenericAssetRegistration(const asset_type_t type, std::string name, void* asset) : m_type(type), m_name(std::move(name)), m_asset(asset) { } void GenericAssetRegistration::AddDependency(XAssetInfoGeneric* dependency) { m_dependencies.emplace(dependency); } void GenericAssetRegistration::AddScriptString(scr_string_t scriptString) { m_used_script_strings.emplace(scriptString); } void GenericAssetRegistration::AddIndirectAssetReference(IndirectAssetReference indirectAssetReference) { m_indirect_asset_references.emplace(std::move(indirectAssetReference)); } std::unique_ptr GenericAssetRegistration::CreateXAssetInfo() { assert(m_asset); std::vector dependencies(m_dependencies.begin(), m_dependencies.end()); std::vector scriptStrings(m_used_script_strings.begin(), m_used_script_strings.end()); std::vector indirectAssetReferences(m_indirect_asset_references.begin(), m_indirect_asset_references.end()); return std::make_unique( m_type, std::move(m_name), m_asset, std::move(dependencies), std::move(scriptStrings), std::move(indirectAssetReferences)); } AssetCreationContext::AssetCreationContext(Zone& zone, const AssetCreatorCollection* creators, const IgnoredAssetLookup* ignoredAssetLookup) : ZoneAssetCreationStateContainer(zone), m_zone(zone), m_game(*IGame::GetGameById(zone.m_game_id)), m_forced_asset_pools(std::make_unique(zone, zone.m_priority)), m_creators(creators), m_ignored_asset_lookup(ignoredAssetLookup), m_forced_load_depth(0u) { const auto subAssetTypeCount = IGame::GetGameById(zone.m_game_id)->GetSubAssetTypeCount(); m_sub_asset_pools.resize(subAssetTypeCount); for (asset_type_t subAssetType = 0; subAssetType < subAssetTypeCount; subAssetType++) m_sub_asset_pools[subAssetType] = std::make_unique(); } XAssetInfoGeneric* AssetCreationContext::AddAssetGeneric(GenericAssetRegistration registration) const { auto xAssetInfo = registration.CreateXAssetInfo(); xAssetInfo->m_zone = &m_zone; const auto assetType = xAssetInfo->m_type; const auto* pAssetName = xAssetInfo->m_name.c_str(); 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) con::error(R"(Failed to add asset of type "{}" to pool: "{}")", *IGame::GetGameById(m_zone.m_game_id)->GetAssetTypeName(assetType), pAssetName); return addedAsset; } XAssetInfoGeneric* AssetCreationContext::AddSubAssetGeneric(GenericAssetRegistration registration) const { auto xAssetInfo = registration.CreateXAssetInfo(); xAssetInfo->m_zone = &m_zone; const auto subAssetType = xAssetInfo->m_type; const auto* pAssetName = xAssetInfo->m_name.c_str(); auto* addedAsset = m_sub_asset_pools[subAssetType]->AddAsset(std::move(xAssetInfo)); if (addedAsset == nullptr) con::error(R"(Failed to add sub asset of type "{}" to pool: "{}")", *IGame::GetGameById(m_zone.m_game_id)->GetAssetTypeName(subAssetType), pAssetName); return addedAsset; } XAssetInfoGeneric* AssetCreationContext::LoadDefaultAssetDependency(const asset_type_t assetType, const std::string& assetName) { const auto result = m_creators->CreateDefaultAsset(assetType, assetName, *this); if (result.HasTakenAction() && !result.HasFailed()) return result.GetAssetInfo(); con::error("Failed to create default asset of type {}", *IGame::GetGameById(m_zone.m_game_id)->GetAssetTypeName(assetType)); return nullptr; } XAssetInfoGeneric* AssetCreationContext::LoadDependencyGeneric(const asset_type_t assetType, const std::string& assetName, const bool required) { auto* alreadyLoadedAsset = m_zone.m_pools.GetAssetOrAssetReference(assetType, assetName); 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 (assetName.starts_with(',')) return LoadDefaultAssetDependency(assetType, assetName); const auto assetTypeName = m_game.GetAssetTypeName(assetType).value_or("unknown"); if (m_ignored_asset_lookup->IsAssetIgnored(assetType, assetName)) return LoadDefaultAssetDependency(assetType, std::format(",{}", assetName)); const auto result = m_creators->CreateAsset(assetType, assetName, *this); if (result.HasTakenAction()) { if (!result.HasFailed()) { auto* assetInfo = result.GetAssetInfo(); con::info(R"(Loaded {} "{}" {})", assetTypeName, assetName, GetAssetSourceDescription(m_zone, *assetInfo)); return assetInfo; } con::error(R"(Could not load asset "{}" of type "{}")", assetName, assetTypeName); } else if (required) { con::error(R"(Missing asset "{}" of type "{}")", assetName, assetTypeName); } return nullptr; } XAssetInfoGeneric* AssetCreationContext::LoadSubAssetGeneric(const asset_type_t subAssetType, const std::string& assetName) { assert(subAssetType < m_sub_asset_pools.size()); auto* alreadyLoadedSubAsset = m_sub_asset_pools[subAssetType]->GetAsset(assetName); if (alreadyLoadedSubAsset) return alreadyLoadedSubAsset; const auto subAssetTypeName = m_game.GetSubAssetTypeName(subAssetType).value_or("unknown"); const auto result = m_creators->CreateSubAsset(subAssetType, assetName, *this); if (result.HasTakenAction()) { if (!result.HasFailed()) { con::debug(R"(Loaded {} "{}")", subAssetTypeName, assetName); return result.GetAssetInfo(); } con::error(R"(Could not load sub asset "{}" of type "{}")", assetName, subAssetTypeName); } else { con::error(R"(Missing sub asset "{}" of type "{}")", assetName, subAssetTypeName); } return nullptr; } IndirectAssetReference AssetCreationContext::LoadIndirectAssetReferenceGeneric(const asset_type_t assetType, const std::string& assetName) { const auto* alreadyLoadedAsset = m_zone.m_pools.GetAssetOrAssetReference(assetType, assetName); if (alreadyLoadedAsset) return IndirectAssetReference(assetType, assetName); if (m_ignored_asset_lookup->IsAssetIgnored(assetType, assetName)) return IndirectAssetReference(assetType, assetName); const auto assetTypeName = m_game.GetAssetTypeName(assetType).value_or("unknown"); const auto result = m_creators->CreateAsset(assetType, assetName, *this); if (result.HasTakenAction() && !result.HasFailed()) { auto* assetInfo = result.GetAssetInfo(); con::info(R"(Loaded {} "{}" {})", assetTypeName, assetName, GetAssetSourceDescription(m_zone, *assetInfo)); } else if (!result.HasTakenAction() && !result.HasFailed()) { con::warn(R"(Could not load indirectly referenced asset "{}" of type "{}")", assetName, assetTypeName); } 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); const auto assetTypeName = m_game.GetAssetTypeName(assetType).value_or("unknown"); if (result.HasTakenAction()) { if (!result.HasFailed()) { auto* assetInfo = result.GetAssetInfo(); con::info(R"(Loaded {} "{}" {})", assetTypeName, assetName, GetAssetSourceDescription(m_zone, *assetInfo)); return assetInfo; } con::error(R"(Could not load asset "{}" of type "{}")", assetName, assetTypeName); } else { con::error(R"(Missing asset "{}" of type "{}")", assetName, assetTypeName); } return nullptr; }