Трудности перевода Yakuza 5: Как взлом шрифтов и переход на 1-байт помогли мне избавить игру от вылетов и выпустить рабочую Альфу 0.3

Трудности перевода Yakuza 5: Как взлом шрифтов и переход на 1-байт помогли мне избавить игру от вылетов и выпустить рабочую Альфу 0.3

В последний раз я подавал признаки жизни 24 апреля. Почти месяц полной тишины в эфире.

Если кто-то думал, что я забросил перевод Yakuza 5 — нет. Я просто медленно сходил с ума, пытаясь подружить капризный японский движок 2012 года с русской кириллицей. И вот на днях на моём Boosty наконец-то вышло обновление: Билд 0.3 Alpha.

Трудности перевода Yakuza 5: Как взлом шрифтов и переход на 1-байт помогли мне избавить игру от вылетов и выпустить рабочую Альфу 0.3

Под капотом этой сборки скрывается самый сложный и выматывающий технический этап за всё время работы — переход на однобайтовую кодировку (Latin-1).

Зачем мне вообще понадобился этот безумный костыль? UTF-8, конечно, использовать было можно. Но на практике это превратилось в ад: пришлось бы переписывать кодирование под каждый отдельный формат файлов в игре. К тому же сам движок Yakuza 5 выделяет под текстовые строки катастрофически мало оперативной памяти. Длинный русский текст в UTF-8 просто взрывал буферы.

В итоге однобайтовый хак (где 1 русская буква весит строго 1 байт) стал единственным спасением. Он дал мне суперсилу — использовать метод In-place (запись перевода прямо поверх оригинальных байт) в тех сложных системных файлах, структуру которых я физически не мог расковырять. Например, там, где было невозможно найти или безопасно перенаправить указатели. Это банально в разы безопаснее, стабильнее для движка, да и файлы весят меньше (хотя размер тут дело десятое).

Трудности перевода Yakuza 5: Как взлом шрифтов и переход на 1-байт помогли мне избавить игру от вылетов и выпустить рабочую Альфу 0.3

Но этот месяц работы был по-настоящему мучительным. Я переписывал свой парсер сотни раз, крутясь по кругу и ломая голову над одними и теми же багами. Самым невыносимым было то, что реплика выводилась на экран на чистом русском, но игра наотрез отказывалась показывать кнопку перехода к следующему диалогу. Из-за этого зависал весь файл сценария, а если это был сюжетный квест — намертво вешалась вся игра. Это — главный минус и главная боль однобайтовой кодировки, из-за которой мне пришлось пережить тонну рутины.

В итоге я прошёл полный круг и вернулся практически к той логике парсера, с которой начинал, но только максимально вычищенной и оптимизированной. Но самое главное — всё это наконец-то стабильно(почти) работает!

Ниже я во всех подробностях разберу всю эту бинарную кухню: как именно перекраивался шрифт, по какому принципу велась замена символов и почему мне пришлось переписать половину собственного переводческого инструментария.

⚙ Анатомия текста в Yakuza: почему стандартные методы не работают

Для начала пара слов о том, как движок Yakuza 5 вообще работает с текстом. В любом бинарном файле игры (будь то диалоги .msg или базы данных меню .bin) строки хранятся в виде блоков байтов, на которые ссылаются указатели (адреса) из заголовка файла.

При переводе такой структуры у переводчика есть два пути:

  1. In-place (Запись на месте): Оригинальные английские буквы затираются русскими. Это самый безопасный метод, потому что структура файла и адреса в заголовке остаются абсолютно нетронутыми. Но перевод здесь жёстко ограничен длиной английского оригинала.
  2. Append (Запись в конец): Если перевод длиннее оригинала, строка дописывается в самый конец файла (в свободную зону), а в заголовке разыскивается указатель и перенаправляется на этот новый адрес.

И вот тут стандартная кодировка UTF-8, которая используется в 99% современных русификаторов, превращается в мину замедленного действия.

Дело в том, что в UTF-8 английские буквы весят по 1 байту, а русская кириллица — по 2 байта (а иногда и по 3 с форматированием).

