Decompiled source of BossGate v1.0.2

BossGate.dll

Decompiled 36 minutes ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("BossGate")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("BossGate")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("dfa5103e-806f-4944-81a2-d3d88f5d02f2")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace BossGate;

[BepInPlugin("com.tyranidex.bossgate", "BossGate", "1.0.2")]
public class BossGatePlugin : BaseUnityPlugin
{
	[CompilerGenerated]
	private sealed class <DelayedLocalLoadedPing>d__17 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		private float <timeout>5__2;

		private float <t>5__3;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <DelayedLocalLoadedPing>d__17(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<timeout>5__2 = 10f;
				<t>5__3 = 0f;
				break;
			case 1:
				<>1__state = -1;
				break;
			}
			if ((Object)(object)Player.m_localPlayer == (Object)null && <t>5__3 < <timeout>5__2)
			{
				<t>5__3 += Time.unscaledDeltaTime;
				<>2__current = null;
				<>1__state = 1;
				return true;
			}
			if ((Object)(object)Player.m_localPlayer != (Object)null && (Object)(object)MessageHud.instance != (Object)null)
			{
				MessageHud.instance.ShowMessage((MessageType)1, "BossGate loaded", 0, (Sprite)null, false);
			}
			return false;
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	public const string ModGUID = "com.tyranidex.bossgate";

	public const string ModName = "BossGate";

	public const string ModVersion = "1.0.2";

	internal static BossGatePlugin Instance;

	internal static ManualLogSource Log;

	internal static Harmony Harmony;

	internal static ConfigFile Cfg;

	private static ConfigEntry<string> _toggleKey;

	private static ConfigEntry<string> _blockedMessage;

	private static ConfigEntry<bool> _alsoShowCenterMessage;

	private static ConfigEntry<bool> _blockUnknownBosses;

	private static ConfigEntry<bool> _blockQueenDoorWhenQueenDisabled;

	private KeyCode _hotKey = (KeyCode)288;

	private bool _uiVisible;

	private Rect _windowRect = new Rect(60f, 60f, 430f, 420f);

	private Vector2 _scroll;

	internal static string BlockedMessage => _blockedMessage.Value;

	internal static bool AlsoShowCenterMessage => _alsoShowCenterMessage.Value;

	internal static bool BlockUnknownBosses => _blockUnknownBosses.Value;

	internal static bool BlockQueenDoorWhenQueenDisabled => _blockQueenDoorWhenQueenDisabled.Value;

	private void Awake()
	{
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Expected O, but got Unknown
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fd: Expected O, but got Unknown
		Instance = this;
		Log = ((BaseUnityPlugin)this).Logger;
		try
		{
			Cfg = new ConfigFile(Path.Combine(Paths.ConfigPath, "bossgate.cfg"), true);
		}
		catch
		{
			Cfg = ((BaseUnityPlugin)this).Config;
		}
		_toggleKey = Cfg.Bind<string>("UI", "ToggleKey", "F7", "Key to toggle the admin UI window.");
		_blockedMessage = Cfg.Bind<string>("Messages", "BlockedMessage", "The boss is still deeply asleep.", "Message shown when a boss spawn is blocked. Supports {boss}.");
		_alsoShowCenterMessage = Cfg.Bind<bool>("Messages", "AlsoShowCenterMessage", true, "Also show as a center-screen message (in addition to chat).");
		_blockUnknownBosses = Cfg.Bind<bool>("Safety", "BlockUnknownBosses", true, "If the boss id cannot be resolved, block anyway (safer).");
		_blockQueenDoorWhenQueenDisabled = Cfg.Bind<bool>("Queen", "BlockQueenDoorWhenQueenDisabled", true, "Block Mistlands Queen door (dungeon_queen_door) until Queen is enabled.");
		ParseHotkey(_toggleKey.Value);
		Harmony = new Harmony("com.tyranidex.bossgate");
		Harmony.PatchAll(Assembly.GetExecutingAssembly());
		Log.LogInfo((object)"BossGate 1.0.2 loaded");
		((MonoBehaviour)this).StartCoroutine(DelayedLocalLoadedPing());
	}

