diff --git a/src/ObjCommon/Weapon/GenericAccuracyGraph.h b/src/ObjCommon/Weapon/GenericAccuracyGraph.h deleted file mode 100644 index 2f827204..00000000 --- a/src/ObjCommon/Weapon/GenericAccuracyGraph.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include -#include - -class GenericAccuracyGraphKnot -{ -public: - float x; - float y; -}; - -class GenericAccuracyGraph -{ -public: - std::string name; - std::vector knots; -}; diff --git a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderWeapon.cpp b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderWeapon.cpp index db91158a..b46bc66e 100644 --- a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderWeapon.cpp +++ b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderWeapon.cpp @@ -9,6 +9,7 @@ #include "ObjLoading.h" #include "Pool/GlobalAssetPool.h" #include "Utils/StringUtils.h" +#include "Weapon/AccuracyGraphLoader.h" #include #include @@ -370,6 +371,62 @@ namespace } } + void ConvertAccuracyGraph(const GenericGraph2D& graph, + vec2_t*& originalGraphKnots, + uint16_t& originalGraphKnotCount, + vec2_t*& graphKnots, + uint16_t& graphKnotCount, + MemoryManager* memory) + { + originalGraphKnotCount = static_cast(graph.knots.size()); + originalGraphKnots = memory->Alloc(originalGraphKnotCount); + + for (auto i = 0u; i < originalGraphKnotCount; i++) + { + const auto& commonKnot = graph.knots[i]; + originalGraphKnots[i][0] = static_cast(commonKnot.x); + originalGraphKnots[i][1] = static_cast(commonKnot.y); + } + + graphKnots = originalGraphKnots; + graphKnotCount = originalGraphKnotCount; + } + + bool LoadAccuracyGraphs(WeaponFullDef* weaponFullDef, MemoryManager* memory, const IAssetLoadingManager* manager) + { + auto* accuracyGraphLoader = manager->GetAssetLoadingContext()->GetZoneAssetLoaderState(); + + if (weaponFullDef->weapDef.aiVsAiAccuracyGraphName && weaponFullDef->weapDef.aiVsAiAccuracyGraphName[0]) + { + const auto* graph = accuracyGraphLoader->LoadAiVsAiGraph(manager, weaponFullDef->weapDef.aiVsAiAccuracyGraphName); + if (!graph) + return false; + + ConvertAccuracyGraph(*graph, + weaponFullDef->weapDef.originalAiVsAiAccuracyGraphKnots, + weaponFullDef->weapDef.originalAiVsAiAccuracyGraphKnotCount, + weaponFullDef->weapCompleteDef.aiVsAiAccuracyGraphKnots, + weaponFullDef->weapCompleteDef.aiVsAiAccuracyGraphKnotCount, + memory); + } + + if (weaponFullDef->weapDef.aiVsPlayerAccuracyGraphName && weaponFullDef->weapDef.aiVsPlayerAccuracyGraphName[0]) + { + const auto* graph = accuracyGraphLoader->LoadAiVsPlayerGraph(manager, weaponFullDef->weapDef.aiVsPlayerAccuracyGraphName); + if (!graph) + return false; + + ConvertAccuracyGraph(*graph, + weaponFullDef->weapDef.originalAiVsPlayerAccuracyGraphKnots, + weaponFullDef->weapDef.originalAiVsPlayerAccuracyGraphKnotCount, + weaponFullDef->weapCompleteDef.aiVsPlayerAccuracyGraphKnots, + weaponFullDef->weapCompleteDef.aiVsPlayerAccuracyGraphKnotCount, + memory); + } + + return true; + } + bool LoadFromInfoString(const InfoString& infoString, const std::string& assetName, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) { auto* weaponFullDef = memory->Create(); @@ -387,6 +444,8 @@ namespace CalculateWeaponFields(weaponFullDef, memory); + LoadAccuracyGraphs(weaponFullDef, memory, manager); + manager->AddAsset( assetName, &weaponFullDef->weapCompleteDef, converter.GetDependencies(), converter.GetUsedScriptStrings(), converter.GetIndirectAssetReferences()); diff --git a/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderWeapon.cpp b/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderWeapon.cpp index 7343589f..18b3007a 100644 --- a/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderWeapon.cpp +++ b/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderWeapon.cpp @@ -8,6 +8,7 @@ #include "ObjLoading.h" #include "Pool/GlobalAssetPool.h" #include "Utils/StringUtils.h" +#include "Weapon/AccuracyGraphLoader.h" #include #include @@ -800,6 +801,62 @@ namespace } } + void ConvertAccuracyGraph(const GenericGraph2D& graph, + vec2_t*& originalGraphKnots, + uint16_t& originalGraphKnotCount, + vec2_t*& graphKnots, + uint16_t& graphKnotCount, + MemoryManager* memory) + { + originalGraphKnotCount = static_cast(graph.knots.size()); + originalGraphKnots = memory->Alloc(originalGraphKnotCount); + + for (auto i = 0u; i < originalGraphKnotCount; i++) + { + const auto& commonKnot = graph.knots[i]; + originalGraphKnots[i][0] = static_cast(commonKnot.x); + originalGraphKnots[i][1] = static_cast(commonKnot.y); + } + + graphKnots = originalGraphKnots; + graphKnotCount = originalGraphKnotCount; + } + + bool LoadAccuracyGraphs(WeaponFullDef* weaponFullDef, MemoryManager* memory, const IAssetLoadingManager* manager) + { + auto* accuracyGraphLoader = manager->GetAssetLoadingContext()->GetZoneAssetLoaderState(); + + if (weaponFullDef->weapDef.aiVsAiAccuracyGraphName && weaponFullDef->weapDef.aiVsAiAccuracyGraphName[0]) + { + const auto* graph = accuracyGraphLoader->LoadAiVsAiGraph(manager, weaponFullDef->weapDef.aiVsAiAccuracyGraphName); + if (!graph) + return false; + + ConvertAccuracyGraph(*graph, + weaponFullDef->weapDef.originalAiVsAiAccuracyGraphKnots, + weaponFullDef->weapDef.originalAiVsAiAccuracyGraphKnotCount, + weaponFullDef->weapCompleteDef.aiVsAiAccuracyGraphKnots, + weaponFullDef->weapCompleteDef.aiVsAiAccuracyGraphKnotCount, + memory); + } + + if (weaponFullDef->weapDef.aiVsPlayerAccuracyGraphName && weaponFullDef->weapDef.aiVsPlayerAccuracyGraphName[0]) + { + const auto* graph = accuracyGraphLoader->LoadAiVsPlayerGraph(manager, weaponFullDef->weapDef.aiVsPlayerAccuracyGraphName); + if (!graph) + return false; + + ConvertAccuracyGraph(*graph, + weaponFullDef->weapDef.originalAiVsPlayerAccuracyGraphKnots, + weaponFullDef->weapDef.originalAiVsPlayerAccuracyGraphKnotCount, + weaponFullDef->weapCompleteDef.aiVsPlayerAccuracyGraphKnots, + weaponFullDef->weapCompleteDef.aiVsPlayerAccuracyGraphKnotCount, + memory); + } + + return true; + } + bool LoadFromInfoString(const InfoString& infoString, const std::string& assetName, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) { auto* weaponFullDef = memory->Create(); @@ -817,6 +874,8 @@ namespace CalculateWeaponFields(weaponFullDef, memory); + LoadAccuracyGraphs(weaponFullDef, memory, manager); + manager->AddAsset( assetName, &weaponFullDef->weapCompleteDef, converter.GetDependencies(), converter.GetUsedScriptStrings(), converter.GetIndirectAssetReferences()); diff --git a/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderWeapon.cpp b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderWeapon.cpp index dc2ab93d..524042f8 100644 --- a/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderWeapon.cpp +++ b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderWeapon.cpp @@ -9,6 +9,7 @@ #include "InfoString/InfoString.h" #include "Utils/ClassUtils.h" #include "Utils/StringUtils.h" +#include "Weapon/AccuracyGraphLoader.h" #include #include @@ -385,6 +386,58 @@ namespace T6 { } }; + + void ConvertAccuracyGraph( + const GenericGraph2D& graph, vec2_t*& originalGraphKnots, int& originalGraphKnotCount, vec2_t*& graphKnots, int& graphKnotCount, MemoryManager* memory) + { + originalGraphKnotCount = static_cast(graph.knots.size()); + originalGraphKnots = memory->Alloc(originalGraphKnotCount); + + for (auto i = 0; i < originalGraphKnotCount; i++) + { + const auto& commonKnot = graph.knots[i]; + originalGraphKnots[i].x = static_cast(commonKnot.x); + originalGraphKnots[i].y = static_cast(commonKnot.y); + } + + graphKnots = originalGraphKnots; + graphKnotCount = originalGraphKnotCount; + } + + bool LoadAccuracyGraphs(WeaponFullDef* weaponFullDef, MemoryManager* memory, const IAssetLoadingManager* manager) + { + auto* accuracyGraphLoader = manager->GetAssetLoadingContext()->GetZoneAssetLoaderState(); + + if (weaponFullDef->weapDef.aiVsAiAccuracyGraphName && weaponFullDef->weapDef.aiVsAiAccuracyGraphName[0]) + { + const auto* graph = accuracyGraphLoader->LoadAiVsAiGraph(manager, weaponFullDef->weapDef.aiVsAiAccuracyGraphName); + if (!graph) + return false; + + ConvertAccuracyGraph(*graph, + weaponFullDef->weapDef.originalAiVsAiAccuracyGraphKnots, + weaponFullDef->weapDef.originalAiVsAiAccuracyGraphKnotCount, + weaponFullDef->weapDef.aiVsAiAccuracyGraphKnots, + weaponFullDef->weapDef.aiVsAiAccuracyGraphKnotCount, + memory); + } + + if (weaponFullDef->weapDef.aiVsPlayerAccuracyGraphName && weaponFullDef->weapDef.aiVsPlayerAccuracyGraphName[0]) + { + const auto* graph = accuracyGraphLoader->LoadAiVsPlayerGraph(manager, weaponFullDef->weapDef.aiVsPlayerAccuracyGraphName); + if (!graph) + return false; + + ConvertAccuracyGraph(*graph, + weaponFullDef->weapDef.originalAiVsPlayerAccuracyGraphKnots, + weaponFullDef->weapDef.originalAiVsPlayerAccuracyGraphKnotCount, + weaponFullDef->weapDef.aiVsPlayerAccuracyGraphKnots, + weaponFullDef->weapDef.aiVsPlayerAccuracyGraphKnotCount, + memory); + } + + return true; + } } // namespace T6 void AssetLoaderWeapon::LinkWeaponFullDefSubStructs(WeaponFullDef* weapon) @@ -563,10 +616,12 @@ bool AssetLoaderWeapon::LoadFromInfoString( weaponFullDef->weapVariantDef.szInternalName = memory->Dup(assetName.c_str()); - // TODO: Load accuracy graph and flametable + // TODO: Load flametable CalculateWeaponFields(weaponFullDef); CalculateAttachmentFields(weaponFullDef); + LoadAccuracyGraphs(weaponFullDef, memory, manager); + manager->AddAsset( assetName, &weaponFullDef->weapVariantDef, converter.GetDependencies(), converter.GetUsedScriptStrings(), converter.GetIndirectAssetReferences()); diff --git a/src/ObjLoading/Weapon/AccuracyGraphLoader.cpp b/src/ObjLoading/Weapon/AccuracyGraphLoader.cpp new file mode 100644 index 00000000..4ffae119 --- /dev/null +++ b/src/ObjLoading/Weapon/AccuracyGraphLoader.cpp @@ -0,0 +1,55 @@ +#include "AccuracyGraphLoader.h" + +#include "Parsing/Graph2D/Graph2DReader.h" + +#include +#include + +namespace +{ + std::unique_ptr LoadAccuracyGraph(const IAssetLoadingManager* manager, const std::string& graphName, const std::string& subFolder) + { + auto* searchPath = manager->GetAssetLoadingContext()->m_raw_search_path; + const auto fileName = std::format("accuracy/{}/{}", subFolder, graphName); + const auto file = searchPath->Open(fileName); + if (!file.IsOpen()) + { + std::cerr << std::format("Failed to open file for accuracy graph: {}/{}\n", subFolder, graphName); + return nullptr; + } + + return graph2d::Read("accuracy graph", "WEAPONACCUFILE", *file.m_stream, fileName, graphName); + } +} // namespace + +const GenericGraph2D* AccuracyGraphLoader::LoadAiVsAiGraph(const IAssetLoadingManager* manager, const std::string& graphName) +{ + const auto alreadyLoadedGraph = m_loaded_ai_vs_ai_graphs.find(graphName); + if (alreadyLoadedGraph != m_loaded_ai_vs_ai_graphs.end()) + return alreadyLoadedGraph->second.get(); + + auto graph = LoadAccuracyGraph(manager, graphName, "aivsai"); + if (!graph) + return nullptr; + + const auto* graphPtr = graph.get(); + m_loaded_ai_vs_ai_graphs.emplace(graphName, std::move(graph)); + + return graphPtr; +} + +const GenericGraph2D* AccuracyGraphLoader::LoadAiVsPlayerGraph(const IAssetLoadingManager* manager, const std::string& graphName) +{ + const auto alreadyLoadedGraph = m_loaded_ai_vs_player_graphs.find(graphName); + if (alreadyLoadedGraph != m_loaded_ai_vs_player_graphs.end()) + return alreadyLoadedGraph->second.get(); + + auto graph = LoadAccuracyGraph(manager, graphName, "aivsplayer"); + if (!graph) + return nullptr; + + const auto* graphPtr = graph.get(); + m_loaded_ai_vs_player_graphs.emplace(graphName, std::move(graph)); + + return graphPtr; +} diff --git a/src/ObjLoading/Weapon/AccuracyGraphLoader.h b/src/ObjLoading/Weapon/AccuracyGraphLoader.h new file mode 100644 index 00000000..216e6618 --- /dev/null +++ b/src/ObjLoading/Weapon/AccuracyGraphLoader.h @@ -0,0 +1,17 @@ +#pragma once +#include "AssetLoading/IAssetLoadingManager.h" +#include "AssetLoading/IZoneAssetLoaderState.h" +#include "Parsing/GenericGraph2D.h" + +#include + +class AccuracyGraphLoader final : public IZoneAssetLoaderState +{ +public: + const GenericGraph2D* LoadAiVsAiGraph(const IAssetLoadingManager* manager, const std::string& graphName); + const GenericGraph2D* LoadAiVsPlayerGraph(const IAssetLoadingManager* manager, const std::string& graphName); + +private: + std::unordered_map> m_loaded_ai_vs_ai_graphs; + std::unordered_map> m_loaded_ai_vs_player_graphs; +}; diff --git a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperWeapon.cpp b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperWeapon.cpp index 41e55a2d..b61f03a3 100644 --- a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperWeapon.cpp +++ b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperWeapon.cpp @@ -221,9 +221,9 @@ namespace IW4 } }; - GenericAccuracyGraph ConvertAccuracyGraph(const char* graphName, const vec2_t* originalKnots, const unsigned originalKnotCount) + GenericGraph2D ConvertAccuracyGraph(const char* graphName, const vec2_t* originalKnots, const unsigned originalKnotCount) { - GenericAccuracyGraph graph; + GenericGraph2D graph; graph.name = graphName; graph.knots.resize(originalKnotCount); diff --git a/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperWeapon.cpp b/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperWeapon.cpp index eb66f1e4..4749d79d 100644 --- a/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperWeapon.cpp +++ b/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperWeapon.cpp @@ -535,9 +535,9 @@ namespace IW5 const WeaponFullDef* m_weapon; }; - GenericAccuracyGraph ConvertAccuracyGraph(const char* graphName, const vec2_t* originalKnots, const unsigned originalKnotCount) + GenericGraph2D ConvertAccuracyGraph(const char* graphName, const vec2_t* originalKnots, const unsigned originalKnotCount) { - GenericAccuracyGraph graph; + GenericGraph2D graph; graph.name = graphName; graph.knots.resize(originalKnotCount); diff --git a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperWeapon.cpp b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperWeapon.cpp index 030cb80d..eb458716 100644 --- a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperWeapon.cpp +++ b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperWeapon.cpp @@ -265,9 +265,9 @@ namespace T6 } }; - GenericAccuracyGraph ConvertAccuracyGraph(const char* graphName, const vec2_t* originalKnots, const unsigned originalKnotCount) + GenericGraph2D ConvertAccuracyGraph(const char* graphName, const vec2_t* originalKnots, const unsigned originalKnotCount) { - GenericAccuracyGraph graph; + GenericGraph2D graph; graph.name = graphName; graph.knots.resize(originalKnotCount); diff --git a/src/ObjWriting/Weapon/AccuracyGraphWriter.cpp b/src/ObjWriting/Weapon/AccuracyGraphWriter.cpp index b6f0583f..4da6e353 100644 --- a/src/ObjWriting/Weapon/AccuracyGraphWriter.cpp +++ b/src/ObjWriting/Weapon/AccuracyGraphWriter.cpp @@ -19,7 +19,7 @@ namespace return false; } - void DumpAccuracyGraph(const AssetDumpingContext& context, const GenericAccuracyGraph& graph, const std::string& subFolder) + void DumpAccuracyGraph(const AssetDumpingContext& context, const GenericGraph2D& graph, const std::string& subFolder) { const auto file = context.OpenAssetFile(std::format("accuracy/{}/{}", subFolder, graph.name)); if (!file) @@ -46,12 +46,12 @@ bool AccuracyGraphWriter::ShouldDumpAiVsPlayerGraph(const std::string& graphName return ShouldDumpAccuracyGraph(m_dumped_ai_vs_player_graphs, graphName); } -void AccuracyGraphWriter::DumpAiVsAiGraph(const AssetDumpingContext& context, const GenericAccuracyGraph& aiVsAiGraph) +void AccuracyGraphWriter::DumpAiVsAiGraph(const AssetDumpingContext& context, const GenericGraph2D& aiVsAiGraph) { DumpAccuracyGraph(context, aiVsAiGraph, "aivsai"); } -void AccuracyGraphWriter::DumpAiVsPlayerGraph(const AssetDumpingContext& context, const GenericAccuracyGraph& aiVsPlayerGraph) +void AccuracyGraphWriter::DumpAiVsPlayerGraph(const AssetDumpingContext& context, const GenericGraph2D& aiVsPlayerGraph) { DumpAccuracyGraph(context, aiVsPlayerGraph, "aivsplayer"); } diff --git a/src/ObjWriting/Weapon/AccuracyGraphWriter.h b/src/ObjWriting/Weapon/AccuracyGraphWriter.h index a5e2edc3..054d5dea 100644 --- a/src/ObjWriting/Weapon/AccuracyGraphWriter.h +++ b/src/ObjWriting/Weapon/AccuracyGraphWriter.h @@ -1,7 +1,7 @@ #pragma once #include "Dumping/AssetDumpingContext.h" #include "Dumping/IZoneAssetDumperState.h" -#include "Weapon/GenericAccuracyGraph.h" +#include "Parsing/GenericGraph2D.h" #include #include @@ -12,8 +12,8 @@ public: bool ShouldDumpAiVsAiGraph(const std::string& graphName); bool ShouldDumpAiVsPlayerGraph(const std::string& graphName); - static void DumpAiVsAiGraph(const AssetDumpingContext& context, const GenericAccuracyGraph& aiVsAiGraph); - static void DumpAiVsPlayerGraph(const AssetDumpingContext& context, const GenericAccuracyGraph& aiVsPlayerGraph); + static void DumpAiVsAiGraph(const AssetDumpingContext& context, const GenericGraph2D& aiVsAiGraph); + static void DumpAiVsPlayerGraph(const AssetDumpingContext& context, const GenericGraph2D& aiVsPlayerGraph); private: std::unordered_set m_dumped_ai_vs_ai_graphs;