Decompiled source of CotLSpineLoader v1.1.1

plugins/CultTweaker/CultTweaker.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using COTL_API.CustomEnemy;
using COTL_API.CustomFollowerCommand;
using COTL_API.CustomInventory;
using COTL_API.CustomSkins;
using COTL_API.CustomStructures;
using COTL_API.CustomTarotCard;
using COTL_API.Guid;
using COTL_API.Helpers;
using CustomSpineLoader.APIHelper;
using CustomSpineLoader.Commands;
using CustomSpineLoader.MapEditor;
using CustomSpineLoader.SpineLoaderHelper;
using HarmonyLib;
using Lamb.UI;
using Lamb.UI.DeathScreen;
using MMBiomeGeneration;
using MMRoomGeneration;
using MMTools;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Pathfinding;
using Spine;
using Spine.Unity;
using Spine.Unity.AttachmentTools;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("CultTweaker")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+3fa0d3d17ee705a76e552500351e1d871466db99")]
[assembly: AssemblyProduct("CultTweaker")]
[assembly: AssemblyTitle("CultTweaker")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[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 CustomSpineLoader
{
	[BepInPlugin("InfernoDragon0.cotl.CustomSpineLoader", "CultTweaker", "1.1.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[HarmonyPatch]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "InfernoDragon0.cotl.CustomSpineLoader";

		public const string PluginName = "CultTweaker";

		public const string PluginVer = "1.1.1";

		internal static ManualLogSource Log;

		internal static readonly Harmony Harmony = new Harmony("InfernoDragon0.cotl.CustomSpineLoader");

		internal static string PluginPath;

		private RuntimeMapEditor runtimeMapEditor;

		public static ConfigEntry<int> CurrentFleeceIndexP1 { get; set; }

		public static ConfigEntry<int> CurrentFleeceIndexP2 { get; set; }

		public static ConfigEntry<bool> DebugDumpFollowerSpineAtlas { get; set; }

		public static ConfigEntry<bool> FleeceCyclingEnabled { get; set; }

		private void Awake()
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			PluginPath = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
			PlayerSpineLoader.LoadAllPlayerSpines();
			Log.LogInfo((object)"Cult Tweaker is loading! For more information or templates on how to use this mod, go to the NexusMods page!");
			CustomFollowerCommandManager.Add((CustomFollowerCommand)(object)new CustomColorCommand());
			StructureBuildingOverrideHelper.LoadBuildingOverrides();
			Log.LogInfo((object)"Loading Custom Items...");
			CustomItemLoader.LoadAllCustomItems();
			Log.LogInfo((object)"Loading Custom Meals...");
			CustomMealLoader.LoadAllCustomMeals();
			Log.LogInfo((object)"Loading Custom Tarots...");
			CustomTarotLoader.LoadAllCustomTarots();
			Log.LogInfo((object)"Loading Custom Structures...");
			CustomStructureLoader.LoadAllCustomStructures();
			Log.LogInfo((object)"Loading Custom Follower Overrides...");
			FollowerSpineLoader.LoadAllNonSpineSkins();
			CurrentFleeceIndexP1 = ((BaseUnityPlugin)this).Config.Bind<int>("Fleece", "CurrentFleeceIndexP1", -1, "Current Fleece Index for Player 1");
			CurrentFleeceIndexP2 = ((BaseUnityPlugin)this).Config.Bind<int>("Fleece", "CurrentFleeceIndexP2", -1, "Current Fleece Index for Player 2");
			DebugDumpFollowerSpineAtlas = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DumpFollowerSpineAtlas", false, "If true, will dump the follower spine slots to a json file. May impact performance when enabled. Ensure followerSlots.json is not present before dumping.");
			FleeceCyclingEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Fleece", "FleeceCyclingEnabled", true, "Enable Fleece Cycling for all players.");
			PlayerSpineLoader.currentFleeceIndexP1 = CurrentFleeceIndexP1.Value;
			PlayerSpineLoader.currentFleeceIndexP2 = CurrentFleeceIndexP2.Value;
			SceneManager.sceneLoaded += OnSceneLoaded;
			TryCreateRuntimeEditor(SceneManager.GetActiveScene());
			CustomDungeon customDungeon = new CustomDungeon();
			CustomDungeonManager.Add(customDungeon);
		}

		public void Update()
		{
			if (Input.GetKeyDown((KeyCode)290))
			{
				Log.LogInfo((object)("Toggling Fleece Cycling to " + !FleeceCyclingEnabled.Value));
				FleeceCyclingEnabled.Value = !FleeceCyclingEnabled.Value;
				if (!FleeceCyclingEnabled.Value && (Object)(object)PlayerFarming.Instance != (Object)null)
				{
					if (CoopManager.CoopActive)
					{
						PlayerFarming.players[1].SetSkin();
					}
					PlayerFarming.Instance.SetSkin();
				}
				else
				{
					TestApplySpineOverride(0, cycle: false);
				}
			}
			if (Input.GetKeyDown((KeyCode)288))
			{
				Log.LogInfo((object)"F7 Pressed - Fleece Cycle Player 1");
				TestApplySpineOverride();
			}
			if (Input.GetKeyDown((KeyCode)289))
			{
				Log.LogInfo((object)"F8 Pressed - Fleece Cycle Player 2");
				TestApplySpineOverride(1);
			}
			if (Input.GetKeyDown((KeyCode)286))
			{
				Log.LogInfo((object)"F5 Pressed - Test Custom Dungeon");
				CustomDungeonManager.CustomDungeonList.Values.ElementAt(0).EnterDungeon();
			}
			if (Input.GetKeyDown((KeyCode)285) && (Object)(object)runtimeMapEditor != (Object)null)
			{
				runtimeMapEditor.ToggleEditor();
			}
		}

		private void TestApplySpineOverride(int playerID = 0, bool cycle = true)
		{
			if (!FleeceCyclingEnabled.Value)
			{
				Log.LogWarning((object)"Fleece Cycling is disabled, Press F9 to enable first!");
				return;
			}
			int num = -1;
			if (cycle)
			{
				num = PlayerSpineLoader.CycleNextFleece(playerID);
			}
			else
			{
				if (1 == 0)
				{
				}
				int num2 = playerID switch
				{
					0 => CurrentFleeceIndexP1.Value, 
					1 => CurrentFleeceIndexP2.Value, 
					_ => -1, 
				};
				if (1 == 0)
				{
				}
				num = num2;
			}
			string text = PlayerSpineLoader.FleeceRotation[num];
			Log.LogInfo((object)("Applying fleece skin: " + text));
			SkeletonAnimation spine = PlayerFarming.Instance.Spine;
			if (playerID >= 1)
			{
				if (!CoopManager.CoopActive)
				{
					Log.LogInfo((object)"Coop not active, no fleece cycling");
					return;
				}
				spine = PlayerFarming.players[1].Spine;
				CurrentFleeceIndexP2.Value = num;
			}
			else
			{
				CurrentFleeceIndexP1.Value = num;
			}
			Skin val;
			if (text.Contains("CultTweaker_"))
			{
				string[] array = text.Split(new char[1] { '_' }, 3);
				if (array.Length < 3)
				{
					Log.LogWarning((object)("Invalid custom fleece skin name: " + text));
					return;
				}
				string text2 = array[1];
				if (!PlayerSpineLoader.FleeceCyclingSpines.ContainsKey(text2))
				{
					Log.LogWarning((object)("Invalid spine skin name: " + text + " for spine: " + text2));
					return;
				}
				val = PlayerSpineLoader.FleeceCyclingSpines[text2].Item1.skeletonData.FindSkin(array[2]);
				if (val == null)
				{
					Log.LogWarning((object)("Defaulting to default as Custom Fleece skin not found: " + text));
					val = ((SkeletonRenderer)spine).Skeleton.Data.FindSkin("Lamb");
				}
			}
			else
			{
				val = ((SkeletonRenderer)spine).Skeleton.Data.FindSkin(text);
			}
			if ((Object)(object)spine == (Object)null || val == null)
			{
				Log.LogInfo((object)("Lamb skin was null after cycling, an error occurred! at skin name " + text));
				return;
			}
			Skin skin = ((SkeletonRenderer)spine).Skeleton.Skin;
			foreach (var fleeceOverrideSlot in PlayerSpineLoader.FleeceOverrideSlots)
			{
				int num3 = ((SkeletonRenderer)spine).Skeleton.FindSlotIndex(fleeceOverrideSlot.Item1);
				Attachment attachment = val.GetAttachment(num3, fleeceOverrideSlot.Item2);
				Log.LogInfo((object)string.Format("Slot {0} index is {1}, attachment {2}", fleeceOverrideSlot.Item1, num3, (attachment != null) ? "found" : "not found"));
				if (attachment == null)
				{
					skin.RemoveAttachment(num3, fleeceOverrideSlot.Item2);
				}
				else
				{
					skin.SetAttachment(num3, fleeceOverrideSlot.Item2, attachment);
				}
				Log.LogInfo((object)("Applied " + fleeceOverrideSlot.Item2 + " attachment to current skin."));
			}
			Log.LogInfo((object)("Applied" + text + " attachment to current skin."));
			((SkeletonRenderer)spine).Skeleton.SetSlotsToSetupPose();
			spine.Update(0f, false);
		}

		private void OnEnable()
		{
			Harmony.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Loaded CultTweaker!");
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
		}

		private void TryCreateRuntimeEditor(Scene scene)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			if (!(((Scene)(ref scene)).name != "Dungeon1") && !((Object)(object)runtimeMapEditor != (Object)null))
			{
				GameObject val = new GameObject("RuntimeMapEditorHost");
				runtimeMapEditor = val.AddComponent<RuntimeMapEditor>();
				Object.DontDestroyOnLoad((Object)(object)val);
			}
		}

		private void DestroyRuntimeEditor()
		{
			if (!((Object)(object)runtimeMapEditor == (Object)null))
			{
				Object.Destroy((Object)(object)((Component)runtimeMapEditor).gameObject);
				runtimeMapEditor = null;
			}
		}

		private void OnDisable()
		{
			Harmony.UnpatchSelf();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Unloaded CultTweaker!");
		}
	}
}
namespace CustomSpineLoader.SpineLoaderHelper
{
	public class CustomColorHelper
	{
		public static Dictionary<int, CustomFollowerColor> CustomColors { get; private set; } = new Dictionary<int, CustomFollowerColor>();

		public static Dictionary<int, CustomFollowerSpineSkin> CustomFollowerSkinConfigs { get; private set; } = new Dictionary<int, CustomFollowerSpineSkin>();

		public static void LoadCustomColors(int saveSlot)
		{
			if (!File.Exists(Path.Combine(Plugin.PluginPath, $"CustomColors{saveSlot}.json")))
			{
				Plugin.Log.LogInfo((object)("Creating new CustomColors.json file for save slot " + saveSlot + "."));
				string contents = JsonConvert.SerializeObject((object)CustomColors, (Formatting)1);
				File.WriteAllText(Path.Combine(Plugin.PluginPath, $"CustomColors{saveSlot}.json"), contents);
			}
			else
			{
				string text = File.ReadAllText(Path.Combine(Plugin.PluginPath, $"CustomColors{saveSlot}.json"));
				CustomColors = JsonConvert.DeserializeObject<Dictionary<int, CustomFollowerColor>>(text) ?? new Dictionary<int, CustomFollowerColor>();
			}
		}

		public static void SaveCustomColors()
		{
			string contents = JsonConvert.SerializeObject((object)CustomColors, (Formatting)1);
			File.WriteAllText(Path.Combine(Plugin.PluginPath, $"CustomColors{SaveAndLoad.SAVE_SLOT}.json"), contents);
			Plugin.Log.LogInfo((object)"Saved custom colors");
		}

		public static CustomFollowerColor GetCustomColor(int id)
		{
			CustomFollowerColor value;
			return CustomColors.TryGetValue(id, out value) ? value : null;
		}

		public static float GetCustomScale(int id)
		{
			CustomFollowerColor value;
			return CustomColors.TryGetValue(id, out value) ? CustomColors[id].scale : (-1f);
		}

		public static void SetCustomColor(int id, float r, float g, float b, float a, float scale = 1f)
		{
			CustomFollowerColor value = new CustomFollowerColor(id, r, g, b, a, scale);
			CustomColors[id] = value;
			Plugin.Log.LogInfo((object)$"Set custom color for follower {id} to ({r}, {g}, {b}, {a}) with scale {scale}");
		}

		public static void SetCustomCostume(int id, bool enabled, int FollowerClothingType, int FollowerSpecialType, int FollowerHatType, int FollowerOutfitType, int FollowerNecklaceType)
		{
			if (CustomColors.ContainsKey(id))
			{
				CustomColors[id].CustomFollowerCostume = enabled;
				CustomColors[id].FollowerClothingType = FollowerClothingType;
				CustomColors[id].FollowerSpecialType = FollowerSpecialType;
				CustomColors[id].FollowerHatType = FollowerHatType;
				CustomColors[id].FollowerOutfitType = FollowerOutfitType;
				CustomColors[id].FollowerNecklaceType = FollowerNecklaceType;
				Plugin.Log.LogInfo((object)$"Set custom costume for follower {id} to ClothingType: {FollowerClothingType}, SpecialType: {FollowerSpecialType}, HatType: {FollowerHatType}, OutfitType: {FollowerOutfitType}");
			}
			else
			{
				Plugin.Log.LogWarning((object)("Tried to set custom costume for follower " + id + " but no custom color exists. Enable Customization first."));
			}
		}

		public static void RemoveCustomColor(int id)
		{
			if (CustomColors.ContainsKey(id))
			{
				CustomColors.Remove(id);
				Plugin.Log.LogInfo((object)$"Removed custom color for follower {id}");
			}
		}
	}
	[Serializable]
	public class CustomFollowerColor
	{
		public bool CustomFollowerCostume;

		public float scale;

		public int FollowerId { get; set; }

		public float R { get; set; }

		public float G { get; set; }

		public float B { get; set; }

		public float A { get; set; }

		public int FollowerClothingType { get; set; }

		public int FollowerSpecialType { get; set; }

		public int FollowerHatType { get; set; }

		public int FollowerOutfitType { get; set; }

		public int FollowerNecklaceType { get; set; }

		public CustomFollowerColor(int id, float r, float g, float b, float a, float scale = 1f)
		{
			FollowerId = id;
			R = Mathf.Clamp(r, 0f, 1f);
			G = Mathf.Clamp(g, 0f, 1f);
			B = Mathf.Clamp(b, 0f, 1f);
			A = Mathf.Clamp(a, 0f, 1f);
			CustomFollowerCostume = false;
			FollowerClothingType = 0;
			FollowerSpecialType = 0;
			FollowerHatType = 0;
			FollowerOutfitType = 0;
			FollowerNecklaceType = 0;
			this.scale = Mathf.Clamp(scale, 0.1f, 5f);
			base..ctor();
		}
	}
	[Serializable]
	public class CustomFollowerSpineSkin
	{
		public string SpineName;

		public List<string> SkinsApplied;
	}
	public class FollowerSpineLoader
	{
		public static Dictionary<string, List<Tuple<int, string, Texture2D, FollowerSkinPartConfig>>> FollowerSkinOverrides = new Dictionary<string, List<Tuple<int, string, Texture2D, FollowerSkinPartConfig>>>();

		public static Dictionary<string, List<SlotsAndColours>> FollowerSlotColors = new Dictionary<string, List<SlotsAndColours>>();

		public static Dictionary<string, Skin> CustomFollowerSkins = new Dictionary<string, Skin>();

		public static void LoadAllFollowerSpines(Material material = null)
		{
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Expected O, but got Unknown
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Expected O, but got Unknown
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Expected O, but got Unknown
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			string path = Path.Combine(Plugin.PluginPath, "FollowerSpines");
			if (!Directory.Exists(path))
			{
				Directory.CreateDirectory(path);
			}
			string[] directories = Directory.GetDirectories(path);
			string[] array = directories;
			foreach (string path2 in array)
			{
				string fileName = Path.GetFileName(path2);
				string[] array2 = (from x in Directory.GetFiles(path2, "*.json", SearchOption.TopDirectoryOnly)
					where !x.Contains("config")
					select x).ToArray();
				string[] files = Directory.GetFiles(path2, "*.png", SearchOption.TopDirectoryOnly);
				string[] files2 = Directory.GetFiles(path2, "*.atlas", SearchOption.TopDirectoryOnly);
				string[] files3 = Directory.GetFiles(path2, "config.json", SearchOption.TopDirectoryOnly);
				List<string> list = new List<string>(1) { "Cat" };
				string[] array3 = new string[0];
				if (files3.Length != 0)
				{
					TextAsset val = new TextAsset(File.ReadAllText(files3[0]));
					FollowerSpineConfig followerSpineConfig = JsonConvert.DeserializeObject<FollowerSpineConfig>(val.text);
					if (followerSpineConfig != null)
					{
						list = followerSpineConfig.DefaultSkin;
						array3 = followerSpineConfig.Skins;
						Plugin.Log.LogInfo((object)$"Using default skin: {list}");
						Plugin.Log.LogInfo((object)("Using skin list: " + string.Join(", ", array3)));
					}
				}
				if (array2.Length != 0 && files.Length != 0 && files2.Length != 0)
				{
					Plugin.Log.LogInfo((object)("Reading atlas from " + files2[0]));
					TextAsset val2 = new TextAsset(File.ReadAllText(files2[0]));
					Plugin.Log.LogInfo((object)("Reading skeleton from " + array2[0]));
					TextAsset val3 = new TextAsset(File.ReadAllText(array2[0]));
					Texture2D[] array4 = (Texture2D[])(object)new Texture2D[files.Length];
					string[] array5 = files;
					foreach (string text in array5)
					{
						Plugin.Log.LogInfo((object)("Reading texture from " + text));
						Texture2D val4 = TextureHelper.CreateTextureFromPath(text, (TextureFormat)4, false, false);
						((Object)val4).name = Path.GetFileNameWithoutExtension(text);
						array4[Array.IndexOf(files, text)] = val4;
					}
					Material val5 = (Material)(((object)material) ?? ((object)new Material(Shader.Find("Spine/Skeleton"))));
					SpineAtlasAsset val6 = SpineAtlasAsset.CreateRuntimeInstance(val2, array4, val5, true);
					SkeletonDataAsset val7 = SkeletonDataAsset.CreateRuntimeInstance(val3, (AtlasAssetBase)(object)val6, true, 0.005f);
					Plugin.Log.LogInfo((object)("Creating skeleton for " + fileName));
					Plugin.Log.LogInfo((object)("Using material name " + ((Object)val5).name));
					CustomSkinManager.AddFollowerSpine(fileName, val7);
					for (int num2 = 0; num2 < list.Count; num2++)
					{
						string text2 = list[num2];
					}
				}
				else
				{
					Plugin.Log.LogInfo((object)("Failed to load follower skin " + fileName + ", ensure that the folder contains at least one of each .json, .png and .atlas file."));
				}
			}
		}

		public static void LoadAllNonSpineSkins()
		{
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Expected O, but got Unknown
			string path = Path.Combine(Plugin.PluginPath, "FollowerSkins");
			if (!Directory.Exists(path))
			{
				Directory.CreateDirectory(path);
			}
			string[] directories = Directory.GetDirectories(path);
			string[] array = directories;
			foreach (string path2 in array)
			{
				string fileName = Path.GetFileName(path2);
				Plugin.Log.LogInfo((object)("Loading Follower Override Skin: " + fileName));
				List<string> list = new List<string>();
				string[] directories2 = Directory.GetDirectories(path2);
				foreach (string text in directories2)
				{
					Plugin.Log.LogInfo((object)("Creating Variant: " + Path.GetFileName(text)));
					string[] files = Directory.GetFiles(text, "*.png", SearchOption.TopDirectoryOnly);
					string[] files2 = Directory.GetFiles(text, "config.json", SearchOption.TopDirectoryOnly);
					Plugin.Log.LogInfo((object)("Variant has a total of " + files.Length + " overrides."));
					if (files2.Length != 0)
					{
						TextAsset val = new TextAsset(File.ReadAllText(files2[0]));
						FollowerSkinConfig followerSkinConfig = JsonConvert.DeserializeObject<FollowerSkinConfig>(val.text);
						if (followerSkinConfig == null)
						{
							Plugin.Log.LogWarning((object)("Failed to deserialize config.json for follower skin " + fileName + " variant: " + text + ", please check syntax."));
							continue;
						}
						Plugin.Log.LogInfo((object)("Variant will be created using base skin: " + followerSkinConfig.OverrideBaseSkin));
						List<Tuple<int, string, Texture2D, FollowerSkinPartConfig>> list2 = new List<Tuple<int, string, Texture2D, FollowerSkinPartConfig>>();
						foreach (KeyValuePair<string, FollowerSkinPartConfig> partConfig in followerSkinConfig.PartConfigs)
						{
							string key = partConfig.Key;
							FollowerSkinPartConfig value = partConfig.Value;
							string text2 = Path.Combine(text, key + ".png");
							Texture2D val2 = null;
							if (!File.Exists(text2))
							{
								Plugin.Log.LogWarning((object)("Part config " + key + " does not have a corresponding PNG file in the variant folder, using only config values!"));
							}
							else
							{
								Plugin.Log.LogInfo((object)("Reading texture from " + Path.GetFileName(text2)));
								val2 = TextureHelper.CreateTextureFromPath(text2, (TextureFormat)4, false, false);
								((Object)val2).name = Path.GetFileNameWithoutExtension(text2);
							}
							list2.Add(new Tuple<int, string, Texture2D, FollowerSkinPartConfig>(value.SlotIndex, value.PartName, val2, value));
						}
						Plugin.Log.LogInfo((object)(fileName + " variant " + text + " has a total of " + files.Length + " and " + list2.Count + " were registered successfully."));
						FollowerSkinOverrides.Add(fileName + "_" + Path.GetFileName(text), list2);
						FollowerSlotColors.Add(fileName + "_" + Path.GetFileName(text), BuildColorsByIndex(followerSkinConfig));
						string text3 = BuildCustomOverrideSkin(fileName + "_" + Path.GetFileName(text), followerSkinConfig.OverrideBaseSkin);
						if (text3 != null)
						{
							list.Add(text3);
						}
					}
					else
					{
						Plugin.Log.LogWarning((object)("No config.json found for follower skin " + fileName + " variant: " + text + ", please create one."));
					}
				}
				if (list.Count > 0)
				{
					Plugin.Log.LogInfo((object)("Creating Follower Skin " + fileName + " with " + list.Count + " variant(s)."));
					CreateNewFollowerType(list[0], list, FollowerSlotColors[list[0]]);
				}
			}
		}

		public static string BuildCustomOverrideSkin(string skinVariantName, string baseSkinName)
		{
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Expected O, but got Unknown
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Expected O, but got Unknown
			//IL_0416: Unknown result type (might be due to invalid IL or missing references)
			//IL_041d: Expected O, but got Unknown
			if (CustomFollowerSkins.ContainsKey(skinVariantName))
			{
				Plugin.Log.LogWarning((object)(skinVariantName + " has already been built!"));
				return null;
			}
			List<Tuple<int, string, Texture2D, FollowerSkinPartConfig>> list = FollowerSkinOverrides[skinVariantName];
			Skin val = ((SkeletonRenderer)WorshipperData.Instance.SkeletonData).Skeleton.Data.FindSkin(baseSkinName);
			if (val == null)
			{
				Plugin.Log.LogWarning((object)("Could not find base skin " + baseSkinName + " for variant " + skinVariantName + "! Defaulting to Cat."));
				val = ((SkeletonRenderer)WorshipperData.Instance.SkeletonData).Skeleton.Data.FindSkin("Cat");
			}
			Skin finalSkin = new Skin(skinVariantName);
			Plugin.Log.LogInfo((object)$"Attempting to build skin with {list.Count} override parts for variant {skinVariantName}");
			val.Attachments.ToList().ForEach(delegate(SkinEntry val11)
			{
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				finalSkin.SetAttachment(((SkinEntry)(ref val11)).SlotIndex, ((SkinEntry)(ref val11)).Name, val11.attachment.Copy());
			});
			((IEnumerable<BoneData>)val.Bones).ToList().ForEach((Action<BoneData>)finalSkin.Bones.Add);
			((IEnumerable<ConstraintData>)val.Constraints).ToList().ForEach((Action<ConstraintData>)finalSkin.Constraints.Add);
			foreach (Tuple<int, string, Texture2D, FollowerSkinPartConfig> item in list)
			{
				if (item.Item4.HideSlot)
				{
					finalSkin.RemoveAttachment(item.Item1, item.Item2);
					Plugin.Log.LogInfo((object)$"Hiding slot {item.Item1} for skin variant {skinVariantName}");
					continue;
				}
				if ((Object)(object)item.Item3 == (Object)null)
				{
					Plugin.Log.LogWarning((object)$"No texture found for override part {item.Item2} in slot {item.Item1} for skin variant {skinVariantName}, apply config values only");
					continue;
				}
				try
				{
					((Object)item.Item3).name = skinVariantName + "_" + item.Item2;
					Material val2 = new Material(Shader.Find("Spine/Skeleton"))
					{
						mainTexture = (Texture)(object)item.Item3
					};
					Material[] array = (Material[])(object)new Material[1] { val2 };
					SpineAtlasAsset val3 = SpineAtlasAsset.CreateRuntimeInstance(GenerateAtlasText(skinVariantName + "_" + item.Item2, item.Item2, ((Texture)item.Item3).width.ToString(), ((Texture)item.Item3).height.ToString()), array, true);
					Attachment attachment = val.GetAttachment(item.Item1, item.Item2);
					if (attachment == null)
					{
						continue;
					}
					attachment = attachment.Copy();
					float offsetX = item.Item4.OffsetX;
					float offsetY = item.Item4.OffsetY;
					float rotation = item.Item4.Rotation;
					float scaleX = item.Item4.ScaleX;
					float scaleY = item.Item4.ScaleY;
					Attachment val4 = attachment;
					Attachment val5 = val4;
					MeshAttachment val6 = (MeshAttachment)(object)((val5 is MeshAttachment) ? val5 : null);
					if (val6 == null)
					{
						RegionAttachment val7 = (RegionAttachment)(object)((val5 is RegionAttachment) ? val5 : null);
						if (val7 != null)
						{
							((Attachment)val7).Name = skinVariantName + "_" + item.Item2;
							((AtlasAssetBase)val3).GetAtlas().regions[0].name = "Custom" + ((AtlasAssetBase)val3).GetAtlas().regions[0].name;
							AttachmentRegionExtensions.SetRegion(val7, ((AtlasAssetBase)val3).GetAtlas().regions[0], true);
							val7.X += offsetX;
							val7.Y += offsetY;
							val7.ScaleX = scaleX;
							val7.ScaleY = scaleY;
							val7.rotation = rotation;
							finalSkin.SetAttachment(item.Item1, item.Item2, (Attachment)(object)val7);
						}
						else
						{
							Plugin.Log.LogWarning((object)("Attachment " + attachment.Name + " is not a MeshAttachment or RegionAttachment, skipping..."));
						}
					}
					else
					{
						float num = 2.1474836E+09f;
						float num2 = -2.1474836E+09f;
						float num3 = 2.1474836E+09f;
						float num4 = -2.1474836E+09f;
						for (int num5 = 0; num5 < ((VertexAttachment)val6).Vertices.Length; num5++)
						{
							switch (num5 % 3)
							{
							case 0:
								num3 = Math.Min(num3, ((VertexAttachment)val6).Vertices[num5]);
								num4 = Math.Max(num4, ((VertexAttachment)val6).Vertices[num5]);
								break;
							case 1:
								num = Math.Min(num, ((VertexAttachment)val6).Vertices[num5]);
								num2 = Math.Max(num2, ((VertexAttachment)val6).Vertices[num5]);
								break;
							}
						}
						float num6 = num2 - num;
						float num7 = num4 - num3;
						float num8 = num + num6 / 2f;
						float num9 = num3 + num7 / 2f;
						RegionAttachment val8 = new RegionAttachment(item.Item2);
						AttachmentRegionExtensions.SetRegion(val8, ((AtlasAssetBase)val3).GetAtlas().regions[0], true);
						val8.X = num9 - offsetY;
						val8.Y = num8 - offsetX;
						val8.rotation = rotation;
						val8.ScaleX = scaleX;
						val8.ScaleY = scaleY;
						val8.Width = num6;
						val8.Height = num7;
						finalSkin.SetAttachment(item.Item1, item.Item2, (Attachment)(object)val8);
					}
					Plugin.Log.LogInfo((object)("Attached override part " + item.Item2 + " to slot " + item.Item1 + " for skin variant " + skinVariantName));
				}
				catch (Exception ex)
				{
					Plugin.Log.LogError((object)("Failed to apply override part " + item.Item2 + " to skin variant " + skinVariantName + ": " + ex.Message));
					return null;
				}
			}
			Plugin.Log.LogInfo((object)("Successfully created skin variant " + skinVariantName));
			Material val9 = default(Material);
			Texture2D val10 = default(Texture2D);
			Skin repackedSkin = AtlasUtilities.GetRepackedSkin(finalSkin, skinVariantName, ((SkeletonRenderer)WorshipperData.Instance.SkeletonData).SkeletonDataAsset.atlasAssets[0].PrimaryMaterial, ref val9, ref val10, 1024, 2, (TextureFormat)4, false, true, false, (int[])null, (Texture2D[])null, (TextureFormat[])null, (bool[])null);
			CustomFollowerSkins.Add(skinVariantName, repackedSkin);
			DataManager.SetFollowerSkinUnlocked(skinVariantName);
			return skinVariantName;
		}

		public static void CreateNewFollowerType(string name, List<string> variantNames, List<SlotsAndColours> colors, bool hidden = false, bool twitchPremium = false, bool invariant = false)
		{
			//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_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: 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_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Expected O, but got Unknown
			List<CharacterSkin> skin = ((IEnumerable<string>)variantNames).Select((Func<string, CharacterSkin>)((string v) => new CharacterSkin
			{
				Skin = v
			})).ToList();
			WorshipperData.Instance.Characters.Add(new SkinAndData
			{
				Title = name,
				Skin = skin,
				SlotAndColours = colors,
				TwitchPremium = twitchPremium,
				_hidden = hidden,
				_dropLocation = (DropLocation)4,
				_invariant = invariant
			});
		}

		public static TextAsset GenerateAtlasText(string filename, string name, string width, string height)
		{
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Expected O, but got Unknown
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine();
			stringBuilder.AppendLine(filename ?? "");
			stringBuilder.AppendLine("size: " + width + ", " + height);
			stringBuilder.AppendLine("format: RGBA8888");
			stringBuilder.AppendLine("filter: Linear,Linear");
			stringBuilder.AppendLine("repeat: none");
			stringBuilder.AppendLine(name ?? "");
			stringBuilder.AppendLine("  rotate: false");
			stringBuilder.AppendLine("  xy: 0,0");
			stringBuilder.AppendLine("  size: " + width + "," + height);
			stringBuilder.AppendLine("  orig: " + width + "," + height);
			stringBuilder.AppendLine("  offset: 0,0");
			stringBuilder.AppendLine("  index: -1");
			return new TextAsset(stringBuilder.ToString());
		}

		public static List<SlotsAndColours> BuildColorsByIndex(FollowerSkinConfig config)
		{
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: 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_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Expected O, but got Unknown
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Expected O, but got Unknown
			//IL_00eb: 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_00fa: Expected O, but got Unknown
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Expected O, but got Unknown
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Expected O, but got Unknown
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Expected O, but got Unknown
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Expected O, but got Unknown
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Expected O, but got Unknown
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Expected O, but got Unknown
			//IL_01e3: Expected O, but got Unknown
			List<FollowerSkinPartConfig> parts = config.PartConfigs.Values.Where((FollowerSkinPartConfig p) => p.ColorChoices?.Any() ?? false).ToList();
			int num = parts.Min((FollowerSkinPartConfig p) => p.ColorChoices.Count);
			if (num == 0)
			{
				return new List<SlotsAndColours>(1)
				{
					new SlotsAndColours
					{
						SlotAndColours = new List<SlotAndColor>(9)
						{
							new SlotAndColor("ARM_LEFT_SKIN", new Color(1f, 1f, 1f)),
							new SlotAndColor("ARM_RIGHT_SKIN", new Color(1f, 1f, 1f)),
							new SlotAndColor("LEG_LEFT_SKIN", new Color(1f, 1f, 1f)),
							new SlotAndColor("LEG_RIGHT_SKIN", new Color(1f, 1f, 1f)),
							new SlotAndColor("Body_Naked", new Color(1f, 1f, 1f)),
							new SlotAndColor("Body_Naked_Up", new Color(1f, 1f, 1f)),
							new SlotAndColor("BODY_BTM", new Color(1f, 1f, 1f)),
							new SlotAndColor("BODY_BTM_UP", new Color(1f, 1f, 1f)),
							new SlotAndColor("BODY_TOP", new Color(1f, 1f, 1f))
						}
					}
				};
			}
			return Enumerable.Range(0, num).Select((Func<int, SlotsAndColours>)((int i) => new SlotsAndColours
			{
				SlotAndColours = ((IEnumerable<FollowerSkinPartConfig>)parts).Select((Func<FollowerSkinPartConfig, SlotAndColor>)((FollowerSkinPartConfig p) => new SlotAndColor(p.PartName, HexToColor(p.ColorChoices[i])))).ToList()
			})).ToList();
		}

		public static Color HexToColor(string hex)
		{
			//IL_000a: 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_000e: Unknown result type (might be due to invalid IL or missing references)
			Color result = default(Color);
			ColorUtility.TryParseHtmlString(hex, ref result);
			return result;
		}
	}
	public class FollowerSpineConfig
	{
		public List<string> DefaultSkin { get; set; }

		public string[] Skins { get; set; }

		public bool InitializeWithoutBase { get; set; } = true;
	}
	[Serializable]
	public class FollowerSkinConfig
	{
		public string OverrideBaseSkin { get; set; } = "Cat";

		public Dictionary<string, FollowerSkinPartConfig> PartConfigs { get; set; }
	}
	[Serializable]
	public class FollowerSkinPartConfig
	{
		public int SlotIndex { get; set; }

		public string PartName { get; set; }

		public float ScaleX { get; set; } = 1f;

		public float ScaleY { get; set; } = 1f;

		public float Rotation { get; set; } = -90f;

		public float OffsetX { get; set; } = 0f;

		public float OffsetY { get; set; } = 0f;

		public bool HideSlot { get; set; } = false;

		public List<string> ColorChoices { get; set; } = new List<string>(1) { "#FFF" };
	}
	[Serializable]
	public class DebugOutputSkin
	{
		public int SlotIndex { get; set; }

		public string PartName { get; set; }
	}
	public class PlayerSpineLoader
	{
		public static List<string> FleeceRotation = new List<string>();

		public static Dictionary<string, Tuple<SkeletonDataAsset, List<string>>> FleeceCyclingSpines = new Dictionary<string, Tuple<SkeletonDataAsset, List<string>>>();

		public static int currentFleeceIndexP1 = -1;

		public static int currentFleeceIndexP2 = -1;

		public static string currentFleeceSpineNameP1 = "";

		public static string currentFleeceSpineNameP2 = "";

		public static bool LoadedCustomSpines = false;

		public static bool LoadedFleeceCycling = false;

		public static List<(string, string)> FleeceOverrideSlots = new List<(string, string)>(14)
		{
			("images/PonchoLeft", "PonchoLeft"),
			("images/PonchoRight", "PonchoRight"),
			("images/PonchoLeft", "PonchoLeft2"),
			("images/PonchoRight", "PonchoRight2"),
			("images/PonchoExtra", "PonchoExtra"),
			("images/PonchoRightCorner2", "PonchoRightCorner"),
			("images/PonchoRightCorner", "PonchoRightCorner"),
			("images/PonchoShoulder", "PonchoShoulder"),
			("images/PonchoShoulder2", "PonchoShoulder_Right"),
			("RopeTopLeft", "images/RopeTopLeft"),
			("RopeTopRight", "images/RopeTopRight"),
			("images/Rope", "images/Rope"),
			("images/Bell", "Bell"),
			("images/Body", "Body")
		};

		public static int CycleNextFleece(int playerID)
		{
			int num = 0;
			switch (playerID)
			{
			case 0:
				currentFleeceIndexP1++;
				if (currentFleeceIndexP1 >= FleeceRotation.Count)
				{
					currentFleeceIndexP1 = 0;
				}
				num = currentFleeceIndexP1;
				break;
			case 1:
				currentFleeceIndexP2++;
				if (currentFleeceIndexP2 >= FleeceRotation.Count)
				{
					currentFleeceIndexP2 = 0;
				}
				num = currentFleeceIndexP2;
				break;
			}
			Plugin.Log.LogInfo((object)("Player " + (playerID + 1) + " cycled to fleece index " + num + " (" + FleeceRotation[num] + ")"));
			return num;
		}

		public static void LoadAllPlayerSpines(Material material = null)
		{
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Expected O, but got Unknown
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Expected O, but got Unknown
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Expected O, but got Unknown
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			if (LoadedCustomSpines)
			{
				Plugin.Log.LogInfo((object)"Load Player Spines was called again but already loaded!");
				return;
			}
			string path = Path.Combine(Plugin.PluginPath, "PlayerSkins");
			if (!Directory.Exists(path))
			{
				Directory.CreateDirectory(path);
			}
			string[] directories = Directory.GetDirectories(path);
			string[] array = directories;
			foreach (string path2 in array)
			{
				string fileName = Path.GetFileName(path2);
				string[] array2 = (from x in Directory.GetFiles(path2, "*.json", SearchOption.TopDirectoryOnly)
					where !x.Contains("config")
					select x).ToArray();
				string[] files = Directory.GetFiles(path2, "*.png", SearchOption.TopDirectoryOnly);
				string[] files2 = Directory.GetFiles(path2, "*.atlas", SearchOption.TopDirectoryOnly);
				string[] files3 = Directory.GetFiles(path2, "config.json", SearchOption.TopDirectoryOnly);
				string text = "Lamb";
				string[] array3 = new string[0];
				bool flag = false;
				if (files3.Length != 0)
				{
					TextAsset val = new TextAsset(File.ReadAllText(files3[0]));
					PlayerSpineConfig playerSpineConfig = JsonConvert.DeserializeObject<PlayerSpineConfig>(val.text);
					if (playerSpineConfig != null)
					{
						text = playerSpineConfig.DefaultSkin;
						array3 = playerSpineConfig.Skins;
						flag = playerSpineConfig.FleeceCyclingOnly;
						Plugin.Log.LogInfo((object)("Using default skin: " + text));
						Plugin.Log.LogInfo((object)("Using skin list: " + string.Join(", ", array3)));
					}
				}
				if (array2.Length != 0 && files.Length != 0 && files2.Length != 0)
				{
					Plugin.Log.LogInfo((object)("Reading atlas from " + files2[0]));
					TextAsset val2 = new TextAsset(File.ReadAllText(files2[0]));
					Plugin.Log.LogInfo((object)("Reading skeleton from " + array2[0]));
					TextAsset val3 = new TextAsset(File.ReadAllText(array2[0]));
					Texture2D[] array4 = (Texture2D[])(object)new Texture2D[files.Length];
					string[] array5 = files;
					foreach (string text2 in array5)
					{
						Plugin.Log.LogInfo((object)("Reading texture from " + text2));
						Texture2D val4 = TextureHelper.CreateTextureFromPath(text2, (TextureFormat)4, false, false);
						((Object)val4).name = Path.GetFileNameWithoutExtension(text2);
						array4[Array.IndexOf(files, text2)] = val4;
					}
					Material val5 = (Material)(((object)material) ?? ((object)new Material(Shader.Find("Spine/Skeleton"))));
					SpineAtlasAsset val6 = SpineAtlasAsset.CreateRuntimeInstance(val2, array4, val5, true);
					SkeletonDataAsset val7 = SkeletonDataAsset.CreateRuntimeInstance(val3, (AtlasAssetBase)(object)val6, true, 0.005f);
					Plugin.Log.LogInfo((object)("Creating skeleton for " + fileName));
					Plugin.Log.LogInfo((object)("Using material name " + ((Object)val5).name));
					if (flag)
					{
						Plugin.Log.LogInfo((object)("Skin: " + fileName + " is added as a fleece cycle skin."));
						FleeceCyclingSpines.Add(fileName, new Tuple<SkeletonDataAsset, List<string>>(val7, array3.ToList()));
					}
					else
					{
						CustomSkinManager.AddPlayerSpine(fileName, val7, array3.ToList());
						CustomSkinManager.ChangeSelectedPlayerSpine(fileName + "/" + text, 0);
					}
				}
				else
				{
					Plugin.Log.LogInfo((object)("Failed to load player skin " + fileName + ", ensure that the folder contains at least one of each .json, .png and .atlas file."));
				}
			}
			LoadedCustomSpines = true;
		}
	}
	public class PlayerSpineConfig
	{
		public string DefaultSkin { get; set; }

		public string[] Skins { get; set; }

		public bool FleeceCyclingOnly { get; set; } = false;
	}
	public class StructureBuildingOverrideHelper
	{
		public static Dictionary<string, List<StructureBuildingOverride>> StructureBuildingOverrides { get; private set; } = new Dictionary<string, List<StructureBuildingOverride>>();

		public static void LoadBuildingOverrides()
		{
			if (!Directory.Exists(Path.Combine(Plugin.PluginPath, "BuildingOverrides")))
			{
				Directory.CreateDirectory(Path.Combine(Plugin.PluginPath, "BuildingOverrides"));
				Plugin.Log.LogInfo((object)"Created BuildingOverrides directory.");
				return;
			}
			string[] directories = Directory.GetDirectories(Path.Combine(Plugin.PluginPath, "BuildingOverrides"));
			foreach (string text in directories)
			{
				string name = new DirectoryInfo(text).Name;
				List<StructureBuildingOverride> list = new List<StructureBuildingOverride>();
				if (File.Exists(Path.Combine(text, "config.json")))
				{
					string text2 = File.ReadAllText(Path.Combine(text, "config.json"));
					try
					{
						StructureBuildingOverrideData structureBuildingOverrideData = JsonConvert.DeserializeObject<StructureBuildingOverrideData>(text2) ?? null;
						if (structureBuildingOverrideData != null && structureBuildingOverrideData.Overrides != null)
						{
							list.AddRange(structureBuildingOverrideData.Overrides);
						}
					}
					catch (Exception arg)
					{
						Plugin.Log.LogError((object)$"Error loading building override from config.json in {text}: {arg}");
					}
				}
				if (list.Count > 0)
				{
					StructureBuildingOverrides[name] = list;
					Plugin.Log.LogInfo((object)$"Loaded {list.Count} overrides for building {name}.");
				}
			}
		}

		public static List<CustomStructureBuildingData> GetOverridesForBuilding(string buildingName)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Expected O, but got Unknown
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: 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)
			List<StructureBuildingOverride> value;
			List<StructureBuildingOverride> list = (StructureBuildingOverrides.TryGetValue(buildingName, out value) ? value : null);
			if (list == null)
			{
				return null;
			}
			List<CustomStructureBuildingData> list2 = new List<CustomStructureBuildingData>();
			foreach (StructureBuildingOverride item in list)
			{
				CustomStructureBuildingData val = new CustomStructureBuildingData
				{
					Offset = item.Offset.ToVector3(),
					Scale = item.Scale.ToVector3(),
					Rotation = item.Rotation.ToVector3(),
					Sprite = TextureHelper.CreateSpriteFromPath(Path.Combine(Plugin.PluginPath, "BuildingOverrides/" + buildingName + "/" + item.SpriteImageName))
				};
				list2.Add(val);
				Plugin.Log.LogInfo((object)$"Custom Spine Loader: Loaded override with sprite {item.SpriteImageName} for building {buildingName}: offset {val.Offset}, scale {val.Scale}, rotation {val.Rotation}.");
			}
			return list2;
		}
	}
	[Serializable]
	public class StructureBuildingOverrideData
	{
		public List<StructureBuildingOverride> Overrides = new List<StructureBuildingOverride>();
	}
	[Serializable]
	public class StructureBuildingOverride
	{
		public SerializableVector3 Offset;

		public SerializableVector3 Scale;

		public SerializableVector3 Rotation;

		public string SpriteImageName;
	}
	[Serializable]
	public class SerializableVector3
	{
		public float X;

		public float Y;

		public float Z;

		public Vector3 ToVector3()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(X, Y, Z);
		}
	}
	[Serializable]
	public class SerializableVector2
	{
		public float X;

		public float Y;

		public Vector2 ToVector2()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			return new Vector2(X, Y);
		}
	}
}
namespace CustomSpineLoader.Patches
{
	[HarmonyPatch]
	public class DungeonPatches
	{
		public static ConnectionTypes NextRoomConnectionType = (ConnectionTypes)2;