Простой пример: слово Save (4 буквы — 5 байт с нуль-терминатором в конце). На русском это Сохранение. В UTF-8 это слово сожрёт 21 байт.Уместить 21 байт на место 5 байт методом In-place физически невозможно. Приходится делать Append — переносить строку в конец файла и обновлять указатели в заголовке.

Но в Yakuza 5 есть десятки файлов баз данных, меню и специфических скриптов, структуру заголовков которых расковырять до конца невероятно сложно. Найти там все скрытые указатели, которые ссылаются на оригинальные текстовые блоки — адский труд. Если пропустить хотя бы один указатель, игра попытается прочитать текст по старому адресу, наткнётся на пустоту или кашу из байтов и намертво вылетит.

Трудности перевода Yakuza 5: Как взлом шрифтов и переход на 1-байт помогли мне избавить игру от вылетов и выпустить рабочую Альфу 0.3

Именно здесь на сцену выходит однобайтовая кодировка (Latin-1).

В Latin-1 слово Сохранение весит ровно 11 байт (вместо 21 в UTF-8!). Благодаря этому колоссальное количество фраз влезает методом In-place прямо на место оригинала. Мне больше не нужно искать скрытые указатели в сложных бинарниках — я просто перезаписываю русский текст поверх английского, и движок игры съедает его без единого вылета. А там, где длина всё-таки превышена и приходится делать Append, файлы весят в два раза меньше, что экономит драгоценную память консольного движка

🎨 Камуро-Дизайн: мой автоматический шрифтовой конвейер

Просто заменить кодировку в Python-скриптах — это только половина дела. Как заставить саму игру рисовать русские буквы вместо французских умляутов или немецких символов вроде ß? Ведь если я пишу перевод в Latin-1, игра по умолчанию попытается нарисовать символ À вместо нашей А.

Трудности перевода Yakuza 5: Как взлом шрифтов и переход на 1-байт помогли мне избавить игру от вылетов и выпустить рабочую Альфу 0.3

Разгадка крылась в текстуре шрифта игры — файле sd_hankaku.dds. Это обычная двухмерная картинка, на которой ровной сеткой расположены все системные символы.

Сначала я залез в графический редактор GIMP, просто чтобы поэкспериментировать. Настроив там точную пиксельную сетку, я обнаружил важную штуку: буквы идеально вписываются в ячейки 16x16. Но поскольку я совершенно не умею пользоваться всеми этими сложными профессиональными редакторами и рисовать каждую букву вручную — я пошёл по пути программиста.

Я полностью переписал и модернизировал собственный плагин «Камуро-Дизайн» (85_kamuro_design.py), превратив его в полноценный автоматический шрифтовой конвейер.

Теперь мне не нужно ничего рисовать руками. По нажатию всего одной кнопки мой плагин сам считывает все подмены из утилит text_utils.py, берёт выбранный векторный TTF/OTF шрифт, применяет к нему тонкие геометрические настройки (сжатие ширины, растяжение высоты, отступы и смещения по осям X/Y) и автоматически за долю секунды отрисовывает всю русскую кириллицу прямо в DDS-текстуру игры! Я немного поигрался с расположением букв, настройкой сжатия и смещениями, и в итоге шрифт стал выглядеть практически идеально — буквы больше не накладываются друг на друга и отлично читаются в диалогах.

Для визуального контроля всей этой бинарной сетки я создал интерактивную HTML-карту kamuro_map.html (она лежит по пути 04_ANALYSIS_REPORTS/docs/kamuro_map.html). Это мой личный интерактивный атлас шрифта, где можно открыть страницу в браузере, навести курсор на любую ячейку и мгновенно увидеть её HEX-адрес и символ подмены.

Трудности перевода Yakuza 5: Как взлом шрифтов и переход на 1-байт помогли мне избавить игру от вылетов и выпустить рабочую Альфу 0.3

Конечно, не обошлось без странных бинарных аномалий, которые потрепали мне нервы. В обычных рядах символов всё шло ровно и соответствовало стандарту Latin-1. Но в рядах A и B (диапазон байтов 0xA0 - 0xBF) обнаружился непонятный сдвиг ровно на 1 байт в сторону. Из-за этого символы уходили на одну ячейку левее или правее, ломая маппинг (например, Иена, которая по стандарту должна быть на 0xA5, вела себя непредсказуемо, улетая на 0xA6). Я так до конца и не понял, было ли это ошибкой стандартов, хитрой задумкой движка или косяком оригинальных японских авторов текстуры, но этот сдвиг в один байт стал ещё одной неприятной загадкой, которую мне пришлось решать при настройке авто-отрисовки в плагине.

