using System;
using System.Collections;
using System.Collections.Concurrent;
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.Threading.Tasks;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;
using UnityEngine.SceneManagement;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("TextureToolbox")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("TextureToolbox")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("f842a2ba-fbe0-4591-bd6f-16c316cedf7b")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace TextureToolbox;
public static class MaterialProcessor
{
public static void Process(Material mat)
{
if (!Object.op_Implicit((Object)(object)mat))
{
return;
}
int instanceID = ((Object)mat).GetInstanceID();
if (OptimizationCore.ProcessedMaterialIDs.Contains(instanceID))
{
return;
}
string text = null;
int num = OptimizationCore.TextureSlots.Length;
for (int i = 0; i < num; i++)
{
int num2 = OptimizationCore.TextureSlots[i];
if (!mat.HasProperty(num2))
{
continue;
}
Texture texture = mat.GetTexture(num2);
if (!Object.op_Implicit((Object)(object)texture))
{
continue;
}
long key = ((long)instanceID << 32) | (uint)num2;
if (OptimizationCore.MatSlotToCustomTexture.TryGetValue(key, out var value))
{
if ((Object)(object)value != (Object)null)
{
mat.SetTexture(num2, (Texture)(object)value);
if (num2 == OptimizationCore.EmissionMapID)
{
mat.EnableKeyword("_EMISSION");
}
}
continue;
}
if (text == null)
{
text = OptimizationCore.CleanName(((Object)mat).name);
}
string slotName = GetSlotName(num2);
if (Plugin.TryGetAdvancedMatch(text, slotName, texture, out var custom))
{
mat.SetTexture(num2, (Texture)(object)custom);
if (num2 == OptimizationCore.EmissionMapID)
{
mat.EnableKeyword("_EMISSION");
}
OptimizationCore.MatSlotToCustomTexture[key] = custom;
}
else
{
OptimizationCore.MatSlotToCustomTexture[key] = null;
}
}
OptimizationCore.ProcessedMaterialIDs.Add(instanceID);
}
private static string GetSlotName(int slotID)
{
if (slotID == OptimizationCore.TextureSlots[0])
{
return "_MainTex";
}
if (slotID == OptimizationCore.TextureSlots[1])
{
return "_BaseMap";
}
if (slotID == OptimizationCore.TextureSlots[2])
{
return "_EmissionMap";
}
return "";
}
}
public static class MeshRendererHandler
{
private static readonly List<Material> _matsBuffer = new List<Material>(16);
public static void Process(MeshRenderer renderer)
{
if (!Object.op_Implicit((Object)(object)renderer))
{
return;
}
((Renderer)renderer).GetSharedMaterials(_matsBuffer);
for (int i = 0; i < _matsBuffer.Count; i++)
{
if (Object.op_Implicit((Object)(object)_matsBuffer[i]))
{
MaterialProcessor.Process(_matsBuffer[i]);
}
}
_matsBuffer.Clear();
}
}
public static class OptimizationCore
{
public static readonly int[] TextureSlots = new int[3]
{
Shader.PropertyToID("_MainTex"),
Shader.PropertyToID("_BaseMap"),
Shader.PropertyToID("_EmissionMap")
};
public static readonly int EmissionMapID = Shader.PropertyToID("_EmissionMap");
public static readonly HashSet<int> ProcessedMaterialIDs = new HashSet<int>();
public static readonly Dictionary<long, Texture2D> MatSlotToCustomTexture = new Dictionary<long, Texture2D>();
public static readonly Dictionary<int, Texture2D> TextureIDToCustomTexture = new Dictionary<int, Texture2D>();
public static readonly HashSet<int> CustomTextureIDs = new HashSet<int>();
public static void Init()
{
SceneManager.sceneLoaded += OnSceneLoaded;
}
private static void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
ProcessedMaterialIDs.Clear();
}
public static void ClearAllCaches()
{
ProcessedMaterialIDs.Clear();
MatSlotToCustomTexture.Clear();
TextureIDToCustomTexture.Clear();
CustomTextureIDs.Clear();
}
public static string CleanName(string name)
{
if (string.IsNullOrEmpty(name))
{
return name;
}
if (name.EndsWith(" (Instance)"))
{
return name.Substring(0, name.Length - 11);
}
if (name.EndsWith("(Instance)"))
{
return name.Substring(0, name.Length - 10);
}
return name;
}
}
public static class RendererManager
{
[CompilerGenerated]
private sealed class <FastSelfHealingSweep>d__0 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
private Renderer[] <allRenderers>5__1;
private int <objectsProcessedThisFrame>5__2;
private int <i>5__3;
private Renderer <r>5__4;
private MeshRenderer <meshRenderer>5__5;
private SkinnedMeshRenderer <skinnedRenderer>5__6;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <FastSelfHealingSweep>d__0(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<allRenderers>5__1 = null;
<r>5__4 = null;
<meshRenderer>5__5 = null;
<skinnedRenderer>5__6 = null;
<>1__state = -2;
}
private bool MoveNext()
{
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Expected O, but got Unknown
//IL_018c: Unknown result type (might be due to invalid IL or missing references)
//IL_0196: Expected O, but got Unknown
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
<>2__current = (object)new WaitForSeconds(3f);
<>1__state = 1;
return true;
case 1:
<>1__state = -1;
goto IL_01ae;
case 2:
<>1__state = -1;
goto IL_014c;
case 3:
{
<>1__state = -1;
<allRenderers>5__1 = null;
goto IL_01ae;
}
IL_01ae:
<allRenderers>5__1 = Object.FindObjectsOfType<Renderer>();
<objectsProcessedThisFrame>5__2 = 0;
<i>5__3 = 0;
goto IL_016d;
IL_016d:
if (<i>5__3 < <allRenderers>5__1.Length)
{
<r>5__4 = <allRenderers>5__1[<i>5__3];
if (!Object.op_Implicit((Object)(object)<r>5__4))
{
goto IL_015b;
}
ref MeshRenderer reference = ref <meshRenderer>5__5;
Renderer obj = <r>5__4;
reference = (MeshRenderer)(object)((obj is MeshRenderer) ? obj : null);
if (<meshRenderer>5__5 != null)
{
MeshRendererHandler.Process(<meshRenderer>5__5);
}
else
{
ref SkinnedMeshRenderer reference2 = ref <skinnedRenderer>5__6;
Renderer obj2 = <r>5__4;
reference2 = (SkinnedMeshRenderer)(object)((obj2 is SkinnedMeshRenderer) ? obj2 : null);
if (<skinnedRenderer>5__6 != null)
{
SkinnedMeshHandler.Process(<skinnedRenderer>5__6);
}
<skinnedRenderer>5__6 = null;
}
<objectsProcessedThisFrame>5__2++;
if (<objectsProcessedThisFrame>5__2 >= 30)
{
<objectsProcessedThisFrame>5__2 = 0;
<>2__current = null;
<>1__state = 2;
return true;
}
goto IL_014c;
}
<>2__current = (object)new WaitForSeconds(10f);
<>1__state = 3;
return true;
IL_014c:
<r>5__4 = null;
<meshRenderer>5__5 = null;
goto IL_015b;
IL_015b:
<i>5__3++;
goto IL_016d;
}
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
[IteratorStateMachine(typeof(<FastSelfHealingSweep>d__0))]
public static IEnumerator FastSelfHealingSweep()
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <FastSelfHealingSweep>d__0(0);
}
}
public static class SkinnedMeshHandler
{
private static readonly List<Material> _matsBuffer = new List<Material>(16);
public static void Process(SkinnedMeshRenderer renderer)
{
if (!Object.op_Implicit((Object)(object)renderer))
{
return;
}
((Renderer)renderer).GetSharedMaterials(_matsBuffer);
for (int i = 0; i < _matsBuffer.Count; i++)
{
if (Object.op_Implicit((Object)(object)_matsBuffer[i]))
{
MaterialProcessor.Process(_matsBuffer[i]);
}
}
_matsBuffer.Clear();
}
}
public static class SpawnHooks
{
private static readonly List<Renderer> _rendererBuffer = new List<Renderer>(128);
[HarmonyPatch(typeof(Object), "Instantiate", new Type[] { typeof(Object) })]
[HarmonyPostfix]
public static void Postfix_Instantiate1(ref Object __result)
{
ProcessSpawn(__result);
}
[HarmonyPatch(typeof(Object), "Instantiate", new Type[]
{
typeof(Object),
typeof(Transform)
})]
[HarmonyPostfix]
public static void Postfix_Instantiate2(ref Object __result)
{
ProcessSpawn(__result);
}
[HarmonyPatch(typeof(Object), "Instantiate", new Type[]
{
typeof(Object),
typeof(Transform),
typeof(bool)
})]
[HarmonyPostfix]
public static void Postfix_Instantiate3(ref Object __result)
{
ProcessSpawn(__result);
}
[HarmonyPatch(typeof(Object), "Instantiate", new Type[]
{
typeof(Object),
typeof(Vector3),
typeof(Quaternion)
})]
[HarmonyPostfix]
public static void Postfix_Instantiate4(ref Object __result)
{
ProcessSpawn(__result);
}
[HarmonyPatch(typeof(Object), "Instantiate", new Type[]
{
typeof(Object),
typeof(Vector3),
typeof(Quaternion),
typeof(Transform)
})]
[HarmonyPostfix]
public static void Postfix_Instantiate5(ref Object __result)
{
ProcessSpawn(__result);
}
private static void ProcessSpawn(Object __result)
{
if (__result == (Object)null)
{
return;
}
GameObject val = (GameObject)(object)((__result is GameObject) ? __result : null);
if ((Object)(object)val == (Object)null)
{
Component val2 = (Component)(object)((__result is Component) ? __result : null);
if (val2 != null)
{
val = val2.gameObject;
}
}
if (!((Object)(object)val != (Object)null))
{
return;
}
val.GetComponentsInChildren<Renderer>(true, _rendererBuffer);
for (int i = 0; i < _rendererBuffer.Count; i++)
{
Renderer val3 = _rendererBuffer[i];
MeshRenderer val4 = (MeshRenderer)(object)((val3 is MeshRenderer) ? val3 : null);
if (val4 != null)
{
MeshRendererHandler.Process(val4);
continue;
}
SkinnedMeshRenderer val5 = (SkinnedMeshRenderer)(object)((val3 is SkinnedMeshRenderer) ? val3 : null);
if (val5 != null)
{
SkinnedMeshHandler.Process(val5);
}
}
_rendererBuffer.Clear();
}
}
public static class StateChangeHooks
{
[HarmonyPatch(typeof(Material), "SetTexture", new Type[]
{
typeof(int),
typeof(Texture)
})]
[HarmonyPrefix]
public static void Prefix_SetTextureInt(Material __instance, int nameID, ref Texture value)
{
if (!Object.op_Implicit((Object)(object)value) || OptimizationCore.CustomTextureIDs.Contains(((Object)value).GetInstanceID()))
{
return;
}
int instanceID = ((Object)__instance).GetInstanceID();
long key = ((long)instanceID << 32) | (uint)nameID;
if (Plugin.TryGetSuperMatch(value, out var custom))
{
value = (Texture)(object)custom;
OptimizationCore.MatSlotToCustomTexture[key] = custom;
return;
}
string matName = OptimizationCore.CleanName(((Object)__instance).name);
string slotName = GetSlotName(nameID);
if (Plugin.TryGetAdvancedMatch(matName, slotName, value, out var custom2))
{
value = (Texture)(object)custom2;
OptimizationCore.MatSlotToCustomTexture[key] = custom2;
}
}
[HarmonyPatch(typeof(Material), "SetTexture", new Type[]
{
typeof(string),
typeof(Texture)
})]
[HarmonyPrefix]
public static void Prefix_SetTextureString(Material __instance, string name, ref Texture value)
{
if (!Object.op_Implicit((Object)(object)value) || OptimizationCore.CustomTextureIDs.Contains(((Object)value).GetInstanceID()))
{
return;
}
int num = Shader.PropertyToID(name);
int instanceID = ((Object)__instance).GetInstanceID();
long key = ((long)instanceID << 32) | (uint)num;
if (Plugin.TryGetSuperMatch(value, out var custom))
{
value = (Texture)(object)custom;
OptimizationCore.MatSlotToCustomTexture[key] = custom;
return;
}
string matName = OptimizationCore.CleanName(((Object)__instance).name);
if (Plugin.TryGetAdvancedMatch(matName, name, value, out var custom2))
{
value = (Texture)(object)custom2;
OptimizationCore.MatSlotToCustomTexture[key] = custom2;
}
}
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
[HarmonyPrefix]
public static void Prefix_MainTexture(Material __instance, ref Texture value)
{
Prefix_SetTextureInt(__instance, OptimizationCore.TextureSlots[0], ref value);
}
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
[HarmonyPostfix]
public static void Postfix_SetMaterial(Material value)
{
if (Object.op_Implicit((Object)(object)value))
{
MaterialProcessor.Process(value);
}
}
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
[HarmonyPostfix]
public static void Postfix_SetSharedMaterial(Material value)
{
if (Object.op_Implicit((Object)(object)value))
{
MaterialProcessor.Process(value);
}
}
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
[HarmonyPostfix]
public static void Postfix_SetMaterials(Material[] value)
{
if (value == null)
{
return;
}
for (int i = 0; i < value.Length; i++)
{
if (Object.op_Implicit((Object)(object)value[i]))
{
MaterialProcessor.Process(value[i]);
}
}
}
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
[HarmonyPostfix]
public static void Postfix_SetSharedMaterials(Material[] value)
{
if (value == null)
{
return;
}
for (int i = 0; i < value.Length; i++)
{
if (Object.op_Implicit((Object)(object)value[i]))
{
MaterialProcessor.Process(value[i]);
}
}
}
private static string GetSlotName(int slotID)
{
if (slotID == OptimizationCore.TextureSlots[0])
{
return "_MainTex";
}
if (slotID == OptimizationCore.TextureSlots[1])
{
return "_BaseMap";
}
if (slotID == OptimizationCore.TextureSlots[2])
{
return "_EmissionMap";
}
return "";
}
}
public static class UIHooks
{
[HarmonyPatch(typeof(CanvasRenderer), "SetTexture")]
[HarmonyPrefix]
public static void Prefix_SetUITexture(ref Texture texture)
{
if (Object.op_Implicit((Object)(object)texture) && Plugin.TryGetSuperMatch(texture, out var custom))
{
texture = (Texture)(object)custom;
}
}
}
public static class WorldHooks
{
[HarmonyPatch(typeof(Resources), "Load", new Type[]
{
typeof(string),
typeof(Type)
})]
[HarmonyPostfix]
public static void Postfix_ResourcesLoad(ref Object __result)
{
Object obj = __result;
Texture val = (Texture)(object)((obj is Texture) ? obj : null);
if (val != null && Plugin.TryGetSuperMatch(val, out var custom))
{
__result = (Object)(object)custom;
}
}
[HarmonyPatch(typeof(AssetBundle), "LoadAsset", new Type[]
{
typeof(string),
typeof(Type)
})]
[HarmonyPostfix]
public static void Postfix_AssetBundleLoad(ref Object __result)
{
Object obj = __result;
Texture val = (Texture)(object)((obj is Texture) ? obj : null);
if (val != null && Plugin.TryGetSuperMatch(val, out var custom))
{
__result = (Object)(object)custom;
}
}
}
[BepInPlugin("com.thehalfbunny.texturetoolbox", "TextureToolbox", "2.8.0")]
public class Plugin : BaseUnityPlugin
{
[CompilerGenerated]
private sealed class <ProcessImageQueue>d__9 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
public Plugin <>4__this;
private Stopwatch <sw>5__1;
private (string name, byte[] data) <item>5__2;
private Texture2D <tex>5__3;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <ProcessImageQueue>d__9(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<sw>5__1 = null;
<item>5__2 = default((string, byte[]));
<tex>5__3 = null;
<>1__state = -2;
}
private bool MoveNext()
{
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: Expected O, but got Unknown
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
<sw>5__1 = new Stopwatch();
break;
case 1:
<>1__state = -1;
break;
}
if (!_isDiskReadingComplete || !_imageLoadQueue.IsEmpty)
{
<sw>5__1.Restart();
while (<sw>5__1.ElapsedMilliseconds < 5 && _imageLoadQueue.TryDequeue(out <item>5__2))
{
<tex>5__3 = new Texture2D(2, 2, (TextureFormat)4, true);
if (ImageConversion.LoadImage(<tex>5__3, <item>5__2.data))
{
((Object)<tex>5__3).name = <item>5__2.name;
((Texture)<tex>5__3).filterMode = (FilterMode)0;
<tex>5__3.Apply(true, true);
TextureVault[((Object)<tex>5__3).name] = <tex>5__3;
OptimizationCore.CustomTextureIDs.Add(((Object)<tex>5__3).GetInstanceID());
}
else
{
Object.Destroy((Object)(object)<tex>5__3);
}
<tex>5__3 = null;
}
<>2__current = null;
<>1__state = 1;
return true;
}
_isAsyncLoading = false;
Log.LogMessage((object)$"Async Vaulting Complete. Vaulted {TextureVault.Count} textures.");
return false;
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
public static Dictionary<string, Texture2D> TextureVault = new Dictionary<string, Texture2D>(StringComparer.OrdinalIgnoreCase);
public static string ImagePath;
public static ManualLogSource Log;
private static ConcurrentQueue<(string name, byte[] data)> _imageLoadQueue = new ConcurrentQueue<(string, byte[])>();
private static bool _isAsyncLoading = false;
private static bool _isDiskReadingComplete = false;
private void Awake()
{
//IL_006a: Unknown result type (might be due to invalid IL or missing references)
//IL_0070: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
Log.LogInfo((object)"TextureToolbox loaded!");
ImagePath = Path.Combine(Paths.PluginPath, "CustomImages");
if (!Directory.Exists(ImagePath))
{
Directory.CreateDirectory(ImagePath);
}
OptimizationCore.Init();
LoadAllImagesAsync();
((MonoBehaviour)this).StartCoroutine(RendererManager.FastSelfHealingSweep());
Harmony val = new Harmony("com.thehalfbunny.texturetoolbox.hooks");
try
{
val.PatchAll(typeof(WorldHooks));
val.PatchAll(typeof(UIHooks));
val.PatchAll(typeof(SpawnHooks));
val.PatchAll(typeof(StateChangeHooks));
Log.LogInfo((object)"Engine Online.");
}
catch (Exception ex)
{
Log.LogError((object)("Harmony Failure: " + ex.Message));
}
}
private void Update()
{
if (Input.GetKeyDown((KeyCode)291))
{
if (!_isAsyncLoading)
{
Log.LogWarning((object)"F10 Pressed: Flushing Cache & Async Reloading...");
LoadAllImagesAsync();
}
else
{
Log.LogWarning((object)"Already loading images, please wait...");
}
}
}
public void LoadAllImagesAsync()
{
if (!Directory.Exists(ImagePath))
{
return;
}
_isAsyncLoading = true;
_isDiskReadingComplete = false;
foreach (Texture2D value in TextureVault.Values)
{
if (Object.op_Implicit((Object)(object)value))
{
Object.Destroy((Object)(object)value);
}
}
TextureVault.Clear();
OptimizationCore.ClearAllCaches();
string[] files = Directory.GetFiles(ImagePath, "*.png", SearchOption.AllDirectories);
Task.Run(delegate
{
for (int i = 0; i < files.Length; i++)
{
try
{
string path = files[i];
byte[] item = File.ReadAllBytes(path);
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path);
_imageLoadQueue.Enqueue((fileNameWithoutExtension, item));
}
catch (Exception ex)
{
Log.LogWarning((object)("Failed to read " + files[i] + ": " + ex.Message));
}
}
_isDiskReadingComplete = true;
});
((MonoBehaviour)this).StartCoroutine(ProcessImageQueue());
}
[IteratorStateMachine(typeof(<ProcessImageQueue>d__9))]
private IEnumerator ProcessImageQueue()
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <ProcessImageQueue>d__9(0)
{
<>4__this = this
};
}
public static bool TryGetAdvancedMatch(string matName, string slotName, Texture orig, out Texture2D custom)
{
custom = null;
if (Object.op_Implicit((Object)(object)orig) && TryGetSuperMatch(orig, out custom))
{
return true;
}
if (!string.IsNullOrEmpty(matName))
{
string key = matName + "_" + slotName;
if (TextureVault.TryGetValue(key, out custom))
{
return true;
}
if (slotName == "_MainTex" || slotName == "_BaseMap")
{
string key2 = "MAT_" + matName;
if (TextureVault.TryGetValue(key2, out custom))
{
return true;
}
}
}
return false;
}
public static bool TryGetSuperMatch(Texture orig, out Texture2D custom)
{
custom = null;
if (!Object.op_Implicit((Object)(object)orig))
{
return false;
}
int instanceID = ((Object)orig).GetInstanceID();
if (OptimizationCore.TextureIDToCustomTexture.TryGetValue(instanceID, out custom))
{
return (Object)(object)custom != (Object)null;
}
string key = OptimizationCore.CleanName(((Object)orig).name);
if (TextureVault.TryGetValue(key, out custom))
{
OptimizationCore.TextureIDToCustomTexture[instanceID] = custom;
return true;
}
OptimizationCore.TextureIDToCustomTexture[instanceID] = null;
return false;
}
}