		public static bool GenCheck = false;

		[HarmonyPatch(typeof(BiomeGenerator), "OnEnable")]
		[HarmonyPrefix]
		private static void BiomeGenerator_OnEnable(BiomeGenerator __instance)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			if (CustomDungeonManager.CustomDungeonList.ContainsKey(CustomDungeonManager.EnteringCustomDungeon))
			{
				Plugin.Log.LogInfo((object)("Entering Custom Dungeon ONENABLE " + ((object)Unsafe.As<FollowerLocation, FollowerLocation>(ref CustomDungeonManager.EnteringCustomDungeon)/*cast due to .constrained prefix*/).ToString()));
				__instance.DungeonLocation = CustomDungeonManager.EnteringCustomDungeon;
				Plugin.Log.LogInfo((object)("Custom Room Count for " + ((object)Unsafe.As<FollowerLocation, FollowerLocation>(ref __instance.DungeonLocation)/*cast due to .constrained prefix*/).ToString() + ": " + CustomDungeonManager.CustomDungeonList[__instance.DungeonLocation].NumRooms));
				__instance.NumberOfRooms = CustomDungeonManager.CustomDungeonList[__instance.DungeonLocation].NumRooms;
				CustomDungeonManager.EnteringCustomDungeon = (FollowerLocation)(-1);
			}
			else
			{
				Plugin.Log.LogInfo((object)("Not a custom dungeon, using default dungeon for " + ((object)Unsafe.As<FollowerLocation, FollowerLocation>(ref __instance.DungeonLocation)/*cast due to .constrained prefix*/).ToString()));
			}
		}

