using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using ModdingTales; using UnityEngine; using UnityEngine.Video; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("RetexturePlugin")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("RetexturePlugin")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("RetexturePlugin")] [assembly: ComVisible(false)] [assembly: Guid("c303405d-e66c-4316-9cdb-4e3ca15c6360")] [assembly: AssemblyFileVersion("3.1.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("3.1.0.0")] namespace LordAshes; [BepInPlugin("org.lordashes.plugins.retexture", "Retexture Plug-In", "3.1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class RetexturePlugin : BaseUnityPlugin { public class ReplacementMateiral { public Renderer renderer { get; set; } public Material material { get; set; } } public static class Utility { public static bool isBoardLoaded() { try { bool flag = (bool)Reflection.Property(Reflection.Type("CameraController", (string[])null, (string[])null, 0), "HasInstance", (string)null).GetValue(null); bool flag2 = (bool)Reflection.Property(Reflection.Type("BoardSessionManager", (string[])null, (string[])null, 0), "HasInstance", (string)null).GetValue(null); bool flag3 = (bool)Reflection.Property(Reflection.Type("BoardSessionManager", (string[])null, (string[])null, 0), "HasInstance", (string)null).GetValue(null); return flag && flag2 && !flag3; } catch { return false; } } public static float ParseFloat(string value) { return float.Parse(value, CultureInfo.InvariantCulture); } public static object FindObjectInHierarchy(GameObject start, string fullName = null, string partialName = null) { return FindObjectsInHierarchy(start, fullName, partialName)?.ElementAt(0); } public static object[] FindObjectsInHierarchy(GameObject start, string fullName = null, string partialName = null) { List results = new List(); Traverse(start, ref results, fullName, partialName); if (results.Count > 0) { return results.ToArray(); } return null; } public static void Traverse(GameObject start, ref List results, string fullName = null, string partialName = null) { LoggingPlugin.LogDebug("Found GameObject " + ((Object)start).name + " (" + ((Object)start.transform).name + ") While Seeking " + typeof(T).ToString() + " With Name " + ((fullName == null) ? "Unspecified" : fullName) + " And Parial Name " + ((partialName == null) ? "Unspecified" : partialName)); if (((object)start).GetType() == typeof(T) && (fullName == null || ((Object)start).name == fullName) && (partialName == null || ((Object)start).name.Contains(partialName))) { LoggingPlugin.LogDebug("Adding GameObject " + ((Object)start).name + " To Results"); results.Add(start); } Component[] components = start.GetComponents(typeof(T)); foreach (Component val in components) { LoggingPlugin.LogDebug("Found GameObject " + ((Object)start).name + " (" + ((Object)start.transform).name + ") Component " + ((Object)val).name + " (" + ((object)val).GetType().ToString() + ") While Seeking " + typeof(T).ToString() + " With Name " + ((fullName == null) ? "Unspecified" : fullName) + " And Parial Name " + ((partialName == null) ? "Unspecified" : partialName)); if ((fullName == null || ((Object)start).name == fullName) && (partialName == null || ((Object)start).name.Contains(partialName))) { LoggingPlugin.LogDebug("Assing GameObject " + ((Object)start).name + " Component " + ((Object)val).name + " To Results"); results.Add(val); } } for (int j = 0; j < start.transform.childCount; j++) { Transform child = start.transform.GetChild(j); Traverse(((Component)child).gameObject, ref results, fullName, partialName); } } public static GameObject FindObjectWithInHierarchy(GameObject start, string fullName = null, string partialName = null) { return FindObjectsWithInHierarchy(start, fullName, partialName)?.ElementAt(0); } public static GameObject[] FindObjectsWithInHierarchy(GameObject start, string fullName = null, string partialName = null) { List results = new List(); TraverseWith(start, ref results, fullName, partialName); if (results.Count > 0) { return results.ToArray(); } return null; } public static void TraverseWith(GameObject start, ref List results, string fullName = null, string partialName = null) { LoggingPlugin.LogDebug("Found GameObject " + ((Object)start).name + " (" + ((Object)start.transform).name + ") While Seeking " + typeof(T).ToString() + " With Name " + ((fullName == null) ? "Unspecified" : fullName) + " And Parial Name " + ((partialName == null) ? "Unspecified" : partialName)); if (((object)start).GetType() == typeof(T) && (fullName == null || ((Object)start).name == fullName) && (partialName == null || ((Object)start).name.Contains(partialName))) { LoggingPlugin.LogDebug("Adding GameObject " + ((Object)start).name + " To Results"); results.Add(start); } Component[] components = start.GetComponents(typeof(T)); foreach (Component val in components) { LoggingPlugin.LogDebug("Found GameObject " + ((Object)start).name + " (" + ((Object)start.transform).name + ") Component " + ((Object)val).name + " (" + ((object)val).GetType().ToString() + ") While Seeking " + typeof(T).ToString() + " With Name " + ((fullName == null) ? "Unspecified" : fullName) + " And Parial Name " + ((partialName == null) ? "Unspecified" : partialName)); if ((fullName == null || ((Object)start).name == fullName) && (partialName == null || ((Object)start).name.Contains(partialName))) { LoggingPlugin.LogDebug("Adding GameObject " + ((Object)start).name + " Component To Results"); results.Add(start); } } for (int j = 0; j < start.transform.childCount; j++) { Transform child = start.transform.GetChild(j); TraverseWith(((Component)child).gameObject, ref results, fullName, partialName); } } public static object LookUp(in Dictionary dictionary, string key) { foreach (KeyValuePair item in dictionary) { if (item.Key.ToUpper() == key.ToUpper()) { return item.Value; } } return null; } public static void PostOnMainPage(BaseUnityPlugin plugin) { string text = "Lord Ashes" + ("Lord Ashes".ToUpper().EndsWith("S") ? "'" : "'s"); ModdingUtils.AddPluginToMenuList(plugin, text); } } public const string Name = "Retexture Plug-In"; public const string Guid = "org.lordashes.plugins.retexture"; public const string Version = "3.1.0.0"; public const string Author = "Lord Ashes"; public static Type _CreatureBoardAsset = Reflection.Type("CreatureBoardAsset", (string[])null, (string[])null, 0); public static Type _CreatureGuid = Reflection.Type("CreatureGuid", (string[])null, (string[])null, 0); public static Type _CreaturePresenter = Reflection.Type("CreaturePresenter", (string[])null, (string[])null, 0); public static Type _LocalClient = Reflection.Type("LocalClient", (string[])null, (string[])null, 0); public static Type _SystemMessage = Reflection.Type("SystemMessage", (string[])null, (string[])null, 0); private Dictionary originalMaterials = new Dictionary(); private Guid subscriptionId = System.Guid.Empty; private static readonly Regex GuidWithOptionalSuffix = new Regex("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}(\\..+)?$", RegexOptions.Compiled); private ConfigEntry triggerKey { get; set; } private ConfigEntry triggerResetKey { get; set; } private ConfigEntry affectAuras { get; set; } private void Awake() { //IL_0018: 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) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) LoggingPlugin.SetLogLevel(((BaseUnityPlugin)this).Config.Bind("Settings", "Diagnostic Level", (DiagnosticLevel)3, (ConfigDescription)null).Value); string? assemblyQualifiedName = ((object)this).GetType().AssemblyQualifiedName; DiagnosticLevel logLevel = LoggingPlugin.GetLogLevel(); LoggingPlugin.LogInfo(assemblyQualifiedName + ": Active. (Diagnostic Mode = " + ((object)(DiagnosticLevel)(ref logLevel)).ToString() + ")"); triggerKey = ((BaseUnityPlugin)this).Config.Bind("Hotkeys", "Repaint Asset Activation", new KeyboardShortcut((KeyCode)120, (KeyCode[])(object)new KeyCode[1] { (KeyCode)305 }), (ConfigDescription)null); triggerResetKey = ((BaseUnityPlugin)this).Config.Bind("Hotkeys", "Transform (Recall) Repainted", new KeyboardShortcut((KeyCode)121, (KeyCode[])(object)new KeyCode[1] { (KeyCode)305 }), (ConfigDescription)null); affectAuras = ((BaseUnityPlugin)this).Config.Bind("Settings", "Affect Auras Instead Of Mini When Present", false, (ConfigDescription)null); AssetDataPlugin.Subscribe("org.lordashes.plugins.retexture", (Action)RequestHandler, (Func)Checker.CheckSourceAsCreature); Utility.PostOnMainPage((BaseUnityPlugin)(object)this); } private void Update() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) KeyboardShortcut value = triggerKey.Value; if (((KeyboardShortcut)(ref value)).IsUp()) { LoggingPlugin.LogDebug("Make Retexture Request For Selected Mini"); object asset = Reflection.Execute(Reflection.Method(_CreaturePresenter, "TryGetAsset", (string[])null), (object)null, new object[2] { Reflection.Property(_LocalClient, "SelectedCreatureId", (string)null).GetValue(null), null }, 2); if (asset != null) { Reflection.Execute(Reflection.Method(_SystemMessage, "AskForTextInput", (string[])null), (object)null, new object[8] { "Replacement Texture...", "\r\nSource:", "Texture", (Action)delegate(object source) { AssetDataPlugin.SetInfo(Reflection.Property(_CreatureBoardAsset, "CreatureId", (string)null).GetValue(asset).ToString(), "org.lordashes.plugins.retexture", source, false); }, null, "Original", (Action)delegate { AssetDataPlugin.ClearInfo(Reflection.Property(_CreatureBoardAsset, "CreatureId", (string)null).GetValue(asset).ToString(), "org.lordashes.plugins.retexture", false); }, "" }, 0); } else { Reflection.Execute(Reflection.Method(_SystemMessage, "DisplayInfoText", (string[])null), (object)null, new object[4] { "Retexture Plugin Requires A Selected Mini", Type.Missing, Type.Missing, Type.Missing }, 0); } } value = triggerResetKey.Value; if (((KeyboardShortcut)(ref value)).IsUp()) { LoggingPlugin.LogDebug("Reset Retexture Subscription"); if (subscriptionId != System.Guid.Empty) { AssetDataPlugin.Unsubscribe(subscriptionId); AssetDataPlugin.Subscribe("org.lordashes.plugins.retexture", (Action)RequestHandler, (Func)Checker.CheckSourceAsCreature); } } } private void RequestHandler(DatumChange change) { //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Expected O, but got Unknown //IL_05cf: Unknown result type (might be due to invalid IL or missing references) //IL_05d5: Invalid comparison between Unknown and I4 try { if (change.source != null && change.source != "" && change.key != null && change.value != null) { LoggingPlugin.LogDebug("Request To Retexture " + change.source + " To " + change.value); object obj = Reflection.New(_CreatureGuid, new object[1] { change.source.ToString() }); object obj2 = Reflection.Execute(Reflection.Method(_CreaturePresenter, "TryGetAsset", (string[])null), (object)null, new object[2] { obj, null }, 2); if (obj2 == null) { return; } string text = Reflection.Property(_CreatureBoardAsset, "Name", (string)null).GetValue(obj2).ToString(); LoggingPlugin.LogDebug("Asset " + text + " Acquired (" + obj2.GetType().ToString() + ")"); object value = Reflection.Property(_CreatureBoardAsset, "Link", (string)null).GetValue(obj2); string link = ((value != null) ? value.ToString() : ""); GameObject val = (GameObject)Reflection.Property(_CreatureBoardAsset, "gameObject", (string)null).GetValue(obj2); LoggingPlugin.LogDebug("Asset " + text + " GameObject Acquired (" + (((Object)(object)val != (Object)null) ? ((object)val).GetType().ToString() : "Null") + ")"); Renderer[] componentsInChildren = val.GetComponentsInChildren(); Renderer val2 = null; if (affectAuras.Value && link.Contains("AURA@")) { link = link.Substring(link.IndexOf("AURA@") + "AURA@".Length); if (link.Contains(";")) { link = link.Substring(0, link.IndexOf(";")); } LoggingPlugin.LogDebug("Creature Aura: " + link); val2 = componentsInChildren.Where((Renderer r) => ((Object)((Component)((Component)r).gameObject.transform.parent).gameObject).name.EndsWith("." + link)).FirstOrDefault(); if ((Object)(object)val2 != (Object)null) { LoggingPlugin.LogDebug("Applying To Aura Of Creature"); } } if ((Object)(object)val2 == (Object)null) { val2 = componentsInChildren.Where((Renderer r) => ((Object)r.material).name == "RETEXTURE_MAT").FirstOrDefault(); if ((Object)(object)val2 != (Object)null) { LoggingPlugin.LogDebug("Applying To RETEXTURE_MAP Component Of Creature"); } } if ((Object)(object)val2 == (Object)null) { val2 = componentsInChildren.Where((Renderer r) => ((Object)r.material.shader).name == "Standard").FirstOrDefault(); if ((Object)(object)val2 != (Object)null) { LoggingPlugin.LogDebug("Applying To ANGEL Creature"); } } if ((Object)(object)val2 == (Object)null) { val2 = componentsInChildren.Where((Renderer r) => ((Object)r.material.shader).name == "Taleweaver/CreatureShader").FirstOrDefault(); if ((Object)(object)val2 != (Object)null) { LoggingPlugin.LogDebug("Applying To Core Creature"); } } if ((Object)(object)val2 == (Object)null) { val2 = componentsInChildren.Where((Renderer r) => ((Object)r.material.shader).name == "Taleweaver/HShaderEmiss").FirstOrDefault(); if ((Object)(object)val2 != (Object)null) { LoggingPlugin.LogDebug("Applying To HeroForge Creature"); } } if ((Object)(object)val2 == (Object)null) { val2 = componentsInChildren.Where((Renderer r) => !((Object)r.material.shader).name.Contains("Taleweaver") && !((Object)r.material.shader).name.Contains("BaseGlowShader")).FirstOrDefault(); if ((Object)(object)val2 != (Object)null) { LoggingPlugin.LogDebug("Applying To TaleweaverLite Creature"); } } Renderer[] componentsInChildren2 = val.GetComponentsInChildren(); foreach (Renderer val3 in componentsInChildren2) { LoggingPlugin.LogDebug((((Object)(object)val3 == (Object)(object)val2) ? "> " : " ") + text + ", Parent: " + ((Object)((Component)((Component)val3).gameObject.transform.parent).gameObject).name + ", Renderer: " + ((Object)val3).name + ", Material: " + (((Object)(object)val3.material != (Object)null) ? ((Object)val3.material).name : "Null") + ", Shader: " + (((Object)(object)val3.material.shader != (Object)null) ? ((Object)val3.material.shader).name : "Null")); } LoggingPlugin.LogDebug("Modifying " + ((Object)((Component)((Component)val2).gameObject.transform.parent).gameObject).name + ": Renderer: " + ((Object)val2).name + ", Material " + ((Object)val2.material).name + ", Shader " + ((Object)val2.material.shader).name); if ((int)change.action != 1 && obj2 != null && (Object)(object)val2.material != (Object)null) { LoggingPlugin.LogDebug("Applying"); ApplyTexture(obj2, ((Component)val2).gameObject, val2, change.value.ToString().Replace("\"", "")); LoggingPlugin.LogDebug("Application Complete"); } else if (obj2 != null && (Object)(object)val2.material != (Object)null) { LoggingPlugin.LogDebug("Restoring"); RestoreTexture(obj2, val, val2); LoggingPlugin.LogDebug("Restoration Complete"); } } else { LoggingPlugin.LogWarning("Retexture Request Incomplete"); if (change.source == null || change.source == "") { LoggingPlugin.LogWarning("Retexture Request Missing Souce"); } if (change.key == null) { LoggingPlugin.LogWarning("Retexture Request Missing Key"); } if (change.value == null) { LoggingPlugin.LogWarning("Retexture Request Missing Value"); } } } catch (Exception ex) { Reflection.CatchFullError(ex); } } private void ApplyTexture(object asset, GameObject heirarchy, Renderer renderer, string source) { //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Expected O, but got Unknown if (asset != null && (Object)(object)renderer.material != (Object)null && source != null && source != "") { object value = Reflection.Property(_CreatureBoardAsset, "Name", (string)null).GetValue(asset); object value2 = Reflection.Property(_CreatureBoardAsset, "CreatureId", (string)null).GetValue(asset); if (!originalMaterials.ContainsKey(value2)) { LoggingPlugin.LogDebug("Storing orignal " + value?.ToString() + " material (" + ((Object)renderer.material).name + ")"); originalMaterials.Add(value2, new ReplacementMateiral { renderer = renderer, material = new Material(renderer.material) }); } if (source.ToString().ToLower().EndsWith(".mp4") || source.ToString().ToLower().EndsWith(".mov") || source.ToString().ToLower().EndsWith(".webm") || source.ToString().ToLower().EndsWith(".wmv")) { LoggingPlugin.LogDebug("Retexturing " + value?.ToString() + " with Video (" + ((Object)renderer.material).name + ":" + ((Object)renderer.material.mainTexture).name + ") from '" + source + "'"); ApplyVideo(heirarchy, new ReplacementMateiral { renderer = renderer, material = renderer.material }, source); } else { LoggingPlugin.LogDebug("Retexturing " + value?.ToString() + " with Texture (" + ((Object)renderer.material).name + ":" + ((Object)renderer.material.mainTexture).name + ") from '" + source + "'"); renderer.material.mainTexture = (Texture)(object)LoadTextureRGBA32(source); } } else { LoggingPlugin.LogWarning("Apply Texture Has Null Asset, Null Mateiral, Or Null Source"); } } private void RestoreTexture(object asset, GameObject heirarchy, Renderer renderer) { //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Expected O, but got Unknown if (asset != null && (Object)(object)renderer.material != (Object)null) { string text = Reflection.Property(_CreatureBoardAsset, "Name", (string)null).GetValue(asset).ToString(); object value = Reflection.Property(_CreatureBoardAsset, "CreatureId", (string)null).GetValue(asset); VideoPlayer component = heirarchy.GetComponent(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } VideoPlayer[] componentsInChildren = heirarchy.GetComponentsInChildren(); foreach (VideoPlayer val in componentsInChildren) { Object.Destroy((Object)(object)val); } LoggingPlugin.LogDebug("Restoring " + text + " to original material (" + ((Object)originalMaterials[value].material).name + ")"); LoggingPlugin.LogDebug("Renderer Passed " + ((Object)renderer).name); LoggingPlugin.LogDebug("Renderer Stored " + ((Object)originalMaterials[value].renderer).name); renderer.material = new Material(originalMaterials[value].material); LoggingPlugin.LogDebug("Removing stored material for " + text); originalMaterials.Remove(value); } else { LoggingPlugin.LogWarning("Restore Texture Has Null Asset, or Null Mateiral"); } } private void ApplyVideo(GameObject heirarchy, ReplacementMateiral replacement, string source) { if ((Object)(object)heirarchy != (Object)null && ((Object)this).name != null && ((Object)this).name != "" && source != null && source != "") { VideoPlayer component = heirarchy.GetComponent(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } VideoPlayer[] componentsInChildren = heirarchy.GetComponentsInChildren(); foreach (VideoPlayer val in componentsInChildren) { Object.Destroy((Object)(object)val); } LoggingPlugin.LogDebug("Looking At Material " + ((Object)replacement.renderer).name + "." + ((Object)replacement.material).name); GameObject gameObject = ((Component)replacement.renderer).gameObject; VideoPlayer val2 = default(VideoPlayer); if (!gameObject.TryGetComponent(ref val2)) { val2 = gameObject.AddComponent(); } val2.playOnAwake = true; val2.source = (VideoSource)1; if (!source.ToString().ToLower().StartsWith("http")) { source = "file://" + source; } val2.url = source; val2.isLooping = true; } else { LoggingPlugin.LogWarning("Apply Vide Has Null Asset, Null Name, or Null Source"); } } public static Texture2D LoadTextureRGBA32(string rawFilePath) { //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Expected O, but got Unknown LoggingPlugin.LogDebug("Requesting Texture from '" + rawFilePath + "'"); string text = rawFilePath; try { LoggingPlugin.LogDebug("Search: " + rawFilePath); string[] array = File.Find(rawFilePath, (CacheType)999); string[] array2 = array; foreach (string text2 in array2) { LoggingPlugin.LogDebug("Found: " + text2); } text = ((array.Length != 0) ? array[0] : null); } catch (Exception ex) { Reflection.CatchFullError(ex); } LoggingPlugin.LogDebug("Loading Texture from '" + text + "'"); byte[] array3 = File.ReadAllBytes(text); Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false, false); if (!ImageConversion.LoadImage(val, array3, false)) { Debug.LogError((object)("Failed to load image: " + text)); return null; } ((Texture)val).wrapMode = (TextureWrapMode)1; ((Texture)val).filterMode = (FilterMode)1; val.Apply(); return val; } public static bool IsGuidWithOptionalText(string input) { if (string.IsNullOrWhiteSpace(input)) { return false; } return GuidWithOptionalSuffix.IsMatch(input); } }