chore: adjust asset creation process to use separated AssetCreators

This commit is contained in:
Jan
2024-12-13 23:28:28 +00:00
parent 63046f5681
commit 4f0a405bdc
46 changed files with 638 additions and 278 deletions

View File

@ -0,0 +1,135 @@
#include "AssetCreationContext.h"
#include <format>
#include <iostream>
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(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<XAssetInfoGeneric> GenericAssetRegistration::CreateXAssetInfo()
{
std::vector<XAssetInfoGeneric*> dependencies(m_dependencies.begin(), m_dependencies.end());
std::vector<scr_string_t> scriptStrings(m_used_script_strings.begin(), m_used_script_strings.end());
std::vector<IndirectAssetReference> indirectAssetReferences(m_indirect_asset_references.begin(), m_indirect_asset_references.end());
return std::make_unique<XAssetInfoGeneric>(
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)
: m_zone(zone),
m_creators(creators),
m_ignored_asset_lookup(ignoredAssetLookup)
{
}
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();
auto* 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;
}
XAssetInfoGeneric* AssetCreationContext::LoadDefaultAssetDependency(const asset_type_t assetType, const std::string& assetName) const
{
const auto result = m_creators->CreateDefaultAsset(assetType, assetName, *this);
if (result.HasTakenAction() && !result.HasFailed())
return result.GetAssetInfo();
std::cerr << std::format("Failed to create default asset of type {}\n", *m_zone->m_pools->GetAssetTypeName(assetType));
return nullptr;
}
XAssetInfoGeneric* AssetCreationContext::LoadDependencyGeneric(const asset_type_t assetType, const std::string& assetName)
{
auto* alreadyLoadedAsset = m_zone->m_pools->GetAssetOrAssetReference(assetType, assetName);
if (alreadyLoadedAsset)
return alreadyLoadedAsset;
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())
return result.GetAssetInfo();
std::cerr << std::format(
"Could not load indirectly referenced asset \"{}\" of type \"{}\"\n", assetName, *m_zone->m_pools->GetAssetTypeName(assetType));
}
else
{
std::cerr << std::format("Could not find creator for asset \"{}\" of type \"{}\"\n", assetName, *m_zone->m_pools->GetAssetTypeName(assetType));
}
return nullptr;
}
IndirectAssetReference AssetCreationContext::LoadIndirectAssetReferenceGeneric(asset_type_t assetType, const std::string& assetName)
{
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 result = m_creators->CreateAsset(assetType, assetName, *this);
if (!result.HasTakenAction() && !result.HasFailed())
{
std::cerr << std::format(
"Could not load indirectly referenced asset \"{}\" of type \"{}\"\n", assetName, *m_zone->m_pools->GetAssetTypeName(assetType));
}
return IndirectAssetReference(assetType, assetName);
}

View File

