diff --git a/.vs/launch.vs.json b/.vs/launch.vs.json index fe373a718f..0e60a8ff56 100644 --- a/.vs/launch.vs.json +++ b/.vs/launch.vs.json @@ -152,6 +152,18 @@ "${workspaceRoot}/decompiler_out" ] }, + { + "type": "default", + "project": "CMakeLists.txt", + "projectTarget": "decompiler.exe (bin\\decompiler.exe)", + "name": "Decompiler - Jak 2 - Extract", + "args": [ + "${workspaceRoot}/decompiler/config/jak2_ntsc_v1.jsonc", + "${workspaceRoot}/iso_data", + "${workspaceRoot}/decompiler_out", + "--config-override \"{\\\"decompile_code\\\": false}\"" + ] + }, { "type": "default", "project": "CMakeLists.txt", diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index ae9f7d870c..7ce3a41e50 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -42,15 +42,15 @@ add_library(common util/DgoWriter.cpp util/diff.cpp util/FileUtil.cpp + util/FontUtils.cpp util/json_util.cpp util/read_iso_file.cpp util/SimpleThreadGroup.cpp util/Timer.cpp util/os.cpp util/print_float.cpp - util/FontUtils.cpp util/FrameLimiter.cpp - util/unicode_util.cpp) + util/unicode_util.cpp ) target_link_libraries(common fmt lzokay replxx libzstd_static) diff --git a/common/util/FontUtils.cpp b/common/util/FontUtils.cpp index 3f1bba4220..631b9dfaba 100644 --- a/common/util/FontUtils.cpp +++ b/common/util/FontUtils.cpp @@ -29,7 +29,8 @@ bool hex_char(char c) { const std::unordered_map sTextVerEnumMap = { {"jak1-v1", GameTextVersion::JAK1_V1}, - {"jak1-v2", GameTextVersion::JAK1_V2}}; + {"jak1-v2", GameTextVersion::JAK1_V2}, + {"jak2", GameTextVersion::JAK2}}; const std::string& get_text_version_name(GameTextVersion version) { for (auto& [name, ver] : sTextVerEnumMap) { @@ -157,6 +158,19 @@ std::string GameTextFontBank::convert_utf8_to_game(std::string str) const { return str; } +bool GameTextFontBank::valid_char_range(const char in) const { + if (m_version == GameTextVersion::JAK1_V1 || m_version == GameTextVersion::JAK1_V2) { + return ((in >= '0' && in <= '9') || (in >= 'A' && in <= 'Z') || + m_passthrus->find(in) != m_passthrus->end()) && + in != '\\'; + } else if (m_version == GameTextVersion::JAK2) { + return ((in >= '0' && in <= '9') || (in >= 'A' && in <= 'Z') || (in >= 'a' && in <= 'z') || + m_passthrus->find(in) != m_passthrus->end()) && + in != '\\'; + } + return false; +} + /*! * Turn a normal readable string into a string readable in the in-game font encoding and converts * \cXX escape sequences @@ -219,9 +233,7 @@ std::string GameTextFontBank::convert_game_to_utf8(const char* in) const { if (remap != nullptr) { result.append(remap->chars); in += remap->bytes.size() - 1; - } else if (((*in >= '0' && *in <= '9') || (*in >= 'A' && *in <= 'Z') || - m_passthrus->find(*in) != m_passthrus->end()) && - *in != '\\') { + } else if (valid_char_range(*in)) { result.push_back(*in); } else if (*in == '\n') { result += "\\n"; @@ -250,9 +262,9 @@ static std::vector s_replace_info_null = {}; * - Jak & Daxter: The Precursor Legacy (Black Label) */ -static std::unordered_set s_passthrus = {'~', ' ', ',', '.', '-', '+', '(', ')', - '!', ':', '?', '=', '%', '*', '/', '#', - ';', '<', '>', '@', '[', '_'}; +static std::unordered_set s_passthrus_jak1 = {'~', ' ', ',', '.', '-', '+', '(', ')', + '!', ':', '?', '=', '%', '*', '/', '#', + ';', '<', '>', '@', '[', '_'}; static std::vector s_encode_info_jak1 = { // random @@ -578,10 +590,10 @@ static std::vector s_replace_info_jak1 = { {"~Y~22L<~Z~Y~24L#~Z~Y~1L>~Z~Y~23L[~Z~+26H", ""}, // custom }; -GameTextFontBank g_font_bank_jak1(GameTextVersion::JAK1_V1, - &s_encode_info_jak1, - &s_replace_info_jak1, - &s_passthrus); +GameTextFontBank g_font_bank_jak1_v1(GameTextVersion::JAK1_V1, + &s_encode_info_jak1, + &s_replace_info_jak1, + &s_passthrus_jak1); /*! * ================================ @@ -815,12 +827,216 @@ static std::vector s_encode_info_jak1_v2 = { GameTextFontBank g_font_bank_jak1_v2(GameTextVersion::JAK1_V2, &s_encode_info_jak1_v2, &s_replace_info_jak1, - &s_passthrus); + &s_passthrus_jak1); + +/*! + * ================================ + * GAME TEXT FONT BANK - JAK 2 + * ================================ + * This font is used in: + * - Jak 2 - NTSC - v1 + */ + +static std::unordered_set s_passthrus_jak2 = {'~', ' ', ',', '.', '-', '+', '(', ')', + '!', ':', '?', '=', '%', '*', '/', '#', + ';', '<', '>', '@', '[', '_'}; + +static std::vector s_replace_info_jak2 = { + // other + {"A~Y~-21H~-5Vº~Z", "Å"}, + {"N~Y~-6Hº~Z~+10H", "Nº"}, + {"~+4VÇ~-4V", "ç"}, + + // tildes + {"N~Y~-22H~-4V~Z", "Ñ"}, + {"n~Y~-24H~-4V~Z", "ñ"}, + {"A~Y~-21H~-5V~Z", "Ã"}, // custom + {"O~Y~-22H~-4V~Z", "Õ"}, // custom + + // acute accents + {"A~Y~-21H~-5V'~Z", "Á"}, + {"a~Y~-25H~-5V'~Z", "á"}, + {"E~Y~-23H~-9V'~Z", "É"}, + {"e~Y~-26H~-5V'~Z", "é"}, + {"I~Y~-19H~-5V'~Z", "Í"}, + {"i~Y~-19H~-8V'~Z", "í"}, + {"O~Y~-22H~-4V'~Z", "Ó"}, + {"o~Y~-26H~-4V'~Z", "ó"}, + {"U~Y~-24H~-3V'~Z", "Ú"}, + {"u~Y~-24H~-3V'~Z", "ú"}, + + // circumflex + {"A~Y~-20H~-4V^~Z", "Â"}, // custom + {"a~Y~-24H~-5V^~Z", "â"}, + {"E~Y~-20H~-5V^~Z", "Ê"}, + {"e~Y~-25H~-4V^~Zt", "ê"}, + {"I~Y~-19H~-5V^~Z", "Î"}, + {"i~Y~-19H~-8V^~Z", "î"}, + {"O~Y~-20H~-4V^~Z", "Ô"}, // custom + {"o~Y~-25H~-4V^~Z", "ô"}, + {"U~Y~-24H~-3V^~Z", "Û"}, + {"u~Y~-23H~-3V^~Z", "û"}, + + // grave accents + {"A~Y~-26H~-8V`~Z", "À"}, + {"a~Y~-25H~-5V`~Z", "à"}, + {"E~Y~-23H~-9V`~Z", "È"}, + {"e~Y~-26H~-5V`~Z", "è"}, + {"I~Y~-19H~-5V`~Z", "Ì"}, + {"i~Y~-19H~-8V`~Z", "ì"}, + {"O~Y~-22H~-4V`~Z", "Ò"}, // custom + {"U~Y~-24H~-3V`~Z", "Ù"}, + {"u~Y~-24H~-3V`~Z", "ù"}, + + // umlaut + {"A~Y~-26H~-8V¨~Z", "Ä"}, + {"a~Y~-25H~-5V¨~Z", "ä"}, + {"E~Y~-20H~-5V¨~Z", "Ë"}, + {"I~Y~-19H~-5V¨~Z", "Ï"}, // custom + {"O~Y~-26H~-8V¨~Z", "Ö"}, + {"o~Y~-26H~-4V¨~Z", "ö"}, + {"U~Y~-25H~-8V¨~Z", "Ü"}, + {"u~Y~-24H~-3V¨~Z", "ü"}, + + // dakuten katakana + {"~Yウ~Z゛", "ヴ"}, + {"~Yカ~Z゛", "ガ"}, + {"~Yキ~Z゛", "ギ"}, + {"~Yク~Z゛", "グ"}, + {"~Yケ~Z゛", "ゲ"}, + {"~Yコ~Z゛", "ゴ"}, + {"~Yサ~Z゛", "ザ"}, + {"~Yシ~Z゛", "ジ"}, + {"~Yス~Z゛", "ズ"}, + {"~Yセ~Z゛", "ゼ"}, + {"~Yソ~Z゛", "ゾ"}, + {"~Yタ~Z゛", "ダ"}, + {"~Yチ~Z゛", "ヂ"}, + {"~Yツ~Z゛", "ヅ"}, + {"~Yテ~Z゛", "デ"}, + {"~Yト~Z゛", "ド"}, + {"~Yハ~Z゛", "バ"}, + {"~Yヒ~Z゛", "ビ"}, + {"~Yフ~Z゛", "ブ"}, + {"~Yヘ~Z゛", "ベ"}, + {"~Yホ~Z゛", "ボ"}, + // handakuten katakana + {"~Yハ~Z゜", "パ"}, + {"~Yヒ~Z゜", "ピ"}, + {"~Yフ~Z゜", "プ"}, + {"~Yヘ~Z゜", "ペ"}, + {"~Yホ~Z゜", "ポ"}, + // dakuten hiragana + {"~Yか~Z゛", "が"}, + {"~Yき~Z゛", "ぎ"}, + {"~Yく~Z゛", "ぐ"}, + {"~Yけ~Z゛", "げ"}, + {"~Yこ~Z゛", "ご"}, + {"~Yさ~Z゛", "ざ"}, + {"~Yし~Z゛", "じ"}, + {"~Yす~Z゛", "ず"}, + {"~Yせ~Z゛", "ぜ"}, + {"~Yそ~Z゛", "ぞ"}, + {"~Yた~Z゛", "だ"}, + {"~Yち~Z゛", "ぢ"}, + {"~Yつ~Z゛", "づ"}, + {"~Yて~Z゛", "で"}, + {"~Yと~Z゛", "ど"}, + {"~Yは~Z゛", "ば"}, + {"~Yひ~Z゛", "び"}, + {"~Yふ~Z゛", "ぶ"}, + {"~Yへ~Z゛", "べ"}, + {"~Yほ~Z゛", "ぼ"}, + // handakuten hiragana + {"~Yは~Z゜", "ぱ"}, + {"~Yひ~Z゜", "ぴ"}, + {"~Yふ~Z゜", "ぷ"}, + {"~Yへ~Z゜", "ぺ"}, + {"~Yほ~Z゜", "ぽ"}, + // japanese punctuation + {",~+8H", "、"}, + {"~+8H ", " "}, + + // (hack) special case kanji + {"~~", "世"}, + + // playstation buttons + {"~Y~22L<~Z~Y~27L*~Z~Y~1L>~Z~Y~23L[~Z~+26H", ""}, + {"~Y~22L<~Z~Y~26L;~Z~Y~1L>~Z~Y~23L[~Z~+26H", ""}, + {"~Y~22L<~Z~Y~25L@~Z~Y~1L>~Z~Y~23L[~Z~+26H", ""}, + {"~Y~22L<~Z~Y~24L#~Z~Y~1L>~Z~Y~23L[~Z~+26H", ""}, // custom + {"~Y~22L~-2H~-12V\\ca6\\ca7~Z~22L~-2H~+17V\\cb0\\cb1~Z~1L~+4H~+3V\\c95~Z~+38H", ""}, + {"~Y~22L~-2H~-12V\\ca6\\ca7~Z~22L~-2H~+17V\\cb0\\cb1~Z~1L~+6H~+3V\\c94~Z~+38H", ""}, + {"~Y~22L\\ca1~Z~3L~+17H~-13V\\ca2~Z~22L~+17H~+14V\\ca0~Z~22L~+32H\\ca3~Z~+56H", + ""}, + {"~Y~22L\\ca1~Z~3L~+17H~-13V\\ca2~Z~3L~+17H~+14V\\ca0~Z~22L~+32H\\ca3~Z~+56H", + ""}, + {"~Y~22L~-2H~-6V\\ca8\\ca9~Z~22L~-2H~+16V\\cb2\\cb3~Z~1L~+5H~-2V\\c96~Z~+38H", ""}, + {"~Y~22L~-2H~-6V\\ca8\\ca9~Z~22L~-2H~+16V\\cb2\\cb3~Z~1L~+5H~-2V\\c97~Z~+38H", ""}, + {"~1L~+8H~Y\\c91~Z~6L~-16H\\c9e~Z~+16h~6L\\ca4~Z~6L~-15V\\c9c~Z~+13V~6L\\c98~Z~-10H~+9V~" + "6L\\c9f~Z~+10H~+9V~6L\\c99~Z~-10H~-11V~6L\\c9d~Z~+10H~-11V~6L\\ca5~Z~+32H", + ""}, + {"~Y~1L~+8H\\c91~Z~6L~-8H\\c9e~Z~+24H~6L\\ca4~Z~+40H", ""}, + {"~Y~1L\\c91~Z~6L~-15V\\c9c~Z~+13V~6L\\c98~Z~+26H", ""}, + // TODO + // - ~Y~22L\ca1~Z~22L~+17H~-13V\ca2~Z~22L~+17H~+14V\ca0~Z~22L~+32H\ca3~Z~+56H + // - ~Y~6L<~Z~Y~1L>~Z~Y~23L[~Z~+26H + // - ~Y~3L<~Z~Y~1L>~Z~Y~23L[~Z~+26H + // - ~Y~1L\c85~Z~3L\c8c~Z~7L\c8e~\c5d~-1H~Y~1L\c85~Z~3L\c8d~Z~7L\c8f~Z~+26H + // - ~Y~3L<~Z~Y~1L>~Z~Y~23L[~Z~+26H + // - ~Y~1L\c85~\c5d~-1H~Y~1L\c85~Z~-11H~3L\c86~Z~+26H + + // flags + {"~Y~6L\\c81~Z~+15H~1L\\c81~Z~+30H~3L\\c81~Z~+45H", ""}, + {"~Y~5L\\c85~Z~3L\\c8b~\\c5d~-1H~Y~5L\\c85~Z~3L\\c8b~Z~+26H", ""}, + {"~Y~39L~~~Z~3L\\c7f~Z~5L\\c80~\\c5d~-1H~Y~39L~~~Z~3L\\c7f~Z~5L\\c80~Z~+26H", + ""}, + {"~Y~7L\\c81~Z~+15H~1L\\c81~Z~+30H~3L\\c81~Z~+47H", ""}, + {"~Y~1L\\c85~Z~3L\\c9a~Z~7L\\c9b~\\c5d~-1H~Y~1L\\c85~Z~3L\\c90~Z~+26H", ""}, + {"~Y~1L\\c85~Z~39L\\c87~\\c5d~-1H~Y~1L\\c85~Z~39L\\c88~Z~-11H~7L\\c8a~Z~-11H~3L\\c89~Z~+26H", ""}, + {"~Y~1L\\c85~\\c5d~-1H~Y~1L\\c85~Z~-11H~3L\\c86~Z~+26H", ""}, + + // weird stuff + // - some sort of control character to adjust kerning, ie after `i` and `o`? + {"~+7V", ""}, + // - preceeding character has a descender? + {"~-7V", ""}, + // - i wonder if this is just a generic code to say "push the next character up or down + // vertically"? + {"~+1V", ""}, + {"~-1V", ""}, + + {"~-4H~-3V\\c19~+3V~-4H", + ""}, // used for the 4<__> place in spanish. the 5th uses the same + // character but looks different...? + {"~Y~-6Hº~Z~+10H", "°"}, + {"\\c5e", "œ"}, // ligature o+e + + // Color / Emphasis + {"~[~1L", ""}, + {"~[~32L", ""}}; + +static std::vector s_encode_info_jak2 = { + {"_", {0x03}}, // large space + {"ˇ", {0x10}}, // caron + {"`", {0x11}}, // grave accent + {"'", {0x12}}, // apostrophe + {"^", {0x13}}, // circumflex + {"", {0x14}}, // tilde + {"¨", {0x15}}, // umlaut + {"º", {0x16}}, // numero/overring + {"¡", {0x17}}, // inverted exclamation mark + {"¿", {0x18}}, // inverted question mark + {"Ç", {0x1d}}, // c-cedilla + + {"ß", {0x1f}}, // eszett + +}; GameTextFontBank g_font_bank_jak2(GameTextVersion::JAK2, - &s_encode_info_null, - &s_replace_info_null, - &s_passthrus); + &s_encode_info_jak2, + &s_replace_info_jak2, + &s_passthrus_jak2); /*! * ======================== @@ -830,7 +1046,7 @@ GameTextFontBank g_font_bank_jak2(GameTextVersion::JAK2, */ std::map g_font_banks = { - {GameTextVersion::JAK1_V1, &g_font_bank_jak1}, + {GameTextVersion::JAK1_V1, &g_font_bank_jak1_v1}, {GameTextVersion::JAK1_V2, &g_font_bank_jak1_v2}, {GameTextVersion::JAK2, &g_font_bank_jak2}}; diff --git a/common/util/FontUtils.h b/common/util/FontUtils.h index fa23ddde2d..3d167fc150 100644 --- a/common/util/FontUtils.h +++ b/common/util/FontUtils.h @@ -75,6 +75,10 @@ class GameTextFontBank { GameTextVersion version() const { return m_version; } + // TODO - methods would help make this code a lot better for different game versions + // hacking it for now + bool valid_char_range(const char in) const; + std::string convert_utf8_to_game_with_escape(const std::string& str) const; std::string convert_utf8_to_game(std::string str) const; std::string convert_game_to_utf8(const char* in) const; diff --git a/decompiler/config/jak2_ntsc_v1.jsonc b/decompiler/config/jak2_ntsc_v1.jsonc index b029010592..ad42a3b90e 100644 --- a/decompiler/config/jak2_ntsc_v1.jsonc +++ b/decompiler/config/jak2_ntsc_v1.jsonc @@ -35,7 +35,7 @@ // unpack textures to assets folder "process_tpages": false, // unpack game text to assets folder - "process_game_text": false, + "process_game_text": true, // unpack game count to assets folder "process_game_count": true, // write goal imports for art groups