	[IteratorStateMachine(typeof(<DelayedLocalLoadedPing>d__17))]
	private IEnumerator DelayedLocalLoadedPing()
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <DelayedLocalLoadedPing>d__17(0);
	}

	private void Update()
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		if (Input.GetKeyDown(_hotKey) && !((Object)(object)ZNet.instance == (Object)null) && ZRoutedRpc.instance != null)
		{
			_uiVisible = !_uiVisible;
		}
	}

	private void OnGUI()
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Expected O, but got Unknown
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		if (_uiVisible)
		{
			_windowRect = GUILayout.Window(((object)this).GetHashCode(), _windowRect, new WindowFunction(DrawWindow), "BossGate (Admin)", Array.Empty<GUILayoutOption>());
		}
	}

	private void DrawWindow(int id)
	{
		//IL_009b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_008e: Unknown result type (might be due to invalid IL or missing references)
		//IL_020a: Unknown result type (might be due to invalid IL or missing references)
		GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
		GUILayout.Label("Server-authoritative boss gating.", Array.Empty<GUILayoutOption>());
		GUILayout.Label("Default: ALL bosses disabled.", Array.Empty<GUILayoutOption>());
		GUILayout.Space(6f);
		GUILayout.Label(BossGateAuth.IsLocalAdminBestEffort() ? "Admin detected (best-effort)." : "Admin not detected (best-effort). Server will verify adminlist.txt.", Array.Empty<GUILayoutOption>());
		GUILayout.Space(6f);
		if ((Object)(object)ZoneSystem.instance == (Object)null)
		{
			GUILayout.Label("ZoneSystem not ready yet.", Array.Empty<GUILayoutOption>());
			GUILayout.EndVertical();
			GUI.DragWindow(new Rect(0f, 0f, 10000f, 25f));
			return;
		}
		_scroll = GUILayout.BeginScrollView(_scroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(280f) });
		for (int i = 0; i < BossGateWorld.Bosses.Count; i++)
		{
			BossGateWorld.BossDef bossDef = BossGateWorld.Bosses[i];
			bool flag = BossGateWorld.IsBossEnabled(bossDef.Id);
			string text = bossDef.DisplayName + "  [" + (flag ? "ENABLED" : "DISABLED") + "]";
			bool flag2 = GUILayout.Toggle(flag, text, Array.Empty<GUILayoutOption>());
			if (flag2 != flag)
			{
				BossGateNetwork.RequestSetBossEnabled(bossDef.Id, flag2);
			}
		}
		GUILayout.EndScrollView();
		GUILayout.Space(6f);
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		if (GUILayout.Button("Enable all", Array.Empty<GUILayoutOption>()))
		{
			for (int j = 0; j < BossGateWorld.Bosses.Count; j++)
			{
				BossGateNetwork.RequestSetBossEnabled(BossGateWorld.Bosses[j].Id, enabled: true);
			}
		}
		if (GUILayout.Button("Disable all", Array.Empty<GUILayoutOption>()))
		{
			for (int k = 0; k < BossGateWorld.Bosses.Count; k++)
			{
				BossGateNetwork.RequestSetBossEnabled(BossGateWorld.Bosses[k].Id, enabled: false);
			}
		}
		GUILayout.EndHorizontal();
		GUILayout.Space(6f);
		if (GUILayout.Button("Close", Array.Empty<GUILayoutOption>()))
		{
			_uiVisible = false;
		}
		GUILayout.EndVertical();
		GUI.DragWindow(new Rect(0f, 0f, 10000f, 25f));
	}

	private void ParseHotkey(string value)
	{
		//IL_0011: 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)
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			KeyCode hotKey = (KeyCode)Enum.Parse(typeof(KeyCode), value, ignoreCase: true);
			_hotKey = hotKey;
		}
		catch
		{
			_hotKey = (KeyCode)288;
			Log.LogWarning((object)("Invalid ToggleKey '" + value + "', falling back to F7."));
		}
	}
}
internal static class BossGateWorld
{
	internal sealed class BossDef
	{
		public string Id;

