diff --git a/src/ObjLoading/Game/IW5/Image/LoaderImageIW5.cpp b/src/ObjLoading/Game/IW5/Image/LoaderImageIW5.cpp index f30d27e4..09bb4046 100644 --- a/src/ObjLoading/Game/IW5/Image/LoaderImageIW5.cpp +++ b/src/ObjLoading/Game/IW5/Image/LoaderImageIW5.cpp @@ -1,6 +1,7 @@ #include "LoaderImageIW5.h" #include "Game/IW5/IW5.h" +#include "Image/ImageCommon.h" #include "Image/IwiLoader.h" #include @@ -9,6 +10,7 @@ #include using namespace IW5; +using namespace ::image; namespace { @@ -25,7 +27,7 @@ namespace AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override { - const auto fileName = std::format("images/{}.iwi", assetName); + const auto fileName = GetFileNameForAsset(assetName, ".iwi"); const auto file = m_search_path.Open(fileName); if (!file.IsOpen()) return AssetCreationResult::NoAction(); @@ -60,10 +62,10 @@ namespace }; } // namespace -namespace IW5 +namespace IW5::image { - std::unique_ptr> CreateImageLoader(MemoryManager& memory, ISearchPath& searchPath) + std::unique_ptr> CreateLoader(MemoryManager& memory, ISearchPath& searchPath) { return std::make_unique(memory, searchPath); } -} // namespace IW5 +} // namespace IW5::image diff --git a/src/ObjLoading/Game/IW5/Image/LoaderImageIW5.h b/src/ObjLoading/Game/IW5/Image/LoaderImageIW5.h index 66609137..120897b0 100644 --- a/src/ObjLoading/Game/IW5/Image/LoaderImageIW5.h +++ b/src/ObjLoading/Game/IW5/Image/LoaderImageIW5.h @@ -7,7 +7,7 @@ #include -namespace IW5 +namespace IW5::image { - std::unique_ptr> CreateImageLoader(MemoryManager& memory, ISearchPath& searchPath); -} // namespace IW5 + std::unique_ptr> CreateLoader(MemoryManager& memory, ISearchPath& searchPath); +} // namespace IW5::image diff --git a/src/ObjLoading/Game/IW5/Leaderboard/JsonLeaderboardDefLoader.cpp b/src/ObjLoading/Game/IW5/Leaderboard/JsonLeaderboardDefLoader.cpp deleted file mode 100644 index df4d9625..00000000 --- a/src/ObjLoading/Game/IW5/Leaderboard/JsonLeaderboardDefLoader.cpp +++ /dev/null @@ -1,131 +0,0 @@ -#include "JsonLeaderboardDefLoader.h" - -#include "Game/IW5/CommonIW5.h" -#include "Game/IW5/Leaderboard/JsonLeaderboardDef.h" - -#include -#include -#include - -using namespace nlohmann; -using namespace IW5; - -namespace -{ - class JsonLoader - { - public: - JsonLoader(std::istream& stream, MemoryManager& memory) - : m_stream(stream), - m_memory(memory) - { - } - - bool Load(LeaderboardDef& leaderboardDef) const - { - try - { - 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 != "leaderboard" || version != 1u) - { - std::cerr << std::format("Tried to load leaderboard \"{}\" but did not find expected type leaderboard of version 1\n", leaderboardDef.name); - return false; - } - - const auto jLeaderboard = jRoot.get(); - return CreateLeaderboardFromJson(jLeaderboard, leaderboardDef); - } - catch (const json::exception& e) - { - std::cerr << std::format("Failed to parse json of leaderboard: {}\n", e.what()); - } - - return false; - } - - private: - static bool CreateTrackTypeFlagsFromJson(const JsonLeaderboardDef& jLeaderboardDef, int& trackTypeFlags) - { - for (const auto trackType : jLeaderboardDef.trackTypes) - trackTypeFlags |= 1 << trackType; - - return true; - } - - bool CreateColumnDefFromJson(const JsonColumnDef& jColumn, LbColumnDef& lbColumnDef, LeaderboardDef& leaderboardDef) const - { - lbColumnDef.name = m_memory.Dup(jColumn.name.c_str()); - - lbColumnDef.id = jColumn.colId; - lbColumnDef.propertyId = jColumn.propertyId.value_or(0); - lbColumnDef.hidden = jColumn.hidden.value_or(false); - - if (jColumn.statName) - lbColumnDef.statName = m_memory.Dup(jColumn.statName->c_str()); - else - lbColumnDef.statName = nullptr; - - lbColumnDef.type = jColumn.type; - - lbColumnDef.precision = jColumn.precision.value_or(0); - - lbColumnDef.agg = jColumn.aggregationFunction; - - lbColumnDef.uiCalColX = jColumn.uiCalColX.value_or(0); - lbColumnDef.uiCalColY = jColumn.uiCalColY.value_or(0); - - return true; - } - - bool CreateLeaderboardFromJson(const JsonLeaderboardDef& jLeaderboardDef, LeaderboardDef& leaderboardDef) const - { - leaderboardDef.id = jLeaderboardDef.id; - - leaderboardDef.xpColId = jLeaderboardDef.xpColId.value_or(-1); - leaderboardDef.prestigeColId = jLeaderboardDef.prestigeColId.value_or(-1); - - if (!jLeaderboardDef.columns.empty()) - { - leaderboardDef.columnCount = static_cast(jLeaderboardDef.columns.size()); - leaderboardDef.columns = m_memory.Alloc(leaderboardDef.columnCount); - - for (auto i = 0; i < leaderboardDef.columnCount; i++) - { - if (!CreateColumnDefFromJson(jLeaderboardDef.columns[i], leaderboardDef.columns[i], leaderboardDef)) - return false; - } - } - else - { - leaderboardDef.columnCount = 0; - leaderboardDef.columns = nullptr; - } - - leaderboardDef.updateType = jLeaderboardDef.updateType; - - if (!CreateTrackTypeFlagsFromJson(jLeaderboardDef, leaderboardDef.trackTypes)) - return false; - - return true; - } - - std::istream& m_stream; - MemoryManager& m_memory; - }; -} // namespace - -namespace IW5 -{ - bool LoadLeaderboardAsJson(std::istream& stream, LeaderboardDef& leaderboard, MemoryManager& memory) - { - const JsonLoader loader(stream, memory); - - return loader.Load(leaderboard); - } -} // namespace IW5 diff --git a/src/ObjLoading/Game/IW5/Leaderboard/JsonLeaderboardDefLoader.h b/src/ObjLoading/Game/IW5/Leaderboard/JsonLeaderboardDefLoader.h deleted file mode 100644 index 753a5db3..00000000 --- a/src/ObjLoading/Game/IW5/Leaderboard/JsonLeaderboardDefLoader.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "Game/IW5/IW5.h" -#include "Utils/MemoryManager.h" - -#include - -namespace IW5 -{ - bool LoadLeaderboardAsJson(std::istream& stream, LeaderboardDef& leaderboard, MemoryManager& memory); -} // namespace IW5 diff --git a/src/ObjLoading/Game/IW5/Leaderboard/LoaderLeaderboardIW5.cpp b/src/ObjLoading/Game/IW5/Leaderboard/LoaderLeaderboardIW5.cpp index c18ed86b..4ec9f420 100644 --- a/src/ObjLoading/Game/IW5/Leaderboard/LoaderLeaderboardIW5.cpp +++ b/src/ObjLoading/Game/IW5/Leaderboard/LoaderLeaderboardIW5.cpp @@ -1,16 +1,127 @@ #include "LoaderLeaderboardIW5.h" #include "Game/IW5/IW5.h" -#include "JsonLeaderboardDefLoader.h" +#include "Game/IW5/Leaderboard/JsonLeaderboardDef.h" +#include "Leaderboard/LeaderboardCommon.h" #include #include #include +#include +using namespace nlohmann; using namespace IW5; +using namespace ::leaderboard; namespace { + class JsonLoader + { + public: + JsonLoader(std::istream& stream, MemoryManager& memory) + : m_stream(stream), + m_memory(memory) + { + } + + bool Load(LeaderboardDef& leaderboardDef) const + { + try + { + 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 != "leaderboard" || version != 1u) + { + std::cerr << std::format("Tried to load leaderboard \"{}\" but did not find expected type leaderboard of version 1\n", leaderboardDef.name); + return false; + } + + const auto jLeaderboard = jRoot.get(); + return CreateLeaderboardFromJson(jLeaderboard, leaderboardDef); + } + catch (const json::exception& e) + { + std::cerr << std::format("Failed to parse json of leaderboard: {}\n", e.what()); + } + + return false; + } + + private: + static bool CreateTrackTypeFlagsFromJson(const JsonLeaderboardDef& jLeaderboardDef, int& trackTypeFlags) + { + for (const auto trackType : jLeaderboardDef.trackTypes) + trackTypeFlags |= 1 << trackType; + + return true; + } + + bool CreateColumnDefFromJson(const JsonColumnDef& jColumn, LbColumnDef& lbColumnDef, LeaderboardDef& leaderboardDef) const + { + lbColumnDef.name = m_memory.Dup(jColumn.name.c_str()); + + lbColumnDef.id = jColumn.colId; + lbColumnDef.propertyId = jColumn.propertyId.value_or(0); + lbColumnDef.hidden = jColumn.hidden.value_or(false); + + if (jColumn.statName) + lbColumnDef.statName = m_memory.Dup(jColumn.statName->c_str()); + else + lbColumnDef.statName = nullptr; + + lbColumnDef.type = jColumn.type; + + lbColumnDef.precision = jColumn.precision.value_or(0); + + lbColumnDef.agg = jColumn.aggregationFunction; + + lbColumnDef.uiCalColX = jColumn.uiCalColX.value_or(0); + lbColumnDef.uiCalColY = jColumn.uiCalColY.value_or(0); + + return true; + } + + bool CreateLeaderboardFromJson(const JsonLeaderboardDef& jLeaderboardDef, LeaderboardDef& leaderboardDef) const + { + leaderboardDef.id = jLeaderboardDef.id; + + leaderboardDef.xpColId = jLeaderboardDef.xpColId.value_or(-1); + leaderboardDef.prestigeColId = jLeaderboardDef.prestigeColId.value_or(-1); + + if (!jLeaderboardDef.columns.empty()) + { + leaderboardDef.columnCount = static_cast(jLeaderboardDef.columns.size()); + leaderboardDef.columns = m_memory.Alloc(leaderboardDef.columnCount); + + for (auto i = 0; i < leaderboardDef.columnCount; i++) + { + if (!CreateColumnDefFromJson(jLeaderboardDef.columns[i], leaderboardDef.columns[i], leaderboardDef)) + return false; + } + } + else + { + leaderboardDef.columnCount = 0; + leaderboardDef.columns = nullptr; + } + + leaderboardDef.updateType = jLeaderboardDef.updateType; + + if (!CreateTrackTypeFlagsFromJson(jLeaderboardDef, leaderboardDef.trackTypes)) + return false; + + return true; + } + + std::istream& m_stream; + MemoryManager& m_memory; + }; + class LeaderboardLoader final : public AssetCreator { public: @@ -22,14 +133,15 @@ namespace AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override { - const auto file = m_search_path.Open(std::format("leaderboards/{}.json", assetName)); + const auto file = m_search_path.Open(GetJsonFileNameForAsset(assetName)); if (!file.IsOpen()) return AssetCreationResult::NoAction(); auto* leaderboardDef = m_memory.Alloc(); leaderboardDef->name = m_memory.Dup(assetName.c_str()); - if (!LoadLeaderboardAsJson(*file.m_stream, *leaderboardDef, m_memory)) + const JsonLoader loader(*file.m_stream, m_memory); + if (!loader.Load(*leaderboardDef)) { std::cerr << std::format("Failed to load leaderboard \"{}\"\n", assetName); return AssetCreationResult::Failure(); @@ -44,10 +156,10 @@ namespace }; } // namespace -namespace IW5 +namespace IW5::leaderboard { - std::unique_ptr> CreateLeaderboardLoader(MemoryManager& memory, ISearchPath& searchPath) + std::unique_ptr> CreateLoader(MemoryManager& memory, ISearchPath& searchPath) { return std::make_unique(memory, searchPath); } -} // namespace IW5 +} // namespace IW5::leaderboard diff --git a/src/ObjLoading/Game/IW5/Leaderboard/LoaderLeaderboardIW5.h b/src/ObjLoading/Game/IW5/Leaderboard/LoaderLeaderboardIW5.h index 6c144840..d074b9b3 100644 --- a/src/ObjLoading/Game/IW5/Leaderboard/LoaderLeaderboardIW5.h +++ b/src/ObjLoading/Game/IW5/Leaderboard/LoaderLeaderboardIW5.h @@ -7,7 +7,7 @@ #include -namespace IW5 +namespace IW5::leaderboard { - std::unique_ptr> CreateLeaderboardLoader(MemoryManager& memory, ISearchPath& searchPath); -} // namespace IW5 + std::unique_ptr> CreateLoader(MemoryManager& memory, ISearchPath& searchPath); +} // namespace IW5::leaderboard diff --git a/src/ObjLoading/Game/IW5/Localize/LoaderLocalizeIW5.cpp b/src/ObjLoading/Game/IW5/Localize/LoaderLocalizeIW5.cpp index a531c42f..218e9aab 100644 --- a/src/ObjLoading/Game/IW5/Localize/LoaderLocalizeIW5.cpp +++ b/src/ObjLoading/Game/IW5/Localize/LoaderLocalizeIW5.cpp @@ -35,10 +35,10 @@ namespace }; } // namespace -namespace IW5 +namespace IW5::localize { - std::unique_ptr> CreateLocalizeLoader(MemoryManager& memory, ISearchPath& searchPath, Zone& zone) + std::unique_ptr> CreateLoader(MemoryManager& memory, ISearchPath& searchPath, Zone& zone) { return std::make_unique(memory, searchPath, zone); } -} // namespace IW5 +} // namespace IW5::localize diff --git a/src/ObjLoading/Game/IW5/Localize/LoaderLocalizeIW5.h b/src/ObjLoading/Game/IW5/Localize/LoaderLocalizeIW5.h index 6c47a8d1..9588b800 100644 --- a/src/ObjLoading/Game/IW5/Localize/LoaderLocalizeIW5.h +++ b/src/ObjLoading/Game/IW5/Localize/LoaderLocalizeIW5.h @@ -8,7 +8,7 @@ #include -namespace IW5 +namespace IW5::localize { - std::unique_ptr> CreateLocalizeLoader(MemoryManager& memory, ISearchPath& searchPath, Zone& zone); -} // namespace IW5 + std::unique_ptr> CreateLoader(MemoryManager& memory, ISearchPath& searchPath, Zone& zone); +} // namespace IW5::localize diff --git a/src/ObjLoading/Game/IW5/Material/LoaderMaterialIW5.cpp b/src/ObjLoading/Game/IW5/Material/LoaderMaterialIW5.cpp index 189e368f..9ed987d1 100644 --- a/src/ObjLoading/Game/IW5/Material/LoaderMaterialIW5.cpp +++ b/src/ObjLoading/Game/IW5/Material/LoaderMaterialIW5.cpp @@ -8,6 +8,7 @@ #include using namespace IW5; +using namespace ::material; namespace { @@ -22,7 +23,7 @@ namespace AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override { - const auto file = m_search_path.Open(material::GetFileNameForAssetName(assetName)); + const auto file = m_search_path.Open(GetFileNameForAssetName(assetName)); if (!file.IsOpen()) return AssetCreationResult::NoAction(); @@ -45,10 +46,10 @@ namespace }; } // namespace -namespace IW5 +namespace IW5::material { - std::unique_ptr> CreateMaterialLoader(MemoryManager& memory, ISearchPath& searchPath) + std::unique_ptr> CreateLoader(MemoryManager& memory, ISearchPath& searchPath) { return std::make_unique(memory, searchPath); } -} // namespace IW5 +} // namespace IW5::material diff --git a/src/ObjLoading/Game/IW5/Material/LoaderMaterialIW5.h b/src/ObjLoading/Game/IW5/Material/LoaderMaterialIW5.h index 5488c1a7..1f0d7690 100644 --- a/src/ObjLoading/Game/IW5/Material/LoaderMaterialIW5.h +++ b/src/ObjLoading/Game/IW5/Material/LoaderMaterialIW5.h @@ -7,7 +7,7 @@ #include -namespace IW5 +namespace IW5::material { - std::unique_ptr> CreateMaterialLoader(MemoryManager& memory, ISearchPath& searchPath); -} // namespace IW5 + std::unique_ptr> CreateLoader(MemoryManager& memory, ISearchPath& searchPath); +} // namespace IW5::material diff --git a/src/ObjLoading/Game/IW5/Menu/LoaderMenuListIW5.cpp b/src/ObjLoading/Game/IW5/Menu/LoaderMenuListIW5.cpp index 46e6938c..f68b8dd4 100644 --- a/src/ObjLoading/Game/IW5/Menu/LoaderMenuListIW5.cpp +++ b/src/ObjLoading/Game/IW5/Menu/LoaderMenuListIW5.cpp @@ -11,6 +11,7 @@ #include using namespace IW5; +using namespace ::menu; namespace { @@ -28,7 +29,7 @@ namespace std::vector menus; AssetRegistration registration(assetName); - auto& zoneState = context.GetZoneAssetCreationState(); + auto& zoneState = context.GetZoneAssetCreationState(); auto& conversionState = context.GetZoneAssetCreationState(); std::deque menuLoadQueue; @@ -80,7 +81,7 @@ namespace private: bool LoadMenuFileFromQueue(const std::string& menuFilePath, AssetCreationContext& context, - menu::MenuAssetZoneState& zoneState, + MenuAssetZoneState& zoneState, MenuConversionZoneState& conversionState, std::vector& menus, AssetRegistration& registration) const @@ -121,8 +122,8 @@ namespace bool ProcessParsedResults(const std::string& fileName, AssetCreationContext& context, - menu::ParsingResult& parsingResult, - menu::MenuAssetZoneState& zoneState, + ParsingResult& parsingResult, + MenuAssetZoneState& zoneState, MenuConversionZoneState& conversionState, std::vector& menus, AssetRegistration& registration) const @@ -196,10 +197,9 @@ namespace menuList.menus = nullptr; } - std::unique_ptr - ParseMenuFile(std::istream& stream, const std::string& menuFileName, const menu::MenuAssetZoneState& zoneState) const + std::unique_ptr ParseMenuFile(std::istream& stream, const std::string& menuFileName, const MenuAssetZoneState& zoneState) const { - menu::MenuFileReader reader(stream, menuFileName, menu::FeatureLevel::IW5, m_search_path); + MenuFileReader reader(stream, menuFileName, FeatureLevel::IW5, m_search_path); reader.IncludeZoneState(zoneState); reader.SetPermissiveMode(ObjLoading::Configuration.MenuPermissiveParsing); @@ -212,10 +212,10 @@ namespace }; } // namespace -namespace IW5 +namespace IW5::menu { std::unique_ptr> CreateMenuListLoader(MemoryManager& memory, ISearchPath& searchPath) { return std::make_unique(memory, searchPath); } -} // namespace IW5 +} // namespace IW5::menu diff --git a/src/ObjLoading/Game/IW5/Menu/LoaderMenuListIW5.h b/src/ObjLoading/Game/IW5/Menu/LoaderMenuListIW5.h index 823161b8..a323e807 100644 --- a/src/ObjLoading/Game/IW5/Menu/LoaderMenuListIW5.h +++ b/src/ObjLoading/Game/IW5/Menu/LoaderMenuListIW5.h @@ -7,7 +7,7 @@ #include -namespace IW5 +namespace IW5::menu { std::unique_ptr> CreateMenuListLoader(MemoryManager& memory, ISearchPath& searchPath); -} // namespace IW5 +} // namespace IW5::menu diff --git a/src/ObjLoading/Game/IW5/Menu/MenuConverterIW5.h b/src/ObjLoading/Game/IW5/Menu/MenuConverterIW5.h index 2f112270..c0b03845 100644 --- a/src/ObjLoading/Game/IW5/Menu/MenuConverterIW5.h +++ b/src/ObjLoading/Game/IW5/Menu/MenuConverterIW5.h @@ -14,7 +14,7 @@ namespace IW5 IMenuConverter() = default; virtual ~IMenuConverter() = default; - virtual void ConvertMenu(const menu::CommonMenuDef& commonMenu, menuDef_t& menu, AssetRegistration& registration) = 0; + virtual void ConvertMenu(const ::menu::CommonMenuDef& commonMenu, menuDef_t& menu, AssetRegistration& registration) = 0; static std::unique_ptr Create(bool disableOptimizations, ISearchPath& searchPath, MemoryManager& memory, AssetCreationContext& context); }; diff --git a/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp b/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp index 5f254899..b331a795 100644 --- a/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp +++ b/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp @@ -126,12 +126,12 @@ namespace // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); collection.AddAssetCreator(xmodel::CreateXModelLoader(memory, searchPath, zone)); - collection.AddAssetCreator(CreateMaterialLoader(memory, searchPath)); + collection.AddAssetCreator(material::CreateLoader(memory, searchPath)); // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); - collection.AddAssetCreator(CreateImageLoader(memory, searchPath)); + collection.AddAssetCreator(image::CreateLoader(memory, searchPath)); // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); @@ -145,19 +145,19 @@ namespace // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); - collection.AddAssetCreator(CreateMenuListLoader(memory, searchPath)); + collection.AddAssetCreator(menu::CreateMenuListLoader(memory, searchPath)); // collection.AddAssetCreator(std::make_unique(memory)); - collection.AddAssetCreator(CreateLocalizeLoader(memory, searchPath, zone)); - collection.AddAssetCreator(CreateAttachmentLoader(memory, searchPath)); - collection.AddAssetCreator(CreateRawWeaponLoader(memory, searchPath, zone)); - collection.AddAssetCreator(CreateGdtWeaponLoader(memory, searchPath, gdt, zone)); + collection.AddAssetCreator(localize::CreateLoader(memory, searchPath, zone)); + collection.AddAssetCreator(attachment::CreateLoader(memory, searchPath)); + collection.AddAssetCreator(weapon::CreateRawLoader(memory, searchPath, zone)); + collection.AddAssetCreator(weapon::CreateGdtLoader(memory, searchPath, gdt, zone)); // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); - collection.AddAssetCreator(CreateRawFileLoader(memory, searchPath)); - collection.AddAssetCreator(CreateScriptLoader(memory, searchPath)); - collection.AddAssetCreator(CreateStringTableLoader(memory, searchPath)); - collection.AddAssetCreator(CreateLeaderboardLoader(memory, searchPath)); + collection.AddAssetCreator(raw_file::CreateLoader(memory, searchPath)); + collection.AddAssetCreator(script::CreateLoader(memory, searchPath)); + collection.AddAssetCreator(string_table::CreateLoader(memory, searchPath)); + collection.AddAssetCreator(leaderboard::CreateLoader(memory, searchPath)); // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); diff --git a/src/ObjLoading/Game/IW5/RawFile/LoaderRawFileIW5.cpp b/src/ObjLoading/Game/IW5/RawFile/LoaderRawFileIW5.cpp index 139e9ad3..9692a6f9 100644 --- a/src/ObjLoading/Game/IW5/RawFile/LoaderRawFileIW5.cpp +++ b/src/ObjLoading/Game/IW5/RawFile/LoaderRawFileIW5.cpp @@ -81,10 +81,10 @@ namespace }; } // namespace -namespace IW5 +namespace IW5::raw_file { - std::unique_ptr> CreateRawFileLoader(MemoryManager& memory, ISearchPath& searchPath) + std::unique_ptr> CreateLoader(MemoryManager& memory, ISearchPath& searchPath) { return std::make_unique(memory, searchPath); } -} // namespace IW5 +} // namespace IW5::raw_file diff --git a/src/ObjLoading/Game/IW5/RawFile/LoaderRawFileIW5.h b/src/ObjLoading/Game/IW5/RawFile/LoaderRawFileIW5.h index 3099146e..e8c96461 100644 --- a/src/ObjLoading/Game/IW5/RawFile/LoaderRawFileIW5.h +++ b/src/ObjLoading/Game/IW5/RawFile/LoaderRawFileIW5.h @@ -7,7 +7,7 @@ #include -namespace IW5 +namespace IW5::raw_file { - std::unique_ptr> CreateRawFileLoader(MemoryManager& memory, ISearchPath& searchPath); -} // namespace IW5 + std::unique_ptr> CreateLoader(MemoryManager& memory, ISearchPath& searchPath); +} // namespace IW5::raw_file diff --git a/src/ObjLoading/Game/IW5/Script/LoaderScriptFileIW5.cpp b/src/ObjLoading/Game/IW5/Script/LoaderScriptFileIW5.cpp index 5ae68da9..cfbf8125 100644 --- a/src/ObjLoading/Game/IW5/Script/LoaderScriptFileIW5.cpp +++ b/src/ObjLoading/Game/IW5/Script/LoaderScriptFileIW5.cpp @@ -79,10 +79,10 @@ namespace }; } // namespace -namespace IW5 +namespace IW5::script { - std::unique_ptr> CreateScriptLoader(MemoryManager& memory, ISearchPath& searchPath) + std::unique_ptr> CreateLoader(MemoryManager& memory, ISearchPath& searchPath) { return std::make_unique(memory, searchPath); } -} // namespace IW5 +} // namespace IW5::script diff --git a/src/ObjLoading/Game/IW5/Script/LoaderScriptFileIW5.h b/src/ObjLoading/Game/IW5/Script/LoaderScriptFileIW5.h index 457a0957..1380a837 100644 --- a/src/ObjLoading/Game/IW5/Script/LoaderScriptFileIW5.h +++ b/src/ObjLoading/Game/IW5/Script/LoaderScriptFileIW5.h @@ -7,7 +7,7 @@ #include -namespace IW5 +namespace IW5::script { - std::unique_ptr> CreateScriptLoader(MemoryManager& memory, ISearchPath& searchPath); -} // namespace IW5 + std::unique_ptr> CreateLoader(MemoryManager& memory, ISearchPath& searchPath); +} // namespace IW5::script diff --git a/src/ObjLoading/Game/IW5/StringTable/LoaderStringTableIW5.cpp b/src/ObjLoading/Game/IW5/StringTable/LoaderStringTableIW5.cpp index 2ca18723..4f56de03 100644 --- a/src/ObjLoading/Game/IW5/StringTable/LoaderStringTableIW5.cpp +++ b/src/ObjLoading/Game/IW5/StringTable/LoaderStringTableIW5.cpp @@ -10,6 +10,7 @@ #include using namespace IW5; +using namespace ::string_table; namespace { @@ -28,7 +29,7 @@ namespace if (!file.IsOpen()) return AssetCreationResult::NoAction(); - string_table::StringTableLoaderV2 loader; + StringTableLoaderV2 loader; auto* stringTable = loader.LoadFromStream(assetName, m_memory, *file.m_stream); return AssetCreationResult::Success(context.AddAsset(assetName, stringTable)); @@ -40,10 +41,10 @@ namespace }; } // namespace -namespace IW5 +namespace IW5::string_table { - std::unique_ptr> CreateStringTableLoader(MemoryManager& memory, ISearchPath& searchPath) + std::unique_ptr> CreateLoader(MemoryManager& memory, ISearchPath& searchPath) { return std::make_unique(memory, searchPath); } -} // namespace IW5 +} // namespace IW5::string_table diff --git a/src/ObjLoading/Game/IW5/StringTable/LoaderStringTableIW5.h b/src/ObjLoading/Game/IW5/StringTable/LoaderStringTableIW5.h index e07bf9c7..804b8444 100644 --- a/src/ObjLoading/Game/IW5/StringTable/LoaderStringTableIW5.h +++ b/src/ObjLoading/Game/IW5/StringTable/LoaderStringTableIW5.h @@ -7,7 +7,7 @@ #include -namespace IW5 +namespace IW5::string_table { - std::unique_ptr> CreateStringTableLoader(MemoryManager& memory, ISearchPath& searchPath); -} // namespace IW5 + std::unique_ptr> CreateLoader(MemoryManager& memory, ISearchPath& searchPath); +} // namespace IW5::string_table diff --git a/src/ObjLoading/Game/IW5/Weapon/GdtLoaderWeaponIW5.cpp b/src/ObjLoading/Game/IW5/Weapon/GdtLoaderWeaponIW5.cpp index 03897a0d..02d8d733 100644 --- a/src/ObjLoading/Game/IW5/Weapon/GdtLoaderWeaponIW5.cpp +++ b/src/ObjLoading/Game/IW5/Weapon/GdtLoaderWeaponIW5.cpp @@ -40,14 +40,14 @@ namespace private: IGdtQueryable& m_gdt; - InfoStringLoaderWeapon m_info_string_loader; + IW5::weapon::InfoStringLoader m_info_string_loader; }; } // namespace -namespace IW5 +namespace IW5::weapon { - std::unique_ptr> CreateGdtWeaponLoader(MemoryManager& memory, ISearchPath& searchPath, IGdtQueryable& gdt, Zone& zone) + std::unique_ptr> CreateGdtLoader(MemoryManager& memory, ISearchPath& searchPath, IGdtQueryable& gdt, Zone& zone) { return std::make_unique(memory, searchPath, gdt, zone); } -} // namespace IW5 +} // namespace IW5::weapon diff --git a/src/ObjLoading/Game/IW5/Weapon/GdtLoaderWeaponIW5.h b/src/ObjLoading/Game/IW5/Weapon/GdtLoaderWeaponIW5.h index 0e86b336..2bccdb9c 100644 --- a/src/ObjLoading/Game/IW5/Weapon/GdtLoaderWeaponIW5.h +++ b/src/ObjLoading/Game/IW5/Weapon/GdtLoaderWeaponIW5.h @@ -8,7 +8,7 @@ #include -namespace IW5 +namespace IW5::weapon { - std::unique_ptr> CreateGdtWeaponLoader(MemoryManager& memory, ISearchPath& searchPath, IGdtQueryable& gdt, Zone& zone); -} // namespace IW5 + std::unique_ptr> CreateGdtLoader(MemoryManager& memory, ISearchPath& searchPath, IGdtQueryable& gdt, Zone& zone); +} // namespace IW5::weapon diff --git a/src/ObjLoading/Game/IW5/Weapon/InfoStringLoaderWeaponIW5.cpp b/src/ObjLoading/Game/IW5/Weapon/InfoStringLoaderWeaponIW5.cpp index 93f82995..cc9f1f3e 100644 --- a/src/ObjLoading/Game/IW5/Weapon/InfoStringLoaderWeaponIW5.cpp +++ b/src/ObjLoading/Game/IW5/Weapon/InfoStringLoaderWeaponIW5.cpp @@ -856,33 +856,36 @@ namespace } } // namespace -InfoStringLoaderWeapon::InfoStringLoaderWeapon(MemoryManager& memory, ISearchPath& searchPath, Zone& zone) - : m_memory(memory), - m_search_path(searchPath), - m_zone(zone) +namespace IW5::weapon { -} - -AssetCreationResult InfoStringLoaderWeapon::CreateAsset(const std::string& assetName, const InfoString& infoString, AssetCreationContext& context) const -{ - auto* weaponFullDef = m_memory.Alloc(); - - InitWeaponFullDef(*weaponFullDef); - weaponFullDef->weapCompleteDef.szInternalName = m_memory.Dup(assetName.c_str()); - - AssetRegistration registration(assetName, &weaponFullDef->weapCompleteDef); - - InfoStringToWeaponConverter converter( - infoString, *weaponFullDef, m_zone.m_script_strings, m_memory, context, registration, weapon_fields, std::extent_v); - if (!converter.Convert()) + InfoStringLoader::InfoStringLoader(MemoryManager& memory, ISearchPath& searchPath, Zone& zone) + : m_memory(memory), + m_search_path(searchPath), + m_zone(zone) { - std::cerr << std::format("Failed to parse weapon: \"{}\"\n", assetName); - return AssetCreationResult::Failure(); } - CalculateWeaponFields(*weaponFullDef, m_memory); + AssetCreationResult InfoStringLoader::CreateAsset(const std::string& assetName, const InfoString& infoString, AssetCreationContext& context) const + { + auto* weaponFullDef = m_memory.Alloc(); - LoadAccuracyGraphs(*weaponFullDef, m_memory, m_search_path, context); + InitWeaponFullDef(*weaponFullDef); + weaponFullDef->weapCompleteDef.szInternalName = m_memory.Dup(assetName.c_str()); - return AssetCreationResult::Success(context.AddAsset(std::move(registration))); -} + AssetRegistration registration(assetName, &weaponFullDef->weapCompleteDef); + + InfoStringToWeaponConverter converter( + infoString, *weaponFullDef, m_zone.m_script_strings, m_memory, context, registration, weapon_fields, std::extent_v); + if (!converter.Convert()) + { + std::cerr << std::format("Failed to parse weapon: \"{}\"\n", assetName); + return AssetCreationResult::Failure(); + } + + CalculateWeaponFields(*weaponFullDef, m_memory); + + LoadAccuracyGraphs(*weaponFullDef, m_memory, m_search_path, context); + + return AssetCreationResult::Success(context.AddAsset(std::move(registration))); + } +} // namespace IW5::weapon diff --git a/src/ObjLoading/Game/IW5/Weapon/InfoStringLoaderWeaponIW5.h b/src/ObjLoading/Game/IW5/Weapon/InfoStringLoaderWeaponIW5.h index 40f14367..e34dbde8 100644 --- a/src/ObjLoading/Game/IW5/Weapon/InfoStringLoaderWeaponIW5.h +++ b/src/ObjLoading/Game/IW5/Weapon/InfoStringLoaderWeaponIW5.h @@ -4,12 +4,12 @@ #include "Asset/AssetCreationResult.h" #include "InfoString/InfoString.h" -namespace IW5 +namespace IW5::weapon { - class InfoStringLoaderWeapon + class InfoStringLoader { public: - InfoStringLoaderWeapon(MemoryManager& memory, ISearchPath& searchPath, Zone& zone); + InfoStringLoader(MemoryManager& memory, ISearchPath& searchPath, Zone& zone); AssetCreationResult CreateAsset(const std::string& assetName, const InfoString& infoString, AssetCreationContext& context) const; @@ -18,4 +18,4 @@ namespace IW5 ISearchPath& m_search_path; Zone& m_zone; }; -} // namespace IW5 +} // namespace IW5::weapon diff --git a/src/ObjLoading/Game/IW5/Weapon/JsonWeaponAttachmentLoader.cpp b/src/ObjLoading/Game/IW5/Weapon/JsonWeaponAttachmentLoader.cpp deleted file mode 100644 index 44d1bf68..00000000 --- a/src/ObjLoading/Game/IW5/Weapon/JsonWeaponAttachmentLoader.cpp +++ /dev/null @@ -1,645 +0,0 @@ -#include "JsonWeaponAttachmentLoader.h" - -#include "Game/IW5/CommonIW5.h" -#include "Game/IW5/Weapon/JsonWeaponAttachment.h" - -#include -#include -#include - -using namespace nlohmann; -using namespace IW5; - -namespace -{ - class JsonLoader - { - public: - JsonLoader(std::istream& stream, MemoryManager& memory, AssetCreationContext& context, AssetRegistration& registration) - : m_stream(stream), - m_memory(memory), - m_context(context), - m_registration(registration) - - { - } - - bool Load(WeaponAttachment& attachment) const - { - try - { - 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 != "attachment" || version != 1u) - { - std::cerr << "Tried to load attachment \"" << attachment.szInternalName << "\" but did not find expected type attachment of version 1\n"; - return false; - } - - const auto jAttachment = jRoot.get(); - return CreateWeaponAttachmentFromJson(jAttachment, attachment); - } - catch (const json::exception& e) - { - std::cerr << std::format("Failed to parse json of attachment: {}\n", e.what()); - } - - return false; - } - - private: - static void PrintError(const WeaponAttachment& attachment, const std::string& message) - { - std::cerr << "Cannot load attachment \"" << attachment.szInternalName << "\": " << message << "\n"; - } - - bool CreateWeaponAttachmentFromJson(const JsonWeaponAttachment& jAttachment, WeaponAttachment& attachment) const - { -#define CONVERT_XMODEL_ARRAY(propertyName, count) \ - CreateXModelArrayFromJson(jAttachment.propertyName, attachment.propertyName, #propertyName, count, attachment); - -#define CONVERT_ATTRIBUTE(attributeClass, attributeName) \ - if (jAttachment.attributeName) \ - { \ - using AttributeType = std::remove_pointer_t; \ - attachment.attributeName = m_memory.Alloc(); \ - if (!Create##attributeClass##FromJson(jAttachment.attributeName.value(), *attachment.attributeName, attachment)) \ - return false; \ - } \ - else \ - attachment.attributeName = nullptr; - - attachment.szDisplayName = m_memory.Dup(jAttachment.displayName.c_str()); - attachment.type = jAttachment.type; - attachment.weaponType = jAttachment.weaponType; - attachment.weapClass = jAttachment.weapClass; - - CONVERT_XMODEL_ARRAY(worldModels, ATTACHMENT_WORLD_MODEL_COUNT) - CONVERT_XMODEL_ARRAY(viewModels, ATTACHMENT_VIEW_MODEL_COUNT) - CONVERT_XMODEL_ARRAY(reticleViewModels, ATTACHMENT_RETICLE_VIEW_MODEL_COUNT) - - CONVERT_ATTRIBUTE(AttAmmoGeneral, ammoGeneral) - CONVERT_ATTRIBUTE(AttSight, sight) - CONVERT_ATTRIBUTE(AttReload, reload) - CONVERT_ATTRIBUTE(AttAddOns, addOns) - CONVERT_ATTRIBUTE(AttGeneral, general) - CONVERT_ATTRIBUTE(AttAimAssist, aimAssist) - CONVERT_ATTRIBUTE(AttAmmunition, ammunition) - CONVERT_ATTRIBUTE(AttDamage, damage) - CONVERT_ATTRIBUTE(AttLocationDamage, locationDamage) - CONVERT_ATTRIBUTE(AttIdleSettings, idleSettings) - CONVERT_ATTRIBUTE(AttADSSettings, adsSettings) - CONVERT_ATTRIBUTE(AttADSSettings, adsSettingsMain) - CONVERT_ATTRIBUTE(AttHipSpread, hipSpread) - CONVERT_ATTRIBUTE(AttGunKick, gunKick) - CONVERT_ATTRIBUTE(AttViewKick, viewKick) - CONVERT_ATTRIBUTE(AttADSOverlay, adsOverlay) - CONVERT_ATTRIBUTE(AttUI, ui) - CONVERT_ATTRIBUTE(AttRumbles, rumbles) - CONVERT_ATTRIBUTE(AttProjectile, projectile) - - attachment.ammunitionScale = jAttachment.ammunitionScale; - attachment.damageScale = jAttachment.damageScale; - attachment.damageScaleMin = jAttachment.damageScaleMin; - attachment.stateTimersScale = jAttachment.stateTimersScale; - attachment.fireTimersScale = jAttachment.fireTimersScale; - attachment.idleSettingsScale = jAttachment.idleSettingsScale; - attachment.adsSettingsScale = jAttachment.adsSettingsScale; - attachment.adsSettingsScaleMain = jAttachment.adsSettingsScaleMain; - attachment.hipSpreadScale = jAttachment.hipSpreadScale; - attachment.gunKickScale = jAttachment.gunKickScale; - attachment.viewKickScale = jAttachment.viewKickScale; - attachment.viewCenterScale = jAttachment.viewCenterScale; - attachment.loadIndex = jAttachment.loadIndex; - attachment.hideIronSightsWithThisAttachment = jAttachment.hideIronSightsWithThisAttachment; - attachment.shareAmmoWithAlt = jAttachment.shareAmmoWithAlt; - - return true; - } - - bool CreateTracerFromJson(const std::string& assetName, TracerDef*& tracerPtr, const WeaponAttachment& attachment) const - { - auto* tracer = m_context.LoadDependency(assetName); - if (!tracer) - { - PrintError(attachment, std::format("Could not find tracer {}", assetName)); - return false; - } - m_registration.AddDependency(tracer); - tracerPtr = tracer->Asset(); - - return true; - } - - bool CreateMaterialFromJson(const std::string& assetName, Material*& materialPtr, const WeaponAttachment& attachment) const - { - auto* material = m_context.LoadDependency(assetName); - if (!material) - { - PrintError(attachment, std::format("Could not find material {}", assetName)); - return false; - } - m_registration.AddDependency(material); - materialPtr = material->Asset(); - - return true; - } - - bool CreateFxFromJson(const std::string& assetName, FxEffectDef*& fxPtr, const WeaponAttachment& attachment) const - { - auto* fx = m_context.LoadDependency(assetName); - if (!fx) - { - PrintError(attachment, std::format("Could not find fx {}", assetName)); - return false; - } - m_registration.AddDependency(fx); - fxPtr = fx->Asset(); - - return true; - } - - bool CreateSoundFromJson(const std::string& assetName, SndAliasCustom& sndAliasCustom, const WeaponAttachment& attachment) const - { - m_registration.AddIndirectAssetReference(m_context.LoadIndirectAssetReference(assetName)); - sndAliasCustom.name = m_memory.Alloc(); - sndAliasCustom.name->soundName = m_memory.Dup(assetName.c_str()); - - return true; - } - - bool CreateXModelFromJson(const std::string& assetName, XModel*& xmodelPtr, const WeaponAttachment& attachment) const - { - auto* xmodel = m_context.LoadDependency(assetName); - if (!xmodel) - { - PrintError(attachment, std::format("Could not find xmodel {}", assetName)); - return false; - } - m_registration.AddDependency(xmodel); - xmodelPtr = xmodel->Asset(); - - return true; - } - - bool CreateXModelArrayFromJson(const std::vector& jXmodelArray, - XModel**& xmodelArray, - const char* propertyName, - size_t propertyCount, - const WeaponAttachment& attachment) const - { - if (!jXmodelArray.empty()) - { - const auto arraySize = jXmodelArray.size(); - if (arraySize > propertyCount) - { - PrintError(attachment, std::format("{} size cannot exceed {}", propertyName, propertyCount)); - return false; - } - xmodelArray = m_memory.Alloc(propertyCount); - memset(xmodelArray, 0, sizeof(void*) * propertyCount); - - for (auto i = 0u; i < arraySize; i++) - { - if (!CreateXModelFromJson(jXmodelArray[i], xmodelArray[i], attachment)) - return false; - } - } - else - { - xmodelArray = nullptr; - } - - return true; - } - - bool CreateAttAmmoGeneralFromJson(const JsonAttAmmoGeneral& jAmmoGeneral, AttAmmoGeneral& ammoGeneral, const WeaponAttachment& attachment) const - { - ammoGeneral.penetrateType = jAmmoGeneral.penetrateType; - ammoGeneral.penetrateMultiplier = jAmmoGeneral.penetrateMultiplier; - ammoGeneral.impactType = jAmmoGeneral.impactType; - ammoGeneral.fireType = jAmmoGeneral.fireType; - - if (jAmmoGeneral.tracerType) - { - if (!CreateTracerFromJson(jAmmoGeneral.tracerType.value(), ammoGeneral.tracerType, attachment)) - return false; - } - else - ammoGeneral.tracerType = nullptr; - - ammoGeneral.rifleBullet = jAmmoGeneral.rifleBullet; - ammoGeneral.armorPiercing = jAmmoGeneral.armorPiercing; - - return true; - } - - static bool CreateAttSightFromJson(const JsonAttSight& jSight, AttSight& sight, const WeaponAttachment& attachment) - { - sight.aimDownSight = jSight.aimDownSight; - sight.adsFire = jSight.adsFire; - sight.rechamberWhileAds = jSight.rechamberWhileAds; - sight.noAdsWhenMagEmpty = jSight.noAdsWhenMagEmpty; - sight.canHoldBreath = jSight.canHoldBreath; - sight.canVariableZoom = jSight.canVariableZoom; - sight.hideRailWithThisScope = jSight.hideRailWithThisScope; - - return true; - } - - static bool CreateAttReloadFromJson(const JsonAttReload& jReload, AttReload& reload, const WeaponAttachment& attachment) - { - reload.noPartialReload = jReload.noPartialReload; - reload.segmentedReload = jReload.segmentedReload; - - return true; - } - - static bool CreateAttAddOnsFromJson(const JsonAttAddOns& jAddOns, AttAddOns& addOns, const WeaponAttachment& attachment) - { - addOns.motionTracker = jAddOns.motionTracker; - addOns.silenced = jAddOns.silenced; - - return true; - } - - bool CreateAttGeneralFromJson(const JsonAttGeneral& jGeneral, AttGeneral& general, const WeaponAttachment& attachment) const - { - general.boltAction = jGeneral.boltAction; - general.inheritsPerks = jGeneral.inheritsPerks; - general.enemyCrosshairRange = jGeneral.enemyCrosshairRange; - - if (jGeneral.reticleCenter) - { - if (!CreateMaterialFromJson(jGeneral.reticleCenter.value(), general.reticleCenter, attachment)) - return false; - } - else - general.reticleCenter = nullptr; - - if (jGeneral.reticleSide) - { - if (!CreateMaterialFromJson(jGeneral.reticleSide.value(), general.reticleSide, attachment)) - return false; - } - else - general.reticleSide = nullptr; - - general.reticleCenterSize = jGeneral.reticleCenterSize; - general.reticleSideSize = jGeneral.reticleSideSize; - general.moveSpeedScale = jGeneral.moveSpeedScale; - general.adsMoveSpeedScale = jGeneral.adsMoveSpeedScale; - - return true; - } - - static bool CreateAttAimAssistFromJson(const JsonAttAimAssist& jAimAssist, AttAimAssist& aimAssist, const WeaponAttachment& attachment) - { - aimAssist.autoAimRange = jAimAssist.autoAimRange; - aimAssist.aimAssistRange = jAimAssist.aimAssistRange; - aimAssist.aimAssistRangeAds = jAimAssist.aimAssistRangeAds; - - return true; - } - - static bool CreateAttAmmunitionFromJson(const JsonAttAmmunition& jAmmunition, AttAmmunition& ammunition, const WeaponAttachment& attachment) - { - ammunition.maxAmmo = jAmmunition.maxAmmo; - ammunition.startAmmo = jAmmunition.startAmmo; - ammunition.clipSize = jAmmunition.clipSize; - ammunition.shotCount = jAmmunition.shotCount; - ammunition.reloadAmmoAdd = jAmmunition.reloadAmmoAdd; - ammunition.reloadStartAdd = jAmmunition.reloadStartAdd; - - return true; - } - - static bool CreateAttDamageFromJson(const JsonAttDamage& jDamage, AttDamage& damage, const WeaponAttachment& attachment) - { - damage.damage = jDamage.damage; - damage.minDamage = jDamage.minDamage; - damage.meleeDamage = jDamage.meleeDamage; - damage.maxDamageRange = jDamage.maxDamageRange; - damage.minDamageRange = jDamage.minDamageRange; - damage.playerDamage = jDamage.playerDamage; - damage.minPlayerDamage = jDamage.minPlayerDamage; - - return true; - } - - static bool - CreateAttLocationDamageFromJson(const JsonAttLocationDamage& jLocationDamage, AttLocationDamage& locationDamage, const WeaponAttachment& attachment) - { - locationDamage.locNone = jLocationDamage.locNone; - locationDamage.locHelmet = jLocationDamage.locHelmet; - locationDamage.locHead = jLocationDamage.locHead; - locationDamage.locNeck = jLocationDamage.locNeck; - locationDamage.locTorsoUpper = jLocationDamage.locTorsoUpper; - locationDamage.locTorsoLower = jLocationDamage.locTorsoLower; - locationDamage.locRightArmUpper = jLocationDamage.locRightArmUpper; - locationDamage.locRightArmLower = jLocationDamage.locRightArmLower; - locationDamage.locRightHand = jLocationDamage.locRightHand; - locationDamage.locLeftArmUpper = jLocationDamage.locLeftArmUpper; - locationDamage.locLeftArmLower = jLocationDamage.locLeftArmLower; - locationDamage.locLeftHand = jLocationDamage.locLeftHand; - locationDamage.locRightLegUpper = jLocationDamage.locRightLegUpper; - locationDamage.locRightLegLower = jLocationDamage.locRightLegLower; - locationDamage.locRightFoot = jLocationDamage.locRightFoot; - locationDamage.locLeftLegUpper = jLocationDamage.locLeftLegUpper; - locationDamage.locLeftLegLower = jLocationDamage.locLeftLegLower; - locationDamage.locLeftFoot = jLocationDamage.locLeftFoot; - locationDamage.locGun = jLocationDamage.locGun; - - return true; - } - - static bool CreateAttIdleSettingsFromJson(const JsonAttIdleSettings& jIdleSettings, AttIdleSettings& idleSettings, const WeaponAttachment& attachment) - { - idleSettings.hipIdleAmount = jIdleSettings.hipIdleAmount; - idleSettings.hipIdleSpeed = jIdleSettings.hipIdleSpeed; - idleSettings.idleCrouchFactor = jIdleSettings.idleCrouchFactor; - idleSettings.idleProneFactor = jIdleSettings.idleProneFactor; - idleSettings.adsIdleLerpStartTime = jIdleSettings.adsIdleLerpStartTime; - idleSettings.adsIdleLerpTime = jIdleSettings.adsIdleLerpTime; - - return true; - } - - static bool CreateAttADSSettingsFromJson(const JsonAttADSSettings& jAdsSettings, AttADSSettings& adsSettings, const WeaponAttachment& attachment) - { - adsSettings.adsSpread = jAdsSettings.adsSpread; - adsSettings.adsAimPitch = jAdsSettings.adsAimPitch; - adsSettings.adsTransInTime = jAdsSettings.adsTransInTime; - adsSettings.adsTransOutTime = jAdsSettings.adsTransOutTime; - adsSettings.adsReloadTransTime = jAdsSettings.adsReloadTransTime; - adsSettings.adsCrosshairInFrac = jAdsSettings.adsCrosshairInFrac; - adsSettings.adsCrosshairOutFrac = jAdsSettings.adsCrosshairOutFrac; - adsSettings.adsZoomFov = jAdsSettings.adsZoomFov; - adsSettings.adsZoomInFrac = jAdsSettings.adsZoomInFrac; - adsSettings.adsZoomOutFrac = jAdsSettings.adsZoomOutFrac; - adsSettings.adsBobFactor = jAdsSettings.adsBobFactor; - adsSettings.adsViewBobMult = jAdsSettings.adsViewBobMult; - adsSettings.adsViewErrorMin = jAdsSettings.adsViewErrorMin; - adsSettings.adsViewErrorMax = jAdsSettings.adsViewErrorMax; - - return true; - } - - static bool CreateAttHipSpreadFromJson(const JsonAttHipSpread& jHipSpread, AttHipSpread& hipSpread, const WeaponAttachment& attachment) - { - hipSpread.hipSpreadStandMin = jHipSpread.hipSpreadStandMin; - hipSpread.hipSpreadDuckedMin = jHipSpread.hipSpreadDuckedMin; - hipSpread.hipSpreadProneMin = jHipSpread.hipSpreadProneMin; - hipSpread.hipSpreadMax = jHipSpread.hipSpreadMax; - hipSpread.hipSpreadDuckedMax = jHipSpread.hipSpreadDuckedMax; - hipSpread.hipSpreadProneMax = jHipSpread.hipSpreadProneMax; - hipSpread.hipSpreadFireAdd = jHipSpread.hipSpreadFireAdd; - hipSpread.hipSpreadTurnAdd = jHipSpread.hipSpreadTurnAdd; - hipSpread.hipSpreadMoveAdd = jHipSpread.hipSpreadMoveAdd; - hipSpread.hipSpreadDecayRate = jHipSpread.hipSpreadDecayRate; - hipSpread.hipSpreadDuckedDecay = jHipSpread.hipSpreadDuckedDecay; - hipSpread.hipSpreadProneDecay = jHipSpread.hipSpreadProneDecay; - - return true; - } - - static bool CreateAttGunKickFromJson(const JsonAttGunKick& jGunKick, AttGunKick& gunKick, const WeaponAttachment& attachment) - { - gunKick.hipGunKickReducedKickBullets = jGunKick.hipGunKickReducedKickBullets; - gunKick.hipGunKickReducedKickPercent = jGunKick.hipGunKickReducedKickPercent; - gunKick.hipGunKickPitchMin = jGunKick.hipGunKickPitchMin; - gunKick.hipGunKickPitchMax = jGunKick.hipGunKickPitchMax; - gunKick.hipGunKickYawMin = jGunKick.hipGunKickYawMin; - gunKick.hipGunKickYawMax = jGunKick.hipGunKickYawMax; - gunKick.hipGunKickAccel = jGunKick.hipGunKickAccel; - gunKick.hipGunKickSpeedMax = jGunKick.hipGunKickSpeedMax; - gunKick.hipGunKickSpeedDecay = jGunKick.hipGunKickSpeedDecay; - gunKick.hipGunKickStaticDecay = jGunKick.hipGunKickStaticDecay; - gunKick.adsGunKickReducedKickBullets = jGunKick.adsGunKickReducedKickBullets; - gunKick.adsGunKickReducedKickPercent = jGunKick.adsGunKickReducedKickPercent; - gunKick.adsGunKickPitchMin = jGunKick.adsGunKickPitchMin; - gunKick.adsGunKickPitchMax = jGunKick.adsGunKickPitchMax; - gunKick.adsGunKickYawMin = jGunKick.adsGunKickYawMin; - gunKick.adsGunKickYawMax = jGunKick.adsGunKickYawMax; - gunKick.adsGunKickAccel = jGunKick.adsGunKickAccel; - gunKick.adsGunKickSpeedMax = jGunKick.adsGunKickSpeedMax; - gunKick.adsGunKickSpeedDecay = jGunKick.adsGunKickSpeedDecay; - gunKick.adsGunKickStaticDecay = jGunKick.adsGunKickStaticDecay; - - return true; - } - - static bool CreateAttViewKickFromJson(const JsonAttViewKick& jViewKick, AttViewKick& viewKick, const WeaponAttachment& attachment) - { - viewKick.hipViewKickPitchMin = jViewKick.hipViewKickPitchMin; - viewKick.hipViewKickPitchMax = jViewKick.hipViewKickPitchMax; - viewKick.hipViewKickYawMin = jViewKick.hipViewKickYawMin; - viewKick.hipViewKickYawMax = jViewKick.hipViewKickYawMax; - viewKick.hipViewKickCenterSpeed = jViewKick.hipViewKickCenterSpeed; - viewKick.adsViewKickPitchMin = jViewKick.adsViewKickPitchMin; - viewKick.adsViewKickPitchMax = jViewKick.adsViewKickPitchMax; - viewKick.adsViewKickYawMin = jViewKick.adsViewKickYawMin; - viewKick.adsViewKickYawMax = jViewKick.adsViewKickYawMax; - viewKick.adsViewKickCenterSpeed = jViewKick.adsViewKickCenterSpeed; - - return true; - } - - bool CreateAttADSOverlayFromJson(const JsonAttADSOverlay& jAdsOverlay, AttADSOverlay& adsOverlay, const WeaponAttachment& attachment) const - { - if (jAdsOverlay.shader) - { - if (!CreateMaterialFromJson(jAdsOverlay.shader.value(), adsOverlay.overlay.shader, attachment)) - return false; - } - else - adsOverlay.overlay.shader = nullptr; - - if (jAdsOverlay.shaderLowRes) - { - if (!CreateMaterialFromJson(jAdsOverlay.shaderLowRes.value(), adsOverlay.overlay.shaderLowRes, attachment)) - return false; - } - else - adsOverlay.overlay.shaderLowRes = nullptr; - - if (jAdsOverlay.shaderEMP) - { - if (!CreateMaterialFromJson(jAdsOverlay.shaderEMP.value(), adsOverlay.overlay.shaderEMP, attachment)) - return false; - } - else - adsOverlay.overlay.shaderEMP = nullptr; - - if (jAdsOverlay.shaderEMPLowRes) - { - if (!CreateMaterialFromJson(jAdsOverlay.shaderEMPLowRes.value(), adsOverlay.overlay.shaderEMPLowRes, attachment)) - return false; - } - else - adsOverlay.overlay.shaderEMPLowRes = nullptr; - - adsOverlay.overlay.reticle = jAdsOverlay.reticle; - adsOverlay.overlay.width = jAdsOverlay.width; - adsOverlay.overlay.height = jAdsOverlay.height; - adsOverlay.overlay.widthSplitscreen = jAdsOverlay.widthSplitscreen; - adsOverlay.overlay.heightSplitscreen = jAdsOverlay.heightSplitscreen; - adsOverlay.thermalScope = jAdsOverlay.thermalScope; - - return true; - } - - bool CreateAttUIFromJson(const JsonAttUI& jUi, AttUI& ui, const WeaponAttachment& attachment) const - { - if (jUi.dpadIcon) - { - if (!CreateMaterialFromJson(jUi.dpadIcon.value(), ui.dpadIcon, attachment)) - return false; - } - else - ui.dpadIcon = nullptr; - - if (jUi.ammoCounterIcon) - { - if (!CreateMaterialFromJson(jUi.ammoCounterIcon.value(), ui.ammoCounterIcon, attachment)) - return false; - } - else - ui.ammoCounterIcon = nullptr; - - ui.dpadIconRatio = jUi.dpadIconRatio; - ui.ammoCounterIconRatio = jUi.ammoCounterIconRatio; - ui.ammoCounterClip = jUi.ammoCounterClip; - - return true; - } - - bool CreateAttRumblesFromJson(const JsonAttRumbles& jRumbles, AttRumbles& rumbles, const WeaponAttachment& attachment) const - { - if (jRumbles.fireRumble) - rumbles.fireRumble = m_memory.Dup(jRumbles.fireRumble.value().c_str()); - else - rumbles.fireRumble = nullptr; - - if (jRumbles.meleeImpactRumble) - rumbles.meleeImpactRumble = m_memory.Dup(jRumbles.meleeImpactRumble.value().c_str()); - else - rumbles.meleeImpactRumble = nullptr; - - return true; - } - - bool CreateAttProjectileFromJson(const JsonAttProjectile& jProjectile, AttProjectile& projectile, const WeaponAttachment& attachment) const - { - projectile.explosionRadius = jProjectile.explosionRadius; - projectile.explosionInnerDamage = jProjectile.explosionInnerDamage; - projectile.explosionOuterDamage = jProjectile.explosionOuterDamage; - projectile.damageConeAngle = jProjectile.damageConeAngle; - projectile.projectileSpeed = jProjectile.projectileSpeed; - projectile.projectileSpeedUp = jProjectile.projectileSpeedUp; - projectile.projectileActivateDist = jProjectile.projectileActivateDist; - projectile.projectileLifetime = jProjectile.projectileLifetime; - - if (jProjectile.projectileModel) - { - if (!CreateXModelFromJson(jProjectile.projectileModel.value(), projectile.projectileModel, attachment)) - return false; - } - else - projectile.projectileModel = nullptr; - - projectile.projExplosionType = jProjectile.projExplosionType; - - if (jProjectile.projExplosionEffect) - { - if (!CreateFxFromJson(jProjectile.projExplosionEffect.value(), projectile.projExplosionEffect, attachment)) - return false; - } - else - projectile.projExplosionEffect = nullptr; - - projectile.projExplosionEffectForceNormalUp = jProjectile.projExplosionEffectForceNormalUp; - - if (jProjectile.projExplosionSound) - { - if (!CreateSoundFromJson(jProjectile.projExplosionSound.value(), projectile.projExplosionSound, attachment)) - return false; - } - else - projectile.projExplosionSound.name = nullptr; - - if (jProjectile.projDudEffect) - { - if (!CreateFxFromJson(jProjectile.projDudEffect.value(), projectile.projDudEffect, attachment)) - return false; - } - else - projectile.projDudEffect = nullptr; - - if (jProjectile.projDudSound) - { - if (!CreateSoundFromJson(jProjectile.projDudSound.value(), projectile.projDudSound, attachment)) - return false; - } - else - projectile.projDudSound.name = nullptr; - - projectile.projImpactExplode = jProjectile.projImpactExplode; - projectile.destabilizationRateTime = jProjectile.destabilizationRateTime; - projectile.destabilizationCurvatureMax = jProjectile.destabilizationCurvatureMax; - projectile.destabilizeDistance = jProjectile.destabilizeDistance; - - if (jProjectile.projTrailEffect) - { - if (!CreateFxFromJson(jProjectile.projTrailEffect.value(), projectile.projTrailEffect, attachment)) - return false; - } - else - projectile.projTrailEffect = nullptr; - - projectile.projIgnitionDelay = jProjectile.projIgnitionDelay; - - if (jProjectile.projIgnitionEffect) - { - if (!CreateFxFromJson(jProjectile.projIgnitionEffect.value(), projectile.projIgnitionEffect, attachment)) - return false; - } - else - projectile.projIgnitionEffect = nullptr; - - if (jProjectile.projIgnitionSound) - { - if (!CreateSoundFromJson(jProjectile.projIgnitionSound.value(), projectile.projIgnitionSound, attachment)) - return false; - } - else - projectile.projIgnitionSound.name = nullptr; - - return true; - } - - std::istream& m_stream; - MemoryManager& m_memory; - AssetCreationContext& m_context; - AssetRegistration& m_registration; - }; -} // namespace - -namespace IW5 -{ - bool LoadWeaponAttachmentAsJson(std::istream& stream, - WeaponAttachment& attachment, - MemoryManager& memory, - AssetCreationContext& context, - AssetRegistration& registration) - { - const JsonLoader loader(stream, memory, context, registration); - - return loader.Load(attachment); - } -} // namespace IW5 diff --git a/src/ObjLoading/Game/IW5/Weapon/JsonWeaponAttachmentLoader.h b/src/ObjLoading/Game/IW5/Weapon/JsonWeaponAttachmentLoader.h deleted file mode 100644 index 5b9d7b06..00000000 --- a/src/ObjLoading/Game/IW5/Weapon/JsonWeaponAttachmentLoader.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include "Asset/AssetCreationContext.h" -#include "Asset/AssetRegistration.h" -#include "Game/IW5/IW5.h" -#include "Utils/MemoryManager.h" - -#include - -namespace IW5 -{ - bool LoadWeaponAttachmentAsJson(std::istream& stream, - WeaponAttachment& attachment, - MemoryManager& memory, - AssetCreationContext& context, - AssetRegistration& registration); -} // namespace IW5 diff --git a/src/ObjLoading/Game/IW5/Weapon/LoaderAttachmentIW5.cpp b/src/ObjLoading/Game/IW5/Weapon/LoaderAttachmentIW5.cpp index ac7197c1..9d261f8e 100644 --- a/src/ObjLoading/Game/IW5/Weapon/LoaderAttachmentIW5.cpp +++ b/src/ObjLoading/Game/IW5/Weapon/LoaderAttachmentIW5.cpp @@ -1,16 +1,637 @@ #include "LoaderAttachmentIW5.h" #include "Game/IW5/IW5.h" -#include "JsonWeaponAttachmentLoader.h" +#include "Game/IW5/Weapon/JsonWeaponAttachment.h" +#include "Weapon/AttachmentCommon.h" #include #include #include +#include +using namespace nlohmann; using namespace IW5; +using namespace ::attachment; namespace { + class JsonLoader + { + public: + JsonLoader(std::istream& stream, MemoryManager& memory, AssetCreationContext& context, AssetRegistration& registration) + : m_stream(stream), + m_memory(memory), + m_context(context), + m_registration(registration) + + { + } + + bool Load(WeaponAttachment& attachment) const + { + try + { + 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 != "attachment" || version != 1u) + { + std::cerr << "Tried to load attachment \"" << attachment.szInternalName << "\" but did not find expected type attachment of version 1\n"; + return false; + } + + const auto jAttachment = jRoot.get(); + return CreateWeaponAttachmentFromJson(jAttachment, attachment); + } + catch (const json::exception& e) + { + std::cerr << std::format("Failed to parse json of attachment: {}\n", e.what()); + } + + return false; + } + + private: + static void PrintError(const WeaponAttachment& attachment, const std::string& message) + { + std::cerr << "Cannot load attachment \"" << attachment.szInternalName << "\": " << message << "\n"; + } + + bool CreateWeaponAttachmentFromJson(const JsonWeaponAttachment& jAttachment, WeaponAttachment& attachment) const + { +#define CONVERT_XMODEL_ARRAY(propertyName, count) \ + CreateXModelArrayFromJson(jAttachment.propertyName, attachment.propertyName, #propertyName, count, attachment); + +#define CONVERT_ATTRIBUTE(attributeClass, attributeName) \ + if (jAttachment.attributeName) \ + { \ + using AttributeType = std::remove_pointer_t; \ + attachment.attributeName = m_memory.Alloc(); \ + if (!Create##attributeClass##FromJson(jAttachment.attributeName.value(), *attachment.attributeName, attachment)) \ + return false; \ + } \ + else \ + attachment.attributeName = nullptr; + + attachment.szDisplayName = m_memory.Dup(jAttachment.displayName.c_str()); + attachment.type = jAttachment.type; + attachment.weaponType = jAttachment.weaponType; + attachment.weapClass = jAttachment.weapClass; + + CONVERT_XMODEL_ARRAY(worldModels, ATTACHMENT_WORLD_MODEL_COUNT) + CONVERT_XMODEL_ARRAY(viewModels, ATTACHMENT_VIEW_MODEL_COUNT) + CONVERT_XMODEL_ARRAY(reticleViewModels, ATTACHMENT_RETICLE_VIEW_MODEL_COUNT) + + CONVERT_ATTRIBUTE(AttAmmoGeneral, ammoGeneral) + CONVERT_ATTRIBUTE(AttSight, sight) + CONVERT_ATTRIBUTE(AttReload, reload) + CONVERT_ATTRIBUTE(AttAddOns, addOns) + CONVERT_ATTRIBUTE(AttGeneral, general) + CONVERT_ATTRIBUTE(AttAimAssist, aimAssist) + CONVERT_ATTRIBUTE(AttAmmunition, ammunition) + CONVERT_ATTRIBUTE(AttDamage, damage) + CONVERT_ATTRIBUTE(AttLocationDamage, locationDamage) + CONVERT_ATTRIBUTE(AttIdleSettings, idleSettings) + CONVERT_ATTRIBUTE(AttADSSettings, adsSettings) + CONVERT_ATTRIBUTE(AttADSSettings, adsSettingsMain) + CONVERT_ATTRIBUTE(AttHipSpread, hipSpread) + CONVERT_ATTRIBUTE(AttGunKick, gunKick) + CONVERT_ATTRIBUTE(AttViewKick, viewKick) + CONVERT_ATTRIBUTE(AttADSOverlay, adsOverlay) + CONVERT_ATTRIBUTE(AttUI, ui) + CONVERT_ATTRIBUTE(AttRumbles, rumbles) + CONVERT_ATTRIBUTE(AttProjectile, projectile) + + attachment.ammunitionScale = jAttachment.ammunitionScale; + attachment.damageScale = jAttachment.damageScale; + attachment.damageScaleMin = jAttachment.damageScaleMin; + attachment.stateTimersScale = jAttachment.stateTimersScale; + attachment.fireTimersScale = jAttachment.fireTimersScale; + attachment.idleSettingsScale = jAttachment.idleSettingsScale; + attachment.adsSettingsScale = jAttachment.adsSettingsScale; + attachment.adsSettingsScaleMain = jAttachment.adsSettingsScaleMain; + attachment.hipSpreadScale = jAttachment.hipSpreadScale; + attachment.gunKickScale = jAttachment.gunKickScale; + attachment.viewKickScale = jAttachment.viewKickScale; + attachment.viewCenterScale = jAttachment.viewCenterScale; + attachment.loadIndex = jAttachment.loadIndex; + attachment.hideIronSightsWithThisAttachment = jAttachment.hideIronSightsWithThisAttachment; + attachment.shareAmmoWithAlt = jAttachment.shareAmmoWithAlt; + + return true; + } + + bool CreateTracerFromJson(const std::string& assetName, TracerDef*& tracerPtr, const WeaponAttachment& attachment) const + { + auto* tracer = m_context.LoadDependency(assetName); + if (!tracer) + { + PrintError(attachment, std::format("Could not find tracer {}", assetName)); + return false; + } + m_registration.AddDependency(tracer); + tracerPtr = tracer->Asset(); + + return true; + } + + bool CreateMaterialFromJson(const std::string& assetName, Material*& materialPtr, const WeaponAttachment& attachment) const + { + auto* material = m_context.LoadDependency(assetName); + if (!material) + { + PrintError(attachment, std::format("Could not find material {}", assetName)); + return false; + } + m_registration.AddDependency(material); + materialPtr = material->Asset(); + + return true; + } + + bool CreateFxFromJson(const std::string& assetName, FxEffectDef*& fxPtr, const WeaponAttachment& attachment) const + { + auto* fx = m_context.LoadDependency(assetName); + if (!fx) + { + PrintError(attachment, std::format("Could not find fx {}", assetName)); + return false; + } + m_registration.AddDependency(fx); + fxPtr = fx->Asset(); + + return true; + } + + bool CreateSoundFromJson(const std::string& assetName, SndAliasCustom& sndAliasCustom, const WeaponAttachment& attachment) const + { + m_registration.AddIndirectAssetReference(m_context.LoadIndirectAssetReference(assetName)); + sndAliasCustom.name = m_memory.Alloc(); + sndAliasCustom.name->soundName = m_memory.Dup(assetName.c_str()); + + return true; + } + + bool CreateXModelFromJson(const std::string& assetName, XModel*& xmodelPtr, const WeaponAttachment& attachment) const + { + auto* xmodel = m_context.LoadDependency(assetName); + if (!xmodel) + { + PrintError(attachment, std::format("Could not find xmodel {}", assetName)); + return false; + } + m_registration.AddDependency(xmodel); + xmodelPtr = xmodel->Asset(); + + return true; + } + + bool CreateXModelArrayFromJson(const std::vector& jXmodelArray, + XModel**& xmodelArray, + const char* propertyName, + size_t propertyCount, + const WeaponAttachment& attachment) const + { + if (!jXmodelArray.empty()) + { + const auto arraySize = jXmodelArray.size(); + if (arraySize > propertyCount) + { + PrintError(attachment, std::format("{} size cannot exceed {}", propertyName, propertyCount)); + return false; + } + xmodelArray = m_memory.Alloc(propertyCount); + memset(xmodelArray, 0, sizeof(void*) * propertyCount); + + for (auto i = 0u; i < arraySize; i++) + { + if (!CreateXModelFromJson(jXmodelArray[i], xmodelArray[i], attachment)) + return false; + } + } + else + { + xmodelArray = nullptr; + } + + return true; + } + + bool CreateAttAmmoGeneralFromJson(const JsonAttAmmoGeneral& jAmmoGeneral, AttAmmoGeneral& ammoGeneral, const WeaponAttachment& attachment) const + { + ammoGeneral.penetrateType = jAmmoGeneral.penetrateType; + ammoGeneral.penetrateMultiplier = jAmmoGeneral.penetrateMultiplier; + ammoGeneral.impactType = jAmmoGeneral.impactType; + ammoGeneral.fireType = jAmmoGeneral.fireType; + + if (jAmmoGeneral.tracerType) + { + if (!CreateTracerFromJson(jAmmoGeneral.tracerType.value(), ammoGeneral.tracerType, attachment)) + return false; + } + else + ammoGeneral.tracerType = nullptr; + + ammoGeneral.rifleBullet = jAmmoGeneral.rifleBullet; + ammoGeneral.armorPiercing = jAmmoGeneral.armorPiercing; + + return true; + } + + static bool CreateAttSightFromJson(const JsonAttSight& jSight, AttSight& sight, const WeaponAttachment& attachment) + { + sight.aimDownSight = jSight.aimDownSight; + sight.adsFire = jSight.adsFire; + sight.rechamberWhileAds = jSight.rechamberWhileAds; + sight.noAdsWhenMagEmpty = jSight.noAdsWhenMagEmpty; + sight.canHoldBreath = jSight.canHoldBreath; + sight.canVariableZoom = jSight.canVariableZoom; + sight.hideRailWithThisScope = jSight.hideRailWithThisScope; + + return true; + } + + static bool CreateAttReloadFromJson(const JsonAttReload& jReload, AttReload& reload, const WeaponAttachment& attachment) + { + reload.noPartialReload = jReload.noPartialReload; + reload.segmentedReload = jReload.segmentedReload; + + return true; + } + + static bool CreateAttAddOnsFromJson(const JsonAttAddOns& jAddOns, AttAddOns& addOns, const WeaponAttachment& attachment) + { + addOns.motionTracker = jAddOns.motionTracker; + addOns.silenced = jAddOns.silenced; + + return true; + } + + bool CreateAttGeneralFromJson(const JsonAttGeneral& jGeneral, AttGeneral& general, const WeaponAttachment& attachment) const + { + general.boltAction = jGeneral.boltAction; + general.inheritsPerks = jGeneral.inheritsPerks; + general.enemyCrosshairRange = jGeneral.enemyCrosshairRange; + + if (jGeneral.reticleCenter) + { + if (!CreateMaterialFromJson(jGeneral.reticleCenter.value(), general.reticleCenter, attachment)) + return false; + } + else + general.reticleCenter = nullptr; + + if (jGeneral.reticleSide) + { + if (!CreateMaterialFromJson(jGeneral.reticleSide.value(), general.reticleSide, attachment)) + return false; + } + else + general.reticleSide = nullptr; + + general.reticleCenterSize = jGeneral.reticleCenterSize; + general.reticleSideSize = jGeneral.reticleSideSize; + general.moveSpeedScale = jGeneral.moveSpeedScale; + general.adsMoveSpeedScale = jGeneral.adsMoveSpeedScale; + + return true; + } + + static bool CreateAttAimAssistFromJson(const JsonAttAimAssist& jAimAssist, AttAimAssist& aimAssist, const WeaponAttachment& attachment) + { + aimAssist.autoAimRange = jAimAssist.autoAimRange; + aimAssist.aimAssistRange = jAimAssist.aimAssistRange; + aimAssist.aimAssistRangeAds = jAimAssist.aimAssistRangeAds; + + return true; + } + + static bool CreateAttAmmunitionFromJson(const JsonAttAmmunition& jAmmunition, AttAmmunition& ammunition, const WeaponAttachment& attachment) + { + ammunition.maxAmmo = jAmmunition.maxAmmo; + ammunition.startAmmo = jAmmunition.startAmmo; + ammunition.clipSize = jAmmunition.clipSize; + ammunition.shotCount = jAmmunition.shotCount; + ammunition.reloadAmmoAdd = jAmmunition.reloadAmmoAdd; + ammunition.reloadStartAdd = jAmmunition.reloadStartAdd; + + return true; + } + + static bool CreateAttDamageFromJson(const JsonAttDamage& jDamage, AttDamage& damage, const WeaponAttachment& attachment) + { + damage.damage = jDamage.damage; + damage.minDamage = jDamage.minDamage; + damage.meleeDamage = jDamage.meleeDamage; + damage.maxDamageRange = jDamage.maxDamageRange; + damage.minDamageRange = jDamage.minDamageRange; + damage.playerDamage = jDamage.playerDamage; + damage.minPlayerDamage = jDamage.minPlayerDamage; + + return true; + } + + static bool + CreateAttLocationDamageFromJson(const JsonAttLocationDamage& jLocationDamage, AttLocationDamage& locationDamage, const WeaponAttachment& attachment) + { + locationDamage.locNone = jLocationDamage.locNone; + locationDamage.locHelmet = jLocationDamage.locHelmet; + locationDamage.locHead = jLocationDamage.locHead; + locationDamage.locNeck = jLocationDamage.locNeck; + locationDamage.locTorsoUpper = jLocationDamage.locTorsoUpper; + locationDamage.locTorsoLower = jLocationDamage.locTorsoLower; + locationDamage.locRightArmUpper = jLocationDamage.locRightArmUpper; + locationDamage.locRightArmLower = jLocationDamage.locRightArmLower; + locationDamage.locRightHand = jLocationDamage.locRightHand; + locationDamage.locLeftArmUpper = jLocationDamage.locLeftArmUpper; + locationDamage.locLeftArmLower = jLocationDamage.locLeftArmLower; + locationDamage.locLeftHand = jLocationDamage.locLeftHand; + locationDamage.locRightLegUpper = jLocationDamage.locRightLegUpper; + locationDamage.locRightLegLower = jLocationDamage.locRightLegLower; + locationDamage.locRightFoot = jLocationDamage.locRightFoot; + locationDamage.locLeftLegUpper = jLocationDamage.locLeftLegUpper; + locationDamage.locLeftLegLower = jLocationDamage.locLeftLegLower; + locationDamage.locLeftFoot = jLocationDamage.locLeftFoot; + locationDamage.locGun = jLocationDamage.locGun; + + return true; + } + + static bool CreateAttIdleSettingsFromJson(const JsonAttIdleSettings& jIdleSettings, AttIdleSettings& idleSettings, const WeaponAttachment& attachment) + { + idleSettings.hipIdleAmount = jIdleSettings.hipIdleAmount; + idleSettings.hipIdleSpeed = jIdleSettings.hipIdleSpeed; + idleSettings.idleCrouchFactor = jIdleSettings.idleCrouchFactor; + idleSettings.idleProneFactor = jIdleSettings.idleProneFactor; + idleSettings.adsIdleLerpStartTime = jIdleSettings.adsIdleLerpStartTime; + idleSettings.adsIdleLerpTime = jIdleSettings.adsIdleLerpTime; + + return true; + } + + static bool CreateAttADSSettingsFromJson(const JsonAttADSSettings& jAdsSettings, AttADSSettings& adsSettings, const WeaponAttachment& attachment) + { + adsSettings.adsSpread = jAdsSettings.adsSpread; + adsSettings.adsAimPitch = jAdsSettings.adsAimPitch; + adsSettings.adsTransInTime = jAdsSettings.adsTransInTime; + adsSettings.adsTransOutTime = jAdsSettings.adsTransOutTime; + adsSettings.adsReloadTransTime = jAdsSettings.adsReloadTransTime; + adsSettings.adsCrosshairInFrac = jAdsSettings.adsCrosshairInFrac; + adsSettings.adsCrosshairOutFrac = jAdsSettings.adsCrosshairOutFrac; + adsSettings.adsZoomFov = jAdsSettings.adsZoomFov; + adsSettings.adsZoomInFrac = jAdsSettings.adsZoomInFrac; + adsSettings.adsZoomOutFrac = jAdsSettings.adsZoomOutFrac; + adsSettings.adsBobFactor = jAdsSettings.adsBobFactor; + adsSettings.adsViewBobMult = jAdsSettings.adsViewBobMult; + adsSettings.adsViewErrorMin = jAdsSettings.adsViewErrorMin; + adsSettings.adsViewErrorMax = jAdsSettings.adsViewErrorMax; + + return true; + } + + static bool CreateAttHipSpreadFromJson(const JsonAttHipSpread& jHipSpread, AttHipSpread& hipSpread, const WeaponAttachment& attachment) + { + hipSpread.hipSpreadStandMin = jHipSpread.hipSpreadStandMin; + hipSpread.hipSpreadDuckedMin = jHipSpread.hipSpreadDuckedMin; + hipSpread.hipSpreadProneMin = jHipSpread.hipSpreadProneMin; + hipSpread.hipSpreadMax = jHipSpread.hipSpreadMax; + hipSpread.hipSpreadDuckedMax = jHipSpread.hipSpreadDuckedMax; + hipSpread.hipSpreadProneMax = jHipSpread.hipSpreadProneMax; + hipSpread.hipSpreadFireAdd = jHipSpread.hipSpreadFireAdd; + hipSpread.hipSpreadTurnAdd = jHipSpread.hipSpreadTurnAdd; + hipSpread.hipSpreadMoveAdd = jHipSpread.hipSpreadMoveAdd; + hipSpread.hipSpreadDecayRate = jHipSpread.hipSpreadDecayRate; + hipSpread.hipSpreadDuckedDecay = jHipSpread.hipSpreadDuckedDecay; + hipSpread.hipSpreadProneDecay = jHipSpread.hipSpreadProneDecay; + + return true; + } + + static bool CreateAttGunKickFromJson(const JsonAttGunKick& jGunKick, AttGunKick& gunKick, const WeaponAttachment& attachment) + { + gunKick.hipGunKickReducedKickBullets = jGunKick.hipGunKickReducedKickBullets; + gunKick.hipGunKickReducedKickPercent = jGunKick.hipGunKickReducedKickPercent; + gunKick.hipGunKickPitchMin = jGunKick.hipGunKickPitchMin; + gunKick.hipGunKickPitchMax = jGunKick.hipGunKickPitchMax; + gunKick.hipGunKickYawMin = jGunKick.hipGunKickYawMin; + gunKick.hipGunKickYawMax = jGunKick.hipGunKickYawMax; + gunKick.hipGunKickAccel = jGunKick.hipGunKickAccel; + gunKick.hipGunKickSpeedMax = jGunKick.hipGunKickSpeedMax; + gunKick.hipGunKickSpeedDecay = jGunKick.hipGunKickSpeedDecay; + gunKick.hipGunKickStaticDecay = jGunKick.hipGunKickStaticDecay; + gunKick.adsGunKickReducedKickBullets = jGunKick.adsGunKickReducedKickBullets; + gunKick.adsGunKickReducedKickPercent = jGunKick.adsGunKickReducedKickPercent; + gunKick.adsGunKickPitchMin = jGunKick.adsGunKickPitchMin; + gunKick.adsGunKickPitchMax = jGunKick.adsGunKickPitchMax; + gunKick.adsGunKickYawMin = jGunKick.adsGunKickYawMin; + gunKick.adsGunKickYawMax = jGunKick.adsGunKickYawMax; + gunKick.adsGunKickAccel = jGunKick.adsGunKickAccel; + gunKick.adsGunKickSpeedMax = jGunKick.adsGunKickSpeedMax; + gunKick.adsGunKickSpeedDecay = jGunKick.adsGunKickSpeedDecay; + gunKick.adsGunKickStaticDecay = jGunKick.adsGunKickStaticDecay; + + return true; + } + + static bool CreateAttViewKickFromJson(const JsonAttViewKick& jViewKick, AttViewKick& viewKick, const WeaponAttachment& attachment) + { + viewKick.hipViewKickPitchMin = jViewKick.hipViewKickPitchMin; + viewKick.hipViewKickPitchMax = jViewKick.hipViewKickPitchMax; + viewKick.hipViewKickYawMin = jViewKick.hipViewKickYawMin; + viewKick.hipViewKickYawMax = jViewKick.hipViewKickYawMax; + viewKick.hipViewKickCenterSpeed = jViewKick.hipViewKickCenterSpeed; + viewKick.adsViewKickPitchMin = jViewKick.adsViewKickPitchMin; + viewKick.adsViewKickPitchMax = jViewKick.adsViewKickPitchMax; + viewKick.adsViewKickYawMin = jViewKick.adsViewKickYawMin; + viewKick.adsViewKickYawMax = jViewKick.adsViewKickYawMax; + viewKick.adsViewKickCenterSpeed = jViewKick.adsViewKickCenterSpeed; + + return true; + } + + bool CreateAttADSOverlayFromJson(const JsonAttADSOverlay& jAdsOverlay, AttADSOverlay& adsOverlay, const WeaponAttachment& attachment) const + { + if (jAdsOverlay.shader) + { + if (!CreateMaterialFromJson(jAdsOverlay.shader.value(), adsOverlay.overlay.shader, attachment)) + return false; + } + else + adsOverlay.overlay.shader = nullptr; + + if (jAdsOverlay.shaderLowRes) + { + if (!CreateMaterialFromJson(jAdsOverlay.shaderLowRes.value(), adsOverlay.overlay.shaderLowRes, attachment)) + return false; + } + else + adsOverlay.overlay.shaderLowRes = nullptr; + + if (jAdsOverlay.shaderEMP) + { + if (!CreateMaterialFromJson(jAdsOverlay.shaderEMP.value(), adsOverlay.overlay.shaderEMP, attachment)) + return false; + } + else + adsOverlay.overlay.shaderEMP = nullptr; + + if (jAdsOverlay.shaderEMPLowRes) + { + if (!CreateMaterialFromJson(jAdsOverlay.shaderEMPLowRes.value(), adsOverlay.overlay.shaderEMPLowRes, attachment)) + return false; + } + else + adsOverlay.overlay.shaderEMPLowRes = nullptr; + + adsOverlay.overlay.reticle = jAdsOverlay.reticle; + adsOverlay.overlay.width = jAdsOverlay.width; + adsOverlay.overlay.height = jAdsOverlay.height; + adsOverlay.overlay.widthSplitscreen = jAdsOverlay.widthSplitscreen; + adsOverlay.overlay.heightSplitscreen = jAdsOverlay.heightSplitscreen; + adsOverlay.thermalScope = jAdsOverlay.thermalScope; + + return true; + } + + bool CreateAttUIFromJson(const JsonAttUI& jUi, AttUI& ui, const WeaponAttachment& attachment) const + { + if (jUi.dpadIcon) + { + if (!CreateMaterialFromJson(jUi.dpadIcon.value(), ui.dpadIcon, attachment)) + return false; + } + else + ui.dpadIcon = nullptr; + + if (jUi.ammoCounterIcon) + { + if (!CreateMaterialFromJson(jUi.ammoCounterIcon.value(), ui.ammoCounterIcon, attachment)) + return false; + } + else + ui.ammoCounterIcon = nullptr; + + ui.dpadIconRatio = jUi.dpadIconRatio; + ui.ammoCounterIconRatio = jUi.ammoCounterIconRatio; + ui.ammoCounterClip = jUi.ammoCounterClip; + + return true; + } + + bool CreateAttRumblesFromJson(const JsonAttRumbles& jRumbles, AttRumbles& rumbles, const WeaponAttachment& attachment) const + { + if (jRumbles.fireRumble) + rumbles.fireRumble = m_memory.Dup(jRumbles.fireRumble.value().c_str()); + else + rumbles.fireRumble = nullptr; + + if (jRumbles.meleeImpactRumble) + rumbles.meleeImpactRumble = m_memory.Dup(jRumbles.meleeImpactRumble.value().c_str()); + else + rumbles.meleeImpactRumble = nullptr; + + return true; + } + + bool CreateAttProjectileFromJson(const JsonAttProjectile& jProjectile, AttProjectile& projectile, const WeaponAttachment& attachment) const + { + projectile.explosionRadius = jProjectile.explosionRadius; + projectile.explosionInnerDamage = jProjectile.explosionInnerDamage; + projectile.explosionOuterDamage = jProjectile.explosionOuterDamage; + projectile.damageConeAngle = jProjectile.damageConeAngle; + projectile.projectileSpeed = jProjectile.projectileSpeed; + projectile.projectileSpeedUp = jProjectile.projectileSpeedUp; + projectile.projectileActivateDist = jProjectile.projectileActivateDist; + projectile.projectileLifetime = jProjectile.projectileLifetime; + + if (jProjectile.projectileModel) + { + if (!CreateXModelFromJson(jProjectile.projectileModel.value(), projectile.projectileModel, attachment)) + return false; + } + else + projectile.projectileModel = nullptr; + + projectile.projExplosionType = jProjectile.projExplosionType; + + if (jProjectile.projExplosionEffect) + { + if (!CreateFxFromJson(jProjectile.projExplosionEffect.value(), projectile.projExplosionEffect, attachment)) + return false; + } + else + projectile.projExplosionEffect = nullptr; + + projectile.projExplosionEffectForceNormalUp = jProjectile.projExplosionEffectForceNormalUp; + + if (jProjectile.projExplosionSound) + { + if (!CreateSoundFromJson(jProjectile.projExplosionSound.value(), projectile.projExplosionSound, attachment)) + return false; + } + else + projectile.projExplosionSound.name = nullptr; + + if (jProjectile.projDudEffect) + { + if (!CreateFxFromJson(jProjectile.projDudEffect.value(), projectile.projDudEffect, attachment)) + return false; + } + else + projectile.projDudEffect = nullptr; + + if (jProjectile.projDudSound) + { + if (!CreateSoundFromJson(jProjectile.projDudSound.value(), projectile.projDudSound, attachment)) + return false; + } + else + projectile.projDudSound.name = nullptr; + + projectile.projImpactExplode = jProjectile.projImpactExplode; + projectile.destabilizationRateTime = jProjectile.destabilizationRateTime; + projectile.destabilizationCurvatureMax = jProjectile.destabilizationCurvatureMax; + projectile.destabilizeDistance = jProjectile.destabilizeDistance; + + if (jProjectile.projTrailEffect) + { + if (!CreateFxFromJson(jProjectile.projTrailEffect.value(), projectile.projTrailEffect, attachment)) + return false; + } + else + projectile.projTrailEffect = nullptr; + + projectile.projIgnitionDelay = jProjectile.projIgnitionDelay; + + if (jProjectile.projIgnitionEffect) + { + if (!CreateFxFromJson(jProjectile.projIgnitionEffect.value(), projectile.projIgnitionEffect, attachment)) + return false; + } + else + projectile.projIgnitionEffect = nullptr; + + if (jProjectile.projIgnitionSound) + { + if (!CreateSoundFromJson(jProjectile.projIgnitionSound.value(), projectile.projIgnitionSound, attachment)) + return false; + } + else + projectile.projIgnitionSound.name = nullptr; + + return true; + } + + std::istream& m_stream; + MemoryManager& m_memory; + AssetCreationContext& m_context; + AssetRegistration& m_registration; + }; + class AttachmentLoader final : public AssetCreator { public: @@ -22,7 +643,7 @@ namespace AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override { - const auto file = m_search_path.Open(std::format("attachment/{}.json", assetName)); + const auto file = m_search_path.Open(GetJsonFileNameForAssetName(assetName)); if (!file.IsOpen()) return AssetCreationResult::NoAction(); @@ -30,7 +651,8 @@ namespace attachment->szInternalName = m_memory.Dup(assetName.c_str()); AssetRegistration registration(assetName, attachment); - if (!LoadWeaponAttachmentAsJson(*file.m_stream, *attachment, m_memory, context, registration)) + const JsonLoader loader(*file.m_stream, m_memory, context, registration); + if (!loader.Load(*attachment)) { std::cerr << std::format("Failed to load attachment \"{}\"\n", assetName); return AssetCreationResult::Failure(); @@ -45,10 +667,10 @@ namespace }; } // namespace -namespace IW5 +namespace IW5::attachment { - std::unique_ptr> CreateAttachmentLoader(MemoryManager& memory, ISearchPath& searchPath) + std::unique_ptr> CreateLoader(MemoryManager& memory, ISearchPath& searchPath) { return std::make_unique(memory, searchPath); } -} // namespace IW5 +} // namespace IW5::attachment diff --git a/src/ObjLoading/Game/IW5/Weapon/LoaderAttachmentIW5.h b/src/ObjLoading/Game/IW5/Weapon/LoaderAttachmentIW5.h index ec43ff96..cf793afa 100644 --- a/src/ObjLoading/Game/IW5/Weapon/LoaderAttachmentIW5.h +++ b/src/ObjLoading/Game/IW5/Weapon/LoaderAttachmentIW5.h @@ -7,7 +7,7 @@ #include -namespace IW5 +namespace IW5::attachment { - std::unique_ptr> CreateAttachmentLoader(MemoryManager& memory, ISearchPath& searchPath); -} // namespace IW5 + std::unique_ptr> CreateLoader(MemoryManager& memory, ISearchPath& searchPath); +} // namespace IW5::attachment diff --git a/src/ObjLoading/Game/IW5/Weapon/RawLoaderWeaponIW5.cpp b/src/ObjLoading/Game/IW5/Weapon/RawLoaderWeaponIW5.cpp index 642efa2e..2d487ae8 100644 --- a/src/ObjLoading/Game/IW5/Weapon/RawLoaderWeaponIW5.cpp +++ b/src/ObjLoading/Game/IW5/Weapon/RawLoaderWeaponIW5.cpp @@ -4,12 +4,14 @@ #include "Game/IW5/ObjConstantsIW5.h" #include "InfoString/InfoString.h" #include "InfoStringLoaderWeaponIW5.h" +#include "Weapon/WeaponCommon.h" #include #include #include using namespace IW5; +using namespace ::weapon; namespace { @@ -24,7 +26,7 @@ namespace AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override { - const auto fileName = std::format("weapons/{}", assetName); + const auto fileName = GetFileNameForAssetName(assetName); const auto file = m_search_path.Open(fileName); if (!file.IsOpen()) return AssetCreationResult::NoAction(); @@ -41,14 +43,14 @@ namespace private: ISearchPath& m_search_path; - InfoStringLoaderWeapon m_info_string_loader; + IW5::weapon::InfoStringLoader m_info_string_loader; }; } // namespace -namespace IW5 +namespace IW5::weapon { - std::unique_ptr> CreateRawWeaponLoader(MemoryManager& memory, ISearchPath& searchPath, Zone& zone) + std::unique_ptr> CreateRawLoader(MemoryManager& memory, ISearchPath& searchPath, Zone& zone) { return std::make_unique(memory, searchPath, zone); } -} // namespace IW5 +} // namespace IW5::weapon diff --git a/src/ObjLoading/Game/IW5/Weapon/RawLoaderWeaponIW5.h b/src/ObjLoading/Game/IW5/Weapon/RawLoaderWeaponIW5.h index d5df5fcf..ceba2d77 100644 --- a/src/ObjLoading/Game/IW5/Weapon/RawLoaderWeaponIW5.h +++ b/src/ObjLoading/Game/IW5/Weapon/RawLoaderWeaponIW5.h @@ -7,7 +7,7 @@ #include -namespace IW5 +namespace IW5::weapon { - std::unique_ptr> CreateRawWeaponLoader(MemoryManager& memory, ISearchPath& searchPath, Zone& zone); -} // namespace IW5 + std::unique_ptr> CreateRawLoader(MemoryManager& memory, ISearchPath& searchPath, Zone& zone); +} // namespace IW5::weapon diff --git a/test/ObjLoadingTests/Game/IW5/AssetLoaders/LoaderStringTableIW5Test.cpp b/test/ObjLoadingTests/Game/IW5/AssetLoaders/LoaderStringTableIW5Test.cpp index ab5ac734..08a7b464 100644 --- a/test/ObjLoadingTests/Game/IW5/AssetLoaders/LoaderStringTableIW5Test.cpp +++ b/test/ObjLoadingTests/Game/IW5/AssetLoaders/LoaderStringTableIW5Test.cpp @@ -26,7 +26,7 @@ namespace IgnoredAssetLookup ignoredAssetLookup; AssetCreationContext context(zone, &creatorCollection, &ignoredAssetLookup); - auto loader = CreateStringTableLoader(memory, searchPath); + auto loader = string_table::CreateLoader(memory, searchPath); auto result = loader->CreateAsset("mp/cooltable.csv", context); REQUIRE(result.HasBeenSuccessful()); diff --git a/test/ObjLoadingTests/Game/IW5/Material/LoaderMaterialIW5Test.cpp b/test/ObjLoadingTests/Game/IW5/Material/LoaderMaterialIW5Test.cpp index 5de6912b..960f119d 100644 --- a/test/ObjLoadingTests/Game/IW5/Material/LoaderMaterialIW5Test.cpp +++ b/test/ObjLoadingTests/Game/IW5/Material/LoaderMaterialIW5Test.cpp @@ -313,7 +313,7 @@ namespace GivenImage("me_metal_rusty02_col", context, memory); GivenTechset("wc_l_sm_r0c0n0s0", context, memory); - auto loader = CreateMaterialLoader(memory, searchPath); + auto loader = material::CreateLoader(memory, searchPath); auto result = loader->CreateAsset("wc/me_metal_rust_02", context); REQUIRE(result.HasBeenSuccessful());