Для обложки статьи на DTF я, скорее всего, выберу один из своих свежих внутриигровых скриншотов — генерировать какую-то особую картинку мне сейчас банально лень, да и настоящие кадры из игры лучше всего показывают реальное положение дел.

А показать мне есть что, ведь у этого сложного перехода на 1-байтовую кодировку есть свои весомые плюсы, суровые минусы и компромиссы, на которые мне пришлось пойти ради стабильности.

➕ Плюсы: скорость и железный In-place

Главный триумф этой сборки — масштабная статистика компиляции по всей игре. Мой новый компилятор успешно обработал 5 214 бинарных файлов и внедрил в игру 81 025 строк перевода (на основе базы из 68 209 уникальных строк словаря)!

При этом более 70 200 строк сели по своим оригинальным адресам (In-place) без изменения структуры файлов, а опасных наложений указателей в Append-зоне по всем пяти тысячам файлов — строго ноль. Вся игра теперь полностью пересобирается с нуля примерно за 14 минут , хотя раньше на один только кривой проход уходило до 4 часов.

Разработка шрифта тоже перестала быть ночным кошмаром. Мне ещё предстоит найти системный файл игры, в котором прописаны точные межсимвольные интервалы и отступы (кернинг), но даже без этих настроек мой шрифт Камуро-Дизайн выглядит на экране отлично, буквы не накладываются друг на друга и прекрасно читаются в диалогах.

➖ Минусы и компромиссы: визуальные жертвы ради стабильности

Самая заметная проблема — это наложение символов на системные знаки. Поскольку кириллица заняла ячейки оригинальных ASCII-символов, игра выводит русские буквы там, где раньше стояли знаки.

И здесь мы натыкаемся на самую забавную историческую бинарную аномалию с байтом 0x5C, которая потрепала мне немало нервов:

  • Теория (ASCII / Latin-1): В стандартной международной таблице символов под кодом 0x5C всегда находился обратный слеш \. Хаб в коде видит этот байт именно так.
  • Практика (Shift-JIS): В японских кодировках (JIS X 0201) разработчики ещё в 80-х годах принудительно заменили обратный слеш \ на знак Иены ¥ на том же самом байте 0x5C. С тех пор на всех японских компьютерах и в играх любой обратный слеш в коде движок игры автоматически читает и рисует как Иену. Именно поэтому художники SEGA на оригинальной текстуре sd_hankaku.dds в ячейке 0x5C нарисовали Иену, а не слеш (как видно на моём втором скриншоте).
  • Что пошло не так: При создании русского шрифта ячейка 0x5C была единственным логичным местом, куда я мог посадить русскую букву у. Но системный код игры (например, счётчик денег в углу экрана) по-прежнему выводит оригинальный байт 0x5C для обозначения валюты. В итоге на экране вместо Иены рисуется буква у (например, у30,000 в деньгах).
Трудности перевода Yakuza 5: Как взлом шрифтов и переход на 1-байт помогли мне избавить игру от вылетов и выпустить рабочую Альфу 0.3
Трудности перевода Yakuza 5: Как взлом шрифтов и переход на 1-байт помогли мне избавить игру от вылетов и выпустить рабочую Альфу 0.3

Похожая беда случилась и с другими системными символами:

  • Русская ы заняла место дефиса - (0x2D). Из-за этого даты сохранений теперь пишутся как 2026ы05ы20.
  • Русская т заняла место плюс-символа + (0x2B).
Трудности перевода Yakuza 5: Как взлом шрифтов и переход на 1-байт помогли мне избавить игру от вылетов и выпустить рабочую Альфу 0.3
Трудности перевода Yakuza 5: Как взлом шрифтов и переход на 1-байт помогли мне избавить игру от вылетов и выпустить рабочую Альфу 0.3
Трудности перевода Yakuza 5: Как взлом шрифтов и переход на 1-байт помогли мне избавить игру от вылетов и выпустить рабочую Альфу 0.3

