Decompiled source of ImprovedTABSlot v2.0.0

plugins/Iron.ImprovedTABSlot.dll

Decompiled 18 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using ImprovedTabSlot.Networking;
using Microsoft.CodeAnalysis;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Iron.ImprovedTABSlot")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("2.0.0.0")]
[assembly: AssemblyInformationalVersion("2.0.0+a1a0ae3f460207ca065f3f4b61d85da3d504388e")]
[assembly: AssemblyProduct("ImprovedTABSlot")]
[assembly: AssemblyTitle("Iron.ImprovedTABSlot")]
[assembly: AssemblyVersion("2.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[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 ImprovedTabSlot
{
	internal static class ItemIdentity
	{
		internal const int ManeaterItemIdA = 123984;

		internal const int ManeaterItemIdB = 819501;

		public static bool IsManeater(GrabbableObject o)
		{
			Item val = o?.itemProperties;
			if ((Object)(object)val != (Object)null)
			{
				if (val.itemId != 123984)
				{
					return val.itemId == 819501;
				}
				return true;
			}
			return false;
		}

		public static string Name(GrabbableObject o)
		{
			if ((Object)(object)o == (Object)null)
			{
				return "<null>";
			}
			if ((Object)(object)o.itemProperties != (Object)null && !string.IsNullOrEmpty(o.itemProperties.itemName))
			{
				return o.itemProperties.itemName;
			}
			return ((object)o).GetType().Name;
		}

		public static bool IsAllowed(GrabbableObject o)
		{
			if ((Object)(object)o == (Object)null)
			{
				return false;
			}
			PluginConfig cfg = Plugin.Cfg;
			string text = (((Object)(object)o.itemProperties != (Object)null && o.itemProperties.itemName != null) ? o.itemProperties.itemName.Trim().ToLowerInvariant() : "");
			if (cfg.AllowShovel.Value)
			{
				if (!HasClass(o, "Shovel"))
				{
					switch (text)
					{
					case "shovel":
					case "stop sign":
					case "yield sign":
						break;
					default:
						goto IL_008c;
					}
				}
				return true;
			}
			goto IL_008c;
			IL_008c:
			if (cfg.AllowShotgun.Value && (HasClass(o, "ShotgunItem") || text == "shotgun"))
			{
				return true;
			}
			if (cfg.AllowKnife.Value && (HasClass(o, "KnifeItem") || text.Contains("knife")))
			{
				return true;
			}
			if (cfg.AllowKey.Value && (HasClass(o, "KeyItem") || text == "key"))
			{
				return true;
			}
			if (cfg.AllowClipboard.Value && text == "clipboard")
			{
				return true;
			}
			if (cfg.AllowStickyNote.Value && text == "sticky note")
			{
				return true;
			}
			if (cfg.AllowAmmo.Value && (text == "ammo" || text.Contains("shell")))
			{
				return true;
			}
			if (cfg.AllowManeater.Value && IsManeater(o))
			{
				return true;
			}
			return false;
		}

		private static bool HasClass(GrabbableObject o, string simpleName)
		{
			Type type = ((object)o).GetType();
			while (type != null && type != typeof(GrabbableObject))
			{
				if (type.Name == simpleName)
				{
					return true;
				}
				type = type.BaseType;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB))]
	internal static class UtilitySlotPatch
	{
		internal const int UtilitySlotIndex = 50;

		[HarmonyPrefix]
		[HarmonyPatch("FirstEmptyItemSlot", new Type[] { typeof(GrabbableObject) })]
		private static bool FirstEmptyItemSlot_Prefix(PlayerControllerB __instance, GrabbableObject attemptingGrab, ref int __result)
		{
			try
			{
				if (!HostSync.Enabled)
				{
					return true;
				}
				if (!Plugin.Cfg.Enabled.Value)
				{
					return true;
				}
				if ((Object)(object)attemptingGrab == (Object)null)
				{
					return true;
				}
				if ((Object)(object)__instance.ItemOnlySlot != (Object)null)
				{
					return true;
				}
				if (!ItemIdentity.IsAllowed(attemptingGrab))
				{
					return true;
				}
				__result = 50;
				if (Plugin.Cfg.VerboseLogging.Value)
				{
					Plugin.Log.LogInfo((object)("Routing '" + ItemIdentity.Name(attemptingGrab) + "' to the utility slot."));
				}
				return false;
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"FirstEmptyItemSlot_Prefix error: {arg}");
				return true;
			}
		}
	}
	[BepInPlugin("Iron.ImprovedTABSlot", "ImprovedTABSlot", "2.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PLUGIN_GUID = "Iron.ImprovedTABSlot";

		public const string PLUGIN_NAME = "ImprovedTABSlot";

		public const string PLUGIN_VERSION = "2.0.0";

		private Harmony _harmony;

		internal static Plugin Instance { get; private set; }

		internal static ManualLogSource Log { get; private set; }

		internal static PluginConfig Cfg { get; private set; }

		private void Awake()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Cfg = new PluginConfig(((BaseUnityPlugin)this).Config);
			_harmony = new Harmony("Iron.ImprovedTABSlot");
			try
			{
				_harmony.PatchAll(typeof(Plugin).Assembly);
				VerifyPatched();
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"Harmony patching failed; the mod is inactive: {arg}");
			}
			Log.LogInfo((object)"ImprovedTABSlot v2.0.0 loaded.");
		}

		private void VerifyPatched()
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(PlayerControllerB), "FirstEmptyItemSlot", new Type[1] { typeof(GrabbableObject) }, (Type[])null);
			if (methodInfo == null)
			{
				Log.LogError((object)"PlayerControllerB.FirstEmptyItemSlot(GrabbableObject) was not found. The game version may have changed it; the utility-slot patch is INACTIVE.");
				return;
			}
			Patches patchInfo = Harmony.GetPatchInfo((MethodBase)methodInfo);
			bool flag = patchInfo?.Prefixes != null && patchInfo.Prefixes.Any((Patch p) => p.owner == "Iron.ImprovedTABSlot");
			Log.LogInfo((object)(flag ? "Utility-slot patch active on PlayerControllerB.FirstEmptyItemSlot." : "WARNING: utility-slot Prefix did not attach — mod is loaded but inactive."));
		}
	}
	public class PluginConfig
	{
		public readonly ConfigEntry<bool> Enabled;

		public readonly ConfigEntry<bool> AllowShovel;

		public readonly ConfigEntry<bool> AllowAmmo;

		public readonly ConfigEntry<bool> AllowClipboard;

		public readonly ConfigEntry<bool> AllowStickyNote;

		public readonly ConfigEntry<bool> AllowKey;

		public readonly ConfigEntry<bool> AllowShotgun;

		public readonly ConfigEntry<bool> AllowKnife;

		public readonly ConfigEntry<bool> AllowManeater;

		public readonly ConfigEntry<bool> VerboseLogging;

		public PluginConfig(ConfigFile file)
		{
			Enabled = file.Bind<bool>("General", "Enabled", true, "Master switch. When false the mod does nothing and the vanilla utility-slot blacklist is left untouched.");
			AllowShovel = file.Bind<bool>("Items", "Shovel", true, "Allow the Shovel into the utility slot. (Stop sign / Yield sign reuse the Shovel class and are included.)");
			AllowAmmo = file.Bind<bool>("Items", "Ammo", true, "Allow Ammo (shotgun shells) into the utility slot.");
			AllowClipboard = file.Bind<bool>("Items", "Clipboard", true, "Allow the Clipboard into the utility slot.");
			AllowStickyNote = file.Bind<bool>("Items", "StickyNote", true, "Allow the Sticky note into the utility slot.");
			AllowKey = file.Bind<bool>("Items", "Key", true, "Allow Keys into the utility slot.");
			AllowShotgun = file.Bind<bool>("Items", "Shotgun", true, "Allow the Shotgun into the utility slot. NOTE: the Shotgun is two-handed, so vanilla's two-handed switching lock still applies once it is in your hands (see README).");
			AllowKnife = file.Bind<bool>("Items", "Knife", true, "Allow the Kitchen knife into the utility slot.");
			AllowManeater = file.Bind<bool>("Items", "Maneater", false, "Allow the Maneater (baby cave dweller) into the utility (Tab) slot. The utility slot uses the real grab path (EquipItem) which freezes the creature correctly. WARNING: off by design — it's a balance cheese. Set true only if you specifically want it.");
			VerboseLogging = file.Bind<bool>("Debug", "VerboseLogging", false, "Log each time an item is routed to the utility slot, and networking state changes.");
		}
	}
}
namespace ImprovedTabSlot.Patches
{
	[HarmonyPatch]
	internal static class NetworkPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(NetworkManager), "Initialize")]
		private static void AfterNetworkInitialize()
		{
			HostSync.Register();
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(GameNetworkManager), "SetInstanceValuesBackToDefault")]
		private static void OnNetworkTearDown()
		{
			HostSync.Unregister();
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(StartOfRound), "Start")]
		private static void OnLobbyStart(StartOfRound __instance)
		{
			if (((NetworkBehaviour)__instance).IsServer)
			{
				HostSync.EnableAsHost();
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(StartOfRound), "OnClientConnect")]
		private static void OnClientConnected(StartOfRound __instance, ulong __0)
		{
			if (((NetworkBehaviour)__instance).IsServer)
			{
				HostSync.SendHostPresent(new ulong[1] { __0 });
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(MenuManager), "Start")]
		private static void OnMainMenu()
		{
			HostSync.Reset();
		}
	}
}
namespace ImprovedTabSlot.Networking
{
	internal static class HostSync
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static HandleNamedMessageDelegate <0>__OnHostPresent;
		}

		internal static bool Enabled;

		private static readonly string HostPresentMessage = "Iron.ImprovedTABSlot|HostPresent";

		internal static void Register()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			NetworkManager singleton = NetworkManager.Singleton;
			if (((singleton != null) ? singleton.CustomMessagingManager : null) != null)
			{
				CustomMessagingManager customMessagingManager = singleton.CustomMessagingManager;
				string hostPresentMessage = HostPresentMessage;
				object obj = <>O.<0>__OnHostPresent;
				if (obj == null)
				{
					HandleNamedMessageDelegate val = OnHostPresent;
					<>O.<0>__OnHostPresent = val;
					obj = (object)val;
				}
				customMessagingManager.RegisterNamedMessageHandler(hostPresentMessage, (HandleNamedMessageDelegate)obj);
			}
		}

		internal static void Unregister()
		{
			NetworkManager singleton = NetworkManager.Singleton;
			if (((singleton != null) ? singleton.CustomMessagingManager : null) != null)
			{
				singleton.CustomMessagingManager.UnregisterNamedMessageHandler(HostPresentMessage);
			}
		}

		internal static void EnableAsHost()
		{
			Enabled = true;
			if (Plugin.Cfg.VerboseLogging.Value)
			{
				Plugin.Log.LogInfo((object)"Host has the mod — utility-slot feature enabled (host).");
			}
		}

		internal static void Reset()
		{
			Enabled = false;
		}

		internal static void SendHostPresent(IReadOnlyList<ulong> targets = null)
		{
			//IL_004c: 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)
			NetworkManager singleton = NetworkManager.Singleton;
			if (!((Object)(object)singleton == (Object)null) && singleton.IsServer && singleton.CustomMessagingManager != null)
			{
				FastBufferWriter val = default(FastBufferWriter);
				((FastBufferWriter)(ref val))..ctor(0, (Allocator)2, -1);
				if (targets == null)
				{
					singleton.CustomMessagingManager.SendNamedMessageToAll(HostPresentMessage, val, (NetworkDelivery)3);
				}
				else
				{
					singleton.CustomMessagingManager.SendNamedMessage(HostPresentMessage, targets, val, (NetworkDelivery)3);
				}
			}
		}

		private static void OnHostPresent(ulong senderId, FastBufferReader reader)
		{
			if (senderId == 0L)
			{
				Enabled = true;
				if (Plugin.Cfg.VerboseLogging.Value)
				{
					Plugin.Log.LogInfo((object)"Host has the mod — utility-slot feature enabled (client).");
				}
			}
		}
	}
}