@ -0,0 +1,85 @@
#pragma once
#include "AssetCreatorCollection.h"
#include "AssetLoading/IZoneAssetLoaderState.h"
#include "AssetRegistration.h"
#include "Game/IAsset.h"
#include "Pool/XAssetInfo.h"
#include "Zone/AssetList/AssetList.h"
#include "Zone/ZoneTypes.h"
#include <memory>
#include <string>
#include <type_traits>
#include <typeindex>
#include <unordered_map>
#include <unordered_set>
class AssetCreatorCollection;
class IgnoredAssetLookup
{
public:
explicit IgnoredAssetLookup(const AssetList& assetList);
[[nodiscard]] bool IsAssetIgnored(asset_type_t assetType, const std::string& name) const;
std::unordered_multimap<std::string, asset_type_t> m_ignored_asset_lookup;
};
class AssetCreationContext
{
public:
AssetCreationContext(Zone* zone, const AssetCreatorCollection* creators, const IgnoredAssetLookup* ignoredAssetLookup);
template<typename AssetType> XAssetInfo<typename AssetType::Type>* AddAsset(AssetRegistration<AssetType> registration)
{
static_assert(std::is_base_of_v<IAssetBase, AssetType>);
return static_cast<XAssetInfo<typename AssetType::Type>*>(AddAssetGeneric(std::move(registration)));
}
XAssetInfoGeneric* AddAssetGeneric(GenericAssetRegistration registration) const;
template<typename AssetType> XAssetInfo<typename AssetType::Type>* LoadDependency(const std::string& assetName)
{
static_assert(std::is_base_of_v<IAssetBase, AssetType>);
return static_cast<XAssetInfo<typename AssetType::Type>*>(LoadDependencyInternal(AssetType::EnumEntry, assetName));
}
XAssetInfoGeneric* LoadDependencyGeneric(asset_type_t assetType, const std::string& assetName);
template<typename AssetType> IndirectAssetReference LoadIndirectAssetReference(const std::string& assetName)
{
static_assert(std::is_base_of_v<IAssetBase, AssetType>);
return LoadIndirectAssetReferenceInternal(AssetType::EnumEntry, assetName);
}
IndirectAssetReference LoadIndirectAssetReferenceGeneric(asset_type_t assetType, const std::string& assetName);
template<typename T> T* GetZoneAssetLoaderState()
{
static_assert(std::is_base_of_v<IZoneAssetLoaderState, T>, "T must inherit IZoneAssetLoaderState");
// T must also have a public default constructor
const auto foundEntry = m_zone_asset_loader_states.find(typeid(T));
if (foundEntry != m_zone_asset_loader_states.end())
return dynamic_cast<T*>(foundEntry->second.get());
auto newState = std::make_unique<T>();
newState->SetZone(&m_zone);
auto* newStatePtr = newState.get();
m_zone_asset_loader_states.emplace(std::make_pair<std::type_index, std::unique_ptr<IZoneAssetLoaderState>>(typeid(T), std::move(newState)));
return newStatePtr;
}
private:
[[nodiscard]] XAssetInfoGeneric* LoadDefaultAssetDependency(asset_type_t assetType, const std::string& assetName) const;
Zone* m_zone;
const AssetCreatorCollection* m_creators;
const IgnoredAssetLookup* m_ignored_asset_lookup;
std::unordered_map<std::type_index, std::unique_ptr<IZoneAssetLoaderState>> m_zone_asset_loader_states;
};

View File

@ -0,0 +1,65 @@
#include "AssetCreatorCollection.h"
#include <cassert>
AssetCreatorCollection::AssetCreatorCollection(const Zone& zone)
{
m_asset_creators_by_type.resize(zone.m_pools->GetAssetTypeCount());
}
void AssetCreatorCollection::AddAssetCreator(std::unique_ptr<IAssetCreator> creator)
{
const auto maybeHandlingAssetType = creator->GetHandlingAssetType();
assert(!maybeHandlingAssetType || static_cast<unsigned>(*maybeHandlingAssetType) < m_asset_creators_by_type.size());
if (maybeHandlingAssetType && static_cast<unsigned>(*maybeHandlingAssetType) < m_asset_creators_by_type.size())
m_asset_creators_by_type[static_cast<unsigned>(*maybeHandlingAssetType)].emplace_back(creator.get());
m_asset_creators.emplace_back(std::move(creator));
}
void AssetCreatorCollection::AddDefaultAssetCreator(std::unique_ptr<IDefaultAssetCreator> defaultAssetCreator)
{
const auto handlingAssetType = defaultAssetCreator->GetHandlingAssetType();
assert(static_cast<unsigned>(handlingAssetType) < m_default_asset_creators_by_type.size());
assert(!m_default_asset_creators_by_type[handlingAssetType]);
if (static_cast<unsigned>(handlingAssetType) < m_default_asset_creators_by_type.size())
m_default_asset_creators_by_type[handlingAssetType] = std::move(defaultAssetCreator);
}
AssetCreationResult AssetCreatorCollection::CreateAsset(const asset_type_t assetType, const std::string& assetName, AssetCreationContext& context) const
{
assert(assetType >= 0 && static_cast<unsigned>(assetType) < m_asset_creators_by_type.size());
if (assetType >= 0 && static_cast<unsigned>(assetType) < m_asset_creators_by_type.size())
{
for (const auto& creator : m_asset_creators_by_type[assetType])
{
const auto result = creator->CreateAsset(assetName, context);
if (result.HasTakenAction())
return result;
}
}
return AssetCreationResult::NoAction();
}
AssetCreationResult
AssetCreatorCollection::CreateDefaultAsset(const asset_type_t assetType, const std::string& assetName, const AssetCreationContext& context) const
{
assert(assetType >= 0 && static_cast<unsigned>(assetType) < m_default_asset_creators_by_type.size());
if (assetType >= 0 && static_cast<unsigned>(assetType) < m_default_asset_creators_by_type.size() && m_default_asset_creators_by_type[assetType])
{
auto defaultAsset = m_default_asset_creators_by_type[assetType]->CreateDefaultAsset(assetName);
return AssetCreationResult::Success(context.AddAssetGeneric(std::move(defaultAsset)));
}
return AssetCreationResult::NoAction();
}
void AssetCreatorCollection::FinalizeZone(AssetCreationContext& context) const
{
for (const auto& creator : m_asset_creators)
creator->FinalizeZone(context);
}