		[HarmonyPatch(typeof(GameManager), "IsDungeon")]
		[HarmonyPrefix]
		private static bool GameManager_IsDungeon(GameManager __instance, FollowerLocation location, ref bool __result)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			if (!CustomDungeonManager.CustomDungeonList.ContainsKey(location))
			{
				return true;
			}
			__result = true;
			return false;
		}

		[HarmonyPatch(typeof(Door), "OnTriggerEnter2D")]
		[HarmonyPrefix]
		public static bool Door_OnTriggerEnter2D(Door __instance)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Invalid comparison between Unknown and I4
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)BiomeGenerator.Instance == (Object)null)
			{
				return true;
			}
			if (!CustomDungeonManager.CustomDungeonList.ContainsKey(BiomeGenerator.Instance.DungeonLocation))
			{
				return true;
			}
			if ((int)__instance.ConnectionType == 6)
			{
				Plugin.Log.LogInfo((object)("Exit Door Triggered for custom dungeon " + ((object)Unsafe.As<FollowerLocation, FollowerLocation>(ref BiomeGenerator.Instance.DungeonLocation)/*cast due to .constrained prefix*/).ToString()));
				CustomDungeonManager.CustomDungeonList[BiomeGenerator.Instance.DungeonLocation].ExitDoor();
				return false;
			}
			Plugin.Log.LogInfo((object)("Entering room type " + ((object)Unsafe.As<ConnectionTypes, ConnectionTypes>(ref __instance.ConnectionType)/*cast due to .constrained prefix*/).ToString()));
			NextRoomConnectionType = __instance.ConnectionType;
			GenCheck = false;
			return true;
		}

		[HarmonyPatch(typeof(LocationManager), "LocationIsDungeon")]
		[HarmonyPrefix]
		public static bool LocationManager_LocationIsDungeon(LocationManager __instance, FollowerLocation location, ref bool __result)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			if (!CustomDungeonManager.CustomDungeonList.ContainsKey(location))
			{
				return true;
			}
			__result = true;
			return false;
		}

		[HarmonyPatch(typeof(HUD_DisplayName), "Play")]
		[HarmonyPatch(new Type[]
		{
			typeof(string),
			typeof(int),
			typeof(Positions),
			typeof(textBlendMode),
			typeof(int)
		})]
		[HarmonyPrefix]
		public static bool HUD_DisplayName_Play(ref string Name, ref Positions Position, ref textBlendMode blend, ref int winterSeverity)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected I4, but got Unknown
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Expected I4, but got Unknown
			if ((Object)(object)BiomeGenerator.Instance == (Object)null)
			{
				return true;
			}
			if (!CustomDungeonManager.CustomDungeonList.ContainsKey(BiomeGenerator.Instance.DungeonLocation))
			{
				return true;
			}
			Plugin.Log.LogInfo((object)("Custom Dungeon HUD_DisplayName_Play for " + ((object)Unsafe.As<FollowerLocation, FollowerLocation>(ref BiomeGenerator.Instance.DungeonLocation)/*cast due to .constrained prefix*/).ToString()));
			CustomDungeon customDungeon = CustomDungeonManager.CustomDungeonList[BiomeGenerator.Instance.DungeonLocation];
			Position = (Positions)(int)customDungeon.TitleTextPosition;
			blend = (textBlendMode)(int)customDungeon.TitleTextBlendMode;
			winterSeverity = customDungeon.Difficulty;
			return true;
		}

		[HarmonyPatch(typeof(HUD_DisplayName), "Show")]
		[HarmonyPrefix]
		public static bool HUD_DisplayName_Show(ref string Name)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)BiomeGenerator.Instance == (Object)null)
			{
				return true;
			}
			if (!CustomDungeonManager.CustomDungeonList.ContainsKey(BiomeGenerator.Instance.DungeonLocation))
			{
				return true;
			}
			Plugin.Log.LogInfo((object)("Custom Dungeon HUD_DisplayName_Show for " + ((object)Unsafe.As<FollowerLocation, FollowerLocation>(ref BiomeGenerator.Instance.DungeonLocation)/*cast due to .constrained prefix*/).ToString()));
			CustomDungeon customDungeon = CustomDungeonManager.CustomDungeonList[BiomeGenerator.Instance.DungeonLocation];
			Name = customDungeon.DungeonName;
			return true;
		}

		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		[HarmonyPatch(new Type[] { })]
		[HarmonyPostfix]
		public static void GenerateRoom_Generate(GenerateRoom __instance)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Expected I4, but got Unknown
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)BiomeGenerator.Instance == (Object)null || GenCheck || !CustomDungeonManager.CustomDungeonList.ContainsKey(BiomeGenerator.Instance.DungeonLocation))
			{
				return;
			}
			GenCheck = true;
			Plugin.Log.LogInfo((object)("GenerateRoom_Generate for custom dungeon " + ((object)Unsafe.As<FollowerLocation, FollowerLocation>(ref BiomeGenerator.Instance.DungeonLocation)/*cast due to .constrained prefix*/).ToString()));
			Plugin.Log.LogInfo((object)("Room complete status: " + BiomeGenerator.Instance.CurrentRoom.Completed));
			if (!BiomeGenerator.Instance.CurrentRoom.Completed)
			{
				ConnectionTypes nextRoomConnectionType = NextRoomConnectionType;
				ConnectionTypes val = nextRoomConnectionType;
				switch ((int)val)
				{
				case 0:
					Plugin.Log.LogInfo((object)"False Room Generated");
					break;
				case 1:
					Plugin.Log.LogInfo((object)"True Room Generated");
					CustomDungeonManager.CustomDungeonList[BiomeGenerator.Instance.DungeonLocation].SpawnEnemies(__instance, NextRoomConnectionType);
					break;
				case 2:
					Plugin.Log.LogInfo((object)"Entrance Room Generated");
					break;
				case 3:
					Plugin.Log.LogInfo((object)"Exit Room Generated");
					break;
				case 4:
					Plugin.Log.LogInfo((object)"Boss Room Generated");
					break;
				case 5:
					Plugin.Log.LogInfo((object)"Door Room Generated");
					break;
				case 6:
					Plugin.Log.LogInfo((object)"NextLayer Room Generated");
					break;
				case 7:
					Plugin.Log.LogInfo((object)"DungeonFirstRoom Generated");
					break;
				case 8:
					Plugin.Log.LogInfo((object)"LeaderBoss Room Generated");
					break;
				case 9:
					Plugin.Log.LogInfo((object)"Tarot Room Generated");
					break;
				case 10:
					Plugin.Log.LogInfo((object)"WeaponShop Room Generated");
					break;
				case 11:
					Plugin.Log.LogInfo((object)"RelicShop Room Generated");
					break;
				case 12:
					Plugin.Log.LogInfo((object)"LoreStoneRoom Generated");
					break;
				default:
					Plugin.Log.LogInfo((object)"Default Room Generated");
					break;
				}
			}
		}
	}
	[HarmonyPatch]
	public class SkinSelectorPatch
	{
		[HarmonyPatch(typeof(FollowerInformationBox), "ConfigureImpl")]
		[HarmonyPostfix]
		private static void FollowerInformationBox_ConfigureImpl(FollowerInformationBox __instance)
		{
			if (FollowerSpineLoader.CustomFollowerSkins.ContainsKey(((FollowerSelectItem)__instance).FollowerInfo.SkinName))
			{
				__instance.FollowerSpine.Skeleton.Skin = FollowerSpineLoader.CustomFollowerSkins[((FollowerSelectItem)__instance).FollowerInfo.SkinName];
			}
		}

		[HarmonyPatch(typeof(SkeletonData), "FindSkin", new Type[] { typeof(string) })]
		[HarmonyPostfix]
		private static void SkeletonData_FindSkin(ref Skin? __result, SkeletonData __instance, string skinName)
		{
			if (__result == null && FollowerSpineLoader.CustomFollowerSkins.TryGetValue(skinName, out var value))
			{
				__result = value;
				DataManager.SetFollowerSkinUnlocked(skinName);
			}
		}

		[HarmonyPatch(typeof(PlayerFarming), "Awake")]
		[HarmonyPrefix]
		private static bool PlayerFarming_Awake(PlayerFarming __instance)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: 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)
			if (!PlayerSpineLoader.LoadedFleeceCycling)
			{
				Plugin.Log.LogInfo((object)"Creating Fleece Rotation!");
				SkeletonAnimation spine = __instance.Spine;
				Enumerator<Skin> enumerator = ((SkeletonRenderer)spine).Skeleton.Data.Skins.GetEnumerator();
				try
				{
					while (enumerator.MoveNext())
					{
						Skin current = enumerator.Current;
						if (!PlayerSpineLoader.FleeceRotation.Contains(current.Name) && !current.Name.ToLower().Contains("lamb_0") && current.Name.ToLower().Contains("lamb"))
						{
							PlayerSpineLoader.FleeceRotation.Add(current.Name);
							Plugin.Log.LogInfo((object)("Added fleece skin: " + current.Name));
						}
					}
				}
				finally
				{
					((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
				}
				if (!PlayerSpineLoader.FleeceRotation.Contains("Goat"))
				{
					PlayerSpineLoader.FleeceRotation.Add("Goat");
					Plugin.Log.LogInfo((object)"Added fleece skin: Goat");
				}
				if (!PlayerSpineLoader.FleeceRotation.Contains("Snake"))
				{
					PlayerSpineLoader.FleeceRotation.Add("Snake");
					Plugin.Log.LogInfo((object)"Added fleece skin: Snake");
				}
				if (!PlayerSpineLoader.FleeceRotation.Contains("Owl"))
				{
					PlayerSpineLoader.FleeceRotation.Add("Owl");
					Plugin.Log.LogInfo((object)"Added fleece skin: Owl");
				}
				foreach (KeyValuePair<string, Tuple<SkeletonDataAsset, List<string>>> fleeceCyclingSpine in PlayerSpineLoader.FleeceCyclingSpines)
				{
					string key = fleeceCyclingSpine.Key;
					foreach (string item in fleeceCyclingSpine.Value.Item2)
					{
						string text = "CultTweaker_" + key + "_" + item;
						if (!PlayerSpineLoader.FleeceRotation.Contains(text))
						{
							PlayerSpineLoader.FleeceRotation.Add(text);
							Plugin.Log.LogInfo((object)("Added custom fleece skin: " + text));
						}
					}
				}
				PlayerSpineLoader.LoadedFleeceCycling = true;
			}
			if (!PlayerSpineLoader.LoadedCustomSpines)
			{
				Plugin.Log.LogInfo((object)"PlayerFarming Awake called, checking for custom spines...");
				Material primaryMaterial = ((SkeletonRenderer)__instance.Spine).skeletonDataAsset.atlasAssets[0].PrimaryMaterial;
				Plugin.Log.LogInfo((object)("Test result is " + ((Object)primaryMaterial).name));
				Plugin.Log.LogInfo((object)("Test shader is " + ((Object)primaryMaterial.shader).name));
				primaryMaterial.SetTextureScale("_EmissionMap", new Vector2(0f, 0f));
				PlayerSpineLoader.LoadAllPlayerSpines(primaryMaterial);
			}
			return true;
		}

		[HarmonyPatch(typeof(PlayerFarming), "SetSkin", new Type[] { typeof(bool) })]
		[HarmonyPostfix]
		private static void PlayerFarming_SetSkin(ref Skin __result, PlayerFarming __instance, bool BlackAndWhite)
		{
			if (!Plugin.FleeceCyclingEnabled.Value)
			{
				return;
			}
			int num = -1;
			string text = "";
			if (CoopManager.CoopActive && __instance.playerID == 1)
			{
				num = PlayerSpineLoader.currentFleeceIndexP2;
				Plugin.Log.LogInfo((object)("Applying fleece skin for Player 2: " + text));
			}
			else
			{
				num = PlayerSpineLoader.currentFleeceIndexP1;
			}
			if (num == -1)
			{
				Plugin.Log.LogInfo((object)"No fleece skin to apply.");
				return;
			}
			if (num >= PlayerSpineLoader.FleeceRotation.Count)
			{
				Plugin.Log.LogInfo((object)"Fleece skin index out of range. Cycle with F7 or F8 to fix.");
				return;
			}
			text = PlayerSpineLoader.FleeceRotation[num];
			Plugin.Log.LogInfo((object)("Applying fleece skin: " + text));
			SkeletonAnimation spine = __instance.Spine;
			Skin val;
			if (text.Contains("CultTweaker_"))
			{
				string[] array = text.Split(new char[1] { '_' }, 3);
				if (array.Length < 3)
				{
					Plugin.Log.LogWarning((object)("Invalid custom fleece skin name: " + text));
					return;
				}
				string text2 = array[1];
				if (!PlayerSpineLoader.FleeceCyclingSpines.ContainsKey(text2))
				{
					Plugin.Log.LogWarning((object)("Invalid spine skin name: " + text + " for spine: " + text2));
					return;
				}
				val = PlayerSpineLoader.FleeceCyclingSpines[text2].Item1.skeletonData.FindSkin(array[2]);
				if (val == null)
				{
					Plugin.Log.LogWarning((object)("Defaulting to default as Custom Fleece skin not found: " + text));
					val = ((SkeletonRenderer)spine).Skeleton.Data.FindSkin("Lamb");
				}
			}
			else
			{
				val = ((SkeletonRenderer)spine).Skeleton.Data.FindSkin(text);
			}
			if ((Object)(object)spine == (Object)null)
			{
				Plugin.Log.LogInfo((object)("Lamb skin was null after cycling, an error occurred! at skin name " + text));
				return;
			}
			Skin skin = ((SkeletonRenderer)spine).Skeleton.Skin;
			foreach (var fleeceOverrideSlot in PlayerSpineLoader.FleeceOverrideSlots)
			{
				int num2 = ((SkeletonRenderer)spine).Skeleton.FindSlotIndex(fleeceOverrideSlot.Item1);
				Attachment attachment = val.GetAttachment(num2, fleeceOverrideSlot.Item2);
				Plugin.Log.LogInfo((object)string.Format("Slot {0} index is {1}, attachment {2}", fleeceOverrideSlot.Item1, num2, (attachment != null) ? "found" : "not found"));
				if (attachment == null)
				{
					skin.RemoveAttachment(num2, fleeceOverrideSlot.Item2);
				}
				else
				{
					skin.SetAttachment(num2, fleeceOverrideSlot.Item2, attachment);
				}
				Plugin.Log.LogInfo((object)("Applied " + fleeceOverrideSlot.Item2 + " attachment to current skin."));
			}
			Plugin.Log.LogInfo((object)("Applied" + text + " attachment to current skin."));
			((SkeletonRenderer)spine).Skeleton.SetSlotsToSetupPose();
			spine.Update(0f, false);
		}

		[HarmonyPatch(typeof(Follower), "Update")]
		[HarmonyPostfix]
		public static void Follower_FacePosition(Follower __instance)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			int iD = __instance.Brain.Info.ID;
			float customScale = CustomColorHelper.GetCustomScale(iD);
			if (!(customScale <= 0f))
			{
				((SkeletonRenderer)__instance.Spine).skeleton.ScaleX = ((((Component)__instance).transform.position.x < __instance._destPos.x) ? (0f - customScale) : customScale);
			}
		}

		[HarmonyPatch(typeof(FollowerBrain), "SetFollowerCostume", new Type[]
		{
			typeof(Skeleton),
			typeof(int),
			typeof(string),
			typeof(int),
			typeof(FollowerOutfitType),
			typeof(FollowerHatType),
			typeof(FollowerClothingType),
			typeof(FollowerCustomisationType),
			typeof(FollowerSpecialType),
			typeof(ITEM_TYPE),
			typeof(string),
			typeof(FollowerInfo)
		})]
		[HarmonyPrefix]
		public static bool FollowerBrain_SetFollowerCostume_Prefix(FollowerBrain __instance, Skeleton skeleton, ref string skinName, ref FollowerOutfitType outfit, ref FollowerHatType hat, ref FollowerClothingType clothing, FollowerCustomisationType customisation, ref FollowerSpecialType special, ref ITEM_TYPE necklace, FollowerInfo info)
		{
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Expected I4, but got Unknown
			//IL_00ff: 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_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Invalid comparison between Unknown and I4
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Invalid comparison between Unknown and I4
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Invalid comparison between Unknown and I4
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Invalid comparison between Unknown and I4
			if (info != null)
			{
				Plugin.Log.LogInfo((object)$"Follower ID: {info.ID}, Name: {info.Name}");
				CustomFollowerColor customColor = CustomColorHelper.GetCustomColor(info.ID);
				if (customColor == null)
				{
					return true;
				}
				if (!customColor.CustomFollowerCostume)
				{
					return true;
				}
				Plugin.Log.LogInfo((object)$"Custom costume enabled: {customColor.CustomFollowerCostume}, ClothingType: {customColor.FollowerClothingType}, SpecialType: {customColor.FollowerSpecialType}, HatType: {customColor.FollowerHatType}, OutfitType: {customColor.FollowerOutfitType}");
				hat = (FollowerHatType)customColor.FollowerHatType;
				necklace = (ITEM_TYPE)(int)CustomColorCommand.GetNecklaceToUse(customColor.FollowerNecklaceType, info);
				special = (FollowerSpecialType)customColor.FollowerSpecialType;
				clothing = (FollowerClothingType)customColor.FollowerClothingType;
				outfit = (FollowerOutfitType)customColor.FollowerOutfitType;
				FollowerSpecialType val = special;
				if (val - 11 <= 2)
				{
					skinName = CustomColorCommand.GetSnowmanRandomSkin(special);
					Plugin.Log.LogInfo((object)("Applying snowman skin: " + skinName));
				}
				FollowerClothingType val2 = clothing;
				if (((int)val2 == 1 || val2 - 3 <= 1 || (int)val2 == 40) ? true : false)
				{
					clothing = (FollowerClothingType)27;
					Plugin.Log.LogInfo((object)"Clothing type was blacklisted, defaulting to Normal.");
				}
				if ((int)outfit == 4)
				{
					outfit = (FollowerOutfitType)18;
					Plugin.Log.LogInfo((object)"Outfit type was blacklisted, defaulting to None.");
				}
			}
			return true;
		}

		[HarmonyPatch(typeof(FollowerBrain), "SetFollowerCostume", new Type[]
		{
			typeof(Skeleton),
			typeof(int),
			typeof(string),
			typeof(int),
			typeof(FollowerOutfitType),
			typeof(FollowerHatType),
			typeof(FollowerClothingType),
			typeof(FollowerCustomisationType),
			typeof(FollowerSpecialType),
			typeof(ITEM_TYPE),
			typeof(string),
			typeof(FollowerInfo)
		})]
		[HarmonyPostfix]
		private static void FollowerBrain_SetFollowerCostume(FollowerBrain __instance, Skeleton skeleton, FollowerInfo info)
		{
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.DebugDumpFollowerSpineAtlas.Value)
			{
				Plugin.Log.LogWarning((object)"Debug Dump is enabled! Performance may be impacted");
				string path = Path.Combine(Plugin.PluginPath, "followerSlots.json");
				if (File.Exists(path))
				{
					Plugin.Log.LogInfo((object)"followerSlots.json already exists, skipping dump. Delete the file to dump again.");
				}
				else
				{
					Plugin.Log.LogInfo((object)"Creating dump for followerslots");
					List<DebugOutputSkin> list = new List<DebugOutputSkin>();
					foreach (SkinEntry attachment in skeleton.Skin.Attachments)
					{
						SkinEntry current = attachment;
						list.Add(new DebugOutputSkin
						{
							SlotIndex = ((SkinEntry)(ref current)).SlotIndex,
							PartName = ((SkinEntry)(ref current)).Name
						});
					}
					string contents = JsonConvert.SerializeObject((object)list, (Formatting)1);
					File.AppendAllText(path, contents);
				}
			}
			Plugin.Log.LogInfo((object)"Setting follower costume for");
			if (info != null)
			{
				Plugin.Log.LogInfo((object)$"Follower ID: {info.ID}, Name: {info.Name}");
				CustomFollowerColor customColor = CustomColorHelper.GetCustomColor(info.ID);
				if (customColor == null)
				{
					return;
				}
				Plugin.Log.LogInfo((object)$"Custom color found for follower {info.ID}: R={customColor.R}, G={customColor.G}, B={customColor.B}, A={customColor.A}");
				SkeletonExtensions.SetColor(skeleton.FindSlot("ARM_LEFT_SKIN"), new Color(customColor.R, customColor.G, customColor.B, 1f));
				SkeletonExtensions.SetColor(skeleton.FindSlot("LEG_LEFT_SKIN"), new Color(customColor.R, customColor.G, customColor.B, 1f));
				SkeletonExtensions.SetColor(skeleton.FindSlot("LEG_RIGHT_SKIN"), new Color(customColor.R, customColor.G, customColor.B, 1f));
				SkeletonExtensions.SetColor(skeleton.FindSlot("ARM_RIGHT_SKIN"), new Color(customColor.R, customColor.G, customColor.B, 1f));
				SkeletonExtensions.SetColor(skeleton.FindSlot("HEAD_SKIN_BTM"), new Color(customColor.R, customColor.G, customColor.B, 1f));
				skeleton.A = customColor.A;
				Follower val = FollowerManager.FindFollowerByID(info.ID);
				if ((Object)(object)val != (Object)null)
				{
					((SkeletonRenderer)val.Spine).skeleton.scaleY = customColor.scale;
					((SkeletonRenderer)val.Spine).skeleton.scaleX = customColor.scale;
					Plugin.Log.LogInfo((object)("Set follower scale to " + customColor.scale));
				}
				if (customColor.CustomFollowerCostume)
				{
					try
					{
						Plugin.Log.LogInfo((object)"Costume override applied successfully.");
					}
					catch (Exception)
					{
						Plugin.Log.LogWarning((object)"The costume combinations were invalid, try another!");
					}
				}
			}
			else
			{
				Plugin.Log.LogInfo((object)"Follower info is null, skipping costume setting.");
			}
		}

		[HarmonyPatch(typeof(SaveAndLoad), "Load")]
		[HarmonyPostfix]
		private static void SaveAndLoad_Load(int saveSlot)
		{
			CustomColorHelper.LoadCustomColors(saveSlot);
		}

		[HarmonyPatch(typeof(SaveAndLoad), "Save", new Type[] { })]
		[HarmonyPostfix]
		private static void SaveAndLoad_Save()
		{
			CustomColorHelper.SaveCustomColors();
		}

		[HarmonyPatch(typeof(Structure), "Start")]
		[HarmonyPostfix]
		private static void Structure_Start(Structure __instance)
		{
			string text = ((object)Unsafe.As<TYPES, TYPES>(ref __instance.Type)/*cast due to .constrained prefix*/).ToString();
			List<CustomStructureBuildingData> overridesForBuilding = StructureBuildingOverrideHelper.GetOverridesForBuilding(text);
			if (overridesForBuilding != null && overridesForBuilding.Count != 0)
			{
				Plugin.Log.LogInfo((object)$"Custom Spine Loader: {overridesForBuilding.Count} overrides to building {text}.");
				CustomStructureManager.OverrideStructureBuilding(((Component)__instance).gameObject, overridesForBuilding);
			}
		}
	}
}
namespace CustomSpineLoader.MapEditor
{
	public class RuntimeMapEditor : MonoBehaviour
	{
		private Canvas canvas;

