using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Logging; using TMPro; using UnityEngine; using UnityEngine.TextCore; [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace DeckGlyphs; [BepInPlugin("com.himiko.deckglyphs", "Deck Glyphs", "1.0.0")] public class DeckGlyphsPlugin : BaseUnityPlugin { public const string GUID = "com.himiko.deckglyphs"; public const string NAME = "Deck Glyphs"; public const string VERSION = "1.0.0"; private const string TargetSpriteAsset = "tmpsprXboxOneGlyphs"; internal static ManualLogSource Log; private readonly Dictionary _deckByGlyphName = new Dictionary(StringComparer.OrdinalIgnoreCase); private bool _patched; private void Awake() { Log = ((BaseUnityPlugin)this).Logger; LoadDeckTextures(); if (_deckByGlyphName.Count == 0) { Log.LogError((object)"No Deck glyphs loaded; check the glyphs/ folder and glyph_map.json."); } else { ((MonoBehaviour)this).StartCoroutine(PatchWhenReady()); } } private void LoadDeckTextures() { //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Expected O, but got Unknown string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); string text = Path.Combine(directoryName, "glyphs"); string path = Path.Combine(directoryName, "glyph_map.json"); if (!Directory.Exists(text) || !File.Exists(path)) { Log.LogError((object)"Missing glyphs/ folder or glyph_map.json next to the DLL."); return; } foreach (KeyValuePair item in ReadFlatJson(File.ReadAllText(path))) { if (!item.Key.StartsWith("_")) { string text2 = Path.Combine(text, item.Value); if (!File.Exists(text2)) { Log.LogWarning((object)("Glyph png not found: " + text2)); continue; } Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); ImageConversion.LoadImage(val, File.ReadAllBytes(text2)); ((Texture)val).wrapMode = (TextureWrapMode)1; _deckByGlyphName[item.Key] = val; } } Log.LogInfo((object)("Loaded " + _deckByGlyphName.Count + " Deck glyph textures.")); } private IEnumerator PatchWhenReady() { float deadline = Time.realtimeSinceStartup + 120f; while (!_patched && Time.realtimeSinceStartup < deadline) { if (TryPatch()) { yield break; } yield return (object)new WaitForSeconds(0.5f); } if (!_patched) { Log.LogWarning((object)"Gave up: 'tmpsprXboxOneGlyphs' sprite asset never appeared."); } } private bool TryPatch() { TMP_SpriteAsset[] array = Resources.FindObjectsOfTypeAll(); bool flag = false; TMP_SpriteAsset[] array2 = array; foreach (TMP_SpriteAsset val in array2) { if (!((Object)(object)val == (Object)null) && !(((Object)val).name != "tmpsprXboxOneGlyphs")) { try { RepaintAtlas(val); flag = true; } catch (Exception ex) { Log.LogError((object)("Failed to repaint " + ((Object)val).name + ": " + ex)); } } } if (flag) { _patched = true; Log.LogInfo((object)"Deck glyphs applied."); } return flag; } private void RepaintAtlas(TMP_SpriteAsset sa) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) Texture spriteSheet = sa.spriteSheet; Texture2D val = (Texture2D)(object)((spriteSheet is Texture2D) ? spriteSheet : null); int num = ((!((Object)(object)val != (Object)null)) ? 1024 : ((Texture)val).width); int num2 = ((!((Object)(object)val != (Object)null)) ? 1024 : ((Texture)val).height); Texture2D val2 = new Texture2D(num, num2, (TextureFormat)4, false); ((Texture)val2).wrapMode = (TextureWrapMode)1; ((Texture)val2).filterMode = (FilterMode)1; Color32[] pixels = (Color32[])(object)new Color32[num * num2]; val2.SetPixels32(pixels); int num3 = 0; List spriteCharacterTable = sa.spriteCharacterTable; for (int i = 0; i < spriteCharacterTable.Count; i++) { TMP_SpriteCharacter val3 = spriteCharacterTable[i]; if (val3 == null || string.IsNullOrEmpty(val3.name) || !_deckByGlyphName.TryGetValue(val3.name, out var value) || (Object)(object)value == (Object)null) { continue; } GlyphRect val4 = ((((TMP_TextElement)val3).glyph == null) ? FindRect(sa, ((TMP_TextElement)val3).glyphIndex) : ((TMP_TextElement)val3).glyph.glyphRect); if (((GlyphRect)(ref val4)).width > 0 && ((GlyphRect)(ref val4)).height > 0) { Color32[] array = Resample(value, ((GlyphRect)(ref val4)).width, ((GlyphRect)(ref val4)).height); if (((GlyphRect)(ref val4)).x >= 0 && ((GlyphRect)(ref val4)).y >= 0 && ((GlyphRect)(ref val4)).x + ((GlyphRect)(ref val4)).width <= num && ((GlyphRect)(ref val4)).y + ((GlyphRect)(ref val4)).height <= num2) { val2.SetPixels32(((GlyphRect)(ref val4)).x, ((GlyphRect)(ref val4)).y, ((GlyphRect)(ref val4)).width, ((GlyphRect)(ref val4)).height, array); num3++; } } } val2.Apply(false, false); sa.spriteSheet = (Texture)(object)val2; Material material = ((TMP_Asset)sa).material; if ((Object)(object)material != (Object)null) { material.mainTexture = (Texture)(object)val2; if (material.HasProperty("_MainTex")) { material.SetTexture("_MainTex", (Texture)(object)val2); } } Log.LogInfo((object)("Repainted " + num3 + " glyphs on " + ((Object)sa).name + " (" + num + "x" + num2 + ").")); } private static GlyphRect FindRect(TMP_SpriteAsset sa, uint glyphIndex) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) List spriteGlyphTable = sa.spriteGlyphTable; for (int i = 0; i < spriteGlyphTable.Count; i++) { if (spriteGlyphTable[i] != null && ((Glyph)spriteGlyphTable[i]).index == glyphIndex) { return ((Glyph)spriteGlyphTable[i]).glyphRect; } } return new GlyphRect(0, 0, 0, 0); } private static Color32[] Resample(Texture2D src, int w, int h) { //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) Color[] pixels = src.GetPixels(); int width = ((Texture)src).width; int height = ((Texture)src).height; Color32[] array = (Color32[])(object)new Color32[w * h]; for (int i = 0; i < h; i++) { float num = ((float)i + 0.5f) * (float)height / (float)h - 0.5f; int num2 = Mathf.Clamp(Mathf.FloorToInt(num), 0, height - 1); int num3 = Mathf.Clamp(num2 + 1, 0, height - 1); float num4 = Mathf.Clamp01(num - (float)num2); for (int j = 0; j < w; j++) { float num5 = ((float)j + 0.5f) * (float)width / (float)w - 0.5f; int num6 = Mathf.Clamp(Mathf.FloorToInt(num5), 0, width - 1); int num7 = Mathf.Clamp(num6 + 1, 0, width - 1); float num8 = Mathf.Clamp01(num5 - (float)num6); Color val = pixels[num2 * width + num6]; Color val2 = pixels[num2 * width + num7]; Color val3 = pixels[num3 * width + num6]; Color val4 = pixels[num3 * width + num7]; Color val5 = Color.Lerp(val, val2, num8); Color val6 = Color.Lerp(val3, val4, num8); ref Color32 reference = ref array[i * w + j]; reference = Color32.op_Implicit(Color.Lerp(val5, val6, num4)); } } return array; } private static IEnumerable> ReadFlatJson(string json) { List> list = new List>(); int startIndex = 0; while (true) { int num = json.IndexOf('"', startIndex); if (num < 0) { break; } int num2 = json.IndexOf('"', num + 1); if (num2 < 0) { break; } string key = json.Substring(num + 1, num2 - num - 1); int num3 = json.IndexOf(':', num2); if (num3 < 0) { break; } int num4 = json.IndexOf('\n', num2); int num5 = json.IndexOf('"', num3); if (num5 < 0) { break; } if (num4 >= 0 && num5 > num4) { startIndex = num2 + 1; continue; } int num6 = json.IndexOf('"', num5 + 1); if (num6 < 0) { break; } string value = json.Substring(num5 + 1, num6 - num5 - 1); list.Add(new KeyValuePair(key, value)); startIndex = num6 + 1; } return list; } }