Decompiled source of SwampKeyPersist v1.1.0

SwampKeyPersist.dll

Decompiled a day ago
using System;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace BakaSwampKeyPersist;

[BepInPlugin("baka.SwampKeyPersist", "Swamp Key Persist", "1.1.0")]
public class SwampKeyPersistPlugin : BaseUnityPlugin
{
	public const string GUID = "baka.SwampKeyPersist";

	public const string NAME = "Swamp Key Persist";

	public const string VERSION = "1.1.0";

	internal static ManualLogSource Log;

	internal static ConfigEntry<bool> Enabled;

	internal static ConfigEntry<bool> ProtectAllKeyedDoors;

	internal static ConfigEntry<string> CryptDoorNameContains;

	private Harmony _harmony;

	private void Awake()
	{
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_007f: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch. When true, the door key (Swamp/Crypt Key) is never consumed when opening a Sunken Crypt gate. Only takes effect on servers that also run this mod (anti-cheat).");
		ProtectAllKeyedDoors = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ProtectAllKeyedDoors", false, "When true, protect the key of ANY keyed door from being consumed, not just Sunken Crypt gates.");
		CryptDoorNameContains = ((BaseUnityPlugin)this).Config.Bind<string>("General", "CryptDoorNameContains", "sunken_crypt_gate", "Comma-separated substrings. A door whose GameObject name contains any of these is treated as a crypt gate whose key must persist.");
		_harmony = new Harmony("baka.SwampKeyPersist");
		_harmony.PatchAll();
		Log.LogInfo((object)"Swamp Key Persist v1.1.0 loaded - keys persist on sanctioning servers/host (server-gated anti-cheat).");
	}

	private void OnDestroy()
	{
		if (_harmony != null)
		{
			_harmony.UnpatchSelf();
		}
	}
}
internal static class ServerSanction
{
	internal const string HELLO_RPC = "SwampKeyPersist_ServerHello";

	internal const int PROTO = 1;

	internal static bool ServerHasMod;

	internal static bool Allowed()
	{
		ZNet instance = ZNet.instance;
		if ((Object)(object)instance == (Object)null)
		{
			return false;
		}
		if (instance.IsServer())
		{
			return true;
		}
		return ServerHasMod;
	}
}
[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
internal static class ZNet_OnNewConnection_Patch
{
	private static void Postfix(ZNet __instance, ZNetPeer peer)
	{
		if (peer == null || peer.m_rpc == null)
		{
			return;
		}
		try
		{
			peer.m_rpc.Register<int>("SwampKeyPersist_ServerHello", (Action<ZRpc, int>)RPC_ServerHello);
			if ((Object)(object)__instance != (Object)null && __instance.IsServer())
			{
				peer.m_rpc.Invoke("SwampKeyPersist_ServerHello", new object[1] { 1 });
			}
			else
			{
				ServerSanction.ServerHasMod = false;
			}
		}
		catch (Exception ex)
		{
			if (SwampKeyPersistPlugin.Log != null)
			{
				SwampKeyPersistPlugin.Log.LogWarning((object)("SwampKeyPersist handshake setup failed: " + ex.Message));
			}
		}
	}

	private static void RPC_ServerHello(ZRpc rpc, int proto)
	{
		ServerSanction.ServerHasMod = true;
		if (SwampKeyPersistPlugin.Log != null)
		{
			SwampKeyPersistPlugin.Log.LogInfo((object)("Server sanctions SwampKeyPersist (proto " + proto + ") - key protection ACTIVE on this server."));
		}
	}
}
[HarmonyPatch(typeof(ZNet), "Shutdown", new Type[] { typeof(bool) })]
internal static class ZNet_Shutdown_Patch
{
	private static void Postfix()
	{
		ServerSanction.ServerHasMod = false;
	}
}
[HarmonyPatch(typeof(Door), "Open")]
internal static class Door_Open_Guard
{
	internal static bool Active;

	internal static string ProtectedKeyName;

	[HarmonyPriority(800)]
	private static void Prefix(Door __instance)
	{
		Active = false;
		ProtectedKeyName = null;
		if ((Object)(object)__instance == (Object)null || SwampKeyPersistPlugin.Enabled == null || !SwampKeyPersistPlugin.Enabled.Value || !ServerSanction.Allowed())
		{
			return;
		}
		ItemDrop keyItem = __instance.m_keyItem;
		if ((Object)(object)keyItem == (Object)null)
		{
			return;
		}
		bool flag = false;
		try
		{
			string text = (((Object)(object)((Component)__instance).gameObject != (Object)null) ? ((Object)((Component)__instance).gameObject).name : "");
			string value = SwampKeyPersistPlugin.CryptDoorNameContains.Value;
			if (!string.IsNullOrEmpty(value) && !string.IsNullOrEmpty(text))
			{
				string[] array = value.Split(new char[1] { ',' });
				foreach (string text2 in array)
				{
					string text3 = text2.Trim();
					if (text3.Length > 0 && text.IndexOf(text3, StringComparison.OrdinalIgnoreCase) >= 0)
					{
						flag = true;
						break;
					}
				}
			}
		}
		catch
		{
		}
		if (!flag && !SwampKeyPersistPlugin.ProtectAllKeyedDoors.Value)
		{
			return;
		}
		Active = true;
		try
		{
			if (keyItem.m_itemData != null && keyItem.m_itemData.m_shared != null)
			{
				ProtectedKeyName = keyItem.m_itemData.m_shared.m_name;
			}
		}
		catch
		{
			ProtectedKeyName = null;
		}
	}

	private static void Finalizer()
	{
		Active = false;
		ProtectedKeyName = null;
	}

	internal static bool ShouldProtect(ItemData item)
	{
		if (!Active || item == null || item.m_shared == null)
		{
			return false;
		}
		if (string.IsNullOrEmpty(ProtectedKeyName))
		{
			return true;
		}
		return item.m_shared.m_name == ProtectedKeyName;
	}
}
[HarmonyPatch(typeof(Inventory), "RemoveOneItem", new Type[] { typeof(ItemData) })]
internal static class Inventory_RemoveOneItem_Guard
{
	private static bool Prefix(ItemData item, ref bool __result)
	{
		if (Door_Open_Guard.ShouldProtect(item))
		{
			__result = true;
			if (SwampKeyPersistPlugin.Log != null)
			{
				SwampKeyPersistPlugin.Log.LogInfo((object)("Preserved door key '" + item.m_shared.m_name + "' (blocked consume on crypt-gate open)."));
			}
			return false;
		}
		return true;
	}
}
[HarmonyPatch(typeof(Inventory), "RemoveItem", new Type[] { typeof(ItemData) })]
internal static class Inventory_RemoveItem_Guard
{
	private static bool Prefix(ItemData item, ref bool __result)
	{
		if (Door_Open_Guard.ShouldProtect(item))
		{
			__result = true;
			return false;
		}
		return true;
	}
}
[HarmonyPatch(typeof(Inventory), "RemoveItem", new Type[]
{
	typeof(ItemData),
	typeof(int)
})]
internal static class Inventory_RemoveItemAmount_Guard
{
	private static bool Prefix(ItemData item, ref bool __result)
	{
		if (Door_Open_Guard.ShouldProtect(item))
		{
			__result = true;
			return false;
		}
		return true;
	}
}