		private RectTransform panel;

		private Camera mainCam;

		private object splineController;

		private Type splineType;

		private List<Vector3> controlPoints = new List<Vector3>();

		private List<GameObject> handles = new List<GameObject>();

		private const string splineTypeName = "SplineShapeController";

		private void Awake()
		{
			mainCam = Camera.main;
			CreateUi();
			HideUi();
		}

		private void Update()
		{
			if ((Object)(object)canvas != (Object)null && ((Behaviour)canvas).enabled)
			{
				UpdateHandlePositions();
			}
		}

		public void ToggleEditor()
		{
			if ((Object)(object)canvas != (Object)null)
			{
				ToggleUi();
			}
		}

		private void ToggleUi()
		{
			((Behaviour)canvas).enabled = !((Behaviour)canvas).enabled;
			if (((Behaviour)canvas).enabled)
			{
				EnterEditorMode();
			}
			else
			{
				ExitEditorMode();
			}
		}

		private void CreateUi()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: 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_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("RuntimeMapEditor_Canvas");
			Object.DontDestroyOnLoad((Object)(object)val);
			canvas = val.AddComponent<Canvas>();
			canvas.renderMode = (RenderMode)0;
			val.AddComponent<CanvasScaler>();
			val.AddComponent<GraphicRaycaster>();
			GameObject val2 = new GameObject("EditorPanel");
			val2.transform.SetParent(((Component)canvas).transform, false);
			panel = val2.AddComponent<RectTransform>();
			panel.sizeDelta = new Vector2(420f, 220f);
			panel.anchorMin = new Vector2(0.5f, 1f);
			panel.anchorMax = new Vector2(0.5f, 1f);
			panel.pivot = new Vector2(0.5f, 1f);
			panel.anchoredPosition = new Vector2(0f, -10f);
			Image val3 = val2.AddComponent<Image>();
			((Graphic)val3).color = new Color(0f, 0f, 0f, 0.6f);
			GameObject val4 = CreateText("Editor Mode", 20, (TextAnchor)1);
			val4.transform.SetParent((Transform)(object)panel, false);
			RectTransform component = val4.GetComponent<RectTransform>();
			component.anchoredPosition = new Vector2(0f, -10f);
			GameObject val5 = CreateButton("Add Point", new Vector2(-120f, -40f), delegate
			{
				AddPointAtMouse();
			});
			val5.transform.SetParent((Transform)(object)panel, false);
			GameObject val6 = CreateButton("Center On Spline", new Vector2(0f, -40f), delegate
			{
				CenterOnSpline();
			});
			val6.transform.SetParent((Transform)(object)panel, false);
			GameObject val7 = CreateButton("Close (F4)", new Vector2(120f, -40f), delegate
			{
				ToggleUi();
			});
			val7.transform.SetParent((Transform)(object)panel, false);
			GameObject val8 = CreateText("Drag handles to edit spline. Add/Delete points.", 14, (TextAnchor)0);
			val8.transform.SetParent((Transform)(object)panel, false);
			RectTransform component2 = val8.GetComponent<RectTransform>();
			component2.anchoredPosition = new Vector2(-180f, -80f);
			((Behaviour)canvas).enabled = false;
		}

