Syberia 3

Syberia 3

Not enough ratings
Заміна TMP-шрифтів у іграх на Unity
By art-kandy
Опис мого досвіду заміни TextMeshPro-шрифтів у іграх Syberia 3 та Syberia TWB.
2
2
   
Award
Favorite
Favorited
Unfavorite
Вступ




На минулому тижні я мав справу з двома різними випадками заміни TMP-шрифтів:
Syberia 3 - Unity 5.4.3
Syberia 4 (TWB) - Unity 2020.3.25
Вирішив занотувати своє дослідження та поділитися цією інформацією з іншими.


Структура файлів
Якщо відкрити файл ресурсів потрібної гри у UABEA (загалом це resource.asset, хоча може бути й інший файл, наприклад sharedassets0.assets), то можна помітити, що шрифти, згенеровані через TMP, представлені трьома файлами:
  • У MonoBehaviour-файлі зберігається інформація про шрифт (його гліфи), посилання на файли атласу, скрипта та матеріалу.
  • У Texture2D-файлі зберігається сам атлас шрифта (графічне представлення усіх потрібних гліфів). Їх опис (в якому місці текстури зберігається той чи інший гліф) міститься у MonoBehaviour-файлі.

  • У Material-файлі зберігається потрібна інформація про рендерінг шрифта у грі, зокрема посилання на шейдер.


Якщо нам треба відредагувати такий шрифт, то загалом потрібно змінити лише перші два файли.
Для цього ми маємо згенерувати новий атлас (Texture2D) із новими мета-даними (MetaBehaviour) і замінити їх в оригінальному файлі ресурсів. При цьому Texture2D-файл зміняється повністю, а от MetaBehaviour ми маємо замінити частково (лише інформацію про шрифт, його гліфи, але не посилання на інші файли).
Material-файл мені довелося редагувати лише в одному випадку, змінюючи товщину шрифта. Так як шрифт TMP зазвичай зберігається через SDF-алгоритм, то змінити його товщину не надто складно. Це можна зробити через параметр _WeightNormal.


І тут починається найцікавіше через відмінності між різними версіями Unity.

Щоб дізнатися версію рушія, відкрийте в UABEA файл globalgamemanagers і пошукайте в ньому безімений ресурс з типом BuildSettings. Потім прогляньте його (View Data) і знайдіть поле m_Version. Це і є версія Unity цієї гри.


