Decompiled source of PerditionQOL v0.1.3

plugins/PerditionQOL.dll

Decompiled 6 hours ago
using 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;
		}
	}
}