From 9f4727789a318954acdd9407e8632c9785695de5 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Tue, 22 Jul 2025 22:48:48 +0100 Subject: [PATCH 1/3] chore: dump font icons as json instead of csv --- .../Game/T6/FontIcon/FontIconCommonT6.cpp | 23 ++ .../Game/T6/FontIcon/FontIconCommonT6.h | 8 + .../Game/T6/FontIcon/JsonFontIconT6.h | 33 +++ .../T6/AssetDumpers/AssetDumperFontIcon.cpp | 264 ------------------ .../Game/T6/FontIcon/DumperFontIconCsvT6.cpp | 146 ++++++++++ .../Game/T6/FontIcon/DumperFontIconCsvT6.h | 9 + .../Game/T6/FontIcon/DumperFontIconJsonT6.cpp | 90 ++++++ .../Game/T6/FontIcon/DumperFontIconJsonT6.h | 9 + .../Game/T6/FontIcon/DumperFontIconT6.cpp | 22 ++ .../DumperFontIconT6.h} | 0 .../T6/FontIcon/KnownFontIconAliasesT6.cpp | 125 +++++++++ .../Game/T6/FontIcon/KnownFontIconAliasesT6.h | 17 ++ src/ObjWriting/Game/T6/ObjWriterT6.cpp | 2 +- 13 files changed, 483 insertions(+), 265 deletions(-) create mode 100644 src/ObjCommon/Game/T6/FontIcon/FontIconCommonT6.cpp create mode 100644 src/ObjCommon/Game/T6/FontIcon/FontIconCommonT6.h create mode 100644 src/ObjCommon/Game/T6/FontIcon/JsonFontIconT6.h delete mode 100644 src/ObjWriting/Game/T6/AssetDumpers/AssetDumperFontIcon.cpp create mode 100644 src/ObjWriting/Game/T6/FontIcon/DumperFontIconCsvT6.cpp create mode 100644 src/ObjWriting/Game/T6/FontIcon/DumperFontIconCsvT6.h create mode 100644 src/ObjWriting/Game/T6/FontIcon/DumperFontIconJsonT6.cpp create mode 100644 src/ObjWriting/Game/T6/FontIcon/DumperFontIconJsonT6.h create mode 100644 src/ObjWriting/Game/T6/FontIcon/DumperFontIconT6.cpp rename src/ObjWriting/Game/T6/{AssetDumpers/AssetDumperFontIcon.h => FontIcon/DumperFontIconT6.h} (100%) create mode 100644 src/ObjWriting/Game/T6/FontIcon/KnownFontIconAliasesT6.cpp create mode 100644 src/ObjWriting/Game/T6/FontIcon/KnownFontIconAliasesT6.h diff --git a/src/ObjCommon/Game/T6/FontIcon/FontIconCommonT6.cpp b/src/ObjCommon/Game/T6/FontIcon/FontIconCommonT6.cpp new file mode 100644 index 00000000..5ae57d48 --- /dev/null +++ b/src/ObjCommon/Game/T6/FontIcon/FontIconCommonT6.cpp @@ -0,0 +1,23 @@ +#include "FontIconCommonT6.h" + +#include "Utils/StringUtils.h" + +#include +namespace fs = std::filesystem; + +namespace T6::font_icon +{ + std::string GetJsonFileNameForAssetName(const std::string& assetName) + { + std::string originalFileName(assetName); + utils::MakeStringLowerCase(originalFileName); + if (originalFileName.ends_with(".csv")) + { + fs::path p(assetName); + p.replace_extension(".json"); + return p.string(); + } + + return assetName; + } +} // namespace T6::font_icon diff --git a/src/ObjCommon/Game/T6/FontIcon/FontIconCommonT6.h b/src/ObjCommon/Game/T6/FontIcon/FontIconCommonT6.h new file mode 100644 index 00000000..bcce4518 --- /dev/null +++ b/src/ObjCommon/Game/T6/FontIcon/FontIconCommonT6.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +namespace T6::font_icon +{ + std::string GetJsonFileNameForAssetName(const std::string& assetName); +} diff --git a/src/ObjCommon/Game/T6/FontIcon/JsonFontIconT6.h b/src/ObjCommon/Game/T6/FontIcon/JsonFontIconT6.h new file mode 100644 index 00000000..583f5ac9 --- /dev/null +++ b/src/ObjCommon/Game/T6/FontIcon/JsonFontIconT6.h @@ -0,0 +1,33 @@ +#pragma once + +#include "Json/JsonCommon.h" +#include "Json/JsonExtension.h" +#include +#include +#include +#include +#include + +namespace T6 +{ + class JsonFontIconEntry + { + public: + std::string name; + std::string material; + unsigned size; + std::optional scale; + std::vector aliases; + std::optional> aliasHashes; + }; + + NLOHMANN_DEFINE_TYPE_EXTENSION(JsonFontIconEntry, name, material, size, scale, aliases, aliasHashes); + + class JsonFontIcon + { + public: + std::vector entries; + }; + + NLOHMANN_DEFINE_TYPE_EXTENSION(JsonFontIcon, entries); +} // namespace T6 diff --git a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperFontIcon.cpp b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperFontIcon.cpp deleted file mode 100644 index 20e375f7..00000000 --- a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperFontIcon.cpp +++ /dev/null @@ -1,264 +0,0 @@ -#include "AssetDumperFontIcon.h" - -#include "Csv/CsvStream.h" -#include "Game/T6/CommonT6.h" - -#include - -using namespace T6; - -class AssetDumperFontIconInternal -{ - class KnownAlias - { - public: - std::string m_name; - int m_hash; - - explicit KnownAlias(std::string aliasName) - : m_name(std::move(aliasName)) - { - m_hash = Common::Com_HashString(m_name.c_str(), 0); - } - }; - - inline static const std::string TYPE_ICON = "icon"; - inline static const std::string ICON_HEADERS[]{ - "# index", - "# type", - "# name", - "# material", - "# size", - "# xScale", - "# yScale", - }; - - inline static const std::string TYPE_ALIAS = "alias"; - inline static const std::string ALIAS_HEADERS[]{ - "# index", - "# type", - "# alias", - "# button", - }; - - inline static const KnownAlias KNOWN_ALIASES[]{ - KnownAlias("BUTTON_ADS"), - KnownAlias("BUTTON_CAC_NEXT"), - KnownAlias("BUTTON_CAC_PREV"), - KnownAlias("BUTTON_CANCEL"), - KnownAlias("BUTTON_CAROUSEL_STICK"), - KnownAlias("BUTTON_CREATE"), - KnownAlias("BUTTON_CYCLE_LEFT"), - KnownAlias("BUTTON_CYCLE_LEFT_ACTIVE"), - KnownAlias("BUTTON_CYCLE_RIGHT"), - KnownAlias("BUTTON_CYCLE_RIGHT_ACTIVE"), - KnownAlias("BUTTON_DELETE"), - KnownAlias("BUTTON_EDIT"), - KnownAlias("BUTTON_EMBLEM_BACKWARD"), - KnownAlias("BUTTON_EMBLEM_FLIP"), - KnownAlias("BUTTON_EMBLEM_FORWARD"), - KnownAlias("BUTTON_EMBLEM_FORWARD_BACKWARD"), - KnownAlias("BUTTON_EMBLEM_MOVE"), - KnownAlias("BUTTON_EMBLEM_OUTLINE"), - KnownAlias("BUTTON_EMBLEM_PALETTE_CYCLE"), - KnownAlias("BUTTON_EMBLEM_PALETTE_NEXT"), - KnownAlias("BUTTON_EMBLEM_PALETTE_PREV"), - KnownAlias("BUTTON_EMBLEM_RESET"), - KnownAlias("BUTTON_EMBLEM_ROTATE_LEFT"), - KnownAlias("BUTTON_EMBLEM_ROTATE_RIGHT"), - KnownAlias("BUTTON_EMBLEM_SCALE"), - KnownAlias("BUTTON_FIRE"), - KnownAlias("BUTTON_FRIENDSLIST"), - KnownAlias("BUTTON_INTERACT"), - KnownAlias("BUTTON_LOOKSTICK"), - KnownAlias("BUTTON_LOOK"), - KnownAlias("BUTTON_LUI_ALT1"), - KnownAlias("BUTTON_LUI_ALT2"), - KnownAlias("BUTTON_LUI_DPAD_ALL"), - KnownAlias("BUTTON_LUI_DPAD_D"), - KnownAlias("BUTTON_LUI_DPAD_L"), - KnownAlias("BUTTON_LUI_DPAD_RL"), - KnownAlias("BUTTON_LUI_DPAD_R"), - KnownAlias("BUTTON_LUI_DPAD_UD"), - KnownAlias("BUTTON_LUI_DPAD_U"), - KnownAlias("BUTTON_LUI_LEFT_STICK_UP"), - KnownAlias("BUTTON_LUI_LEFT_TRIGGER"), - KnownAlias("BUTTON_LUI_PRIMARY"), - KnownAlias("BUTTON_LUI_RIGHT_STICK"), - KnownAlias("BUTTON_LUI_RIGHT_TRIGGER"), - KnownAlias("BUTTON_LUI_SECONDARY"), - KnownAlias("BUTTON_LUI_SELECT"), - KnownAlias("BUTTON_LUI_SHOULDERL"), - KnownAlias("BUTTON_LUI_SHOULDERR"), - KnownAlias("BUTTON_LUI_START"), - KnownAlias("BUTTON_MOUSE_CLICK"), - KnownAlias("BUTTON_MOUSE_CLICK_ACTIVE"), - KnownAlias("BUTTON_MOUSE_EDIT"), - KnownAlias("BUTTON_MOUSE_EDIT_ACTIVE"), - KnownAlias("BUTTON_MOUSE_LEFT"), - KnownAlias("BUTTON_MOUSE_MIDDLE"), - KnownAlias("BUTTON_MOUSE_RIGHT"), - KnownAlias("BUTTON_MOVESTICK"), - KnownAlias("BUTTON_MOVE"), - KnownAlias("BUTTON_MP_CANCELCOMMAND"), - KnownAlias("BUTTON_MP_CHANGESETTINGS"), - KnownAlias("BUTTON_MP_GAMERCARD"), - KnownAlias("BUTTON_MP_GAMERREVIEW"), - KnownAlias("BUTTON_MP_JOINGAME"), - KnownAlias("BUTTON_MP_KICKPLAYER"), - KnownAlias("BUTTON_MP_LEAVEGAME"), - KnownAlias("BUTTON_MP_LOBBY_GAMERCARD"), - KnownAlias("BUTTON_MP_NOTREADY"), - KnownAlias("BUTTON_MP_PGDOWN"), - KnownAlias("BUTTON_MP_PGUP"), - KnownAlias("BUTTON_MP_READY"), - KnownAlias("BUTTON_MP_REFRESH"), - KnownAlias("BUTTON_MP_SCOREBOARD"), - KnownAlias("BUTTON_MP_SIGNIN"), - KnownAlias("BUTTON_MP_SPECNEXT"), - KnownAlias("BUTTON_MP_SPECPREV"), - KnownAlias("BUTTON_MP_STARTGAME"), - KnownAlias("BUTTON_MP_TOGGLECHASECAM"), - KnownAlias("BUTTON_MP_TOGGLEVIEW"), - KnownAlias("BUTTON_NO"), - KnownAlias("BUTTON_RECORD_VIEW_NEXT"), - KnownAlias("BUTTON_RECORD_VIEW_PREV"), - KnownAlias("BUTTON_SELECTCHOICE"), - KnownAlias("BUTTON_SP_TOGGLEMENU"), - KnownAlias("BUTTON_YES"), - KnownAlias("CP"), - KnownAlias("FONT_CAPITAL_I"), - KnownAlias("FONT_NUMBER_ZERO"), - KnownAlias("KEY_DOWN_ARROW"), - KnownAlias("KEY_LEFT_ARROW"), - KnownAlias("KEY_RIGHT_ARROW"), - KnownAlias("KEY_UP_ARROW"), - KnownAlias("MOUSE_WHEEL_DOWN"), - KnownAlias("MOUSE_WHEEL_UP"), - KnownAlias("Remote_LStick"), - }; - - CsvOutputStream m_csv; - - static FontIconEntry* FindEntryByHash(const FontIcon* fontIcon, const int hash) - { - auto lowerBound = 0u; - auto upperBound = fontIcon->numEntries; - - while (true) - { - const auto entryIndex = (lowerBound + upperBound) / 2u; - auto* entry = &fontIcon->fontIconEntry[entryIndex]; - - if (entry->fontIconName.hash == hash) - return entry; - - if (lowerBound == upperBound) - return nullptr; - - if (entry->fontIconName.hash < hash) - lowerBound = entryIndex + 1u; - else - upperBound = entryIndex - 1u; - } - } - - static const KnownAlias* FindKnownAliasByHash(const int hash) - { - for (const auto& i : KNOWN_ALIASES) - { - if (i.m_hash == hash) - return &i; - } - - return nullptr; - } - - void WriteFontIconEntries(const FontIcon* fontIcon) - { - for (const auto& header : ICON_HEADERS) - m_csv.WriteColumn(header); - m_csv.NextRow(); - - for (auto iconIndex = 0u; iconIndex < fontIcon->numEntries; iconIndex++) - { - const auto* entry = &fontIcon->fontIconEntry[iconIndex]; - m_csv.WriteColumn(std::to_string(iconIndex)); - m_csv.WriteColumn(TYPE_ICON); - - if (entry->fontIconName.string) - m_csv.WriteColumn(entry->fontIconName.string); - else - m_csv.WriteColumn(""); - - if (entry->fontIconMaterialHandle && entry->fontIconMaterialHandle->info.name) - m_csv.WriteColumn(entry->fontIconMaterialHandle->info.name); - else - m_csv.WriteColumn(""); - - m_csv.WriteColumn(std::to_string(entry->fontIconSize)); - m_csv.WriteColumn(std::to_string(entry->xScale)); - m_csv.WriteColumn(std::to_string(entry->yScale)); - - m_csv.NextRow(); - } - } - - void WriteFontIconAliases(const FontIcon* fontIcon) - { - for (const auto& header : ALIAS_HEADERS) - m_csv.WriteColumn(header); - m_csv.NextRow(); - - for (auto aliasIndex = 0u; aliasIndex < fontIcon->numAliasEntries; aliasIndex++) - { - const auto* alias = &fontIcon->fontIconAlias[aliasIndex]; - m_csv.WriteColumn(std::to_string(aliasIndex)); - m_csv.WriteColumn(TYPE_ALIAS); - - auto* knownAlias = FindKnownAliasByHash(alias->aliasHash); - if (knownAlias) - m_csv.WriteColumn(knownAlias->m_name); - else - m_csv.WriteColumn(std::format("@{:x}", alias->aliasHash)); - - const auto* referencedEntry = FindEntryByHash(fontIcon, alias->buttonHash); - if (referencedEntry && referencedEntry->fontIconName.string) - m_csv.WriteColumn(referencedEntry->fontIconName.string); - else - m_csv.WriteColumn(""); - - m_csv.NextRow(); - } - } - -public: - explicit AssetDumperFontIconInternal(std::ostream& stream) - : m_csv(stream) - { - } - - void DumpFontIcon(const FontIcon* fontIcon) - { - WriteFontIconEntries(fontIcon); - m_csv.NextRow(); - - WriteFontIconAliases(fontIcon); - } -}; - -bool AssetDumperFontIcon::ShouldDump(XAssetInfo* asset) -{ - return true; -} - -void AssetDumperFontIcon::DumpAsset(AssetDumpingContext& context, XAssetInfo* asset) -{ - const auto assetFile = context.OpenAssetFile(asset->m_name); - - if (!assetFile) - return; - - AssetDumperFontIconInternal dumper(*assetFile); - dumper.DumpFontIcon(asset->Asset()); -} diff --git a/src/ObjWriting/Game/T6/FontIcon/DumperFontIconCsvT6.cpp b/src/ObjWriting/Game/T6/FontIcon/DumperFontIconCsvT6.cpp new file mode 100644 index 00000000..a6b199ae --- /dev/null +++ b/src/ObjWriting/Game/T6/FontIcon/DumperFontIconCsvT6.cpp @@ -0,0 +1,146 @@ +#include "DumperFontIconCsvT6.h" + +#include "Csv/CsvStream.h" +#include "Game/T6/CommonT6.h" +#include "KnownFontIconAliasesT6.h" + +#include + +using namespace T6; + +namespace +{ + const std::string TYPE_ICON = "icon"; + const std::string ICON_HEADERS[]{ + "# index", + "# type", + "# name", + "# material", + "# size", + "# xScale", + "# yScale", + }; + + const std::string TYPE_ALIAS = "alias"; + const std::string ALIAS_HEADERS[]{ + "# index", + "# type", + "# alias", + "# button", + }; + + FontIconEntry* FindEntryByHash(const FontIcon& fontIcon, const int hash) + { + auto lowerBound = 0u; + auto upperBound = fontIcon.numEntries; + + while (true) + { + const auto entryIndex = (lowerBound + upperBound) / 2u; + auto* entry = &fontIcon.fontIconEntry[entryIndex]; + + if (entry->fontIconName.hash == hash) + return entry; + + if (lowerBound == upperBound) + return nullptr; + + if (entry->fontIconName.hash < hash) + lowerBound = entryIndex + 1u; + else + upperBound = entryIndex - 1u; + } + } + + class DumperFontIconCsv + { + public: + explicit DumperFontIconCsv(std::ostream& stream) + : m_csv(stream) + { + } + + void DumpFontIcon(const FontIcon& fontIcon) + { + WriteFontIconEntries(fontIcon); + m_csv.NextRow(); + + WriteFontIconAliases(fontIcon); + } + + private: + void WriteFontIconEntries(const FontIcon& fontIcon) + { + for (const auto& header : ICON_HEADERS) + m_csv.WriteColumn(header); + m_csv.NextRow(); + + for (auto iconIndex = 0u; iconIndex < fontIcon.numEntries; iconIndex++) + { + const auto* entry = &fontIcon.fontIconEntry[iconIndex]; + m_csv.WriteColumn(std::to_string(iconIndex)); + m_csv.WriteColumn(TYPE_ICON); + + if (entry->fontIconName.string) + m_csv.WriteColumn(entry->fontIconName.string); + else + m_csv.WriteColumn(""); + + if (entry->fontIconMaterialHandle && entry->fontIconMaterialHandle->info.name) + m_csv.WriteColumn(entry->fontIconMaterialHandle->info.name); + else + m_csv.WriteColumn(""); + + m_csv.WriteColumn(std::to_string(entry->fontIconSize)); + m_csv.WriteColumn(std::to_string(entry->xScale)); + m_csv.WriteColumn(std::to_string(entry->yScale)); + + m_csv.NextRow(); + } + } + + void WriteFontIconAliases(const FontIcon& fontIcon) + { + for (const auto& header : ALIAS_HEADERS) + m_csv.WriteColumn(header); + m_csv.NextRow(); + + for (auto aliasIndex = 0u; aliasIndex < fontIcon.numAliasEntries; aliasIndex++) + { + const auto* alias = &fontIcon.fontIconAlias[aliasIndex]; + m_csv.WriteColumn(std::to_string(aliasIndex)); + m_csv.WriteColumn(TYPE_ALIAS); + + auto* knownAlias = FindKnownFontIconAliasByHash(alias->aliasHash); + if (knownAlias) + m_csv.WriteColumn(knownAlias->m_name); + else + m_csv.WriteColumn(std::format("@{:x}", alias->aliasHash)); + + const auto* referencedEntry = FindEntryByHash(fontIcon, alias->buttonHash); + if (referencedEntry && referencedEntry->fontIconName.string) + m_csv.WriteColumn(referencedEntry->fontIconName.string); + else + m_csv.WriteColumn(""); + + m_csv.NextRow(); + } + } + + CsvOutputStream m_csv; + }; +} // namespace + +namespace T6 +{ + void DumpFontIconAsCsv(const AssetDumpingContext& context, const FontIcon& fontIcon) + { + const auto assetFile = context.OpenAssetFile(fontIcon.name); + + if (!assetFile) + return; + + DumperFontIconCsv dumperFontIconCsv(*assetFile); + dumperFontIconCsv.DumpFontIcon(fontIcon); + } +} // namespace T6 diff --git a/src/ObjWriting/Game/T6/FontIcon/DumperFontIconCsvT6.h b/src/ObjWriting/Game/T6/FontIcon/DumperFontIconCsvT6.h new file mode 100644 index 00000000..bbdc5649 --- /dev/null +++ b/src/ObjWriting/Game/T6/FontIcon/DumperFontIconCsvT6.h @@ -0,0 +1,9 @@ +#pragma once + +#include "Dumping/AbstractAssetDumper.h" +#include "Game/T6/T6.h" + +namespace T6 +{ + void DumpFontIconAsCsv(const AssetDumpingContext& context, const FontIcon& fontIcon); +} diff --git a/src/ObjWriting/Game/T6/FontIcon/DumperFontIconJsonT6.cpp b/src/ObjWriting/Game/T6/FontIcon/DumperFontIconJsonT6.cpp new file mode 100644 index 00000000..f532ebe3 --- /dev/null +++ b/src/ObjWriting/Game/T6/FontIcon/DumperFontIconJsonT6.cpp @@ -0,0 +1,90 @@ +#include "DumperFontIconJsonT6.h" + +#include "Game/T6/CommonT6.h" +#include "Game/T6/FontIcon/FontIconCommonT6.h" +#include "Game/T6/FontIcon/JsonFontIconT6.h" +#include "KnownFontIconAliasesT6.h" + +#include + +using namespace nlohmann; +using namespace T6; + +namespace +{ + void AddFontIconEntryAlias(JsonFontIconEntry& jFontIconEntry, const int aliasHash) + { + auto* knownAlias = FindKnownFontIconAliasByHash(aliasHash); + if (knownAlias) + { + jFontIconEntry.aliases.emplace_back(knownAlias->m_name); + } + else + { + if (!jFontIconEntry.aliasHashes.has_value()) + jFontIconEntry.aliasHashes.emplace(); + + jFontIconEntry.aliasHashes->emplace_back(static_cast(aliasHash)); + } + } + + void CreateJsonFontIconEntry(JsonFontIconEntry& jFontIconEntry, const FontIconEntry& fontIconEntry, const FontIcon& fontIcon) + { + jFontIconEntry.name = fontIconEntry.fontIconName.string; + + if (fontIconEntry.fontIconMaterialHandle && fontIconEntry.fontIconMaterialHandle->info.name) + jFontIconEntry.material = fontIconEntry.fontIconMaterialHandle->info.name; + + jFontIconEntry.size = static_cast(fontIconEntry.fontIconSize); + jFontIconEntry.scale = JsonVec2(); + jFontIconEntry.scale->x = fontIconEntry.xScale; + jFontIconEntry.scale->y = fontIconEntry.yScale; + + if (fontIcon.fontIconAlias) + { + for (auto aliasIndex = 0u; aliasIndex < fontIcon.numAliasEntries; aliasIndex++) + { + const auto& alias = fontIcon.fontIconAlias[aliasIndex]; + if (alias.buttonHash == fontIconEntry.fontIconName.hash) + AddFontIconEntryAlias(jFontIconEntry, alias.aliasHash); + } + } + } + + void CreateJsonFontIconFile(JsonFontIcon& jFontIcon, const FontIcon& fontIcon) + { + if (fontIcon.fontIconEntry == nullptr) + return; + + jFontIcon.entries.resize(fontIcon.numEntries); + for (auto i = 0u; i < fontIcon.numEntries; i++) + CreateJsonFontIconEntry(jFontIcon.entries[i], fontIcon.fontIconEntry[i], fontIcon); + } + + void DumpFontIcon(std::ostream& stream, const FontIcon& fontIcon) + { + JsonFontIcon jFontIcon; + CreateJsonFontIconFile(jFontIcon, fontIcon); + json jRoot = jFontIcon; + + jRoot["$schema"] = "http://openassettools.dev/schema/font-icon.v1.json"; + jRoot["_type"] = "font-icon"; + jRoot["_version"] = 1; + jRoot["_game"] = "t6"; + + stream << std::setw(4) << jRoot << "\n"; + } +} // namespace + +namespace T6 +{ + void DumpFontIconAsJson(const AssetDumpingContext& context, const FontIcon& fontIcon) + { + const auto assetFile = context.OpenAssetFile(font_icon::GetJsonFileNameForAssetName(fontIcon.name)); + + if (!assetFile) + return; + + DumpFontIcon(*assetFile, fontIcon); + } +} // namespace T6 diff --git a/src/ObjWriting/Game/T6/FontIcon/DumperFontIconJsonT6.h b/src/ObjWriting/Game/T6/FontIcon/DumperFontIconJsonT6.h new file mode 100644 index 00000000..7603e35d --- /dev/null +++ b/src/ObjWriting/Game/T6/FontIcon/DumperFontIconJsonT6.h @@ -0,0 +1,9 @@ +#pragma once + +#include "Dumping/AbstractAssetDumper.h" +#include "Game/T6/T6.h" + +namespace T6 +{ + void DumpFontIconAsJson(const AssetDumpingContext& context, const FontIcon& fontIcon); +} diff --git a/src/ObjWriting/Game/T6/FontIcon/DumperFontIconT6.cpp b/src/ObjWriting/Game/T6/FontIcon/DumperFontIconT6.cpp new file mode 100644 index 00000000..91dc5946 --- /dev/null +++ b/src/ObjWriting/Game/T6/FontIcon/DumperFontIconT6.cpp @@ -0,0 +1,22 @@ +#include "DumperFontIconT6.h" + +#include "DumperFontIconCsvT6.h" +#include "DumperFontIconJsonT6.h" + +using namespace T6; + +// #define DUMP_FONT_ICON_AS_CSV 1 + +bool AssetDumperFontIcon::ShouldDump(XAssetInfo* asset) +{ + return true; +} + +void AssetDumperFontIcon::DumpAsset(AssetDumpingContext& context, XAssetInfo* asset) +{ +#ifdef DUMP_FONT_ICON_AS_CSV + DumpFontIconAsCsv(context, *asset->Asset()); +#else + DumpFontIconAsJson(context, *asset->Asset()); +#endif +} diff --git a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperFontIcon.h b/src/ObjWriting/Game/T6/FontIcon/DumperFontIconT6.h similarity index 100% rename from src/ObjWriting/Game/T6/AssetDumpers/AssetDumperFontIcon.h rename to src/ObjWriting/Game/T6/FontIcon/DumperFontIconT6.h diff --git a/src/ObjWriting/Game/T6/FontIcon/KnownFontIconAliasesT6.cpp b/src/ObjWriting/Game/T6/FontIcon/KnownFontIconAliasesT6.cpp new file mode 100644 index 00000000..ef391651 --- /dev/null +++ b/src/ObjWriting/Game/T6/FontIcon/KnownFontIconAliasesT6.cpp @@ -0,0 +1,125 @@ +#include "KnownFontIconAliasesT6.h" + +#include "Game/T6/CommonT6.h" + +using namespace T6; + +namespace +{ + inline const KnownAlias KNOWN_ALIASES[]{ + KnownAlias("BUTTON_ADS"), + KnownAlias("BUTTON_CAC_NEXT"), + KnownAlias("BUTTON_CAC_PREV"), + KnownAlias("BUTTON_CANCEL"), + KnownAlias("BUTTON_CAROUSEL_STICK"), + KnownAlias("BUTTON_CREATE"), + KnownAlias("BUTTON_CYCLE_LEFT"), + KnownAlias("BUTTON_CYCLE_LEFT_ACTIVE"), + KnownAlias("BUTTON_CYCLE_RIGHT"), + KnownAlias("BUTTON_CYCLE_RIGHT_ACTIVE"), + KnownAlias("BUTTON_DELETE"), + KnownAlias("BUTTON_EDIT"), + KnownAlias("BUTTON_EMBLEM_BACKWARD"), + KnownAlias("BUTTON_EMBLEM_FLIP"), + KnownAlias("BUTTON_EMBLEM_FORWARD"), + KnownAlias("BUTTON_EMBLEM_FORWARD_BACKWARD"), + KnownAlias("BUTTON_EMBLEM_MOVE"), + KnownAlias("BUTTON_EMBLEM_OUTLINE"), + KnownAlias("BUTTON_EMBLEM_PALETTE_CYCLE"), + KnownAlias("BUTTON_EMBLEM_PALETTE_NEXT"), + KnownAlias("BUTTON_EMBLEM_PALETTE_PREV"), + KnownAlias("BUTTON_EMBLEM_RESET"), + KnownAlias("BUTTON_EMBLEM_ROTATE_LEFT"), + KnownAlias("BUTTON_EMBLEM_ROTATE_RIGHT"), + KnownAlias("BUTTON_EMBLEM_SCALE"), + KnownAlias("BUTTON_FIRE"), + KnownAlias("BUTTON_FRIENDSLIST"), + KnownAlias("BUTTON_INTERACT"), + KnownAlias("BUTTON_LOOKSTICK"), + KnownAlias("BUTTON_LOOK"), + KnownAlias("BUTTON_LUI_ALT1"), + KnownAlias("BUTTON_LUI_ALT2"), + KnownAlias("BUTTON_LUI_DPAD_ALL"), + KnownAlias("BUTTON_LUI_DPAD_D"), + KnownAlias("BUTTON_LUI_DPAD_L"), + KnownAlias("BUTTON_LUI_DPAD_RL"), + KnownAlias("BUTTON_LUI_DPAD_R"), + KnownAlias("BUTTON_LUI_DPAD_UD"), + KnownAlias("BUTTON_LUI_DPAD_U"), + KnownAlias("BUTTON_LUI_LEFT_STICK_UP"), + KnownAlias("BUTTON_LUI_LEFT_TRIGGER"), + KnownAlias("BUTTON_LUI_PRIMARY"), + KnownAlias("BUTTON_LUI_RIGHT_STICK"), + KnownAlias("BUTTON_LUI_RIGHT_TRIGGER"), + KnownAlias("BUTTON_LUI_SECONDARY"), + KnownAlias("BUTTON_LUI_SELECT"), + KnownAlias("BUTTON_LUI_SHOULDERL"), + KnownAlias("BUTTON_LUI_SHOULDERR"), + KnownAlias("BUTTON_LUI_START"), + KnownAlias("BUTTON_MOUSE_CLICK"), + KnownAlias("BUTTON_MOUSE_CLICK_ACTIVE"), + KnownAlias("BUTTON_MOUSE_EDIT"), + KnownAlias("BUTTON_MOUSE_EDIT_ACTIVE"), + KnownAlias("BUTTON_MOUSE_LEFT"), + KnownAlias("BUTTON_MOUSE_MIDDLE"), + KnownAlias("BUTTON_MOUSE_RIGHT"), + KnownAlias("BUTTON_MOVESTICK"), + KnownAlias("BUTTON_MOVE"), + KnownAlias("BUTTON_MP_CANCELCOMMAND"), + KnownAlias("BUTTON_MP_CHANGESETTINGS"), + KnownAlias("BUTTON_MP_GAMERCARD"), + KnownAlias("BUTTON_MP_GAMERREVIEW"), + KnownAlias("BUTTON_MP_JOINGAME"), + KnownAlias("BUTTON_MP_KICKPLAYER"), + KnownAlias("BUTTON_MP_LEAVEGAME"), + KnownAlias("BUTTON_MP_LOBBY_GAMERCARD"), + KnownAlias("BUTTON_MP_NOTREADY"), + KnownAlias("BUTTON_MP_PGDOWN"), + KnownAlias("BUTTON_MP_PGUP"), + KnownAlias("BUTTON_MP_READY"), + KnownAlias("BUTTON_MP_REFRESH"), + KnownAlias("BUTTON_MP_SCOREBOARD"), + KnownAlias("BUTTON_MP_SIGNIN"), + KnownAlias("BUTTON_MP_SPECNEXT"), + KnownAlias("BUTTON_MP_SPECPREV"), + KnownAlias("BUTTON_MP_STARTGAME"), + KnownAlias("BUTTON_MP_TOGGLECHASECAM"), + KnownAlias("BUTTON_MP_TOGGLEVIEW"), + KnownAlias("BUTTON_NO"), + KnownAlias("BUTTON_RECORD_VIEW_NEXT"), + KnownAlias("BUTTON_RECORD_VIEW_PREV"), + KnownAlias("BUTTON_SELECTCHOICE"), + KnownAlias("BUTTON_SP_TOGGLEMENU"), + KnownAlias("BUTTON_YES"), + KnownAlias("CP"), + KnownAlias("FONT_CAPITAL_I"), + KnownAlias("FONT_NUMBER_ZERO"), + KnownAlias("KEY_DOWN_ARROW"), + KnownAlias("KEY_LEFT_ARROW"), + KnownAlias("KEY_RIGHT_ARROW"), + KnownAlias("KEY_UP_ARROW"), + KnownAlias("MOUSE_WHEEL_DOWN"), + KnownAlias("MOUSE_WHEEL_UP"), + KnownAlias("Remote_LStick"), + }; +} + +namespace T6 +{ + KnownAlias::KnownAlias(std::string aliasName) + : m_name(std::move(aliasName)), + m_hash(Common::Com_HashString(m_name.c_str())) + { + } + + const KnownAlias* FindKnownFontIconAliasByHash(const int hash) + { + for (const auto& i : KNOWN_ALIASES) + { + if (i.m_hash == hash) + return &i; + } + + return nullptr; + } +} // namespace T6 diff --git a/src/ObjWriting/Game/T6/FontIcon/KnownFontIconAliasesT6.h b/src/ObjWriting/Game/T6/FontIcon/KnownFontIconAliasesT6.h new file mode 100644 index 00000000..bca5a007 --- /dev/null +++ b/src/ObjWriting/Game/T6/FontIcon/KnownFontIconAliasesT6.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +namespace T6 +{ + class KnownAlias + { + public: + explicit KnownAlias(std::string aliasName); + + std::string m_name; + int m_hash; + }; + + const KnownAlias* FindKnownFontIconAliasByHash(int hash); +} // namespace T6 diff --git a/src/ObjWriting/Game/T6/ObjWriterT6.cpp b/src/ObjWriting/Game/T6/ObjWriterT6.cpp index bb4bcb15..971462b8 100644 --- a/src/ObjWriting/Game/T6/ObjWriterT6.cpp +++ b/src/ObjWriting/Game/T6/ObjWriterT6.cpp @@ -1,6 +1,5 @@ #include "ObjWriterT6.h" -#include "AssetDumpers/AssetDumperFontIcon.h" #include "AssetDumpers/AssetDumperGfxImage.h" #include "AssetDumpers/AssetDumperLeaderboardDef.h" #include "AssetDumpers/AssetDumperLocalizeEntry.h" @@ -23,6 +22,7 @@ #include "AssetDumpers/AssetDumperWeaponCamo.h" #include "AssetDumpers/AssetDumperXModel.h" #include "AssetDumpers/AssetDumperZBarrier.h" +#include "FontIcon/DumperFontIconT6.h" #include "Game/T6/GameAssetPoolT6.h" #include "Material/DumperMaterialT6.h" #include "ObjWriting.h" From b8f72b782624115f2a8421e8e29ae6b693a73852 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Wed, 23 Jul 2025 19:21:09 +0100 Subject: [PATCH 2/3] feat: add loader for fonticon json files --- ...FontIconT6.cpp => CsvLoaderFontIconT6.cpp} | 10 +- ...aderFontIconT6.h => CsvLoaderFontIconT6.h} | 2 +- .../Game/T6/FontIcon/JsonLoaderFontIconT6.cpp | 150 ++++++++++++++++++ .../Game/T6/FontIcon/JsonLoaderFontIconT6.h | 13 ++ src/ObjLoading/Game/T6/ObjLoaderT6.cpp | 6 +- 5 files changed, 173 insertions(+), 8 deletions(-) rename src/ObjLoading/Game/T6/FontIcon/{LoaderFontIconT6.cpp => CsvLoaderFontIconT6.cpp} (96%) rename src/ObjLoading/Game/T6/FontIcon/{LoaderFontIconT6.h => CsvLoaderFontIconT6.h} (61%) create mode 100644 src/ObjLoading/Game/T6/FontIcon/JsonLoaderFontIconT6.cpp create mode 100644 src/ObjLoading/Game/T6/FontIcon/JsonLoaderFontIconT6.h diff --git a/src/ObjLoading/Game/T6/FontIcon/LoaderFontIconT6.cpp b/src/ObjLoading/Game/T6/FontIcon/CsvLoaderFontIconT6.cpp similarity index 96% rename from src/ObjLoading/Game/T6/FontIcon/LoaderFontIconT6.cpp rename to src/ObjLoading/Game/T6/FontIcon/CsvLoaderFontIconT6.cpp index 43cde72c..ca53435b 100644 --- a/src/ObjLoading/Game/T6/FontIcon/LoaderFontIconT6.cpp +++ b/src/ObjLoading/Game/T6/FontIcon/CsvLoaderFontIconT6.cpp @@ -1,4 +1,4 @@ -#include "LoaderFontIconT6.h" +#include "CsvLoaderFontIconT6.h" #include "Csv/CsvStream.h" #include "Game/T6/CommonT6.h" @@ -30,10 +30,10 @@ namespace constexpr unsigned COL_COUNT_ALIAS = 4; constexpr unsigned COL_COUNT_MIN = std::min(COL_COUNT_ICON, COL_COUNT_ALIAS); - class FontIconLoader final : public AssetCreator + class CsvFontIconLoader final : public AssetCreator { public: - FontIconLoader(MemoryManager& memory, ISearchPath& searchPath) + CsvFontIconLoader(MemoryManager& memory, ISearchPath& searchPath) : m_memory(memory), m_search_path(searchPath) { @@ -284,8 +284,8 @@ namespace namespace T6 { - std::unique_ptr> CreateFontIconLoader(MemoryManager& memory, ISearchPath& searchPath) + std::unique_ptr> CreateCsvFontIconLoader(MemoryManager& memory, ISearchPath& searchPath) { - return std::make_unique(memory, searchPath); + return std::make_unique(memory, searchPath); } } // namespace T6 diff --git a/src/ObjLoading/Game/T6/FontIcon/LoaderFontIconT6.h b/src/ObjLoading/Game/T6/FontIcon/CsvLoaderFontIconT6.h similarity index 61% rename from src/ObjLoading/Game/T6/FontIcon/LoaderFontIconT6.h rename to src/ObjLoading/Game/T6/FontIcon/CsvLoaderFontIconT6.h index e9f658e8..7bb1e58f 100644 --- a/src/ObjLoading/Game/T6/FontIcon/LoaderFontIconT6.h +++ b/src/ObjLoading/Game/T6/FontIcon/CsvLoaderFontIconT6.h @@ -9,5 +9,5 @@ namespace T6 { - std::unique_ptr> CreateFontIconLoader(MemoryManager& memory, ISearchPath& searchPath); + std::unique_ptr> CreateCsvFontIconLoader(MemoryManager& memory, ISearchPath& searchPath); } // namespace T6 diff --git a/src/ObjLoading/Game/T6/FontIcon/JsonLoaderFontIconT6.cpp b/src/ObjLoading/Game/T6/FontIcon/JsonLoaderFontIconT6.cpp new file mode 100644 index 00000000..002e778c --- /dev/null +++ b/src/ObjLoading/Game/T6/FontIcon/JsonLoaderFontIconT6.cpp @@ -0,0 +1,150 @@ +#include "JsonLoaderFontIconT6.h" + +#include "Game/T6/CommonT6.h" +#include "Game/T6/FontIcon/FontIconCommonT6.h" +#include "Game/T6/FontIcon/JsonFontIconT6.h" +#include "Game/T6/T6.h" + +#include +#include +#include +#include + +using namespace nlohmann; +using namespace T6; + +namespace +{ + class JsonFontIconLoader final : public AssetCreator + { + public: + JsonFontIconLoader(MemoryManager& memory, ISearchPath& searchPath) + : m_memory(memory), + m_search_path(searchPath) + { + } + + AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override + { + const auto file = m_search_path.Open(font_icon::GetJsonFileNameForAssetName(assetName)); + if (!file.IsOpen()) + return AssetCreationResult::NoAction(); + + auto* fontIcon = m_memory.Alloc(); + fontIcon->name = m_memory.Dup(assetName.c_str()); + AssetRegistration registration(assetName, fontIcon); + + try + { + const auto jRoot = json::parse(*file.m_stream); + std::string type; + unsigned version; + + jRoot.at("_type").get_to(type); + jRoot.at("_version").get_to(version); + + if (type != "font-icon" || version != 1u) + { + std::cerr << std::format("Tried to load font icon \"{}\" but did not find expected type font-icon of version 1\n", assetName); + return AssetCreationResult::Failure(); + } + + const auto jFontIcon = jRoot.get(); + if (CreateFontIconFromJson(jFontIcon, *fontIcon, registration, context)) + return AssetCreationResult::Success(context.AddAsset(std::move(registration))); + } + catch (const json::exception& e) + { + std::cerr << std::format("Failed to parse json of font icon: {}\n", e.what()); + } + + return AssetCreationResult::Failure(); + } + + private: + bool CreateFontIconFromJson(const JsonFontIcon& jFontIcon, + FontIcon& fontIcon, + AssetRegistration& registration, + AssetCreationContext& context) const + { + std::vector aliases; + + fontIcon.numEntries = static_cast(jFontIcon.entries.size()); + fontIcon.fontIconEntry = m_memory.Alloc(fontIcon.numEntries); + + for (auto entryIndex = 0u; entryIndex < fontIcon.numEntries; entryIndex++) + { + if (!CreateFontIconEntryFromJson(jFontIcon.entries[entryIndex], fontIcon.fontIconEntry[entryIndex], aliases, registration, context)) + return false; + } + + std::sort(fontIcon.fontIconEntry, + &fontIcon.fontIconEntry[fontIcon.numEntries], + [](const FontIconEntry& e0, const FontIconEntry& e1) -> bool + { + return e0.fontIconName.hash < e1.fontIconName.hash; + }); + + if (!aliases.empty()) + { + fontIcon.numAliasEntries = static_cast(aliases.size()); + fontIcon.fontIconAlias = m_memory.Alloc(fontIcon.numAliasEntries); + std::memcpy(fontIcon.fontIconAlias, aliases.data(), sizeof(FontIconAlias) * fontIcon.numAliasEntries); + + std::sort(fontIcon.fontIconAlias, + &fontIcon.fontIconAlias[fontIcon.numAliasEntries], + [](const FontIconAlias& a0, const FontIconAlias& a1) -> bool + { + return a0.aliasHash < a1.aliasHash; + }); + } + + return true; + } + + bool CreateFontIconEntryFromJson(const JsonFontIconEntry& jFontIconEntry, + FontIconEntry& fontIconEntry, + std::vector& aliases, + AssetRegistration& registration, + AssetCreationContext& context) const + { + fontIconEntry.fontIconName.string = m_memory.Dup(jFontIconEntry.name.c_str()); + fontIconEntry.fontIconName.hash = Common::Com_HashString(jFontIconEntry.name.c_str()); + + auto* materialDependency = context.LoadDependency(jFontIconEntry.material); + if (materialDependency == nullptr) + { + std::cerr << std::format("Failed to load material \"{}\" for font icon entry \"{}\"\n", jFontIconEntry.material, jFontIconEntry.name); + return false; + } + registration.AddDependency(materialDependency); + fontIconEntry.fontIconMaterialHandle = materialDependency->Asset(); + + fontIconEntry.fontIconSize = static_cast(jFontIconEntry.size); + fontIconEntry.xScale = jFontIconEntry.scale.has_value() ? jFontIconEntry.scale->x : 0; + fontIconEntry.yScale = jFontIconEntry.scale.has_value() ? jFontIconEntry.scale->y : 0; + + for (const auto& alias : jFontIconEntry.aliases) + aliases.emplace_back(Common::Com_HashString(alias.c_str()), fontIconEntry.fontIconName.hash); + + if (jFontIconEntry.aliasHashes.has_value()) + { + for (const auto aliasHash : *jFontIconEntry.aliasHashes) + aliases.emplace_back(aliasHash, fontIconEntry.fontIconName.hash); + } + + return true; + } + + MemoryManager& m_memory; + ISearchPath& m_search_path; + }; +} // namespace + +namespace T6 +{ + std::unique_ptr> CreateJsonFontIconLoader(MemoryManager& memory, ISearchPath& searchPath) + { + return std::make_unique(memory, searchPath); + } +} // namespace T6 diff --git a/src/ObjLoading/Game/T6/FontIcon/JsonLoaderFontIconT6.h b/src/ObjLoading/Game/T6/FontIcon/JsonLoaderFontIconT6.h new file mode 100644 index 00000000..7938827a --- /dev/null +++ b/src/ObjLoading/Game/T6/FontIcon/JsonLoaderFontIconT6.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Asset/IAssetCreator.h" +#include "Game/T6/T6.h" +#include "SearchPath/ISearchPath.h" +#include "Utils/MemoryManager.h" + +#include + +namespace T6 +{ + std::unique_ptr> CreateJsonFontIconLoader(MemoryManager& memory, ISearchPath& searchPath); +} // namespace T6 diff --git a/src/ObjLoading/Game/T6/ObjLoaderT6.cpp b/src/ObjLoading/Game/T6/ObjLoaderT6.cpp index 37afdf89..a1f029f3 100644 --- a/src/ObjLoading/Game/T6/ObjLoaderT6.cpp +++ b/src/ObjLoading/Game/T6/ObjLoaderT6.cpp @@ -1,7 +1,8 @@ #include "ObjLoaderT6.h" #include "Asset/GlobalAssetPoolsLoader.h" -#include "FontIcon/LoaderFontIconT6.h" +#include "FontIcon/CsvLoaderFontIconT6.h" +#include "FontIcon/JsonLoaderFontIconT6.h" #include "Game/T6/CommonT6.h" #include "Game/T6/GameAssetPoolT6.h" #include "Game/T6/GameT6.h" @@ -412,7 +413,8 @@ namespace T6 // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); - collection.AddAssetCreator(CreateFontIconLoader(memory, searchPath)); + collection.AddAssetCreator(CreateCsvFontIconLoader(memory, searchPath)); + collection.AddAssetCreator(CreateJsonFontIconLoader(memory, searchPath)); // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); collection.AddAssetCreator(CreateLocalizeLoader(memory, searchPath, zone)); From bca5fd3f1a16be40922db8b566f8f0776248b072 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Wed, 23 Jul 2025 22:52:26 +0100 Subject: [PATCH 3/3] chore: add tests for font icon json writing and loading --- .../T6/FontIcon/JsonLoaderFontIconT6Test.cpp | 156 +++++++++++++++++ .../T6/FontIcon/DumperFontIconJsonT6Test.cpp | 159 ++++++++++++++++++ 2 files changed, 315 insertions(+) create mode 100644 test/ObjLoadingTests/Game/T6/FontIcon/JsonLoaderFontIconT6Test.cpp create mode 100644 test/ObjWritingTests/Game/T6/FontIcon/DumperFontIconJsonT6Test.cpp diff --git a/test/ObjLoadingTests/Game/T6/FontIcon/JsonLoaderFontIconT6Test.cpp b/test/ObjLoadingTests/Game/T6/FontIcon/JsonLoaderFontIconT6Test.cpp new file mode 100644 index 00000000..f99d761f --- /dev/null +++ b/test/ObjLoadingTests/Game/T6/FontIcon/JsonLoaderFontIconT6Test.cpp @@ -0,0 +1,156 @@ +#include "Game/T6/FontIcon/JsonLoaderFontIconT6.h" + +#include "Game/T6/CommonT6.h" +#include "Game/T6/GameT6.h" +#include "SearchPath/MockSearchPath.h" +#include "Utils/MemoryManager.h" + +#include +#include +#include + +using namespace T6; +using namespace Catch; +using namespace std::literals; + +namespace +{ + void GivenMaterial(const std::string& name, AssetCreationContext& context, MemoryManager& memory) + { + auto* material = memory.Alloc(); + material->info.name = memory.Dup(name.c_str()); + + AssetRegistration registration(name); + registration.SetAsset(material); + context.AddAsset(std::move(registration)); + } + + TEST_CASE("JsonLoaderFontIcon(T6): Can parse font icon", "[t6][font-icon][assetloader]") + { + MockSearchPath searchPath; + searchPath.AddFileData("fonticon/test.json", + R"FONT_ICON( +{ + "$schema": "http://openassettools.dev/schema/font-icon.v1.json", + "_game": "t6", + "_type": "font-icon", + "_version": 1, + "entries": [ + { + "aliases": [ + "BUTTON_LUI_DPAD_ALL" + ], + "material": "xenonbutton_dpad_all", + "name": "XenonButtondpadAll", + "scale": { + "x": 1.0, + "y": 1.0 + }, + "size": 32 + }, + { + "aliasHashes": [ + 3463582170 + ], + "aliases": [], + "material": "ui_button_xenon_lstick_anim_d", + "name": "XenonButtonLStickAnimatedD", + "scale": { + "x": 1.5, + "y": 1.5 + }, + "size": 32 + }, + { + "aliases": [ + "BUTTON_MOVE", + "BUTTON_EMBLEM_MOVE", + "BUTTON_LUI_LEFT_STICK_UP", + "BUTTON_MOVESTICK" + ], + "material": "xenonbutton_ls", + "name": "XenonButtonStickAnimatedL", + "scale": { + "x": 1.0, + "y": 1.0 + }, + "size": 32 + } + ] +})FONT_ICON"); + + Zone zone("MockZone", 0, IGame::GetGameById(GameId::T6)); + + MemoryManager memory; + AssetCreatorCollection creatorCollection(zone); + IgnoredAssetLookup ignoredAssetLookup; + AssetCreationContext context(zone, &creatorCollection, &ignoredAssetLookup); + + GivenMaterial("xenonbutton_dpad_all", context, memory); + GivenMaterial("ui_button_xenon_lstick_anim_d", context, memory); + GivenMaterial("xenonbutton_ls", context, memory); + + auto loader = CreateJsonFontIconLoader(memory, searchPath); + auto result = loader->CreateAsset("fonticon/test.csv", context); + REQUIRE(result.HasBeenSuccessful()); + + const auto* assetInfo = reinterpret_cast*>(result.GetAssetInfo()); + const auto* fontIcon = assetInfo->Asset(); + + REQUIRE(fontIcon->name == "fonticon/test.csv"s); + + REQUIRE(fontIcon->numEntries == 3); + REQUIRE(fontIcon->fontIconEntry != nullptr); + + const auto& entry0 = fontIcon->fontIconEntry[0]; + REQUIRE(entry0.fontIconName.string == "XenonButtondpadAll"s); + REQUIRE(entry0.fontIconName.hash == static_cast(0x9220177B)); + REQUIRE(entry0.fontIconMaterialHandle->info.name == "xenonbutton_dpad_all"s); + REQUIRE(entry0.fontIconSize == 32); + REQUIRE(entry0.xScale == 1.0f); + REQUIRE(entry0.yScale == 1.0f); + + const auto& entry1 = fontIcon->fontIconEntry[1]; + REQUIRE(entry1.fontIconName.string == "XenonButtonLStickAnimatedD"s); + REQUIRE(entry1.fontIconName.hash == static_cast(0x9E7D535A)); + REQUIRE(entry1.fontIconMaterialHandle->info.name == "ui_button_xenon_lstick_anim_d"s); + REQUIRE(entry1.fontIconSize == 32); + REQUIRE(entry1.xScale == 1.5f); + REQUIRE(entry1.yScale == 1.5f); + + const auto& entry2 = fontIcon->fontIconEntry[2]; + REQUIRE(entry2.fontIconName.string == "XenonButtonStickAnimatedL"s); + REQUIRE(entry2.fontIconName.hash == static_cast(0xABF58CD6)); + REQUIRE(entry2.fontIconMaterialHandle->info.name == "xenonbutton_ls"s); + REQUIRE(entry2.fontIconSize == 32); + REQUIRE(entry2.xScale == 1.0f); + REQUIRE(entry2.yScale == 1.0f); + + REQUIRE(fontIcon->numAliasEntries == 6); + REQUIRE(fontIcon->fontIconAlias != nullptr); + + auto& alias0 = fontIcon->fontIconAlias[0]; + REQUIRE(alias0.aliasHash == static_cast(0xCE7211DA)); + REQUIRE(alias0.buttonHash == entry1.fontIconName.hash); + + const auto& alias1 = fontIcon->fontIconAlias[1]; + REQUIRE(alias1.aliasHash == static_cast(0xDD3B363A)); + REQUIRE(alias1.buttonHash == entry0.fontIconName.hash); + + const auto& alias2 = fontIcon->fontIconAlias[2]; + REQUIRE(alias2.aliasHash == static_cast(0xFFFBB17)); + REQUIRE(alias2.buttonHash == entry2.fontIconName.hash); + + const auto& alias3 = fontIcon->fontIconAlias[3]; + REQUIRE(alias3.aliasHash == static_cast(0x1893B6A8)); + REQUIRE(alias3.buttonHash == entry2.fontIconName.hash); + + const auto& alias4 = fontIcon->fontIconAlias[4]; + REQUIRE(alias4.aliasHash == static_cast(0x18A33DB5)); + REQUIRE(alias4.buttonHash == entry2.fontIconName.hash); + + const auto& alias5 = fontIcon->fontIconAlias[5]; + REQUIRE(alias5.aliasHash == static_cast(0x5A15AB35)); + REQUIRE(alias5.buttonHash == entry2.fontIconName.hash); + } +} // namespace diff --git a/test/ObjWritingTests/Game/T6/FontIcon/DumperFontIconJsonT6Test.cpp b/test/ObjWritingTests/Game/T6/FontIcon/DumperFontIconJsonT6Test.cpp new file mode 100644 index 00000000..c8837e7b --- /dev/null +++ b/test/ObjWritingTests/Game/T6/FontIcon/DumperFontIconJsonT6Test.cpp @@ -0,0 +1,159 @@ +#include "Game/T6/FontIcon/DumperFontIconJsonT6.h" + +#include "Asset/AssetRegistration.h" +#include "Game/T6/CommonT6.h" +#include "Game/T6/GameT6.h" +#include "NormalizedJson.h" +#include "Pool/AssetPoolDynamic.h" +#include "SearchPath/MockOutputPath.h" +#include "SearchPath/MockSearchPath.h" +#include "Utils/MemoryManager.h" + +#include +#include +#include + +using namespace T6; +using namespace Catch; +using namespace std::literals; + +namespace +{ + Material* GivenMaterial(const std::string& name, MemoryManager& memory) + { + auto* material = memory.Alloc(); + material->info.name = memory.Dup(name.c_str()); + + return material; + } + + void GivenFontIcon(const std::string& name, FontIcon& fontIcon, MemoryManager& memory) + { + fontIcon.name = memory.Dup(name.c_str()); + + fontIcon.numEntries = 3; + fontIcon.fontIconEntry = memory.Alloc(fontIcon.numEntries); + + auto& entry0 = fontIcon.fontIconEntry[0]; + entry0.fontIconName.string = "XenonButtondpadAll"; + entry0.fontIconName.hash = Common::Com_HashString(entry0.fontIconName.string); + entry0.fontIconMaterialHandle = GivenMaterial("xenonbutton_dpad_all", memory); + entry0.fontIconSize = 32; + entry0.xScale = 1.0f; + entry0.yScale = 1.0f; + + auto& entry1 = fontIcon.fontIconEntry[1]; + entry1.fontIconName.string = "XenonButtonLStickAnimatedD"; + entry1.fontIconName.hash = Common::Com_HashString(entry1.fontIconName.string); + entry1.fontIconMaterialHandle = GivenMaterial("ui_button_xenon_lstick_anim_d", memory); + entry1.fontIconSize = 32; + entry1.xScale = 1.5f; + entry1.yScale = 1.5f; + + auto& entry2 = fontIcon.fontIconEntry[2]; + entry2.fontIconName.string = "XenonButtonStickAnimatedL"; + entry2.fontIconName.hash = Common::Com_HashString(entry2.fontIconName.string); + entry2.fontIconMaterialHandle = GivenMaterial("xenonbutton_ls", memory); + entry2.fontIconSize = 32; + entry2.xScale = 1.0f; + entry2.yScale = 1.0f; + + fontIcon.numAliasEntries = 6; + fontIcon.fontIconAlias = memory.Alloc(fontIcon.numAliasEntries); + + auto& alias0 = fontIcon.fontIconAlias[0]; + alias0.aliasHash = Common::Com_HashString("BUTTON_LUI_DPAD_ALL"); + alias0.buttonHash = entry0.fontIconName.hash; + + auto& alias1 = fontIcon.fontIconAlias[1]; + alias1.aliasHash = static_cast(0xCE7211DA); + alias1.buttonHash = entry1.fontIconName.hash; + + auto& alias2 = fontIcon.fontIconAlias[2]; + alias2.aliasHash = Common::Com_HashString("BUTTON_MOVE"); + alias2.buttonHash = entry2.fontIconName.hash; + + auto& alias3 = fontIcon.fontIconAlias[3]; + alias3.aliasHash = Common::Com_HashString("BUTTON_EMBLEM_MOVE"); + alias3.buttonHash = entry2.fontIconName.hash; + + auto& alias4 = fontIcon.fontIconAlias[4]; + alias4.aliasHash = Common::Com_HashString("BUTTON_LUI_LEFT_STICK_UP"); + alias4.buttonHash = entry2.fontIconName.hash; + + auto& alias5 = fontIcon.fontIconAlias[5]; + alias5.aliasHash = Common::Com_HashString("BUTTON_MOVESTICK"); + alias5.buttonHash = entry2.fontIconName.hash; + } + + TEST_CASE("DumperFontIconJson(T6): Can dump font icon", "[t6][font-icon][assetdumper]") + { + std::string expected(R"FONT_ICON( +{ + "$schema": "http://openassettools.dev/schema/font-icon.v1.json", + "_game": "t6", + "_type": "font-icon", + "_version": 1, + "entries": [ + { + "aliases": [ + "BUTTON_LUI_DPAD_ALL" + ], + "material": "xenonbutton_dpad_all", + "name": "XenonButtondpadAll", + "scale": { + "x": 1.0, + "y": 1.0 + }, + "size": 32 + }, + { + "aliasHashes": [ + 3463582170 + ], + "aliases": [], + "material": "ui_button_xenon_lstick_anim_d", + "name": "XenonButtonLStickAnimatedD", + "scale": { + "x": 1.5, + "y": 1.5 + }, + "size": 32 + }, + { + "aliases": [ + "BUTTON_MOVE", + "BUTTON_EMBLEM_MOVE", + "BUTTON_LUI_LEFT_STICK_UP", + "BUTTON_MOVESTICK" + ], + "material": "xenonbutton_ls", + "name": "XenonButtonStickAnimatedL", + "scale": { + "x": 1.0, + "y": 1.0 + }, + "size": 32 + } + ] +})FONT_ICON"); + + Zone zone("MockZone", 0, IGame::GetGameById(GameId::T6)); + + MemoryManager memory; + MockSearchPath mockObjPath; + MockOutputPath mockOutput; + AssetDumpingContext context(zone, "", mockOutput, mockObjPath); + + AssetPoolDynamic materialPool(0); + + FontIcon asset; + GivenFontIcon("fonticon/test.csv", asset, memory); + + DumpFontIconAsJson(context, asset); + + const auto* file = mockOutput.GetMockedFile("fonticon/test.json"); + REQUIRE(file); + REQUIRE(JsonNormalized(file->AsString()) == JsonNormalized(expected)); + } +} // namespace