using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Nessie.ATLYSS.EasySettings;
using Newtonsoft.Json;
using TMPro;
using Tanuki.Atlyss.Core.Plugins;
using Tanuki.Atlyss.FontAssetsManager.Managers;
using Tanuki.Atlyss.FontAssetsManager.Models;
using Tanuki.Atlyss.FontAssetsManager.Models.Configuration;
using Tanuki.Atlyss.FontAssetsManager.Patches.TMPro.TMP_Text;
using Tanuki.Atlyss.FontAssetsManager.Patches.TMPro.TextMeshPro;
using Tanuki.Atlyss.FontAssetsManager.Patches.TMPro.TextMeshProUGUI;
using Tanuki.Atlyss.FontAssetsManager.Patches.UnityEngine.UI.Text;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Tanuki.Atlyss.FontAssetsManager")]
[assembly: AssemblyDescription("Plugin for Atlyss that customizes in-game fonts. Use custom fonts, replace existing ones, add fallbacks, and prevent missing characters from being displayed.")]
[assembly: AssemblyCompany("Tanuki")]
[assembly: AssemblyProduct("Tanuki.Atlyss.FontAssetsManager")]
[assembly: AssemblyCopyright("Copyright © Tanuki 2025")]
[assembly: ComVisible(false)]
[assembly: Guid("941c959b-230f-4a52-b0f7-db438c6031e1")]
[assembly: AssemblyFileVersion("1.0.2")]
[assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")]
[assembly: AssemblyVersion("1.0.2.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.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 Tanuki.Atlyss.FontAssetsManager
{
internal class Configuration
{
public static Configuration Instance;
public General General;
public Tanuki.Atlyss.FontAssetsManager.Models.Configuration.Debug Debug;
private Configuration()
{
}
public static void Initialize()
{
if (Instance == null)
{
Instance = new Configuration();
}
}
public void Load(ConfigFile ConfigFile)
{
General = new General(ConfigFile);
Debug = new Tanuki.Atlyss.FontAssetsManager.Models.Configuration.Debug(ConfigFile);
}
}
[BepInPlugin("941c959b-230f-4a52-b0f7-db438c6031e1", "Tanuki.Atlyss.FontAssetsManager", "1.0.2")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
internal class Main : Plugin
{
internal static Main Instance;
internal ManualLogSource ManualLogSource;
private bool Reloaded;
internal void Awake()
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
Instance = this;
ManualLogSource = ((BaseUnityPlugin)this).Logger;
new Harmony("941c959b-230f-4a52-b0f7-db438c6031e1").PatchAll();
Configuration.Initialize();
Configuration.Instance.Load(((BaseUnityPlugin)this).Config);
AssetBundles.Initialize();
AssetBundles.Instance.OnAssetsRefreshFinished += AssetBundles_OnAssetsRefreshed;
Replacements.Initialize();
Fallbacks.Initialize();
UnknownCharactersReplace.Initialize();
if (Chainloader.PluginInfos.ContainsKey("EasySettings"))
{
NessieEasySettings.Initialize();
}
}
protected override void Load()
{
if (Reloaded)
{
((BaseUnityPlugin)this).Config.Reload();
Configuration.Instance.Load(((BaseUnityPlugin)this).Config);
}
if (!AssetBundles.Instance.Refreshing)
{
AssetBundles.Instance.Refresh();
}
if (Configuration.Instance.Debug.TMP_Text_OnEnable.Value)
{
Tanuki.Atlyss.FontAssetsManager.Patches.TMPro.TextMeshProUGUI.OnEnable_Prefix.OnInvoke += TMP_Text_OnEnable_Log;
Tanuki.Atlyss.FontAssetsManager.Patches.TMPro.TextMeshPro.OnEnable_Prefix.OnInvoke += TMP_Text_OnEnable_Log;
}
if (Configuration.Instance.Debug.Text_OnEnable.Value)
{
Tanuki.Atlyss.FontAssetsManager.Patches.UnityEngine.UI.Text.OnEnable_Prefix.OnInvoke += Text_OnEnable_Log;
}
Tanuki.Atlyss.FontAssetsManager.Patches.UnityEngine.UI.Text.OnEnable_Prefix.OnInvoke += Text_OnEnable_Prefix_OnInvoke;
Tanuki.Atlyss.FontAssetsManager.Patches.TMPro.TextMeshProUGUI.OnEnable_Prefix.OnInvoke += TextMeshProUGUI_OnEnable_Prefix_OnInvoke;
Tanuki.Atlyss.FontAssetsManager.Patches.TMPro.TextMeshPro.OnEnable_Prefix.OnInvoke += TextMeshPro_OnEnable_Prefix_OnInvoke;
UnknownCharactersReplace.Instance.Load();
}
private void AssetBundles_OnAssetsRefreshed()
{
Replacements.Instance.Reload();
Fallbacks.Instance.Reload();
if (Configuration.Instance.General.UnloadUnusedAssets.Value)
{
AssetBundles.Instance.DestroyUnusedAssets();
}
}
private void TMP_Text_OnEnable_Log(TMP_Text Instance)
{
((BaseUnityPlugin)this).Logger.LogDebug((object)((Plugin)this).Translate("Debug.TMP_Text.OnEnable", new object[2]
{
((Object)Instance).name,
((Object)Instance.font).name
}));
}
private void Text_OnEnable_Log(Text Instance)
{
((BaseUnityPlugin)this).Logger.LogDebug((object)((Plugin)this).Translate("Debug.Text.OnEnable", new object[2]
{
((Object)Instance).name,
((Object)Instance.font).name
}));
}
private void Text_OnEnable_Prefix_OnInvoke(Text Instance)
{
if (Instance.font != null)
{
Replacements.Instance.Replace(Instance);
}
}
private void TextMeshProUGUI_OnEnable_Prefix_OnInvoke(TextMeshProUGUI Instance)
{
Replacements.Instance.Handle((TMP_Text)(object)Instance);
Fallbacks.Instance.Handle((TMP_Text)(object)Instance);
}
private void TextMeshPro_OnEnable_Prefix_OnInvoke(TextMeshPro Instance)
{
Replacements.Instance.Handle((TMP_Text)(object)Instance);
Fallbacks.Instance.Handle((TMP_Text)(object)Instance);
}
protected override void Unload()
{
Reloaded = true;
if (Configuration.Instance.Debug.TMP_Text_OnEnable.Value)
{
Tanuki.Atlyss.FontAssetsManager.Patches.TMPro.TextMeshProUGUI.OnEnable_Prefix.OnInvoke += TMP_Text_OnEnable_Log;
Tanuki.Atlyss.FontAssetsManager.Patches.TMPro.TextMeshPro.OnEnable_Prefix.OnInvoke += TMP_Text_OnEnable_Log;
}
if (Configuration.Instance.Debug.Text_OnEnable.Value)
{
Tanuki.Atlyss.FontAssetsManager.Patches.UnityEngine.UI.Text.OnEnable_Prefix.OnInvoke += Text_OnEnable_Log;
}
Tanuki.Atlyss.FontAssetsManager.Patches.UnityEngine.UI.Text.OnEnable_Prefix.OnInvoke -= Text_OnEnable_Prefix_OnInvoke;
Tanuki.Atlyss.FontAssetsManager.Patches.TMPro.TextMeshProUGUI.OnEnable_Prefix.OnInvoke -= TextMeshProUGUI_OnEnable_Prefix_OnInvoke;
Tanuki.Atlyss.FontAssetsManager.Patches.TMPro.TextMeshPro.OnEnable_Prefix.OnInvoke -= TextMeshPro_OnEnable_Prefix_OnInvoke;
Replacements.Instance.Reset();
Fallbacks.Instance.Reset();
UnknownCharactersReplace.Instance.Unload();
}
}
internal class PluginInfo
{
public const string GUID = "941c959b-230f-4a52-b0f7-db438c6031e1";
public const string Version = "1.0.2";
}
}
namespace Tanuki.Atlyss.FontAssetsManager.Patches.UnityEngine.UI.Text
{
[HarmonyPriority(int.MaxValue)]
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
public static class OnEnable_Prefix
{
public delegate void EventHandler(Text Instance);
public static event EventHandler OnInvoke;
private static void Postfix(Text __instance)
{
OnEnable_Prefix.OnInvoke?.Invoke(__instance);
}
}
}
namespace Tanuki.Atlyss.FontAssetsManager.Patches.TMPro.TextMeshPro
{
[HarmonyPriority(int.MaxValue)]
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
public static class OnEnable_Prefix
{
public delegate void EventHandler(TextMeshPro Instance);
public static event EventHandler OnInvoke;
private static void Postfix(TextMeshPro __instance)
{
OnEnable_Prefix.OnInvoke?.Invoke(__instance);
}
}
}
namespace Tanuki.Atlyss.FontAssetsManager.Patches.TMPro.TextMeshProUGUI
{
[HarmonyPriority(int.MaxValue)]
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
public static class OnEnable_Prefix
{
public delegate void EventHandler(TextMeshProUGUI Instance);
public static event EventHandler OnInvoke;
private static void Postfix(TextMeshProUGUI __instance)
{
OnEnable_Prefix.OnInvoke?.Invoke(__instance);
}
}
}
namespace Tanuki.Atlyss.FontAssetsManager.Patches.TMPro.TMP_Text
{
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
public static class Text_Setter_Prefix
{
public delegate void EventHandler(TMP_Text __instance, ref string value);
public static event EventHandler OnInvoke;
private static void Prefix(TMP_Text __instance, ref string value)
{
if (!(__instance.text == value))
{
Text_Setter_Prefix.OnInvoke?.Invoke(__instance, ref value);
}
}
}
}
namespace Tanuki.Atlyss.FontAssetsManager.Patches.ChatBehaviour
{
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
public static class UserCode_Rpc_RecieveChatMessage__String__Boolean__ChatChannel_Prefix
{
public delegate void EventHandler(ref string Message);
public static event EventHandler OnInvoke;
private static void Prefix(ref string message)
{
UserCode_Rpc_RecieveChatMessage__String__Boolean__ChatChannel_Prefix.OnInvoke?.Invoke(ref message);
}
}
}
namespace Tanuki.Atlyss.FontAssetsManager.Models
{
public class Asset
{
public Object Object;
public ushort Uses;
public Asset(Object Asset)
{
Object = Asset;
base..ctor();
}
}
public class Fallback
{
public Rule Rule;
public bool Fixed;
public HashSet<TMP_FontAsset> Assets;
public Fallback(Rule Rule, bool Fixed)
{
this.Rule = Rule;
this.Fixed = Fixed;
Assets = new HashSet<TMP_FontAsset>();
base..ctor();
}
}
public class Replacement<T>
{
public Rule Rule;
public T Asset;
public Replacement(Rule Rule, T Asset)
{
this.Rule = Rule;
this.Asset = Asset;
base..ctor();
}
}
public class Rule : IEquatable<Rule>
{
private readonly Regex ObjectName;
private readonly Regex FontName;
public Rule(Regex ObjectName, Regex FontName)
{
this.ObjectName = ObjectName;
this.FontName = FontName;
base..ctor();
}
public bool IsMatch(string ObjectName, string FontName)
{
if (this.ObjectName.IsMatch(ObjectName))
{
return this.FontName.IsMatch(FontName);
}
return false;
}
public bool Equals(Rule Other)
{
if (ObjectName.ToString() == Other.ObjectName.ToString())
{
return FontName.ToString() == Other.FontName.ToString();
}
return false;
}
}
}
namespace Tanuki.Atlyss.FontAssetsManager.Models.Configuration
{
internal class Debug
{
private const string Section = "Debug";
public ConfigEntry<bool> TMP_Text_OnEnable = ConfigFile.Bind<bool>("Debug", "TMP_Text_OnEnable", false, (ConfigDescription)null);
public ConfigEntry<bool> Text_OnEnable = ConfigFile.Bind<bool>("Debug", "Text_OnEnable", false, (ConfigDescription)null);
public Debug(ConfigFile ConfigFile)
{
}
}
[Serializable]
internal struct Fallback
{
[JsonProperty("Rule")]
public Rule Rule;
[JsonProperty("Fixed")]
public bool Fixed;
[JsonProperty("Assets")]
public List<Asset> Assets;
}
internal class General
{
private const string Section = "General";
public ConfigEntry<bool> ReplaceUnknownCharactersWithCodes = ConfigFile.Bind<bool>("General", "ReplaceUnknownCharactersWithCodes", true, (ConfigDescription)null);
public ConfigEntry<bool> UnloadUnusedAssets = ConfigFile.Bind<bool>("General", "DestroyUnusedAssets", true, (ConfigDescription)null);
public ConfigEntry<bool> RemoveCompletelyUnusedRuleFiles = ConfigFile.Bind<bool>("General", "RemoveCompletelyUnusedRuleFiles", true, (ConfigDescription)null);
public General(ConfigFile ConfigFile)
{
}
}
[Serializable]
internal struct Replacement
{
[JsonProperty("Asset")]
public Asset Asset;
[JsonProperty("Rule")]
public Rule Rule;
}
[Serializable]
internal struct Asset
{
[JsonProperty("Bundle")]
public string Bundle;
[JsonProperty("Object")]
public string Object;
}
[Serializable]
internal struct Rule
{
[JsonProperty("Object")]
public string Object;
[JsonProperty("Font")]
public string Font;
}
}
namespace Tanuki.Atlyss.FontAssetsManager.Managers
{
public class Fallbacks
{
private const string DirectoryName = "Fallbacks";
public static Fallbacks Instance;
private string Directory;
public readonly List<Tanuki.Atlyss.FontAssetsManager.Models.Fallback> Assets;
private Fallbacks()
{
Assets = new List<Tanuki.Atlyss.FontAssetsManager.Models.Fallback>();
}
public static void Initialize()
{
if (Instance == null)
{
Instance = new Fallbacks
{
Directory = Path.Combine(Paths.ConfigPath, ((Plugin)Main.Instance).Name, "Fallbacks")
};
}
}
public void Reload()
{
if (!System.IO.Directory.Exists(Directory))
{
System.IO.Directory.CreateDirectory(Directory);
}
HashSet<TMP_FontAsset> hashSet = new HashSet<TMP_FontAsset>();
string[] files = System.IO.Directory.GetFiles(Directory, "*.json");
foreach (string text in files)
{
List<Tanuki.Atlyss.FontAssetsManager.Models.Configuration.Fallback> list = JsonConvert.DeserializeObject<List<Tanuki.Atlyss.FontAssetsManager.Models.Configuration.Fallback>>(File.ReadAllText(text));
ushort num = 0;
foreach (Tanuki.Atlyss.FontAssetsManager.Models.Configuration.Fallback item in list)
{
Tanuki.Atlyss.FontAssetsManager.Models.Rule rule;
try
{
rule = new Tanuki.Atlyss.FontAssetsManager.Models.Rule(new Regex(item.Rule.Object), new Regex(item.Rule.Font));
}
catch
{
Main.Instance.ManualLogSource.LogWarning((object)((Plugin)Main.Instance).Translate("Fallback.InvalidRegex", new object[1] { text }));
continue;
}
hashSet.Clear();
foreach (Tanuki.Atlyss.FontAssetsManager.Models.Configuration.Asset asset in item.Assets)
{
TMP_FontAsset assetObject = AssetBundles.Instance.GetAssetObject<TMP_FontAsset>(asset.Bundle, asset.Object);
if (assetObject == null)
{
Main.Instance.ManualLogSource.LogWarning((object)((Plugin)Main.Instance).Translate("Fallback.AssetNotFound", new object[3] { asset.Object, asset.Bundle, text }));
}
else
{
num++;
hashSet.Add(assetObject);
}
}
if (hashSet.Count == 0)
{
continue;
}
Tanuki.Atlyss.FontAssetsManager.Models.Fallback fallback = null;
foreach (Tanuki.Atlyss.FontAssetsManager.Models.Fallback asset2 in Assets)
{
if (rule.Equals(asset2.Rule))
{
fallback = asset2;
break;
}
}
if (fallback == null)
{
fallback = new Tanuki.Atlyss.FontAssetsManager.Models.Fallback(rule, item.Fixed);
Assets.Add(fallback);
}
else
{
if (fallback.Fixed || item.Fixed)
{
foreach (TMP_FontAsset asset3 in fallback.Assets)
{
AssetBundles.Instance.Unuse((Object)(object)asset3, PreventUnload: true);
}
fallback.Assets.Clear();
}
fallback.Fixed = item.Fixed;
}
foreach (TMP_FontAsset item2 in hashSet)
{
fallback.Assets.Add(item2);
AssetBundles.Instance.Use((Object)(object)item2);
}
}
if (num <= 0)
{
RemoveCompletelyUnusedRulesFile(text);
}
}
}
private void RemoveCompletelyUnusedRulesFile(string Path)
{
if (Configuration.Instance.General.RemoveCompletelyUnusedRuleFiles.Value)
{
File.Delete(Path);
}
}
public void Reset()
{
Assets.Clear();
}
public void Handle(TMP_Text TMP_Text)
{
foreach (Tanuki.Atlyss.FontAssetsManager.Models.Fallback asset in Assets)
{
if (!asset.Rule.IsMatch(((Object)TMP_Text).name, ((Object)TMP_Text.font).name))
{
continue;
}
TMP_FontAsset font = TMP_Text.font;
if (font.fallbackFontAssetTable == null)
{
List<TMP_FontAsset> list2 = (font.fallbackFontAssetTable = new List<TMP_FontAsset>());
}
{
foreach (TMP_FontAsset asset2 in asset.Assets)
{
if (!((Object)(object)TMP_Text.font == (Object)(object)asset2) && !TMP_Text.font.fallbackFontAssetTable.Contains(asset2))
{
TMP_Text.font.fallbackFontAssetTable.Add(asset2);
}
}
break;
}
}
}
}
internal class NessieEasySettings
{
public const string GUID = "EasySettings";
internal static NessieEasySettings Instance;
private NessieEasySettings()
{
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Expected O, but got Unknown
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Expected O, but got Unknown
Settings.OnInitialized.AddListener(new UnityAction(NessieEasySettings_OnInitialize));
Settings.OnApplySettings.AddListener(new UnityAction(NessieEasySettings_OnApplySettings));
}
public static void Initialize()
{
if (Instance == null)
{
Instance = new NessieEasySettings();
}
}
private void NessieEasySettings_OnInitialize()
{
SettingsTab modTab = Settings.ModTab;
modTab.AddHeader("- TA FontAssetsManager -");
modTab.AddToggle("Replace unknown characters with codes", Configuration.Instance.General.ReplaceUnknownCharactersWithCodes);
modTab.AddSpace();
}
private void NessieEasySettings_OnApplySettings()
{
Configuration.Instance.Load(((BaseUnityPlugin)Main.Instance).Config);
UnknownCharactersReplace.Instance.Reload();
}
}
public class Replacements
{
private const string DirectoryName = "Replacements";
public static Replacements Instance;
private string Directory;
public readonly List<Replacement<Font>> Assets;
public readonly List<Replacement<TMP_FontAsset>> AssetsTMP;
private Replacements()
{
Assets = new List<Replacement<Font>>();
AssetsTMP = new List<Replacement<TMP_FontAsset>>();
}
public static void Initialize()
{
if (Instance == null)
{
Instance = new Replacements
{
Directory = Path.Combine(Paths.ConfigPath, ((Plugin)Main.Instance).Name, "Replacements")
};
}
}
public void Reload()
{
if (!System.IO.Directory.Exists(Directory))
{
System.IO.Directory.CreateDirectory(Directory);
}
string[] files = System.IO.Directory.GetFiles(Directory, "*.json");
foreach (string text in files)
{
List<Replacement> list = JsonConvert.DeserializeObject<List<Replacement>>(File.ReadAllText(text));
ushort num = 0;
foreach (Replacement item in list)
{
TMP_FontAsset assetObject = AssetBundles.Instance.GetAssetObject<TMP_FontAsset>(item.Asset.Bundle, item.Asset.Object);
Font assetObject2 = AssetBundles.Instance.GetAssetObject<Font>(item.Asset.Bundle, item.Asset.Object);
if (assetObject2 == null && assetObject == null)
{
Main.Instance.ManualLogSource.LogWarning((object)((Plugin)Main.Instance).Translate("Replacement.AssetNotFound", new object[3]
{
item.Asset.Object,
item.Asset.Bundle,
text
}));
continue;
}
Tanuki.Atlyss.FontAssetsManager.Models.Rule rule;
try
{
rule = new Tanuki.Atlyss.FontAssetsManager.Models.Rule(new Regex(item.Rule.Object), new Regex(item.Rule.Font));
}
catch
{
Main.Instance.ManualLogSource.LogWarning((object)((Plugin)Main.Instance).Translate("Replacement.InvalidRegex", new object[1] { text }));
continue;
}
bool flag;
if (assetObject != null)
{
flag = true;
num++;
foreach (Replacement<TMP_FontAsset> item2 in AssetsTMP)
{
if (!item2.Rule.Equals(rule))
{
flag = false;
AssetBundles.Instance.Unuse((Object)(object)item2.Asset, PreventUnload: true);
item2.Asset = assetObject;
break;
}
}
if (flag)
{
AssetsTMP.Add(new Replacement<TMP_FontAsset>(rule, assetObject));
}
AssetBundles.Instance.Use((Object)(object)assetObject);
}
if (assetObject2 == null)
{
continue;
}
flag = true;
num++;
foreach (Replacement<Font> asset in Assets)
{
if (asset.Equals(rule))
{
flag = false;
AssetBundles.Instance.Unuse((Object)(object)asset.Asset, PreventUnload: true);
asset.Asset = assetObject2;
break;
}
}
if (flag)
{
Assets.Add(new Replacement<Font>(rule, assetObject2));
}
AssetBundles.Instance.Use((Object)(object)assetObject2);
}
if (num <= 0)
{
RemoveCompletelyUnusedRulesFile(text);
}
}
}
private void RemoveCompletelyUnusedRulesFile(string Path)
{
if (Configuration.Instance.General.RemoveCompletelyUnusedRuleFiles.Value)
{
File.Delete(Path);
}
}
public void Handle(TMP_Text TMP_Text)
{
foreach (Replacement<TMP_FontAsset> item in AssetsTMP)
{
if ((Object)(object)TMP_Text.font == (Object)(object)item.Asset)
{
break;
}
if (item.Rule.IsMatch(((Object)TMP_Text).name, ((Object)TMP_Text.font).name))
{
TMP_Text.font = item.Asset;
break;
}
}
}
public void Replace(Text Text)
{
foreach (Replacement<Font> asset in Assets)
{
if ((Object)(object)Text.font == (Object)(object)asset.Asset)
{
break;
}
if (asset.Rule.IsMatch(((Object)Text).name, ((Object)Text.font).name))
{
Text.font = asset.Asset;
break;
}
}
}
public void Reset()
{
Assets.Clear();
AssetsTMP.Clear();
}
}
public class AssetBundles
{
public delegate void AssetsRefreshed();
public delegate void BeforeAssetsRefresh();
public static AssetBundles Instance;
private string AssetBundlesPath;
private readonly Dictionary<ulong, Tanuki.Atlyss.FontAssetsManager.Models.Asset> Assets;
private readonly Dictionary<Object, ulong> AssetHashes;
private ushort PendingRefreshes;
public bool Refreshing => PendingRefreshes > 0;
public event AssetsRefreshed OnAssetsRefreshFinished;
public event BeforeAssetsRefresh OnBeforeAssetsRefresh;
private AssetBundles()
{
Assets = new Dictionary<ulong, Tanuki.Atlyss.FontAssetsManager.Models.Asset>();
AssetHashes = new Dictionary<Object, ulong>();
}
public static void Initialize()
{
if (Instance == null)
{
Instance = new AssetBundles();
}
}
internal void Refresh()
{
if (Assets.Count > 0)
{
return;
}
PendingRefreshes = 0;
this.OnBeforeAssetsRefresh?.Invoke();
string[] directories = Directory.GetDirectories(Paths.PluginPath, "Tanuki.Atlyss.FontAssetsManager.AssetBundles", SearchOption.AllDirectories);
for (int i = 0; i < directories.Length; i++)
{
string[] files = Directory.GetFiles(directories[i], "*.assetbundle", SearchOption.AllDirectories);
foreach (string obj in files)
{
PendingRefreshes++;
((AsyncOperation)AssetBundle.LoadFromFileAsync(obj)).completed += OnAssetBundleLoaded;
}
}
}
private void OnAssetBundleLoaded(AsyncOperation AsyncOperation)
{
AssetBundle assetBundle = ((AssetBundleCreateRequest)((AsyncOperation is AssetBundleCreateRequest) ? AsyncOperation : null)).assetBundle;
if (!Object.op_Implicit((Object)(object)assetBundle))
{
OnAssetBundleProcessFinished();
return;
}
TMP_FontAsset[] array = assetBundle.LoadAllAssets<TMP_FontAsset>();
foreach (TMP_FontAsset val in array)
{
ulong assetHash = GetAssetHash(((Object)assetBundle).name, ((Object)val).name);
if (Assets.ContainsKey(assetHash))
{
Main.Instance.ManualLogSource.LogWarning((object)((Plugin)Main.Instance).Translate("AssetBundle.Duplicate", new object[3]
{
((Object)val).name,
"name",
((Object)assetBundle).name
}));
}
else
{
Assets.Add(assetHash, new Tanuki.Atlyss.FontAssetsManager.Models.Asset((Object)(object)val));
AssetHashes.Add((Object)(object)val, assetHash);
}
}
Font[] array2 = assetBundle.LoadAllAssets<Font>();
foreach (Font val2 in array2)
{
ulong assetHash = GetAssetHash(((Object)assetBundle).name, ((Object)val2).name);
if (Assets.ContainsKey(assetHash))
{
Main.Instance.ManualLogSource.LogWarning((object)((Plugin)Main.Instance).Translate("AssetBundle.Duplicate", new object[3]
{
((Object)val2).name,
"name",
((Object)assetBundle).name
}));
}
else
{
Assets.Add(assetHash, new Tanuki.Atlyss.FontAssetsManager.Models.Asset((Object)(object)val2));
AssetHashes.Add((Object)(object)val2, assetHash);
}
}
((AsyncOperation)assetBundle.UnloadAsync(false)).completed += OnAssetBundleUnloaded;
}
private void OnAssetBundleUnloaded(AsyncOperation AsyncOperation)
{
OnAssetBundleProcessFinished();
}
private void OnAssetBundleProcessFinished()
{
PendingRefreshes--;
if (PendingRefreshes <= 0)
{
this.OnAssetsRefreshFinished?.Invoke();
}
}
private ulong GetAssetHash(string AssetBundle, string AssetName)
{
return (ulong)(((long)AssetBundle.GetHashCode() << 32) | (uint)AssetName.GetHashCode());
}
public T GetAssetObject<T>(string AssetBundle, string AssetName) where T : class
{
Assets.TryGetValue(GetAssetHash(AssetBundle, AssetName), out var value);
if (value == null)
{
return null;
}
if (!(value.Object is T))
{
return null;
}
return value.Object as T;
}
public void Use(Object Object)
{
if (AssetHashes.TryGetValue(Object, out var value))
{
Assets[value].Uses++;
}
}
public void Unuse(Object Object, bool PreventUnload)
{
if (AssetHashes.TryGetValue(Object, out var value))
{
Tanuki.Atlyss.FontAssetsManager.Models.Asset asset = Assets[value];
if (asset.Uses > 0)
{
asset.Uses--;
}
if (!(asset.Uses > 0 || PreventUnload))
{
Assets.Remove(value);
AssetHashes.Remove(Object);
Object.Destroy(Object);
}
}
}
public void DestroyUnusedAssets()
{
List<ulong> list = new List<ulong>();
foreach (KeyValuePair<ulong, Tanuki.Atlyss.FontAssetsManager.Models.Asset> asset in Assets)
{
if (asset.Value.Uses <= 0)
{
list.Add(asset.Key);
}
}
foreach (ulong item in list)
{
Object @object = Assets[item].Object;
Assets.Remove(item);
AssetHashes.Remove(@object);
Object.Destroy(@object);
}
}
}
public class UnknownCharactersReplace
{
public static UnknownCharactersReplace Instance;
private UnknownCharactersReplace()
{
}
public static void Initialize()
{
if (Instance == null)
{
Instance = new UnknownCharactersReplace();
}
}
private void TMPro_TMP_Text_Text_Setter_Prefix_OnInvoke(TMP_Text __instance, ref string value)
{
if (string.IsNullOrEmpty(value) || !Object.op_Implicit((Object)(object)__instance.font))
{
return;
}
StringBuilder stringBuilder = new StringBuilder();
string text = value;
foreach (char c in text)
{
if (__instance.font.HasCharacter(c, true, false))
{
stringBuilder.Append(c);
}
else
{
stringBuilder.Append($"\\u{Convert.ToInt32(c)}");
}
}
value = stringBuilder.ToString();
}
public void Load()
{
if (Configuration.Instance.General.ReplaceUnknownCharactersWithCodes.Value)
{
Text_Setter_Prefix.OnInvoke += TMPro_TMP_Text_Text_Setter_Prefix_OnInvoke;
}
}
public void Unload()
{
Text_Setter_Prefix.OnInvoke -= TMPro_TMP_Text_Text_Setter_Prefix_OnInvoke;
}
public void Reload()
{
Unload();
Load();
}
}
}