		private GameObject CreateButton(string text, Vector2 anchoredPos, Action onClick)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Expected O, but got Unknown
			GameObject val = new GameObject("Btn_" + text);
			RectTransform val2 = val.AddComponent<RectTransform>();
			val2.sizeDelta = new Vector2(140f, 28f);
			val2.anchoredPosition = anchoredPos;
			Image val3 = val.AddComponent<Image>();
			((Graphic)val3).color = new Color(0.2f, 0.2f, 0.2f, 0.95f);
			Button val4 = val.AddComponent<Button>();
			((UnityEvent)val4.onClick).AddListener((UnityAction)delegate
			{
				onClick?.Invoke();
			});
			GameObject val5 = CreateText(text, 14, (TextAnchor)4);
			val5.transform.SetParent(val.transform, false);
			return val;
		}

		private GameObject CreateText(string content, int size, TextAnchor anchor)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			//IL_003b: 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_0060: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Text_" + content);
			Text val2 = val.AddComponent<Text>();
			val2.text = content;
			val2.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
			val2.fontSize = size;
			((Graphic)val2).color = Color.white;
			val2.alignment = anchor;
			RectTransform component = val.GetComponent<RectTransform>();
			component.sizeDelta = new Vector2(380f, 30f);
			return val;
		}

		private void ShowUi()
		{
			((Behaviour)canvas).enabled = true;
		}

		private void HideUi()
		{
			((Behaviour)canvas).enabled = false;
		}

		private void EnterEditorMode()
		{
			FindSplineController();
			if (splineController == null)
			{
				Debug.LogWarning((object)"RuntimeMapEditor: No spline controller found in scene.");
				return;
			}
			LoadControlPointsFromSpline();
			CreateHandles();
		}

		private void ExitEditorMode()
		{
			ClearHandles();
		}

		private void FindSplineController()
		{
			splineController = null;
			splineType = null;
			Object[] array = Object.FindObjectsOfType<Object>();
			Object[] array2 = array;
			foreach (Object val in array2)
			{
				if (!(val == (Object)null))
				{
					Type type = ((object)val).GetType();
					if (type.Name == "SplineShapeController")
					{
						splineController = val;
						splineType = type;
						break;
					}
				}
			}
			if (splineController != null)
			{
				return;
			}
			Object[] array3 = array;
			foreach (Object val2 in array3)
			{
				if (!(val2 == (Object)null))
				{
					Type type2 = ((object)val2).GetType();
					if (type2.Name.IndexOf("Spline", StringComparison.OrdinalIgnoreCase) >= 0)
					{
						splineController = val2;
						splineType = type2;
						break;
					}
				}
			}
		}

		private void LoadControlPointsFromSpline()
		{
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			controlPoints.Clear();
			if (splineController == null)
			{
				return;
			}
			MethodInfo methodInfo = splineType.GetMethod("GetControlPoints") ?? splineType.GetMethod("GetPoints");
			if (methodInfo != null)
			{
				if (methodInfo.Invoke(splineController, null) is IEnumerable<Vector3> collection)
				{
					controlPoints.AddRange(collection);
				}
				return;
			}
			PropertyInfo propertyInfo = splineType.GetProperty("ControlPoints") ?? splineType.GetProperty("Points") ?? splineType.GetProperty("points");
			if (propertyInfo != null)
			{
				object value = propertyInfo.GetValue(splineController);
				if (value is IEnumerable<Vector3> collection2)
				{
					controlPoints.AddRange(collection2);
				}
				else
				{
					if (!(value is IList list))
					{
						return;
					}
					for (int i = 0; i < list.Count; i++)
					{
						if (list[i] is Vector3 item)
						{
							controlPoints.Add(item);
						}
					}
				}
				return;
			}
			FieldInfo fieldInfo = splineType.GetField("points") ?? splineType.GetField("controlPoints");
			if (!(fieldInfo != null))
			{
				return;
			}
			object value2 = fieldInfo.GetValue(splineController);
			if (!(value2 is IList list2))
			{
				return;
			}
			for (int j = 0; j < list2.Count; j++)
			{
				if (list2[j] is Vector3 item2)
				{
					controlPoints.Add(item2);
				}
			}
		}

		private void CreateHandles()
		{
			ClearHandles();
			for (int i = 0; i < controlPoints.Count; i++)
			{
				GameObject item = CreateHandle(i);
				handles.Add(item);
			}
		}

		private GameObject CreateHandle(int index)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Expected O, but got Unknown
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Expected O, but got Unknown
			GameObject val = new GameObject("Handle_" + index);
			val.transform.SetParent(((Component)canvas).transform, false);
			RectTransform val2 = val.AddComponent<RectTransform>();
			val2.sizeDelta = new Vector2(18f, 18f);
			Image val3 = val.AddComponent<Image>();
			((Graphic)val3).color = Color.cyan;
			PointHandle pointHandle = val.AddComponent<PointHandle>();
			pointHandle.Initialize(this, index);
			GameObject val4 = new GameObject("Del");
			val4.transform.SetParent(val.transform, false);
			RectTransform val5 = val4.AddComponent<RectTransform>();
			val5.anchorMin = new Vector2(1f, 1f);
			val5.anchorMax = new Vector2(1f, 1f);
			val5.anchoredPosition = new Vector2(6f, 6f);
			val5.sizeDelta = new Vector2(12f, 12f);
			Image val6 = val4.AddComponent<Image>();
			((Graphic)val6).color = Color.red;
			Button val7 = val4.AddComponent<Button>();
			int idx = index;
			((UnityEvent)val7.onClick).AddListener((UnityAction)delegate
			{
				RemovePoint(idx);
			});
			return val;
		}

		private void UpdateHandlePositions()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: 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_004c: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < handles.Count; i++)
			{
				if (i < controlPoints.Count)
				{
					Vector3 val = controlPoints[i];
					Vector3 position = mainCam.WorldToScreenPoint(val);
					RectTransform component = handles[i].GetComponent<RectTransform>();
					((Transform)component).position = position;
				}
			}
		}

		private void ClearHandles()
		{
			foreach (GameObject handle in handles)
			{
				if ((Object)(object)handle != (Object)null)
				{
					Object.Destroy((Object)(object)handle);
				}
			}
			handles.Clear();
		}

		public void SetPointPosition(int index, Vector3 worldPos)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			if (index >= 0 && index < controlPoints.Count)
			{
				controlPoints[index] = worldPos;
				ApplyPointsToSpline();
			}
		}

		public void RemovePoint(int index)
		{
			if (index >= 0 && index < controlPoints.Count)
			{
				controlPoints.RemoveAt(index);
				ApplyPointsToSpline();
				CreateHandles();
			}
		}

		public void AddPointAtMouse()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			Vector3 mousePosition = Input.mousePosition;
			if ((Object)(object)mainCam == (Object)null)
			{
				mainCam = Camera.main;
			}
			Vector3 item = mainCam.ScreenToWorldPoint(new Vector3(mousePosition.x, mousePosition.y, 10f));
			controlPoints.Add(item);
			ApplyPointsToSpline();
			CreateHandles();
		}

		private void CenterOnSpline()
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			if (splineController != null)
			{
				object obj = splineController;
				object obj2 = ((obj is MonoBehaviour) ? obj : null);
				Transform val = ((obj2 != null) ? ((Component)obj2).transform : null);
				if ((Object)(object)val != (Object)null)
				{
					((Component)mainCam).transform.position = new Vector3(val.position.x, val.position.y, ((Component)mainCam).transform.position.z);
				}
			}
		}

		private void ApplyPointsToSpline()
		{
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			if (splineController == null)
			{
				return;
			}
			MethodInfo methodInfo = splineType.GetMethod("SetControlPoints") ?? splineType.GetMethod("SetPoints");
			if (methodInfo != null)
			{
				methodInfo.Invoke(splineController, new object[1] { controlPoints.ToArray() });
			}
			else
			{
				PropertyInfo propertyInfo = splineType.GetProperty("ControlPoints") ?? splineType.GetProperty("Points");
				if (propertyInfo != null)
				{
					if (propertyInfo.PropertyType.IsArray)
					{
						Array array = Array.CreateInstance(typeof(Vector3), controlPoints.Count);
						for (int i = 0; i < controlPoints.Count; i++)
						{
							array.SetValue(controlPoints[i], i);
						}
						propertyInfo.SetValue(splineController, array);
					}
					else if (typeof(IList).IsAssignableFrom(propertyInfo.PropertyType))
					{
						IList list = Activator.CreateInstance(propertyInfo.PropertyType) as IList;
						for (int j = 0; j < controlPoints.Count; j++)
						{
							list.Add(controlPoints[j]);
						}
						propertyInfo.SetValue(splineController, list);
					}
				}
				else
				{
					FieldInfo fieldInfo = splineType.GetField("points") ?? splineType.GetField("controlPoints");
					if (fieldInfo != null && Activator.CreateInstance(fieldInfo.FieldType) is IList list2)
					{
						list2.Clear();
						for (int k = 0; k < controlPoints.Count; k++)
						{
							list2.Add(controlPoints[k]);
						}
						fieldInfo.SetValue(splineController, list2);
					}
				}
			}
			MethodInfo methodInfo2 = splineType.GetMethod("Rebuild") ?? splineType.GetMethod("UpdateSpline") ?? splineType.GetMethod("GenerateMesh");
			if (methodInfo2 != null)
			{
				methodInfo2.Invoke(splineController, null);
			}
			object obj = splineController;
			MonoBehaviour val = (MonoBehaviour)((obj is MonoBehaviour) ? obj : null);
			if (!((Object)(object)val != (Object)null))
			{
				return;
			}
			MeshCollider component = ((Component)val).GetComponent<MeshCollider>();
			if ((Object)(object)component != (Object)null)
			{
				Mesh val2 = null;
				FieldInfo fieldInfo2 = splineType.GetField("generatedMesh") ?? splineType.GetField("mesh");
				if (fieldInfo2 != null)
				{
					object? value = fieldInfo2.GetValue(splineController);
					val2 = (Mesh)((value is Mesh) ? value : null);
				}
				PropertyInfo propertyInfo2 = splineType.GetProperty("GeneratedMesh") ?? splineType.GetProperty("Mesh");
				if ((Object)(object)val2 == (Object)null && propertyInfo2 != null)
				{
					object? value2 = propertyInfo2.GetValue(splineController);
					val2 = (Mesh)((value2 is Mesh) ? value2 : null);
				}
				if ((Object)(object)val2 != (Object)null)
				{
					component.sharedMesh = val2;
				}
			}
		}
	}
	public class PointHandle : MonoBehaviour, IPointerDownHandler, IEventSystemHandler, IDragHandler, IPointerUpHandler
	{
		private int index;

		private RuntimeMapEditor editor;

		public void Initialize(RuntimeMapEditor e, int idx)
		{
			editor = e;
			index = idx;
		}

		public void OnPointerDown(PointerEventData eventData)
		{
		}

		public void OnDrag(PointerEventData eventData)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)editor == (Object)null))
			{
				Camera main = Camera.main;
				Vector3 val = Vector2.op_Implicit(eventData.position);
				Vector3 worldPos = main.ScreenToWorldPoint(new Vector3(val.x, val.y, 10f));
				editor.SetPointPosition(index, worldPos);
			}
		}

		public void OnPointerUp(PointerEventData eventData)
		{
		}
	}
}
namespace CustomSpineLoader.Commands
{
	public class CustomColorCommand : CustomFollowerCommand
	{
		public UIFollowerSummaryMenuController _followerSummaryMenuController;