Почему я оставил это так? Потому что если попытаться запустить автозамену байтов 0x5C (слеш) или 0x2D (дефис) по всем системным бинарникам игры, программа неизбежно затрёт важные структурные смещения в заголовках файлов и намертво сломает игру. Оставить временные буквы вместо знаков оказалось единственным безопасным решением для первой альфа-версии.

Кроме того, этот месяц работы был по-настоящему мучительным. Мне пришлось переписать свой парсер сотни раз, крутясь по кругу и ломая голову над одними и теми же багами. Самым невыносимым было то, что реплика выводилась на экран на чистом русском, но игра наотрез отказывалась показывать кнопку перехода к следующему диалогу (кнопки [A] или [E]). Из-за этого зависал весь файл сценария, а если это был сюжетный квест — намертво вешалась вся игра. Это — главный минус и главная боль однобайтовой кодировки, из-за которой мне пришлось пережить тонну рутины.

Ради стабильности мне также пришлось пойти на жёсткие косметические жертвы:

  • Я полностью вырезал все теги цвета и курсива из словаря диалогов. Сейчас весь текст идёт стандартным сплошным цветом. Это сугубо декоративный момент — как только я буду уверен в стабильности на 100%, я смогу легко вернуть выделения обратно, но сейчас рисковать лишними ошибками не имеет смысла.
  • Я не стал возвращать кавычки-ёлочки. Они тоже потенциально могли сломать парсер, и я просто не стал рисковать.
  • Пришлось спасать теги действий (<Action:...>): Без специальной защиты в кодере эти теги кодировались в кириллицу и выводились на экран в виде гигантского текста на пол-экрана вместо красивых круглых кнопок геймпада.
Трудности перевода Yakuza 5: Как взлом шрифтов и переход на 1-байт помогли мне избавить игру от вылетов и выпустить рабочую Альфу 0.3

Самый главный минус — на этой кодировке все старые переведённые плагины и системные .bin файлы больше не подходят, их придётся пересобирать заново под новую кодовую страницу.

Бывало и такое. Есть шанс, что починилось, но возможно и нет. По крайней мере, "подозрительный" будет с переводом.
Бывало и такое. Есть шанс, что починилось, но возможно и нет. По крайней мере, "подозрительный" будет с переводом.

Но если искать в этом положительные стороны: в тех старых файлах и базах данных и без того хватало скрытых багов. Этот вынужденный старт с чистого листа позволит мне заново перепроверить, вычистить и пересобрать все ресурсы игры на моих новых, гораздо более стабильных и безопасных инструментах.

🎬 Заключение и что дальше

Подводя итог этой безумной трёхнедельной эпопее, я могу сказать одно: технический барьер, который долгое время казался непреодолимым, наконец-то взломан. Переход на однобайтовую кодировку дался мне тяжело, но теперь у меня на руках есть стабильный, гибкий и невероятно быстрый инструментарий, который позволяет собирать файлы за минуты, а не за часы.

Альфа 0.3 — это только начало новой, стабильной главы перевода Yakuza 5. Впереди ещё много работы: нужно пересобрать базы данных .bin, дочистить мелкие меню, вернуть красивые цветные теги в диалоги и, наконец, найти тот самый конфигурационный файл разметки шрифтов, чтобы настроить идеальные межсимвольные отступы. Но теперь я точно знаю, что это лишь вопрос времени, а не технических ограничений движка.

Если вы хотите протестировать свежую сборку, помочь мне с поиском скрытых вылетов или просто следить за разработкой в реальном времени — добро пожаловать на мои ресурсы:

Огромное спасибо всем, кто поддерживает меня на Бусти и верит в этот русификатор. Ваша поддержка — это то, что заставляет меня продолжать копаться в бинарных недрах игры даже тогда, когда хочется всё бросить.

Играйте в хорошие игры, не бойтесь безумных технических костылей и до встречи в новых девлогах!

Трудности перевода Yakuza 5: Как взлом шрифтов и переход на 1-байт помогли мне избавить игру от вылетов и выпустить рабочую Альфу 0.3

🏷 Теги:

30
9
1
1