Перший випадок (Syberia 3)
До Unity 2018 TMP ще не був влаштований, і потребувалося його довстановлювати окремо. Я не зміг знайти потрібну версію TMP, тож скористався найстарішою доступною на GitHub https://github.com/needle-mirror/com.unity.textmeshpro/releases/tag/1.0.25
  1. Встановив версію Unity 2017.4.40f1 (у ході експериментів вона мені підійшла найкраще для Syberia 3 та TMP 1.0.25).
  2. Створив порожній проєкт і скопіював у Assets теку з релізом TMP.
  3. Перейменував скопійовану папку на "TextMesh Pro".
  4. Запустив скрипт Package Resources/TMP Essential Resources.unitypackage.
  5. Потім імпортував у Assets потрібний шрифт (з доданою заздалегідь українізацією).
  6. Відкрив вікно Window -> TextMeshPro -> Font Asset Creator.


  7. Вказав потрібні параметри:
    • Font Size (інформацію про оригінальний шрифт я підгледів у оригінальному MonoBehaviour-файлі, див. п.12);
    • Font Padding (значення 5 підійшло для Syberia 3);
    • Packing Method (Optimum);
    • Atlas Resolution (варто збільшити, якщо не всі гліфи із вказаним розміром вміщаються у атлас);
    • Character Set (Custom Characters);
      Я використав такий набір, який можна у разі потреби зменшити (мені були потрібні діакритичні символи для Credits):
      1234567890-+/\|*_()[]@#$%&,:;.?!…"«»—'’~®°ÀÁÂÄĄÈÉÊÔÖÙÛÜÎÏÇŒŃŁŻàáâäąèéêôöùûüîïçœßńłżABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzАБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯабвгґдеєжзиіїйклмнопрстуфхцчшщьюя
    • Font Render Mode (SDF 16).
    Можливі значення Render Mode (підгледів через ndSpy у DLL-ці TMP):
    SMOOTH_HINTED = 4121,
    SMOOTH = 4117,
    COLOR_HINTED = 69656,
    COLOR = 69652,
    RASTER_HINTED = 4122,
    RASTER = 4118,
    SDF = 4134,
    SDF8 = 8230,
    SDF16 = 16422,
    SDF32 = 32806,
    SDFAA_HINTED = 4169,
    SDFAA = 4165


    Також в старих версіях можуть бути:
    0: SMOOTH_HINTED;
    1: SMOOTH;
    2: RASTER_HINTED;
    3: RASTER;
    6: SDF16;
    7: SDF32;
  8. Генерував атлас з потрібними мета-даними (Generate Font Atlas). Зберіг його (Save TextMeshPro Font Asset).
    Приклад нового атласу:


  9. Додав TMPText-об'єкт у сцену і вказав йому наш новий шрифт (щоб при збірці гри шрифт додався у ресурси).



  10. Тестові скрипти мають помилку при збірці, тому видалив їх:
    Tests/Runtime/TMP_RuntimeTests.cs

  11. Зібрав гру.


  12. Потім через UABEA я вийняв потрібні два файла шрифта (MonoBehaviour та Texture2D):
    • MonoBehaviour я вийняв через Export Raw та Export Dump. Також, якщо UABEA бачить всю структуру файлу, то дуже зручним є скопіювати структуру через Edit Data.
    • Texture2D вийняв через плагін UABEA (Plugins -> Export Texture).

  13. З заміною Texture2D файлу не виникає проблем (Plugins -> Import Texture).
  14. А от замінити MonoBehaviour може бути складно. Особливо якщо UABEA не бачить всю його структуру (як було в моєму випадку з Syberia 3).
    Якщо доступна вся структура файлу (не лише базовий клас), то достатньо скопіювати потрібні секції через Edit Data.
    Нас цікавлять секції:
    • m_fontInfo та m_glyphInfoList (у випадку старої версії, як у Syberia 3);
    • або m_FaceInfo, m_AtlasWidth і m_AtlasHeight (якщо змінювався розмір), m_GlyphTable, m_CharacterTable, m_UsedGlyphRects та m_FreeGlyphRects (у новіших версіях, як-то Syberia 4).

    Якщо структура недоступна, то прийдеться скористатися HEX-редактором. Я користуюся HxD.
    Вивантажуємо оригінальний файл через Export Raw, а потім його редагуємо у редакторі, замінюючи вказані вище секції значеннями з нової згенерованої версії.
    Структуру файлу можна підгледіти у файлах з теки "TextMesh Pro\Scripts\Runtime" з GitHub, зокрема TMP_FontAsset.cs.
    Не буду вдаватися в деталі редагування. Скажу тільки, що в моєму випадку найстаріша версія TMP, що я знайшов, мала іншу структуру, аніж в Syberia 3, і мені довелося вручну змінювати (скорочувати) дані (m_fontInfo був на 3 поля (12 байт) менший, а елементи m_glyphInfoList - на 1 поле (4 байта)).

    Зрозуміти, які саме поля були потрібні, допомогли експерименти з конвертацією байтів у флоути та аналіз, що могло додатися у нову версію TMP, а що було там раніше.
    Але є кращий спосіб: скористатися AssetStudioGUI і продивитися структуру MonoBehaviour-файлу там, вказавши шлях до Assembly-теки (зазвичай це тека Managed). Дякую Loki за інформацію.
    Замінити редагований файл у UABEA можна через Import Raw.