		public float currentRed = 1f;

		public float currentGreen = 1f;

		public float currentBlue = 1f;

		public float currentAlpha = 1f;

		public float currentScale = 1f;

		public bool isCustomColorEnabled = false;

		public bool isCustomFollowerCostumeEnabled = false;

		public int selectedClothingTypeIndex = 0;

		public int selectedSpecialTypeIndex = 0;

		public int selectedHatTypeIndex = 0;

		public int selectedOutfitTypeIndex = 0;

		public int selectedNecklaceTypeIndex = 0;

		public override string InternalName => "CustomColor_Command";

		public override Sprite CommandIcon => TextureHelper.CreateSpriteFromPath(Path.Combine(Plugin.PluginPath, "Assets/colorwheel.png"));

		public override List<FollowerCommandCategory> Categories { get; } = new List<FollowerCommandCategory>(1) { (FollowerCommandCategory)0 };

		public override string GetTitle(Follower follower)
		{
			return "Customize Follower";
		}

		public override string GetDescription(Follower follower)
		{
			return "Customize Me!";
		}

		public override void Execute(interaction_FollowerInteraction interaction, FollowerCommands finalCommand)
		{
			((MonoBehaviour)interaction).StartCoroutine(interaction.FrameDelayCallback((Action)delegate
			{
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				//IL_001b: Expected O, but got Unknown
				interaction.follower.Brain.HardSwapToTask((FollowerTask)new FollowerTask_ManualControl());
				_followerSummaryMenuController = MonoSingleton<UIManager>.Instance.ShowFollowerSummaryMenu(interaction.follower);
				CreateColorUI();
				UIFollowerSummaryMenuController followerSummaryMenuController = _followerSummaryMenuController;
				((UIMenuBase)followerSummaryMenuController).OnHidden = (Action)Delegate.Combine(((UIMenuBase)followerSummaryMenuController).OnHidden, (Action)delegate
				{
					//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
					//IL_010c: Unknown result type (might be due to invalid IL or missing references)
					//IL_015c: Unknown result type (might be due to invalid IL or missing references)
					//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
					//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
					_followerSummaryMenuController = null;
					if (isCustomColorEnabled)
					{
						CustomColorHelper.SetCustomColor(interaction.follower.Brain.Info.ID, currentRed, currentGreen, currentBlue, currentAlpha, currentScale);
						SkeletonExtensions.SetColor(((SkeletonRenderer)interaction.follower.Spine).skeleton.FindSlot("ARM_LEFT_SKIN"), new Color(currentRed, currentGreen, currentBlue, 1f));
						SkeletonExtensions.SetColor(((SkeletonRenderer)interaction.follower.Spine).skeleton.FindSlot("LEG_LEFT_SKIN"), new Color(currentRed, currentGreen, currentBlue, 1f));
						SkeletonExtensions.SetColor(((SkeletonRenderer)interaction.follower.Spine).skeleton.FindSlot("LEG_RIGHT_SKIN"), new Color(currentRed, currentGreen, currentBlue, 1f));
						SkeletonExtensions.SetColor(((SkeletonRenderer)interaction.follower.Spine).skeleton.FindSlot("ARM_RIGHT_SKIN"), new Color(currentRed, currentGreen, currentBlue, 1f));
						SkeletonExtensions.SetColor(((SkeletonRenderer)interaction.follower.Spine).skeleton.FindSlot("HEAD_SKIN_BTM"), new Color(currentRed, currentGreen, currentBlue, 1f));
						((SkeletonRenderer)interaction.follower.Spine).skeleton.A = currentAlpha;
						((SkeletonRenderer)interaction.follower.Spine).skeleton.ScaleX = currentScale;
						((SkeletonRenderer)interaction.follower.Spine).skeleton.ScaleY = currentScale;
						Plugin.Log.LogInfo((object)("Scale is set to: " + currentScale + "X is " + ((SkeletonRenderer)interaction.follower.Spine).Skeleton.ScaleX + " Y is " + ((SkeletonRenderer)interaction.follower.Spine).Skeleton.ScaleY));
						if (isCustomFollowerCostumeEnabled)
						{
							CustomColorHelper.SetCustomCostume(interaction.follower.Brain.Info.ID, enabled: true, selectedClothingTypeIndex, selectedSpecialTypeIndex, selectedHatTypeIndex, selectedOutfitTypeIndex, selectedNecklaceTypeIndex);
						}
						else
						{
							CustomColorHelper.SetCustomCostume(interaction.follower.Brain.Info.ID, enabled: false, 0, 0, 0, 0, 0);
						}
					}
					else
					{
						CustomColorHelper.RemoveCustomColor(interaction.follower.Brain.Info.ID);
					}
					interaction.Close(true, true, false);
				});
				HUD_Manager.Instance.Hide(false, 0, false);
			}));
		}

