Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of PerditionQOL v0.1.3
plugins/PerditionQOL.dll
Decompiled 6 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Microsoft.CodeAnalysis; using PerditionQOL.Hearthstone; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("PerditionQOL")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.3.0")] [assembly: AssemblyInformationalVersion("0.1.3")] [assembly: AssemblyProduct("PerditionQOL")] [assembly: AssemblyTitle("PerditionQOL")] [assembly: AssemblyVersion("0.1.3.0")] [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 PerditionQOL { internal sealed class PerditionQOLConfig { internal ConfigEntry<int> HearthstoneWoodCost { get; } internal ConfigEntry<float> TeleportCooldownSeconds { get; } internal ConfigEntry<bool> BlockUseDuringCombat { get; } internal PerditionQOLConfig(ConfigFile config) { HearthstoneWoodCost = config.Bind<int>("Hearthstone", "WoodCost", 1, "Wood required to craft one Hearthstone."); TeleportCooldownSeconds = config.Bind<float>("Hearthstone", "TeleportCooldownSeconds", 60f, "Cooldown applied after a successful teleport."); BlockUseDuringCombat = config.Bind<bool>("Restrictions", "BlockUseDuringCombat", true, "Prevent Hearthstone actions while the player is in combat."); } } [BepInPlugin("com.perdition.qol", "PerditionQOL", "0.1.3")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "com.perdition.qol"; public const string Name = "PerditionQOL"; public const string Version = "0.1.3"; private OnlinePlayerService onlinePlayerService; private bool hearthstoneRegistered; internal static ManualLogSource Log { get; private set; } internal static PerditionQOLConfig ModConfig { get; private set; } private void Awake() { Log = ((BaseUnityPlugin)this).Logger; ModConfig = new PerditionQOLConfig(((BaseUnityPlugin)this).Config); Log.LogInfo((object)"PerditionQOL 0.1.3 loaded."); PrefabManager.OnVanillaPrefabsAvailable += RegisterHearthstone; onlinePlayerService = new OnlinePlayerService(); HearthstoneService hearthstoneService = new HearthstoneService(ModConfig); HearthstoneMenu menu = new HearthstoneMenu(hearthstoneService, onlinePlayerService); HearthstoneInteraction.Install(hearthstoneService, menu); } private void RegisterHearthstone() { if (!hearthstoneRegistered) { new HearthstoneItem().Register(ModConfig.HearthstoneWoodCost.Value); hearthstoneRegistered = true; } } private void OnDestroy() { PrefabManager.OnVanillaPrefabsAvailable -= RegisterHearthstone; } private void Update() { } } } namespace PerditionQOL.Hearthstone { internal static class HearthstoneInteraction { [HarmonyPatch(typeof(Humanoid), "UseItem")] private static class HumanoidUseItemPatch { private static bool Prefix(Humanoid __instance, Inventory inventory, ItemData item) { Player val = (Player)(object)((__instance is Player) ? __instance : null); if (val == null || (Object)(object)item?.m_dropPrefab == (Object)null) { return true; } if (((Object)item.m_dropPrefab).name != "PerditionQOL_Hearthstone") { return true; } Menu.Open(val); return false; } } private static HearthstoneService Service { get; set; } private static HearthstoneMenu Menu { get; set; } internal static void Install(HearthstoneService service, HearthstoneMenu menu) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) Service = service; Menu = menu; new Harmony("com.perdition.qol").PatchAll(typeof(HearthstoneInteraction).Assembly); Plugin.Log.LogInfo((object)"Registered Hearthstone item-use hook on Humanoid.UseItem."); } } internal sealed class HearthstoneItem { internal const string PrefabName = "PerditionQOL_Hearthstone"; private const string SourcePrefabName = "AmberPearl"; internal void Register(int woodCost) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_0056: 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) //IL_00b2: Expected O, but got Unknown //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Expected O, but got Unknown //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Expected O, but got Unknown CustomItem val = new CustomItem("PerditionQOL_Hearthstone", "AmberPearl"); val.ItemDrop.m_itemData.m_shared.m_name = "Perdition Hearthstone"; val.ItemDrop.m_itemData.m_shared.m_description = "Choose a spawn point or another online player."; val.ItemDrop.m_itemData.m_shared.m_itemType = (ItemType)18; val.ItemDrop.m_itemData.m_shared.m_maxStackSize = 1; val.ItemDrop.m_itemData.m_shared.m_icons = (Sprite[])(object)new Sprite[1] { LoadIcon() }; if (!ItemManager.Instance.AddItem(val)) { throw new InvalidOperationException("Unable to register item 'PerditionQOL_Hearthstone'."); } RecipeConfig val2 = new RecipeConfig(); val2.Item = "PerditionQOL_Hearthstone"; val2.CraftingStation = "piece_workbench"; val2.MinStationLevel = 1; val2.Requirements = (RequirementConfig[])(object)new RequirementConfig[1] { new RequirementConfig("Wood", woodCost, 0, true) }; CustomRecipe val3 = new CustomRecipe(val2); if (!ItemManager.Instance.AddRecipe(val3)) { throw new InvalidOperationException("Unable to register recipe for 'PerditionQOL_Hearthstone'."); } Plugin.Log.LogInfo((object)string.Format("Registered {0} with a {1} Wood recipe.", "PerditionQOL_Hearthstone", woodCost)); } private static Sprite LoadIcon() { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) using Stream stream = typeof(HearthstoneItem).Assembly.GetManifestResourceStream("PerditionQOL.Hearthstone.Assets.Hearthstone.png"); if (stream == null) { throw new InvalidOperationException("Embedded Hearthstone icon was not found: PerditionQOL.Hearthstone.Assets.Hearthstone.png"); } byte[] array = new byte[stream.Length]; if (stream.Read(array, 0, array.Length) != array.Length) { throw new InvalidOperationException("The embedded Hearthstone icon could not be read completely."); } Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); object obj = (Type.GetType("UnityEngine.ImageConversion, UnityEngine.ImageConversionModule")?.GetMethod("LoadImage", BindingFlags.Static | BindingFlags.Public, null, new Type[3] { typeof(Texture2D), typeof(byte[]), typeof(bool) }, null))?.Invoke(null, new object[3] { val, array, true }); if (!(obj is bool) || !(bool)obj) { Object.Destroy((Object)(object)val); throw new InvalidOperationException("The embedded Hearthstone icon could not be decoded."); } ((Object)val).name = "PerditionQOL_HearthstoneIcon"; return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f); } } internal sealed class HearthstoneMenu { private readonly HearthstoneService hearthstoneService; private readonly OnlinePlayerService onlinePlayerService; private GameObject? menuRoot; internal HearthstoneMenu(HearthstoneService hearthstoneService, OnlinePlayerService onlinePlayerService) { this.hearthstoneService = hearthstoneService; this.onlinePlayerService = onlinePlayerService; GUIManager.OnCustomGUIAvailable += CreateMenu; } internal void Open(Player player) { if ((Object)(object)menuRoot == (Object)null) { CreateMenu(); } if ((Object)(object)menuRoot == (Object)null) { Plugin.Log.LogError((object)"Unable to open Hearthstone menu because Jotunn GUI is unavailable."); return; } ShowMainMenu(player); menuRoot.SetActive(true); GUIManager.BlockInput(true); } private void CreateMenu() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_007a: 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) if ((Object)(object)menuRoot != (Object)null) { Object.Destroy((Object)(object)menuRoot); menuRoot = null; } if (!((Object)(object)GUIManager.CustomGUIFront == (Object)null)) { menuRoot = new GameObject("PerditionQOL_HearthstoneMenu"); RectTransform obj = menuRoot.AddComponent<RectTransform>(); ((Transform)obj).SetParent(GUIManager.CustomGUIFront.transform, false); obj.anchorMin = new Vector2(0.5f, 0.5f); obj.anchorMax = new Vector2(0.5f, 0.5f); obj.anchoredPosition = Vector2.zero; menuRoot.SetActive(false); } } private void ShowMainMenu(Player player) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown ClearButtons(); AddButton("Return to Bed", 90f, (UnityAction)delegate { CloseAfter(delegate { hearthstoneService.ReturnToSpawn(player); }); }); AddButton("Teleport to Player", 30f, (UnityAction)delegate { ShowPlayerMenu(player); }); AddButton("Close", -30f, new UnityAction(Close)); } private void ShowPlayerMenu(Player requester) { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Expected O, but got Unknown //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Expected O, but got Unknown ClearButtons(); IReadOnlyList<OnlinePlayerTarget> otherOnlinePlayers = onlinePlayerService.GetOtherOnlinePlayers(requester); int num = 90; foreach (OnlinePlayerTarget item in otherOnlinePlayers) { OnlinePlayerTarget selectedTarget = item; AddButton("Teleport to " + item.Name, num, (UnityAction)delegate { CloseAfter(delegate { hearthstoneService.TeleportToPlayer(requester, selectedTarget); }); }); num -= 60; } if (otherOnlinePlayers.Count == 0) { AddButton("No other players online", 30f, (UnityAction)delegate { ShowMainMenu(requester); }); } AddButton("Back", -120f, (UnityAction)delegate { ShowMainMenu(requester); }); } private void AddButton(string label, float y, UnityAction action) { //IL_002a: 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_0044: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)menuRoot == (Object)null)) { Button component = GUIManager.Instance.CreateButton(label, menuRoot.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, y), 320f, 48f).GetComponent<Button>(); if ((Object)(object)component == (Object)null) { Plugin.Log.LogError((object)("Jotunn did not create a Button for '" + label + "'.")); } else { ((UnityEvent)component.onClick).AddListener(action); } } } private void ClearButtons() { if (!((Object)(object)menuRoot == (Object)null)) { for (int num = menuRoot.transform.childCount - 1; num >= 0; num--) { Object.Destroy((Object)(object)((Component)menuRoot.transform.GetChild(num)).gameObject); } } } private void CloseAfter(Action action) { action(); Close(); } private void Close() { if ((Object)(object)menuRoot != (Object)null) { menuRoot.SetActive(false); } GUIManager.BlockInput(false); } } internal sealed class HearthstoneService { private readonly PerditionQOLConfig config; private float nextAvailableTime; internal HearthstoneService(PerditionQOLConfig config) { this.config = config; } internal bool ReturnToSpawn(Player player) { //IL_0047: 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 (config.BlockUseDuringCombat.Value && !((Humanoid)player).IsTeleportable(false)) { ShowMessage("Hearthstone cannot be used in combat."); return false; } if (!CheckCooldown()) { return false; } if (!TryResolveSpawn(out var destination)) { ShowMessage("No valid spawn point could be found."); return false; } if (!((Character)player).TeleportTo(destination, ((Component)player).transform.rotation, true)) { ShowMessage("Hearthstone teleport failed."); return false; } StartCooldown(); Plugin.Log.LogInfo((object)"Hearthstone returned the player to their spawn point."); return true; } internal bool TeleportToPlayer(Player player, OnlinePlayerTarget target) { //IL_00b1: 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_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ZNet.instance == (Object)null) { ShowMessage("That player is no longer online."); return false; } ZNetPeer val = null; foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { if (peer.m_playerID == target.PlayerId) { val = peer; break; } } if (val == null) { ShowMessage("That player is no longer online."); return false; } if (config.BlockUseDuringCombat.Value && !((Humanoid)player).IsTeleportable(false)) { ShowMessage("Hearthstone cannot be used in combat."); return false; } if (!CheckCooldown()) { return false; } Player player2 = Player.GetPlayer(target.PlayerId); Vector3 refPos = val.GetRefPos(); Quaternion val2 = (((Object)(object)player2 != (Object)null) ? ((Component)player2).transform.rotation : ((Component)player).transform.rotation); bool flag = (Object)(object)player2 == (Object)null; if (!((Character)player).TeleportTo(refPos, val2, flag)) { ShowMessage("Hearthstone teleport failed."); return false; } StartCooldown(); Plugin.Log.LogInfo((object)("Hearthstone teleported the player to " + target.Name + ".")); return true; } private bool CheckCooldown() { float num = nextAvailableTime - Time.time; if (num > 0f) { ShowMessage($"Hearthstone is recharging ({num:0}s)."); return false; } return true; } private void StartCooldown() { nextAvailableTime = Time.time + config.TeleportCooldownSeconds.Value; } private static bool TryResolveSpawn(out Vector3 destination) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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) //IL_006e: 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) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0053: 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_0061: Unknown result type (might be due to invalid IL or missing references) PlayerProfile playerProfile = Game.instance.GetPlayerProfile(); if (playerProfile.HaveCustomSpawnPoint()) { destination = playerProfile.GetCustomSpawnPoint(); return true; } if (AccessTools.Field(typeof(PlayerProfile), "m_firstSpawn")?.GetValue(playerProfile) is Vector3 val && val != Vector3.zero) { destination = val; return true; } destination = Vector3.zero; return false; } private static void ShowMessage(string message) { if ((Object)(object)MessageHud.instance != (Object)null) { MessageHud.instance.ShowMessage((MessageType)2, message, 0, (Sprite)null, false, true); } } } internal sealed class OnlinePlayerTarget { internal long PlayerId { get; } internal string Name { get; } internal Vector3 Position { get; } internal OnlinePlayerTarget(long playerId, string name, Vector3 position) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) PlayerId = playerId; Name = name; Position = position; } } internal sealed class OnlinePlayerService { internal IReadOnlyList<OnlinePlayerTarget> GetOtherOnlinePlayers(Player requester) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) List<OnlinePlayerTarget> list = new List<OnlinePlayerTarget>(); if ((Object)(object)ZNet.instance == (Object)null) { return list; } long playerID = requester.GetPlayerID(); foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { if (peer.m_playerID != playerID && !string.IsNullOrWhiteSpace(peer.m_playerName)) { list.Add(new OnlinePlayerTarget(peer.m_playerID, peer.m_playerName, peer.GetRefPos())); } } return list; } } }