Шрифты

Есть проблема: TMP не особо дружит с Addressables. TMP предполагает, что шрифты хранятся в ресурсах и сделать их асинхронную загрузку не тривиально. Есть подробный пост в обсуждениях Unity, где расписаны все проблемы.
В этом же посте предлагается ряд решений, в моем случае почти все не сработали, но я расскажу что сработало:

  1. В билд добавляем только одну пустую сцену, все остальные сцены загружаем через Addressables. В этой пустой сцене не должно быть ссылок на шрифты.
  2. Шрифты не складываем в Resources, кладём куда-нибудь в другое место, и выносим в отдельный Asset Group, чтобы они не дублировались.
  3. Разбираемся с TMP Settings. В нем есть ссылка на шрифт по умолчанию. Её нужно удалять на время билда, чтобы шрифт не попал в основной билд. Можно делать это вручную, но я сделал это автоматическим скриптом:
    public class TmpSettingsCleaner : IPreprocessBuildWithReport
    {
        private static TMP_Settings tmpSettings;
        private static FieldInfo defaultFontField;
        private static object defaultFont;

        public int callbackOrder => 0;

        public void OnPreprocessBuild(BuildReport report)
        {
            tmpSettings = Resources.Load<TMP_Settings>("TMP Settings");
            defaultFontField = tmpSettings.GetType()
                .GetField("m_defaultFontAsset", BindingFlags.Instance | BindingFlags.NonPublic);
            defaultFont = defaultFontField!.GetValue(tmpSettings);
            Debug.Log($"Default TMP font was {defaultFont}, now it is null");
            defaultFontField.SetValue(tmpSettings, null);
        }
        
        [PostProcessBuild]
        public static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject)
        {
            defaultFontField.SetValue(tmpSettings, defaultFont);
            Debug.Log($"Restored default font {defaultFont}");
        }
    }

Про способы создания атласов:
В TMP есть два варианта создания атласа: статический и динамический. Я считаю, что для веб игр однозначно выигрывает динамический вариант, потому что он сильно уменьшает размер билда. Плюс, если в игре есть лидерборды, то для статического варианта нужно будет сразу добавлять в атлас все возможные символы, так как в именах игроков могут встретиться любые символы. И атлас получается огромный, особенно если шрифт поддерживает несколько языков.

Иконки в тексте (Sprite Asset)

Нам понадобилось добавить иконку ресурса в текст. Сложность в том, что у нас несколько локаций, в каждом будет свой ресурс. То есть <sprite name="gems_icons_3"> в пустыне – это рубин, а в другой локации это может быть мандарин или крышка от кока-колы.
Я реализовал это довольно просто с помощью прокси-ассета.

  1. Создал пустой SpriteAsset, назвал его Proxy
  2. В TMP Settings выставил Proxy как defaultSpriteAsset
  3. Добавил все нужные мне атласы с иконками в свойства локации, которую я подгружаю.
  4. После загрузки мира, добавляю иконки как fallbackSpriteAssets в Proxy:
var proxy = Resources.Load<TMP_SpriteAsset>("Sprite Assets/Proxy");
proxy.fallbackSpriteAssets.Add(currentWorld.Value.FontSprites.GemsIcons);

Таким образом, у меня в конкретной локации будут только иконки из этой локации, подгруженные асинхронно через Addressables. Единственный возможный минус, что не будет работать вставка символов через индекс, типа <sprite=3> , ну и ладно.