Update Sprite Assets before building

Hey, I use TextMeshPro to show inputs in speech bubbles. The sprites are defined in an atlas. Whenever I change something in the atlas the sprite location breaks. This is easily fixed by updating the sprite asset via the inspector.

However, this process is prone to errors since I might forget to update before I build. Actually, this happens quite regularly. Therefore I would like to add this to a script to update this Sprite Asset before I build my game.

Since these Sprite Asset files are not really part of the game but rather some sort of dictionary I am not sure how to access and alter these files via script.

Do you have any idea how to do this, is it even possible?

I started using this:

[MenuItem("TMPTest/UpdateTMP")]
    private static void UpdateSpriteAssets()
    {
        TMP_SpriteAsset  inputGamepad;
        inputGamepad = Resources.Load<TMP_SpriteAsset>("Sprites/UI_Input_Gamepad");

        inputGamepad.UpdateLookupTables();
      
      
    }

However - it does not work. Nothing happens. No error message - nothing.

With the help of a friend, I managed to come up with this here. Which works fine.
I use methods from a locked-away script within Unity, so I copied and pasted these functions into my script.

I hope you find this useful. Or if you know a much easier way, you can let me know as well.

using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEngine;
using UnityEditor;

using TMPro;
using System.Linq;
using System.Collections.Generic;
using UnityEngine.TextCore;

/// <summary>
/// This script updates the sprite assets before building to make sure the correct symbols are available.
/// </summary>

class UpdateSpriteAssets : IPreprocessBuildWithReport
{
    public int callbackOrder { get { return 0; } }
   
    public void OnPreprocessBuild(BuildReport report)
    {
       
        UpdateSpriteAssetsFunc();
    }

    [MenuItem("TMPAssetUpdateTest/UpdateTMP_SpriteAssets")]
    private static void UpdateSpriteAssetsFunc()
    {
        TMP_SpriteAsset inputGamepad;
        inputGamepad = Resources.Load<TMP_SpriteAsset>("Sprites/UI_Input_Gamepad");
       
        if(inputGamepad != null)
        {
           
            UpdateSpriteAssetsFunc(inputGamepad);
        }
        else
        {
            Debug.LogError("TMPSpriteAsset UI_InputGamepad was null!");
        }
    
       
        TMP_SpriteAsset inputKeyboard;
        inputKeyboard = Resources.Load<TMP_SpriteAsset>("Sprites/UI_Input_Keyboard");

        if (inputKeyboard != null)
        {
            UpdateSpriteAssetsFunc(inputKeyboard);
        }
        else
        {
            Debug.LogError("TMPSpriteAsset UI_InputKeyboard was null!");
        }

        TMP_SpriteAsset inputSwitch;
        inputSwitch = Resources.Load<TMP_SpriteAsset>("Sprites/UI_Input_Switch");

        if (inputSwitch != null)
        {
            UpdateSpriteAssetsFunc(inputSwitch);
        }
        else
        {
            Debug.LogError("TMPSpriteAsset UI_InputSwitch was null!");
        }
       
    }