Другий випадок (Syberia 4)
Тут ситуація була значно простішою, адже TMP вже був влаштований у Unity.
  1. Встановив версію Unity 2023.3.25.
  2. Створив проєкт, імпортував підготовлений TTF-шрифт.
  3. Вибравши імпортований шрифт, через контекстне меню створив TMP Font Asset. У Inspector натиснув Update Atlas Texture.


  4. Згенерував атлас аналогічно випадку Syberia 3 (змінив тільки Font Render Mode на SDFAA_HINTED, адже він використовувався в оригінальному шрифті).
  5. Додав TMP Text об'єкт, зібрав гру, дістав ресурси (аналогічно попередньому випадку).
  6. Заміна аналогічна. Єдине, що було набагато легше працювати з MonoBehaviour, адже вся структура була доступна, і було достатньо скористатися "Edit Data"-функціоналом.


Fallback шрифтів
Також додам цікаву знахідку у Syberia 4. У TMP-шрифтів є fallback-функціонал. Тобто, якщо він не знаходить потрібний гліф, то перебирає по черзі шрифти вказані у секції m_FallbackFontAssetTable. Якщо ж і тих шрифтів недостатньо, то береться оригінальний TTF-шрифт, якщо той присутній у збірці.
Так у Syberia 4 реалізована локалізація шрифту (додана кирилиця, китайські та корейські ієрогліфи).
Так що за бажанням можна не замінювати оригінальний шрифт, а додати новий з кирилічними символами, та прописати його як fallback-шрифт в MonoBehaviour-файлі оригіналу.



Відео-посібник від Like a Bot
Також додаю чудове відео на основі цього посібника, яке підготував Like a Bot. Велике йому за це спасибі!



Сподіваюся, цей посібник комусь допоможе.
Дякую за увагу.



P.S.: Користуючись нагодою, додам посилання на мої українізатори:
https://steamcommunity.com/sharedfiles/filedetails/?id=3015494847
https://steamcommunity.com/sharedfiles/filedetails/?id=3015781158
https://steamcommunity.com/sharedfiles/filedetails/?id=3139448041
Також на сайті KULI:
Prince of Persia: The Lost Crown[kuli.com.ua]
Valiant Hearts: Coming Home[kuli.com.ua]

7 Comments
Шпрот🏳‍🌈 Jun 18 @ 9:51am 
Ще, певно, треба уточнити, що біхуйвори ці дампити краще в json, бо якщо дампити їх у txt, то в уйобі чи де ви там витягуєте і пакуєте ассети, вони потім не розпізнаватимуться.
Шпрот🏳‍🌈 Jun 18 @ 5:35am 
Файний посібник, дякую. Але було би чудово, якби ще навели приклад того, як саме додавати шрифт через fallback в monobehaviour, тобто що і як прописувати в ньому.

Наприклад, у грі, яку я перекладаю, в одному з асетів уже є потрібний ttf шрифт з усіма необхідними символами, але в атлас запхнули лише ту частину кирилиці, що використовується в російській лоці, а відсутні символи чомусь беруться з дефолтного нотосансу, який також є в одному з асетів у форматі ттф, хоча в фоллбеці потрібного монобіхейвора він не прописаний.
Fomka_Wyverno Feb 28 @ 4:19am 
посібник імба. Кращий просто!
art-kandy  [author] Feb 10 @ 2:28pm 
Дякую усім за подяку.
@Artie Bow Вибач за пізню відповідь. 4165 означає SDFAA. Я про це дізнався проглянувши код TMP у dnSpy. Додам можливі усі значення у посібник.
ToniCaru Feb 6 @ 11:45am 
:okey:
Artie Bow Jan 4 @ 2:49pm 
Ви створили дійсно гарний мануал, все описано легко і доступно. Цікаво, як ви дізналися про потрібний рендер (Font Render Mode), тому що в цьому полі я бачу лише цифрові позначення типу 4165. Спроби знайти розшифровку в інтернеті не мали успіху.
Amorten Dec 26, 2023 @ 9:02am 
Величезне дякую!