diff --git a/docs/SupportedAssetTypes.md b/docs/SupportedAssetTypes.md index deeca7c4..4d69498e 100644 --- a/docs/SupportedAssetTypes.md +++ b/docs/SupportedAssetTypes.md @@ -194,7 +194,7 @@ The following section specify which assets are supported to be dumped to disk (u | FxImpactTable | ❌ | ❌ | | | RawFile | ✅ | ✅ | | | StringTable | ✅ | ✅ | | -| LeaderboardDef | ❌ | ❌ | | +| LeaderboardDef | ✅ | ❌ | | | XGlobals | ❌ | ❌ | | | ddlRoot_t | ❌ | ❌ | | | Glasses | ❌ | ❌ | | diff --git a/src/Common/Game/T6/T6_Assets.h b/src/Common/Game/T6/T6_Assets.h index 581745fb..3cdf952c 100644 --- a/src/Common/Game/T6/T6_Assets.h +++ b/src/Common/Game/T6/T6_Assets.h @@ -1949,6 +1949,19 @@ namespace T6 LBUPDATE_TYPE_COUNT = 0x3, }; + enum LbTrackType + { + TRK_ALLTIME = 0x0, + TRK_WEEKLY = 0x1, + TRK_MONTHLY = 0x2, + TRK_PRESTIGE_ALLTIME = 0x3, + TRK_PRESTIGE_WEEKLY = 0x4, + TRK_PRESTIGE_MONTHLY = 0x5, + TRK_DAILY = 0x6, + TRK_PRESTIGE_DAILY = 0x7, + TRK_COUNT + }; + struct LeaderboardDef { const char* name; diff --git a/src/ObjCommon/Game/T6/Json/JsonLeaderboardDef.h b/src/ObjCommon/Game/T6/Json/JsonLeaderboardDef.h new file mode 100644 index 00000000..83457795 --- /dev/null +++ b/src/ObjCommon/Game/T6/Json/JsonLeaderboardDef.h @@ -0,0 +1,84 @@ +#pragma once + +#include "Game/T6/T6.h" + +#include "Json/JsonCommon.h" +#include "Json/JsonExtension.h" +#include +#include +#include +#include +#include + +namespace T6 +{ + NLOHMANN_JSON_SERIALIZE_ENUM(LbColType, + { + {LBCOL_TYPE_NUMBER, "number" }, + {LBCOL_TYPE_TIME, "time" }, + {LBCOL_TYPE_LEVELXP, "levelxp" }, + {LBCOL_TYPE_PRESTIGE, "prestige" }, + {LBCOL_TYPE_BIGNUMBER, "bignumber"}, + {LBCOL_TYPE_PERCENT, "percent" }, + {LBCOL_TYPE_TIME_FULL, "time_full"}, + }); + + NLOHMANN_JSON_SERIALIZE_ENUM(LbAggType, + { + {LBAGG_TYPE_MIN, "min" }, + {LBAGG_TYPE_MAX, "max" }, + {LBAGG_TYPE_ADD, "add" }, + {LBAGG_TYPE_REPLACE, "replace"}, + }); + + NLOHMANN_JSON_SERIALIZE_ENUM(LbUpdateType, + { + {LBUPDATE_TYPE_NORMAL, "normal" }, + {LBUPDATE_TYPE_RANK, "rank" }, + {LBUPDATE_TYPE_COMBINE, "combine"}, + }); + + NLOHMANN_JSON_SERIALIZE_ENUM(LbTrackType, + { + {TRK_ALLTIME, "ALLTIME" }, + {TRK_WEEKLY, "WEEKLY" }, + {TRK_MONTHLY, "MONTHLY" }, + {TRK_PRESTIGE_ALLTIME, "PRESTIGE_ALLTIME"}, + {TRK_PRESTIGE_WEEKLY, "PRESTIGE_WEEKLY" }, + {TRK_PRESTIGE_MONTHLY, "PRESTIGE_MONTHLY"}, + {TRK_DAILY, "DAILY" }, + {TRK_PRESTIGE_DAILY, "PRESTIGE_DAILY" }, + }); + + class JsonColumnDef + { + public: + std::string name; + int colId; + int dwColIndex; + bool hidden; + std::string statName; + LbColType type; + int precision; + LbAggType agg; + std::string localization; + int uiCalColX; + int uiCalColY; + }; + + NLOHMANN_DEFINE_TYPE_EXTENSION(JsonColumnDef, name, colId, dwColIndex, hidden, statName, type, precision, agg, localization, uiCalColX, uiCalColY); + + class JsonLeaderboardDef + { + public: + unsigned int id; + int dwColumnCount; + std::optional xpColId; + std::optional prestigeColId; + std::vector columns; + LbUpdateType updateType; + std::vector trackTypes; + }; + + NLOHMANN_DEFINE_TYPE_EXTENSION(JsonLeaderboardDef, id, dwColumnCount, xpColId, prestigeColId, columns, updateType, trackTypes); +} // namespace T6 diff --git a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperLeaderboardDef.cpp b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperLeaderboardDef.cpp new file mode 100644 index 00000000..75a08a41 --- /dev/null +++ b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperLeaderboardDef.cpp @@ -0,0 +1,29 @@ +#include "AssetDumperLeaderboardDef.h" + +#include "Game/T6/LeaderboardDef/JsonLeaderboardDefWriter.h" + +#include +#include + +using namespace T6; + +std::string AssetDumperLeaderboardDef::GetFileNameForAsset(const std::string& assetName) +{ + + return std::format("leaderboards/{}.json", assetName); +} + +bool AssetDumperLeaderboardDef::ShouldDump(XAssetInfo* asset) +{ + return true; +} + +void AssetDumperLeaderboardDef::DumpAsset(AssetDumpingContext& context, XAssetInfo* asset) +{ + const auto assetFile = context.OpenAssetFile(GetFileNameForAsset(asset->m_name)); + + if (!assetFile) + return; + + DumpLeaderboardDefAsJson(*assetFile, asset->Asset()); +} diff --git a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperLeaderboardDef.h b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperLeaderboardDef.h new file mode 100644 index 00000000..057d4252 --- /dev/null +++ b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperLeaderboardDef.h @@ -0,0 +1,16 @@ +#pragma once + +#include "Dumping/AbstractAssetDumper.h" +#include "Game/T6/T6.h" + +namespace T6 +{ + 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; + }; +} // namespace T6 diff --git a/src/ObjWriting/Game/T6/LeaderboardDef/JsonLeaderboardDefWriter.cpp b/src/ObjWriting/Game/T6/LeaderboardDef/JsonLeaderboardDefWriter.cpp new file mode 100644 index 00000000..0ec0dcee --- /dev/null +++ b/src/ObjWriting/Game/T6/LeaderboardDef/JsonLeaderboardDefWriter.cpp @@ -0,0 +1,84 @@ +#include "JsonLeaderboardDefWriter.h" + +#include "Game/T6/CommonT6.h" +#include "Game/T6/Json/JsonLeaderboardDef.h" + +#include +#include + +using namespace nlohmann; +using namespace T6; + +namespace +{ + class JsonDumper + { + public: + explicit JsonDumper(std::ostream& stream) + : m_stream(stream) + { + } + + void Dump(const LeaderboardDef* leaderboardDef) + { + JsonLeaderboardDef jsonLeaderboardDef; + CreateJsonLeaderboardDef(jsonLeaderboardDef, *leaderboardDef); + + json jRoot = jsonLeaderboardDef; + + jRoot["_type"] = "leaderboard"; + jRoot["_version"] = 1; + + m_stream << std::setw(4) << jRoot << "\n"; + } + + private: + static void CreateJsonColumnDef(JsonColumnDef& jColumnDef, const LbColumnDef& lbColumnDef) + { + jColumnDef.name = lbColumnDef.name; + jColumnDef.colId = lbColumnDef.colId; + jColumnDef.dwColIndex = lbColumnDef.dwColIndex; + jColumnDef.hidden = lbColumnDef.hidden; + jColumnDef.statName = lbColumnDef.statName; + jColumnDef.type = lbColumnDef.type; + jColumnDef.precision = lbColumnDef.precision; + jColumnDef.agg = lbColumnDef.agg; + jColumnDef.localization = lbColumnDef.localization; + jColumnDef.uiCalColX = lbColumnDef.uiCalColX; + jColumnDef.uiCalColY = lbColumnDef.uiCalColY; + } + + static void CreateJsonLeaderboardDef(JsonLeaderboardDef& jLeaderboardDef, const LeaderboardDef& leaderboardDef) + { + jLeaderboardDef.id = leaderboardDef.id; + jLeaderboardDef.dwColumnCount = leaderboardDef.dwColumnCount; + jLeaderboardDef.xpColId = (leaderboardDef.xpColId < 0) ? std::nullopt : std::make_optional(leaderboardDef.xpColId); + jLeaderboardDef.prestigeColId = (leaderboardDef.prestigeColId < 0) ? std::nullopt : std::make_optional(leaderboardDef.prestigeColId); + + jLeaderboardDef.columns.resize(leaderboardDef.columnCount); + for (auto i = 0; i < leaderboardDef.columnCount; ++i) + CreateJsonColumnDef(jLeaderboardDef.columns[i], leaderboardDef.columns[i]); + + jLeaderboardDef.updateType = leaderboardDef.updateType; + + for (auto i = 0; i < LbTrackType::TRK_COUNT; ++i) + { + if ((leaderboardDef.trackTypes & (1 << i)) != 0) + { + jLeaderboardDef.trackTypes.emplace_back(static_cast(i)); + } + } + } + + std::ostream& m_stream; + }; +} // namespace + +namespace T6 +{ + void DumpLeaderboardDefAsJson(std::ostream& stream, const LeaderboardDef* leaderboardDef) + { + JsonDumper dumper(stream); + dumper.Dump(leaderboardDef); + } +} // namespace T6 diff --git a/src/ObjWriting/Game/T6/LeaderboardDef/JsonLeaderboardDefWriter.h b/src/ObjWriting/Game/T6/LeaderboardDef/JsonLeaderboardDefWriter.h new file mode 100644 index 00000000..cdc31389 --- /dev/null +++ b/src/ObjWriting/Game/T6/LeaderboardDef/JsonLeaderboardDefWriter.h @@ -0,0 +1,11 @@ +#pragma once + +#include "Dumping/AssetDumpingContext.h" +#include "Game/T6/T6.h" + +#include + +namespace T6 +{ + void DumpLeaderboardDefAsJson(std::ostream& stream, const LeaderboardDef* leaderboardDef); +} // namespace T6 diff --git a/src/ObjWriting/Game/T6/ZoneDumperT6.cpp b/src/ObjWriting/Game/T6/ZoneDumperT6.cpp index f781a54d..9fe2ba76 100644 --- a/src/ObjWriting/Game/T6/ZoneDumperT6.cpp +++ b/src/ObjWriting/Game/T6/ZoneDumperT6.cpp @@ -2,6 +2,7 @@ #include "AssetDumpers/AssetDumperFontIcon.h" #include "AssetDumpers/AssetDumperGfxImage.h" +#include "AssetDumpers/AssetDumperLeaderboardDef.h" #include "AssetDumpers/AssetDumperLocalizeEntry.h" #include "AssetDumpers/AssetDumperMaterial.h" #include "AssetDumpers/AssetDumperPhysConstraints.h" @@ -75,7 +76,7 @@ bool ZoneDumper::DumpZone(AssetDumpingContext& context) const // DUMP_ASSET_POOL(AssetDumperFxImpactTable, m_fx_impact_table, ASSET_TYPE_IMPACT_FX) DUMP_ASSET_POOL(AssetDumperRawFile, m_raw_file, ASSET_TYPE_RAWFILE) DUMP_ASSET_POOL(AssetDumperStringTable, m_string_table, ASSET_TYPE_STRINGTABLE) - // DUMP_ASSET_POOL(AssetDumperLeaderboardDef, m_leaderboard, ASSET_TYPE_LEADERBOARD) + DUMP_ASSET_POOL(AssetDumperLeaderboardDef, m_leaderboard, ASSET_TYPE_LEADERBOARD) // DUMP_ASSET_POOL(AssetDumperXGlobals, m_xglobals, ASSET_TYPE_XGLOBALS) // DUMP_ASSET_POOL(AssetDumperDDLRoot, m_ddl, ASSET_TYPE_DDL) // DUMP_ASSET_POOL(AssetDumperGlasses, m_glasses, ASSET_TYPE_GLASSES)