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);
}
}
}