		public string DisplayName;

		public string BossPrefabName;

		public BossDef(string id, string displayName, string bossPrefabName)
		{
			Id = id;
			DisplayName = displayName;
			BossPrefabName = bossPrefabName;
		}
	}

	internal static readonly List<BossDef> Bosses = new List<BossDef>
	{
		new BossDef("eikthyr", "Eikthyr", "Eikthyr"),
		new BossDef("elder", "The Elder", "gd_king"),
		new BossDef("bonemass", "Bonemass", "Bonemass"),
		new BossDef("moder", "Moder", "Dragon"),
		new BossDef("yagluth", "Yagluth", "GoblinKing"),
		new BossDef("queen", "The Queen", "SeekerQueen"),
		new BossDef("fader", "Fader", "Fader")
	};

	internal static string GetBossKey(string bossId)
	{
		return ("bossgate_allow_" + bossId).ToLowerInvariant();
	}

	internal static bool IsBossEnabled(string bossId)
	{
		if ((Object)(object)ZoneSystem.instance == (Object)null)
		{
			return false;
		}
		return ZoneSystem.instance.GetGlobalKey(GetBossKey(bossId));
	}

	internal static void SetBossEnabledServer(string bossId, bool enabled)
	{
		if ((Object)(object)ZoneSystem.instance == (Object)null)
		{
			return;
		}
		string bossKey = GetBossKey(bossId);
		if (enabled)
		{
			ZoneSystem.instance.SetGlobalKey(bossKey);
			return;
		}
		try
		{
			MethodInfo method = typeof(ZoneSystem).GetMethod("RemoveGlobalKey", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(string) }, null);
			if (method != null)
			{
				method.Invoke(ZoneSystem.instance, new object[1] { bossKey });
				return;
			}
		}
		catch
		{
		}
		try
		{
			FieldInfo field = typeof(ZoneSystem).GetField("m_globalKeys", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			object obj2 = ((field != null) ? field.GetValue(ZoneSystem.instance) : null);
			if (obj2 == null)
			{
				return;
			}
			MethodInfo method2 = obj2.GetType().GetMethod("Contains", new Type[1] { typeof(string) });
			MethodInfo method3 = obj2.GetType().GetMethod("Remove", new Type[1] { typeof(string) });
			if (!(method2 != null) || !(method3 != null))
			{
				return;
			}
			object obj3 = method2.Invoke(obj2, new object[1] { bossKey });
			if (obj3 is bool && (bool)obj3)
			{
				method3.Invoke(obj2, new object[1] { bossKey });
				MethodInfo method4 = typeof(ZoneSystem).GetMethod("SendGlobalKeys", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (method4 != null)
				{
					method4.Invoke(ZoneSystem.instance, new object[0]);
				}
			}
		}
		catch
		{
		}
	}

	internal static string GetDisplayName(string bossId)
	{
		for (int i = 0; i < Bosses.Count; i++)
		{
			if (string.Equals(Bosses[i].Id, bossId, StringComparison.OrdinalIgnoreCase))
			{
				return Bosses[i].DisplayName;
			}
		}
		return bossId;
	}

	internal static bool IsKnownBossId(string bossId)
	{
		for (int i = 0; i < Bosses.Count; i++)
		{
			if (string.Equals(Bosses[i].Id, bossId, StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
		}
		return false;
	}
}
internal static class BossGateNetwork
{
	[HarmonyPatch(typeof(ZNet), "Awake")]
	private static class ZNet_Awake_RegisterRPC
	{
		private static void Postfix()
		{
			if (ZRoutedRpc.instance != null)
			{
				ZRoutedRpc.instance.Register<string, bool>("BossGate_SetBossEnabled", (Action<long, string, bool>)RPC_SetBossEnabled_Handler);
				BossGatePlugin.Log.LogInfo((object)"BossGate RPC registered");
			}
		}
	}

	private const string RPC_SetBossEnabled = "BossGate_SetBossEnabled";

	internal static void RequestSetBossEnabled(string bossId, bool enabled)
	{
		if ((Object)(object)ZNet.instance == (Object)null || ZRoutedRpc.instance == null)
		{
			return;
		}
		if (ZNet.instance.IsServer() && !ZNet.instance.IsDedicated())
		{
			BossGateWorld.SetBossEnabledServer(bossId, enabled);
			BossGatePlugin.Log.LogInfo((object)("Local host set " + bossId + " = " + enabled));
		}
		else if (ZRoutedRpc.instance != null)
		{
			long serverPeerIdBestEffort = BossGateNetUtil.GetServerPeerIdBestEffort();
			if (serverPeerIdBestEffort <= 0)
			{
				BossGatePlugin.Log.LogWarning((object)"Could not resolve server peer id; cannot send RPC.");
				return;
			}
			ZRoutedRpc.instance.InvokeRoutedRPC(serverPeerIdBestEffort, "BossGate_SetBossEnabled", new object[2] { bossId, enabled });
		}
	}

	private static void RPC_SetBossEnabled_Handler(long senderPeerId, string bossId, bool enabled)
	{
		if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer())
		{
			if (!BossGateWorld.IsKnownBossId(bossId))
			{
				BossGateMessaging.SendToPeer(senderPeerId, "Unknown boss id '" + bossId + "'.", forceCenter: false);
				return;
			}
			if (!BossGateAuth.IsSenderAdmin(senderPeerId))
			{
				BossGateMessaging.SendToPeer(senderPeerId, "You are not an admin.", forceCenter: false);
				return;
			}
			BossGateWorld.SetBossEnabledServer(bossId, enabled);
			string text = (enabled ? "ENABLED" : "DISABLED");
			BossGateMessaging.SendToPeer(senderPeerId, BossGateWorld.GetDisplayName(bossId) + " is now " + text + ".", forceCenter: false);
		}
	}
}
internal static class BossGateAuth
{
	internal static bool IsLocalAdminBestEffort()
	{
		try
		{
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				return false;
			}
			if (ZNet.instance.IsServer() && !ZNet.instance.IsDedicated())
			{
				return true;
			}
			MethodInfo[] methods = typeof(ZNet).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo in methods)
			{
				if (!(methodInfo == null) && !(methodInfo.ReturnType != typeof(bool)) && string.Equals(methodInfo.Name, "IsAdmin", StringComparison.OrdinalIgnoreCase) && methodInfo.GetParameters().Length == 0 && methodInfo.Invoke(ZNet.instance, new object[0]) is bool result)
				{
					return result;
				}
			}
		}
		catch
		{
		}
		return false;
	}

