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;
}
}