    private static void UpdateSpriteAssetsFunc(TMP_SpriteAsset spriteAsset)
    {
        // Get a list of all the sprites contained in the texture referenced by the sprite asset.
        // This only works if the texture is set to sprite mode.
        string filePath = AssetDatabase.GetAssetPath(spriteAsset.spriteSheet);

        if (string.IsNullOrEmpty(filePath))
            return;

        // Get all the sprites defined in the sprite sheet texture referenced by this sprite asset.
        Sprite[] sprites = AssetDatabase.LoadAllAssetsAtPath(filePath).Select(x => x as Sprite).Where(x => x != null).ToArray();

        // Return if sprite sheet texture does not have any sprites defined in it.
        if (sprites.Length == 0)
        {
            Debug.Log("Sprite Asset <color=#FFFF80>[" + spriteAsset.name + "]</color>'s atlas texture does not appear to have any sprites defined in it. Use the Unity Sprite Editor to define sprites for this texture.", spriteAsset.spriteSheet);
            return;
        }

        List<TMP_SpriteGlyph> spriteGlyphTable = spriteAsset.spriteGlyphTable;

        // Find available glpyh indexes
        uint[] existingGlyphIndexes = spriteGlyphTable.Select(x => x.index).ToArray();
        List<uint> availableGlyphIndexes = new List<uint>();

        uint lastGlyphIndex = existingGlyphIndexes.Length > 0 ? existingGlyphIndexes.Last() : 0;
        int elementIndex = 0;
        for (uint i = 0; i < lastGlyphIndex; i++)
        {
            uint existingGlyphIndex = existingGlyphIndexes[elementIndex];

            if (i == existingGlyphIndex)
                elementIndex += 1;
            else
                availableGlyphIndexes.Add(i);
        }

        // Iterate over sprites contained in the updated sprite sheet to identify new and / or modified sprites.
        for (int i = 0; i < sprites.Length; i++)
        {
            Sprite sprite = sprites[i];

            // Check if current sprites is already contained in the sprite glyph table of the sprite asset.
            TMP_SpriteGlyph spriteGlyph = spriteGlyphTable.FirstOrDefault(x => x.sprite == sprite);

            if (spriteGlyph != null)
            {
                // update existing sprite glyph
                if (spriteGlyph.glyphRect.x != sprite.rect.x || spriteGlyph.glyphRect.y != sprite.rect.y || spriteGlyph.glyphRect.width != sprite.rect.width || spriteGlyph.glyphRect.height != sprite.rect.height)
                    spriteGlyph.glyphRect = new GlyphRect(sprite.rect);
            }
            else
            {
                TMP_SpriteCharacter spriteCharacter;

                // Check if this sprite potentially exists under the same name in the sprite character table.
                if (spriteAsset.spriteCharacterTable != null && spriteAsset.spriteCharacterTable.Count > 0)
                {
                    spriteCharacter = spriteAsset.spriteCharacterTable.FirstOrDefault(x => x.name == sprite.name);
                    spriteGlyph = spriteCharacter != null ? spriteGlyphTable[(int)spriteCharacter.glyphIndex] : null;

                    if (spriteGlyph != null)
                    {
                        // Update sprite reference and data
                        spriteGlyph.sprite = sprite;

                        if (spriteGlyph.glyphRect.x != sprite.rect.x || spriteGlyph.glyphRect.y != sprite.rect.y || spriteGlyph.glyphRect.width != sprite.rect.width || spriteGlyph.glyphRect.height != sprite.rect.height)
                            spriteGlyph.glyphRect = new GlyphRect(sprite.rect);
                    }
                }

                // Add new Sprite Glyph to the table
                spriteGlyph = new TMP_SpriteGlyph();

                // Get available glyph index
                if (availableGlyphIndexes.Count > 0)
                {
                    spriteGlyph.index = availableGlyphIndexes[0];
                    availableGlyphIndexes.RemoveAt(0);
                }
                else
                    spriteGlyph.index = (uint)spriteGlyphTable.Count;

                spriteGlyph.metrics = new GlyphMetrics(sprite.rect.width, sprite.rect.height, -sprite.pivot.x, sprite.rect.height - sprite.pivot.y, sprite.rect.width);
                spriteGlyph.glyphRect = new GlyphRect(sprite.rect);
                spriteGlyph.scale = 1.0f;
                spriteGlyph.sprite = sprite;

                spriteGlyphTable.Add(spriteGlyph);

                spriteCharacter = new TMP_SpriteCharacter(0xFFFE, spriteGlyph);
                spriteCharacter.name = sprite.name;
                spriteCharacter.scale = 1.0f;

                spriteAsset.spriteCharacterTable.Add(spriteCharacter);
            }
        }

        // Update Sprite Character Table to replace unicode 0x0 by 0xFFFE
        for (int i = 0; i < spriteAsset.spriteCharacterTable.Count; i++)
        {
            TMP_SpriteCharacter spriteCharacter = spriteAsset.spriteCharacterTable[i];
            if (spriteCharacter.unicode == 0)
                spriteCharacter.unicode = 0xFFFE;
        }

        // Sort glyph table by glyph index
        spriteAsset.SortGlyphTable();
        spriteAsset.UpdateLookupTables();
        TMPro_EventManager.ON_SPRITE_ASSET_PROPERTY_CHANGED(true, spriteAsset);
    }
}
1 Like