View File

@ -0,0 +1,32 @@
#pragma once
#include "AssetCreationContext.h"
#include "Game/IGame.h"
#include "IAssetCreator.h"
#include "IDefaultAssetCreator.h"
#include "Zone/ZoneTypes.h"
#include <memory>
class AssetCreationContext;
class IAssetCreator;
class AssetCreationResult;
class IDefaultAssetCreator;
class AssetCreatorCollection
{
public:
explicit AssetCreatorCollection(const Zone& zone);
void AddAssetCreator(std::unique_ptr<IAssetCreator> creator);
void AddDefaultAssetCreator(std::unique_ptr<IDefaultAssetCreator> defaultAssetCreator);
AssetCreationResult CreateAsset(asset_type_t assetType, const std::string& assetName, AssetCreationContext& context) const;
AssetCreationResult CreateDefaultAsset(asset_type_t assetType, const std::string& assetName, const AssetCreationContext& context) const;
void FinalizeZone(AssetCreationContext& context) const;
private:
std::vector<std::vector<IAssetCreator*>> m_asset_creators_by_type;
std::vector<std::unique_ptr<IDefaultAssetCreator>> m_default_asset_creators_by_type;
std::vector<std::unique_ptr<IAssetCreator>> m_asset_creators;
};

View File

@ -0,0 +1,51 @@
#pragma once
#include "Game/IAsset.h"
#include "Pool/XAssetInfo.h"
#include "Zone/ZoneTypes.h"
#include <memory>
#include <string>
#include <unordered_set>
class GenericAssetRegistration
{
protected:
GenericAssetRegistration(asset_type_t type, std::string name, void* asset);
public:
GenericAssetRegistration(const GenericAssetRegistration& other) = delete;
GenericAssetRegistration(GenericAssetRegistration&& other) = default;
GenericAssetRegistration& operator=(const GenericAssetRegistration& other) = delete;
GenericAssetRegistration& operator=(GenericAssetRegistration&& other) noexcept = default;
void AddDependency(XAssetInfoGeneric* dependency);
void AddScriptString(scr_string_t scriptString);
void AddIndirectAssetReference(IndirectAssetReference indirectAssetReference);
std::unique_ptr<XAssetInfoGeneric> CreateXAssetInfo();
private:
asset_type_t m_type;
std::string m_name;
void* m_asset;
std::unordered_set<XAssetInfoGeneric*> m_dependencies;
std::unordered_set<scr_string_t> m_used_script_strings;
std::unordered_set<IndirectAssetReference> m_indirect_asset_references;
};
template<typename AssetType> class AssetRegistration : public GenericAssetRegistration
{
static_assert(std::is_base_of_v<IAssetBase, AssetType>);
public:
AssetRegistration(std::string assetName, typename AssetType::Type* asset)
: GenericAssetRegistration(AssetType::EnumEntry, std::move(assetName), asset)
{
}
AssetRegistration(const AssetRegistration& other) = delete;
AssetRegistration(AssetRegistration&& other) = default;
AssetRegistration& operator=(const AssetRegistration& other) = delete;
AssetRegistration& operator=(AssetRegistration&& other) noexcept = default;
};

View File

@ -0,0 +1,37 @@
#include "IAssetCreator.h"
AssetCreationResult AssetCreationResult::Success(XAssetInfoGeneric* assetInfo)
{
return AssetCreationResult(true, assetInfo);
}
AssetCreationResult AssetCreationResult::Failure()
{
return AssetCreationResult(true, nullptr);
}
AssetCreationResult AssetCreationResult::NoAction()
{
return AssetCreationResult(false, nullptr);
}
bool AssetCreationResult::HasTakenAction() const
{
return m_taken_action;
}
bool AssetCreationResult::HasFailed() const
{
return m_taken_action && m_asset_info == nullptr;
}
XAssetInfoGeneric* AssetCreationResult::GetAssetInfo() const
{
return m_asset_info;
}
AssetCreationResult::AssetCreationResult(const bool takenAction, XAssetInfoGeneric* assetInfo)
: m_taken_action(takenAction),
m_asset_info(assetInfo)
{
}

View File

