Decompiled source of Reskin Switcher v1.2.0

ReskinSwitcherMod.dll

Decompiled 2 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using Gunfiguration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("ReskinSwitcherMod")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("N/A")]
[assembly: AssemblyProduct("ReskinSwitcherMod")]
[assembly: AssemblyCopyright("Copyright © N/A 2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("78ed1445-9a9d-438b-a7a8-350f9024e295")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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 ReskinSwitcherMod
{
	[HarmonyPatch]
	public static class Patches
	{
		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		[HarmonyPrefix]
		public static void ProcessNewCollectionSet(tk2dSpriteCollectionData value)
		{
			ProcessedCollections.ProcessNewCollection(value);
		}

		[HarmonyPatch(typeof(tk2dBaseSprite), "Awake")]
		[HarmonyPrefix]
		public static void ProcessNewCollectionAwake(tk2dBaseSprite __instance)
		{
			ProcessedCollections.ProcessNewCollection(__instance.Collection);
		}

		[HarmonyPatch(typeof(tk2dBaseSprite), "SetSprite", new Type[]
		{
			typeof(tk2dSpriteCollectionData),
			typeof(int)
		})]
		[HarmonyPatch(typeof(tk2dBaseSprite), "SetSprite", new Type[]
		{
			typeof(tk2dSpriteCollectionData),
			typeof(string)
		})]
		[HarmonyPrefix]
		public static void ProcessNewCollectionSS(tk2dSpriteCollectionData newCollection)
		{
			ProcessedCollections.ProcessNewCollection(newCollection);
		}

		[HarmonyPatch(typeof(tk2dTileMap), "Awake")]
		[HarmonyPrefix]
		public static void ProcessNewCollectionTilemap(tk2dTileMap __instance)
		{
			ProcessedCollections.ProcessNewCollection(__instance.spriteCollection);
		}

		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		[HarmonyPrefix]
		public static void ProcessNewCollectionTilemapCollection(tk2dSpriteCollectionData value)
		{
			ProcessedCollections.ProcessNewCollection(value);
		}

		[HarmonyPatch(typeof(GameManager), "ClearActiveGameData")]
		[HarmonyPrefix]
		public static void StartReskinRun()
		{
			if (ReskinLoader.groups == null)
			{
				return;
			}
			foreach (ReskinGroup value in ReskinLoader.groups.Values)
			{
				if (value != null && value.TryGetReskin(value.currentResprite, out var reskin))
				{
					reskin.OnNewRunStarted();
				}
			}
		}
	}
	[BepInPlugin("spapi.etg.reskinswitcher", "Reskin Switcher", "1.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string GUID = "spapi.etg.reskinswitcher";

		public const string NAME = "Reskin Switcher";

		public const string VERSION = "1.1.0";

		public void Awake()
		{
			ReskinLoader.LoadReskins();
			ReskinConfig.Init();
			Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "spapi.etg.reskinswitcher");
		}
	}
	public static class ProcessedCollections
	{
		public static readonly Dictionary<string, tk2dSpriteCollectionData> processed = new Dictionary<string, tk2dSpriteCollectionData>();

		public static bool TryGetCollection(string name, out tk2dSpriteCollectionData coll)
		{
			if (processed.TryGetValue(name, out coll))
			{
				return (Object)(object)coll != (Object)null;
			}
			coll = Assets.Collections.Find((tk2dSpriteCollectionData x) => ((Object)x).name == name);
			if ((Object)(object)coll == (Object)null)
			{
				return false;
			}
			processed[name] = coll;
			return true;
		}

		public static void ProcessNewCollection(tk2dSpriteCollectionData coll)
		{
			if ((Object)(object)coll == (Object)null || (processed.TryGetValue(((Object)coll).name, out var value) && (Object)(object)value != (Object)null))
			{
				return;
			}
			processed[((Object)coll).name] = coll;
			foreach (ReskinGroup value2 in ReskinLoader.groups.Values)
			{
				if (value2.TryGetReskin(value2.currentResprite, out var reskin))
				{
					reskin.ProcessCollection(coll, alsoApply: true);
				}
				foreach (ReskinBase reskin2 in value2.ReskinList)
				{
					reskin2.ProcessCollection(coll, alsoApply: false);
				}
			}
		}
	}
	public abstract class ReplacementBase
	{
		public string collName;

		public tk2dSpriteCollectionData loadedCollection;

		public abstract void ApplyResprites(tk2dSpriteCollectionData coll);

		public abstract void UnapplyResprites(tk2dSpriteCollectionData coll);
	}
	public class SpritesheetReplacement : ReplacementBase
	{
		public Texture2D spritesheet;

		public Dictionary<Material, Texture> previousDefinitions = new Dictionary<Material, Texture>();

		public override void ApplyResprites(tk2dSpriteCollectionData coll)
		{
			if (coll.materials == null || coll.materials.Length == 0)
			{
				return;
			}
			Material val = coll.materials[0];
			if (!Object.op_Implicit((Object)(object)val))
			{
				return;
			}
			Texture mainTexture = val.mainTexture;
			if (!Object.op_Implicit((Object)(object)mainTexture))
			{
				return;
			}
			string name = ((Object)mainTexture).name;
			if (string.IsNullOrEmpty(name) || name[0] == '~')
			{
				return;
			}
			((Object)spritesheet).name = "~" + name;
			for (int i = 0; i < coll.materials.Length; i++)
			{
				Material obj = coll.materials[i];
				if (!((Object)(object)((obj != null) ? obj.mainTexture : null) == (Object)null))
				{
					previousDefinitions[coll.materials[i]] = coll.materials[i].mainTexture;
					coll.materials[i].mainTexture = (Texture)(object)spritesheet;
				}
			}
			coll.inst.materialInsts = null;
			coll.inst.Init();
			if (!((Object)(object)coll.inst != (Object)(object)coll) || coll.inst?.materials == null)
			{
				return;
			}
			for (int j = 0; j < coll.inst.materials.Length; j++)
			{
				Material obj2 = coll.inst.materials[j];
				if (!((Object)(object)((obj2 != null) ? obj2.mainTexture : null) == (Object)null))
				{
					previousDefinitions[coll.inst.materials[j]] = coll.inst.materials[j].mainTexture;
					coll.inst.materials[j].mainTexture = (Texture)(object)spritesheet;
				}
			}
		}

		public override void UnapplyResprites(tk2dSpriteCollectionData coll)
		{
			foreach (KeyValuePair<Material, Texture> previousDefinition in previousDefinitions)
			{
				if ((Object)(object)previousDefinition.Key != (Object)null)
				{
					previousDefinition.Key.mainTexture = previousDefinition.Value;
				}
			}
			previousDefinitions.Clear();
		}
	}
	public class IndividualReplacement : ReplacementBase
	{
		public class DefinitionInfoCache
		{
			public FlipMode flipped;

			public Material materialInst;

			public Vector2 texelSize;

			public bool extractRegion;

			public Vector2[] uvs;

			public Vector3 position0;

			public Vector3 position1;

			public Vector3 position2;

			public Vector3 position3;

			public Vector3 boundsCenter;

			public Vector3 boundsExtents;

			public Vector3 untrimmedBoundsCenter;

			public Vector3 untrimmedBoundsExtents;
		}

		public class DefinitionReplacementInfo
		{
			public Texture2D texture;

			public RuntimeAtlasSegment pack;

			public bool hasSavedTrimData;

			public int? minX;

			public int? maxX;

			public int? minY;

			public int? maxY;
		}

		public Dictionary<string, DefinitionReplacementInfo> definitionReplacements;

		public Dictionary<tk2dSpriteDefinition, DefinitionInfoCache> previousDefinitions = new Dictionary<tk2dSpriteDefinition, DefinitionInfoCache>();

		public bool advanced;

		public override void ApplyResprites(tk2dSpriteCollectionData coll)
		{
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: 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_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Expected O, but got Unknown
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: Unknown result type (might be due to invalid IL or missing references)
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_025e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Unknown result type (might be due to invalid IL or missing references)
			//IL_026a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_04af: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0436: Unknown result type (might be due to invalid IL or missing references)
			//IL_0440: Unknown result type (might be due to invalid IL or missing references)
			//IL_0445: Unknown result type (might be due to invalid IL or missing references)
			//IL_0477: Unknown result type (might be due to invalid IL or missing references)
			//IL_0481: Unknown result type (might be due to invalid IL or missing references)
			//IL_0486: Unknown result type (might be due to invalid IL or missing references)
			//IL_048a: Unknown result type (might be due to invalid IL or missing references)
			//IL_048f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0491: Unknown result type (might be due to invalid IL or missing references)
			//IL_0496: Unknown result type (might be due to invalid IL or missing references)
			//IL_049c: Unknown result type (might be due to invalid IL or missing references)
			//IL_049e: Unknown result type (might be due to invalid IL or missing references)
			//IL_04bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c7: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val5 = default(Vector3);
			Vector3 val6 = default(Vector3);
			foreach (KeyValuePair<string, DefinitionReplacementInfo> definitionReplacement in definitionReplacements)
			{
				tk2dSpriteDefinition spriteDefinition = coll.GetSpriteDefinition(definitionReplacement.Key);
				if (spriteDefinition == null)
				{
					continue;
				}
				DefinitionReplacementInfo value = definitionReplacement.Value;
				Texture2D texture = value.texture;
				DefinitionReplacementInfo definitionReplacementInfo = value;
				RuntimeAtlasSegment val = definitionReplacementInfo.pack ?? (definitionReplacementInfo.pack = Assets.Packer.Pack(texture, false));
				if (val == null)
				{
					continue;
				}
				previousDefinitions[spriteDefinition] = new DefinitionInfoCache
				{
					extractRegion = spriteDefinition.extractRegion,
					flipped = spriteDefinition.flipped,
					materialInst = spriteDefinition.materialInst,
					texelSize = spriteDefinition.texelSize,
					uvs = spriteDefinition.uvs,
					position0 = spriteDefinition.position0,
					position1 = spriteDefinition.position1,
					position2 = spriteDefinition.position2,
					position3 = spriteDefinition.position3,
					boundsCenter = spriteDefinition.boundsDataCenter,
					boundsExtents = spriteDefinition.boundsDataExtents,
					untrimmedBoundsCenter = spriteDefinition.untrimmedBoundsDataCenter,
					untrimmedBoundsExtents = spriteDefinition.untrimmedBoundsDataExtents
				};
				spriteDefinition.flipped = (FlipMode)0;
				spriteDefinition.materialInst = new Material(spriteDefinition.material);
				spriteDefinition.texelSize = ((Texture)texture).texelSize;
				spriteDefinition.extractRegion = true;
				spriteDefinition.materialInst.mainTexture = (Texture)(object)val.texture;
				spriteDefinition.uvs = val.uvs;
				if (!advanced)
				{
					continue;
				}
				Vector3 val2 = spriteDefinition.position3 - spriteDefinition.position0;
				Vector3 val3 = new Vector3((float)((Texture)texture).width, (float)((Texture)texture).height) / 16f;
				Vector3 val4 = val3 - val2;
				((Vector3)(ref val5))..ctor(val4.x / 2f, 0f);
				((Vector3)(ref val6))..ctor(0f, val4.y / 2f);
				spriteDefinition.position0 += -val5 - val6;
				spriteDefinition.position1 += val5 - val6;
				spriteDefinition.position2 += -val5 + val6;
				spriteDefinition.position3 += val5 + val6;
				Color[] pixels = texture.GetPixels();
				int? minX = null;
				int? maxX = null;
				int? minY = null;
				int? maxY = null;
				if (value.hasSavedTrimData)
				{
					minX = value.minX;
					maxX = value.maxX;
					minY = value.minY;
					maxY = value.maxY;
				}
				else if (ETGMod.IsReadable(texture))
				{
					for (int i = 0; i < pixels.Length; i++)
					{
						Color val7 = pixels[i];
						if (!(val7.a <= 0f))
						{
							int num = i % ((Texture)texture).width;
							int num2 = i / ((Texture)texture).width;
							int valueOrDefault = minY.GetValueOrDefault();
							if (!minY.HasValue)
							{
								valueOrDefault = num2;
								minY = valueOrDefault;
							}
							maxY = num2;
							minX = Mathf.Min(minX.GetValueOrDefault(int.MaxValue), num);
							maxX = Mathf.Max(maxX.GetValueOrDefault(int.MinValue), num);
						}
					}
				}
				if (!value.hasSavedTrimData)
				{
					value.minX = minX;
					value.maxX = maxX;
					value.minY = minY;
					value.maxY = maxY;
					value.hasSavedTrimData = true;
				}
				if (minX.HasValue && maxX.HasValue && minY.HasValue && maxY.HasValue)
				{
					int num3 = maxX.GetValueOrDefault() - minX.GetValueOrDefault() + 1;
					int num4 = maxY.GetValueOrDefault() - minY.GetValueOrDefault() + 1;
					Vector3 boundsDataExtents = new Vector3((float)num3, (float)num4) / 16f;
					Vector3 val8 = new Vector3((float)(maxX.GetValueOrDefault() + minX.GetValueOrDefault() + 1) / 2f, (float)(maxY.GetValueOrDefault() + minY.GetValueOrDefault() + 1) / 2f) / 16f;
					spriteDefinition.boundsDataCenter = spriteDefinition.position0 + val8;
					spriteDefinition.boundsDataExtents = boundsDataExtents;
				}
				else
				{
					spriteDefinition.boundsDataExtents += val4;
				}
				spriteDefinition.untrimmedBoundsDataExtents += val4;
			}
		}

		public override void UnapplyResprites(tk2dSpriteCollectionData coll)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			foreach (KeyValuePair<tk2dSpriteDefinition, DefinitionInfoCache> previousDefinition in previousDefinitions)
			{
				if (previousDefinition.Key != null)
				{
					tk2dSpriteDefinition key = previousDefinition.Key;
					DefinitionInfoCache value = previousDefinition.Value;
					key.flipped = value.flipped;
					key.materialInst = value.materialInst;
					key.texelSize = value.texelSize;
					key.extractRegion = value.extractRegion;
					key.uvs = value.uvs;
					key.position0 = value.position0;
					key.position1 = value.position1;
					key.position2 = value.position2;
					key.position3 = value.position3;
					key.boundsDataCenter = value.boundsCenter;
					key.boundsDataExtents = value.boundsExtents;
					key.untrimmedBoundsDataCenter = value.untrimmedBoundsCenter;
					key.untrimmedBoundsDataExtents = value.untrimmedBoundsExtents;
				}
			}
			previousDefinitions.Clear();
		}
	}
	public class ReskinGroup
	{
		public string name;

		public string currentResprite;

		public RandomReskin randomReskin;

		public EmptyReskin emptyReskin;

		public Dictionary<string, NamedReskin> reskins;

		public List<ReskinBase> ReskinList
		{
			get
			{
				ReskinBase item = emptyReskin;
				Dictionary<string, NamedReskin>.ValueCollection values = reskins.Values;
				List<ReskinBase> list = new List<ReskinBase>(2 + values.Count);
				list.Add(item);
				foreach (NamedReskin item2 in values)
				{
					list.Add(item2);
				}
				list.Add(randomReskin);
				return list;
			}
		}

		public List<ReskinBase> ReskinListNoRandom
		{
			get
			{
				ReskinBase item = emptyReskin;
				Dictionary<string, NamedReskin>.ValueCollection values = reskins.Values;
				List<ReskinBase> list = new List<ReskinBase>(1 + values.Count);
				list.Add(item);
				foreach (NamedReskin item2 in values)
				{
					list.Add(item2);
				}
				return list;
			}
		}

		public ReskinGroup()
		{
			randomReskin = new RandomReskin
			{
				group = this
			};
			emptyReskin = new EmptyReskin
			{
				group = this
			};
		}

		public bool TryGetReskin(string name, out ReskinBase reskin)
		{
			if (name == ReskinConfig.NoResprite)
			{
				reskin = null;
				return false;
			}
			if (name == ReskinConfig.RandomResprite)
			{
				reskin = randomReskin;
				return true;
			}
			if (reskins.TryGetValue(name, out var value))
			{
				reskin = value;
				return true;
			}
			reskin = null;
			return false;
		}
	}
	public abstract class ReskinBase
	{
		public List<ReplacementBase> replacements = new List<ReplacementBase>();

		public ReskinGroup group;

		public abstract string Name { get; }

		public virtual void ApplyReplacements()
		{
			foreach (ReplacementBase replacement in replacements)
			{
				if (!((Object)(object)replacement.loadedCollection == (Object)null))
				{
					replacement.ApplyResprites(replacement.loadedCollection);
				}
			}
		}

		public virtual void UnapplyReplacements()
		{
			foreach (ReplacementBase replacement in replacements)
			{
				if (!((Object)(object)replacement.loadedCollection == (Object)null))
				{
					replacement.UnapplyResprites(replacement.loadedCollection);
				}
			}
		}

		public virtual void LoadCollections(bool alsoApply)
		{
			foreach (ReplacementBase replacement in replacements)
			{
				if (ProcessedCollections.TryGetCollection(replacement.collName, out replacement.loadedCollection) && alsoApply)
				{
					replacement.ApplyResprites(replacement.loadedCollection);
				}
			}
		}

		public virtual void ProcessCollection(tk2dSpriteCollectionData coll, bool alsoApply)
		{
			if ((Object)(object)coll == (Object)null)
			{
				return;
			}
			foreach (ReplacementBase replacement in replacements)
			{
				if (!((Object)(object)replacement.loadedCollection != (Object)null) && !(replacement.collName != ((Object)coll).name))
				{
					replacement.loadedCollection = coll;
					if (alsoApply)
					{
						replacement.ApplyResprites(coll);
					}
				}
			}
		}

		public virtual void OnNewRunStarted()
		{
		}
	}
	public class NamedReskin : ReskinBase
	{
		public string _name;

		public override string Name => _name;
	}
	public class EmptyReskin : ReskinBase
	{
		public override string Name => ReskinConfig.NoResprite;

		public override void ApplyReplacements()
		{
		}

		public override void UnapplyReplacements()
		{
		}

		public override void LoadCollections(bool alsoApply)
		{
		}

		public override void ProcessCollection(tk2dSpriteCollectionData coll, bool alsoApply)
		{
		}
	}
	public class RandomReskin : ReskinBase
	{
		public override string Name => ReskinConfig.RandomResprite;

		public override void ApplyReplacements()
		{
			RandomizeReplacements();
			base.ApplyReplacements();
		}

		public override void LoadCollections(bool alsoApply)
		{
			RandomizeReplacements();
			base.LoadCollections(alsoApply);
		}

		public override void OnNewRunStarted()
		{
			UnapplyReplacements();
			ApplyReplacements();
		}

		public void RandomizeReplacements()
		{
			replacements.Clear();
			if (group != null)
			{
				List<ReskinBase> reskinListNoRandom = group.ReskinListNoRandom;
				if (reskinListNoRandom != null && reskinListNoRandom.Count > 0)
				{
					replacements.AddRange(BraveUtility.RandomElement<ReskinBase>(group.ReskinListNoRandom).replacements);
				}
			}
		}
	}
	public static class ReskinConfig
	{
		public static Gunfig gunfig;

		public static string NoResprite = "None";

		public static string RandomResprite = "Random";

		public static void Init()
		{
			if (ReskinLoader.groups.Count <= 0)
			{
				return;
			}
			gunfig = Gunfig.Get("Reskin Switcher");
			foreach (ReskinGroup value in ReskinLoader.groups.Values)
			{
				Gunfig obj = gunfig;
				string name = value.name;
				List<string> list = value.ReskinList.ConvertAll((ReskinBase x) => x.Name);
				Action<string, string> action = MaybeUpdateSprites;
				obj.AddScrollBox(name, list, "Current resprite for group \"" + value.name + "\"", action, (List<string>)null, (Update)1);
				value.currentResprite = gunfig.Value(value.name);
				foreach (ReskinBase reskin in value.ReskinList)
				{
					reskin.LoadCollections(reskin.Name == value.currentResprite);
				}
			}
		}

		public static void MaybeUpdateSprites(string key, string value)
		{
			if (ReskinLoader.groups.TryGetValue(key, out var value2))
			{
				if (value2.currentResprite != null && value2.TryGetReskin(value2.currentResprite, out var reskin))
				{
					reskin.UnapplyReplacements();
				}
				if (value2.TryGetReskin(value, out var reskin2))
				{
					reskin2.ApplyReplacements();
				}
				value2.currentResprite = value;
			}
		}
	}
	public static class ReskinLoader
	{
		public const string RESKIN_FILTER = "*-resprite.spapi";

		public const string READMODE_GROUPNAME = "GroupName";

		public const string READMODE_RESPRITENAME = "RespriteName";

		public const string READMODE_RESPRITEFILES = "RespriteFiles";

		public const string READMODE_ADVANCEDMODE = "AdvancedMode";

		public static Dictionary<string, ReskinGroup> groups = new Dictionary<string, ReskinGroup>();

		public static void LoadReskins()
		{
			string[] files = Directory.GetFiles(Paths.PluginPath, "*-resprite.spapi", SearchOption.AllDirectories);
			if (files == null)
			{
				return;
			}
			string[] array = files;
			foreach (string text in array)
			{
				string fileName = Path.GetFileName(text);
				Debug.Log((object)("[Reskin Switcher] Reading resprite file: " + fileName));
				if (!TryReadReskinData(text, out var groupName, out var replacementName, out var replacements, out var advancedMode))
				{
					continue;
				}
				if (Utility.IsNullOrWhiteSpace(groupName) || Utility.IsNullOrWhiteSpace(replacementName) || replacements.Count <= 0)
				{
					Debug.LogError((object)("Error reading resprite data file \"" + fileName + "\": GroupName, RespriteName and/or RespriteFiles are empty."));
					continue;
				}
				if (replacementName == ReskinConfig.NoResprite || replacementName == ReskinConfig.RandomResprite)
				{
					Debug.LogError((object)("Error reading resprite data file \"" + fileName + "\": RespriteName cannot be a special name (" + replacementName + ")."));
					continue;
				}
				List<ReplacementBase> list = ReadReplacementsForReskin(text, replacements, advancedMode);
				if (list.Count > 0)
				{
					NamedReskin namedReskin = new NamedReskin
					{
						_name = replacementName,
						replacements = list
					};
					if (!groups.TryGetValue(groupName, out var value))
					{
						Dictionary<string, ReskinGroup> dictionary = groups;
						string key = groupName;
						ReskinGroup obj = new ReskinGroup
						{
							name = groupName,
							reskins = new Dictionary<string, NamedReskin>()
						};
						value = obj;
						dictionary[key] = obj;
					}
					try
					{
						value.reskins.Add(replacementName, namedReskin);
						namedReskin.group = value;
						Debug.Log((object)("Successfully added resprite \"" + replacementName + "\" to group \"" + groupName + "\""));
					}
					catch
					{
						Debug.LogError((object)("Error loading resprite data file \"" + fileName + "\": resprite \"" + replacementName + "\" already exists."));
					}
				}
			}
		}

		public static List<ReplacementBase> ReadReplacementsForReskin(string f, List<string> replacements, bool advanced)
		{
			string fileName = Path.GetFileName(f);
			string directoryName = Path.GetDirectoryName(f);
			List<ReplacementBase> list = new List<ReplacementBase>();
			foreach (string replacement in replacements)
			{
				string text = Path.Combine(directoryName, replacement);
				string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(replacement);
				if (replacement.EndsWith(".png"))
				{
					Texture2D tex;
					if (!File.Exists(text))
					{
						Debug.LogError((object)("Error reading resprites for resprite data file \"" + fileName + "\": no file \"" + replacement + "\" exists in folder \"" + Path.GetFileName(directoryName) + "\"."));
					}
					else if (!TryReadImage(text, out tex))
					{
						Debug.LogError((object)("Error reading spritesheet resprite \"" + replacement + "\" for resprite data file \"" + fileName + "\": invalid image."));
					}
					else
					{
						list.Add(new SpritesheetReplacement
						{
							spritesheet = tex,
							collName = fileNameWithoutExtension
						});
					}
					continue;
				}
				if (!Directory.Exists(text))
				{
					Debug.LogError((object)("Error reading resprites for resprite data file \"" + fileName + "\": no folder \"" + replacement + "\" exists in folder \"" + Path.GetFileName(directoryName) + "\"."));
					continue;
				}
				IndividualReplacement individualReplacement = new IndividualReplacement
				{
					collName = fileNameWithoutExtension,
					definitionReplacements = new Dictionary<string, IndividualReplacement.DefinitionReplacementInfo>(),
					advanced = advanced
				};
				string[] files = Directory.GetFiles(text, "*.png");
				foreach (string text2 in files)
				{
					if (!TryReadImage(text2, out var tex2))
					{
						Debug.LogError((object)("Error reading individual resprite frame \"" + replacement + "/" + Path.GetFileName(text2) + "\" for resprite data file \"" + fileName + "\": invalid image."));
					}
					else if (!individualReplacement.definitionReplacements.ContainsKey(((Object)tex2).name))
					{
						individualReplacement.definitionReplacements[((Object)tex2).name] = new IndividualReplacement.DefinitionReplacementInfo
						{
							texture = tex2
						};
					}
					else
					{
						Debug.LogError((object)("Error reading individual resprite frame \"" + replacement + "/" + Path.GetFileName(text2) + "\" for resprite data file \"" + fileName + "\": frame named \"" + ((Object)tex2).name + "\" already exists."));
					}
				}
				if (individualReplacement.definitionReplacements.Count > 0)
				{
					list.Add(individualReplacement);
				}
			}
			return list;
		}

		public static bool TryReadImage(string f, out Texture2D tex)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			tex = new Texture2D(1, 1, (TextureFormat)4, false)
			{
				filterMode = (FilterMode)0,
				name = Path.GetFileNameWithoutExtension(f)
			};
			try
			{
				if (ImageConversion.LoadImage(tex, File.ReadAllBytes(f)))
				{
					return true;
				}
			}
			catch
			{
			}
			return false;
		}

		public static bool TryReadReskinData(string f, out string groupName, out string replacementName, out List<string> replacements, out bool advancedMode)
		{
			string fileName = Path.GetFileName(f);
			groupName = "";
			replacementName = "";
			replacements = new List<string>();
			advancedMode = false;
			string[] array = File.ReadAllLines(f);
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i];
				if (Utility.IsNullOrWhiteSpace(text))
				{
					continue;
				}
				string text2 = text.Trim();
				if (text2.StartsWith("#") && text2.Length > 1)
				{
					string text3 = text2.Substring(1).Trim().ToLowerInvariant();
					if (Utility.IsNullOrWhiteSpace(text3))
					{
						continue;
					}
					List<string> property;
					bool flag = TryReadDataProperty(array, ref i, out property);
					if (text3 == "GroupName".ToLowerInvariant())
					{
						if (flag)
						{
							groupName = property.LastOrDefault();
						}
						continue;
					}
					if (text3 == "RespriteName".ToLowerInvariant())
					{
						if (flag)
						{
							replacementName = property.LastOrDefault();
						}
						continue;
					}
					if (text3 == "RespriteFiles".ToLowerInvariant())
					{
						if (flag)
						{
							replacements.AddRange(property);
						}
						continue;
					}
					if (text3 == "AdvancedMode".ToLowerInvariant())
					{
						if (flag)
						{
							if (bool.TryParse(property.Last().ToLowerInvariant(), out var result))
							{
								advancedMode = result;
							}
							else
							{
								Debug.LogError((object)("Error reading resprite data file \"" + fileName + "\": unexpected value for AdvancedMode. Value can only be \"true\" or \"false\""));
							}
						}
						continue;
					}
					Debug.LogError((object)("Error reading resprite data file \"" + fileName + "\": read mode \"" + text3 + "\" doesn't exist."));
					return false;
				}
				Debug.LogError((object)("Error reading resprite data file \"" + fileName + "\": unexpected line \"" + text + "\"."));
				return false;
			}
			return true;
		}

		public static bool TryReadDataProperty(string[] lines, ref int index, out List<string> property)
		{
			property = new List<string>();
			index++;
			while (index < lines.Length)
			{
				string text = lines[index];
				if (!Utility.IsNullOrWhiteSpace(text))
				{
					string text2 = text.Trim();
					if (text2.StartsWith("#") && text2.Length > 1)
					{
						index--;
						break;
					}
					property.Add(text2);
				}
				index++;
			}
			return property.Count > 0;
		}
	}
}