Decompiled source of Hat Loader v1.1.0

HatLoader.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Alexandria.ItemAPI;
using Alexandria.cAPI;
using BepInEx;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using SGUI;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("HatLoader")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("N/A")]
[assembly: AssemblyProduct("HatLoader")]
[assembly: AssemblyCopyright("Copyright © N/A 2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("13bd8a8a-8724-4ced-af43-687ebc23ca8f")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace HatLoader
{
	[HarmonyPatch]
	public static class AutoHatManager
	{
		public static readonly HashSet<string> RandomHatList = new HashSet<string>();

		public const string RandomHatListFileName = "RandomHatList.txt";

		public static string RandomHatListFilePath;

		public const string RandomHatCommandGroup = "randomhats";

		public static void Init()
		{
			RandomHatListFilePath = Path.Combine(Paths.ConfigPath, "RandomHatList.txt");
			LoadRandomHatList();
			ETGModConsole.Commands.AddGroup("randomhats");
			ConsoleCommandGroup group = ETGModConsole.Commands.GetGroup("randomhats");
			group.AddUnit("addcurrent", (Action<string[]>)delegate
			{
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				//IL_007f: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
				if (GameManager.HasInstance)
				{
					if ((Object)(object)GameManager.Instance.PrimaryPlayer == (Object)null)
					{
						((SElement)ETGModConsole.Log((object)"No active player.", false)).Foreground = Color.red;
					}
					else
					{
						HatController component3 = ((Component)GameManager.Instance.PrimaryPlayer).GetComponent<HatController>();
						if (component3 != null)
						{
							Hat currentHat3 = component3.CurrentHat;
							if (currentHat3 != null && !((Object)(object)currentHat3 == (Object)null))
							{
								string hatName3 = currentHat3.hatName;
								string databaseFriendlyHatName3 = HatUtility.GetDatabaseFriendlyHatName(hatName3);
								if (!RandomHatList.Add(databaseFriendlyHatName3))
								{
									((SElement)ETGModConsole.Log((object)("Current hat \"" + databaseFriendlyHatName3 + "\" is already in the random hat list."), false)).Foreground = Color.yellow;
								}
								else
								{
									((SElement)ETGModConsole.Log((object)("Current hat \"" + databaseFriendlyHatName3 + "\" successfully added to the random hat list."), false)).Foreground = Color.green;
									WriteRandomHatList();
								}
								return;
							}
						}
						((SElement)ETGModConsole.Log((object)"The active player isn't wearing a hat.", false)).Foreground = Color.red;
					}
				}
			});
			group.AddUnit("setcurrent", (Action<string[]>)delegate
			{
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
				//IL_007f: Unknown result type (might be due to invalid IL or missing references)
				if (GameManager.HasInstance)
				{
					if ((Object)(object)GameManager.Instance.PrimaryPlayer == (Object)null)
					{
						((SElement)ETGModConsole.Log((object)"No active player.", false)).Foreground = Color.red;
					}
					else
					{
						HatController component2 = ((Component)GameManager.Instance.PrimaryPlayer).GetComponent<HatController>();
						if (component2 != null)
						{
							Hat currentHat2 = component2.CurrentHat;
							if (currentHat2 != null && !((Object)(object)currentHat2 == (Object)null))
							{
								string hatName2 = currentHat2.hatName;
								string databaseFriendlyHatName2 = HatUtility.GetDatabaseFriendlyHatName(hatName2);
								RandomHatList.Clear();
								RandomHatList.Add(databaseFriendlyHatName2);
								((SElement)ETGModConsole.Log((object)("Random hat list set to current hat \"" + databaseFriendlyHatName2 + "\""), false)).Foreground = Color.green;
								WriteRandomHatList();
								return;
							}
						}
						((SElement)ETGModConsole.Log((object)"The active player isn't wearing a hat.", false)).Foreground = Color.red;
					}
				}
			});
			group.AddUnit("removecurrent", (Action<string[]>)delegate
			{
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				//IL_007f: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
				if (GameManager.HasInstance)
				{
					if ((Object)(object)GameManager.Instance.PrimaryPlayer == (Object)null)
					{
						((SElement)ETGModConsole.Log((object)"No active player.", false)).Foreground = Color.red;
					}
					else
					{
						HatController component = ((Component)GameManager.Instance.PrimaryPlayer).GetComponent<HatController>();
						if (component != null)
						{
							Hat currentHat = component.CurrentHat;
							if (currentHat != null && !((Object)(object)currentHat == (Object)null))
							{
								string hatName = currentHat.hatName;
								string databaseFriendlyHatName = HatUtility.GetDatabaseFriendlyHatName(hatName);
								if (!RandomHatList.Remove(databaseFriendlyHatName))
								{
									((SElement)ETGModConsole.Log((object)("Current hat \"" + databaseFriendlyHatName + "\" is not in the random hat list."), false)).Foreground = Color.yellow;
								}
								else
								{
									((SElement)ETGModConsole.Log((object)("Current hat \"" + databaseFriendlyHatName + "\" successfully removed from the random hat list."), false)).Foreground = Color.green;
									WriteRandomHatList();
								}
								return;
							}
						}
						((SElement)ETGModConsole.Log((object)"The active player isn't wearing a hat.", false)).Foreground = Color.red;
					}
				}
			});
			group.AddUnit("clear", (Action<string[]>)delegate
			{
				//IL_0044: Unknown result type (might be due to invalid IL or missing references)
				//IL_0021: Unknown result type (might be due to invalid IL or missing references)
				if (RandomHatList.Count <= 0)
				{
					((SElement)ETGModConsole.Log((object)"Random hat list is already empty.", false)).Foreground = Color.yellow;
				}
				else
				{
					RandomHatList.Clear();
					((SElement)ETGModConsole.Log((object)"Successfully cleared the random hat list.", false)).Foreground = Color.green;
					WriteRandomHatList();
				}
			});
			group.AddUnit("log", (Action<string[]>)delegate
			{
				//IL_0021: Unknown result type (might be due to invalid IL or missing references)
				if (RandomHatList.Count <= 0)
				{
					((SElement)ETGModConsole.Log((object)"Random hat list is empty.", false)).Foreground = Color.yellow;
					return;
				}
				ETGModConsole.Log((object)"Current random hat list:", false);
				foreach (string randomHat in RandomHatList)
				{
					string text = randomHat;
					if (!Hatabase.Hats.ContainsKey(HatUtility.GetDatabaseFriendlyHatName(text)))
					{
						text += "<color=$FF0000>(not currently loaded)</color>";
					}
					ETGModConsole.Log((object)randomHat, false);
				}
			});
			ETGModConsole.CommandDescriptions["randomhats addcurrent"] = "Adds the player's current hat to the random hats list.";
			ETGModConsole.CommandDescriptions["randomhats setcurrent"] = "Sets the random hats list to only contain the player's current hat.";
			ETGModConsole.CommandDescriptions["randomhats removecurrent"] = "Removes the player's current hat from the random hats list.";
			ETGModConsole.CommandDescriptions["randomhats clear"] = "Removes all hats from the random hats list.";
			ETGModConsole.CommandDescriptions["randomhats log"] = "Logs the current hats list to the console.";
		}

		public static void LoadRandomHatList()
		{
			RandomHatList.Clear();
			if (File.Exists(RandomHatListFilePath))
			{
				string[] array = File.ReadAllLines(RandomHatListFilePath);
				foreach (string item in array)
				{
					RandomHatList.Add(item);
				}
			}
		}

		public static void WriteRandomHatList()
		{
			string directoryName = Path.GetDirectoryName(RandomHatListFilePath);
			if (!Directory.Exists(directoryName))
			{
				Directory.CreateDirectory(directoryName);
			}
			string randomHatListFilePath = RandomHatListFilePath;
			HashSet<string> randomHatList = RandomHatList;
			int num = 0;
			string[] array = new string[randomHatList.Count];
			foreach (string item in randomHatList)
			{
				array[num] = item;
				num++;
			}
			File.WriteAllLines(randomHatListFilePath, array);
		}

		[HarmonyPatch(typeof(PlayerController), "Start")]
		[HarmonyPostfix]
		public static void EquipRandomHat_Postfix(PlayerController __instance)
		{
			if ((Object)(object)__instance == (Object)null || RandomHatList.Count <= 0)
			{
				return;
			}
			List<string> list = new List<string>(RandomHatList);
			if (list.Count > 0)
			{
				int index = Random.Range(0, list.Count);
				string databaseFriendlyHatName = HatUtility.GetDatabaseFriendlyHatName(list[index]);
				list.RemoveAt(index);
				if (Hatabase.Hats.ContainsKey(databaseFriendlyHatName))
				{
					Hatabase.StoredHats[((Object)__instance).name] = databaseFriendlyHatName;
					GameObjectExtensions.GetOrAddComponent<HatController>(((Component)__instance).gameObject);
				}
			}
		}
	}
	public static class Loader
	{
		public static tk2dSpriteCollectionData HatLoaderCollection;

		public static void LoadHats()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_047c: Unknown result type (might be due to invalid IL or missing references)
			//IL_056a: Unknown result type (might be due to invalid IL or missing references)
			//IL_056f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0575: Unknown result type (might be due to invalid IL or missing references)
			//IL_0577: Unknown result type (might be due to invalid IL or missing references)
			HatLoaderCollection = SpriteBuilder.ConstructCollection(new GameObject(), "HatLoaderHatCollection", false);
			string[] files = Directory.GetFiles(Paths.PluginPath, "*-hat.spapi", SearchOption.AllDirectories);
			foreach (string path in files)
			{
				string[] lines = File.ReadAllLines(path);
				string file = Path.GetFileName(path);
				string directoryName = Path.GetDirectoryName(path);
				string name = "";
				int xOffs = 0;
				int yOffs = 0;
				int fps = 4;
				bool attachedToHead = true;
				bool inFrontWhenFacingBack = true;
				bool inFrontWhenFacingFront = true;
				bool flipOnRoll = true;
				bool vanishOnRoll = false;
				string flipStartSound = "";
				string flipEndSound = "";
				float flipSpeed = 1f;
				float flipHeight = 1f;
				bool? flipHorizontalWithPlayer = null;
				Dictionary<string, List<string>> hatSpritePaths = new Dictionary<string, List<string>>();
				List<tk2dSpriteDefinition> list = new List<tk2dSpriteDefinition>();
				string hatRoomSprite = "";
				SpapiDataReader.HandleLines(lines, new Dictionary<string, Func<List<string>, bool>>
				{
					{
						"name",
						delegate(List<string> x)
						{
							name = x.LastOrDefault();
							return true;
						}
					},
					{
						"northsprites",
						delegate(List<string> x)
						{
							hatSpritePaths["north"] = x;
							return true;
						}
					},
					{
						"southsprites",
						delegate(List<string> x)
						{
							hatSpritePaths["south"] = x;
							return true;
						}
					},
					{
						"westsprites",
						delegate(List<string> x)
						{
							hatSpritePaths["west"] = x;
							return true;
						}
					},
					{
						"eastsprites",
						delegate(List<string> x)
						{
							hatSpritePaths["east"] = x;
							return true;
						}
					},
					{
						"northwestsprites",
						delegate(List<string> x)
						{
							hatSpritePaths["northwest"] = x;
							return true;
						}
					},
					{
						"northeastsprites",
						delegate(List<string> x)
						{
							hatSpritePaths["northeast"] = x;
							return true;
						}
					},
					{
						"hatroomsprite",
						delegate(List<string> x)
						{
							hatRoomSprite = x.LastOrDefault();
							return true;
						}
					},
					{
						"xoffset",
						delegate(List<string> x)
						{
							if (int.TryParse(x.LastOrDefault(), out xOffs))
							{
								return true;
							}
							Debug.LogError((object)("Error reading hat file " + file + ": XOffset should be an integer."));
							return false;
						}
					},
					{
						"yoffset",
						delegate(List<string> x)
						{
							if (int.TryParse(x.LastOrDefault(), out yOffs))
							{
								return true;
							}
							Debug.LogError((object)("Error reading hat file " + file + ": YOffset should be an integer."));
							return false;
						}
					},
					{
						"fps",
						delegate(List<string> x)
						{
							if (int.TryParse(x.LastOrDefault(), out fps))
							{
								return true;
							}
							Debug.LogError((object)("Error reading hat file " + file + ": FPS should be an integer."));
							return false;
						}
					},
					{
						"attachedtohead",
						delegate(List<string> x)
						{
							if (bool.TryParse(x.LastOrDefault(), out attachedToHead))
							{
								return true;
							}
							Debug.LogError((object)("Error reading hat file " + file + ": AttachedToHead should be True or False."));
							return false;
						}
					},
					{
						"infrontwhenfacingback",
						delegate(List<string> x)
						{
							if (bool.TryParse(x.LastOrDefault(), out inFrontWhenFacingBack))
							{
								return true;
							}
							Debug.LogError((object)("Error reading hat file " + file + ": InFrontWhenFacingBack should be True or False."));
							return false;
						}
					},
					{
						"infrontwhenfacingfront",
						delegate(List<string> x)
						{
							if (bool.TryParse(x.LastOrDefault(), out inFrontWhenFacingFront))
							{
								return true;
							}
							Debug.LogError((object)("Error reading hat file " + file + ": InFrontWhenFacingFront should be True or False."));
							return false;
						}
					},
					{
						"fliponroll",
						delegate(List<string> x)
						{
							if (bool.TryParse(x.LastOrDefault(), out flipOnRoll))
							{
								return true;
							}
							Debug.LogError((object)("Error reading hat file " + file + ": FlipOnRoll should be True or False."));
							return false;
						}
					},
					{
						"vanishonroll",
						delegate(List<string> x)
						{
							if (bool.TryParse(x.LastOrDefault(), out vanishOnRoll))
							{
								return true;
							}
							Debug.LogError((object)("Error reading hat file " + file + ": VanishOnRoll should be True or False."));
							return false;
						}
					},
					{
						"flipstartsound",
						delegate(List<string> x)
						{
							flipStartSound = x.LastOrDefault();
							return true;
						}
					},
					{
						"flipendsound",
						delegate(List<string> x)
						{
							flipEndSound = x.LastOrDefault();
							return true;
						}
					},
					{
						"flipspeed",
						delegate(List<string> x)
						{
							if (float.TryParse(x.LastOrDefault(), out flipSpeed))
							{
								return true;
							}
							Debug.LogError((object)("Error reading hat file " + file + ": FlipSpeed should be a number."));
							return false;
						}
					},
					{
						"flipheight",
						delegate(List<string> x)
						{
							if (float.TryParse(x.LastOrDefault(), out flipHeight))
							{
								return true;
							}
							Debug.LogError((object)("Error reading hat file " + file + ": FlipHeight should be a number."));
							return false;
						}
					},
					{
						"fliphorizontalwithplayer",
						delegate(List<string> x)
						{
							bool result;
							bool flag = bool.TryParse(x.LastOrDefault(), out result);
							flipHorizontalWithPlayer = result;
							if (flag)
							{
								return true;
							}
							Debug.LogError((object)("Error reading hat file " + file + ": FlipHorizontalWithPlayer should be True or False."));
							return false;
						}
					}
				}, delegate(string x)
				{
					Debug.LogError((object)("Error reading hat file " + file + ": " + x));
				});
				if (string.IsNullOrEmpty(name))
				{
					Debug.LogError((object)("Error loading hat " + file + ": hat name not given."));
					continue;
				}
				foreach (KeyValuePair<string, List<string>> item in hatSpritePaths)
				{
					string key = item.Key;
					List<string> value = item.Value;
					for (int j = 0; j < value.Count; j++)
					{
						int spriteId;
						tk2dSpriteDefinition val = LoadHatSpriteDefinition(directoryName, value[j], $"{ETGMod.ToID(name)}_{key}_{j + 1:D3}", file, out spriteId);
						if (val != null)
						{
							list.Add(val);
						}
					}
				}
				int spriteId2 = -1;
				tk2dSpriteDefinition val2 = null;
				if (!string.IsNullOrEmpty(hatRoomSprite))
				{
					val2 = LoadHatSpriteDefinition(directoryName, hatRoomSprite, ETGMod.ToID(name) + "_default_001", file, out spriteId2);
				}
				if (list.Count <= 0)
				{
					Debug.LogError((object)("Error loading hat " + file + ": hat doesn't have any sprites."));
					continue;
				}
				try
				{
					Hat val3 = HatUtility.SetupHat(name, (List<string>)null, (IntVector2?)new IntVector2(xOffs, yOffs), fps, (HatAttachLevel)((!attachedToHead) ? 1 : 0), (HatDepthType)((!inFrontWhenFacingBack) ? ((!inFrontWhenFacingFront) ? 1 : 2) : ((!inFrontWhenFacingFront) ? 3 : 0)), (HatRollReaction)(vanishOnRoll ? 1 : ((!flipOnRoll) ? 2 : 0)), string.IsNullOrEmpty(flipStartSound) ? null : flipStartSound, string.IsNullOrEmpty(flipEndSound) ? null : flipEndSound, flipSpeed, flipHeight, flipHorizontalWithPlayer, false, (List<GungeonFlags>)null, (List<DungeonPrerequisite>)null, (string)null, false);
					HatUtility.SetupHatSprites(val3, (List<string>)null, list, fps, (Assembly)null);
					if (val2 != null)
					{
						tk2dSpriteDefinition val4 = val2;
						Vector3[] colliderVertices = ((BraveBehaviour)val3).sprite.CurrentSprite.colliderVertices;
						int num = 0;
						Vector3[] array = (Vector3[])(object)new Vector3[colliderVertices.Length];
						Vector3[] array2 = colliderVertices;
						foreach (Vector3 val5 in array2)
						{
							array[num] = val5;
							num++;
						}
						val4.colliderVertices = array;
					}
					if (spriteId2 >= 0)
					{
						((BraveBehaviour)val3).sprite.SetSprite(HatLoaderCollection, spriteId2);
					}
				}
				catch (Exception ex)
				{
					Debug.LogError((object)("Error loading hat " + file + ": " + ex.Message));
				}
			}
		}

		public static tk2dSpriteDefinition LoadHatSpriteDefinition(string hatDirectory, string spriteName, string definitionName, string hatFile, out int spriteId)
		{
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Expected O, but got Unknown
			spriteId = -1;
			string text = spriteName.Replace('\\', Path.DirectorySeparatorChar).Replace('/', Path.DirectorySeparatorChar);
			if (!text.EndsWith(".png"))
			{
				text += ".png";
			}
			string path = Path.Combine(hatDirectory, text);
			if (!File.Exists(path))
			{
				Debug.LogError((object)("Error loading sprites for hat " + hatFile + ": file " + spriteName + " doesn't exist."));
				return null;
			}
			byte[] array = File.ReadAllBytes(path);
			Texture2D val = new Texture2D(1, 1, (TextureFormat)4, false)
			{
				filterMode = (FilterMode)0,
				name = definitionName
			};
			try
			{
				if (!ImageConversion.LoadImage(val, array))
				{
					Debug.LogError((object)("Error loading sprites for hat " + hatFile + ": file " + text + " is not a valid texture."));
					return null;
				}
			}
			catch
			{
				Debug.LogError((object)("Error loading sprites for hat " + hatFile + ": file " + text + " is not a valid texture."));
				return null;
			}
			spriteId = SpriteBuilder.AddSpriteToCollection(val, HatLoaderCollection, "");
			return HatLoaderCollection.spriteDefinitions[spriteId];
		}
	}
	[BepInPlugin("spapi.etg.hatloader", "Hat Loader", "1.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string GUID = "spapi.etg.hatloader";

		public const string NAME = "Hat Loader";

		public const string VERSION = "1.1.0";

		public void Awake()
		{
			ETGModMainBehaviour.WaitForGameManagerStart((Action<GameManager>)GMStart);
		}

		public void GMStart(GameManager gm)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			Loader.LoadHats();
			AutoHatManager.Init();
			Harmony val = new Harmony("spapi.etg.hatloader");
			val.PatchAll();
		}
	}
	public static class SpapiDataReader
	{
		public static bool HandleLines(string[] lines, Dictionary<string, Func<List<string>, bool>> propertyHandler, Action<string> errorHandler)
		{
			for (int i = 0; i < lines.Length; i++)
			{
				string text = lines[i];
				if (Utility.IsNullOrWhiteSpace(text))
				{
					continue;
				}
				string text2 = text.Trim();
				if (text2.StartsWith("#") && text2.Length > 1)
				{
					string text3 = text2.Substring(1).Trim().ToLowerInvariant();
					if (!Utility.IsNullOrWhiteSpace(text3))
					{
						List<string> property;
						bool flag = TryReadDataProperty(lines, ref i, out property);
						if (!propertyHandler.TryGetValue(text3.ToLowerInvariant(), out var value))
						{
							errorHandler?.Invoke("unknown property " + text3 + ".");
							return false;
						}
						if (flag && value != null && !value(property))
						{
							return false;
						}
					}
					continue;
				}
				errorHandler?.Invoke($"unexpected data at line {i + 1}.");
				return false;
			}
			return true;
		}

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