@ -0,0 +1,57 @@
#pragma once
#include "AssetCreationContext.h"
#include "Game/IAsset.h"
#include "Pool/XAssetInfo.h"
#include "SearchPath/ISearchPath.h"
#include "Utils/MemoryManager.h"
#include "Zone/ZoneTypes.h"
#include <optional>
#include <string>
class AssetCreationResult
{
public:
static AssetCreationResult Success(XAssetInfoGeneric* assetInfo);
static AssetCreationResult Failure();
static AssetCreationResult NoAction();
[[nodiscard]] bool HasTakenAction() const;
[[nodiscard]] bool HasFailed() const;
[[nodiscard]] XAssetInfoGeneric* GetAssetInfo() const;
private:
AssetCreationResult(bool takenAction, XAssetInfoGeneric* assetInfo);
bool m_taken_action;
XAssetInfoGeneric* m_asset_info;
};
class AssetCreationContext;
class IAssetCreator
{
public:
IAssetCreator() = default;
virtual ~IAssetCreator() = default;
IAssetCreator(const IAssetCreator& other) = default;
IAssetCreator(IAssetCreator&& other) noexcept = default;
IAssetCreator& operator=(const IAssetCreator& other) = default;
IAssetCreator& operator=(IAssetCreator&& other) noexcept = default;
[[nodiscard]] virtual std::optional<asset_type_t> GetHandlingAssetType() const = 0;
virtual AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) = 0;
virtual void FinalizeZone(AssetCreationContext& context) {};
};
template<typename AssetType> class AssetCreator : public IAssetCreator
{
public:
static_assert(std::is_base_of_v<IAssetBase, AssetType>);
[[nodiscard]] std::optional<asset_type_t> GetHandlingAssetType() const override
{
return AssetType::EnumEntry;
};
};

View File

@ -0,0 +1,46 @@
#pragma once
#include "AssetCreationContext.h"
#include "AssetRegistration.h"
#include "Game/IAsset.h"
#include "Utils/MemoryManager.h"
#include "Zone/ZoneTypes.h"
#include <string>
#include <type_traits>
class GenericAssetRegistration;
template<typename AssetType> class AssetRegistration;
class IDefaultAssetCreator
{
public:
IDefaultAssetCreator() = default;
virtual ~IDefaultAssetCreator() = default;
IDefaultAssetCreator(const IDefaultAssetCreator& other) = default;
IDefaultAssetCreator(IDefaultAssetCreator&& other) noexcept = default;
IDefaultAssetCreator& operator=(const IDefaultAssetCreator& other) = default;
IDefaultAssetCreator& operator=(IDefaultAssetCreator&& other) noexcept = default;
[[nodiscard]] virtual asset_type_t GetHandlingAssetType() const = 0;
virtual GenericAssetRegistration CreateDefaultAsset(const std::string& assetName) const = 0;
};
template<typename AssetType> class DefaultAssetCreator : public IDefaultAssetCreator
{
public:
static_assert(std::is_base_of_v<IAssetBase, AssetType>);
[[nodiscard]] asset_type_t GetHandlingAssetType() const override
{
return AssetType::EnumEntry;
}
GenericAssetRegistration CreateDefaultAsset(const std::string& assetName) const override
{
return CreateDefaultAssetInternal(assetName);
}
protected:
virtual AssetRegistration<typename AssetType::Type> CreateDefaultAssetInternal(const std::string& assetName) const = 0;
};

View File

