From 2d28f423ef89b7980d0cc526f08b1435ae2f282f Mon Sep 17 00:00:00 2001 From: Future Date: Sat, 25 May 2024 17:00:18 +0200 Subject: [PATCH 1/5] feat(iw4): load leaderboard definitions from raw --- .../Game/IW4/Leaderboard/JsonLeaderboardDef.h | 8 +- .../AssetLoaders/AssetLoaderLeaderboard.cpp | 26 ++++ .../IW4/AssetLoaders/AssetLoaderLeaderboard.h | 3 + .../Leaderboard/JsonLeaderboardDefLoader.cpp | 121 ++++++++++++++++++ .../Leaderboard/JsonLeaderboardDefLoader.h | 9 ++ .../AssetDumperLeaderboardDef.cpp | 9 +- .../AssetDumpers/AssetDumperLeaderboardDef.h | 2 - .../AssetDumperLeaderboardDef.cpp | 9 +- .../AssetDumpers/AssetDumperLeaderboardDef.h | 2 - 9 files changed, 167 insertions(+), 22 deletions(-) create mode 100644 src/ObjLoading/Game/IW4/Leaderboard/JsonLeaderboardDefLoader.cpp create mode 100644 src/ObjLoading/Game/IW4/Leaderboard/JsonLeaderboardDefLoader.h diff --git a/src/ObjCommon/Game/IW4/Leaderboard/JsonLeaderboardDef.h b/src/ObjCommon/Game/IW4/Leaderboard/JsonLeaderboardDef.h index 82114665..28ee20ac 100644 --- a/src/ObjCommon/Game/IW4/Leaderboard/JsonLeaderboardDef.h +++ b/src/ObjCommon/Game/IW4/Leaderboard/JsonLeaderboardDef.h @@ -35,11 +35,11 @@ namespace IW4 public: std::string name; int colId; - int propertyId; - bool hidden; - std::string statName; + std::optional propertyId; + std::optional hidden; + std::optional statName; LbColType type; - int precision; + std::optional precision; LbAggType aggregationFunction; }; diff --git a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderLeaderboard.cpp b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderLeaderboard.cpp index e87e3042..17952169 100644 --- a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderLeaderboard.cpp +++ b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderLeaderboard.cpp @@ -1,10 +1,13 @@ #include "AssetLoaderLeaderboard.h" #include "Game/IW4/IW4.h" +#include "Game/IW4/Leaderboard/JsonLeaderboardDefLoader.h" #include "ObjLoading.h" #include "Pool/GlobalAssetPool.h" #include +#include +#include using namespace IW4; @@ -15,3 +18,26 @@ void* AssetLoaderLeaderboard::CreateEmptyAsset(const std::string& assetName, Mem leaderboard->name = memory->Dup(assetName.c_str()); return leaderboard; } + +bool AssetLoaderLeaderboard::CanLoadFromRaw() const +{ + return true; +} + +bool AssetLoaderLeaderboard::LoadFromRaw( + const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const +{ + const auto file = searchPath->Open(std::format("leaderboards/{}.json", assetName)); + if (!file.IsOpen()) + return false; + + auto* leaderboardDef = memory->Alloc(); + leaderboardDef->name = memory->Dup(assetName.c_str()); + + if (LoadLeaderboardAsJson(*file.m_stream, *leaderboardDef, memory)) + manager->AddAsset(assetName, leaderboardDef); + else + std::cerr << std::format("Failed to load leaderboard \"{}\"\n", assetName); + + return true; +} diff --git a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderLeaderboard.h b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderLeaderboard.h index aba19fa3..1d3a224d 100644 --- a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderLeaderboard.h +++ b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderLeaderboard.h @@ -10,5 +10,8 @@ namespace IW4 { public: _NODISCARD void* CreateEmptyAsset(const std::string& assetName, MemoryManager* memory) override; + _NODISCARD bool CanLoadFromRaw() const override; + bool + LoadFromRaw(const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const override; }; } // namespace IW4 diff --git a/src/ObjLoading/Game/IW4/Leaderboard/JsonLeaderboardDefLoader.cpp b/src/ObjLoading/Game/IW4/Leaderboard/JsonLeaderboardDefLoader.cpp new file mode 100644 index 00000000..624ec85a --- /dev/null +++ b/src/ObjLoading/Game/IW4/Leaderboard/JsonLeaderboardDefLoader.cpp @@ -0,0 +1,121 @@ +#include "JsonLeaderboardDefLoader.h" + +#include "Game/IW4/CommonIW4.h" +#include "Game/IW4/Leaderboard/JsonLeaderboardDef.h" + +#include +#include + +using namespace nlohmann; +using namespace IW4; + +namespace +{ + class JsonLoader + { + public: + JsonLoader(std::istream& stream, MemoryManager& memory) + : m_stream(stream), + m_memory(memory) + { + } + + bool Load(LeaderboardDef& leaderboardDef) const + { + const auto jRoot = json::parse(m_stream); + std::string type; + unsigned version; + + jRoot.at("_type").get_to(type); + jRoot.at("_version").get_to(version); + + if (type != "leaderboard" || version != 1u) + { + std::cerr << "Tried to load leaderboard \"" << leaderboardDef.name << "\" but did not find expected type leaderboard of version 1\n"; + return false; + } + + const auto jLeaderboard = jRoot.get(); + return CreateLeaderboardFromJson(jLeaderboard, leaderboardDef); + } + + private: + bool CreateColumnDefFromJson(const JsonColumnDef& jColumn, LbColumnDef& lbColumnDef, LeaderboardDef& leaderboardDef) const + { + lbColumnDef.name = m_memory.Dup(jColumn.name.c_str()); + + if (jColumn.propertyId) + lbColumnDef.propertyId = jColumn.propertyId.value(); + else + lbColumnDef.propertyId = 0; + + if (jColumn.hidden) + lbColumnDef.hidden = jColumn.hidden.value(); + else + lbColumnDef.hidden = false; + + if (jColumn.statName) + lbColumnDef.statName = m_memory.Dup(jColumn.statName->c_str()); + else + lbColumnDef.statName = nullptr; + + lbColumnDef.type = jColumn.type; + + if (jColumn.precision) + lbColumnDef.precision = jColumn.precision.value(); + else + lbColumnDef.precision = 0; + + lbColumnDef.agg = jColumn.aggregationFunction; + + return true; + } + + bool CreateLeaderboardFromJson(const JsonLeaderboardDef& jLeaderboardDef, LeaderboardDef& leaderboardDef) const + { + leaderboardDef.id = jLeaderboardDef.id; + + if (jLeaderboardDef.xpColId) + leaderboardDef.xpColId = jLeaderboardDef.xpColId.value(); + else + leaderboardDef.xpColId = -1; + + if (jLeaderboardDef.prestigeColId) + leaderboardDef.prestigeColId = jLeaderboardDef.prestigeColId.value(); + else + leaderboardDef.prestigeColId = -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; + } + + return true; + } + + std::istream& m_stream; + MemoryManager& m_memory; + }; +} // namespace + +namespace IW4 +{ + bool LoadLeaderboardAsJson(std::istream& stream, LeaderboardDef& leaderboard, MemoryManager* memory) + { + const JsonLoader loader(stream, *memory); + + return loader.Load(leaderboard); + } +} // namespace IW4 diff --git a/src/ObjLoading/Game/IW4/Leaderboard/JsonLeaderboardDefLoader.h b/src/ObjLoading/Game/IW4/Leaderboard/JsonLeaderboardDefLoader.h new file mode 100644 index 00000000..04646104 --- /dev/null +++ b/src/ObjLoading/Game/IW4/Leaderboard/JsonLeaderboardDefLoader.h @@ -0,0 +1,9 @@ +#pragma once + +#include "Game/IW4/IW4.h" +#include "Utils/MemoryManager.h" + +namespace IW4 +{ + bool LoadLeaderboardAsJson(std::istream& stream, LeaderboardDef& leaderboard, MemoryManager* memory); +} // namespace IW4 diff --git a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperLeaderboardDef.cpp b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperLeaderboardDef.cpp index 8e2f5ee7..a761b471 100644 --- a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperLeaderboardDef.cpp +++ b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperLeaderboardDef.cpp @@ -7,12 +7,6 @@ using namespace IW4; -std::string AssetDumperLeaderboardDef::GetFileNameForAsset(const std::string& assetName) -{ - - return std::format("leaderboards/{}.json", assetName); -} - bool AssetDumperLeaderboardDef::ShouldDump(XAssetInfo* asset) { return true; @@ -20,7 +14,8 @@ bool AssetDumperLeaderboardDef::ShouldDump(XAssetInfo* asset) void AssetDumperLeaderboardDef::DumpAsset(AssetDumpingContext& context, XAssetInfo* asset) { - const auto assetFile = context.OpenAssetFile(GetFileNameForAsset(asset->m_name)); + const auto assetName = asset->m_name; + const auto assetFile = context.OpenAssetFile(std::format("leaderboards/{}.json", assetName)); if (!assetFile) return; diff --git a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperLeaderboardDef.h b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperLeaderboardDef.h index 00b9c2c0..c8a344bf 100644 --- a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperLeaderboardDef.h +++ b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperLeaderboardDef.h @@ -7,8 +7,6 @@ namespace IW4 { class AssetDumperLeaderboardDef final : public AbstractAssetDumper { - static std::string GetFileNameForAsset(const std::string& assetName); - protected: _NODISCARD bool ShouldDump(XAssetInfo* asset) override; void DumpAsset(AssetDumpingContext& context, XAssetInfo* asset) override; diff --git a/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperLeaderboardDef.cpp b/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperLeaderboardDef.cpp index 6587432b..9b1804f2 100644 --- a/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperLeaderboardDef.cpp +++ b/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperLeaderboardDef.cpp @@ -7,12 +7,6 @@ using namespace IW5; -std::string AssetDumperLeaderboardDef::GetFileNameForAsset(const std::string& assetName) -{ - - return std::format("leaderboards/{}.json", assetName); -} - bool AssetDumperLeaderboardDef::ShouldDump(XAssetInfo* asset) { return true; @@ -20,7 +14,8 @@ bool AssetDumperLeaderboardDef::ShouldDump(XAssetInfo* asset) void AssetDumperLeaderboardDef::DumpAsset(AssetDumpingContext& context, XAssetInfo* asset) { - const auto assetFile = context.OpenAssetFile(GetFileNameForAsset(asset->m_name)); + const auto assetName = asset->m_name; + const auto assetFile = context.OpenAssetFile(std::format("leaderboards/{}.json", assetName)); if (!assetFile) return; diff --git a/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperLeaderboardDef.h b/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperLeaderboardDef.h index fad9cb5e..934ad940 100644 --- a/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperLeaderboardDef.h +++ b/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperLeaderboardDef.h @@ -7,8 +7,6 @@ namespace IW5 { class AssetDumperLeaderboardDef final : public AbstractAssetDumper { - static std::string GetFileNameForAsset(const std::string& assetName); - protected: _NODISCARD bool ShouldDump(XAssetInfo* asset) override; void DumpAsset(AssetDumpingContext& context, XAssetInfo* asset) override; From 960a606a4bd7c846a4931cb28849d5da4071529a Mon Sep 17 00:00:00 2001 From: Diamante Date: Sun, 26 May 2024 11:40:26 +0200 Subject: [PATCH 2/5] maint: use std::format here as well --- .../Game/IW4/Leaderboard/JsonLeaderboardDefLoader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ObjLoading/Game/IW4/Leaderboard/JsonLeaderboardDefLoader.cpp b/src/ObjLoading/Game/IW4/Leaderboard/JsonLeaderboardDefLoader.cpp index 624ec85a..431001a2 100644 --- a/src/ObjLoading/Game/IW4/Leaderboard/JsonLeaderboardDefLoader.cpp +++ b/src/ObjLoading/Game/IW4/Leaderboard/JsonLeaderboardDefLoader.cpp @@ -31,7 +31,7 @@ namespace if (type != "leaderboard" || version != 1u) { - std::cerr << "Tried to load leaderboard \"" << leaderboardDef.name << "\" but did not find expected type leaderboard of version 1\n"; + std::cerr << std::format("Tried to load leaderboard \"{}\" but did not find expected type leaderboard of version 1\n", leaderboardDef.name); return false; } From 601494e51502b3a61b45c97a46bb1b0bc49ba3c7 Mon Sep 17 00:00:00 2001 From: Diamante Date: Sun, 26 May 2024 11:52:31 +0200 Subject: [PATCH 3/5] fix compilation --- src/ObjLoading/Game/IW4/Leaderboard/JsonLeaderboardDefLoader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ObjLoading/Game/IW4/Leaderboard/JsonLeaderboardDefLoader.cpp b/src/ObjLoading/Game/IW4/Leaderboard/JsonLeaderboardDefLoader.cpp index 431001a2..3a90565d 100644 --- a/src/ObjLoading/Game/IW4/Leaderboard/JsonLeaderboardDefLoader.cpp +++ b/src/ObjLoading/Game/IW4/Leaderboard/JsonLeaderboardDefLoader.cpp @@ -3,6 +3,7 @@ #include "Game/IW4/CommonIW4.h" #include "Game/IW4/Leaderboard/JsonLeaderboardDef.h" +#include #include #include From b76bdabc758b62992ad826cd1b69d8ba8587d571 Mon Sep 17 00:00:00 2001 From: Jan Date: Sat, 1 Jun 2024 13:12:42 +0200 Subject: [PATCH 4/5] chore: use std::optional value_or --- .../Leaderboard/JsonLeaderboardDefLoader.cpp | 28 ++++--------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/src/ObjLoading/Game/IW4/Leaderboard/JsonLeaderboardDefLoader.cpp b/src/ObjLoading/Game/IW4/Leaderboard/JsonLeaderboardDefLoader.cpp index 3a90565d..12ddbe8e 100644 --- a/src/ObjLoading/Game/IW4/Leaderboard/JsonLeaderboardDefLoader.cpp +++ b/src/ObjLoading/Game/IW4/Leaderboard/JsonLeaderboardDefLoader.cpp @@ -45,15 +45,8 @@ namespace { lbColumnDef.name = m_memory.Dup(jColumn.name.c_str()); - if (jColumn.propertyId) - lbColumnDef.propertyId = jColumn.propertyId.value(); - else - lbColumnDef.propertyId = 0; - - if (jColumn.hidden) - lbColumnDef.hidden = jColumn.hidden.value(); - else - lbColumnDef.hidden = false; + 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()); @@ -62,11 +55,7 @@ namespace lbColumnDef.type = jColumn.type; - if (jColumn.precision) - lbColumnDef.precision = jColumn.precision.value(); - else - lbColumnDef.precision = 0; - + lbColumnDef.precision = jColumn.precision.value_or(0); lbColumnDef.agg = jColumn.aggregationFunction; return true; @@ -76,15 +65,8 @@ namespace { leaderboardDef.id = jLeaderboardDef.id; - if (jLeaderboardDef.xpColId) - leaderboardDef.xpColId = jLeaderboardDef.xpColId.value(); - else - leaderboardDef.xpColId = -1; - - if (jLeaderboardDef.prestigeColId) - leaderboardDef.prestigeColId = jLeaderboardDef.prestigeColId.value(); - else - leaderboardDef.prestigeColId = -1; + leaderboardDef.xpColId = jLeaderboardDef.xpColId.value_or(-1); + leaderboardDef.prestigeColId = jLeaderboardDef.prestigeColId.value_or(-1); if (!jLeaderboardDef.columns.empty()) { From 02e39a036112a9d24199706e9daed01ed6a41f22 Mon Sep 17 00:00:00 2001 From: Jan Date: Sat, 1 Jun 2024 13:25:04 +0200 Subject: [PATCH 5/5] fix: not setting column ids for iw4 leaderboards --- src/ObjLoading/Game/IW4/Leaderboard/JsonLeaderboardDefLoader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ObjLoading/Game/IW4/Leaderboard/JsonLeaderboardDefLoader.cpp b/src/ObjLoading/Game/IW4/Leaderboard/JsonLeaderboardDefLoader.cpp index 12ddbe8e..4133b5eb 100644 --- a/src/ObjLoading/Game/IW4/Leaderboard/JsonLeaderboardDefLoader.cpp +++ b/src/ObjLoading/Game/IW4/Leaderboard/JsonLeaderboardDefLoader.cpp @@ -45,6 +45,7 @@ namespace { 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);