From 8ec525d3d2b94abd64cf3d3b449e440b9b895f64 Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 23 Feb 2020 02:02:11 +0100 Subject: [PATCH] ObjWriting: Dump FontIcon assets as csv files According to the asset names this seems to be their original format. however since i didn't find any examples of that asset in raw form i just tried to come up with a realistic csv style for it --- src/ObjWriting/Dumping/CsvWriter.cpp | 76 ++++++ src/ObjWriting/Dumping/CsvWriter.h | 19 ++ .../T6/AssetDumpers/AssetDumperFontIcon.cpp | 244 ++++++++++++++++++ .../T6/AssetDumpers/AssetDumperFontIcon.h | 12 + src/ObjWriting/Game/T6/ZoneDumperT6.cpp | 4 +- src/ZoneCommon/Game/T6/CommonT6.cpp | 21 ++ src/ZoneCommon/Game/T6/CommonT6.h | 1 + 7 files changed, 376 insertions(+), 1 deletion(-) create mode 100644 src/ObjWriting/Dumping/CsvWriter.cpp create mode 100644 src/ObjWriting/Dumping/CsvWriter.h create mode 100644 src/ObjWriting/Game/T6/AssetDumpers/AssetDumperFontIcon.cpp create mode 100644 src/ObjWriting/Game/T6/AssetDumpers/AssetDumperFontIcon.h diff --git a/src/ObjWriting/Dumping/CsvWriter.cpp b/src/ObjWriting/Dumping/CsvWriter.cpp new file mode 100644 index 00000000..9c5dfad8 --- /dev/null +++ b/src/ObjWriting/Dumping/CsvWriter.cpp @@ -0,0 +1,76 @@ +#include "CsvWriter.h" + +#include + +const std::string CsvWriter::LINE_BREAK = "\n"; + +CsvWriter::CsvWriter(FileAPI::IFile* file) +{ + m_file = file; + m_first_row = true; + m_current_column = 0; + m_column_count = 0; +} + +void CsvWriter::WriteColumn(const std::string& value) +{ + if (m_current_column++ > 0) + m_file->Printf(","); + + bool containsSeparator = false; + bool containsQuote = false; + for (const auto& c : value) + { + if (c == '"') + { + containsQuote = true; + break; + } + + if (c == SEPARATOR) + containsSeparator = true; + } + + if (containsQuote) + { + std::ostringstream str; + + for(const auto& c : value) + { + if (c == '"') + str << "\"\""; + else + str << c; + } + + m_file->Printf("\"%s\"", str.str().c_str()); + } + else if (containsSeparator) + { + m_file->Printf("\"%s\"", value.c_str()); + } + else + { + m_file->Printf("%s", value.c_str()); + } +} + +void CsvWriter::NextRow() +{ + if (m_first_row) + { + m_first_row = false; + m_column_count = m_current_column; + } + else + { + while(m_current_column < m_column_count) + { + m_file->Printf(","); + m_current_column++; + } + } + + m_file->Printf("\n"); + m_current_column = 0; +} diff --git a/src/ObjWriting/Dumping/CsvWriter.h b/src/ObjWriting/Dumping/CsvWriter.h new file mode 100644 index 00000000..6bdcd979 --- /dev/null +++ b/src/ObjWriting/Dumping/CsvWriter.h @@ -0,0 +1,19 @@ +#pragma once +#include "Utils/FileAPI.h" + +class CsvWriter +{ + static constexpr char SEPARATOR = ','; + static const std::string LINE_BREAK; + + FileAPI::IFile* m_file; + unsigned m_column_count; + unsigned m_current_column; + bool m_first_row; + +public: + explicit CsvWriter(FileAPI::IFile* file); + + void WriteColumn(const std::string& value); + void NextRow(); +}; diff --git a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperFontIcon.cpp b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperFontIcon.cpp new file mode 100644 index 00000000..9207106a --- /dev/null +++ b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperFontIcon.cpp @@ -0,0 +1,244 @@ +#include "AssetDumperFontIcon.h" + +#include "Dumping/CsvWriter.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 = CommonT6::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_CREATE"), + 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_LOOK"), + KnownAlias("BUTTON_LOOKSTICK"), + KnownAlias("BUTTON_LUI_ALT1"), + KnownAlias("BUTTON_LUI_DPAD_RL"), + KnownAlias("BUTTON_LUI_DPAD_UD"), + KnownAlias("BUTTON_LUI_RIGHT_STICK"), + KnownAlias("BUTTON_LUI_SHOULDERR"), + KnownAlias("BUTTON_MOUSE_LEFT"), + KnownAlias("BUTTON_MOUSE_RIGHT"), + KnownAlias("BUTTON_MOVE"), + KnownAlias("BUTTON_MOVESTICK"), + 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_SELECTCHOICE"), + KnownAlias("BUTTON_SP_TOGGLEMENU"), + KnownAlias("BUTTON_YES"), + KnownAlias("CP"), + KnownAlias("KEY_DOWN_ARROW"), + KnownAlias("KEY_LEFT_ARROW"), + KnownAlias("KEY_RIGHT_ARROW"), + KnownAlias("KEY_UP_ARROW"), + KnownAlias("MOUSE_WHEEL_UP"), + KnownAlias("Remote_LStick") + }; + + CsvWriter m_csv; + + static FontIconEntry* FindEntryByHash(FontIcon* fontIcon, const int hash) + { + int lowerBound = 0; + int upperBound = fontIcon->numEntries; + + while (true) + { + const int entryIndex = (lowerBound + upperBound) / 2; + auto* entry = &fontIcon->fontIconEntry[entryIndex]; + + if (entry->fontIconName.hash == hash) + return entry; + + if (lowerBound == upperBound) + return nullptr; + + if (entry->fontIconName.hash < hash) + lowerBound = entryIndex + 1; + else + upperBound = entryIndex - 1; + } + } + + static const KnownAlias* FindKnownAliasByHash(const int hash) + { + for (unsigned i = 0; i < _countof(KNOWN_ALIASES); i++) + { + if (KNOWN_ALIASES[i].m_hash == hash) + return &KNOWN_ALIASES[i]; + } + + return nullptr; + } + + void WriteFontIconEntries(FontIcon* fontIcon) + { + for (const auto& header : ICON_HEADERS) + m_csv.WriteColumn(header); + m_csv.NextRow(); + + for (int iconIndex = 0; iconIndex < fontIcon->numEntries; iconIndex++) + { + 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(FontIcon* fontIcon) + { + for (const auto& header : ALIAS_HEADERS) + m_csv.WriteColumn(header); + m_csv.NextRow(); + + for (int aliasIndex = 0; aliasIndex < fontIcon->numAliasEntries; aliasIndex++) + { + 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 + { + std::ostringstream str; + str << '@' << std::hex << alias->aliasHash; + + m_csv.WriteColumn(str.str()); + } + + 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(FileAPI::IFile* file) + : m_csv(file) + { + } + + void DumpFontIcon(FontIcon* fontIcon) + { + WriteFontIconEntries(fontIcon); + m_csv.NextRow(); + + WriteFontIconAliases(fontIcon); + } +}; + +bool AssetDumperFontIcon::ShouldDump(FontIcon* asset) +{ + return true; +} + +std::string AssetDumperFontIcon::GetFileNameForAsset(Zone* zone, FontIcon* asset) +{ + return std::string(asset->name); +} + +void AssetDumperFontIcon::DumpAsset(Zone* zone, FontIcon* asset, FileAPI::File* out) +{ + AssetDumperFontIconInternal dumper(out); + dumper.DumpFontIcon(asset); +} diff --git a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperFontIcon.h b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperFontIcon.h new file mode 100644 index 00000000..f2402dfc --- /dev/null +++ b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperFontIcon.h @@ -0,0 +1,12 @@ +#pragma once + +#include "Dumping/AbstractAssetDumper.h" +#include "Game/T6/T6.h" + +class AssetDumperFontIcon final : public AbstractAssetDumper +{ +protected: + bool ShouldDump(T6::FontIcon* asset) override; + std::string GetFileNameForAsset(Zone* zone, T6::FontIcon* asset) override; + void DumpAsset(Zone* zone, T6::FontIcon* asset, FileAPI::File* out) override; +}; \ No newline at end of file diff --git a/src/ObjWriting/Game/T6/ZoneDumperT6.cpp b/src/ObjWriting/Game/T6/ZoneDumperT6.cpp index 2e487a84..8dd7de35 100644 --- a/src/ObjWriting/Game/T6/ZoneDumperT6.cpp +++ b/src/ObjWriting/Game/T6/ZoneDumperT6.cpp @@ -1,4 +1,5 @@ #include "ZoneDumperT6.h" + #include "Game/T6/GameT6.h" #include "Game/T6/GameAssetPoolT6.h" @@ -9,6 +10,7 @@ #include "AssetDumpers/AssetDumperStringTable.h" #include "AssetDumpers/AssetDumperLocalizeEntry.h" #include "AssetDumpers/AssetDumperGfxImage.h" +#include "AssetDumpers/AssetDumperFontIcon.h" bool ZoneDumperT6::CanHandleZone(Zone* zone) const { @@ -44,7 +46,7 @@ bool ZoneDumperT6::DumpZone(Zone* zone, const std::string& basePath) const // DUMP_ASSET_POOL(AssetDumperGfxWorld, m_gfx_world); // DUMP_ASSET_POOL(AssetDumperGfxLightDef, m_gfx_light_def); // DUMP_ASSET_POOL(AssetDumperFont, m_font); - // DUMP_ASSET_POOL(AssetDumperFontIcon, m_font_icon); + DUMP_ASSET_POOL(AssetDumperFontIcon, m_font_icon); // DUMP_ASSET_POOL(AssetDumperMenuList, m_menu_list); // DUMP_ASSET_POOL(AssetDumperMenuDef, m_menu_def); DUMP_ASSET_POOL(AssetDumperLocalizeEntry, m_localize); diff --git a/src/ZoneCommon/Game/T6/CommonT6.cpp b/src/ZoneCommon/Game/T6/CommonT6.cpp index 5a57cfcd..b6d389b5 100644 --- a/src/ZoneCommon/Game/T6/CommonT6.cpp +++ b/src/ZoneCommon/Game/T6/CommonT6.cpp @@ -1,5 +1,7 @@ #include "CommonT6.h" +#include + int CommonT6::Com_HashKey(const char* str, const int maxLen) { if (str == nullptr) @@ -15,4 +17,23 @@ int CommonT6::Com_HashKey(const char* str, const int maxLen) } return hash ^ ((hash ^ (hash >> 10)) >> 10); +} + +int CommonT6::Com_HashString(const char* str, const int len) +{ + if (!str) + return 0; + + int result = 0x1505; + int offset = 0; + while(str[offset]) + { + if (len > 0 && offset >= len) + break; + + const int c = tolower(str[offset++]); + result = c + 33 * result; + } + + return result; } \ No newline at end of file diff --git a/src/ZoneCommon/Game/T6/CommonT6.h b/src/ZoneCommon/Game/T6/CommonT6.h index c80b4d5f..73e8e97a 100644 --- a/src/ZoneCommon/Game/T6/CommonT6.h +++ b/src/ZoneCommon/Game/T6/CommonT6.h @@ -4,4 +4,5 @@ class CommonT6 { public: static int Com_HashKey(const char* str, int maxLen); + static int Com_HashString(const char* str, int len); }; \ No newline at end of file