		public unsafe void CreateColorUI()
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c04: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c0e: Expected I4, but got Unknown
			//IL_0c26: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c30: Expected I4, but got Unknown
			//IL_0c48: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c52: Expected I4, but got Unknown
			//IL_0c6a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c74: Expected I4, but got Unknown
			if ((Object)(object)_followerSummaryMenuController == (Object)null)
			{
				Debug.LogError((object)"Follower Summary Menu Controller is not initialized.");
				return;
			}
			Debug.Log((object)"Creating color picker UI...");
			Time.timeScale = 1f;
			Transform val = ((Component)_followerSummaryMenuController).transform.Find("BlurImageBackground");
			((Component)val).gameObject.SetActive(false);
			GameManager.GetInstance().CameraSetOffset(new Vector3(-2f, 0f, 0f));
			Transform val2 = ((Component)_followerSummaryMenuController).transform.Find("FollowerSummaryContainer");
			Transform val3 = ((val2 != null) ? val2.Find("Left") : null);
			Transform val4 = ((val3 != null) ? val3.Find("Transform") : null);
			Transform val5 = ((val4 != null) ? val4.Find("Top") : null);
			Transform val6 = ((val5 != null) ? val5.Find("Header") : null);
			TMP_Text val7 = ((val6 != null) ? ((Component)val6).GetComponent<TMP_Text>() : null);
			if ((Object)(object)val7 != (Object)null)
			{
				val7.text = "Customize Follower";
			}
			Transform val8 = ((val4 != null) ? val4.Find("Content") : null);
			Transform val9 = ((val8 != null) ? val8.Find("Scroll View") : null);
			Transform val10 = ((val9 != null) ? val9.Find("Viewport") : null);
			Transform val11 = ((val10 != null) ? val10.Find("Content") : null);
			Transform val12 = ((val11 != null) ? val11.Find("Follower Traits Header") : null);
			TMP_Text val13 = ((val12 != null) ? ((Component)val12).GetComponent<TMP_Text>() : null);
			if ((Object)(object)val13 != (Object)null)
			{
				val13.text = "Color preview above.";
			}
			Transform val14 = ((val11 != null) ? val11.Find("Follower Traits Content") : null);
			if (val14 != null)
			{
				((Component)val14).gameObject.SetActive(false);
			}
			Transform val15 = ((val11 != null) ? val11.Find("Cult Traits Header") : null);
			TMP_Text val16 = ((val15 != null) ? ((Component)val15).GetComponent<TMP_Text>() : null);
			if ((Object)(object)val15 != (Object)null)
			{
				val16.text = "Costume Preview on the right.";
			}
			Transform val17 = ((val11 != null) ? val11.Find("Cult Traits Content") : null);
			if (val17 != null)
			{
				((Component)val17).gameObject.SetActive(false);
			}
			Transform val18 = ((val11 != null) ? val11.Find("Follower Thoughts") : null);
			if (val18 != null)
			{
				((Component)val18).gameObject.SetActive(false);
			}
			Transform val19 = ((val11 != null) ? val11.Find("Follower Thoughts Content") : null);
			if (val19 != null)
			{
				((Component)val19).gameObject.SetActive(false);
			}
			Transform val20 = ((val11 != null) ? val11.Find("Spacer") : null);
			GameObject gameObject = ((Component)((Transform)((Component)MonoSingleton<UIManager>.Instance.SettingsMenuControllerTemplate._audioSettings).GetComponentInChildren<ScrollRect>().content).GetChild(0)).gameObject;
			GameObject gameObject2 = ((Component)((Transform)((Component)MonoSingleton<UIManager>.Instance.SettingsMenuControllerTemplate._graphicsSettings).GetComponentInChildren<ScrollRect>().content).GetChild(4)).gameObject;
			GameObject gameObject3 = ((Component)((Transform)((Component)MonoSingleton<UIManager>.Instance.SettingsMenuControllerTemplate._graphicsSettings).GetComponentInChildren<ScrollRect>().content).GetChild(3)).gameObject;
			GameObject val21 = Object.Instantiate<GameObject>(gameObject2, val11);
			Transform val22 = Object.Instantiate<Transform>(val20, val11);
			GameObject val23 = Object.Instantiate<GameObject>(gameObject, val11);
			Transform val24 = Object.Instantiate<Transform>(val20, val11);
			GameObject val25 = Object.Instantiate<GameObject>(gameObject, val11);
			Transform val26 = Object.Instantiate<T