	internal static bool IsSenderAdmin(long senderPeerId)
	{
		try
		{
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
			{
				return false;
			}
			MethodInfo[] methods = typeof(ZNet).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo in methods)
			{
				if (!(methodInfo == null) && !(methodInfo.ReturnType != typeof(bool)) && string.Equals(methodInfo.Name, "IsAdmin", StringComparison.OrdinalIgnoreCase))
				{
					ParameterInfo[] parameters = methodInfo.GetParameters();
					if (parameters.Length == 1 && parameters[0].ParameterType == typeof(long) && methodInfo.Invoke(ZNet.instance, new object[1] { senderPeerId }) is bool result)
					{
						return result;
					}
				}
			}
			FieldInfo field = typeof(ZNet).GetField("m_adminList", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			object obj = ((field != null) ? field.GetValue(ZNet.instance) : null);
			if (obj != null)
			{
				string text = senderPeerId.ToString();
				MethodInfo method = obj.GetType().GetMethod("Contains", new Type[1] { typeof(string) });
				if (method != null)
				{
					object obj2 = method.Invoke(obj, new object[1] { text });
					if (obj2 is bool && (bool)obj2)
					{
						return true;
					}
				}
				string peerHostNameBestEffort = BossGateNetUtil.GetPeerHostNameBestEffort(senderPeerId);
				if (!string.IsNullOrEmpty(peerHostNameBestEffort) && method != null)
				{
					object obj3 = method.Invoke(obj, new object[1] { peerHostNameBestEffort });
					if (obj3 is bool && (bool)obj3)
					{
						return true;
					}
				}
			}
		}
		catch
		{
		}
		return false;
	}
}
internal static class BossGateNetUtil
{
	internal static long GetServerPeerIdBestEffort()
	{
		try
		{
			if (ZRoutedRpc.instance == null)
			{
				return 0L;
			}
			MethodInfo methodInfo = typeof(ZRoutedRpc).GetMethod("GetServerPeerID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? typeof(ZRoutedRpc).GetMethod("GetServerPeerId", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (methodInfo != null && methodInfo.ReturnType == typeof(long) && methodInfo.GetParameters().Length == 0 && methodInfo.Invoke(ZRoutedRpc.instance, new object[0]) is long result)
			{
				return result;
			}
			FieldInfo[] fields = typeof(ZRoutedRpc).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo in fields)
			{
				if (!(fieldInfo.FieldType != typeof(long)))
				{
					string text = (fieldInfo.Name ?? "").ToLowerInvariant();
					if (text.Contains("server") && text.Contains("peer") && fieldInfo.GetValue(ZRoutedRpc.instance) is long result2)
					{
						return result2;
					}
				}
			}
		}
		catch
		{
		}
		return 0L;
	}

