diff --git a/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderWeaponCamo.cpp b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderWeaponCamo.cpp new file mode 100644 index 00000000..160a8e2f --- /dev/null +++ b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderWeaponCamo.cpp @@ -0,0 +1,46 @@ +#include "AssetLoaderWeaponCamo.h" + +#include "Game/T6/WeaponCamo/JsonWeaponCamoLoader.h" +#include "Game/T6/T6.h" +#include "Pool/GlobalAssetPool.h" + +#include +#include +#include + +using namespace T6; + +void* AssetLoaderWeaponCamo::CreateEmptyAsset(const std::string& assetName, MemoryManager* memory) +{ + auto* weaponCamo = memory->Create(); + memset(weaponCamo, 0, sizeof(WeaponCamo)); + weaponCamo->name = memory->Dup(assetName.c_str()); + + return weaponCamo; +} + +bool AssetLoaderWeaponCamo::CanLoadFromRaw() const +{ + return true; +} + +bool AssetLoaderWeaponCamo::LoadFromRaw( + const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const +{ + const auto fileName = std::format("camo/{}.json", assetName); + const auto file = searchPath->Open(fileName); + if (!file.IsOpen()) + return false; + + auto* weaponCamo = static_cast(memory->Alloc(sizeof(WeaponCamo))); + memset(weaponCamo, 0, sizeof(WeaponCamo)); + weaponCamo->name = memory->Dup(assetName.c_str()); + + std::vector dependencies; + if (LoadWeaponCamoAsJson(*file.m_stream, *weaponCamo, memory, manager, dependencies)) + manager->AddAsset(ASSET_TYPE_WEAPON_CAMO, assetName, weaponCamo, std::move(dependencies)); + else + std::cerr << "Failed to load weapon camo \"" << assetName << "\"\n"; + + return true; +} diff --git a/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderWeaponCamo.h b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderWeaponCamo.h new file mode 100644 index 00000000..7c6fb2ac --- /dev/null +++ b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderWeaponCamo.h @@ -0,0 +1,17 @@ +#pragma once +#include "AssetLoading/BasicAssetLoader.h" +#include "AssetLoading/IAssetLoadingManager.h" +#include "Game/T6/T6.h" +#include "SearchPath/ISearchPath.h" + +namespace T6 +{ + class AssetLoaderWeaponCamo final : public BasicAssetLoader + { + public: + _NODISCARD void* CreateEmptyAsset(const std::string& assetName, MemoryManager* memory) override; + _NODISCARD bool CanLoadFromRaw() const override; + bool + LoadFromRaw(const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const override; + }; +} // namespace T6 diff --git a/src/ObjLoading/Game/T6/ObjLoaderT6.cpp b/src/ObjLoading/Game/T6/ObjLoaderT6.cpp index 667e70ab..40b29f29 100644 --- a/src/ObjLoading/Game/T6/ObjLoaderT6.cpp +++ b/src/ObjLoading/Game/T6/ObjLoaderT6.cpp @@ -17,6 +17,7 @@ #include "AssetLoaders/AssetLoaderWeapon.h" #include "AssetLoaders/AssetLoaderWeaponAttachment.h" #include "AssetLoaders/AssetLoaderWeaponAttachmentUnique.h" +#include "AssetLoaders/AssetLoaderWeaponCamo.h" #include "AssetLoaders/AssetLoaderZBarrier.h" #include "AssetLoading/AssetLoadingManager.h" #include "Game/T6/CommonT6.h" @@ -72,7 +73,7 @@ namespace T6 REGISTER_ASSET_LOADER(AssetLoaderWeapon) REGISTER_ASSET_LOADER(AssetLoaderWeaponAttachment) REGISTER_ASSET_LOADER(AssetLoaderWeaponAttachmentUnique) - REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_WEAPON_CAMO, WeaponCamo)) + REGISTER_ASSET_LOADER(AssetLoaderWeaponCamo) REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_SNDDRIVER_GLOBALS, SndDriverGlobals)) REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_FX, FxEffectDef)) REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_IMPACT_FX, FxImpactTable)) diff --git a/src/ObjLoading/Game/T6/WeaponCamo/JsonWeaponCamoLoader.cpp b/src/ObjLoading/Game/T6/WeaponCamo/JsonWeaponCamoLoader.cpp new file mode 100644 index 00000000..9c527f21 --- /dev/null +++ b/src/ObjLoading/Game/T6/WeaponCamo/JsonWeaponCamoLoader.cpp @@ -0,0 +1,247 @@ +#include "JsonWeaponCamoLoader.h" + +#include "Game/T6/CommonT6.h" +#include "Game/T6/Json/JsonWeaponCamo.h" + +#include +#include +#include + +using namespace nlohmann; +using namespace T6; + +namespace +{ + class JsonLoader + { + public: + JsonLoader(std::istream& stream, MemoryManager& memory, IAssetLoadingManager& manager, std::vector& dependencies) + : m_stream(stream), + m_memory(memory), + m_manager(manager), + m_dependencies(dependencies) + + { + } + + bool Load(WeaponCamo& weaponCamo) const + { + const auto jRoot = json::parse(m_stream); + std::string type; + unsigned version; + + jRoot.at("_type").get_to(type); + jRoot.at("_version").get_to(version); + + if (type != "weaponCamo" || version != 1u) + { + std::cerr << "Tried to load weapon camo \"" << weaponCamo.name << "\" but did not find expected type weaponCamo of version 1\n"; + return false; + } + + const auto jWeaponCamo = jRoot.get(); + return CreateWeaponCamoFromJson(jWeaponCamo, weaponCamo); + } + + private: + static void PrintError(const WeaponCamo& weaponCamo, const std::string& message) + { + std::cerr << "Cannot load weapon camo \"" << weaponCamo.name << "\": " << message << "\n"; + } + + bool CreateWeaponCamoSetFromJson(const JsonWeaponCamoSet& jWeaponCamoSet, WeaponCamoSet& weaponCamoSet, const WeaponCamo& weaponCamo) const + { + if (jWeaponCamoSet.solidCamoImage) + { + auto* image = static_cast*>(m_manager.LoadDependency(ASSET_TYPE_IMAGE, jWeaponCamoSet.solidCamoImage.value())); + if (!image) + { + PrintError(weaponCamo, "Could not find solidCamoImage"); + return false; + } + m_dependencies.push_back(image); + weaponCamoSet.solidCamoImage = image->Asset(); + } + + if (jWeaponCamoSet.patternCamoImage) + { + auto* image = static_cast*>(m_manager.LoadDependency(ASSET_TYPE_IMAGE, jWeaponCamoSet.patternCamoImage.value())); + if (!image) + { + PrintError(weaponCamo, "Could not find patternCamoImage"); + return false; + } + m_dependencies.push_back(image); + weaponCamoSet.patternCamoImage = image->Asset(); + } + + weaponCamoSet.patternOffset.x = jWeaponCamoSet.patternOffset.x; + weaponCamoSet.patternOffset.y = jWeaponCamoSet.patternOffset.y; + weaponCamoSet.patternScale = jWeaponCamoSet.patternScale; + + return true; + } + + bool CreateWeaponCamoMaterialFromJson(const JsonWeaponCamoMaterial& jWeaponCamoMaterial, + WeaponCamoMaterial& weaponCamoMaterial, + const WeaponCamo& weaponCamo) const + { + weaponCamoMaterial.replaceFlags = static_cast(jWeaponCamoMaterial.replaceFlags); + + if (jWeaponCamoMaterial.baseMaterials.size() != jWeaponCamoMaterial.camoMaterials.size()) + { + PrintError(weaponCamo, "baseMaterials and camoMaterials arrays must have the same amount of entries"); + return false; + } + + weaponCamoMaterial.numBaseMaterials = static_cast(jWeaponCamoMaterial.baseMaterials.size()); + if (weaponCamoMaterial.numBaseMaterials > 0) + { + weaponCamoMaterial.baseMaterials = static_cast(m_memory.Alloc(sizeof(Material*) * weaponCamoMaterial.numBaseMaterials)); + weaponCamoMaterial.camoMaterials = static_cast(m_memory.Alloc(sizeof(Material*) * weaponCamoMaterial.numBaseMaterials)); + memset(weaponCamoMaterial.baseMaterials, 0, sizeof(Material*) * weaponCamoMaterial.numBaseMaterials); + memset(weaponCamoMaterial.camoMaterials, 0, sizeof(Material*) * weaponCamoMaterial.numBaseMaterials); + + for (auto i = 0u; i < weaponCamoMaterial.numBaseMaterials; i++) + { + auto* baseMaterial = + static_cast*>(m_manager.LoadDependency(ASSET_TYPE_MATERIAL, jWeaponCamoMaterial.baseMaterials[i])); + auto* camoMaterial = + static_cast*>(m_manager.LoadDependency(ASSET_TYPE_MATERIAL, jWeaponCamoMaterial.camoMaterials[i])); + + if (!baseMaterial) + { + PrintError(weaponCamo, "Could not find baseMaterial"); + return false; + } + + if (!camoMaterial) + { + PrintError(weaponCamo, "Could not find camoMaterial"); + return false; + } + + m_dependencies.push_back(baseMaterial); + m_dependencies.push_back(camoMaterial); + + weaponCamoMaterial.baseMaterials[i] = baseMaterial->Asset(); + weaponCamoMaterial.camoMaterials[i] = camoMaterial->Asset(); + } + } + else + { + weaponCamoMaterial.baseMaterials = nullptr; + weaponCamoMaterial.camoMaterials = nullptr; + } + + return true; + } + + bool CreateWeaponCamoMaterialSetFromJson(const JsonWeaponCamoMaterialSet& jWeaponCamoMaterialSet, + WeaponCamoMaterialSet& weaponCamoMaterialSet, + const WeaponCamo& weaponCamo) const + { + if (!jWeaponCamoMaterialSet.materials.empty()) + { + weaponCamoMaterialSet.numMaterials = jWeaponCamoMaterialSet.materials.size(); + weaponCamoMaterialSet.materials = + static_cast(m_memory.Alloc(sizeof(WeaponCamoMaterial) * weaponCamoMaterialSet.numMaterials)); + memset(weaponCamoMaterialSet.materials, 0, sizeof(WeaponCamoMaterial) * weaponCamoMaterialSet.numMaterials); + + for (auto i = 0u; i < weaponCamoMaterialSet.numMaterials; i++) + { + if (!CreateWeaponCamoMaterialFromJson(jWeaponCamoMaterialSet.materials[i], weaponCamoMaterialSet.materials[i], weaponCamo)) + return false; + } + } + else + { + weaponCamoMaterialSet.numMaterials = 0; + weaponCamoMaterialSet.materials = nullptr; + } + + return true; + } + + bool CreateWeaponCamoFromJson(const JsonWeaponCamo& jWeaponCamo, WeaponCamo& weaponCamo) const + { + if (jWeaponCamo.solidBaseImage) + { + auto* image = static_cast*>(m_manager.LoadDependency(ASSET_TYPE_IMAGE, jWeaponCamo.solidBaseImage.value())); + if (!image) + { + PrintError(weaponCamo, "Could not find solidBaseImage"); + return false; + } + m_dependencies.push_back(image); + weaponCamo.solidBaseImage = image->Asset(); + } + + if (jWeaponCamo.patternBaseImage) + { + auto* image = static_cast*>(m_manager.LoadDependency(ASSET_TYPE_IMAGE, jWeaponCamo.patternBaseImage.value())); + if (!image) + { + PrintError(weaponCamo, "Could not find patternBaseImage"); + return false; + } + m_dependencies.push_back(image); + weaponCamo.patternBaseImage = image->Asset(); + } + + if (!jWeaponCamo.camoSets.empty()) + { + weaponCamo.numCamoSets = jWeaponCamo.camoSets.size(); + weaponCamo.camoSets = static_cast(m_memory.Alloc(sizeof(WeaponCamoSet) * weaponCamo.numCamoSets)); + memset(weaponCamo.camoSets, 0, sizeof(WeaponCamoSet) * weaponCamo.numCamoSets); + + for (auto i = 0u; i < weaponCamo.numCamoSets; i++) + { + if (!CreateWeaponCamoSetFromJson(jWeaponCamo.camoSets[i], weaponCamo.camoSets[i], weaponCamo)) + return false; + } + } + else + { + weaponCamo.numCamoSets = 0; + weaponCamo.camoSets = nullptr; + } + + if (!jWeaponCamo.camoMaterials.empty()) + { + weaponCamo.numCamoMaterials = jWeaponCamo.camoMaterials.size(); + weaponCamo.camoMaterials = static_cast(m_memory.Alloc(sizeof(WeaponCamoMaterialSet) * weaponCamo.numCamoMaterials)); + memset(weaponCamo.camoMaterials, 0, sizeof(WeaponCamoMaterialSet) * weaponCamo.numCamoMaterials); + + for (auto i = 0u; i < weaponCamo.numCamoMaterials; i++) + { + if (!CreateWeaponCamoMaterialSetFromJson(jWeaponCamo.camoMaterials[i], weaponCamo.camoMaterials[i], weaponCamo)) + return false; + } + } + else + { + weaponCamo.numCamoMaterials = 0; + weaponCamo.camoMaterials = nullptr; + } + + return true; + } + + std::istream& m_stream; + MemoryManager& m_memory; + IAssetLoadingManager& m_manager; + std::vector& m_dependencies; + }; +} // namespace + +namespace T6 +{ + bool LoadWeaponCamoAsJson( + std::istream& stream, WeaponCamo& weaponCamo, MemoryManager* memory, IAssetLoadingManager* manager, std::vector& dependencies) + { + const JsonLoader loader(stream, *memory, *manager, dependencies); + + return loader.Load(weaponCamo); + } +} // namespace T6 diff --git a/src/ObjLoading/Game/T6/WeaponCamo/JsonWeaponCamoLoader.h b/src/ObjLoading/Game/T6/WeaponCamo/JsonWeaponCamoLoader.h new file mode 100644 index 00000000..b0fc78bb --- /dev/null +++ b/src/ObjLoading/Game/T6/WeaponCamo/JsonWeaponCamoLoader.h @@ -0,0 +1,13 @@ +#pragma once + +#include "AssetLoading/IAssetLoadingManager.h" +#include "Game/T6/T6.h" +#include "Utils/MemoryManager.h" + +#include + +namespace T6 +{ + bool LoadWeaponCamoAsJson( + std::istream& stream, WeaponCamo& weaponCamo, MemoryManager* memory, IAssetLoadingManager* manager, std::vector& dependencies); +} // namespace T6