Decompiled source of PEAK Thai Translation v1.0.1

BepInEx/plugins/ThaiFontLoader.dll

Decompiled 2 days ago
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.TextCore.LowLevel;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ThaiFontLoader")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ThaiFontLoader")]
[assembly: AssemblyTitle("ThaiFontLoader")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ThaiFontLoader
{
	[BepInPlugin("com.devdroggy.thaifontloader", "PEAK Thai Font Loader", "1.0.0")]
	public class ThaiFontLoaderPlugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log;

		public static ConfigEntry<bool> ReplaceAllFonts;

		public static ConfigEntry<bool> AddAsFallback;

		public static ConfigEntry<bool> PreloadThaiCharacters;

		public static ConfigEntry<bool> DebugLogging;

		public static TMP_FontAsset ThaiTMPFont;

		public static Font ThaiUnityFont;

		private static bool _materialConfigured;

		[DllImport("gdi32.dll", SetLastError = true)]
		private static extern int AddFontResourceEx(string lpszFilename, uint fl, IntPtr pdv);

		private void Awake()
		{
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			ReplaceAllFonts = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ReplaceAllFonts", true, "Directly replace in-game TMP fonts with Thai font for clean, consistent Thai & English typography");
			AddAsFallback = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AddAsFallback", true, "Add Thai font as a fallback font for all original game fonts");
			PreloadThaiCharacters = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "PreloadThaiCharacters", true, "Pre-render Thai glyphs into atlas at startup to avoid frame stutter");
			DebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DebugLogging", false, "Enable verbose logging");
			Log.LogInfo((object)"=== PEAK Thai Font Loader v1.0.0 Starting ===");
			try
			{
				LoadFont();
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"Exception during font initialization: {arg}");
			}
			try
			{
				new Harmony("com.devdroggy.thaifontloader").PatchAll();
				Log.LogInfo((object)"Harmony patches for TextMeshPro and UI.Text applied successfully.");
			}
			catch (Exception arg2)
			{
				Log.LogError((object)$"Exception while applying Harmony patches: {arg2}");
			}
			SceneManager.sceneLoaded += OnSceneLoaded;
		}

		private void LoadFont()
		{
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			string text = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Prompt-Bold.ttf");
			if (!File.Exists(text))
			{
				try
				{
					using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("ThaiFontLoader.Prompt-Bold.ttf");
					if (stream != null)
					{
						using FileStream destination = new FileStream(text, FileMode.Create, FileAccess.Write);
						stream.CopyTo(destination);
						Log.LogInfo((object)("Extracted embedded font to: " + text));
					}
					else
					{
						Log.LogWarning((object)"Embedded font resource 'ThaiFontLoader.Prompt-Bold.ttf' not found in DLL.");
					}
				}
				catch (Exception ex)
				{
					Log.LogWarning((object)("Failed to extract embedded font: " + ex.Message));
				}
			}
			if (File.Exists(text))
			{
				int num = AddFontResourceEx(text, 16u, IntPtr.Zero);
				Log.LogInfo((object)$"Registered '{text}' with Windows GDI (Result: {num}).");
			}
			try
			{
				ThaiUnityFont = Font.CreateDynamicFontFromOSFont("Prompt", 36);
				if ((Object)(object)ThaiUnityFont == (Object)null)
				{
					ThaiUnityFont = Font.CreateDynamicFontFromOSFont("Prompt-Bold", 36);
				}
				if ((Object)(object)ThaiUnityFont != (Object)null)
				{
					Object.DontDestroyOnLoad((Object)(object)ThaiUnityFont);
					Log.LogInfo((object)("Created dynamic Unity Font: " + ((Object)ThaiUnityFont).name));
				}
			}
			catch (Exception ex2)
			{
				Log.LogWarning((object)("Could not create dynamic Unity Font: " + ex2.Message));
			}
			try
			{
				if (File.Exists(text))
				{
					Log.LogInfo((object)"Creating dynamic TMP_FontAsset from TTF file...");
					ThaiTMPFont = TMP_FontAsset.CreateFontAsset(text, 0, 36, 4, (GlyphRenderMode)4165, 1024, 1024);
				}
				if ((Object)(object)ThaiTMPFont == (Object)null && (Object)(object)ThaiUnityFont != (Object)null)
				{
					Log.LogInfo((object)"Creating TMP_FontAsset from dynamic Unity Font...");
					ThaiTMPFont = TMP_FontAsset.CreateFontAsset(ThaiUnityFont);
				}
				if ((Object)(object)ThaiTMPFont != (Object)null)
				{
					ThaiTMPFont.atlasPopulationMode = (AtlasPopulationMode)1;
					ThaiTMPFont.isMultiAtlasTexturesEnabled = true;
					((Object)ThaiTMPFont).name = "Prompt-Bold Thai SDF";
					Object.DontDestroyOnLoad((Object)(object)ThaiTMPFont);
					Log.LogInfo((object)$"Created TMP_FontAsset '{((Object)ThaiTMPFont).name}' (AtlasPopulationMode: {ThaiTMPFont.atlasPopulationMode})");
					if (PreloadThaiCharacters.Value)
					{
						PreloadGlyphs();
					}
					SetupFallbackTables();
				}
				else
				{
					Log.LogError((object)"Failed to create TMP_FontAsset! Both TTF and OS font methods returned null.");
				}
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"Exception while creating TMP_FontAsset: {arg}");
			}
		}

		private static void PreloadGlyphs()
		{
			if ((Object)(object)ThaiTMPFont == (Object)null)
			{
				return;
			}
			try
			{
				string text = "กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะ\u0e31าำ\u0e34\u0e35\u0e36\u0e37\u0e38\u0e39\u0e3a฿เแโใไๅๆ\u0e47\u0e48\u0e49\u0e4a\u0e4b\u0e4c\u0e4d\u0e4e๏๐๑๒๓๔๕๖๗๘๙๚๛0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";
				bool flag = ThaiTMPFont.TryAddCharacters(text, false);
				Log.LogInfo((object)$"Preloaded {text.Length} Thai/Latin glyphs into font atlas: {flag}");
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("PreloadGlyphs warning: " + ex.Message));
			}
		}

		public static void SetupFallbackTables()
		{
			if ((Object)(object)ThaiTMPFont == (Object)null)
			{
				return;
			}
			try
			{
				if (TMP_Settings.fallbackFontAssets != null && !TMP_Settings.fallbackFontAssets.Contains(ThaiTMPFont))
				{
					TMP_Settings.fallbackFontAssets.Insert(0, ThaiTMPFont);
					Log.LogInfo((object)"Added Thai font to TMP_Settings.fallbackFontAssets (Priority 0).");
				}
				if ((Object)(object)TMP_Settings.defaultFontAsset != (Object)null && TMP_Settings.defaultFontAsset.fallbackFontAssetTable != null)
				{
					if (!TMP_Settings.defaultFontAsset.fallbackFontAssetTable.Contains(ThaiTMPFont))
					{
						TMP_Settings.defaultFontAsset.fallbackFontAssetTable.Insert(0, ThaiTMPFont);
						Log.LogInfo((object)"Added Thai font to defaultFontAsset.fallbackFontAssetTable.");
					}
					EnsureMaterialConfigured(TMP_Settings.defaultFontAsset);
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("SetupFallbackTables exception: " + ex.Message));
			}
		}

		public static void EnsureMaterialConfigured(TMP_FontAsset referenceFont)
		{
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Expected O, but got Unknown
			if (_materialConfigured || (Object)(object)ThaiTMPFont == (Object)null)
			{
				return;
			}
			try
			{
				if ((Object)(object)((TMP_Asset)ThaiTMPFont).material == (Object)null || (Object)(object)((TMP_Asset)ThaiTMPFont).material.shader == (Object)null)
				{
					Material val = ((referenceFont != null) ? ((TMP_Asset)referenceFont).material : null);
					if ((Object)(object)val == (Object)null || (Object)(object)val.shader == (Object)null)
					{
						TMP_FontAsset[] array = Resources.FindObjectsOfTypeAll<TMP_FontAsset>();
						foreach (TMP_FontAsset val2 in array)
						{
							if ((Object)(object)val2 != (Object)null && (Object)(object)((TMP_Asset)val2).material != (Object)null && (Object)(object)((TMP_Asset)val2).material.shader != (Object)null)
							{
								val = ((TMP_Asset)val2).material;
								break;
							}
						}
					}
					if ((Object)(object)val != (Object)null && (Object)(object)val.shader != (Object)null)
					{
						((TMP_Asset)ThaiTMPFont).material = new Material(val);
						((Object)((TMP_Asset)ThaiTMPFont).material).name = "Prompt-Bold Thai Material";
						if ((Object)(object)ThaiTMPFont.atlasTexture != (Object)null)
						{
							((TMP_Asset)ThaiTMPFont).material.mainTexture = (Texture)(object)ThaiTMPFont.atlasTexture;
						}
						_materialConfigured = true;
						Log.LogInfo((object)("Configured Thai font material using in-game shader: " + ((Object)val.shader).name));
					}
				}
				else
				{
					_materialConfigured = true;
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("EnsureMaterialConfigured warning: " + ex.Message));
			}
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			SetupFallbackTables();
			RepatchAllTextsInScene();
		}

		public static void RepatchAllTextsInScene()
		{
			if ((Object)(object)ThaiTMPFont == (Object)null)
			{
				return;
			}
			try
			{
				TMP_Text[] array = Resources.FindObjectsOfTypeAll<TMP_Text>();
				if (array != null)
				{
					TMP_Text[] array2 = array;
					for (int i = 0; i < array2.Length; i++)
					{
						ApplyFontToTMP(array2[i]);
					}
				}
			}
			catch (Exception ex)
			{
				if (DebugLogging.Value)
				{
					Log.LogWarning((object)("RepatchAllTextsInScene: " + ex.Message));
				}
			}
		}

		public static void ApplyFontToTMP(TMP_Text text)
		{
			if ((Object)(object)text == (Object)null || (Object)(object)ThaiTMPFont == (Object)null)
			{
				return;
			}
			try
			{
				EnsureMaterialConfigured(text.font);
				if (AddAsFallback.Value && (Object)(object)text.font != (Object)null && (Object)(object)text.font != (Object)(object)ThaiTMPFont && text.font.fallbackFontAssetTable != null && !text.font.fallbackFontAssetTable.Contains(ThaiTMPFont))
				{
					text.font.fallbackFontAssetTable.Insert(0, ThaiTMPFont);
				}
				if (ReplaceAllFonts.Value && (Object)(object)text.font != (Object)(object)ThaiTMPFont)
				{
					text.font = ThaiTMPFont;
					if ((Object)(object)((TMP_Asset)ThaiTMPFont).material != (Object)null)
					{
						text.fontSharedMaterial = ((TMP_Asset)ThaiTMPFont).material;
					}
				}
			}
			catch (Exception ex)
			{
				if (DebugLogging.Value)
				{
					Log.LogWarning((object)("ApplyFontToTMP error: " + ex.Message));
				}
			}
		}

		public static void ApplyFontToLegacyUI(Text text)
		{
			if ((Object)(object)text == (Object)null || (Object)(object)ThaiUnityFont == (Object)null)
			{
				return;
			}
			try
			{
				if (ReplaceAllFonts.Value && (Object)(object)text.font != (Object)(object)ThaiUnityFont)
				{
					text.font = ThaiUnityFont;
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(TMP_Text), "Awake")]
	internal static class Patch_TMP_Text_Awake
	{
		private static void Postfix(TMP_Text __instance)
		{
			ThaiFontLoaderPlugin.ApplyFontToTMP(__instance);
		}
	}
	[HarmonyPatch(typeof(TMP_Text), "OnEnable")]
	internal static class Patch_TMP_Text_OnEnable
	{
		private static void Postfix(TMP_Text __instance)
		{
			ThaiFontLoaderPlugin.ApplyFontToTMP(__instance);
		}
	}
	[HarmonyPatch(typeof(TextMeshProUGUI), "GenerateTextMesh")]
	internal static class Patch_TMPUGUI_GenerateTextMesh
	{
		private static void Prefix(TextMeshProUGUI __instance)
		{
			ThaiFontLoaderPlugin.ApplyFontToTMP((TMP_Text)(object)__instance);
		}
	}
	[HarmonyPatch(typeof(TextMeshPro), "GenerateTextMesh")]
	internal static class Patch_TMP_GenerateTextMesh
	{
		private static void Prefix(TextMeshPro __instance)
		{
			ThaiFontLoaderPlugin.ApplyFontToTMP((TMP_Text)(object)__instance);
		}
	}
	[HarmonyPatch(typeof(Text), "Awake")]
	internal static class Patch_UI_Text_Awake
	{
		private static void Postfix(Text __instance)
		{
			ThaiFontLoaderPlugin.ApplyFontToLegacyUI(__instance);
		}
	}
	[HarmonyPatch(typeof(Text), "OnEnable")]
	internal static class Patch_UI_Text_OnEnable
	{
		private static void Postfix(Text __instance)
		{
			ThaiFontLoaderPlugin.ApplyFontToLegacyUI(__instance);
		}
	}
}