	internal static string GetPeerHostNameBestEffort(long peerId)
	{
		try
		{
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				return "";
			}
			FieldInfo field = typeof(ZNet).GetField("m_peers", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (!(((field != null) ? field.GetValue(ZNet.instance) : null) is List<ZNetPeer> list))
			{
				return "";
			}
			for (int i = 0; i < list.Count; i++)
			{
				ZNetPeer val = list[i];
				if (val == null)
				{
					continue;
				}
				FieldInfo field2 = typeof(ZNetPeer).GetField("m_uid", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				object obj = ((field2 != null) ? field2.GetValue(val) : null);
				if (obj is long && (long)obj == peerId)
				{
					FieldInfo field3 = typeof(ZNetPeer).GetField("m_socket", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					object obj2 = ((field3 != null) ? field3.GetValue(val) : null);
					if (obj2 == null)
					{
						return "";
					}
					MethodInfo method = obj2.GetType().GetMethod("GetHostName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (method != null && method.ReturnType == typeof(string) && method.GetParameters().Length == 0)
					{
						return (method.Invoke(obj2, new object[0]) as string) ?? "";
					}
					return "";
				}
			}
		}
		catch
		{
		}
		return "";
	}
}
internal static class BossGateMessaging
{
	private static MethodInfo _cachedChatRpc;

	private static Type[] _cachedArgTypes;

	internal static void SendBlocked(long peerId, string bossId)
	{
		string displayName = BossGateWorld.GetDisplayName(bossId);
		string text = BossGatePlugin.BlockedMessage.Replace("{boss}", displayName);
		SendToPeer(peerId, text, BossGatePlugin.AlsoShowCenterMessage);
	}

	internal static void SendToPeer(long peerId, string text, bool forceCenter)
	{
		bool flag = TrySendChatMessage(peerId, text);
		if (forceCenter || !flag)
		{
			TrySendCenterMessage(peerId, text);
		}
	}

	private static bool TrySendCenterMessage(long peerId, string text)
	{
		try
		{
			if (ZRoutedRpc.instance == null)
			{
				return false;
			}
			ZRoutedRpc.instance.InvokeRoutedRPC(peerId, "ShowMessage", new object[2] { 2, text });
			return true;
		}
		catch
		{
			return false;
		}
	}

	private static bool TrySendChatMessage(long peerId, string text)
	{
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if (ZRoutedRpc.instance == null)
			{
				return false;
			}
			CacheChatSignatureIfNeeded();
			if (_cachedArgTypes == null)
			{
				return false;
			}
			Vector3 zero = Vector3.zero;
			int type = 2;
			string name = "Server";
			object[] array = BuildChatArgs(_cachedArgTypes, zero, type, name, text);
			if (array == null)
			{
				return false;
			}
			ZRoutedRpc.instance.InvokeRoutedRPC(peerId, "ChatMessage", array);
			return true;
		}
		catch
		{
			return false;
		}
	}

	private static void CacheChatSignatureIfNeeded()
	{
		if (_cachedArgTypes != null)
		{
			return;
		}
		try
		{
			MethodInfo method = typeof(Chat).GetMethod("RPC_ChatMessage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (method == null)
			{
				return;
			}
			ParameterInfo[] parameters = method.GetParameters();
			int num = 0;
			if (parameters.Length != 0 && parameters[0].ParameterType == typeof(long))
			{
				num = 1;
			}
			int num2 = parameters.Length - num;
			if (num2 > 0)
			{
				Type[] array = new Type[num2];
				for (int i = 0; i < num2; i++)
				{
					array[i] = parameters[num + i].ParameterType;
				}
				_cachedChatRpc = method;
				_cachedArgTypes = array;
			}
		}
		catch
		{
		}
	}

	private static object[] BuildChatArgs(Type[] argTypes, Vector3 pos, int type, string name, string text)
	{
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0184: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0225: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if (argTypes.Length == 4 && argTypes[0] == typeof(Vector3) && argTypes[1] == typeof(int) && argTypes[2] == typeof(string) && argTypes[3] == typeof(string))
			{
				return new object[4] { pos, type, name, text };
			}
			if (argTypes.Length == 5 && argTypes[0] == typeof(Vector3) && argTypes[1] == typeof(int) && argTypes[2] == typeof(string) && argTypes[3] == typeof(string) && argTypes[4] == typeof(string))
			{
				return new object[5] { pos, type, name, text, "" };
			}
			if (argTypes.Length == 4 && argTypes[0] == typeof(Vector3) && argTypes[1] == typeof(int) && argTypes[2].Name == "UserInfo" && argTypes[3] == typeof(string))
			{
				object obj = CreateServerUserInfo(argTypes[2], name);
				return new object[4] { pos, type, obj, text };
			}
			if (argTypes.Length == 5 && argTypes[0] == typeof(Vector3) && argTypes[1] == typeof(int) && argTypes[2].Name == "UserInfo" && argTypes[3] == typeof(string) && argTypes[4] == typeof(string))
			{
				object obj2 = CreateServerUserInfo(argTypes[2], name);
				return new object[5] { pos, type, obj2, text, "" };
			}
		}
		catch
		{
		}
		return null;
	}

	private static object CreateServerUserInfo(Type userInfoType, string name)
	{
		try
		{
			MethodInfo method = userInfoType.GetMethod("GetLocalUser", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			if (method != null)
			{
				object obj = method.Invoke(null, new object[0]);
				if (obj != null)
				{
					PropertyInfo property = userInfoType.GetProperty("Name", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (property != null && property.CanWrite)
					{
						property.SetValue(obj, name, null);
					}
					else
					{
						FieldInfo field = userInfoType.GetField("Name", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
						if (field != null)
						{
							field.SetValue(obj, name);
						}
					}
					return obj;
				}
			}
			return Activator.CreateInstance(userInfoType);
		}
		catch
		{
			return null;
		}
	}
}
internal static class BossGatePrefabUtil
{
	internal static string GetPrefabName(GameObject go)
	{
		if ((Object)(object)go == (Object)null)
		{
			return "";
		}
		string text = ((Object)go).name ?? "";
		if (text.EndsWith("(Clone)"))
		{
			text = text.Replace("(Clone)", "");
		}
		return text.Trim();
	}

	internal static bool HasParentNamed(Transform t, string prefabNameLower, int maxDepth)
	{
		if ((Object)(object)t == (Object)null)
		{
			return false;
		}
		string text = (prefabNameLower ?? "").ToLowerInvariant();
		int num = 0;
		Transform val = t;
		while ((Object)(object)val != (Object)null && num <= maxDepth)
		{
			if (GetPrefabName(((Component)val).gameObject).ToLowerInvariant() == text)
			{
				return true;
			}
			val = val.parent;
			num++;
		}
		return false;
	}
}
internal static class BossGateBossResolver
{
	internal static bool TryResolveBossIdFromOfferingBowl(OfferingBowl bowl, out string bossId)
	{
		bossId = "";
		GameObject val = TryGetBossPrefab(bowl);
		if ((Object)(object)val != (Object)null && TryMapBossPrefabName(BossGatePrefabUtil.GetPrefabName(val), out bossId))
		{
			return true;
		}
		if (TryMapOfferingBowlOwnerName(BossGatePrefabUtil.GetPrefabName(((Component)bowl).gameObject), out bossId))
		{
			return true;
		}
		return false;
	}

	private static GameObject TryGetBossPrefab(OfferingBowl bowl)
	{
		try
		{
			FieldInfo field = typeof(OfferingBowl).GetField("m_bossPrefab", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null)
			{
				object? value = field.GetValue(bowl);
				return (GameObject)((value is GameObject) ? value : null);
			}
			FieldInfo[] fields = typeof(OfferingBowl).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo in fields)
			{
				if (!(fieldInfo.FieldType != typeof(GameObject)) && (fieldInfo.Name ?? "").ToLowerInvariant().Contains("boss"))
				{
					object? value2 = fieldInfo.GetValue(bowl);
					GameObject val = (GameObject)((value2 is GameObject) ? value2 : null);
					if ((Object)(object)val != (Object)null)
					{
						return val;
					}
				}
			}
		}
		catch
		{
		}
		return null;
	}

	private static string Normalize(string s)
	{
		if (s == null)
		{
			return "";
		}
		return s.Trim().ToLowerInvariant().Replace("_", "")
			.Replace("-", "");
	}

	private static bool TryMapOfferingBowlOwnerName(string altarPrefabName, out string bossId)
	{
		bossId = "";
		string text = Normalize(altarPrefabName ?? "");
		if (text.Contains("bossstoneeikthyr"))
		{
			bossId = "eikthyr";
			return true;
		}
		if (text.Contains("bossstonetheelder") || text.Contains("bossstoneelder"))
		{
			bossId = "elder";
			return true;
		}
		if (text.Contains("bossstonebonemass"))
		{
			bossId = "bonemass";
			return true;
		}
		if (text.Contains("bossstonedragonqueen"))
		{
			bossId = "moder";
			return true;
		}
		if (text.Contains("bossstoneyagluth"))
		{
			bossId = "yagluth";
			return true;
		}
		if (text.Contains("bossstonethequeen") || text.Contains("bossstonequeen"))
		{
			bossId = "queen";
			return true;
		}
		if (text.Contains("bossstonefader"))
		{
			bossId = "fader";
			return true;
		}
		if (text.Contains("eikthyr"))
		{
			bossId = "eikthyr";
			return true;
		}
		if (text.Contains("gdking") || text.Contains("theelder") || text.Contains("elder"))
		{
			bossId = "elder";
			return true;
		}
		if (text.Contains("bonemass"))
		{
			bossId = "bonemass";
			return true;
		}
		if (text.Contains("dragonqueen"))
		{
			bossId = "moder";
			return true;
		}
		if (text.Contains("goblinking"))
		{
			bossId = "yagluth";
			return true;
		}
		if (text.Contains("seekerqueen"))
		{
			bossId = "queen";
			return true;
		}
		if (text.Contains("fader"))
		{
			bossId = "fader";
			return true;
		}
		return false;
	}

	private static bool TryMapBossPrefabName(string bossPrefabName, out string bossId)
	{
		bossId = "";
		string text = Normalize(bossPrefabName ?? "");
		if (text == Normalize("Eikthyr") || text.Contains("eikthyr"))
		{
			bossId = "eikthyr";
			return true;
		}
		if (text == Normalize("gd_king") || text.Contains("gdking"))
		{
			bossId = "elder";
			return true;
		}
		if (text == Normalize("Bonemass") || text.Contains("bonemass"))
		{
			bossId = "bonemass";
			return true;
		}
		if (text == Normalize("Dragon") || text.Contains("dragon"))
		{
			bossId = "moder";
			return true;
		}
		if (text == Normalize("GoblinKing") || text.Contains("goblinking"))
		{
			bossId = "yagluth";
			return true;
		}
		if (text == Normalize("SeekerQueen") || text.Contains("seekerqueen"))
		{
			bossId = "queen";
			return true;
		}
		if (text == Normalize("Fader") || text.Contains("fader"))
		{
			bossId = "fader";
			return true;
		}
		return false;
	}
}
internal static class BossGateGateLogic
{
	internal static bool ServerAllowOrBlockOffering(OfferingBowl bowl, long senderPeerId)
	{
		if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
		{
			return true;
		}
		if (!BossGateBossResolver.TryResolveBossIdFromOfferingBowl(bowl, out var bossId))
		{
			if (BossGatePlugin.BlockUnknownBosses)
			{
				BossGateMessaging.SendToPeer(senderPeerId, BossGatePlugin.BlockedMessage, BossGatePlugin.AlsoShowCenterMessage);
				return false;
			}
			return true;
		}
		if (BossGateWorld.IsBossEnabled(bossId))
		{
			return true;
		}
		BossGateMessaging.SendBlocked(senderPeerId, bossId);
		return false;
	}

	internal static bool ShouldBlockQueenDoor(Door door)
	{
		if (!BossGatePlugin.BlockQueenDoorWhenQueenDisabled)
		{
			return false;
		}
		if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
		{
			return false;
		}
		if (BossGateWorld.IsBossEnabled("queen"))
		{
			return false;
		}
		Transform val = (((Object)(object)door != (Object)null) ? ((Component)door).transform : null);
		if (BossGatePrefabUtil.HasParentNamed(val, "dungeon_queen_door", 10))
		{
			return true;
		}
		if ((Object)(object)val != (Object)null && (Object)(object)val.root != (Object)null && BossGatePrefabUtil.GetPrefabName(((Component)val.root).gameObject).ToLowerInvariant() == "dungeon_queen_door")
		{
			return true;
		}
		return false;
	}
}
[HarmonyPatch(typeof(OfferingBowl), "RPC_BossSpawnInitiated")]
internal static class BossGate_Patch_OfferingBowl_BossSpawnInitiated
{
	private static bool Prefix(OfferingBowl __instance, object[] __args)
	{
		long senderPeerId = 0L;
		if (__args != null && __args.Length != 0 && __args[0] is long)
		{
			senderPeerId = (long)__args[0];
		}
		return BossGateGateLogic.ServerAllowOrBlockOffering(__instance, senderPeerId);
	}
}
[HarmonyPatch(typeof(OfferingBowl), "RPC_RemoveBossSpawnInventoryItems")]
internal static class BossGate_Patch_OfferingBowl_RemoveItems
{
	private static bool Prefix(OfferingBowl __instance, object[] __args)
	{
		long senderPeerId = 0L;
		if (__args != null && __args.Length != 0 && __args[0] is long)
		{
			senderPeerId = (long)__args[0];
		}
		return BossGateGateLogic.ServerAllowOrBlockOffering(__instance, senderPeerId);
	}
}
[HarmonyPatch(typeof(OfferingBowl), "RPC_SpawnBoss")]
internal static class BossGate_Patch_OfferingBowl_SpawnBoss
{
	private static bool Prefix(OfferingBowl __instance, object[] __args)
	{
		long senderPeerId = 0L;
		if (__args != null && __args.Length != 0 && __args[0] is long)
		{
			senderPeerId = (long)__args[0];
		}
		return BossGateGateLogic.ServerAllowOrBlockOffering(__instance, senderPeerId);
	}
}
[HarmonyPatch(typeof(Door), "RPC_UseDoor")]
internal static class BossGate_Patch_Door_UseDoor
{
	private static bool Prefix(Door __instance, object[] __args)
	{
		long peerId = 0L;
		if (__args != null && __args.Length != 0 && __args[0] is long)
		{
			peerId = (long)__args[0];
		}
		if (BossGateGateLogic.ShouldBlockQueenDoor(__instance))
		{
			BossGateMessaging.SendBlocked(peerId, "queen");
			return false;
		}
		return true;
	}
}