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;
}
}
}