using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using HarmonyLib;
using UnityEngine;
using UnityEngine.SceneManagement;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("CustomizerT2DOnly")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("CustomizerT2DOnly")]
[assembly: AssemblyTitle("CustomizerT2DOnly")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace CustomizerT2DOnly;
[BepInPlugin("com.yourname.customizer.t2donly", "CustomizerT2DOnly", "2.0.0")]
public class CustomizerT2DOnly : BaseUnityPlugin
{
[HarmonyPatch(typeof(Material), "set_mainTexture")]
internal static class H_Material_Setters
{
private static void Postfix(Material __instance, Texture value)
{
Texture2D val = (Texture2D)(object)((value is Texture2D) ? value : null);
if (val != null)
{
Instance?.TrySwap(val);
}
}
[HarmonyPatch(typeof(Material), "SetTexture", new Type[]
{
typeof(string),
typeof(Texture)
})]
[HarmonyPostfix]
private static void SetTexture_Postfix(Material __instance, string name, Texture value)
{
Texture2D val = (Texture2D)(object)((value is Texture2D) ? value : null);
if (val != null)
{
Instance?.TrySwap(val);
}
}
}
[HarmonyPatch(typeof(SpriteRenderer), "set_sprite")]
internal static class H_SpriteRenderer_SetSprite
{
private static void Postfix(Sprite value)
{
Texture2D val = (Object.op_Implicit((Object)(object)value) ? value.texture : null);
if (Object.op_Implicit((Object)(object)val))
{
Instance?.TrySwap(val);
}
}
}
internal static class H_UI_Image_SetSprite
{
public static void Postfix(object __instance, Sprite value)
{
if (Object.op_Implicit((Object)(object)value))
{
Texture2D texture = value.texture;
if (Object.op_Implicit((Object)(object)texture))
{
Instance?.TrySwap(texture);
}
}
}
}
[CompilerGenerated]
private sealed class <AdaptiveWatcher>d__41 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
public CustomizerT2DOnly <>4__this;
private Stopwatch <sw>5__2;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <AdaptiveWatcher>d__41(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<sw>5__2 = null;
<>1__state = -2;
}
private bool MoveNext()
{
//IL_0102: Unknown result type (might be due to invalid IL or missing references)
//IL_010c: Expected O, but got Unknown
int num = <>1__state;
CustomizerT2DOnly customizerT2DOnly = <>4__this;
if (num != 0)
{
if (num != 1)
{
return false;
}
<>1__state = -1;
}
else
{
<>1__state = -1;
<sw>5__2 = new Stopwatch();
}
if (customizerT2DOnly._keys != null && customizerT2DOnly._satisfiedKeys.Count < customizerT2DOnly._keys.Count)
{
if (customizerT2DOnly._scanSnapshot == null || customizerT2DOnly._scanIndex >= customizerT2DOnly._scanSnapshot.Length)
{
customizerT2DOnly._scanSnapshot = Resources.FindObjectsOfTypeAll<Texture2D>();
customizerT2DOnly._scanIndex = 0;
}
<sw>5__2.Restart();
while (customizerT2DOnly._scanIndex < customizerT2DOnly._scanSnapshot.Length && <sw>5__2.Elapsed.TotalMilliseconds < 3.0)
{
Texture2D val = customizerT2DOnly._scanSnapshot[customizerT2DOnly._scanIndex++];
if (Object.op_Implicit((Object)(object)val))
{
customizerT2DOnly.TrySwap(val);
}
}
<sw>5__2.Stop();
}
else
{
customizerT2DOnly._scanSnapshot = null;
customizerT2DOnly._scanIndex = 0;
}
<>2__current = (object)new WaitForSeconds(0.1f);
<>1__state = 1;
return true;
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
[CompilerGenerated]
private sealed class <WatchRoutine>d__34 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
public CustomizerT2DOnly <>4__this;
private float <elapsed>5__2;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <WatchRoutine>d__34(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Expected O, but got Unknown
int num = <>1__state;
CustomizerT2DOnly customizerT2DOnly = <>4__this;
switch (num)
{
default:
return false;
case 0:
<>1__state = -1;
<elapsed>5__2 = 0f;
break;
case 1:
<>1__state = -1;
<elapsed>5__2 += 0.5f;
break;
}
if (<elapsed>5__2 < 4f)
{
customizerT2DOnly.ApplyOverridesPass();
if (customizerT2DOnly._satisfiedKeys.Count < customizerT2DOnly._keys.Count)
{
<>2__current = (object)new WaitForSeconds(0.5f);
<>1__state = 1;
return true;
}
}
customizerT2DOnly._watchRoutine = null;
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();
}
}
private const float MENU_DELAY = 0.6f;
private const float GAMEPLAY_DELAY = 0.5f;
private const float WATCH_WINDOW_SECONDS = 4f;
private const float WATCH_TICK_SECONDS = 0.5f;
private const float ADAPTIVE_TICK = 0.1f;
private const double ADAPTIVE_BUDGET_MS = 3.0;
private static readonly string[] MENU_SCENE_PATTERNS = new string[3] { "menu", "mainmenu", "title" };
private static MethodInfo _miLoadImageBool;
private static MethodInfo _miLoadImage;
private static MethodInfo _miTexLoadImage;
private Dictionary<string, (byte[] bytes, int w, int h)> _map;
private HashSet<string> _keys;
private readonly HashSet<int> _replacedIds = new HashSet<int>();
private readonly HashSet<int> _notOurTex = new HashSet<int>();
private readonly HashSet<string> _satisfiedKeys = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
private bool _armedForGameplayOnce;
private Coroutine _watchRoutine;
private Coroutine _adaptiveRoutine;
private Type _typeSpriteAtlas;
private Type _typeSpriteAtlasManager;
private EventInfo _evAtlasRegistered;
private MethodInfo _miGetSprites_Array;
private Delegate _atlasCallbackDelegate;
private Texture2D[] _scanSnapshot;
private int _scanIndex;
private Harmony _harmony;
private static CustomizerT2DOnly Instance
{
get
{
GameObject managerObject = Chainloader.ManagerObject;
if (managerObject == null)
{
return null;
}
return managerObject.GetComponent<CustomizerT2DOnly>();
}
}
private void OnEnable()
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Expected O, but got Unknown
_harmony = new Harmony("com.yourname.customizer.t2donly.setters");
try
{
_harmony.PatchAll(typeof(H_Material_Setters));
_harmony.PatchAll(typeof(H_SpriteRenderer_SetSprite));
TryPatchUIImageSetter(_harmony);
}
catch (Exception arg)
{
((BaseUnityPlugin)this).Logger.LogWarning((object)$"[T2D] Harmony setters failed: {arg}");
}
TryHookSpriteAtlasRegistered();
SceneManager.sceneLoaded += OnSceneLoaded;
}
private void OnDisable()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
if (_watchRoutine != null)
{
((MonoBehaviour)this).StopCoroutine(_watchRoutine);
}
if (_adaptiveRoutine != null)
{
((MonoBehaviour)this).StopCoroutine(_adaptiveRoutine);
}
TryUnhookSpriteAtlasRegistered();
try
{
Harmony harmony = _harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
}
catch
{
}
}
private void Awake()
{
CacheLoadImageMethods();
}
private void Start()
{
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
BuildOverrideMap();
if (_keys != null && _keys.Count > 0 && _adaptiveRoutine == null)
{
_adaptiveRoutine = ((MonoBehaviour)this).StartCoroutine(AdaptiveWatcher());
}
Scene activeScene = SceneManager.GetActiveScene();
if (IsMenu(activeScene))
{
_armedForGameplayOnce = true;
((MonoBehaviour)this).Invoke("ApplyOnMenu", 0.6f);
}
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
if (IsMenu(scene))
{
_armedForGameplayOnce = true;
((MonoBehaviour)this).Invoke("ApplyOnMenu", 0.6f);
}
else if (_armedForGameplayOnce)
{
_armedForGameplayOnce = false;
((MonoBehaviour)this).Invoke("StartGameplayWatch", 0.5f);
}
}
private static bool IsMenu(Scene scene)
{
string text = ((Scene)(ref scene)).name ?? string.Empty;
string[] mENU_SCENE_PATTERNS = MENU_SCENE_PATTERNS;
foreach (string value in mENU_SCENE_PATTERNS)
{
if (text.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0)
{
return true;
}
}
return false;
}
private void ApplyOnMenu()
{
_satisfiedKeys.Clear();
ApplyOverridesPass();
}
private void StartGameplayWatch()
{
if (_watchRoutine != null)
{
((MonoBehaviour)this).StopCoroutine(_watchRoutine);
}
_watchRoutine = ((MonoBehaviour)this).StartCoroutine(WatchRoutine());
}
[IteratorStateMachine(typeof(<WatchRoutine>d__34))]
private IEnumerator WatchRoutine()
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <WatchRoutine>d__34(0)
{
<>4__this = this
};
}
private void CacheLoadImageMethods()
{
try
{
Type type = Type.GetType("UnityEngine.ImageConversion, UnityEngine.ImageConversionModule", throwOnError: false);
if (type != null)
{
_miLoadImageBool = type.GetMethod("LoadImage", BindingFlags.Static | BindingFlags.Public, null, new Type[3]
{
typeof(Texture2D),
typeof(byte[]),
typeof(bool)
}, null);
if (_miLoadImageBool == null)
{
_miLoadImage = type.GetMethod("LoadImage", BindingFlags.Static | BindingFlags.Public, null, new Type[2]
{
typeof(Texture2D),
typeof(byte[])
}, null);
}
}
_miTexLoadImage = typeof(Texture2D).GetMethod("LoadImage", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(byte[]) }, null);
}
catch
{
}
}
private bool LoadImageCompat(Texture2D tex, byte[] data, bool makeNoLongerReadable)
{
try
{
if ((Object)(object)tex == (Object)null || data == null)
{
return false;
}
if (_miLoadImageBool != null)
{
return (bool)_miLoadImageBool.Invoke(null, new object[3] { tex, data, makeNoLongerReadable });
}
if (_miLoadImage != null)
{
return (bool)_miLoadImage.Invoke(null, new object[2] { tex, data });
}
if (_miTexLoadImage != null)
{
return (bool)_miTexLoadImage.Invoke(tex, new object[1] { data });
}
return false;
}
catch
{
return false;
}
}
private static string NormalizeName(string name)
{
if (string.IsNullOrEmpty(name))
{
return name;
}
if (name.StartsWith("sactx-", StringComparison.OrdinalIgnoreCase))
{
int num = name.LastIndexOf('-');
if (num > 0 && num < name.Length - 1)
{
int num2 = name.Length - (num + 1);
if (num2 >= 6 && num2 <= 10)
{
bool flag = true;
for (int i = num + 1; i < name.Length; i++)
{
char c = name[i];
if ((c < '0' || c > '9') && (c < 'a' || c > 'f') && (c < 'A' || c > 'F'))
{
flag = false;
break;
}
}
if (flag)
{
return name.Substring(0, num);
}
}
}
}
return name;
}
private void BuildOverrideMap()
{
//IL_009b: Unknown result type (might be due to invalid IL or missing references)
//IL_00a2: Expected O, but got Unknown
_map = new Dictionary<string, (byte[], int, int)>(StringComparer.OrdinalIgnoreCase);
try
{
string path = Path.Combine(Application.dataPath, "Mods", "Customizer");
if (!Directory.Exists(path))
{
return;
}
string[] directories = Directory.GetDirectories(path);
foreach (string path2 in directories)
{
string path3 = Path.Combine(path2, "Texture2D");
if (!Directory.Exists(path3))
{
continue;
}
foreach (string item in Directory.EnumerateFiles(path3, "*.png", SearchOption.TopDirectoryOnly))
{
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(item);
string key = NormalizeName(fileNameWithoutExtension);
try
{
byte[] array = File.ReadAllBytes(item);
Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
if (LoadImageCompat(val, array, makeNoLongerReadable: false))
{
_map[key] = (array, ((Texture)val).width, ((Texture)val).height);
}
Object.Destroy((Object)(object)val);
}
catch
{
}
}
}
_keys = new HashSet<string>(_map.Keys, StringComparer.OrdinalIgnoreCase);
}
catch
{
}
}
private void ApplyOverridesPass()
{
if (_map != null && _map.Count != 0)
{
Texture2D[] array = Resources.FindObjectsOfTypeAll<Texture2D>();
for (int i = 0; i < array.Length; i++)
{
TrySwap(array[i]);
}
}
}
private bool TrySwap(Texture2D tex)
{
if (!Object.op_Implicit((Object)(object)tex))
{
return false;
}
int instanceID = ((Object)tex).GetInstanceID();
if (_replacedIds.Contains(instanceID) || _notOurTex.Contains(instanceID))
{
return false;
}
string text = NormalizeName(((Object)tex).name);
if (!_keys.Contains(text))
{
_notOurTex.Add(instanceID);
return false;
}
(byte[], int, int) tuple = _map[text];
if (((Texture)tex).width != tuple.Item2 || ((Texture)tex).height != tuple.Item3)
{
_notOurTex.Add(instanceID);
return false;
}
if (LoadImageCompat(tex, tuple.Item1, makeNoLongerReadable: false))
{
_replacedIds.Add(instanceID);
_satisfiedKeys.Add(text);
if (_replacedIds.Count > 16384 || _notOurTex.Count > 16384)
{
_replacedIds.Clear();
_notOurTex.Clear();
}
return true;
}
_notOurTex.Add(instanceID);
return false;
}
[IteratorStateMachine(typeof(<AdaptiveWatcher>d__41))]
private IEnumerator AdaptiveWatcher()
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <AdaptiveWatcher>d__41(0)
{
<>4__this = this
};
}
private void TryHookSpriteAtlasRegistered()
{
try
{
_typeSpriteAtlas = Type.GetType("UnityEngine.U2D.SpriteAtlas, UnityEngine.U2DModule", throwOnError: false);
_typeSpriteAtlasManager = Type.GetType("UnityEngine.U2D.SpriteAtlasManager, UnityEngine.U2DModule", throwOnError: false);
if (!(_typeSpriteAtlas == null) && !(_typeSpriteAtlasManager == null))
{
_evAtlasRegistered = _typeSpriteAtlasManager.GetEvent("atlasRegistered", BindingFlags.Static | BindingFlags.Public);
_miGetSprites_Array = _typeSpriteAtlas.GetMethod("GetSprites", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(Sprite[]) }, null);
if (!(_evAtlasRegistered == null) && !(_miGetSprites_Array == null))
{
MethodInfo method = typeof(CustomizerT2DOnly).GetMethod("OnAtlasRegisteredHandler", BindingFlags.Instance | BindingFlags.NonPublic);
Type type = typeof(Action<>).MakeGenericType(_typeSpriteAtlas);
_atlasCallbackDelegate = Delegate.CreateDelegate(type, this, method);
_evAtlasRegistered.GetAddMethod().Invoke(null, new object[1] { _atlasCallbackDelegate });
}
}
}
catch
{
}
}
private void TryUnhookSpriteAtlasRegistered()
{
try
{
if (_evAtlasRegistered != null && (object)_atlasCallbackDelegate != null)
{
_evAtlasRegistered.GetRemoveMethod().Invoke(null, new object[1] { _atlasCallbackDelegate });
}
}
catch
{
}
finally
{
_atlasCallbackDelegate = null;
_evAtlasRegistered = null;
_miGetSprites_Array = null;
_typeSpriteAtlas = null;
_typeSpriteAtlasManager = null;
}
}
private void OnAtlasRegisteredHandler(object atlasObj)
{
try
{
if (atlasObj == null || _miGetSprites_Array == null || _map == null || _map.Count == 0)
{
return;
}
Sprite[] array = (Sprite[])(object)new Sprite[1024];
int num = (int)_miGetSprites_Array.Invoke(atlasObj, new object[1] { array });
if (num <= 0)
{
return;
}
for (int i = 0; i < num && i < array.Length; i++)
{
Sprite val = array[i];
if (Object.op_Implicit((Object)(object)val))
{
Texture2D texture = val.texture;
if (Object.op_Implicit((Object)(object)texture))
{
TrySwap(texture);
}
}
}
}
catch
{
}
}
private void TryPatchUIImageSetter(Harmony h)
{
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Expected O, but got Unknown
try
{
Type type = Type.GetType("UnityEngine.UI.Image, UnityEngine.UI", throwOnError: false) ?? Type.GetType("UnityEngine.UI.Image, UnityEngine.UIModule", throwOnError: false);
if (!(type == null))
{
MethodInfo methodInfo = AccessTools.Property(type, "sprite")?.GetSetMethod();
if (!(methodInfo == null))
{
HarmonyMethod val = new HarmonyMethod(typeof(H_UI_Image_SetSprite).GetMethod("Postfix", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic));
h.Patch((MethodBase)methodInfo, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
((BaseUnityPlugin)this).Logger.LogInfo((object)"[T2D] Patched UI.Image.set_sprite");
}
}
}
catch
{
}
}
}