@ -62,6 +62,8 @@ void ObjLoader::LoadReferencedContainersForZone(ISearchPath& searchPath, Zone& z
void ObjLoader::UnloadContainersOfZone(Zone& zone) const {}
void ObjLoader::ConfigureCreatorCollection(AssetCreatorCollection& collection) const {}
bool ObjLoader::LoadAssetForZone(AssetLoadingContext& context, const asset_type_t assetType, const std::string& assetName) const
{
AssetLoadingManager assetLoadingManager(m_asset_loaders_by_type, context);

View File

@ -22,6 +22,8 @@ namespace IW3
void LoadReferencedContainersForZone(ISearchPath& searchPath, Zone& zone) const override;
void UnloadContainersOfZone(Zone& zone) const override;
void ConfigureCreatorCollection(AssetCreatorCollection& collection) const override;
bool LoadAssetForZone(AssetLoadingContext& context, asset_type_t assetType, const std::string& assetName) const override;
void FinalizeAssetsForZone(AssetLoadingContext& context) const override;
};

View File

@ -106,6 +106,8 @@ void ObjLoader::LoadReferencedContainersForZone(ISearchPath& searchPath, Zone& z
void ObjLoader::UnloadContainersOfZone(Zone& zone) const {}
void ObjLoader::ConfigureCreatorCollection(AssetCreatorCollection& collection) const {}
bool ObjLoader::LoadAssetForZone(AssetLoadingContext& context, asset_type_t assetType, const std::string& assetName) const
{
AssetLoadingManager assetLoadingManager(m_asset_loaders_by_type, context);

View File

@ -17,6 +17,8 @@ namespace IW4
void LoadReferencedContainersForZone(ISearchPath& searchPath, Zone& zone) const override;
void UnloadContainersOfZone(Zone& zone) const override;
void ConfigureCreatorCollection(AssetCreatorCollection& collection) const override;
bool LoadAssetForZone(AssetLoadingContext& context, asset_type_t assetType, const std::string& assetName) const override;
void FinalizeAssetsForZone(AssetLoadingContext& context) const override;

View File

@ -113,6 +113,8 @@ void ObjLoader::LoadReferencedContainersForZone(ISearchPath& searchPath, Zone& z
void ObjLoader::UnloadContainersOfZone(Zone& zone) const {}
void ObjLoader::ConfigureCreatorCollection(AssetCreatorCollection& collection) const {}
bool ObjLoader::LoadAssetForZone(AssetLoadingContext& context, const asset_type_t assetType, const std::string& assetName) const
{
AssetLoadingManager assetLoadingManager(m_asset_loaders_by_type, context);

View File

@ -17,6 +17,8 @@ namespace IW5
void LoadReferencedContainersForZone(ISearchPath& searchPath, Zone& zone) const override;
void UnloadContainersOfZone(Zone& zone) const override;
void ConfigureCreatorCollection(AssetCreatorCollection& collection) const override;
bool LoadAssetForZone(AssetLoadingContext& context, asset_type_t assetType, const std::string& assetName) const override;
void FinalizeAssetsForZone(AssetLoadingContext& context) const override;

View File

@ -70,6 +70,8 @@ void ObjLoader::LoadReferencedContainersForZone(ISearchPath& searchPath, Zone& z
void ObjLoader::UnloadContainersOfZone(Zone& zone) const {}
void ObjLoader::ConfigureCreatorCollection(AssetCreatorCollection& collection) const {}
bool ObjLoader::LoadAssetForZone(AssetLoadingContext& context, asset_type_t assetType, const std::string& assetName) const
{
AssetLoadingManager assetLoadingManager(m_asset_loaders_by_type, context);

View File

@ -17,6 +17,8 @@ namespace T5
void LoadReferencedContainersForZone(ISearchPath& searchPath, Zone& zone) const override;
void UnloadContainersOfZone(Zone& zone) const override;
void ConfigureCreatorCollection(AssetCreatorCollection& collection) const override;
bool LoadAssetForZone(AssetLoadingContext& context, asset_type_t assetType, const std::string& assetName) const override;
void FinalizeAssetsForZone(AssetLoadingContext& context) const override;

View File

@ -356,6 +356,8 @@ namespace T6
IPak::Repository.RemoveContainerReferences(&zone);
}
void ObjLoader::ConfigureCreatorCollection(AssetCreatorCollection& collection) const {}
bool ObjLoader::LoadAssetForZone(AssetLoadingContext& context, const asset_type_t assetType, const std::string& assetName) const
{
AssetLoadingManager assetLoadingManager(m_asset_loaders_by_type, context);

View File

@ -22,6 +22,8 @@ namespace T6
void LoadReferencedContainersForZone(ISearchPath& searchPath, Zone& zone) const override;
void UnloadContainersOfZone(Zone& zone) const override;
void ConfigureCreatorCollection(AssetCreatorCollection& collection) const override;
bool LoadAssetForZone(AssetLoadingContext& context, asset_type_t assetType, const std::string& assetName) const override;
void FinalizeAssetsForZone(AssetLoadingContext& context) const override;

View File

@ -1,5 +1,6 @@
#pragma once
#include "Asset/AssetCreatorCollection.h"
#include "AssetLoading/AssetLoadingContext.h"
#include "SearchPath/ISearchPath.h"
#include "Zone/Zone.h"
@ -27,6 +28,8 @@ public:
*/
virtual void UnloadContainersOfZone(Zone& zone) const = 0;
virtual void ConfigureCreatorCollection(AssetCreatorCollection& collection) const = 0;
virtual bool LoadAssetForZone(AssetLoadingContext& context, asset_type_t assetType, const std::string& assetName) const = 0;
virtual void FinalizeAssetsForZone(AssetLoadingContext& context) const = 0;