Decompiled source of MultiplayerPVP v1.0.6

MultiplayerPVP.IL2CPP.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using DooDesch.FullHouse;
using HarmonyLib;
using Il2Cpp;
using Il2CppFishNet;
using Il2CppFishNet.Managing;
using Il2CppFishNet.Object;
using Il2CppFishySteamworks;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppScheduleOne;
using Il2CppScheduleOne.Cartel;
using Il2CppScheduleOne.Combat;
using Il2CppScheduleOne.Core.Items.Framework;
using Il2CppScheduleOne.DevUtilities;
using Il2CppScheduleOne.Doors;
using Il2CppScheduleOne.Economy;
using Il2CppScheduleOne.Equipping;
using Il2CppScheduleOne.FX;
using Il2CppScheduleOne.GameTime;
using Il2CppScheduleOne.ItemFramework;
using Il2CppScheduleOne.Law;
using Il2CppScheduleOne.Map;
using Il2CppScheduleOne.Money;
using Il2CppScheduleOne.NPCs;
using Il2CppScheduleOne.NPCs.Behaviour;
using Il2CppScheduleOne.Networking;
using Il2CppScheduleOne.PlayerScripts;
using Il2CppScheduleOne.PlayerScripts.Health;
using Il2CppScheduleOne.Police;
using Il2CppScheduleOne.Product;
using Il2CppScheduleOne.Product.Packaging;
using Il2CppScheduleOne.Storage;
using Il2CppScheduleOne.UI;
using Il2CppScheduleOne.UI.Multiplayer;
using Il2CppScheduleOne.Vision;
using Il2CppSteamworks;
using Il2CppSystem.Collections.Generic;
using Il2CppTMPro;
using MelonLoader;
using MelonLoader.Preferences;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using MultiplayerPVP;
using MultiplayerPVP.Addons;
using MultiplayerPVP.Compat;
using MultiplayerPVP.Config;
using MultiplayerPVP.Core;
using MultiplayerPVP.Modes;
using MultiplayerPVP.Net;
using MultiplayerPVP.UI;
using SteamNetworkLib;
using SteamNetworkLib.Events;
using SteamNetworkLib.Models;
using SteamNetworkLib.Sync;
using UnityEngine;
using UnityEngine.AI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("MultiplayerPVP")]
[assembly: AssemblyDescription("Schedule I MelonLoader Mod")]
[assembly: AssemblyCompany("Virtunerd")]
[assembly: AssemblyProduct("MultiplayerPVP")]
[assembly: AssemblyCopyright("Copyright (c) Virtunerd 2026")]
[assembly: ComVisible(false)]
[assembly: Guid("f83b02a6-396b-4b34-b8b7-3d0117d8d960")]
[assembly: MelonAdditionalDependencies(new string[] { "SteamNetworkLib" })]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: MelonInfo(typeof(MultiplayerPVPMod), "MultiplayerPVP", "1.0.6", "Virtunerd", null)]
[assembly: MelonGame(null, "Schedule I")]
[assembly: AssemblyFileVersion("1.0.6")]
[assembly: AssemblyInformationalVersion("1.0.6")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.6.0")]
[module: UnverifiableCode]
[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 DooDesch.FullHouse
{
	internal static class Lobbies
	{
		internal const int DefaultCapacity = 32;

		private const int HardMax = 250;

		private const int SafeMax = 32;

		private const string GuardName = "___DooDesch_FullHouse___";

		private static bool _installed;

		private static MelonPreferences_Entry<int> _capEntry;

		private static int _hostCap;

		internal static int Capacity
		{
			get
			{
				int num = ((_capEntry != null) ? _capEntry.Value : 32);
				if (num < 2)
				{
					num = 2;
				}
				if (num > 250)
				{
					num = 250;
				}
				return num;
			}
		}

		internal static int EffectiveCap => Math.Min(250, Math.Max(Capacity, _hostCap));

		internal static ulong CurrentLobbyId
		{
			get
			{
				try
				{
					SteamLobbyService val = Service();
					return (val != null) ? val._lobbyID : 0;
				}
				catch
				{
					return 0uL;
				}
			}
		}

		internal static int SeatCount
		{
			get
			{
				try
				{
					SteamLobbyService val = Service();
					return ((Il2CppArrayBase<CSteamID>)(object)((val != null) ? val._players : null))?.Length ?? 0;
				}
				catch
				{
					return 0;
				}
			}
		}

		internal static void Install()
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Expected O, but got Unknown
			if (_installed)
			{
				return;
			}
			_installed = true;
			try
			{
				if ((Object)(object)GameObject.Find("___DooDesch_FullHouse___") != (Object)null)
				{
					MelonLogger.Msg("[FullHouse] another copy is already active - standing down.");
					return;
				}
				GameObject val = new GameObject("___DooDesch_FullHouse___");
				Object.DontDestroyOnLoad((Object)(object)val);
				((Object)val).hideFlags = (HideFlags)61;
			}
			catch
			{
			}
			try
			{
				MelonPreferences_Category val2 = MelonPreferences.CreateCategory("FullHouse", "FullHouse");
				_capEntry = val2.CreateEntry<int>("Capacity", 32, "Max lobby players", "Maximum co-op players FullHouse seats (2-250). Values above 32 are unsupported and may destabilise the game.", false, false, (ValueValidator)null, (string)null);
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[FullHouse] preference registration failed: " + ex.Message);
			}
			if (Capacity > 32)
			{
				MelonLogger.Warning($"[FullHouse] capacity {Capacity} exceeds the tested maximum of {32} - expect instability.");
			}
			try
			{
				Harmony h = new Harmony("com.doodesch.fullhouse");
				Patch(h, typeof(SteamLobbyService), "Initialize", null, "Service_Initialize_Postfix");
				Patch(h, typeof(SteamLobbyService), "UpdateLobbyMembers", "Service_UpdateLobbyMembers_Prefix");
				Patch(h, typeof(SteamLobbyService), "CreateLobby", "Service_CreateLobby_Prefix");
				Patch(h, typeof(SteamLobbyService), "OnLobbyCreated", null, "Service_OnLobbyCreated_Postfix");
				Patch(h, typeof(SteamLobbyService), "OnLobbyEntered", null, "Service_OnLobbyEntered_Postfix");
				Patch(h, typeof(SteamLobbyService), "OpenInviteUI", "Service_OpenInviteUI_Prefix");
				Patch(h, typeof(SteamLobbyService), "LeaveLobby", null, "Service_LeaveLobby_Postfix");
				Patch(h, typeof(LobbyInterface), "Start", null, "LobbyInterface_Start_Postfix");
				Patch(h, typeof(LobbyInterface), "UpdateUI", null, "LobbyInterface_UpdateUI_Postfix");
				Patch(h, typeof(LobbyInterface), "UpdateButtons", null, "LobbyInterface_UpdateButtons_Postfix");
				MelonLogger.Msg($"[FullHouse] active - lobby cap raised to {Capacity}.");
			}
			catch (Exception ex2)
			{
				MelonLogger.Error("[FullHouse] patch install failed: " + ex2);
			}
		}

		private static void Patch(Harmony h, Type type, string method, string prefix = null, string postfix = null)
		{
			MethodInfo methodInfo = AccessTools.Method(type, method, (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				MelonLogger.Warning($"[FullHouse] {type.Name}.{method} not found - skipped.");
			}
			else
			{
				h.Patch((MethodBase)methodInfo, Hook(prefix), Hook(postfix), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}

		private static HarmonyMethod Hook(string name)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			return (name == null) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(Lobbies).GetMethod(name, AccessTools.all));
		}

		private static SteamLobbyService Service()
		{
			try
			{
				Lobby instance = Singleton<Lobby>.Instance;
				ILobbyService val = ((instance != null) ? instance._lobbyService : null);
				if (val == null)
				{
					return null;
				}
				return ((Il2CppObjectBase)val).TryCast<SteamLobbyService>();
			}
			catch
			{
				return null;
			}
		}

		private static void EnsurePlayers(SteamLobbyService svc, int target)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (svc == null || target < 2)
				{
					return;
				}
				Il2CppStructArray<CSteamID> players = svc._players;
				int num = ((Il2CppArrayBase<CSteamID>)(object)players)?.Length ?? 0;
				if (num < target)
				{
					Il2CppStructArray<CSteamID> val = new Il2CppStructArray<CSteamID>((long)target);
					for (int i = 0; i < num; i++)
					{
						((Il2CppArrayBase<CSteamID>)(object)val)[i] = ((Il2CppArrayBase<CSteamID>)(object)players)[i];
					}
					svc._players = val;
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[FullHouse] resizing the lobby seat array failed: " + ex.Message);
			}
		}

		private static void Service_Initialize_Postfix(SteamLobbyService __instance)
		{
			EnsurePlayers(__instance, EffectiveCap);
			RaiseTransportCap();
		}

		private static void RaiseTransportCap()
		{
			try
			{
				FishySteamworks val = Object.FindObjectOfType<FishySteamworks>();
				if (!((Object)(object)val == (Object)null))
				{
					int effectiveCap = EffectiveCap;
					ushort maximumClients = val._maximumClients;
					if (maximumClients < effectiveCap)
					{
						val._maximumClients = (ushort)effectiveCap;
						MelonLogger.Msg($"[FullHouse] transport client limit {maximumClients} -> {effectiveCap}.");
					}
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[FullHouse] raising the transport client limit failed: " + ex.Message);
			}
		}

		private static void Service_UpdateLobbyMembers_Prefix(SteamLobbyService __instance)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				int val = 0;
				try
				{
					ulong num = ((__instance != null) ? __instance._lobbyID : 0);
					if (num != 0)
					{
						val = SteamMatchmaking.GetNumLobbyMembers(new CSteamID(num));
					}
				}
				catch
				{
				}
				EnsurePlayers(__instance, Math.Max(EffectiveCap, val));
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[FullHouse] seat guard failed: " + ex.Message);
			}
		}

		private static void Service_CreateLobby_Prefix(ref int maxPlayers)
		{
			int effectiveCap = EffectiveCap;
			if (maxPlayers < effectiveCap)
			{
				maxPlayers = effectiveCap;
			}
		}

		private static void Service_OnLobbyCreated_Postfix(LobbyCreated_t result)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Invalid comparison between Unknown and I4
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((int)result.m_eResult == 1)
				{
					RaiseTransportCap();
					CSteamID val = (CSteamID)result.m_ulSteamIDLobby;
					int effectiveCap = EffectiveCap;
					if (SteamMatchmaking.GetLobbyMemberLimit(val) < effectiveCap)
					{
						SteamMatchmaking.SetLobbyMemberLimit(val, effectiveCap);
					}
					int lobbyMemberLimit = SteamMatchmaking.GetLobbyMemberLimit(val);
					if (lobbyMemberLimit < effectiveCap)
					{
						MelonLogger.Warning($"[FullHouse] Steam kept the lobby member limit at {lobbyMemberLimit} (requested {effectiveCap}); advertising {lobbyMemberLimit}.");
					}
					SteamMatchmaking.SetLobbyData(val, "max_players", lobbyMemberLimit.ToString());
					SteamMatchmaking.SetLobbyData(val, "num_slots", lobbyMemberLimit.ToString());
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[FullHouse] OnLobbyCreated failed: " + ex.Message);
			}
		}

		private static void Service_OnLobbyEntered_Postfix(SteamLobbyService __instance, LobbyEnter_t result)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (__instance == null || __instance._lobbyID == 0)
				{
					return;
				}
				CSteamID val = (CSteamID)result.m_ulSteamIDLobby;
				int result2 = 0;
				int.TryParse(SteamMatchmaking.GetLobbyData(val, "max_players"), out result2);
				int lobbyMemberLimit = SteamMatchmaking.GetLobbyMemberLimit(val);
				if (lobbyMemberLimit > 0 && result2 > lobbyMemberLimit)
				{
					result2 = lobbyMemberLimit;
				}
				if (result2 > _hostCap)
				{
					if (result2 > 32)
					{
						MelonLogger.Warning($"[FullHouse] this lobby seats {result2}, past the tested maximum of {32} - expect instability.");
					}
					_hostCap = result2;
					int effectiveCap = EffectiveCap;
					EnsurePlayers(__instance, effectiveCap);
					EnsureSlots(Singleton<LobbyInterface>.Instance, effectiveCap);
					MelonLogger.Msg($"[FullHouse] adopted host lobby cap {effectiveCap}.");
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[FullHouse] host-cap sync failed: " + ex.Message);
			}
		}

		private static void Service_LeaveLobby_Postfix()
		{
			if (_hostCap != 0)
			{
				_hostCap = 0;
				MelonLogger.Msg($"[FullHouse] left the lobby - back to the local cap of {Capacity}.");
			}
		}

		private static bool Service_OpenInviteUI_Prefix(SteamLobbyService __instance)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: 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)
			try
			{
				if (__instance == null)
				{
					return true;
				}
				if (__instance._lobbyID == 0)
				{
					__instance.CreateLobby(EffectiveCap);
					return false;
				}
				CSteamID val = default(CSteamID);
				((CSteamID)(ref val))..ctor(__instance._lobbyID);
				int num = EffectiveCap;
				int lobbyMemberLimit = SteamMatchmaking.GetLobbyMemberLimit(val);
				if (lobbyMemberLimit > 0 && lobbyMemberLimit < num)
				{
					num = lobbyMemberLimit;
				}
				if (SteamMatchmaking.GetNumLobbyMembers(val) >= num)
				{
					MelonLogger.Warning($"[FullHouse] lobby already at max capacity ({num}).");
					return false;
				}
				SteamFriends.ActivateGameOverlayInviteDialog(val);
				return false;
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[FullHouse] invite gate failed, falling back to vanilla: " + ex.Message);
				return true;
			}
		}

		private static void LobbyInterface_Start_Postfix(LobbyInterface __instance)
		{
			try
			{
				MelonCoroutines.Start(BuildUi(__instance));
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[FullHouse] UI coroutine start failed: " + ex.Message);
			}
		}

		private static void LobbyInterface_UpdateUI_Postfix(LobbyInterface __instance)
		{
			try
			{
				Lobby instance = Singleton<Lobby>.Instance;
				int num = (((Object)(object)instance != (Object)null) ? instance.PlayerCount : 0);
				if ((Object)(object)((__instance != null) ? __instance.LobbyTitle : null) != (Object)null)
				{
					((TMP_Text)__instance.LobbyTitle).text = "Lobby (" + num + "/" + EffectiveCap + ")";
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[FullHouse] title sync failed: " + ex.Message);
			}
		}

		[HarmonyPriority(600)]
		private static void LobbyInterface_UpdateButtons_Postfix(LobbyInterface __instance)
		{
			try
			{
				Lobby instance = Singleton<Lobby>.Instance;
				if (!((Object)(object)instance == (Object)null) && !((Object)(object)((__instance != null) ? __instance.InviteButton : null) == (Object)null))
				{
					((Component)__instance.InviteButton).gameObject.SetActive(instance.IsHost && instance.PlayerCount < EffectiveCap);
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[FullHouse] invite button sync failed: " + ex.Message);
			}
		}

		private static IEnumerator BuildUi(LobbyInterface ui)
		{
			while ((Object)(object)Singleton<Lobby>.Instance == (Object)null)
			{
				yield return null;
			}
			bool steamReady = true;
			try
			{
				steamReady = SteamManager.Initialized;
			}
			catch
			{
			}
			if (steamReady)
			{
				EnsurePlayers(Service(), EffectiveCap);
				EnsureSlots(ui, EffectiveCap);
			}
		}

		private static void EnsureSlots(LobbyInterface ui, int target)
		{
			if ((Object)(object)ui == (Object)null)
			{
				return;
			}
			try
			{
				Il2CppReferenceArray<RectTransform> playerSlots = ui.PlayerSlots;
				if (playerSlots == null || ((Il2CppArrayBase<RectTransform>)(object)playerSlots).Length == 0)
				{
					MelonLogger.Warning("[FullHouse] lobby PlayerSlots not found.");
					return;
				}
				int length = ((Il2CppArrayBase<RectTransform>)(object)playerSlots).Length;
				if (length >= target)
				{
					RefreshPlayers(ui);
					return;
				}
				RectTransform val = ((Il2CppArrayBase<RectTransform>)(object)playerSlots)[length - 1];
				Transform parent = ((Transform)val).parent;
				RectTransform[] array = (RectTransform[])(object)new RectTransform[target];
				for (int i = 0; i < length; i++)
				{
					array[i] = ((Il2CppArrayBase<RectTransform>)(object)playerSlots)[i];
				}
				for (int j = length; j < target; j++)
				{
					GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, parent, false);
					((Object)val2).name = ((Object)((Component)val).gameObject).name + " (" + j + ")";
					array[j] = val2.GetComponent<RectTransform>();
				}
				ui.PlayerSlots = Il2CppReferenceArray<RectTransform>.op_Implicit(array);
				RefreshPlayers(ui);
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[FullHouse] building lobby UI failed: " + ex.Message);
			}
		}

		private static void RefreshPlayers(LobbyInterface ui)
		{
			try
			{
				ui.UpdatePlayers();
			}
			catch
			{
			}
		}
	}
}
namespace MultiplayerPVP
{
	internal static class ImguiCompat
	{
		private static GUIStyle _style;

		internal static void DrawTexture(Rect position, Texture2D image)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			Blit(position, image);
		}

		internal static void DrawTexture(Rect position, Texture2D image, ScaleMode scaleMode)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			Blit(Fit(position, image, scaleMode), image);
		}

		private static Rect Fit(Rect position, Texture2D image, ScaleMode scaleMode)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Invalid comparison between Unknown and I4
			//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_00cb: 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_0054: Invalid comparison between Unknown and I4
			//IL_004d: 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)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)image == (Object)null || (int)scaleMode == 0)
			{
				return position;
			}
			float num = ((Texture)image).width;
			float num2 = ((Texture)image).height;
			if (num <= 0f || num2 <= 0f)
			{
				return position;
			}
			float num3 = (((int)scaleMode == 2) ? Mathf.Min(((Rect)(ref position)).width / num, ((Rect)(ref position)).height / num2) : Mathf.Max(((Rect)(ref position)).width / num, ((Rect)(ref position)).height / num2));
			float num4 = num * num3;
			float num5 = num2 * num3;
			return new Rect(((Rect)(ref position)).x + (((Rect)(ref position)).width - num4) * 0.5f, ((Rect)(ref position)).y + (((Rect)(ref position)).height - num5) * 0.5f, num4, num5);
		}

		private static void Blit(Rect position, Texture2D image)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Invalid comparison between Unknown and I4
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: 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_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			if ((Object)(object)image == (Object)null)
			{
				return;
			}
			Event current = Event.current;
			if (current != null && (int)current.type == 7)
			{
				if (_style == null)
				{
					_style = new GUIStyle();
				}
				_style.normal.background = image;
				Color backgroundColor = GUI.backgroundColor;
				GUI.backgroundColor = Color.white;
				_style.Draw(position, false, false, false, false);
				GUI.backgroundColor = backgroundColor;
			}
		}
	}
	public class MultiplayerPVPMod : MelonMod
	{
		private MatchController _controller;

		private PvpHud _hud;

		private PvpNet _net;

		internal static MultiplayerPVPMod Instance { get; private set; }

		internal MatchController Controller => _controller;

		internal PvpNet Net => _net;

		public override void OnInitializeMelon()
		{
			Instance = this;
			Lobbies.Install();
			PvpConfig.Load();
			_net = new PvpNet();
			_net.Init();
			_net.OnSighting += SightingRelay.OnReceived;
			_controller = new MatchController(_net);
			_hud = new PvpHud();
			PvpAddonManager.Init(_net);
			RiotChaos.Init();
			MelonLogger.Msg($"[MultiplayerPVP] v{((MelonBase)this).Info.Version} ready. Press {PvpConfig.PanelKey.Value} in-game to open the host panel.");
		}

		public override void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			try
			{
				RiotChaos.OnSceneLoaded();
			}
			catch
			{
			}
			try
			{
				_net?.Init();
				_controller?.Cleanup();
				_hud?.Reset();
				SightingRelay.Reset();
				ViewLock.Release();
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("OnSceneWasLoaded: " + ex.Message);
			}
			try
			{
				PvpAddonManager.SceneLoaded(buildIndex, sceneName);
			}
			catch (Exception ex2)
			{
				MelonLogger.Warning("OnSceneWasLoaded(addons): " + ex2.Message);
			}
		}

		public override void OnDeinitializeMelon()
		{
			try
			{
				RiotChaos.Deinit();
			}
			catch
			{
			}
			try
			{
				PvpAddonManager.Deinit();
			}
			catch
			{
			}
			try
			{
				ViewLock.Release();
				_controller?.Cleanup();
				_net?.Dispose();
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("OnDeinitializeMelon: " + ex.Message);
			}
		}

		public override void OnUpdate()
		{
			if (_controller == null)
			{
				return;
			}
			try
			{
				if (Input.GetKeyDown((KeyCode)PvpConfig.PanelKey.Value))
				{
					if (_controller.Phase == MatchPhase.Idle)
					{
						_hud.PanelOpen = !_hud.PanelOpen;
					}
					else if (_controller.Phase == MatchPhase.Active && !_controller.IsRemote)
					{
						_hud.EndPromptOpen = !_hud.EndPromptOpen;
					}
				}
				if (_controller.Phase != MatchPhase.Active)
				{
					_hud.EndPromptOpen = false;
				}
				try
				{
					Player local = Player.Local;
					if ((Object)(object)local != (Object)null)
					{
						_net?.SetLocalIdentity(local.PlayerCode);
					}
				}
				catch
				{
				}
				_net?.Tick();
				_controller.Tick(Time.deltaTime);
				PvpAddonManager.Tick(Time.deltaTime, _controller.Phase, _controller.ModeType, _controller.Day);
				RiotChaos.Tick(Time.deltaTime, _controller);
				UnlimitedAmmo.Tick(_controller);
				DoubleJump.Tick(_controller);
				bool locked = _hud.PanelOpen || _hud.EndPromptOpen || (_controller.Phase == MatchPhase.EndOfDay && !_controller.IsRemote);
				ViewLock.Set(locked);
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("OnUpdate: " + ex.Message);
			}
		}

		public override void OnGUI()
		{
			if (_hud == null)
			{
				return;
			}
			try
			{
				_hud.Draw(_controller);
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("OnGUI: " + ex.Message);
			}
			try
			{
				PvpAddonManager.DrawGui();
			}
			catch (Exception ex2)
			{
				MelonLogger.Warning("OnGUI(addons): " + ex2.Message);
			}
		}
	}
}
namespace MultiplayerPVP.UI
{
	internal class PvpHud
	{
		private struct DispRow
		{
			public int ColorIdx;

			public string Text;

			public int Kills;

			public int Downs;

			public int Arrests;

			public int BagsCap;

			public int BagsLost;

			public int WpnLost;

			public int WpnWon;

			public int PlayerIndex;

			public string Days;
		}

		internal bool PanelOpen;

		internal bool EndPromptOpen;

		private static Texture2D _white;

		private readonly List<WorldMarker> _markers = new List<WorldMarker>();

		private Camera _cam;

		private int _camRevalidate;

		private int _hoverMode = -1;

		private PvpMatchToggle _hoverToggle;

		private readonly List<DispRow> _rows = new List<DispRow>();

		private static Texture2D White
		{
			get
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_001d: Expected O, but got Unknown
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)_white == (Object)null)
				{
					_white = new Texture2D(1, 1);
					_white.SetPixel(0, 0, Color.white);
					_white.Apply();
				}
				return _white;
			}
		}

		private static string FormatDays(string dotted)
		{
			return string.IsNullOrEmpty(dotted) ? "" : dotted.Replace(".", ", ");
		}

		internal void Reset()
		{
			_cam = null;
			_camRevalidate = 0;
			_markers.Clear();
			PanelOpen = false;
			EndPromptOpen = false;
		}

		internal void Draw(MatchController mc)
		{
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			if (mc == null)
			{
				return;
			}
			Safe(delegate
			{
				DrawBanner(mc);
			});
			Safe(delegate
			{
				DrawLocalBanner(mc);
			});
			switch (mc.Phase)
			{
			case MatchPhase.Countdown:
			case MatchPhase.Active:
			{
				bool flag = true;
				Safe(delegate
				{
					DrawCountdown(mc);
				});
				Safe(delegate
				{
					DrawScoreboard(mc, 220f);
				});
				Safe(delegate
				{
					DrawMarkers(mc);
				});
				if (mc.IsRemote)
				{
					Safe(delegate
					{
						DrawClientModeCard(mc);
					});
				}
				break;
			}
			case MatchPhase.EndOfDay:
				Safe(delegate
				{
					DrawEndOfDayMenu(mc);
				});
				break;
			case MatchPhase.Idle:
				if (PanelOpen)
				{
					Safe(delegate
					{
						DrawHostPanel(mc);
					});
				}
				break;
			}
			if (EndPromptOpen && mc.Phase == MatchPhase.Active && !mc.IsRemote)
			{
				Safe(delegate
				{
					DrawEndMatchPrompt(mc);
				});
			}
			GUI.color = Color.white;
		}

		private static void Safe(Action draw)
		{
			try
			{
				draw();
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("HUD draw: " + ex.Message);
			}
		}

		private void DrawBanner(MatchController mc)
		{
			//IL_0022: 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)
			//IL_0030: 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)
			//IL_0041: Expected O, but got Unknown
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			if (mc.Announcer.HasBanner)
			{
				GUIStyle val = new GUIStyle(GUI.skin.label)
				{
					fontSize = 40,
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)4
				};
				Rect val2 = default(Rect);
				((Rect)(ref val2))..ctor(0f, (float)Screen.height * 0.14f, (float)Screen.width, 60f);
				GUI.color = Color.black;
				GUI.Label(new Rect(((Rect)(ref val2)).x + 2f, ((Rect)(ref val2)).y + 2f, ((Rect)(ref val2)).width, ((Rect)(ref val2)).height), mc.Announcer.Banner, val);
				GUI.color = new Color(1f, 0.85f, 0.2f);
				GUI.Label(val2, mc.Announcer.Banner, val);
				GUI.color = Color.white;
			}
		}

		private void DrawLocalBanner(MatchController mc)
		{
			//IL_0022: 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)
			//IL_0030: 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)
			//IL_0041: Expected O, but got Unknown
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			if (mc.Announcer.HasLocalBanner)
			{
				GUIStyle val = new GUIStyle(GUI.skin.label)
				{
					fontSize = 26,
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)4
				};
				Rect val2 = default(Rect);
				((Rect)(ref val2))..ctor(0f, (float)Screen.height * 0.21f, (float)Screen.width, 44f);
				GUI.color = Color.black;
				GUI.Label(new Rect(((Rect)(ref val2)).x + 2f, ((Rect)(ref val2)).y + 2f, ((Rect)(ref val2)).width, ((Rect)(ref val2)).height), mc.Announcer.LocalBanner, val);
				GUI.color = mc.Announcer.LocalBannerColor;
				GUI.Label(val2, mc.Announcer.LocalBanner, val);
				GUI.color = Color.white;
			}
		}

		private void DrawCountdown(MatchController mc)
		{
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Expected O, but got Unknown
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			string text;
			if (mc.Phase == MatchPhase.Countdown)
			{
				text = "Starting…";
			}
			else
			{
				int num = Mathf.Max(0, Mathf.CeilToInt(mc.RemainingSeconds));
				text = $"{GameModeInfo.Title(mc.ModeType)}  ·  Day {mc.Day}  ·  {num / 60:0}:{num % 60:00}";
			}
			GUIStyle val = new GUIStyle(GUI.skin.label)
			{
				fontSize = 20,
				fontStyle = (FontStyle)1,
				alignment = (TextAnchor)4
			};
			Rect val2 = default(Rect);
			((Rect)(ref val2))..ctor((float)Screen.width * 0.5f - 220f, 70f, 440f, 28f);
			GUI.color = new Color(0f, 0f, 0f, 0.55f);
			ImguiCompat.DrawTexture(val2, White);
			GUI.color = Color.white;
			GUI.Label(val2, text, val);
		}

		private void DrawLoadoutCard(Rect anchor)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Expected O, but got Unknown
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Expected O, but got Unknown
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
			List<string> list = StartingLoadout.Buttons();
			float num = 210f;
			float num2 = Mathf.Max(((Rect)(ref anchor)).height, 64f + (float)list.Count * 24f + 60f);
			Rect position = default(Rect);
			((Rect)(ref position))..ctor(((Rect)(ref anchor)).x - num - 10f, ((Rect)(ref anchor)).y, num, num2);
			GUI.color = new Color(0.05f, 0.05f, 0.08f, 0.92f);
			ImguiCompat.DrawTexture(position, White);
			GUI.color = Color.white;
			GUIStyle val = new GUIStyle(GUI.skin.label)
			{
				fontSize = 15,
				fontStyle = (FontStyle)1
			};
			GUIStyle val2 = new GUIStyle(GUI.skin.label)
			{
				fontSize = 11,
				wordWrap = true
			};
			GUI.Label(new Rect(((Rect)(ref position)).x + 10f, ((Rect)(ref position)).y + 8f, num - 20f, 20f), "STARTING LOADOUT", val);
			GUI.Label(new Rect(((Rect)(ref position)).x + 10f, ((Rect)(ref position)).y + 28f, num - 20f, 30f), "Every player gets the checked items at round start.", val2);
			float num3 = ((Rect)(ref position)).y + 62f;
			for (int i = 0; i < list.Count; i++)
			{
				string id = list[i];
				bool flag = StartingLoadout.IsChecked(id);
				bool flag2 = GUI.Toggle(new Rect(((Rect)(ref position)).x + 12f, num3, num - 24f, 22f), flag, " " + StartingLoadout.LabelOf(id));
				if (flag2 != flag)
				{
					StartingLoadout.SetChecked(id, flag2);
				}
				num3 += 24f;
			}
			num3 += 6f;
			GUI.color = new Color(1f, 1f, 1f, 0.15f);
			ImguiCompat.DrawTexture(new Rect(((Rect)(ref position)).x + 10f, num3, num - 20f, 1f), White);
			GUI.color = Color.white;
			num3 += 6f;
			bool flag3 = UnlimitedAmmo.Checked;
			bool flag4 = GUI.Toggle(new Rect(((Rect)(ref position)).x + 12f, num3, num - 24f, 22f), flag3, " unlimited ammo (this round)");
			if (flag4 != flag3)
			{
				UnlimitedAmmo.SetChecked(flag4);
			}
			num3 += 24f;
			bool flag5 = DoubleJump.Checked;
			bool flag6 = GUI.Toggle(new Rect(((Rect)(ref position)).x + 12f, num3, num - 24f, 22f), flag5, " double jump (this round)");
			if (flag6 != flag5)
			{
				DoubleJump.SetChecked(flag6);
			}
		}

		private void DrawModeInfoCard(Rect anchor)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: 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_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Expected O, but got Unknown
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			Rect position = default(Rect);
			((Rect)(ref position))..ctor(((Rect)(ref anchor)).xMax + 10f, ((Rect)(ref anchor)).y, 240f, ((Rect)(ref anchor)).height);
			GUI.color = new Color(0.05f, 0.05f, 0.08f, 0.92f);
			ImguiCompat.DrawTexture(position, White);
			GUI.color = Color.white;
			GUIStyle val = new GUIStyle(GUI.skin.label)
			{
				fontSize = 15,
				fontStyle = (FontStyle)1,
				wordWrap = true
			};
			GUIStyle val2 = new GUIStyle(GUI.skin.label)
			{
				fontSize = 12,
				wordWrap = true
			};
			if (_hoverToggle != null)
			{
				GUI.Label(new Rect(((Rect)(ref position)).x + 10f, ((Rect)(ref position)).y + 10f, 220f, 44f), _hoverToggle.Label + " (modifier)", val);
				GUI.Label(new Rect(((Rect)(ref position)).x + 10f, ((Rect)(ref position)).y + 48f, 220f, ((Rect)(ref position)).height - 58f), _hoverToggle.Description, val2);
			}
			else if (_hoverMode >= 0)
			{
				GameModeType hoverMode = (GameModeType)_hoverMode;
				GUI.Label(new Rect(((Rect)(ref position)).x + 10f, ((Rect)(ref position)).y + 10f, 220f, 44f), GameModeInfo.Title(hoverMode), val);
				GUI.Label(new Rect(((Rect)(ref position)).x + 10f, ((Rect)(ref position)).y + 48f, 220f, ((Rect)(ref position)).height - 58f), GameModeInfo.Description(hoverMode), val2);
			}
			else
			{
				GUI.Label(new Rect(((Rect)(ref position)).x + 10f, ((Rect)(ref position)).y + 10f, 220f, ((Rect)(ref position)).height - 20f), "Hover a mode button to see what it does.", val2);
			}
		}

		private void DrawClientModeCard(MatchController mc)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: 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)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Expected O, but got Unknown
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			Rect position = default(Rect);
			((Rect)(ref position))..ctor(12f, 70f, 290f, 116f);
			GUI.color = new Color(0f, 0f, 0f, 0.6f);
			ImguiCompat.DrawTexture(position, White);
			GUI.color = Color.white;
			GUIStyle val = new GUIStyle(GUI.skin.label)
			{
				fontSize = 15,
				fontStyle = (FontStyle)1,
				wordWrap = true
			};
			GUIStyle val2 = new GUIStyle(GUI.skin.label)
			{
				fontSize = 12,
				wordWrap = true
			};
			GUI.Label(new Rect(((Rect)(ref position)).x + 10f, ((Rect)(ref position)).y + 8f, 270f, 22f), GameModeInfo.Title(mc.ModeType), val);
			GUI.Label(new Rect(((Rect)(ref position)).x + 10f, ((Rect)(ref position)).y + 32f, 270f, 76f), GameModeInfo.Description(mc.ModeType), val2);
		}

		private void BuildRows(MatchController mc)
		{
			_rows.Clear();
			if (mc.IsRemote ? (mc.RemoteTeamRows.Count > 0) : mc.IsTeamScoredMode)
			{
				if (mc.IsRemote)
				{
					for (int i = 0; i < mc.RemoteTeamRows.Count; i++)
					{
						SnapTeamRow snapTeamRow = mc.RemoteTeamRows[i];
						_rows.Add(new DispRow
						{
							ColorIdx = snapTeamRow.Team,
							Text = snapTeamRow.Name + "  —  " + snapTeamRow.Score,
							Kills = snapTeamRow.Kills,
							Downs = snapTeamRow.Downs,
							Arrests = snapTeamRow.Arrests,
							BagsCap = snapTeamRow.BagsCaptured,
							BagsLost = snapTeamRow.BagsLost,
							WpnLost = snapTeamRow.WeaponsLost,
							WpnWon = snapTeamRow.WeaponsWon,
							PlayerIndex = -1
						});
					}
					return;
				}
				int activeTeamCount = mc.ActiveTeamCount;
				List<PvpPlayer> players = mc.Registry.Players;
				for (int j = 0; j < activeTeamCount; j++)
				{
					int num = 0;
					int num2 = 0;
					int num3 = 0;
					int num4 = 0;
					int num5 = 0;
					int num6 = 0;
					int num7 = 0;
					for (int k = 0; k < players.Count; k++)
					{
						PvpPlayer pvpPlayer = players[k];
						if (pvpPlayer.Team == j)
						{
							num += pvpPlayer.Kills;
							num2 += pvpPlayer.Downs;
							num3 += pvpPlayer.Arrests;
							num4 += pvpPlayer.BagsCaptured;
							num5 += pvpPlayer.BagsLost;
							num6 += pvpPlayer.WeaponsLost;
							num7 += pvpPlayer.WeaponsWon;
						}
					}
					string text = "";
					try
					{
						if (mc.CurrentMode != null)
						{
							text = mc.CurrentMode.TeamScoreText(mc.Context, j);
						}
					}
					catch
					{
					}
					_rows.Add(new DispRow
					{
						ColorIdx = j,
						Text = mc.Registry.TeamLabel(j) + "  —  " + text,
						Kills = num,
						Downs = num2,
						Arrests = num3,
						BagsCap = num4,
						BagsLost = num5,
						WpnLost = num6,
						WpnWon = num7,
						PlayerIndex = -1
					});
				}
				return;
			}
			if (mc.IsRemote)
			{
				for (int l = 0; l < mc.RemoteRows.Count; l++)
				{
					SnapRow snapRow = mc.RemoteRows[l];
					_rows.Add(new DispRow
					{
						ColorIdx = snapRow.Index,
						Text = snapRow.Name + "  —  " + snapRow.Score,
						Kills = snapRow.Kills,
						Downs = snapRow.Downs,
						Arrests = snapRow.Arrests,
						BagsCap = snapRow.BagsCaptured,
						BagsLost = snapRow.BagsLost,
						WpnLost = snapRow.WeaponsLost,
						WpnWon = snapRow.WeaponsWon,
						PlayerIndex = snapRow.Index,
						Days = FormatDays(snapRow.History)
					});
				}
				return;
			}
			List<PvpPlayer> players2 = mc.Registry.Players;
			for (int m = 0; m < players2.Count; m++)
			{
				PvpPlayer pvpPlayer2 = players2[m];
				string text2 = "";
				string text3 = pvpPlayer2.Name;
				try
				{
					if (mc.CurrentMode != null)
					{
						text2 = mc.CurrentMode.ScoreText(pvpPlayer2);
						text3 = mc.CurrentMode.DisplayName(pvpPlayer2);
					}
				}
				catch
				{
				}
				string days = "";
				List<int> list = mc.HistoryOf(pvpPlayer2);
				if (list != null && list.Count >= 2)
				{
					days = string.Join(", ", list);
				}
				_rows.Add(new DispRow
				{
					ColorIdx = pvpPlayer2.Index,
					Text = text3 + "  —  " + text2,
					Kills = pvpPlayer2.Kills,
					Downs = pvpPlayer2.Downs,
					Arrests = pvpPlayer2.Arrests,
					BagsCap = pvpPlayer2.BagsCaptured,
					BagsLost = pvpPlayer2.BagsLost,
					WpnLost = pvpPlayer2.WeaponsLost,
					WpnWon = pvpPlayer2.WeaponsWon,
					PlayerIndex = pvpPlayer2.Index,
					Days = days
				});
			}
		}

		private void DrawScoreboard(MatchController mc, float width)
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: 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_00c1: Expected O, but got Unknown
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Expected O, but got Unknown
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			if (!mc.IsRemote && mc.CurrentMode == null)
			{
				return;
			}
			BuildRows(mc);
			int count = _rows.Count;
			if (count != 0)
			{
				float num = 26 + count * 22 + 8;
				Rect position = default(Rect);
				((Rect)(ref position))..ctor((float)Screen.width - width - 12f, 50f, width, num);
				GUI.color = new Color(0f, 0f, 0f, 0.55f);
				ImguiCompat.DrawTexture(position, White);
				GUI.color = Color.white;
				GUIStyle val = new GUIStyle(GUI.skin.label)
				{
					fontSize = 14,
					fontStyle = (FontStyle)1
				};
				GUI.Label(new Rect(((Rect)(ref position)).x + 8f, ((Rect)(ref position)).y + 4f, width - 16f, 20f), "SCOREBOARD", val);
				GUIStyle val2 = new GUIStyle(GUI.skin.label)
				{
					fontSize = 13
				};
				for (int i = 0; i < count; i++)
				{
					float num2 = ((Rect)(ref position)).y + 26f + (float)(i * 22);
					DispRow dispRow = _rows[i];
					GUI.color = PvpColors.For(dispRow.ColorIdx);
					ImguiCompat.DrawTexture(new Rect(((Rect)(ref position)).x + 8f, num2 + 4f, 10f, 10f), White);
					GUI.color = Color.white;
					GUI.Label(new Rect(((Rect)(ref position)).x + 24f, num2, width - 32f, 20f), dispRow.Text, val2);
				}
			}
		}

		private void DrawMarkers(MatchController mc)
		{
			//IL_02f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Expected O, but got Unknown
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_0263: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_029d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c2: Unknown result type (might be due to invalid IL or missing references)
			if (_camRevalidate-- <= 0 || (Object)(object)_cam == (Object)null)
			{
				_cam = Camera.main;
				_camRevalidate = 30;
			}
			if ((Object)(object)_cam == (Object)null)
			{
				return;
			}
			_markers.Clear();
			if (mc.IsRemote)
			{
				List<SnapMarker> remoteMarkers = mc.RemoteMarkers;
				for (int i = 0; i < remoteMarkers.Count; i++)
				{
					_markers.Add(new WorldMarker(remoteMarkers[i].Pos, remoteMarkers[i].Color, remoteMarkers[i].Label, remoteMarkers[i].Team));
				}
			}
			else
			{
				if (!(mc.CurrentMode is IWorldMarkers worldMarkers))
				{
					return;
				}
				try
				{
					worldMarkers.CollectMarkers(mc.Context, mc.Registry.Local, _markers);
				}
				catch
				{
					return;
				}
			}
			if (_markers.Count == 0)
			{
				return;
			}
			int num = mc.LocalTeam();
			GUIStyle val = new GUIStyle(GUI.skin.label)
			{
				fontSize = 12,
				fontStyle = (FontStyle)1,
				alignment = (TextAnchor)4
			};
			for (int j = 0; j < _markers.Count; j++)
			{
				WorldMarker worldMarker = _markers[j];
				if (worldMarker.Team < 0 || worldMarker.Team == num)
				{
					Vector3 val2;
					try
					{
						val2 = _cam.WorldToScreenPoint(worldMarker.Pos);
					}
					catch
					{
						continue;
					}
					if (!(val2.z <= 0f))
					{
						float x = val2.x;
						float num2 = (float)Screen.height - val2.y;
						GUI.color = worldMarker.Color;
						ImguiCompat.DrawTexture(new Rect(x - 2f, num2 - 80f, 4f, 80f), White);
						ImguiCompat.DrawTexture(new Rect(x - 7f, num2 - 7f, 14f, 14f), White);
						GUI.color = Color.black;
						GUI.Label(new Rect(x - 99f, num2 - 104f, 200f, 18f), worldMarker.Label, val);
						GUI.color = worldMarker.Color;
						GUI.Label(new Rect(x - 100f, num2 - 105f, 200f, 18f), worldMarker.Label, val);
					}
				}
			}
			GUI.color = Color.white;
		}

		private void DrawEndOfDayMenu(MatchController mc)
		{
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Expected O, but got Unknown
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Expected O, but got Unknown
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Expected O, but got Unknown
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Expected O, but got Unknown
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			//IL_02af: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_05cc: Expected O, but got Unknown
			//IL_0504: Unknown result type (might be due to invalid IL or missing references)
			//IL_0509: Unknown result type (might be due to invalid IL or missing references)
			//IL_0512: Unknown result type (might be due to invalid IL or missing references)
			//IL_051c: Expected O, but got Unknown
			//IL_052b: Unknown result type (might be due to invalid IL or missing references)
			//IL_055b: Unknown result type (might be due to invalid IL or missing references)
			//IL_059e: Unknown result type (might be due to invalid IL or missing references)
			//IL_065b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0686: Unknown result type (might be due to invalid IL or missing references)
			//IL_0693: Unknown result type (might be due to invalid IL or missing references)
			//IL_069c: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0610: Unknown result type (might be due to invalid IL or missing references)
			//IL_0622: Unknown result type (might be due to invalid IL or missing references)
			//IL_048f: Unknown result type (might be due to invalid IL or missing references)
			//IL_04bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_06df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0742: Unknown result type (might be due to invalid IL or missing references)
			BuildRows(mc);
			int count = _rows.Count;
			float num = ModeGridHeight();
			float num2 = Mathf.Max(0f, num - 104f);
			float num3 = 560f;
			float num4 = Mathf.Clamp(78f + (float)count * 46f + 200f + num2, 470f + num2, (float)(Screen.height - 40));
			Rect val = default(Rect);
			((Rect)(ref val))..ctor((float)Screen.width * 0.5f - num3 / 2f, (float)Screen.height * 0.5f - num4 / 2f, num3, num4);
			GUI.color = new Color(0.05f, 0.05f, 0.08f, 0.92f);
			ImguiCompat.DrawTexture(val, White);
			GUI.color = Color.white;
			GUIStyle val2 = new GUIStyle(GUI.skin.label)
			{
				fontSize = 24,
				fontStyle = (FontStyle)1,
				alignment = (TextAnchor)4
			};
			GUI.Label(new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).y + 12f, num3, 32f), $"END OF DAY {mc.Day}", val2);
			GUIStyle val3 = new GUIStyle(GUI.skin.label)
			{
				fontSize = 15,
				alignment = (TextAnchor)4
			};
			GUI.Label(new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).y + 46f, num3, 22f), mc.DayResult ?? "", val3);
			GUIStyle val4 = new GUIStyle(GUI.skin.label)
			{
				fontSize = 14
			};
			GUIStyle val5 = new GUIStyle(GUI.skin.label)
			{
				fontSize = 12
			};
			float num5 = ((Rect)(ref val)).y + 78f;
			int num6 = Mathf.Max(1, Mathf.FloorToInt((num4 - 268f - num2) / 46f));
			if (count > num6)
			{
				num6 = Mathf.Max(1, num6 - 1);
			}
			int num7 = Mathf.Min(count, num6);
			for (int i = 0; i < num7; i++)
			{
				DispRow dispRow = _rows[i];
				string text = dispRow.Text;
				if (!string.IsNullOrEmpty(dispRow.Days))
				{
					text = text + "   (days: " + dispRow.Days + ")";
				}
				float num8 = num5 + (float)i * 46f;
				GUI.color = PvpColors.For(dispRow.ColorIdx);
				ImguiCompat.DrawTexture(new Rect(((Rect)(ref val)).x + 30f, num8 + 4f, 10f, 10f), White);
				GUI.color = Color.white;
				GUI.Label(new Rect(((Rect)(ref val)).x + 48f, num8, num3 - 80f, 20f), $"{i + 1}. {text}", val4);
				string text2 = mc.ModeType switch
				{
					GameModeType.StealTheBags => $"Bags captured {dispRow.BagsCap}    ·    Bags lost {dispRow.BagsLost}", 
					GameModeType.Teams => $"Kills {dispRow.Kills}  ·  Downs {dispRow.Downs}  ·  Weapons won {dispRow.WpnWon}  ·  Weapons lost {dispRow.WpnLost}", 
					_ => $"Kills {dispRow.Kills}    ·    Downs {dispRow.Downs}    ·    Cuffs {dispRow.Arrests}", 
				};
				GUI.color = new Color(0.78f, 0.82f, 0.9f);
				GUI.Label(new Rect(((Rect)(ref val)).x + 48f, num8 + 22f, num3 - 80f, 18f), text2, val5);
				GUI.color = Color.white;
			}
			if (count > num7)
			{
				GUIStyle val6 = new GUIStyle(GUI.skin.label)
				{
					fontSize = 12,
					fontStyle = (FontStyle)2
				};
				GUI.color = new Color(0.7f, 0.75f, 0.85f);
				GUI.Label(new Rect(((Rect)(ref val)).x + 48f, num5 + (float)num7 * 46f, num3 - 80f, 18f), $"+ {count - num7} more…", val6);
				GUI.color = Color.white;
			}
			GUIStyle val7 = new GUIStyle(GUI.skin.label)
			{
				fontSize = 13,
				alignment = (TextAnchor)4
			};
			if (mc.IsRemote)
			{
				GUI.color = new Color(1f, 0.85f, 0.3f);
				GUI.Label(new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).y + num4 - 90f, num3, 22f), "Waiting for the host to choose the next mode…", val7);
				GUI.color = Color.white;
				return;
			}
			float num9 = ((Rect)(ref val)).y + num4 - 168f - num2;
			GUI.Label(new Rect(((Rect)(ref val)).x, num9 - 22f, num3, 18f), "Host: choose the next mode to start the morning", val7);
			DrawModeGrid(mc, new Rect(((Rect)(ref val)).x + 20f, num9, num3 - 40f, num), fresh: true);
			DrawModeInfoCard(val);
			DrawLoadoutCard(val);
			float num10 = ((Rect)(ref val)).y + num4 - 44f;
			if (mc.HasActiveMode && GUI.Button(new Rect(((Rect)(ref val)).x + 20f, num10, (num3 - 50f) / 2f, 30f), "Continue " + GameModeInfo.Title(mc.ModeType) + " (next day)"))
			{
				mc.RequestContinue();
			}
			if (GUI.Button(new Rect(((Rect)(ref val)).x + 30f + (num3 - 50f) / 2f, num10, (num3 - 50f) / 2f, 30f), "Stop match"))
			{
				mc.RequestStop();
			}
		}

		private void DrawHostPanel(MatchController mc)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: 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_00b6: Expected O, but got Unknown
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Expected O, but got Unknown
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: 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)
			//IL_012e: Expected O, but got Unknown
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0292: Unknown result type (might be due to invalid IL or missing references)
			//IL_029c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
			float num = ModeGridHeight();
			float num2 = 540f;
			float num3 = 250f + Mathf.Max(0f, num - 104f);
			Rect val = default(Rect);
			((Rect)(ref val))..ctor((float)Screen.width * 0.5f - num2 / 2f, (float)Screen.height * 0.5f - num3 / 2f, num2, num3);
			GUI.color = new Color(0.05f, 0.05f, 0.08f, 0.92f);
			ImguiCompat.DrawTexture(val, White);
			GUI.color = Color.white;
			GUIStyle val2 = new GUIStyle(GUI.skin.label)
			{
				fontSize = 22,
				fontStyle = (FontStyle)1,
				alignment = (TextAnchor)4
			};
			GUI.Label(new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).y + 12f, num2, 30f), "MULTIPLAYER PVP", val2);
			GUIStyle val3 = new GUIStyle(GUI.skin.label)
			{
				fontSize = 13,
				alignment = (TextAnchor)4
			};
			GUIStyle val4 = new GUIStyle(GUI.skin.label)
			{
				fontSize = 15,
				alignment = (TextAnchor)4,
				wordWrap = true
			};
			if (!mc.IsMultiplayer)
			{
				GUI.color = new Color(1f, 0.7f, 0.3f);
				GUI.Label(new Rect(((Rect)(ref val)).x + 20f, ((Rect)(ref val)).y + 70f, num2 - 40f, 80f), "This mod is multiplayer-only.\nHost or join a co-op lobby with 2+ players,\nthen press the host key again.", val4);
				GUI.color = Color.white;
			}
			else if (!mc.IsHost)
			{
				GUI.color = new Color(1f, 0.7f, 0.3f);
				GUI.Label(new Rect(((Rect)(ref val)).x + 20f, ((Rect)(ref val)).y + 70f, num2 - 40f, 80f), "Only the host controls the match.\nThe host picks the game mode.", val4);
				GUI.color = Color.white;
			}
			else
			{
				GUI.Label(new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).y + 44f, num2, 18f), $"{SessionUtil.PlayerCount()} player(s) · pick a mode to start", val3);
				Rect area = default(Rect);
				((Rect)(ref area))..ctor(((Rect)(ref val)).x + 20f, ((Rect)(ref val)).y + 70f, num2 - 40f, num);
				DrawModeGrid(mc, area, fresh: true);
				DrawModeInfoCard(val);
				DrawLoadoutCard(val);
			}
			if (GUI.Button(new Rect(((Rect)(ref val)).x + num2 - 110f, ((Rect)(ref val)).y + num3 - 34f, 90f, 26f), "Close"))
			{
				PanelOpen = false;
			}
		}

		private void DrawEndMatchPrompt(MatchController mc)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: 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_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Expected O, but got Unknown
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Expected O, but got Unknown
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Expected O, but got Unknown
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			float num = 440f;
			float num2 = 180f;
			Rect position = default(Rect);
			((Rect)(ref position))..ctor((float)Screen.width * 0.5f - num / 2f, (float)Screen.height * 0.5f - num2 / 2f, num, num2);
			GUI.color = new Color(0.05f, 0.05f, 0.08f, 0.95f);
			ImguiCompat.DrawTexture(position, White);
			GUI.color = Color.white;
			GUIStyle val = new GUIStyle(GUI.skin.label)
			{
				fontSize = 20,
				fontStyle = (FontStyle)1,
				alignment = (TextAnchor)4
			};
			GUI.Label(new Rect(((Rect)(ref position)).x, ((Rect)(ref position)).y + 16f, num, 28f), "END MATCH EARLY?", val);
			GUIStyle val2 = new GUIStyle(GUI.skin.label)
			{
				fontSize = 14,
				alignment = (TextAnchor)4,
				wordWrap = true
			};
			GUI.Label(new Rect(((Rect)(ref position)).x + 24f, ((Rect)(ref position)).y + 52f, num - 48f, 44f), "End the running match now? The countdown drops to 3 seconds and the day is scored as normal.", val2);
			if (GUI.Button(new Rect(((Rect)(ref position)).x + 40f, ((Rect)(ref position)).y + num2 - 64f, num - 80f, 38f), "End match early"))
			{
				EndPromptOpen = false;
				mc.RequestEndEarly();
			}
			GUIStyle val3 = new GUIStyle(GUI.skin.label)
			{
				fontSize = 11,
				alignment = (TextAnchor)4
			};
			GUI.color = new Color(0.7f, 0.75f, 0.85f);
			GUI.Label(new Rect(((Rect)(ref position)).x, ((Rect)(ref position)).y + num2 - 22f, num, 16f), $"Press {PvpConfig.PanelKey.Value} again to cancel", val3);
			GUI.color = Color.white;
		}

		private static float ModeGridHeight()
		{
			int num = 7 + MatchToggles.Snapshot().Length;
			int num2 = (num + 3) / 4;
			return (float)num2 * 48f + (float)(num2 - 1) * 8f;
		}

		private void DrawModeGrid(MatchController mc, Rect area, bool fresh)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: 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_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			int num = 7;
			float num2 = (((Rect)(ref area)).width - 24f) / 4f;
			float num3 = 48f;
			_hoverMode = -1;
			_hoverToggle = null;
			Vector2 val = (Vector2)((Event.current != null) ? Event.current.mousePosition : new Vector2(-1f, -1f));
			Rect val2 = default(Rect);
			for (int i = 0; i < num; i++)
			{
				int num4 = i / 4;
				int num5 = i % 4;
				((Rect)(ref val2))..ctor(((Rect)(ref area)).x + (float)num5 * (num2 + 8f), ((Rect)(ref area)).y + (float)num4 * (num3 + 8f), num2, num3);
				if (((Rect)(ref val2)).Contains(val))
				{
					_hoverMode = i;
				}
				GameModeType gameModeType = (GameModeType)i;
				if (GUI.Button(val2, $"{i + 1}. {GameModeInfo.Title(gameModeType)}"))
				{
					PanelOpen = false;
					if (fresh)
					{
						mc.RequestStart(gameModeType);
					}
				}
			}
			PvpMatchToggle[] array = MatchToggles.Snapshot();
			Rect val3 = default(Rect);
			for (int j = 0; j < array.Length; j++)
			{
				int num6 = num + j;
				int num7 = num6 / 4;
				int num8 = num6 % 4;
				((Rect)(ref val3))..ctor(((Rect)(ref area)).x + (float)num8 * (num2 + 8f), ((Rect)(ref area)).y + (float)num7 * (num3 + 8f), num2, num3);
				PvpMatchToggle pvpMatchToggle = array[j];
				if (((Rect)(ref val3)).Contains(val))
				{
					_hoverToggle = pvpMatchToggle;
				}
				GUI.color = (pvpMatchToggle.Requested ? new Color(0.55f, 1f, 0.55f) : new Color(0.85f, 0.85f, 0.9f));
				if (GUI.Button(val3, pvpMatchToggle.Label + "\n" + (pvpMatchToggle.Requested ? "ON (this round)" : "OFF")))
				{
					pvpMatchToggle.Requested = !pvpMatchToggle.Requested;
				}
				GUI.color = Color.white;
			}
		}
	}
	internal static class ViewLock
	{
		private static bool _locked;

		internal static void Set(bool locked)
		{
			if (locked != _locked)
			{
				_locked = locked;
				try
				{
					PlayerCamera instance = PlayerSingleton<PlayerCamera>.Instance;
					if ((Object)(object)instance != (Object)null)
					{
						instance.SetCanLook(!locked);
						if (locked)
						{
							instance.FreeMouse(true);
						}
						else
						{
							instance.LockMouse(true);
						}
					}
				}
				catch
				{
				}
			}
			if (locked)
			{
				try
				{
					Cursor.visible = true;
					Cursor.lockState = (CursorLockMode)0;
				}
				catch
				{
				}
			}
		}

		internal static void Release()
		{
			if (!_locked)
			{
				return;
			}
			_locked = false;
			try
			{
				PlayerCamera instance = PlayerSingleton<PlayerCamera>.Instance;
				if ((Object)(object)instance != (Object)null)
				{
					instance.SetCanLook(true);
					instance.LockMouse(true);
				}
			}
			catch
			{
			}
		}
	}
}
namespace MultiplayerPVP.Net
{
	internal struct SnapRow
	{
		internal string Name;

		internal int Team;

		internal int Index;

		internal string Score;

		internal bool Bag;

		internal Vector3 Spawn;

		internal int Kills;

		internal int Downs;

		internal int Arrests;

		internal int BagsCaptured;

		internal int BagsLost;

		internal int WeaponsLost;

		internal int WeaponsWon;

		internal string History;
	}
	internal struct SnapTeamRow
	{
		internal int Team;

		internal string Name;

		internal string Score;

		internal int Kills;

		internal int Downs;

		internal int Arrests;

		internal int BagsCaptured;

		internal int BagsLost;

		internal int WeaponsLost;

		internal int WeaponsWon;
	}
	internal struct SnapMarker
	{
		internal Vector3 Pos;

		internal Color Color;

		internal string Label;

		internal int Team;
	}
	internal class MatchSnapshot
	{
		internal int Phase;

		internal int Mode;

		internal int Day;

		internal float Remaining;

		internal string Banner = "";

		internal string Result = "";

		internal string Loot = "";

		internal bool Chaos;

		internal bool Ammo;

		internal bool Jump;

		internal string Loadout = "";

		internal long RoundId;

		internal readonly List<SnapRow> Rows = new List<SnapRow>();

		internal readonly List<SnapTeamRow> TeamRows = new List<SnapTeamRow>();

		internal readonly List<SnapMarker> Markers = new List<SnapMarker>();

		internal long Seq;

		private static string San(string s)
		{
			if (string.IsNullOrEmpty(s))
			{
				return "";
			}
			return s.Replace('|', ' ').Replace('~', ' ').Replace(';', ' ')
				.Replace('=', ' ')
				.Replace(',', ' ')
				.Replace('"', ' ')
				.Replace('\\', ' ');
		}

		private static string F(float v)
		{
			return v.ToString("0.0", CultureInfo.InvariantCulture);
		}

		internal string Serialize()
		{
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_044b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0468: Unknown result type (might be due to invalid IL or missing references)
			//IL_0485: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_04bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_04dc: Unknown result type (might be due to invalid IL or missing references)
			StringBuilder stringBuilder = new StringBuilder(192);
			stringBuilder.Append("v=1|sq=").Append(Seq).Append("|ph=")
				.Append(Phase)
				.Append("|md=")
				.Append(Mode)
				.Append("|day=")
				.Append(Day)
				.Append("|rs=")
				.Append(Remaining.ToString("0.0", CultureInfo.InvariantCulture))
				.Append("|bn=")
				.Append(San(Banner))
				.Append("|rz=")
				.Append(San(Result))
				.Append("|lt=")
				.Append(Loot ?? "")
				.Append("|cx=")
				.Append(Chaos ? 1 : 0)
				.Append("|ua=")
				.Append(Ammo ? 1 : 0)
				.Append("|dj=")
				.Append(Jump ? 1 : 0)
				.Append("|gi=")
				.Append(Loadout ?? "")
				.Append("|gr=")
				.Append(RoundId)
				.Append("|p=");
			for (int i = 0; i < Rows.Count; i++)
			{
				SnapRow snapRow = Rows[i];
				if (i > 0)
				{
					stringBuilder.Append(';');
				}
				stringBuilder.Append(San(snapRow.Name)).Append('~').Append(snapRow.Team)
					.Append('~')
					.Append(snapRow.Index)
					.Append('~')
					.Append(San(snapRow.Score))
					.Append('~')
					.Append(snapRow.Bag ? 1 : 0)
					.Append('~')
					.Append(F(snapRow.Spawn.x))
					.Append('~')
					.Append(F(snapRow.Spawn.y))
					.Append('~')
					.Append(F(snapRow.Spawn.z))
					.Append('~')
					.Append(snapRow.Kills)
					.Append('~')
					.Append(snapRow.Downs)
					.Append('~')
					.Append(snapRow.Arrests)
					.Append('~')
					.Append(snapRow.BagsCaptured)
					.Append('~')
					.Append(snapRow.BagsLost)
					.Append('~')
					.Append(snapRow.WeaponsLost)
					.Append('~')
					.Append(snapRow.WeaponsWon)
					.Append('~')
					.Append(San(snapRow.History));
			}
			stringBuilder.Append("|tr=");
			for (int j = 0; j < TeamRows.Count; j++)
			{
				SnapTeamRow snapTeamRow = TeamRows[j];
				if (j > 0)
				{
					stringBuilder.Append(';');
				}
				stringBuilder.Append(snapTeamRow.Team).Append('~').Append(San(snapTeamRow.Name))
					.Append('~')
					.Append(San(snapTeamRow.Score))
					.Append('~')
					.Append(snapTeamRow.Kills)
					.Append('~')
					.Append(snapTeamRow.Downs)
					.Append('~')
					.Append(snapTeamRow.Arrests)
					.Append('~')
					.Append(snapTeamRow.BagsCaptured)
					.Append('~')
					.Append(snapTeamRow.BagsLost)
					.Append('~')
					.Append(snapTeamRow.WeaponsLost)
					.Append('~')
					.Append(snapTeamRow.WeaponsWon);
			}
			stringBuilder.Append("|m=");
			for (int k = 0; k < Markers.Count; k++)
			{
				SnapMarker snapMarker = Markers[k];
				if (k > 0)
				{
					stringBuilder.Append(',');
				}
				stringBuilder.Append(F(snapMarker.Pos.x)).Append('~').Append(F(snapMarker.Pos.y))
					.Append('~')
					.Append(F(snapMarker.Pos.z))
					.Append('~')
					.Append(F(snapMarker.Color.r))
					.Append('~')
					.Append(F(snapMarker.Color.g))
					.Append('~')
					.Append(F(snapMarker.Color.b))
					.Append('~')
					.Append(San(snapMarker.Label))
					.Append('~')
					.Append(snapMarker.Team);
			}
			return stringBuilder.ToString();
		}

		internal static bool TryParse(string s, MatchSnapshot into)
		{
			//IL_08c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_08cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_08de: Unknown result type (might be due to invalid IL or missing references)
			//IL_08e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0588: Unknown result type (might be due to invalid IL or missing references)
			//IL_058d: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(s) || into == null)
			{
				return false;
			}
			try
			{
				into.Rows.Clear();
				into.TeamRows.Clear();
				into.Markers.Clear();
				into.Banner = "";
				into.Result = "";
				into.Loot = "";
				into.Chaos = false;
				into.Ammo = false;
				into.Jump = false;
				into.Loadout = "";
				into.RoundId = 0L;
				string[] array = s.Split('|');
				string[] array2 = array;
				foreach (string text in array2)
				{
					int num = text.IndexOf('=');
					if (num < 0)
					{
						continue;
					}
					string text2 = text.Substring(0, num);
					string text3 = text.Substring(num + 1);
					switch (text2)
					{
					case "sq":
						long.TryParse(text3, out into.Seq);
						break;
					case "ph":
						int.TryParse(text3, out into.Phase);
						break;
					case "md":
						int.TryParse(text3, out into.Mode);
						break;
					case "day":
						int.TryParse(text3, out into.Day);
						break;
					case "rs":
						float.TryParse(text3, NumberStyles.Float, CultureInfo.InvariantCulture, out into.Remaining);
						break;
					case "bn":
						into.Banner = text3;
						break;
					case "rz":
						into.Result = text3;
						break;
					case "lt":
						into.Loot = text3;
						break;
					case "cx":
						into.Chaos = text3 == "1";
						break;
					case "ua":
						into.Ammo = text3 == "1";
						break;
					case "dj":
						into.Jump = text3 == "1";
						break;
					case "gi":
						into.Loadout = text3;
						break;
					case "gr":
						long.TryParse(text3, out into.RoundId);
						break;
					case "p":
					{
						if (text3.Length == 0)
						{
							break;
						}
						string[] array7 = text3.Split(';');
						foreach (string text6 in array7)
						{
							string[] array8 = text6.Split('~');
							if (array8.Length >= 4)
							{
								SnapRow item3 = new SnapRow
								{
									Name = array8[0],
									Score = array8[3]
								};
								int.TryParse(array8[1], out item3.Team);
								int.TryParse(array8[2], out item3.Index);
								if (array8.Length >= 5)
								{
									item3.Bag = array8[4] == "1";
								}
								if (array8.Length >= 8)
								{
									float.TryParse(array8[5], NumberStyles.Float, CultureInfo.InvariantCulture, out var result7);
									float.TryParse(array8[6], NumberStyles.Float, CultureInfo.InvariantCulture, out var result8);
									float.TryParse(array8[7], NumberStyles.Float, CultureInfo.InvariantCulture, out var result9);
									item3.Spawn = new Vector3(result7, result8, result9);
								}
								if (array8.Length >= 11)
								{
									int.TryParse(array8[8], out item3.Kills);
									int.TryParse(array8[9], out item3.Downs);
									int.TryParse(array8[10], out item3.Arrests);
								}
								if (array8.Length >= 15)
								{
									int.TryParse(array8[11], out item3.BagsCaptured);
									int.TryParse(array8[12], out item3.BagsLost);
									int.TryParse(array8[13], out item3.WeaponsLost);
									int.TryParse(array8[14], out item3.WeaponsWon);
								}
								if (array8.Length >= 16)
								{
									item3.History = array8[15];
								}
								into.Rows.Add(item3);
							}
						}
						break;
					}
					case "tr":
					{
						if (text3.Length == 0)
						{
							break;
						}
						string[] array5 = text3.Split(';');
						foreach (string text5 in array5)
						{
							string[] array6 = text5.Split('~');
							if (array6.Length >= 3)
							{
								SnapTeamRow item2 = new SnapTeamRow
								{
									Name = array6[1],
									Score = array6[2]
								};
								int.TryParse(array6[0], out item2.Team);
								if (array6.Length >= 10)
								{
									int.TryParse(array6[3], out item2.Kills);
									int.TryParse(array6[4], out item2.Downs);
									int.TryParse(array6[5], out item2.Arrests);
									int.TryParse(array6[6], out item2.BagsCaptured);
									int.TryParse(array6[7], out item2.BagsLost);
									int.TryParse(array6[8], out item2.WeaponsLost);
									int.TryParse(array6[9], out item2.WeaponsWon);
								}
								into.TeamRows.Add(item2);
							}
						}
						break;
					}
					case "m":
					{
						if (text3.Length == 0)
						{
							break;
						}
						string[] array3 = text3.Split(',');
						foreach (string text4 in array3)
						{
							string[] array4 = text4.Split('~');
							if (array4.Length >= 7)
							{
								SnapMarker item = new SnapMarker
								{
									Label = array4[6],
									Team = -1
								};
								float.TryParse(array4[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var result);
								float.TryParse(array4[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2);
								float.TryParse(array4[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3);
								float.TryParse(array4[3], NumberStyles.Float, CultureInfo.InvariantCulture, out var result4);
								float.TryParse(array4[4], NumberStyles.Float, CultureInfo.InvariantCulture, out var result5);
								float.TryParse(array4[5], NumberStyles.Float, CultureInfo.InvariantCulture, out var result6);
								if (array4.Length >= 8)
								{
									int.TryParse(array4[7], out item.Team);
								}
								item.Pos = new Vector3(result, result2, result3);
								item.Color = new Color(result4, result5, result6, 1f);
								into.Markers.Add(item);
							}
						}
						break;
					}
					}
				}
				return true;
			}
			catch
			{
				return false;
			}
		}
	}
	internal sealed class PvpNet
	{
		internal const string KeyPrefix = "mpvp_";

		internal const string SnapshotKey = "snap";

		internal const string ModTagKey = "mod";

		internal const string LootKey = "loot";

		internal const string EarnKey = "earn";

		internal const string SpillKey = "spill";

		internal const string IdTagKey = "idtag";

		internal const string SightKey = "sight";

		private SteamNetworkClient _client;

		private HostSyncVar<string> _snap;

		private ClientSyncVar<string> _modTag;

		private ClientSyncVar<string> _loot;

		private ClientSyncVar<string> _earn;

		private ClientSyncVar<string> _spill;

		private ClientSyncVar<string> _idTag;

		private ClientSyncVar<string> _sight;

		private readonly List<ClientSyncVar<string>> _addonVars = new List<ClientSyncVar<string>>();

		private bool _init;

		private static readonly string ModTag = "MultiplayerPVP/" + ModVersion();

		private bool _wasInLobby;

		private bool _tagSet;

		private string _idCode;

		private bool _idSet;

		private const float WarnInterval = 15f;

		private float _lastWarn = -999f;

		internal bool Available => _init && _client != null;

		internal bool IsInLobby
		{
			get
			{
				try
				{
					return Available && _client.IsInLobby;
				}
				catch
				{
					return false;
				}
			}
		}

		internal bool IsHost
		{
			get
			{
				try
				{
					return Available && _client.IsHost;
				}
				catch
				{
					return false;
				}
			}
		}

		internal ulong LocalSteamId
		{
			get
			{
				//IL_0044: Unknown result type (might be due to invalid IL or missing references)
				if (!Available)
				{
					return 0uL;
				}
				try
				{
					foreach (MemberInfo lobbyMember in _client.GetLobbyMembers())
					{
						if (lobbyMember != null && lobbyMember.IsLocalPlayer)
						{
							return lobbyMember.SteamId.m_SteamID;
						}
					}
				}
				catch
				{
				}
				return 0uL;
			}
		}

		internal int ModdedMemberCount
		{
			get
			{
				if (_modTag == null)
				{
					return 0;
				}
				try
				{
					int num = 0;
					foreach (KeyValuePair<CSteamID, string> allValue in _modTag.GetAllValues())
					{
						if (!string.IsNullOrEmpty(allValue.Value))
						{
							num++;
						}
					}
					return num;
				}
				catch
				{
					return 0;
				}
			}
		}

		internal int MemberCount
		{
			get
			{
				try
				{
					return Available ? _client.GetLobbyMembers().Count : 0;
				}
				catch
				{
					return 0;
				}
			}
		}

		internal bool AllMembersModded
		{
			get
			{
				int memberCount = MemberCount;
				return memberCount > 0 && ModdedMemberCount >= memberCount;
			}
		}

		internal event Action<string> OnSnapshot;

		internal event Action<ulong, string> OnLoot;

		internal event Action<ulong, string> OnSpill;

		internal event Action<ulong, string> OnSighting;

		internal void Init()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			if (_init)
			{
				return;
			}
			try
			{
				_client = new SteamNetworkClient();
				if (!_client.Initialize())
				{
					return;
				}
				try
				{
					_client.OnVersionMismatch += OnVersionMismatch;
				}
				catch
				{
				}
				NetworkSyncOptions val = MakeOpts();
				_snap = _client.CreateHostSyncVar<string>("snap", "", val, (ISyncValidator<string>)null);
				_snap.OnValueChanged += OnSnapValueChanged;
				_snap.OnSyncError += OnSyncError;
				_modTag = _client.CreateClientSyncVar<string>("mod", "", val, (ISyncValidator<string>)null);
				_loot = _client.CreateClientSyncVar<string>("loot", "", val, (ISyncValidator<string>)null);
				_loot.OnValueChanged += delegate(CSteamID from, string oldV, string newV)
				{
					//IL_0020: Unknown result type (might be due to invalid IL or missing references)
					try
					{
						if (!string.IsNullOrEmpty(newV))
						{
							this.OnLoot?.Invoke(from.m_SteamID, newV);
						}
					}
					catch
					{
					}
				};
				_earn = _client.CreateClientSyncVar<string>("earn", "", val, (ISyncValidator<string>)null);
				_spill = _client.CreateClientSyncVar<string>("spill", "", val, (ISyncValidator<string>)null);
				_spill.OnValueChanged += delegate(CSteamID from, string oldV, string newV)
				{
					//IL_0020: Unknown result type (might be due to invalid IL or missing references)
					try
					{
						if (!string.IsNullOrEmpty(newV))
						{
							this.OnSpill?.Invoke(from.m_SteamID, newV);
						}
					}
					catch
					{
					}
				};
				_idTag = _client.CreateClientSyncVar<string>("idtag", "", val, (ISyncValidator<string>)null);
				_sight = _client.CreateClientSyncVar<string>("sight", "", val, (ISyncValidator<string>)null);
				_sight.OnValueChanged += delegate(CSteamID from, string oldV, string newV)
				{
					//IL_0020: Unknown result type (might be due to invalid IL or missing references)
					try
					{
						if (!string.IsNullOrEmpty(newV))
						{
							this.OnSighting?.Invoke(from.m_SteamID, newV);
						}
					}
					catch
					{
					}
				};
				_init = true;
				PvpLog.Debug("[MultiplayerPVP][Net] SteamNetworkClient initialized (HostSyncVar transport).");
			}
			catch
			{
			}
		}

		private static NetworkSyncOptions MakeOpts()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: 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_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			return new NetworkSyncOptions
			{
				KeyPrefix = "mpvp_",
				AutoSync = true,
				SyncOnPlayerJoin = true,
				MaxSyncsPerSecond = 0
			};
		}

		internal ClientSyncVar<string> CreateAddonVar(string keySuffix, Action<ulong, string> onMessage)
		{
			if (!_init || _client == null || string.IsNullOrEmpty(keySuffix))
			{
				return null;
			}
			try
			{
				ClientSyncVar<string> val = _client.CreateClientSyncVar<string>(keySuffix, "", MakeOpts(), (ISyncValidator<string>)null);
				if (onMessage != null)
				{
					val.OnValueChanged += delegate(CSteamID from, string oldV, string newV)
					{
						//IL_0015: Unknown result type (might be due to invalid IL or missing references)
						try
						{
							if (!string.IsNullOrEmpty(newV))
							{
								onMessage(from.m_SteamID, newV);
							}
						}
						catch
						{
						}
					};
				}
				lock (_addonVars)
				{
					_addonVars.Add(val);
				}
				return val;
			}
			catch (Exception ex)
			{
				float realtimeSinceStartup = Time.realtimeSinceStartup;
				if (realtimeSinceStartup - _lastWarn >= 15f)
				{
					_lastWarn = realtimeSinceStartup;
					MelonLogger.Warning("[MultiplayerPVP][Net] addon channel '" + keySuffix + "' create failed: " + ex.Message);
				}
				return null;
			}
		}

		internal void Tick()
		{
			if (!_init)
			{
				return;
			}
			bool isInLobby = IsInLobby;
			if (isInLobby && !_wasInLobby)
			{
				_tagSet = false;
				_idSet = false;
			}
			_wasInLobby = isInLobby;
			if (isInLobby && !_tagSet && _modTag != null)
			{
				try
				{
					_modTag.Value = ModTag;
					_tagSet = true;
				}
				catch
				{
				}
			}
			if (!isInLobby || _idSet || _idTag == null || string.IsNullOrEmpty(_idCode))
			{
				return;
			}
			try
			{
				_idTag.Value = _idCode;
				_idSet = true;
			}
			catch
			{
			}
		}

		internal void SetLocalIdentity(string playerCode)
		{
			if (!string.IsNullOrEmpty(playerCode) && playerCode != _idCode)
			{
				_idCode = playerCode;
				_idSet = false;
			}
		}

		private void OnSnapValueChanged(string oldValue, string newValue)
		{
			try
			{
				if (!IsHost && !string.IsNullOrEmpty(newValue))
				{
					this.OnSnapshot?.Invoke(newValue);
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[MultiplayerPVP][Net] snapshot apply: " + ex.Message);
			}
		}

		internal void PublishSnapshot(string snapshot)
		{
			if (!Available || !IsHost || _snap == null)
			{
				return;
			}
			try
			{
				_snap.Value = snapshot;
			}
			catch (Exception ex)
			{
				OnSyncError(ex);
			}
		}

		internal void PublishLoot(string record)
		{
			if (!Available || _loot == null)
			{
				return;
			}
			try
			{
				_loot.Value = record;
			}
			catch
			{
			}
		}

		internal void PublishSpill(string record)
		{
			if (!Available || _spill == null)
			{
				return;
			}
			try
			{
				_spill.Value = record;
			}
			catch
			{
			}
		}

		internal void PublishEarnings(string record)
		{
			if (!Available || _earn == null)
			{
				return;
			}
			try
			{
				_earn.Value = record;
			}
			catch
			{
			}
		}

		internal List<KeyValuePair<ulong, string>> AllEarnings()
		{
			return ReadAllOf(_earn);
		}

		internal List<KeyValuePair<ulong, string>> AllLoot()
		{
			return ReadAllOf(_loot);
		}

		internal List<KeyValuePair<ulong, string>> AllSpill()
		{
			return ReadAllOf(_spill);
		}

		internal static List<KeyValuePair<ulong, string>> ReadAllOf(ClientSyncVar<string> v)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			List<KeyValuePair<ulong, string>> list = new List<KeyValuePair<ulong, string>>();
			if (v == null)
			{
				return list;
			}
			try
			{
				v.Refresh();
			}
			catch
			{
			}
			try
			{
				foreach (KeyValuePair<CSteamID, string> allValue in v.GetAllValues())
				{
					if (!string.IsNullOrEmpty(allValue.Value))
					{
						list.Add(new KeyValuePair<ulong, string>(allValue.Key.m_SteamID, allValue.Value));
					}
				}
			}
			catch
			{
			}
			return list;
		}

		internal void PublishSighting(string record)
		{
			if (!Available || _sight == null)
			{
				return;
			}
			try
			{
				_sight.Value = record;
			}
			catch
			{
			}
		}

		internal Dictionary<string, ulong> AllIdentities()
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<string, ulong> dictionary = new Dictionary<string, ulong>();
			if (_idTag == null)
			{
				return dictionary;
			}
			try
			{
				foreach (KeyValuePair<CSteamID, string> allValue in _idTag.GetAllValues())
				{
					if (!string.IsNullOrEmpty(allValue.Value))
					{
						dictionary[allValue.Value] = allValue.Key.m_SteamID;
					}
				}
			}
			catch
			{
			}
			return dictionary;
		}

		internal string PersonaOf(ulong steamId)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			if (!Available || steamId == 0)
			{
				return null;
			}
			try
			{
				foreach (MemberInfo lobbyMember in _client.GetLobbyMembers())
				{
					if (lobbyMember != null && lobbyMember.SteamId.m_SteamID == steamId)
					{
						return lobbyMember.DisplayName;
					}
				}
			}
			catch
			{
			}
			return null;
		}

		private void OnVersionMismatch(object sender, VersionMismatchEventArgs e)
		{
			MelonLogger.Warning("[MultiplayerPVP][Net] SteamNetworkLib version mismatch between players — networking may be unreliable. Ensure everyone runs the same mod/lib build.");
		}

		private void OnSyncError(Exception ex)
		{
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (!(realtimeSinceStartup - _lastWarn < 15f))
			{
				_lastWarn = realtimeSinceStartup;
				MelonLogger.Warning("[MultiplayerPVP][Net] snapshot sync error (throttled): " + ex.Message);
			}
		}

		internal void Dispose()
		{
			try
			{
				if (_snap != null)
				{
					_snap.OnValueChanged -= OnSnapValueChanged;
					_snap.OnSyncError -= OnSyncError;
					_snap.Dispose();
				}
			}
			catch
			{
			}
			try
			{
				if (_modTag != null)
				{
					_modTag.Dispose();
				}
			}
			catch
			{
			}
			try
			{
				if (_loot != null)
				{
					_loot.Dispose();
				}
			}
			catch
			{
			}
			try
			{
				if (_earn != null)
				{
					_earn.Dispose();
				}
			}
			catch
			{
			}
			try
			{
				if (_spill != null)
				{
					_spill.Dispose();
				}
			}
			catch
			{
			}
			try
			{
				if (_idTag != null)
				{
					_idTag.Dispose();
				}
			}
			catch
			{
			}
			try
			{
				if (_sight != null)
				{
					_sight.Dispose();
				}
			}
			catch
			{
			}
			lock (_addonVars)
			{
				for (int i = 0; i < _addonVars.Count; i++)
				{
					try
					{
						_addonVars[i].Dispose();
					}
					catch
					{
					}
				}
				_addonVars.Clear();
			}
			try
			{
				if (_client != null)
				{
					_client.OnVersionMismatch -= OnVersionMismatch;
					_client.Dispose();
				}
			}
			catch
			{
			}
			_snap = null;
			_modTag = null;
			_loot = null;
			_earn = null;
			_spill = null;
			_idTag = null;
			_sight = null;
			_client = null;
			_init = false;
			_tagSet = false;
			_idSet = false;
			_idCode = null;
			_wasInLobby = false;
		}

		private static string ModVersion()
		{
			try
			{
				Version version = typeof(PvpNet).Assembly.GetName().Version;
				return (version != null) ? version.ToString() : "1.0";
			}
			catch
			{
				return "1.0";
			}
		}
	}
}
namespace MultiplayerPVP.Modes
{
	internal class FindersKeepersMode : GameModeBase, IWorldMarkers, IBagSpillHandler
	{
		private DeadDrop _pickup;

		private int _pickupZone = -1;

		private int _pickupKnown;

		private PvpPlayer _carrier;

		private int _carrierHome = -1;

		private int _homeBaseline;

		private float _transit;

		private bool _active;

		private static string BagId => BagFactory.MatchId;

		public override GameModeType Type => GameModeType.FindersKeepers;

		public override void OnMatchStart(MatchContext ctx)
		{
			_active = true;
			SpawnBag(ctx, announce: false);
		}

		public override void OnMatchEnd(MatchContext ctx)
		{
			_active = false;
			bool tie;
			PvpPlayer pvpPlayer = ctx.Registry.Leader(out tie);
			if (pvpPlayer != null)
			{
				ctx.Announcer.Announce(tie ? $"It's a draw at {pvpPlayer.Score} delivery(ies)!" : $"{pvpPlayer.Name} wins with {pvpPlayer.Score} delivery(ies)!", 6f);
			}
		}

		private void SpawnBag(MatchContext ctx, bool announce)
		{
			_carrier = null;
			_carrierHome = -1;
			_transit = 0f;
			_pickup = ctx.Drops.RandomNonZoneDrop();
			_pickupZone = -1;
			for (int i = 0; i < ctx.Drops.Count; i++)
			{
				if ((Object)(object)ctx.Drops.Zone(i) == (Object)(object)_pickup)
				{
					_pickupZone = i;
					break;
				}
			}
			if (GameCompat.Alive((Object)(object)_pickup))
			{
				DeadDropStash.Insert(_pickup, BagId, 1, BagFactory.Create);
				_pickupKnown = DeadDropStash.Count(_pickup, BagId);
			}
			else
			{
				_pickupKnown = 0;
			}
			if (announce && GameCompat.Alive((Object)(object)_pickup))
			{
				ctx.Announcer.Announce("A fresh bag is in a dead drop — find it!", 3f);
			}
		}

		public bool OnCarrierSpill(MatchContext ctx, PvpPlayer victim, int count, string reason)
		{
			if (count <= 0)
			{
				return true;
			}
			if (_carrier == null)
			{
				return true;
			}
			if (victim != null && victim != _carrier)
			{
				return true;
			}
			string name = _carrier.Name;
			string text = ((reason == "arrested") ? "was busted" : "went down");
			SpawnBag(ctx, announce: false);
			ctx.Announcer.Announce(name + " " + text + " — the bag dropped and reappears in a dead drop!", 4f, notify: false);
			return true;
		}

		public override void Tick(MatchContext ctx, float dt)
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			if (!_active)
			{
				return;
			}
			if (_carrier == null)
			{
				if (!GameCompat.Alive((Object)(object)_pickup))
				{
					SpawnBag(ctx, announce: false);
					return;
				}
				int num = DeadDropStash.Count(_pickup, BagId);
				if (num < _pickupKnown)
				{
					_carrier = NearestPlayer(ctx, PickupPos(ctx));
					_pickupKnown = num;
					_transit = 0f;
					_carrierHome = ((_carrier != null) ? ctx.Drops.ZoneForIndex(_carrier.Index) : (-1));
					DeadDrop val = ((_carrierHome >= 0) ? ctx.Drops.Zone(_carrierHome) : null);
					_homeBaseline = (GameCompat.Alive((Object)(object)val) ? DeadDropStash.Count(val, BagId) : 0);
					string text = ((_carrier != null) ? _carrier.Name : "Someone");
					ctx.Announcer.Announce(text + " has the bag!");
				}
				return;
			}
			_transit += dt;
			int carrierHome = _carrierHome;
			DeadDrop val2 = ((carrierHome >= 0) ? ctx.Drops.Zone(carrierHome) : null);
			if (GameCompat.Alive((Object)(object)val2) && DeadDropStash.Count(val2, BagId) > _homeBaseline)
			{
				DeadDropStash.RemoveOne(val2, BagId);
				ctx.Award(_carrier, 1);
				ctx.Announcer.Announce($"{_carrier.Name} delivered the bag! ({_carrier.Score})", 5f);
				SpawnBag(ctx, announce: false);
			}
			else if (_transit > 60f)
			{
				ctx.Announcer.Announce("The bag was lost — a new one appears.");
				SpawnBag(ctx, announce: true);
			}
		}

		private Vector3 PickupPos(MatchContext ctx)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: 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_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			if (_pickupZone >= 0)
			{
				return ctx.Drops.ZonePosition(_pickupZone);
			}
			try
			{
				return GameCompat.Alive((Object)(object)_pickup) ? ((Component)_pickup).transform.position : Vector3.zero;
			}
			catch
			{
				return Vector3.zero;
			}
		}

		private static PvpPlayer NearestPlayer(MatchContext ctx, Vector3 pos)
		{
			//IL_0035: 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)
			List<PvpPlayer> players = ctx.Registry.Players;
			PvpPlayer result = null;
			float num = float.MaxValue;
			for (int i = 0; i < players.Count; i++)
			{
				PvpPlayer pvpPlayer = players[i];
				if (pvpPlayer.Valid)
				{
					float num2 = Vector3.Distance(pos, pvpPlayer.Position);
					if (num2 < num)
					{
						num = num2;
						result = pvpPlayer;
					}
				}
			}
			return result;
		}

		public override bool IsComplete(MatchContext ctx)
		{
			int num = Mathf.Max(1, PvpConfig.CtfScoreToWin.Value);
			List<PvpPlayer> players = ctx.Registry.Players;
			for (int i = 0; i < players.Count; i++)
			{
				if (players[i].Score >= num)
				{
					return true;
				}
			}
			return false;
		}

		public override string ScoreText(PvpPlayer p)
		{
			return p.Score + " caps" + ((_carrier == p) ? " ·BAG" : "");
		}

		public void CollectMarkers(MatchContext ctx, PvpPlayer local, List<WorldMarker> into)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			if (_active && _carrier != null)
			{
				int carrierHome = _carrierHome;
				if (carrierHome >= 0)
				{
					into.Add(new WorldMarker(ctx.Drops.ZonePosition(carrierHome) + Vector3.up * 1.4f, PvpColors.For(_carrier.Index), "DELIVER HERE (" + _carrier.Name + ")"));
				}
			}
		}
	}
	internal class FreeForAllMode : GameModeBase
	{
		public override GameModeType Type => GameModeType.FreeForAll;

		public override void Tick(MatchContext ctx, float dt)
		{
			Combat.ProcessEliminations(ctx, teamMode: false);
		}

		public override void OnMatchEnd(MatchContext ctx)
		{
			bool tie;
			PvpPlayer pvpPlayer = ctx.Registry.Leader(out tie);
			if (pvpPlayer != null)
			{
				ctx.Announcer.Announce(tie ? $"It's a draw at {pvpPlayer.Score} eliminations!" : $"{pvpPlayer.Name} wins with {pvpPlayer.Score} eliminations!", 6f);
			}
		}

		public override string ScoreText(PvpPlayer p)
		{
			return p.Score + " elim";
		}
	}
	internal class HideAndSeekMode : GameModeBase
	{
		private readonly HashSet<string> _originalHiders = new HashSet<string>();

		private readonly Dictionary<string, int> _foundRank = new Dictionary<string, int>();

		private int _foundCounter;

		private float _lastScan;

		public override GameModeType Type => GameModeType.HideAndSeek;

		private static string KeyOf(PvpPlayer p)
		{
			return (p != null) ? p.StableKey : "";
		}

		private bool IsOriginalHider(PvpPlayer p)
		{
			return _originalHiders.Contains(KeyOf(p)) || (p != null && p.Name != null && 

MultiplayerPVP.MONO.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using DooDesch.FullHouse;
using FishNet;
using FishNet.Managing;
using FishNet.Object;
using FishySteamworks;
using HarmonyLib;
using MelonLoader;
using MelonLoader.Preferences;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using MultiplayerPVP;
using MultiplayerPVP.Addons;
using MultiplayerPVP.Compat;
using MultiplayerPVP.Config;
using MultiplayerPVP.Core;
using MultiplayerPVP.Modes;
using MultiplayerPVP.Net;
using MultiplayerPVP.UI;
using ScheduleOne;
using ScheduleOne.Cartel;
using ScheduleOne.Combat;
using ScheduleOne.Core.Items.Framework;
using ScheduleOne.DevUtilities;
using ScheduleOne.Doors;
using ScheduleOne.Economy;
using ScheduleOne.Equipping;
using ScheduleOne.FX;
using ScheduleOne.GameTime;
using ScheduleOne.ItemFramework;
using ScheduleOne.Law;
using ScheduleOne.Map;
using ScheduleOne.Money;
using ScheduleOne.NPCs;
using ScheduleOne.NPCs.Behaviour;
using ScheduleOne.Networking;
using ScheduleOne.PlayerScripts;
using ScheduleOne.PlayerScripts.Health;
using ScheduleOne.Police;
using ScheduleOne.Product;
using ScheduleOne.Product.Packaging;
using ScheduleOne.Storage;
using ScheduleOne.UI;
using ScheduleOne.UI.Multiplayer;
using ScheduleOne.Vision;
using SteamNetworkLib;
using SteamNetworkLib.Events;
using SteamNetworkLib.Models;
using SteamNetworkLib.Sync;
using Steamworks;
using TMPro;
using UnityEngine;
using UnityEngine.AI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("MultiplayerPVP")]
[assembly: AssemblyDescription("Schedule I MelonLoader Mod")]
[assembly: AssemblyCompany("Virtunerd")]
[assembly: AssemblyProduct("MultiplayerPVP")]
[assembly: AssemblyCopyright("Copyright (c) Virtunerd 2026")]
[assembly: ComVisible(false)]
[assembly: Guid("f83b02a6-396b-4b34-b8b7-3d0117d8d960")]
[assembly: MelonAdditionalDependencies(new string[] { "SteamNetworkLib" })]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: MelonInfo(typeof(MultiplayerPVPMod), "MultiplayerPVP", "1.0.6", "Virtunerd", null)]
[assembly: MelonGame(null, "Schedule I")]
[assembly: AssemblyFileVersion("1.0.6")]
[assembly: AssemblyInformationalVersion("1.0.6")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.6.0")]
[module: UnverifiableCode]
[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 DooDesch.FullHouse
{
	internal static class Lobbies
	{
		internal const int DefaultCapacity = 32;

		private const int HardMax = 250;

		private const int SafeMax = 32;

		private const string GuardName = "___DooDesch_FullHouse___";

		private static bool _installed;

		private static MelonPreferences_Entry<int> _capEntry;

		private static int _hostCap;

		internal static int Capacity
		{
			get
			{
				int num = ((_capEntry != null) ? _capEntry.Value : 32);
				if (num < 2)
				{
					num = 2;
				}
				if (num > 250)
				{
					num = 250;
				}
				return num;
			}
		}

		internal static int EffectiveCap => Math.Min(250, Math.Max(Capacity, _hostCap));

		internal static ulong CurrentLobbyId
		{
			get
			{
				try
				{
					SteamLobbyService val = Service();
					return (val != null) ? val._lobbyID : 0;
				}
				catch
				{
					return 0uL;
				}
			}
		}

		internal static int SeatCount
		{
			get
			{
				try
				{
					CSteamID[] array = Service()?._players;
					return (array != null) ? array.Length : 0;
				}
				catch
				{
					return 0;
				}
			}
		}

		internal static void Install()
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Expected O, but got Unknown
			if (_installed)
			{
				return;
			}
			_installed = true;
			try
			{
				if ((Object)(object)GameObject.Find("___DooDesch_FullHouse___") != (Object)null)
				{
					MelonLogger.Msg("[FullHouse] another copy is already active - standing down.");
					return;
				}
				GameObject val = new GameObject("___DooDesch_FullHouse___");
				Object.DontDestroyOnLoad((Object)(object)val);
				((Object)val).hideFlags = (HideFlags)61;
			}
			catch
			{
			}
			try
			{
				MelonPreferences_Category val2 = MelonPreferences.CreateCategory("FullHouse", "FullHouse");
				_capEntry = val2.CreateEntry<int>("Capacity", 32, "Max lobby players", "Maximum co-op players FullHouse seats (2-250). Values above 32 are unsupported and may destabilise the game.", false, false, (ValueValidator)null, (string)null);
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[FullHouse] preference registration failed: " + ex.Message);
			}
			if (Capacity > 32)
			{
				MelonLogger.Warning($"[FullHouse] capacity {Capacity} exceeds the tested maximum of {32} - expect instability.");
			}
			try
			{
				Harmony h = new Harmony("com.doodesch.fullhouse");
				Patch(h, typeof(SteamLobbyService), "Initialize", null, "Service_Initialize_Postfix");
				Patch(h, typeof(SteamLobbyService), "UpdateLobbyMembers", "Service_UpdateLobbyMembers_Prefix");
				Patch(h, typeof(SteamLobbyService), "CreateLobby", "Service_CreateLobby_Prefix");
				Patch(h, typeof(SteamLobbyService), "OnLobbyCreated", null, "Service_OnLobbyCreated_Postfix");
				Patch(h, typeof(SteamLobbyService), "OnLobbyEntered", null, "Service_OnLobbyEntered_Postfix");
				Patch(h, typeof(SteamLobbyService), "OpenInviteUI", "Service_OpenInviteUI_Prefix");
				Patch(h, typeof(SteamLobbyService), "LeaveLobby", null, "Service_LeaveLobby_Postfix");
				Patch(h, typeof(LobbyInterface), "Start", null, "LobbyInterface_Start_Postfix");
				Patch(h, typeof(LobbyInterface), "UpdateUI", null, "LobbyInterface_UpdateUI_Postfix");
				Patch(h, typeof(LobbyInterface), "UpdateButtons", null, "LobbyInterface_UpdateButtons_Postfix");
				MelonLogger.Msg($"[FullHouse] active - lobby cap raised to {Capacity}.");
			}
			catch (Exception ex2)
			{
				MelonLogger.Error("[FullHouse] patch install failed: " + ex2);
			}
		}

		private static void Patch(Harmony h, Type type, string method, string prefix = null, string postfix = null)
		{
			MethodInfo methodInfo = AccessTools.Method(type, method, (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				MelonLogger.Warning("[FullHouse] " + type.Name + "." + method + " not found - skipped.");
			}
			else
			{
				h.Patch((MethodBase)methodInfo, Hook(prefix), Hook(postfix), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}

		private static HarmonyMethod Hook(string name)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			return (name == null) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(Lobbies).GetMethod(name, AccessTools.all));
		}

		private static SteamLobbyService Service()
		{
			try
			{
				ILobbyService val = Singleton<Lobby>.Instance?._lobbyService;
				if (val == null)
				{
					return null;
				}
				return (SteamLobbyService)(object)((val is SteamLobbyService) ? val : null);
			}
			catch
			{
				return null;
			}
		}

		private static void EnsurePlayers(SteamLobbyService svc, int target)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (svc == null || target < 2)
				{
					return;
				}
				CSteamID[] players = svc._players;
				int num = ((players != null) ? players.Length : 0);
				if (num < target)
				{
					CSteamID[] array = (CSteamID[])(object)new CSteamID[target];
					for (int i = 0; i < num; i++)
					{
						array[i] = players[i];
					}
					svc._players = array;
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[FullHouse] resizing the lobby seat array failed: " + ex.Message);
			}
		}

		private static void Service_Initialize_Postfix(SteamLobbyService __instance)
		{
			EnsurePlayers(__instance, EffectiveCap);
			RaiseTransportCap();
		}

		private static void RaiseTransportCap()
		{
			try
			{
				FishySteamworks val = Object.FindObjectOfType<FishySteamworks>();
				if (!((Object)(object)val == (Object)null))
				{
					int effectiveCap = EffectiveCap;
					ushort maximumClients = val._maximumClients;
					if (maximumClients < effectiveCap)
					{
						val._maximumClients = (ushort)effectiveCap;
						MelonLogger.Msg($"[FullHouse] transport client limit {maximumClients} -> {effectiveCap}.");
					}
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[FullHouse] raising the transport client limit failed: " + ex.Message);
			}
		}

		private static void Service_UpdateLobbyMembers_Prefix(SteamLobbyService __instance)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				int val = 0;
				try
				{
					ulong num = ((__instance != null) ? __instance._lobbyID : 0);
					if (num != 0)
					{
						val = SteamMatchmaking.GetNumLobbyMembers(new CSteamID(num));
					}
				}
				catch
				{
				}
				EnsurePlayers(__instance, Math.Max(EffectiveCap, val));
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[FullHouse] seat guard failed: " + ex.Message);
			}
		}

		private static void Service_CreateLobby_Prefix(ref int maxPlayers)
		{
			int effectiveCap = EffectiveCap;
			if (maxPlayers < effectiveCap)
			{
				maxPlayers = effectiveCap;
			}
		}

		private static void Service_OnLobbyCreated_Postfix(LobbyCreated_t result)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Invalid comparison between Unknown and I4
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((int)result.m_eResult == 1)
				{
					RaiseTransportCap();
					CSteamID val = (CSteamID)result.m_ulSteamIDLobby;
					int effectiveCap = EffectiveCap;
					if (SteamMatchmaking.GetLobbyMemberLimit(val) < effectiveCap)
					{
						SteamMatchmaking.SetLobbyMemberLimit(val, effectiveCap);
					}
					int lobbyMemberLimit = SteamMatchmaking.GetLobbyMemberLimit(val);
					if (lobbyMemberLimit < effectiveCap)
					{
						MelonLogger.Warning($"[FullHouse] Steam kept the lobby member limit at {lobbyMemberLimit} (requested {effectiveCap}); advertising {lobbyMemberLimit}.");
					}
					SteamMatchmaking.SetLobbyData(val, "max_players", lobbyMemberLimit.ToString());
					SteamMatchmaking.SetLobbyData(val, "num_slots", lobbyMemberLimit.ToString());
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[FullHouse] OnLobbyCreated failed: " + ex.Message);
			}
		}

		private static void Service_OnLobbyEntered_Postfix(SteamLobbyService __instance, LobbyEnter_t result)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (__instance == null || __instance._lobbyID == 0)
				{
					return;
				}
				CSteamID val = (CSteamID)result.m_ulSteamIDLobby;
				int result2 = 0;
				int.TryParse(SteamMatchmaking.GetLobbyData(val, "max_players"), out result2);
				int lobbyMemberLimit = SteamMatchmaking.GetLobbyMemberLimit(val);
				if (lobbyMemberLimit > 0 && result2 > lobbyMemberLimit)
				{
					result2 = lobbyMemberLimit;
				}
				if (result2 > _hostCap)
				{
					if (result2 > 32)
					{
						MelonLogger.Warning($"[FullHouse] this lobby seats {result2}, past the tested maximum of {32} - expect instability.");
					}
					_hostCap = result2;
					int effectiveCap = EffectiveCap;
					EnsurePlayers(__instance, effectiveCap);
					EnsureSlots(Singleton<LobbyInterface>.Instance, effectiveCap);
					MelonLogger.Msg($"[FullHouse] adopted host lobby cap {effectiveCap}.");
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[FullHouse] host-cap sync failed: " + ex.Message);
			}
		}

		private static void Service_LeaveLobby_Postfix()
		{
			if (_hostCap != 0)
			{
				_hostCap = 0;
				MelonLogger.Msg($"[FullHouse] left the lobby - back to the local cap of {Capacity}.");
			}
		}

		private static bool Service_OpenInviteUI_Prefix(SteamLobbyService __instance)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (__instance == null)
				{
					return true;
				}
				if (__instance._lobbyID == 0)
				{
					__instance.CreateLobby(EffectiveCap);
					return false;
				}
				CSteamID val = default(CSteamID);
				((CSteamID)(ref val))..ctor(__instance._lobbyID);
				int num = EffectiveCap;
				int lobbyMemberLimit = SteamMatchmaking.GetLobbyMemberLimit(val);
				if (lobbyMemberLimit > 0 && lobbyMemberLimit < num)
				{
					num = lobbyMemberLimit;
				}
				if (SteamMatchmaking.GetNumLobbyMembers(val) >= num)
				{
					MelonLogger.Warning($"[FullHouse] lobby already at max capacity ({num}).");
					return false;
				}
				SteamFriends.ActivateGameOverlayInviteDialog(val);
				return false;
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[FullHouse] invite gate failed, falling back to vanilla: " + ex.Message);
				return true;
			}
		}

		private static void LobbyInterface_Start_Postfix(LobbyInterface __instance)
		{
			try
			{
				MelonCoroutines.Start(BuildUi(__instance));
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[FullHouse] UI coroutine start failed: " + ex.Message);
			}
		}

		private static void LobbyInterface_UpdateUI_Postfix(LobbyInterface __instance)
		{
			try
			{
				Lobby instance = Singleton<Lobby>.Instance;
				int num = (((Object)(object)instance != (Object)null) ? instance.PlayerCount : 0);
				if ((Object)(object)__instance?.LobbyTitle != (Object)null)
				{
					((TMP_Text)__instance.LobbyTitle).text = "Lobby (" + num + "/" + EffectiveCap + ")";
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[FullHouse] title sync failed: " + ex.Message);
			}
		}

		[HarmonyPriority(600)]
		private static void LobbyInterface_UpdateButtons_Postfix(LobbyInterface __instance)
		{
			try
			{
				Lobby instance = Singleton<Lobby>.Instance;
				if (!((Object)(object)instance == (Object)null) && !((Object)(object)__instance?.InviteButton == (Object)null))
				{
					((Component)__instance.InviteButton).gameObject.SetActive(instance.IsHost && instance.PlayerCount < EffectiveCap);
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[FullHouse] invite button sync failed: " + ex.Message);
			}
		}

		private static IEnumerator BuildUi(LobbyInterface ui)
		{
			while ((Object)(object)Singleton<Lobby>.Instance == (Object)null)
			{
				yield return null;
			}
			bool steamReady = true;
			try
			{
				steamReady = SteamManager.Initialized;
			}
			catch
			{
			}
			if (steamReady)
			{
				EnsurePlayers(Service(), EffectiveCap);
				EnsureSlots(ui, EffectiveCap);
			}
		}

		private static void EnsureSlots(LobbyInterface ui, int target)
		{
			if ((Object)(object)ui == (Object)null)
			{
				return;
			}
			try
			{
				RectTransform[] playerSlots = ui.PlayerSlots;
				if (playerSlots == null || playerSlots.Length == 0)
				{
					MelonLogger.Warning("[FullHouse] lobby PlayerSlots not found.");
					return;
				}
				int num = playerSlots.Length;
				if (num >= target)
				{
					RefreshPlayers(ui);
					return;
				}
				RectTransform val = playerSlots[num - 1];
				Transform parent = ((Transform)val).parent;
				RectTransform[] array = (RectTransform[])(object)new RectTransform[target];
				for (int i = 0; i < num; i++)
				{
					array[i] = playerSlots[i];
				}
				for (int j = num; j < target; j++)
				{
					GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, parent, false);
					((Object)val2).name = ((Object)((Component)val).gameObject).name + " (" + j + ")";
					array[j] = val2.GetComponent<RectTransform>();
				}
				ui.PlayerSlots = array;
				RefreshPlayers(ui);
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[FullHouse] building lobby UI failed: " + ex.Message);
			}
		}

		private static void RefreshPlayers(LobbyInterface ui)
		{
			try
			{
				AccessTools.Method(typeof(LobbyInterface), "UpdatePlayers", (Type[])null, (Type[])null)?.Invoke(ui, null);
			}
			catch
			{
			}
		}
	}
}
namespace MultiplayerPVP
{
	internal static class ImguiCompat
	{
		private static GUIStyle _style;

		internal static void DrawTexture(Rect position, Texture2D image)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			Blit(position, image);
		}

		internal static void DrawTexture(Rect position, Texture2D image, ScaleMode scaleMode)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			Blit(Fit(position, image, scaleMode), image);
		}

		private static Rect Fit(Rect position, Texture2D image, ScaleMode scaleMode)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Invalid comparison between Unknown and I4
			//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_00cb: 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_0054: Invalid comparison between Unknown and I4
			//IL_004d: 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)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)image == (Object)null || (int)scaleMode == 0)
			{
				return position;
			}
			float num = ((Texture)image).width;
			float num2 = ((Texture)image).height;
			if (num <= 0f || num2 <= 0f)
			{
				return position;
			}
			float num3 = (((int)scaleMode == 2) ? Mathf.Min(((Rect)(ref position)).width / num, ((Rect)(ref position)).height / num2) : Mathf.Max(((Rect)(ref position)).width / num, ((Rect)(ref position)).height / num2));
			float num4 = num * num3;
			float num5 = num2 * num3;
			return new Rect(((Rect)(ref position)).x + (((Rect)(ref position)).width - num4) * 0.5f, ((Rect)(ref position)).y + (((Rect)(ref position)).height - num5) * 0.5f, num4, num5);
		}

		private static void Blit(Rect position, Texture2D image)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Invalid comparison between Unknown and I4
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: 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_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			if ((Object)(object)image == (Object)null)
			{
				return;
			}
			Event current = Event.current;
			if (current != null && (int)current.type == 7)
			{
				if (_style == null)
				{
					_style = new GUIStyle();
				}
				_style.normal.background = image;
				Color backgroundColor = GUI.backgroundColor;
				GUI.backgroundColor = Color.white;
				_style.Draw(position, false, false, false, false);
				GUI.backgroundColor = backgroundColor;
			}
		}
	}
	public class MultiplayerPVPMod : MelonMod
	{
		private MatchController _controller;

		private PvpHud _hud;

		private PvpNet _net;

		internal static MultiplayerPVPMod Instance { get; private set; }

		internal MatchController Controller => _controller;

		internal PvpNet Net => _net;

		public override void OnInitializeMelon()
		{
			Instance = this;
			Lobbies.Install();
			PvpConfig.Load();
			_net = new PvpNet();
			_net.Init();
			_net.OnSighting += SightingRelay.OnReceived;
			_controller = new MatchController(_net);
			_hud = new PvpHud();
			PvpAddonManager.Init(_net);
			RiotChaos.Init();
			MelonLogger.Msg($"[MultiplayerPVP] v{((MelonBase)this).Info.Version} ready. Press {(object)(KeyCode)PvpConfig.PanelKey.Value} in-game to open the host panel.");
		}

		public override void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			try
			{
				RiotChaos.OnSceneLoaded();
			}
			catch
			{
			}
			try
			{
				_net?.Init();
				_controller?.Cleanup();
				_hud?.Reset();
				SightingRelay.Reset();
				ViewLock.Release();
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("OnSceneWasLoaded: " + ex.Message);
			}
			try
			{
				PvpAddonManager.SceneLoaded(buildIndex, sceneName);
			}
			catch (Exception ex2)
			{
				MelonLogger.Warning("OnSceneWasLoaded(addons): " + ex2.Message);
			}
		}

		public override void OnDeinitializeMelon()
		{
			try
			{
				RiotChaos.Deinit();
			}
			catch
			{
			}
			try
			{
				PvpAddonManager.Deinit();
			}
			catch
			{
			}
			try
			{
				ViewLock.Release();
				_controller?.Cleanup();
				_net?.Dispose();
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("OnDeinitializeMelon: " + ex.Message);
			}
		}

		public override void OnUpdate()
		{
			if (_controller == null)
			{
				return;
			}
			try
			{
				if (Input.GetKeyDown((KeyCode)PvpConfig.PanelKey.Value))
				{
					if (_controller.Phase == MatchPhase.Idle)
					{
						_hud.PanelOpen = !_hud.PanelOpen;
					}
					else if (_controller.Phase == MatchPhase.Active && !_controller.IsRemote)
					{
						_hud.EndPromptOpen = !_hud.EndPromptOpen;
					}
				}
				if (_controller.Phase != MatchPhase.Active)
				{
					_hud.EndPromptOpen = false;
				}
				try
				{
					Player local = Player.Local;
					if ((Object)(object)local != (Object)null)
					{
						_net?.SetLocalIdentity(local.PlayerCode);
					}
				}
				catch
				{
				}
				_net?.Tick();
				_controller.Tick(Time.deltaTime);
				PvpAddonManager.Tick(Time.deltaTime, _controller.Phase, _controller.ModeType, _controller.Day);
				RiotChaos.Tick(Time.deltaTime, _controller);
				UnlimitedAmmo.Tick(_controller);
				DoubleJump.Tick(_controller);
				bool locked = _hud.PanelOpen || _hud.EndPromptOpen || (_controller.Phase == MatchPhase.EndOfDay && !_controller.IsRemote);
				ViewLock.Set(locked);
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("OnUpdate: " + ex.Message);
			}
		}

		public override void OnGUI()
		{
			if (_hud == null)
			{
				return;
			}
			try
			{
				_hud.Draw(_controller);
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("OnGUI: " + ex.Message);
			}
			try
			{
				PvpAddonManager.DrawGui();
			}
			catch (Exception ex2)
			{
				MelonLogger.Warning("OnGUI(addons): " + ex2.Message);
			}
		}
	}
}
namespace MultiplayerPVP.UI
{
	internal class PvpHud
	{
		private struct DispRow
		{
			public int ColorIdx;

			public string Text;

			public int Kills;

			public int Downs;

			public int Arrests;

			public int BagsCap;

			public int BagsLost;

			public int WpnLost;

			public int WpnWon;

			public int PlayerIndex;

			public string Days;
		}

		internal bool PanelOpen;

		internal bool EndPromptOpen;

		private static Texture2D _white;

		private readonly List<WorldMarker> _markers = new List<WorldMarker>();

		private Camera _cam;

		private int _camRevalidate;

		private int _hoverMode = -1;

		private PvpMatchToggle _hoverToggle;

		private readonly List<DispRow> _rows = new List<DispRow>();

		private static Texture2D White
		{
			get
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_001d: Expected O, but got Unknown
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)_white == (Object)null)
				{
					_white = new Texture2D(1, 1);
					_white.SetPixel(0, 0, Color.white);
					_white.Apply();
				}
				return _white;
			}
		}

		private static string FormatDays(string dotted)
		{
			return string.IsNullOrEmpty(dotted) ? "" : dotted.Replace(".", ", ");
		}

		internal void Reset()
		{
			_cam = null;
			_camRevalidate = 0;
			_markers.Clear();
			PanelOpen = false;
			EndPromptOpen = false;
		}

		internal void Draw(MatchController mc)
		{
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			if (mc == null)
			{
				return;
			}
			Safe(delegate
			{
				DrawBanner(mc);
			});
			Safe(delegate
			{
				DrawLocalBanner(mc);
			});
			switch (mc.Phase)
			{
			case MatchPhase.Countdown:
			case MatchPhase.Active:
			{
				bool flag = true;
				Safe(delegate
				{
					DrawCountdown(mc);
				});
				Safe(delegate
				{
					DrawScoreboard(mc, 220f);
				});
				Safe(delegate
				{
					DrawMarkers(mc);
				});
				if (mc.IsRemote)
				{
					Safe(delegate
					{
						DrawClientModeCard(mc);
					});
				}
				break;
			}
			case MatchPhase.EndOfDay:
				Safe(delegate
				{
					DrawEndOfDayMenu(mc);
				});
				break;
			case MatchPhase.Idle:
				if (PanelOpen)
				{
					Safe(delegate
					{
						DrawHostPanel(mc);
					});
				}
				break;
			}
			if (EndPromptOpen && mc.Phase == MatchPhase.Active && !mc.IsRemote)
			{
				Safe(delegate
				{
					DrawEndMatchPrompt(mc);
				});
			}
			GUI.color = Color.white;
		}

		private static void Safe(Action draw)
		{
			try
			{
				draw();
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("HUD draw: " + ex.Message);
			}
		}

		private void DrawBanner(MatchController mc)
		{
			//IL_0022: 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)
			//IL_0030: 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)
			//IL_0041: Expected O, but got Unknown
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			if (mc.Announcer.HasBanner)
			{
				GUIStyle val = new GUIStyle(GUI.skin.label)
				{
					fontSize = 40,
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)4
				};
				Rect val2 = default(Rect);
				((Rect)(ref val2))..ctor(0f, (float)Screen.height * 0.14f, (float)Screen.width, 60f);
				GUI.color = Color.black;
				GUI.Label(new Rect(((Rect)(ref val2)).x + 2f, ((Rect)(ref val2)).y + 2f, ((Rect)(ref val2)).width, ((Rect)(ref val2)).height), mc.Announcer.Banner, val);
				GUI.color = new Color(1f, 0.85f, 0.2f);
				GUI.Label(val2, mc.Announcer.Banner, val);
				GUI.color = Color.white;
			}
		}

		private void DrawLocalBanner(MatchController mc)
		{
			//IL_0022: 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)
			//IL_0030: 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)
			//IL_0041: Expected O, but got Unknown
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			if (mc.Announcer.HasLocalBanner)
			{
				GUIStyle val = new GUIStyle(GUI.skin.label)
				{
					fontSize = 26,
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)4
				};
				Rect val2 = default(Rect);
				((Rect)(ref val2))..ctor(0f, (float)Screen.height * 0.21f, (float)Screen.width, 44f);
				GUI.color = Color.black;
				GUI.Label(new Rect(((Rect)(ref val2)).x + 2f, ((Rect)(ref val2)).y + 2f, ((Rect)(ref val2)).width, ((Rect)(ref val2)).height), mc.Announcer.LocalBanner, val);
				GUI.color = mc.Announcer.LocalBannerColor;
				GUI.Label(val2, mc.Announcer.LocalBanner, val);
				GUI.color = Color.white;
			}
		}

		private void DrawCountdown(MatchController mc)
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Expected O, but got Unknown
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			string text;
			if (mc.Phase == MatchPhase.Countdown)
			{
				text = "Starting…";
			}
			else
			{
				int num = Mathf.Max(0, Mathf.CeilToInt(mc.RemainingSeconds));
				text = $"{GameModeInfo.Title(mc.ModeType)}  ·  Day {mc.Day}  ·  {num / 60:0}:{num % 60:00}";
			}
			GUIStyle val = new GUIStyle(GUI.skin.label)
			{
				fontSize = 20,
				fontStyle = (FontStyle)1,
				alignment = (TextAnchor)4
			};
			Rect val2 = default(Rect);
			((Rect)(ref val2))..ctor((float)Screen.width * 0.5f - 220f, 70f, 440f, 28f);
			GUI.color = new Color(0f, 0f, 0f, 0.55f);
			ImguiCompat.DrawTexture(val2, White);
			GUI.color = Color.white;
			GUI.Label(val2, text, val);
		}

		private void DrawLoadoutCard(Rect anchor)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Expected O, but got Unknown
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Expected O, but got Unknown
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
			List<string> list = StartingLoadout.Buttons();
			float num = 210f;
			float num2 = Mathf.Max(((Rect)(ref anchor)).height, 64f + (float)list.Count * 24f + 60f);
			Rect position = default(Rect);
			((Rect)(ref position))..ctor(((Rect)(ref anchor)).x - num - 10f, ((Rect)(ref anchor)).y, num, num2);
			GUI.color = new Color(0.05f, 0.05f, 0.08f, 0.92f);
			ImguiCompat.DrawTexture(position, White);
			GUI.color = Color.white;
			GUIStyle val = new GUIStyle(GUI.skin.label)
			{
				fontSize = 15,
				fontStyle = (FontStyle)1
			};
			GUIStyle val2 = new GUIStyle(GUI.skin.label)
			{
				fontSize = 11,
				wordWrap = true
			};
			GUI.Label(new Rect(((Rect)(ref position)).x + 10f, ((Rect)(ref position)).y + 8f, num - 20f, 20f), "STARTING LOADOUT", val);
			GUI.Label(new Rect(((Rect)(ref position)).x + 10f, ((Rect)(ref position)).y + 28f, num - 20f, 30f), "Every player gets the checked items at round start.", val2);
			float num3 = ((Rect)(ref position)).y + 62f;
			for (int i = 0; i < list.Count; i++)
			{
				string id = list[i];
				bool flag = StartingLoadout.IsChecked(id);
				bool flag2 = GUI.Toggle(new Rect(((Rect)(ref position)).x + 12f, num3, num - 24f, 22f), flag, " " + StartingLoadout.LabelOf(id));
				if (flag2 != flag)
				{
					StartingLoadout.SetChecked(id, flag2);
				}
				num3 += 24f;
			}
			num3 += 6f;
			GUI.color = new Color(1f, 1f, 1f, 0.15f);
			ImguiCompat.DrawTexture(new Rect(((Rect)(ref position)).x + 10f, num3, num - 20f, 1f), White);
			GUI.color = Color.white;
			num3 += 6f;
			bool flag3 = UnlimitedAmmo.Checked;
			bool flag4 = GUI.Toggle(new Rect(((Rect)(ref position)).x + 12f, num3, num - 24f, 22f), flag3, " unlimited ammo (this round)");
			if (flag4 != flag3)
			{
				UnlimitedAmmo.SetChecked(flag4);
			}
			num3 += 24f;
			bool flag5 = DoubleJump.Checked;
			bool flag6 = GUI.Toggle(new Rect(((Rect)(ref position)).x + 12f, num3, num - 24f, 22f), flag5, " double jump (this round)");
			if (flag6 != flag5)
			{
				DoubleJump.SetChecked(flag6);
			}
		}

		private void DrawModeInfoCard(Rect anchor)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: 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_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Expected O, but got Unknown
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			Rect position = default(Rect);
			((Rect)(ref position))..ctor(((Rect)(ref anchor)).xMax + 10f, ((Rect)(ref anchor)).y, 240f, ((Rect)(ref anchor)).height);
			GUI.color = new Color(0.05f, 0.05f, 0.08f, 0.92f);
			ImguiCompat.DrawTexture(position, White);
			GUI.color = Color.white;
			GUIStyle val = new GUIStyle(GUI.skin.label)
			{
				fontSize = 15,
				fontStyle = (FontStyle)1,
				wordWrap = true
			};
			GUIStyle val2 = new GUIStyle(GUI.skin.label)
			{
				fontSize = 12,
				wordWrap = true
			};
			if (_hoverToggle != null)
			{
				GUI.Label(new Rect(((Rect)(ref position)).x + 10f, ((Rect)(ref position)).y + 10f, 220f, 44f), _hoverToggle.Label + " (modifier)", val);
				GUI.Label(new Rect(((Rect)(ref position)).x + 10f, ((Rect)(ref position)).y + 48f, 220f, ((Rect)(ref position)).height - 58f), _hoverToggle.Description, val2);
			}
			else if (_hoverMode >= 0)
			{
				GameModeType hoverMode = (GameModeType)_hoverMode;
				GUI.Label(new Rect(((Rect)(ref position)).x + 10f, ((Rect)(ref position)).y + 10f, 220f, 44f), GameModeInfo.Title(hoverMode), val);
				GUI.Label(new Rect(((Rect)(ref position)).x + 10f, ((Rect)(ref position)).y + 48f, 220f, ((Rect)(ref position)).height - 58f), GameModeInfo.Description(hoverMode), val2);
			}
			else
			{
				GUI.Label(new Rect(((Rect)(ref position)).x + 10f, ((Rect)(ref position)).y + 10f, 220f, ((Rect)(ref position)).height - 20f), "Hover a mode button to see what it does.", val2);
			}
		}

		private void DrawClientModeCard(MatchController mc)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: 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)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Expected O, but got Unknown
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			Rect position = default(Rect);
			((Rect)(ref position))..ctor(12f, 70f, 290f, 116f);
			GUI.color = new Color(0f, 0f, 0f, 0.6f);
			ImguiCompat.DrawTexture(position, White);
			GUI.color = Color.white;
			GUIStyle val = new GUIStyle(GUI.skin.label)
			{
				fontSize = 15,
				fontStyle = (FontStyle)1,
				wordWrap = true
			};
			GUIStyle val2 = new GUIStyle(GUI.skin.label)
			{
				fontSize = 12,
				wordWrap = true
			};
			GUI.Label(new Rect(((Rect)(ref position)).x + 10f, ((Rect)(ref position)).y + 8f, 270f, 22f), GameModeInfo.Title(mc.ModeType), val);
			GUI.Label(new Rect(((Rect)(ref position)).x + 10f, ((Rect)(ref position)).y + 32f, 270f, 76f), GameModeInfo.Description(mc.ModeType), val2);
		}

		private void BuildRows(MatchController mc)
		{
			_rows.Clear();
			if (mc.IsRemote ? (mc.RemoteTeamRows.Count > 0) : mc.IsTeamScoredMode)
			{
				if (mc.IsRemote)
				{
					for (int i = 0; i < mc.RemoteTeamRows.Count; i++)
					{
						SnapTeamRow snapTeamRow = mc.RemoteTeamRows[i];
						_rows.Add(new DispRow
						{
							ColorIdx = snapTeamRow.Team,
							Text = snapTeamRow.Name + "  —  " + snapTeamRow.Score,
							Kills = snapTeamRow.Kills,
							Downs = snapTeamRow.Downs,
							Arrests = snapTeamRow.Arrests,
							BagsCap = snapTeamRow.BagsCaptured,
							BagsLost = snapTeamRow.BagsLost,
							WpnLost = snapTeamRow.WeaponsLost,
							WpnWon = snapTeamRow.WeaponsWon,
							PlayerIndex = -1
						});
					}
					return;
				}
				int activeTeamCount = mc.ActiveTeamCount;
				List<PvpPlayer> players = mc.Registry.Players;
				for (int j = 0; j < activeTeamCount; j++)
				{
					int num = 0;
					int num2 = 0;
					int num3 = 0;
					int num4 = 0;
					int num5 = 0;
					int num6 = 0;
					int num7 = 0;
					for (int k = 0; k < players.Count; k++)
					{
						PvpPlayer pvpPlayer = players[k];
						if (pvpPlayer.Team == j)
						{
							num += pvpPlayer.Kills;
							num2 += pvpPlayer.Downs;
							num3 += pvpPlayer.Arrests;
							num4 += pvpPlayer.BagsCaptured;
							num5 += pvpPlayer.BagsLost;
							num6 += pvpPlayer.WeaponsLost;
							num7 += pvpPlayer.WeaponsWon;
						}
					}
					string text = "";
					try
					{
						if (mc.CurrentMode != null)
						{
							text = mc.CurrentMode.TeamScoreText(mc.Context, j);
						}
					}
					catch
					{
					}
					_rows.Add(new DispRow
					{
						ColorIdx = j,
						Text = mc.Registry.TeamLabel(j) + "  —  " + text,
						Kills = num,
						Downs = num2,
						Arrests = num3,
						BagsCap = num4,
						BagsLost = num5,
						WpnLost = num6,
						WpnWon = num7,
						PlayerIndex = -1
					});
				}
				return;
			}
			if (mc.IsRemote)
			{
				for (int l = 0; l < mc.RemoteRows.Count; l++)
				{
					SnapRow snapRow = mc.RemoteRows[l];
					_rows.Add(new DispRow
					{
						ColorIdx = snapRow.Index,
						Text = snapRow.Name + "  —  " + snapRow.Score,
						Kills = snapRow.Kills,
						Downs = snapRow.Downs,
						Arrests = snapRow.Arrests,
						BagsCap = snapRow.BagsCaptured,
						BagsLost = snapRow.BagsLost,
						WpnLost = snapRow.WeaponsLost,
						WpnWon = snapRow.WeaponsWon,
						PlayerIndex = snapRow.Index,
						Days = FormatDays(snapRow.History)
					});
				}
				return;
			}
			List<PvpPlayer> players2 = mc.Registry.Players;
			for (int m = 0; m < players2.Count; m++)
			{
				PvpPlayer pvpPlayer2 = players2[m];
				string text2 = "";
				string text3 = pvpPlayer2.Name;
				try
				{
					if (mc.CurrentMode != null)
					{
						text2 = mc.CurrentMode.ScoreText(pvpPlayer2);
						text3 = mc.CurrentMode.DisplayName(pvpPlayer2);
					}
				}
				catch
				{
				}
				string days = "";
				List<int> list = mc.HistoryOf(pvpPlayer2);
				if (list != null && list.Count >= 2)
				{
					days = string.Join(", ", list);
				}
				_rows.Add(new DispRow
				{
					ColorIdx = pvpPlayer2.Index,
					Text = text3 + "  —  " + text2,
					Kills = pvpPlayer2.Kills,
					Downs = pvpPlayer2.Downs,
					Arrests = pvpPlayer2.Arrests,
					BagsCap = pvpPlayer2.BagsCaptured,
					BagsLost = pvpPlayer2.BagsLost,
					WpnLost = pvpPlayer2.WeaponsLost,
					WpnWon = pvpPlayer2.WeaponsWon,
					PlayerIndex = pvpPlayer2.Index,
					Days = days
				});
			}
		}

		private void DrawScoreboard(MatchController mc, float width)
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: 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_00c1: Expected O, but got Unknown
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Expected O, but got Unknown
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			if (!mc.IsRemote && mc.CurrentMode == null)
			{
				return;
			}
			BuildRows(mc);
			int count = _rows.Count;
			if (count != 0)
			{
				float num = 26 + count * 22 + 8;
				Rect position = default(Rect);
				((Rect)(ref position))..ctor((float)Screen.width - width - 12f, 50f, width, num);
				GUI.color = new Color(0f, 0f, 0f, 0.55f);
				ImguiCompat.DrawTexture(position, White);
				GUI.color = Color.white;
				GUIStyle val = new GUIStyle(GUI.skin.label)
				{
					fontSize = 14,
					fontStyle = (FontStyle)1
				};
				GUI.Label(new Rect(((Rect)(ref position)).x + 8f, ((Rect)(ref position)).y + 4f, width - 16f, 20f), "SCOREBOARD", val);
				GUIStyle val2 = new GUIStyle(GUI.skin.label)
				{
					fontSize = 13
				};
				for (int i = 0; i < count; i++)
				{
					float num2 = ((Rect)(ref position)).y + 26f + (float)(i * 22);
					DispRow dispRow = _rows[i];
					GUI.color = PvpColors.For(dispRow.ColorIdx);
					ImguiCompat.DrawTexture(new Rect(((Rect)(ref position)).x + 8f, num2 + 4f, 10f, 10f), White);
					GUI.color = Color.white;
					GUI.Label(new Rect(((Rect)(ref position)).x + 24f, num2, width - 32f, 20f), dispRow.Text, val2);
				}
			}
		}

		private void DrawMarkers(MatchController mc)
		{
			//IL_02f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Expected O, but got Unknown
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_0263: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_029d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c2: Unknown result type (might be due to invalid IL or missing references)
			if (_camRevalidate-- <= 0 || (Object)(object)_cam == (Object)null)
			{
				_cam = Camera.main;
				_camRevalidate = 30;
			}
			if ((Object)(object)_cam == (Object)null)
			{
				return;
			}
			_markers.Clear();
			if (mc.IsRemote)
			{
				List<SnapMarker> remoteMarkers = mc.RemoteMarkers;
				for (int i = 0; i < remoteMarkers.Count; i++)
				{
					_markers.Add(new WorldMarker(remoteMarkers[i].Pos, remoteMarkers[i].Color, remoteMarkers[i].Label, remoteMarkers[i].Team));
				}
			}
			else
			{
				if (!(mc.CurrentMode is IWorldMarkers worldMarkers))
				{
					return;
				}
				try
				{
					worldMarkers.CollectMarkers(mc.Context, mc.Registry.Local, _markers);
				}
				catch
				{
					return;
				}
			}
			if (_markers.Count == 0)
			{
				return;
			}
			int num = mc.LocalTeam();
			GUIStyle val = new GUIStyle(GUI.skin.label)
			{
				fontSize = 12,
				fontStyle = (FontStyle)1,
				alignment = (TextAnchor)4
			};
			for (int j = 0; j < _markers.Count; j++)
			{
				WorldMarker worldMarker = _markers[j];
				if (worldMarker.Team < 0 || worldMarker.Team == num)
				{
					Vector3 val2;
					try
					{
						val2 = _cam.WorldToScreenPoint(worldMarker.Pos);
					}
					catch
					{
						continue;
					}
					if (!(val2.z <= 0f))
					{
						float x = val2.x;
						float num2 = (float)Screen.height - val2.y;
						GUI.color = worldMarker.Color;
						ImguiCompat.DrawTexture(new Rect(x - 2f, num2 - 80f, 4f, 80f), White);
						ImguiCompat.DrawTexture(new Rect(x - 7f, num2 - 7f, 14f, 14f), White);
						GUI.color = Color.black;
						GUI.Label(new Rect(x - 99f, num2 - 104f, 200f, 18f), worldMarker.Label, val);
						GUI.color = worldMarker.Color;
						GUI.Label(new Rect(x - 100f, num2 - 105f, 200f, 18f), worldMarker.Label, val);
					}
				}
			}
			GUI.color = Color.white;
		}

		private void DrawEndOfDayMenu(MatchController mc)
		{
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Expected O, but got Unknown
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Expected O, but got Unknown
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Expected O, but got Unknown
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Expected O, but got Unknown
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0298: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_04cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_04de: Expected O, but got Unknown
			//IL_0439: Unknown result type (might be due to invalid IL or missing references)
			//IL_043e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0447: Unknown result type (might be due to invalid IL or missing references)
			//IL_0451: Expected O, but got Unknown
			//IL_0460: Unknown result type (might be due to invalid IL or missing references)
			//IL_0490: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_056d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0598: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_04fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0522: Unknown result type (might be due to invalid IL or missing references)
			//IL_0534: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0654: Unknown result type (might be due to invalid IL or missing references)
			BuildRows(mc);
			int count = _rows.Count;
			float num = ModeGridHeight();
			float num2 = Mathf.Max(0f, num - 104f);
			float num3 = 560f;
			float num4 = Mathf.Clamp(78f + (float)count * 46f + 200f + num2, 470f + num2, (float)(Screen.height - 40));
			Rect val = default(Rect);
			((Rect)(ref val))..ctor((float)Screen.width * 0.5f - num3 / 2f, (float)Screen.height * 0.5f - num4 / 2f, num3, num4);
			GUI.color = new Color(0.05f, 0.05f, 0.08f, 0.92f);
			ImguiCompat.DrawTexture(val, White);
			GUI.color = Color.white;
			GUIStyle val2 = new GUIStyle(GUI.skin.label)
			{
				fontSize = 24,
				fontStyle = (FontStyle)1,
				alignment = (TextAnchor)4
			};
			GUI.Label(new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).y + 12f, num3, 32f), $"END OF DAY {mc.Day}", val2);
			GUIStyle val3 = new GUIStyle(GUI.skin.label)
			{
				fontSize = 15,
				alignment = (TextAnchor)4
			};
			GUI.Label(new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).y + 46f, num3, 22f), mc.DayResult ?? "", val3);
			GUIStyle val4 = new GUIStyle(GUI.skin.label)
			{
				fontSize = 14
			};
			GUIStyle val5 = new GUIStyle(GUI.skin.label)
			{
				fontSize = 12
			};
			float num5 = ((Rect)(ref val)).y + 78f;
			int num6 = Mathf.Max(1, Mathf.FloorToInt((num4 - 268f - num2) / 46f));
			if (count > num6)
			{
				num6 = Mathf.Max(1, num6 - 1);
			}
			int num7 = Mathf.Min(count, num6);
			for (int i = 0; i < num7; i++)
			{
				DispRow dispRow = _rows[i];
				string text = dispRow.Text;
				if (!string.IsNullOrEmpty(dispRow.Days))
				{
					text = text + "   (days: " + dispRow.Days + ")";
				}
				float num8 = num5 + (float)i * 46f;
				GUI.color = PvpColors.For(dispRow.ColorIdx);
				ImguiCompat.DrawTexture(new Rect(((Rect)(ref val)).x + 30f, num8 + 4f, 10f, 10f), White);
				GUI.color = Color.white;
				GUI.Label(new Rect(((Rect)(ref val)).x + 48f, num8, num3 - 80f, 20f), $"{i + 1}. {text}", val4);
				string text2 = mc.ModeType switch
				{
					GameModeType.StealTheBags => $"Bags captured {dispRow.BagsCap}    ·    Bags lost {dispRow.BagsLost}", 
					GameModeType.Teams => $"Kills {dispRow.Kills}  ·  Downs {dispRow.Downs}  ·  Weapons won {dispRow.WpnWon}  ·  Weapons lost {dispRow.WpnLost}", 
					_ => $"Kills {dispRow.Kills}    ·    Downs {dispRow.Downs}    ·    Cuffs {dispRow.Arrests}", 
				};
				GUI.color = new Color(0.78f, 0.82f, 0.9f);
				GUI.Label(new Rect(((Rect)(ref val)).x + 48f, num8 + 22f, num3 - 80f, 18f), text2, val5);
				GUI.color = Color.white;
			}
			if (count > num7)
			{
				GUIStyle val6 = new GUIStyle(GUI.skin.label)
				{
					fontSize = 12,
					fontStyle = (FontStyle)2
				};
				GUI.color = new Color(0.7f, 0.75f, 0.85f);
				GUI.Label(new Rect(((Rect)(ref val)).x + 48f, num5 + (float)num7 * 46f, num3 - 80f, 18f), $"+ {count - num7} more…", val6);
				GUI.color = Color.white;
			}
			GUIStyle val7 = new GUIStyle(GUI.skin.label)
			{
				fontSize = 13,
				alignment = (TextAnchor)4
			};
			if (mc.IsRemote)
			{
				GUI.color = new Color(1f, 0.85f, 0.3f);
				GUI.Label(new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).y + num4 - 90f, num3, 22f), "Waiting for the host to choose the next mode…", val7);
				GUI.color = Color.white;
				return;
			}
			float num9 = ((Rect)(ref val)).y + num4 - 168f - num2;
			GUI.Label(new Rect(((Rect)(ref val)).x, num9 - 22f, num3, 18f), "Host: choose the next mode to start the morning", val7);
			DrawModeGrid(mc, new Rect(((Rect)(ref val)).x + 20f, num9, num3 - 40f, num), fresh: true);
			DrawModeInfoCard(val);
			DrawLoadoutCard(val);
			float num10 = ((Rect)(ref val)).y + num4 - 44f;
			if (mc.HasActiveMode && GUI.Button(new Rect(((Rect)(ref val)).x + 20f, num10, (num3 - 50f) / 2f, 30f), "Continue " + GameModeInfo.Title(mc.ModeType) + " (next day)"))
			{
				mc.RequestContinue();
			}
			if (GUI.Button(new Rect(((Rect)(ref val)).x + 30f + (num3 - 50f) / 2f, num10, (num3 - 50f) / 2f, 30f), "Stop match"))
			{
				mc.RequestStop();
			}
		}

		private void DrawHostPanel(MatchController mc)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: 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_00b6: Expected O, but got Unknown
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Expected O, but got Unknown
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: 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)
			//IL_012e: Expected O, but got Unknown
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_027b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
			float num = ModeGridHeight();
			float num2 = 540f;
			float num3 = 250f + Mathf.Max(0f, num - 104f);
			Rect val = default(Rect);
			((Rect)(ref val))..ctor((float)Screen.width * 0.5f - num2 / 2f, (float)Screen.height * 0.5f - num3 / 2f, num2, num3);
			GUI.color = new Color(0.05f, 0.05f, 0.08f, 0.92f);
			ImguiCompat.DrawTexture(val, White);
			GUI.color = Color.white;
			GUIStyle val2 = new GUIStyle(GUI.skin.label)
			{
				fontSize = 22,
				fontStyle = (FontStyle)1,
				alignment = (TextAnchor)4
			};
			GUI.Label(new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).y + 12f, num2, 30f), "MULTIPLAYER PVP", val2);
			GUIStyle val3 = new GUIStyle(GUI.skin.label)
			{
				fontSize = 13,
				alignment = (TextAnchor)4
			};
			GUIStyle val4 = new GUIStyle(GUI.skin.label)
			{
				fontSize = 15,
				alignment = (TextAnchor)4,
				wordWrap = true
			};
			if (!mc.IsMultiplayer)
			{
				GUI.color = new Color(1f, 0.7f, 0.3f);
				GUI.Label(new Rect(((Rect)(ref val)).x + 20f, ((Rect)(ref val)).y + 70f, num2 - 40f, 80f), "This mod is multiplayer-only.\nHost or join a co-op lobby with 2+ players,\nthen press the host key again.", val4);
				GUI.color = Color.white;
			}
			else if (!mc.IsHost)
			{
				GUI.color = new Color(1f, 0.7f, 0.3f);
				GUI.Label(new Rect(((Rect)(ref val)).x + 20f, ((Rect)(ref val)).y + 70f, num2 - 40f, 80f), "Only the host controls the match.\nThe host picks the game mode.", val4);
				GUI.color = Color.white;
			}
			else
			{
				GUI.Label(new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).y + 44f, num2, 18f), $"{SessionUtil.PlayerCount()} player(s) · pick a mode to start", val3);
				Rect area = default(Rect);
				((Rect)(ref area))..ctor(((Rect)(ref val)).x + 20f, ((Rect)(ref val)).y + 70f, num2 - 40f, num);
				DrawModeGrid(mc, area, fresh: true);
				DrawModeInfoCard(val);
				DrawLoadoutCard(val);
			}
			if (GUI.Button(new Rect(((Rect)(ref val)).x + num2 - 110f, ((Rect)(ref val)).y + num3 - 34f, 90f, 26f), "Close"))
			{
				PanelOpen = false;
			}
		}

		private void DrawEndMatchPrompt(MatchController mc)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: 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_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Expected O, but got Unknown
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Expected O, but got Unknown
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Expected O, but got Unknown
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			float num = 440f;
			float num2 = 180f;
			Rect position = default(Rect);
			((Rect)(ref position))..ctor((float)Screen.width * 0.5f - num / 2f, (float)Screen.height * 0.5f - num2 / 2f, num, num2);
			GUI.color = new Color(0.05f, 0.05f, 0.08f, 0.95f);
			ImguiCompat.DrawTexture(position, White);
			GUI.color = Color.white;
			GUIStyle val = new GUIStyle(GUI.skin.label)
			{
				fontSize = 20,
				fontStyle = (FontStyle)1,
				alignment = (TextAnchor)4
			};
			GUI.Label(new Rect(((Rect)(ref position)).x, ((Rect)(ref position)).y + 16f, num, 28f), "END MATCH EARLY?", val);
			GUIStyle val2 = new GUIStyle(GUI.skin.label)
			{
				fontSize = 14,
				alignment = (TextAnchor)4,
				wordWrap = true
			};
			GUI.Label(new Rect(((Rect)(ref position)).x + 24f, ((Rect)(ref position)).y + 52f, num - 48f, 44f), "End the running match now? The countdown drops to 3 seconds and the day is scored as normal.", val2);
			if (GUI.Button(new Rect(((Rect)(ref position)).x + 40f, ((Rect)(ref position)).y + num2 - 64f, num - 80f, 38f), "End match early"))
			{
				EndPromptOpen = false;
				mc.RequestEndEarly();
			}
			GUIStyle val3 = new GUIStyle(GUI.skin.label)
			{
				fontSize = 11,
				alignment = (TextAnchor)4
			};
			GUI.color = new Color(0.7f, 0.75f, 0.85f);
			GUI.Label(new Rect(((Rect)(ref position)).x, ((Rect)(ref position)).y + num2 - 22f, num, 16f), $"Press {(object)(KeyCode)PvpConfig.PanelKey.Value} again to cancel", val3);
			GUI.color = Color.white;
		}

		private static float ModeGridHeight()
		{
			int num = 7 + MatchToggles.Snapshot().Length;
			int num2 = (num + 3) / 4;
			return (float)num2 * 48f + (float)(num2 - 1) * 8f;
		}

		private void DrawModeGrid(MatchController mc, Rect area, bool fresh)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: 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_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			int num = 7;
			float num2 = (((Rect)(ref area)).width - 24f) / 4f;
			float num3 = 48f;
			_hoverMode = -1;
			_hoverToggle = null;
			Vector2 val = (Vector2)((Event.current != null) ? Event.current.mousePosition : new Vector2(-1f, -1f));
			Rect val2 = default(Rect);
			for (int i = 0; i < num; i++)
			{
				int num4 = i / 4;
				int num5 = i % 4;
				((Rect)(ref val2))..ctor(((Rect)(ref area)).x + (float)num5 * (num2 + 8f), ((Rect)(ref area)).y + (float)num4 * (num3 + 8f), num2, num3);
				if (((Rect)(ref val2)).Contains(val))
				{
					_hoverMode = i;
				}
				GameModeType gameModeType = (GameModeType)i;
				if (GUI.Button(val2, $"{i + 1}. {GameModeInfo.Title(gameModeType)}"))
				{
					PanelOpen = false;
					if (fresh)
					{
						mc.RequestStart(gameModeType);
					}
				}
			}
			PvpMatchToggle[] array = MatchToggles.Snapshot();
			Rect val3 = default(Rect);
			for (int j = 0; j < array.Length; j++)
			{
				int num6 = num + j;
				int num7 = num6 / 4;
				int num8 = num6 % 4;
				((Rect)(ref val3))..ctor(((Rect)(ref area)).x + (float)num8 * (num2 + 8f), ((Rect)(ref area)).y + (float)num7 * (num3 + 8f), num2, num3);
				PvpMatchToggle pvpMatchToggle = array[j];
				if (((Rect)(ref val3)).Contains(val))
				{
					_hoverToggle = pvpMatchToggle;
				}
				GUI.color = (pvpMatchToggle.Requested ? new Color(0.55f, 1f, 0.55f) : new Color(0.85f, 0.85f, 0.9f));
				if (GUI.Button(val3, pvpMatchToggle.Label + "\n" + (pvpMatchToggle.Requested ? "ON (this round)" : "OFF")))
				{
					pvpMatchToggle.Requested = !pvpMatchToggle.Requested;
				}
				GUI.color = Color.white;
			}
		}
	}
	internal static class ViewLock
	{
		private static bool _locked;

		internal static void Set(bool locked)
		{
			if (locked != _locked)
			{
				_locked = locked;
				try
				{
					PlayerCamera instance = PlayerSingleton<PlayerCamera>.Instance;
					if ((Object)(object)instance != (Object)null)
					{
						instance.SetCanLook(!locked);
						if (locked)
						{
							instance.FreeMouse(true);
						}
						else
						{
							instance.LockMouse(true);
						}
					}
				}
				catch
				{
				}
			}
			if (locked)
			{
				try
				{
					Cursor.visible = true;
					Cursor.lockState = (CursorLockMode)0;
				}
				catch
				{
				}
			}
		}

		internal static void Release()
		{
			if (!_locked)
			{
				return;
			}
			_locked = false;
			try
			{
				PlayerCamera instance = PlayerSingleton<PlayerCamera>.Instance;
				if ((Object)(object)instance != (Object)null)
				{
					instance.SetCanLook(true);
					instance.LockMouse(true);
				}
			}
			catch
			{
			}
		}
	}
}
namespace MultiplayerPVP.Net
{
	internal struct SnapRow
	{
		internal string Name;

		internal int Team;

		internal int Index;

		internal string Score;

		internal bool Bag;

		internal Vector3 Spawn;

		internal int Kills;

		internal int Downs;

		internal int Arrests;

		internal int BagsCaptured;

		internal int BagsLost;

		internal int WeaponsLost;

		internal int WeaponsWon;

		internal string History;
	}
	internal struct SnapTeamRow
	{
		internal int Team;

		internal string Name;

		internal string Score;

		internal int Kills;

		internal int Downs;

		internal int Arrests;

		internal int BagsCaptured;

		internal int BagsLost;

		internal int WeaponsLost;

		internal int WeaponsWon;
	}
	internal struct SnapMarker
	{
		internal Vector3 Pos;

		internal Color Color;

		internal string Label;

		internal int Team;
	}
	internal class MatchSnapshot
	{
		internal int Phase;

		internal int Mode;

		internal int Day;

		internal float Remaining;

		internal string Banner = "";

		internal string Result = "";

		internal string Loot = "";

		internal bool Chaos;

		internal bool Ammo;

		internal bool Jump;

		internal string Loadout = "";

		internal long RoundId;

		internal readonly List<SnapRow> Rows = new List<SnapRow>();

		internal readonly List<SnapTeamRow> TeamRows = new List<SnapTeamRow>();

		internal readonly List<SnapMarker> Markers = new List<SnapMarker>();

		internal long Seq;

		private static string San(string s)
		{
			if (string.IsNullOrEmpty(s))
			{
				return "";
			}
			return s.Replace('|', ' ').Replace('~', ' ').Replace(';', ' ')
				.Replace('=', ' ')
				.Replace(',', ' ')
				.Replace('"', ' ')
				.Replace('\\', ' ');
		}

		private static string F(float v)
		{
			return v.ToString("0.0", CultureInfo.InvariantCulture);
		}

		internal string Serialize()
		{
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_044b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0468: Unknown result type (might be due to invalid IL or missing references)
			//IL_0485: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_04bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_04dc: Unknown result type (might be due to invalid IL or missing references)
			StringBuilder stringBuilder = new StringBuilder(192);
			stringBuilder.Append("v=1|sq=").Append(Seq).Append("|ph=")
				.Append(Phase)
				.Append("|md=")
				.Append(Mode)
				.Append("|day=")
				.Append(Day)
				.Append("|rs=")
				.Append(Remaining.ToString("0.0", CultureInfo.InvariantCulture))
				.Append("|bn=")
				.Append(San(Banner))
				.Append("|rz=")
				.Append(San(Result))
				.Append("|lt=")
				.Append(Loot ?? "")
				.Append("|cx=")
				.Append(Chaos ? 1 : 0)
				.Append("|ua=")
				.Append(Ammo ? 1 : 0)
				.Append("|dj=")
				.Append(Jump ? 1 : 0)
				.Append("|gi=")
				.Append(Loadout ?? "")
				.Append("|gr=")
				.Append(RoundId)
				.Append("|p=");
			for (int i = 0; i < Rows.Count; i++)
			{
				SnapRow snapRow = Rows[i];
				if (i > 0)
				{
					stringBuilder.Append(';');
				}
				stringBuilder.Append(San(snapRow.Name)).Append('~').Append(snapRow.Team)
					.Append('~')
					.Append(snapRow.Index)
					.Append('~')
					.Append(San(snapRow.Score))
					.Append('~')
					.Append(snapRow.Bag ? 1 : 0)
					.Append('~')
					.Append(F(snapRow.Spawn.x))
					.Append('~')
					.Append(F(snapRow.Spawn.y))
					.Append('~')
					.Append(F(snapRow.Spawn.z))
					.Append('~')
					.Append(snapRow.Kills)
					.Append('~')
					.Append(snapRow.Downs)
					.Append('~')
					.Append(snapRow.Arrests)
					.Append('~')
					.Append(snapRow.BagsCaptured)
					.Append('~')
					.Append(snapRow.BagsLost)
					.Append('~')
					.Append(snapRow.WeaponsLost)
					.Append('~')
					.Append(snapRow.WeaponsWon)
					.Append('~')
					.Append(San(snapRow.History));
			}
			stringBuilder.Append("|tr=");
			for (int j = 0; j < TeamRows.Count; j++)
			{
				SnapTeamRow snapTeamRow = TeamRows[j];
				if (j > 0)
				{
					stringBuilder.Append(';');
				}
				stringBuilder.Append(snapTeamRow.Team).Append('~').Append(San(snapTeamRow.Name))
					.Append('~')
					.Append(San(snapTeamRow.Score))
					.Append('~')
					.Append(snapTeamRow.Kills)
					.Append('~')
					.Append(snapTeamRow.Downs)
					.Append('~')
					.Append(snapTeamRow.Arrests)
					.Append('~')
					.Append(snapTeamRow.BagsCaptured)
					.Append('~')
					.Append(snapTeamRow.BagsLost)
					.Append('~')
					.Append(snapTeamRow.WeaponsLost)
					.Append('~')
					.Append(snapTeamRow.WeaponsWon);
			}
			stringBuilder.Append("|m=");
			for (int k = 0; k < Markers.Count; k++)
			{
				SnapMarker snapMarker = Markers[k];
				if (k > 0)
				{
					stringBuilder.Append(',');
				}
				stringBuilder.Append(F(snapMarker.Pos.x)).Append('~').Append(F(snapMarker.Pos.y))
					.Append('~')
					.Append(F(snapMarker.Pos.z))
					.Append('~')
					.Append(F(snapMarker.Color.r))
					.Append('~')
					.Append(F(snapMarker.Color.g))
					.Append('~')
					.Append(F(snapMarker.Color.b))
					.Append('~')
					.Append(San(snapMarker.Label))
					.Append('~')
					.Append(snapMarker.Team);
			}
			return stringBuilder.ToString();
		}

		internal static bool TryParse(string s, MatchSnapshot into)
		{
			//IL_08ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0904: Unknown result type (might be due to invalid IL or missing references)
			//IL_0916: Unknown result type (might be due to invalid IL or missing references)
			//IL_091b: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a5: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(s) || into == null)
			{
				return false;
			}
			try
			{
				into.Rows.Clear();
				into.TeamRows.Clear();
				into.Markers.Clear();
				into.Banner = "";
				into.Result = "";
				into.Loot = "";
				into.Chaos = false;
				into.Ammo = false;
				into.Jump = false;
				into.Loadout = "";
				into.RoundId = 0L;
				string[] array = s.Split(new char[1] { '|' });
				string[] array2 = array;
				foreach (string text in array2)
				{
					int num = text.IndexOf('=');
					if (num < 0)
					{
						continue;
					}
					string text2 = text.Substring(0, num);
					string text3 = text.Substring(num + 1);
					switch (text2)
					{
					case "sq":
						long.TryParse(text3, out into.Seq);
						break;
					case "ph":
						int.TryParse(text3, out into.Phase);
						break;
					case "md":
						int.TryParse(text3, out into.Mode);
						break;
					case "day":
						int.TryParse(text3, out into.Day);
						break;
					case "rs":
						float.TryParse(text3, NumberStyles.Float, CultureInfo.InvariantCulture, out into.Remaining);
						break;
					case "bn":
						into.Banner = text3;
						break;
					case "rz":
						into.Result = text3;
						break;
					case "lt":
						into.Loot = text3;
						break;
					case "cx":
						into.Chaos = text3 == "1";
						break;
					case "ua":
						into.Ammo = text3 == "1";
						break;
					case "dj":
						into.Jump = text3 == "1";
						break;
					case "gi":
						into.Loadout = text3;
						break;
					case "gr":
						long.TryParse(text3, out into.RoundId);
						break;
					case "p":
					{
						if (text3.Length == 0)
						{
							break;
						}
						string[] array7 = text3.Split(new char[1] { ';' });
						foreach (string text6 in array7)
						{
							string[] array8 = text6.Split(new char[1] { '~' });
							if (array8.Length >= 4)
							{
								SnapRow item3 = new SnapRow
								{
									Name = array8[0],
									Score = array8[3]
								};
								int.TryParse(array8[1], out item3.Team);
								int.TryParse(array8[2], out item3.Index);
								if (array8.Length >= 5)
								{
									item3.Bag = array8[4] == "1";
								}
								if (array8.Length >= 8)
								{
									float.TryParse(array8[5], NumberStyles.Float, CultureInfo.InvariantCulture, out var result7);
									float.TryParse(array8[6], NumberStyles.Float, CultureInfo.InvariantCulture, out var result8);
									float.TryParse(array8[7], NumberStyles.Float, CultureInfo.InvariantCulture, out var result9);
									item3.Spawn = new Vector3(result7, result8, result9);
								}
								if (array8.Length >= 11)
								{
									int.TryParse(array8[8], out item3.Kills);
									int.TryParse(array8[9], out item3.Downs);
									int.TryParse(array8[10], out item3.Arrests);
								}
								if (array8.Length >= 15)
								{
									int.TryParse(array8[11], out item3.BagsCaptured);
									int.TryParse(array8[12], out item3.BagsLost);
									int.TryParse(array8[13], out item3.WeaponsLost);
									int.TryParse(array8[14], out item3.WeaponsWon);
								}
								if (array8.Length >= 16)
								{
									item3.History = array8[15];
								}
								into.Rows.Add(item3);
							}
						}
						break;
					}
					case "tr":
					{
						if (text3.Length == 0)
						{
							break;
						}
						string[] array5 = text3.Split(new char[1] { ';' });
						foreach (string text5 in array5)
						{
							string[] array6 = text5.Split(new char[1] { '~' });
							if (array6.Length >= 3)
							{
								SnapTeamRow item2 = new SnapTeamRow
								{
									Name = array6[1],
									Score = array6[2]
								};
								int.TryParse(array6[0], out item2.Team);
								if (array6.Length >= 10)
								{
									int.TryParse(array6[3], out item2.Kills);
									int.TryParse(array6[4], out item2.Downs);
									int.TryParse(array6[5], out item2.Arrests);
									int.TryParse(array6[6], out item2.BagsCaptured);
									int.TryParse(array6[7], out item2.BagsLost);
									int.TryParse(array6[8], out item2.WeaponsLost);
									int.TryParse(array6[9], out item2.WeaponsWon);
								}
								into.TeamRows.Add(item2);
							}
						}
						break;
					}
					case "m":
					{
						if (text3.Length == 0)
						{
							break;
						}
						string[] array3 = text3.Split(new char[1] { ',' });
						foreach (string text4 in array3)
						{
							string[] array4 = text4.Split(new char[1] { '~' });
							if (array4.Length >= 7)
							{
								SnapMarker item = new SnapMarker
								{
									Label = array4[6],
									Team = -1
								};
								float.TryParse(array4[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var result);
								float.TryParse(array4[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2);
								float.TryParse(array4[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3);
								float.TryParse(array4[3], NumberStyles.Float, CultureInfo.InvariantCulture, out var result4);
								float.TryParse(array4[4], NumberStyles.Float, CultureInfo.InvariantCulture, out var result5);
								float.TryParse(array4[5], NumberStyles.Float, CultureInfo.InvariantCulture, out var result6);
								if (array4.Length >= 8)
								{
									int.TryParse(array4[7], out item.Team);
								}
								item.Pos = new Vector3(result, result2, result3);
								item.Color = new Color(result4, result5, result6, 1f);
								into.Markers.Add(item);
							}
						}
						break;
					}
					}
				}
				return true;
			}
			catch
			{
				return false;
			}
		}
	}
	internal sealed class PvpNet
	{
		internal const string KeyPrefix = "mpvp_";

		internal const string SnapshotKey = "snap";

		internal const string ModTagKey = "mod";

		internal const string LootKey = "loot";

		internal const string EarnKey = "earn";

		internal const string SpillKey = "spill";

		internal const string IdTagKey = "idtag";

		internal const string SightKey = "sight";

		private SteamNetworkClient _client;

		private HostSyncVar<string> _snap;

		private ClientSyncVar<string> _modTag;

		private ClientSyncVar<string> _loot;

		private ClientSyncVar<string> _earn;

		private ClientSyncVar<string> _spill;

		private ClientSyncVar<string> _idTag;

		private ClientSyncVar<string> _sight;

		private readonly List<ClientSyncVar<string>> _addonVars = new List<ClientSyncVar<string>>();

		private bool _init;

		private static readonly string ModTag = "MultiplayerPVP/" + ModVersion();

		private bool _wasInLobby;

		private bool _tagSet;

		private string _idCode;

		private bool _idSet;

		private const float WarnInterval = 15f;

		private float _lastWarn = -999f;

		internal bool Available => _init && _client != null;

		internal bool IsInLobby
		{
			get
			{
				try
				{
					return Available && _client.IsInLobby;
				}
				catch
				{
					return false;
				}
			}
		}

		internal bool IsHost
		{
			get
			{
				try
				{
					return Available && _client.IsHost;
				}
				catch
				{
					return false;
				}
			}
		}

		internal ulong LocalSteamId
		{
			get
			{
				//IL_0044: Unknown result type (might be due to invalid IL or missing references)
				if (!Available)
				{
					return 0uL;
				}
				try
				{
					foreach (MemberInfo lobbyMember in _client.GetLobbyMembers())
					{
						if (lobbyMember != null && lobbyMember.IsLocalPlayer)
						{
							return lobbyMember.SteamId.m_SteamID;
						}
					}
				}
				catch
				{
				}
				return 0uL;
			}
		}

		internal int ModdedMemberCount
		{
			get
			{
				if (_modTag == null)
				{
					return 0;
				}
				try
				{
					int num = 0;
					foreach (KeyValuePair<CSteamID, string> allValue in _modTag.GetAllValues())
					{
						if (!string.IsNullOrEmpty(allValue.Value))
						{
							num++;
						}
					}
					return num;
				}
				catch
				{
					return 0;
				}
			}
		}

		internal int MemberCount
		{
			get
			{
				try
				{
					return Available ? _client.GetLobbyMembers().Count : 0;
				}
				catch
				{
					return 0;
				}
			}
		}

		internal bool AllMembersModded
		{
			get
			{
				int memberCount = MemberCount;
				return memberCount > 0 && ModdedMemberCount >= memberCount;
			}
		}

		internal event Action<string> OnSnapshot;

		internal event Action<ulong, string> OnLoot;

		internal event Action<ulong, string> OnSpill;

		internal event Action<ulong, string> OnSighting;

		internal void Init()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			if (_init)
			{
				return;
			}
			try
			{
				_client = new SteamNetworkClient();
				if (!_client.Initialize())
				{
					return;
				}
				try
				{
					_client.OnVersionMismatch += OnVersionMismatch;
				}
				catch
				{
				}
				NetworkSyncOptions val = MakeOpts();
				_snap = _client.CreateHostSyncVar<string>("snap", "", val, (ISyncValidator<string>)null);
				_snap.OnValueChanged += OnSnapValueChanged;
				_snap.OnSyncError += OnSyncError;
				_modTag = _client.CreateClientSyncVar<string>("mod", "", val, (ISyncValidator<string>)null);
				_loot = _client.CreateClientSyncVar<string>("loot", "", val, (ISyncValidator<string>)null);
				_loot.OnValueChanged += delegate(CSteamID from, string oldV, string newV)
				{
					//IL_0020: Unknown result type (might be due to invalid IL or missing references)
					try
					{
						if (!string.IsNullOrEmpty(newV))
						{
							this.OnLoot?.Invoke(from.m_SteamID, newV);
						}
					}
					catch
					{
					}
				};
				_earn = _client.CreateClientSyncVar<string>("earn", "", val, (ISyncValidator<string>)null);
				_spill = _client.CreateClientSyncVar<string>("spill", "", val, (ISyncValidator<string>)null);
				_spill.OnValueChanged += delegate(CSteamID from, string oldV, string newV)
				{
					//IL_0020: Unknown result type (might be due to invalid IL or missing references)
					try
					{
						if (!string.IsNullOrEmpty(newV))
						{
							this.OnSpill?.Invoke(from.m_SteamID, newV);
						}
					}
					catch
					{
					}
				};
				_idTag = _client.CreateClientSyncVar<string>("idtag", "", val, (ISyncValidator<string>)null);
				_sight = _client.CreateClientSyncVar<string>("sight", "", val, (ISyncValidator<string>)null);
				_sight.OnValueChanged += delegate(CSteamID from, string oldV, string newV)
				{
					//IL_0020: Unknown result type (might be due to invalid IL or missing references)
					try
					{
						if (!string.IsNullOrEmpty(newV))
						{
							this.OnSighting?.Invoke(from.m_SteamID, newV);
						}
					}
					catch
					{
					}
				};
				_init = true;
				PvpLog.Debug("[MultiplayerPVP][Net] SteamNetworkClient initialized (HostSyncVar transport).");
			}
			catch
			{
			}
		}

		private static NetworkSyncOptions MakeOpts()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: 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_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			return new NetworkSyncOptions
			{
				KeyPrefix = "mpvp_",
				AutoSync = true,
				SyncOnPlayerJoin = true,
				MaxSyncsPerSecond = 0
			};
		}

		internal ClientSyncVar<string> CreateAddonVar(string keySuffix, Action<ulong, string> onMessage)
		{
			if (!_init || _client == null || string.IsNullOrEmpty(keySuffix))
			{
				return null;
			}
			try
			{
				ClientSyncVar<string> val = _client.CreateClientSyncVar<string>(keySuffix, "", MakeOpts(), (ISyncValidator<string>)null);
				if (onMessage != null)
				{
					val.OnValueChanged += delegate(CSteamID from, string oldV, string newV)
					{
						//IL_0015: Unknown result type (might be due to invalid IL or missing references)
						try
						{
							if (!string.IsNullOrEmpty(newV))
							{
								onMessage(from.m_SteamID, newV);
							}
						}
						catch
						{
						}
					};
				}
				lock (_addonVars)
				{
					_addonVars.Add(val);
				}
				return val;
			}
			catch (Exception ex)
			{
				float realtimeSinceStartup = Time.realtimeSinceStartup;
				if (realtimeSinceStartup - _lastWarn >= 15f)
				{
					_lastWarn = realtimeSinceStartup;
					MelonLogger.Warning("[MultiplayerPVP][Net] addon channel '" + keySuffix + "' create failed: " + ex.Message);
				}
				return null;
			}
		}

		internal void Tick()
		{
			if (!_init)
			{
				return;
			}
			bool isInLobby = IsInLobby;
			if (isInLobby && !_wasInLobby)
			{
				_tagSet = false;
				_idSet = false;
			}
			_wasInLobby = isInLobby;
			if (isInLobby && !_tagSet && _modTag != null)
			{
				try
				{
					_modTag.Value = ModTag;
					_tagSet = true;
				}
				catch
				{
				}
			}
			if (!isInLobby || _idSet || _idTag == null || string.IsNullOrEmpty(_idCode))
			{
				return;
			}
			try
			{
				_idTag.Value = _idCode;
				_idSet = true;
			}
			catch
			{
			}
		}

		internal void SetLocalIdentity(string playerCode)
		{
			if (!string.IsNullOrEmpty(playerCode) && playerCode != _idCode)
			{
				_idCode = playerCode;
				_idSet = false;
			}
		}

		private void OnSnapValueChanged(string oldValue, string newValue)
		{
			try
			{
				if (!IsHost && !string.IsNullOrEmpty(newValue))
				{
					this.OnSnapshot?.Invoke(newValue);
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[MultiplayerPVP][Net] snapshot apply: " + ex.Message);
			}
		}

		internal void PublishSnapshot(string snapshot)
		{
			if (!Available || !IsHost || _snap == null)
			{
				return;
			}
			try
			{
				_snap.Value = snapshot;
			}
			catch (Exception ex)
			{
				OnSyncError(ex);
			}
		}

		internal void PublishLoot(string record)
		{
			if (!Available || _loot == null)
			{
				return;
			}
			try
			{
				_loot.Value = record;
			}
			catch
			{
			}
		}

		internal void PublishSpill(string record)
		{
			if (!Available || _spill == null)
			{
				return;
			}
			try
			{
				_spill.Value = record;
			}
			catch
			{
			}
		}

		internal void PublishEarnings(string record)
		{
			if (!Available || _earn == null)
			{
				return;
			}
			try
			{
				_earn.Value = record;
			}
			catch
			{
			}
		}

		internal List<KeyValuePair<ulong, string>> AllEarnings()
		{
			return ReadAllOf(_earn);
		}

		internal List<KeyValuePair<ulong, string>> AllLoot()
		{
			return ReadAllOf(_loot);
		}

		internal List<KeyValuePair<ulong, string>> AllSpill()
		{
			return ReadAllOf(_spill);
		}

		internal static List<KeyValuePair<ulong, string>> ReadAllOf(ClientSyncVar<string> v)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			List<KeyValuePair<ulong, string>> list = new List<KeyValuePair<ulong, string>>();
			if (v == null)
			{
				return list;
			}
			try
			{
				v.Refresh();
			}
			catch
			{
			}
			try
			{
				foreach (KeyValuePair<CSteamID, string> allValue in v.GetAllValues())
				{
					if (!string.IsNullOrEmpty(allValue.Value))
					{
						list.Add(new KeyValuePair<ulong, string>(allValue.Key.m_SteamID, allValue.Value));
					}
				}
			}
			catch
			{
			}
			return list;
		}

		internal void PublishSighting(string record)
		{
			if (!Available || _sight == null)
			{
				return;
			}
			try
			{
				_sight.Value = record;
			}
			catch
			{
			}
		}

		internal Dictionary<string, ulong> AllIdentities()
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<string, ulong> dictionary = new Dictionary<string, ulong>();
			if (_idTag == null)
			{
				return dictionary;
			}
			try
			{
				foreach (KeyValuePair<CSteamID, string> allValue in _idTag.GetAllValues())
				{
					if (!string.IsNullOrEmpty(allValue.Value))
					{
						dictionary[allValue.Value] = allValue.Key.m_SteamID;
					}
				}
			}
			catch
			{
			}
			return dictionary;
		}

		internal string PersonaOf(ulong steamId)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			if (!Available || steamId == 0)
			{
				return null;
			}
			try
			{
				foreach (MemberInfo lobbyMember in _client.GetLobbyMembers())
				{
					if (lobbyMember != null && lobbyMember.SteamId.m_SteamID == steamId)
					{
						return lobbyMember.DisplayName;
					}
				}
			}
			catch
			{
			}
			return null;
		}

		private void OnVersionMismatch(object sender, VersionMismatchEventArgs e)
		{
			MelonLogger.Warning("[MultiplayerPVP][Net] SteamNetworkLib version mismatch between players — networking may be unreliable. Ensure everyone runs the same mod/lib build.");
		}

		private void OnSyncError(Exception ex)
		{
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (!(realtimeSinceStartup - _lastWarn < 15f))
			{
				_lastWarn = realtimeSinceStartup;
				MelonLogger.Warning("[MultiplayerPVP][Net] snapshot sync error (throttled): " + ex.Message);
			}
		}

		internal void Dispose()
		{
			try
			{
				if (_snap != null)
				{
					_snap.OnValueChanged -= OnSnapValueChanged;
					_snap.OnSyncError -= OnSyncError;
					_snap.Dispose();
				}
			}
			catch
			{
			}
			try
			{
				if (_modTag != null)
				{
					_modTag.Dispose();
				}
			}
			catch
			{
			}
			try
			{
				if (_loot != null)
				{
					_loot.Dispose();
				}
			}
			catch
			{
			}
			try
			{
				if (_earn != null)
				{
					_earn.Dispose();
				}
			}
			catch
			{
			}
			try
			{
				if (_spill != null)
				{
					_spill.Dispose();
				}
			}
			catch
			{
			}
			try
			{
				if (_idTag != null)
				{
					_idTag.Dispose();
				}
			}
			catch
			{
			}
			try
			{
				if (_sight != null)
				{
					_sight.Dispose();
				}
			}
			catch
			{
			}
			lock (_addonVars)
			{
				for (int i = 0; i < _addonVars.Count; i++)
				{
					try
					{
						_addonVars[i].Dispose();
					}
					catch
					{
					}
				}
				_addonVars.Clear();
			}
			try
			{
				if (_client != null)
				{
					_client.OnVersionMismatch -= OnVersionMismatch;
					_client.Dispose();
				}
			}
			catch
			{
			}
			_snap = null;
			_modTag = null;
			_loot = null;
			_earn = null;
			_spill = null;
			_idTag = null;
			_sight = null;
			_client = null;
			_init = false;
			_tagSet = false;
			_idSet = false;
			_idCode = null;
			_wasInLobby = false;
		}

		private static string ModVersion()
		{
			try
			{
				Version version = typeof(PvpNet).Assembly.GetName().Version;
				return (version != null) ? version.ToString() : "1.0";
			}
			catch
			{
				return "1.0";
			}
		}
	}
}
namespace MultiplayerPVP.Modes
{
	internal class FindersKeepersMode : GameModeBase, IWorldMarkers, IBagSpillHandler
	{
		private DeadDrop _pickup;

		private int _pickupZone = -1;

		private int _pickupKnown;

		private PvpPlayer _carrier;

		private int _carrierHome = -1;

		private int _homeBaseline;

		private float _transit;

		private bool _active;

		private static string BagId => BagFactory.MatchId;

		public override GameModeType Type => GameModeType.FindersKeepers;

		public override void OnMatchStart(MatchContext ctx)
		{
			_active = true;
			SpawnBag(ctx, announce: false);
		}

		public override void OnMatchEnd(MatchContext ctx)
		{
			_active = false;
			bool tie;
			PvpPlayer pvpPlayer = ctx.Registry.Leader(out tie);
			if (pvpPlayer != null)
			{
				ctx.Announcer.Announce(tie ? $"It's a draw at {pvpPlayer.Score} delivery(ies)!" : $"{pvpPlayer.Name} wins with {pvpPlayer.Score} delivery(ies)!", 6f);
			}
		}

		private void SpawnBag(MatchContext ctx, bool announce)
		{
			_carrier = null;
			_carrierHome = -1;
			_transit = 0f;
			_pickup = ctx.Drops.RandomNonZoneDrop();
			_pickupZone = -1;
			for (int i = 0; i < ctx.Drops.Count; i++)
			{
				if ((Object)(object)ctx.Drops.Zone(i) == (Object)(object)_pickup)
				{
					_pickupZone = i;
					break;
				}
			}
			if (GameCompat.Alive((Object)(object)_pickup))
			{
				DeadDropStash.Insert(_pickup, BagId, 1, BagFactory.Create);
				_pickupKnown = DeadDropStash.Count(_pickup, BagId);
			}
			else
			{
				_pickupKnown = 0;
			}
			if (announce && GameCompat.Alive((Object)(object)_pickup))
			{
				ctx.Announcer.Announce("A fresh bag is in a dead drop — find it!", 3f);
			}
		}

		public bool OnCarrierSpill(MatchContext ctx, PvpPlayer victim, int count, string reason)
		{
			if (count <= 0)
			{
				return true;
			}
			if (_carrier == null)
			{
				return true;
			}
			if (victim != null && victim != _carrier)
			{
				return true;
			}
			string name = _carrier.Name;
			string text = ((reason == "arrested") ? "was busted" : "went down");
			SpawnBag(ctx, announce: false);
			ctx.Announcer.Announce(name + " " + text + " — the bag dropped and reappears in a dead drop!", 4f, notify: false);
			return true;
		}

		public override void Tick(MatchContext ctx, float dt)
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			if (!_active)
			{
				return;
			}
			if (_carrier == null)
			{
				if (!GameCompat.Alive((Object)(object)_pickup))
				{
					SpawnBag(ctx, announce: false);
					return;
				}
				int num = DeadDropStash.Count(_pickup, BagId);
				if (num < _pickupKnown)
				{
					_carrier = NearestPlayer(ctx, PickupPos(ctx));
					_pickupKnown = num;
					_transit = 0f;
					_carrierHome = ((_carrier != null) ? ctx.Drops.ZoneForIndex(_carrier.Index) : (-1));
					DeadDrop val = ((_carrierHome >= 0) ? ctx.Drops.Zone(_carrierHome) : null);
					_homeBaseline = (GameCompat.Alive((Object)(object)val) ? DeadDropStash.Count(val, BagId) : 0);
					string text = ((_carrier != null) ? _carrier.Name : "Someone");
					ctx.Announcer.Announce(text + " has the bag!");
				}
			}
			else
			{
				_transit += dt;
				int carrierHome = _carrierHome;
				DeadDrop val2 = ((carrierHome >= 0) ? ctx.Drops.Zone(carrierHome) : null);
				if (GameCompat.Alive((Object)(object)val2) && DeadDropStash.Count(val2, BagId) > _homeBaseline)
				{
					DeadDropStash.RemoveOne(val2, BagId);
					ctx.Award(_carrier, 1);
					ctx.Announcer.Announce($"{_carrier.Name} delivered the bag! ({_carrier.Score})", 5f);
					SpawnBag(ctx, announce: false);
				}
				else if (_transit > 60f)
				{
					ctx.Announcer.Announce("The bag was lost — a new one appears.");
					SpawnBag(ctx, announce: true);
				}
			}
		}

		private Vector3 PickupPos(MatchContext ctx)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: 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_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			if (_pickupZone >= 0)
			{
				return ctx.Drops.ZonePosition(_pickupZone);
			}
			try
			{
				return GameCompat.Alive((Object)(object)_pickup) ? ((Component)_pickup).transform.position : Vector3.zero;
			}
			catch
			{
				return Vector3.zero;
			}
		}

		private static PvpPlayer NearestPlayer(MatchContext ctx, Vector3 pos)
		{
			//IL_0035: 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)
			List<PvpPlayer> players = ctx.Registry.Players;
			PvpPlayer result = null;
			float num = float.MaxValue;
			for (int i = 0; i < players.Count; i++)
			{
				PvpPlayer pvpPlayer = players[i];
				if (pvpPlayer.Valid)
				{
					float num2 = Vector3.Distance(pos, pvpPlayer.Position);
					if (num2 < num)
					{
						num = num2;
						result = pvpPlayer;
					}
				}
			}
			return result;
		}

		public override bool IsComplete(MatchContext ctx)
		{
			int num = Mathf.Max(1, PvpConfig.CtfScoreToWin.Value);
			List<PvpPlayer> players = ctx.Registry.Players;
			for (int i = 0; i < players.Count; i++)
			{
				if (players[i].Score >= num)
				{
					return true;
				}
			}
			return false;
		}

		public override string ScoreText(PvpPlayer p)
		{
			return p.Score + " caps" + ((_carrier == p) ? " ·BAG" : "");
		}

		public void CollectMarkers(MatchContext ctx, PvpPlayer local, List<WorldMarker> into)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			if (_active && _carrier != null)
			{
				int carrierHome = _carrierHome;
				if (carrierHome >= 0)
				{
					into.Add(new WorldMarker(ctx.Drops.ZonePosition(carrierHome) + Vector3.up * 1.4f, PvpColors.For(_carrier.Index), "DELIVER HERE (" + _carrier.Name + ")"));
				}
			}
		}
	}
	internal class FreeForAllMode : GameModeBase
	{
		public override GameModeType Type => GameModeType.FreeForAll;

		public override void Tick(MatchContext ctx, float dt)
		{
			Combat.ProcessEliminations(ctx, teamMode: false);
		}

		public override void OnMatchEnd(MatchContext ctx)
		{
			bool tie;
			PvpPlayer pvpPlayer = ctx.Registry.Leader(out tie);
			if (pvpPlayer != null)
			{
				ctx.Announcer.Announce(tie ? $"It's a draw at {pvpPlayer.Score} eliminations!" : $"{pvpPlayer.Name} wins with {pvpPlayer.Score} eliminations!", 6f);
			}
		}

		public override string ScoreText(PvpPlayer p)
		{
			return p.Score + " elim";
		}
	}
	internal class HideAndSeekMode : GameModeBase
	{
		private readonly HashSet<string> _originalHiders = new HashSet<string>();

		private readonly Dictionary<string, int> _foundRank = new Dictionary<string, int>();

		private int _foundCounter;

		private float _lastScan;

		public override GameModeType Type => GameModeType.HideAndSeek;

		private static string KeyOf(PvpPlayer p)
		{
			return (p != null) ? p.StableKey : "";
		}

		private bool IsOriginalHider(PvpPlayer p)
		{
			return _originalHiders.Contains(KeyOf(p)) || (p != null && p.Name != null && _originalHiders.Contains(p.Name));
		}

		private bool TryGetFoundRank(PvpPlayer p, out int rank)
		{
			if (_foundRank.TryGetValue(KeyOf(p), out rank))
			{
				return true;
			}
			return p != null && p.Name != null && _foundRank.TryGetValue(p.Name, out rank);
		}

		public override void OnMatchStart(MatchContext ctx)
		{
			_originalHiders.Clear();
			_foundRank.Clear();
			_foundCounter = 0;
			List<PvpPlayer> players = ctx.Registry.Players;
			int count = players.Count;
			int num = Mathf.Cl

PvpCameraEsp.IL2CPP.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppScheduleOne.EntityFramework;
using Il2CppScheduleOne.ItemFramework;
using Il2CppScheduleOne.PlayerScripts;
using Il2CppTMPro;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using MultiplayerPVP.Core;
using PvpCameraEsp;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonAdditionalDependencies(new string[] { "MultiplayerPVP" })]
[assembly: MelonOptionalDependencies(new string[] { "NetEye" })]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: MelonInfo(typeof(PvpCameraEspMod), "PvpCameraEsp", "1.0.3", "Virtunerd", null)]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: AssemblyFileVersion("1.0.3")]
[assembly: AssemblyInformationalVersion("1.0.3")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.3.0")]
[module: UnverifiableCode]
[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 PvpCameraEsp
{
	internal static class CameraBuildTracker
	{
		private static bool _active;

		private static float _graceUntil;

		private const float GraceSeconds = 2.5f;

		private static bool _hooked;

		internal static bool Hooked => _hooked;

		internal static bool LocalPlacingCamera
		{
			get
			{
				try
				{
					return _active || Time.unscaledTime < _graceUntil;
				}
				catch
				{
					return false;
				}
			}
		}

		internal static void Apply(Harmony h)
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Expected O, but got Unknown
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Expected O, but got Unknown
			try
			{
				Type type = ResolveBuildManager();
				if (type == null)
				{
					MelonLogger.Warning("[PvpCameraEsp] BuildManager type not found — ownership falls back to proximity.");
					return;
				}
				MethodInfo methodInfo = FindMethod(type, "StartBuilding");
				if (methodInfo == null)
				{
					MelonLogger.Warning("[PvpCameraEsp] BuildManager.StartBuilding not found — ownership falls back to proximity.");
					return;
				}
				MethodInfo method = typeof(CameraBuildTracker).GetMethod("StartPostfix", BindingFlags.Static | BindingFlags.NonPublic);
				h.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				MethodInfo methodInfo2 = FindMethod(type, "StopBuilding");
				if (methodInfo2 != null)
				{
					MethodInfo method2 = typeof(CameraBuildTracker).GetMethod("StopPostfix", BindingFlags.Static | BindingFlags.NonPublic);
					h.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				_hooked = true;
				MelonLogger.Msg("[PvpCameraEsp] camera-placement tracker armed (BuildManager hooked).");
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[PvpCameraEsp] CameraBuildTracker.Apply: " + ex.Message);
			}
		}

		private static void StartPostfix(ItemInstance __0)
		{
			try
			{
				string text = ItemId(__0);
				if (EspConfig.DebugLog.Value)
				{
					MelonLogger.Msg("[PvpCameraEsp] StartBuilding item='" + (text ?? "?") + "'");
				}
				if (!string.IsNullOrEmpty(text) && text.IndexOf("NetEye", StringComparison.OrdinalIgnoreCase) >= 0 && text.IndexOf("Camera", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					_active = true;
					_graceUntil = Time.unscaledTime + 2.5f;
					if (EspConfig.DebugLog.Value)
					{
						MelonLogger.Msg("[PvpCameraEsp] local CAMERA placement STARTED → next new camera = mine");
					}
				}
			}
			catch
			{
			}
		}

		private static void StopPostfix()
		{
			try
			{
				bool active = _active;
				_active = false;
				if (active)
				{
					_graceUntil = Time.unscaledTime + 2.5f;
					if (EspConfig.DebugLog.Value)
					{
						MelonLogger.Msg("[PvpCameraEsp] local camera placement STOPPED (grace armed)");
					}
				}
			}
			catch
			{
			}
		}

		private static string ItemId(ItemInstance item)
		{
			try
			{
				if (item == null)
				{
					return null;
				}
				object member = GetMember(item, "Definition");
				if (member == null)
				{
					return null;
				}
				return GetMember(member, "ID") as string;
			}
			catch
			{
				return null;
			}
		}

		private static object GetMember(object target, string name)
		{
			if (target == null)
			{
				return null;
			}
			Type type = target.GetType();
			try
			{
				PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
				if (property != null)
				{
					return property.GetValue(target);
				}
			}
			catch
			{
			}
			try
			{
				FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
				if (field != null)
				{
					return field.GetValue(target);
				}
			}
			catch
			{
			}
			return null;
		}

		private static MethodInfo FindMethod(Type t, string name)
		{
			try
			{
				return t.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			}
			catch (AmbiguousMatchException)
			{
				MethodInfo methodInfo = null;
				MethodInfo[] methods = t.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (MethodInfo methodInfo2 in methods)
				{
					if (!(methodInfo2.Name != name))
					{
						if (methodInfo == null)
						{
							methodInfo = methodInfo2;
						}
						ParameterInfo[] parameters = methodInfo2.GetParameters();
						if (parameters.Length == 1)
						{
							methodInfo = methodInfo2;
							break;
						}
					}
				}
				return methodInfo;
			}
			catch
			{
				return null;
			}
		}

		private static Type ResolveBuildManager()
		{
			Type type = FindType("Il2CppScheduleOne.Building.BuildManager") ?? FindType("ScheduleOne.Building.BuildManager");
			if (type != null)
			{
				return type;
			}
			try
			{
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				foreach (Assembly assembly in assemblies)
				{
					if (assembly.GetName().Name != "Assembly-CSharp")
					{
						continue;
					}
					Type[] types;
					try
					{
						types = assembly.GetTypes();
					}
					catch
					{
						continue;
					}
					Type[] array = types;
					foreach (Type type2 in array)
					{
						if (type2.Name == "BuildManager" && type2.Namespace != null && type2.Namespace.IndexOf("ScheduleOne", StringComparison.Ordinal) >= 0)
						{
							return type2;
						}
					}
				}
			}
			catch
			{
			}
			return null;
		}

		private static Type FindType(string fullName)
		{
			try
			{
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				foreach (Assembly assembly in assemblies)
				{
					Type type = assembly.GetType(fullName);
					if (type != null)
					{
						return type;
					}
				}
			}
			catch
			{
			}
			try
			{
				return Type.GetType(fullName + ", Assembly-CSharp");
			}
			catch
			{
				return null;
			}
		}

		internal static void Reset()
		{
			_active = false;
			_graceUntil = 0f;
		}
	}
	internal static class CameraGuard
	{
		internal static void Apply()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			try
			{
				Harmony h = new Harmony("com.virtunerd.pvpcameraesp");
				Type typeFromHandle = typeof(BuildableItem);
				PatchVoid(h, typeFromHandle, "PickupItem");
				PatchCan(h, typeFromHandle, "CanBePickedUp");
				PatchCan(h, typeFromHandle, "CanBeDestroyed");
				CameraBuildTracker.Apply(h);
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[PvpCameraEsp] guard apply: " + ex.Message);
			}
		}

		private static bool ShouldBlock(BuildableItem bi)
		{
			try
			{
				if (!EspConfig.ProtectCameras.Value)
				{
					return false;
				}
				if (!PvpApi.IsMatchActive)
				{
					return false;
				}
				if ((Object)(object)bi == (Object)null)
				{
					return false;
				}
				GameObject gameObject = ((Component)bi).gameObject;
				if ((Object)(object)gameObject == (Object)null)
				{
					return false;
				}
				if (!IsNetEyeCameraDeployable(gameObject))
				{
					return false;
				}
				if (CameraOwnership.IsMine(((Object)gameObject).GetInstanceID()))
				{
					return false;
				}
				return true;
			}
			catch
			{
				return false;
			}
		}

		private static bool IsNetEyeCameraDeployable(GameObject go)
		{
			try
			{
				Transform transform = go.transform;
				int childCount = transform.childCount;
				for (int i = 0; i < childCount; i++)
				{
					Transform child = transform.GetChild(i);
					if ((Object)(object)child != (Object)null && ((Object)child).name != null && ((Object)child).name.StartsWith("NetEye_"))
					{
						return true;
					}
				}
			}
			catch
			{
			}
			return false;
		}

		private static bool BlockVoidPrefix(BuildableItem __instance)
		{
			try
			{
				if (ShouldBlock(__instance))
				{
					return false;
				}
			}
			catch
			{
			}
			return true;
		}

		private static bool CanPrefix(BuildableItem __instance, ref string reason, ref bool __result)
		{
			try
			{
				if (ShouldBlock(__instance))
				{
					reason = "Protected PvP camera";
					__result = false;
					return false;
				}
			}
			catch
			{
			}
			return true;
		}

		private static void PatchVoid(Harmony h, Type t, string method)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			try
			{
				MethodInfo method2 = t.GetMethod(method, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (method2 == null)
				{
					MelonLogger.Warning("[PvpCameraEsp] guard: " + method + " not found");
					return;
				}
				MethodInfo method3 = typeof(CameraGuard).GetMethod("BlockVoidPrefix", BindingFlags.Static | BindingFlags.NonPublic);
				h.Patch((MethodBase)method2, new HarmonyMethod(method3), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[PvpCameraEsp] guard patch " + method + ": " + ex.Message);
			}
		}

		private static void PatchCan(Harmony h, Type t, string method)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			try
			{
				MethodInfo method2 = t.GetMethod(method, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (!(method2 == null))
				{
					MethodInfo method3 = typeof(CameraGuard).GetMethod("CanPrefix", BindingFlags.Static | BindingFlags.NonPublic);
					h.Patch((MethodBase)method2, new HarmonyMethod(method3), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[PvpCameraEsp] guard patch " + method + ": " + ex.Message);
			}
		}
	}
	internal static class CameraOwnership
	{
		private static readonly HashSet<int> _known = new HashSet<int>();

		private static readonly Dictionary<int, float> _pending = new Dictionary<int, float>();

		private static readonly Dictionary<int, BuildableItem> _mine = new Dictionary<int, BuildableItem>();

		private const float ClaimWindow = 2.5f;

		private const float PlacingClaimRadius = 10f;

		private static readonly Dictionary<int, BuildableItem> _pendingPickup = new Dictionary<int, BuildableItem>();

		private static float _nextPickupTry;

		private static int _pickupRounds;

		private const float PickupInterval = 1.5f;

		private const int MaxPickupRounds = 12;

		internal static bool PickupPending => _pendingPickup.Count > 0;

		internal static bool IsMine(int deployableInstanceId)
		{
			return _mine.ContainsKey(deployableInstanceId);
		}

		internal static bool IsMineCamera(Camera cam)
		{
			try
			{
				if ((Object)(object)cam == (Object)null)
				{
					return false;
				}
				BuildableItem val = FindDeployable(cam);
				if ((Object)(object)val == (Object)null)
				{
					return false;
				}
				return _mine.ContainsKey(((Object)((Component)val).gameObject).GetInstanceID());
			}
			catch
			{
				return false;
			}
		}

		internal static void Tick(float radius)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: 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)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				bool localPlacingCamera = CameraBuildTracker.LocalPlacingCamera;
				bool hooked = CameraBuildTracker.Hooked;
				float unscaledTime = Time.unscaledTime;
				Player localPlayer = PvpApi.LocalPlayer;
				bool flag = (Object)(object)localPlayer != (Object)null;
				Vector3 val = Vector3.zero;
				if (flag)
				{
					try
					{
						val = ((Component)localPlayer).transform.position;
					}
					catch
					{
						flag = false;
					}
				}
				IReadOnlyList<CamEntry> readOnlyList = NetEyeBridge.AllCameras();
				for (int i = 0; i < readOnlyList.Count; i++)
				{
					Camera cam = readOnlyList[i].Cam;
					if ((Object)(object)cam == (Object)null)
					{
						continue;
					}
					BuildableItem val2 = FindDeployable(cam);
					if ((Object)(object)val2 == (Object)null)
					{
						continue;
					}
					int instanceID;
					try
					{
						instanceID = ((Object)((Component)val2).gameObject).GetInstanceID();
					}
					catch
					{
						continue;
					}
					if (_mine.ContainsKey(instanceID) || _known.Contains(instanceID) || _pendingPickup.ContainsKey(instanceID))
					{
						continue;
					}
					if (localPlacingCamera)
					{
						bool flag2 = !flag;
						if (flag)
						{
							try
							{
								Vector3 val3 = ((Component)val2).transform.position - val;
								val3.y = 0f;
								flag2 = ((Vector3)(ref val3)).magnitude <= 10f;
							}
							catch
							{
								flag2 = true;
							}
						}
						if (flag2)
						{
							_mine[instanceID] = val2;
							_pending.Remove(instanceID);
							_known.Add(instanceID);
							if (EspConfig.DebugLog.Value)
							{
								MelonLogger.Msg("[PvpCameraEsp] claimed own camera (local build flow)");
							}
						}
						continue;
					}
					if (hooked)
					{
						_known.Add(instanceID);
						_pending.Remove(instanceID);
						continue;
					}
					if (!_pending.TryGetValue(instanceID, out var value))
					{
						_pending[instanceID] = unscaledTime;
						value = unscaledTime;
					}
					bool flag3 = false;
					if (flag)
					{
						try
						{
							Vector3 val4 = ((Component)val2).transform.position - val;
							val4.y = 0f;
							flag3 = ((Vector3)(ref val4)).magnitude <= radius;
						}
						catch
						{
						}
					}
					if (flag3)
					{
						_mine[instanceID] = val2;
						_pending.Remove(instanceID);
						_known.Add(instanceID);
					}
					else if (unscaledTime - value > 2.5f)
					{
						_pending.Remove(instanceID);
						_known.Add(instanceID);
					}
				}
			}
			catch
			{
			}
		}

		private static BuildableItem FindDeployable(Camera cam)
		{
			try
			{
				Transform val = ((Component)cam).transform;
				int num = 0;
				while ((Object)(object)val != (Object)null && num++ < 64)
				{
					BuildableItem component = ((Component)val).GetComponent<BuildableItem>();
					if ((Object)(object)component != (Object)null)
					{
						return component;
					}
					val = val.parent;
				}
			}
			catch
			{
			}
			return null;
		}

		internal static void QueuePickUpMine()
		{
			foreach (KeyValuePair<int, BuildableItem> item in _mine)
			{
				if ((Object)(object)item.Value != (Object)null)
				{
					_pendingPickup[item.Key] = item.Value;
				}
			}
			_pickupRounds = 0;
			_nextPickupTry = 0f;
			_mine.Clear();
			_known.Clear();
			_pending.Clear();
		}

		internal static void TickPickupRetry()
		{
			if (_pendingPickup.Count == 0)
			{
				return;
			}
			float unscaledTime = Time.unscaledTime;
			if (unscaledTime < _nextPickupTry)
			{
				return;
			}
			_nextPickupTry = unscaledTime + 1.5f;
			bool value = EspConfig.DebugLog.Value;
			List<int> list = new List<int>();
			foreach (KeyValuePair<int, BuildableItem> item in _pendingPickup)
			{
				BuildableItem value2 = item.Value;
				if ((Object)(object)value2 == (Object)null)
				{
					list.Add(item.Key);
					continue;
				}
				bool flag = false;
				try
				{
					flag = value2.IsDestroyed;
				}
				catch
				{
				}
				if (flag)
				{
					list.Add(item.Key);
					continue;
				}
				string value3 = null;
				bool flag2 = false;
				try
				{
					flag2 = value2.CanBePickedUp(ref value3);
				}
				catch
				{
				}
				if (value)
				{
					MelonLogger.Msg($"[PvpCameraEsp] pickup-retry: can={flag2} reason='{value3}' host={PvpApi.IsHost}");
				}
				if (!flag2)
				{
					continue;
				}
				try
				{
					value2.PickupItem();
				}
				catch (Exception ex)
				{
					if (value)
					{
						MelonLogger.Msg("[PvpCameraEsp] pickup-retry threw: " + ex.Message);
					}
				}
			}
			for (int i = 0; i < list.Count; i++)
			{
				_pendingPickup.Remove(list[i]);
			}
			if (_pendingPickup.Count > 0 && ++_pickupRounds >= 12)
			{
				if (value)
				{
					MelonLogger.Warning($"[PvpCameraEsp] gave up restoring {_pendingPickup.Count} camera(s) after {12} tries");
				}
				_pendingPickup.Clear();
			}
		}

		internal static void AbortPickup()
		{
			_pendingPickup.Clear();
			_pickupRounds = 0;
		}

		internal static void Reset()
		{
			_known.Clear();
			_mine.Clear();
			_pending.Clear();
			_pendingPickup.Clear();
			_pickupRounds = 0;
		}
	}
	internal struct VisibleEnemy
	{
		internal Player Player;

		internal int Team;

		internal ulong SteamId;

		internal string Persona;

		internal Vector3 ViewportFeet;

		internal Vector3 ViewportTop;
	}
	internal static class EnemyTracker
	{
		private static readonly List<VisibleEnemy> _result = new List<VisibleEnemy>(8);

		internal static List<VisibleEnemy> Scan(Camera cam)
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: 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_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_0259: Unknown result type (might be due to invalid IL or missing references)
			//IL_025b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0262: Unknown result type (might be due to invalid IL or missing references)
			//IL_0264: Unknown result type (might be due to invalid IL or missing references)
			_result.Clear();
			if ((Object)(object)cam == (Object)null)
			{
				return _result;
			}
			int localTeam = PvpApi.LocalTeam;
			if (localTeam < 0)
			{
				return _result;
			}
			Player localPlayer = PvpApi.LocalPlayer;
			List<Player> players = PvpApi.Players;
			float value = EspConfig.MaxDistance.Value;
			float num = Mathf.Max(0.5f, EspConfig.BodyHeight.Value);
			bool value2 = EspConfig.RequireLineOfSight.Value;
			Vector3 position = ((Component)cam).transform.position;
			ulong steamId = default(ulong);
			string persona = default(string);
			for (int i = 0; i < players.Count; i++)
			{
				Player val = players[i];
				if ((Object)(object)val == (Object)null || ((Object)(object)localPlayer != (Object)null && (val == localPlayer || (Object)(object)val == (Object)(object)localPlayer)))
				{
					continue;
				}
				int team = PvpApi.GetTeam(val);
				if (team < 0 || team == localTeam)
				{
					continue;
				}
				Vector3 position2;
				Vector3 val2;
				Vector3 val3;
				try
				{
					position2 = ((Component)val).transform.position;
					val2 = position2 + Vector3.up * num;
					val3 = position2 + Vector3.up * (num * 0.5f);
				}
				catch
				{
					continue;
				}
				if (Vector3.Distance(position, val3) > value)
				{
					continue;
				}
				Vector3 val4;
				Vector3 val5;
				try
				{
					val4 = cam.WorldToViewportPoint(position2);
					val5 = cam.WorldToViewportPoint(val2);
				}
				catch
				{
					continue;
				}
				if (!(val4.z <= 0f) && !(val5.z <= 0f))
				{
					float num2 = (val4.x + val5.x) * 0.5f;
					float num3 = (val4.y + val5.y) * 0.5f;
					if (!(num2 < -0.2f) && !(num2 > 1.2f) && !(num3 < -0.2f) && !(num3 > 1.2f) && (!value2 || !IsOccluded(position, val3, val)))
					{
						PvpApi.TryGetIdentity(val, ref steamId, ref persona);
						_result.Add(new VisibleEnemy
						{
							Player = val,
							Team = team,
							SteamId = steamId,
							Persona = persona,
							ViewportFeet = val4,
							ViewportTop = val5
						});
					}
				}
			}
			return _result;
		}

		private static bool IsOccluded(Vector3 from, Vector3 to, Player target)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Vector3 val = to - from;
				float magnitude = ((Vector3)(ref val)).magnitude;
				if (magnitude < 0.05f)
				{
					return false;
				}
				RaycastHit val2 = default(RaycastHit);
				if (!Physics.Raycast(from, val / magnitude, ref val2, magnitude - 0.3f))
				{
					return false;
				}
				if ((Object)(object)((RaycastHit)(ref val2)).collider == (Object)null)
				{
					return false;
				}
				Player componentInParent = ((Component)((RaycastHit)(ref val2)).collider).GetComponentInParent<Player>();
				return !((Object)(object)componentInParent != (Object)null) || (componentInParent != target && !((Object)(object)componentInParent == (Object)(object)target));
			}
			catch
			{
				return false;
			}
		}
	}
	internal static class EspConfig
	{
		private static MelonPreferences_Category _cat;

		internal static MelonPreferences_Entry<bool> Enabled;

		internal static MelonPreferences_Entry<float> MaxDistance;

		internal static MelonPreferences_Entry<bool> RequireLineOfSight;

		internal static MelonPreferences_Entry<float> ReportCooldownSeconds;

		internal static MelonPreferences_Entry<float> RemindWhileVisibleSeconds;

		internal static MelonPreferences_Entry<bool> ShowBox;

		internal static MelonPreferences_Entry<int> BoxThickness;

		internal static MelonPreferences_Entry<float> BodyHeight;

		internal static MelonPreferences_Entry<string> BoxColorMode;

		internal static MelonPreferences_Entry<string> BoxColor;

		internal static MelonPreferences_Entry<bool> ShowLabels;

		internal static MelonPreferences_Entry<int> LabelFontSize;

		internal static MelonPreferences_Entry<bool> DebugLog;

		internal static MelonPreferences_Entry<bool> ProtectCameras;

		internal static MelonPreferences_Entry<float> OwnPlacementRadius;

		internal static MelonPreferences_Entry<bool> CleanupOwnCamerasOnRoundEnd;

		internal static MelonPreferences_Entry<bool> CleanStaleCameras;

		internal static void Load()
		{
			_cat = MelonPreferences.CreateCategory("PvpCameraEsp");
			Enabled = _cat.CreateEntry<bool>("Enabled", true, (string)null, "Master toggle for the camera ESP.", false, false, (ValueValidator)null, (string)null);
			MaxDistance = _cat.CreateEntry<float>("MaxDistance", 80f, (string)null, "Max distance (m) from the camera to detect an enemy (camera far clip is ~80).", false, false, (ValueValidator)null, (string)null);
			RequireLineOfSight = _cat.CreateEntry<bool>("RequireLineOfSight", true, (string)null, "Only detect enemies with a clear line of sight (not behind walls). Disable if detection misses.", false, false, (ValueValidator)null, (string)null);
			ReportCooldownSeconds = _cat.CreateEntry<float>("ReportCooldownSeconds", 5f, (string)null, "Re-arm window: an enemy must be GONE from a camera this long before a NEW alert fires (edge-triggered, no spam while they stay in view).", false, false, (ValueValidator)null, (string)null);
			RemindWhileVisibleSeconds = _cat.CreateEntry<float>("RemindWhileVisibleSeconds", 0f, (string)null, "Optional: re-alert every N seconds while an enemy stays continuously in view (0 = off, alert only on enter).", false, false, (ValueValidator)null, (string)null);
			ShowBox = _cat.CreateEntry<bool>("ShowBox", true, (string)null, "Draw a box around each spotted enemy on the camera feed (ESP box).", false, false, (ValueValidator)null, (string)null);
			BoxThickness = _cat.CreateEntry<int>("BoxThickness", 2, (string)null, "Border thickness (px) of the ESP box.", false, false, (ValueValidator)null, (string)null);
			BodyHeight = _cat.CreateEntry<float>("BodyHeight", 2f, (string)null, "Assumed player height (m) used to size the box from feet to head.", false, false, (ValueValidator)null, (string)null);
			BoxColorMode = _cat.CreateEntry<string>("BoxColorMode", "enemyteam", (string)null, "Box/label colour source: 'enemyteam' (spotted enemy's team colour), 'ownteam' (your team = the camera owner's team), or 'custom' (use BoxColor).", false, false, (ValueValidator)null, (string)null);
			BoxColor = _cat.CreateEntry<string>("BoxColor", "FF3030", (string)null, "Custom box/label colour as hex RGB or RGBA (e.g. FF3030 or FF3030C0). Used only when BoxColorMode = custom.", false, false, (ValueValidator)null, (string)null);
			ShowLabels = _cat.CreateEntry<bool>("ShowLabels", true, (string)null, "Draw the enemy's Steam name above the box on the camera feed.", false, false, (ValueValidator)null, (string)null);
			LabelFontSize = _cat.CreateEntry<int>("LabelFontSize", 20, (string)null, "Font size of the on-feed name labels.", false, false, (ValueValidator)null, (string)null);
			DebugLog = _cat.CreateEntry<bool>("DebugLog", false, (string)null, "Verbose logging (cameras found, alerts) for diagnosing the live test.", false, false, (ValueValidator)null, (string)null);
			ProtectCameras = _cat.CreateEntry<bool>("ProtectCameras", true, (string)null, "During a Teams match, block players from picking up / demolishing cameras they didn't place (protects client cameras from the host & host-team, and vice-versa).", false, false, (ValueValidator)null, (string)null);
			OwnPlacementRadius = _cat.CreateEntry<float>("OwnPlacementRadius", 4f, (string)null, "FALLBACK ONLY (used if the BuildManager hook isn't available): a newly-placed camera within this horizontal distance (m) of you is treated as YOURS. Normally ownership comes from the local build flow and this is ignored.", false, false, (ValueValidator)null, (string)null);
			CleanupOwnCamerasOnRoundEnd = _cat.CreateEntry<bool>("CleanupOwnCamerasOnRoundEnd", true, (string)null, "Pick up your own cameras (back into your inventory) automatically when a match ends, so they don't linger in the NetEye app. Applies to both host and client.", false, false, (ValueValidator)null, (string)null);
			CleanStaleCameras = _cat.CreateEntry<bool>("CleanStaleCameras", true, (string)null, "HOST: remove stale camera entries (loaded from a previous session's cameras.txt, shown in the app but not backed by a live camera) while in a multiplayer match.", false, false, (ValueValidator)null, (string)null);
		}

		internal static Color ResolveBoxColor(int enemyTeam)
		{
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			string text = (BoxColorMode.Value ?? "").Trim().ToLowerInvariant();
			if (text == "ownteam")
			{
				int localTeam = PvpApi.LocalTeam;
				return PvpApi.TeamColor((localTeam >= 0) ? localTeam : 0);
			}
			if (text == "custom")
			{
				string value = BoxColor.Value;
				Color result = default(Color);
				if (!string.IsNullOrEmpty(value) && ColorUtility.TryParseHtmlString((value[0] == '#') ? value : ("#" + value), ref result))
				{
					return result;
				}
				return Color.red;
			}
			return PvpApi.TeamColor(enemyTeam);
		}
	}
	internal static class FeedOverlay
	{
		private sealed class EnemyBox
		{
			internal RectTransform Root;

			internal RawImage Top;

			internal RawImage Bottom;

			internal RawImage Left;

			internal RawImage Right;

			internal TextMeshProUGUI Label;
		}

		private static RawImage _bound;

		private static RectTransform _container;

		private static TMP_FontAsset _font;

		private static bool _fontResolved;

		private static bool _warnedNoFont;

		private static Texture2D _white;

		private static readonly Dictionary<string, EnemyBox> _boxes = new Dictionary<string, EnemyBox>();

		private static readonly HashSet<string> _seen = new HashSet<string>();

		private static Texture2D White
		{
			get
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_001d: Expected O, but got Unknown
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)_white == (Object)null)
				{
					_white = new Texture2D(1, 1);
					_white.SetPixel(0, 0, Color.white);
					_white.Apply();
				}
				return _white;
			}
		}

		internal static void Update(RawImage feed, List<VisibleEnemy> enemies)
		{
			//IL_0075: 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_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_0233: Unknown result type (might be due to invalid IL or missing references)
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)feed == (Object)null)
			{
				HideAll();
				return;
			}
			bool value = EspConfig.ShowBox.Value;
			bool value2 = EspConfig.ShowLabels.Value;
			if (!value && !value2)
			{
				HideAll();
				return;
			}
			EnsureContainer(feed);
			if ((Object)(object)_container == (Object)null)
			{
				return;
			}
			TMP_FontAsset font = ResolveFont();
			Rect rect = ((Graphic)feed).rectTransform.rect;
			Vector2 size = ((Rect)(ref rect)).size;
			int value3 = EspConfig.LabelFontSize.Value;
			_seen.Clear();
			Vector2 val = default(Vector2);
			Vector2 val2 = default(Vector2);
			Vector2 anchoredPosition = default(Vector2);
			for (int i = 0; i < enemies.Count; i++)
			{
				VisibleEnemy visibleEnemy = enemies[i];
				string text = ((visibleEnemy.SteamId != 0L) ? visibleEnemy.SteamId.ToString() : ("n:" + visibleEnemy.Persona));
				_seen.Add(text);
				EnemyBox orCreate = GetOrCreate(text, font);
				if (orCreate == null)
				{
					continue;
				}
				((Vector2)(ref val))..ctor((visibleEnemy.ViewportFeet.x - 0.5f) * size.x, (visibleEnemy.ViewportFeet.y - 0.5f) * size.y);
				((Vector2)(ref val2))..ctor((visibleEnemy.ViewportTop.x - 0.5f) * size.x, (visibleEnemy.ViewportTop.y - 0.5f) * size.y);
				float num = Mathf.Max(6f, Mathf.Abs(val2.y - val.y));
				float num2 = Mathf.Clamp(num * 0.4f, 6f, num);
				((Vector2)(ref anchoredPosition))..ctor((val.x + val2.x) * 0.5f, (val.y + val2.y) * 0.5f);
				orCreate.Root.anchoredPosition = anchoredPosition;
				orCreate.Root.sizeDelta = new Vector2(num2, num);
				Color val3 = EspConfig.ResolveBoxColor(visibleEnemy.Team);
				SetEdge(orCreate.Top, value, val3);
				SetEdge(orCreate.Bottom, value, val3);
				SetEdge(orCreate.Left, value, val3);
				SetEdge(orCreate.Right, value, val3);
				if ((Object)(object)orCreate.Label != (Object)null)
				{
					((Component)orCreate.Label).gameObject.SetActive(value2);
					if (value2)
					{
						((TMP_Text)orCreate.Label).text = visibleEnemy.Persona;
						((TMP_Text)orCreate.Label).fontSize = value3;
						((Graphic)orCreate.Label).color = val3;
					}
				}
				if (!((Component)orCreate.Root).gameObject.activeSelf)
				{
					((Component)orCreate.Root).gameObject.SetActive(true);
				}
			}
			foreach (KeyValuePair<string, EnemyBox> box in _boxes)
			{
				if (!_seen.Contains(box.Key) && (Object)(object)box.Value.Root != (Object)null && ((Component)box.Value.Root).gameObject.activeSelf)
				{
					((Component)box.Value.Root).gameObject.SetActive(false);
				}
			}
		}

		private static void SetEdge(RawImage edge, bool show, Color col)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)edge == (Object)null))
			{
				if (((Component)edge).gameObject.activeSelf != show)
				{
					((Component)edge).gameObject.SetActive(show);
				}
				if (show)
				{
					((Graphic)edge).color = col;
				}
			}
		}

		internal static void HideAll()
		{
			try
			{
				foreach (KeyValuePair<string, EnemyBox> box in _boxes)
				{
					if ((Object)(object)box.Value.Root != (Object)null && ((Component)box.Value.Root).gameObject.activeSelf)
					{
						((Component)box.Value.Root).gameObject.SetActive(false);
					}
				}
			}
			catch
			{
			}
		}

		private static void EnsureContainer(RawImage feed)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_bound == (Object)(object)feed && (Object)(object)_container != (Object)null)
			{
				return;
			}
			_boxes.Clear();
			_bound = feed;
			try
			{
				GameObject val = new GameObject("PvpCamEsp_Overlay");
				RectTransform val2 = val.AddComponent<RectTransform>();
				((Transform)val2).SetParent(((Component)feed).transform, false);
				val2.anchorMin = Vector2.zero;
				val2.anchorMax = Vector2.one;
				val2.offsetMin = Vector2.zero;
				val2.offsetMax = Vector2.zero;
				val.AddComponent<RectMask2D>();
				_container = val2;
				if (EspConfig.DebugLog.Value)
				{
					MelonLogger.Msg("[PvpCameraEsp] overlay container attached to feed");
				}
			}
			catch
			{
				_container = null;
			}
		}

		private static EnemyBox GetOrCreate(string key, TMP_FontAsset font)
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: 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_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0216: Unknown result type (might be due to invalid IL or missing references)
			if (_boxes.TryGetValue(key, out var value) && (Object)(object)value.Root != (Object)null)
			{
				return value;
			}
			try
			{
				int num = Mathf.Max(1, EspConfig.BoxThickness.Value);
				RectTransform val = NewRect("box_" + key, (Transform)(object)_container, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f));
				value = new EnemyBox
				{
					Root = val
				};
				value.Top = Edge((Transform)(object)val, new Vector2(0f, 1f), new Vector2(1f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, (float)num));
				value.Bottom = Edge((Transform)(object)val, new Vector2(0f, 0f), new Vector2(1f, 0f), new Vector2(0.5f, 0f), new Vector2(0f, (float)num));
				value.Left = Edge((Transform)(object)val, new Vector2(0f, 0f), new Vector2(0f, 1f), new Vector2(0f, 0.5f), new Vector2((float)num, 0f));
				value.Right = Edge((Transform)(object)val, new Vector2(1f, 0f), new Vector2(1f, 1f), new Vector2(1f, 0.5f), new Vector2((float)num, 0f));
				if ((Object)(object)font != (Object)null)
				{
					RectTransform val2 = NewRect("name", (Transform)(object)val, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0.5f, 0f));
					val2.sizeDelta = new Vector2(260f, 28f);
					val2.anchoredPosition = new Vector2(0f, 4f);
					TextMeshProUGUI val3 = ((Component)val2).gameObject.AddComponent<TextMeshProUGUI>();
					((TMP_Text)val3).font = font;
					((TMP_Text)val3).alignment = (TextAlignmentOptions)1026;
					((TMP_Text)val3).enableWordWrapping = false;
					((TMP_Text)val3).richText = false;
					((TMP_Text)val3).fontStyle = (FontStyles)1;
					((TMP_Text)val3).overflowMode = (TextOverflowModes)0;
					((Graphic)val3).raycastTarget = false;
					value.Label = val3;
				}
				else if (!_warnedNoFont)
				{
					_warnedNoFont = true;
					MelonLogger.Warning("[PvpCameraEsp] No TMP font found — boxes still draw, name labels disabled.");
				}
				_boxes[key] = value;
				return value;
			}
			catch
			{
				return null;
			}
		}

		private static RectTransform NewRect(string name, Transform parent, Vector2 aMin, Vector2 aMax, Vector2 pivot)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			RectTransform val2 = val.AddComponent<RectTransform>();
			((Transform)val2).SetParent(parent, false);
			val2.anchorMin = aMin;
			val2.anchorMax = aMax;
			val2.pivot = pivot;
			val2.anchoredPosition = Vector2.zero;
			return val2;
		}

		private static RawImage Edge(Transform parent, Vector2 aMin, Vector2 aMax, Vector2 pivot, Vector2 sizeDelta)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = NewRect("edge", parent, aMin, aMax, pivot);
			val.sizeDelta = sizeDelta;
			RawImage val2 = ((Component)val).gameObject.AddComponent<RawImage>();
			val2.texture = (Texture)(object)White;
			((Graphic)val2).raycastTarget = false;
			return val2;
		}

		private static TMP_FontAsset ResolveFont()
		{
			if (_fontResolved)
			{
				return _font;
			}
			_fontResolved = true;
			try
			{
				Il2CppArrayBase<TMP_FontAsset> val = Resources.FindObjectsOfTypeAll<TMP_FontAsset>();
				if (val != null)
				{
					foreach (TMP_FontAsset item in val)
					{
						if ((Object)(object)item != (Object)null && ((Object)item).name != null && ((Object)item).name.Contains("OpenSans"))
						{
							_font = item;
							return _font;
						}
					}
					foreach (TMP_FontAsset item2 in val)
					{
						if ((Object)(object)item2 != (Object)null && ((Object)item2).name != null && (((Object)item2).name.Contains("Inter") || ((Object)item2).name.Contains("Roboto") || ((Object)item2).name.Contains("Liberation") || ((Object)item2).name.Contains("Arial")))
						{
							_font = item2;
							return _font;
						}
					}
					foreach (TMP_FontAsset item3 in val)
					{
						if ((Object)(object)item3 != (Object)null)
						{
							_font = item3;
							return _font;
						}
					}
				}
			}
			catch
			{
			}
			return _font;
		}

		internal static void Reset()
		{
			try
			{
				if ((Object)(object)_container != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)_container).gameObject);
				}
			}
			catch
			{
			}
			_container = null;
			_bound = null;
			_boxes.Clear();
		}
	}
	internal struct CamEntry
	{
		internal Camera Cam;

		internal string Name;

		internal CamEntry(Camera cam, string name)
		{
			Cam = cam;
			Name = name;
		}
	}
	internal static class NetEyeBridge
	{
		internal const string RtPrefix = "NetEye_RT_";

		private const string RootPrefix = "NetEye_";

		private static readonly List<CamEntry> _all = new List<CamEntry>(8);

		private static float _nextAllScan;

		private static int _lastCount = -1;

		private static Camera _feedCam;

		private static RawImage _feedCache;

		private static readonly Dictionary<int, string> _niceCache = new Dictionary<int, string>();

		private static bool _reflectInit;

		private static bool _reflectOk;

		private static FieldInfo _fInstance;

		private static FieldInfo _fCameras;

		private static FieldInfo _fUnityCam;

		private static FieldInfo _fName;

		private static FieldInfo _fLoc;

		private static FieldInfo _fIsVanilla;

		private static FieldInfo _fActiveIdx;

		private static MethodInfo _mDestroy;

		internal static IReadOnlyList<CamEntry> AllCameras()
		{
			float unscaledTime = Time.unscaledTime;
			if (unscaledTime >= _nextAllScan)
			{
				_nextAllScan = unscaledTime + 1f;
				RebuildAll();
			}
			return _all;
		}

		private static void RebuildAll()
		{
			_all.Clear();
			try
			{
				Il2CppArrayBase<Camera> val = Resources.FindObjectsOfTypeAll<Camera>();
				if (val != null)
				{
					foreach (Camera item in val)
					{
						if (!((Object)(object)item == (Object)null))
						{
							RenderTexture targetTexture = item.targetTexture;
							if (!((Object)(object)targetTexture == (Object)null) && ((Object)targetTexture).name != null && ((Object)targetTexture).name.StartsWith("NetEye_RT_"))
							{
								_all.Add(new CamEntry(item, ResolveName(item, targetTexture)));
							}
						}
					}
				}
			}
			catch
			{
			}
			if (EspConfig.DebugLog.Value && _all.Count != _lastCount)
			{
				_lastCount = _all.Count;
				MelonLogger.Msg("[PvpCameraEsp] NetEye cameras detected: " + _all.Count);
			}
		}

		internal static bool TryGetLive(out Camera cam, out RawImage feed, out string name)
		{
			cam = null;
			feed = null;
			name = null;
			try
			{
				IReadOnlyList<CamEntry> readOnlyList = AllCameras();
				for (int i = 0; i < readOnlyList.Count; i++)
				{
					Camera cam2 = readOnlyList[i].Cam;
					if ((Object)(object)cam2 != (Object)null && ((Behaviour)cam2).enabled)
					{
						cam = cam2;
						name = readOnlyList[i].Name;
						break;
					}
				}
				if ((Object)(object)cam == (Object)null)
				{
					return false;
				}
				feed = ResolveFeed(cam);
				return (Object)(object)feed != (Object)null;
			}
			catch
			{
				return false;
			}
		}

		private static RawImage ResolveFeed(Camera cam)
		{
			if ((Object)(object)_feedCache != (Object)null && (Object)(object)_feedCam == (Object)(object)cam && (Object)(object)_feedCache.texture == (Object)(object)cam.targetTexture)
			{
				return _feedCache;
			}
			_feedCache = null;
			_feedCam = cam;
			try
			{
				Texture targetTexture = (Texture)(object)cam.targetTexture;
				Il2CppArrayBase<RawImage> val = Resources.FindObjectsOfTypeAll<RawImage>();
				if (val != null)
				{
					foreach (RawImage item in val)
					{
						if ((Object)(object)item == (Object)null || !((Object)(object)item.texture != (Object)null) || !((Object)(object)item.texture == (Object)(object)targetTexture))
						{
							continue;
						}
						_feedCache = item;
						break;
					}
				}
			}
			catch
			{
				_feedCache = null;
			}
			return _feedCache;
		}

		private static string ResolveName(Camera cam, RenderTexture rt)
		{
			int instanceID = ((Object)cam).GetInstanceID();
			if (_niceCache.TryGetValue(instanceID, out var value))
			{
				return value;
			}
			string text = TryReflectName(cam);
			if (!string.IsNullOrEmpty(text))
			{
				_niceCache[instanceID] = text;
				return text;
			}
			return GoName(cam, rt);
		}

		private static string GoName(Camera cam, RenderTexture rt)
		{
			try
			{
				Transform val = ((Component)cam).transform;
				while ((Object)(object)val.parent != (Object)null)
				{
					val = val.parent;
				}
				string name = ((Object)((Component)val).gameObject).name;
				if (!string.IsNullOrEmpty(name) && name.StartsWith("NetEye_"))
				{
					return name.Substring("NetEye_".Length);
				}
				if ((Object)(object)rt != (Object)null && ((Object)rt).name != null && ((Object)rt).name.StartsWith("NetEye_RT_"))
				{
					return ((Object)rt).name.Substring("NetEye_RT_".Length);
				}
				return string.IsNullOrEmpty(name) ? "?" : name;
			}
			catch
			{
				return "?";
			}
		}

		internal static int RemoveStaleCameras()
		{
			int num = 0;
			try
			{
				EnsureReflect();
				if (!_reflectOk || _fIsVanilla == null || _mDestroy == null || _fCameras == null)
				{
					return 0;
				}
				object value = _fInstance.GetValue(null);
				if (value == null)
				{
					return 0;
				}
				if (!(_fCameras.GetValue(value) is IList list))
				{
					return 0;
				}
				for (int num2 = list.Count - 1; num2 >= 0; num2--)
				{
					object obj = list[num2];
					if (obj == null)
					{
						continue;
					}
					bool flag;
					try
					{
						flag = (bool)_fIsVanilla.GetValue(obj);
					}
					catch
					{
						continue;
					}
					if (!flag)
					{
						try
						{
							_mDestroy.Invoke(obj, null);
						}
						catch
						{
						}
						try
						{
							list.RemoveAt(num2);
							num++;
						}
						catch
						{
						}
					}
				}
				if (num > 0 && _fActiveIdx != null)
				{
					try
					{
						int num3 = (int)_fActiveIdx.GetValue(value);
						if (num3 >= list.Count)
						{
							_fActiveIdx.SetValue(value, list.Count - 1);
						}
					}
					catch
					{
					}
				}
			}
			catch
			{
			}
			return num;
		}

		private static string TryReflectName(Camera cam)
		{
			try
			{
				EnsureReflect();
				if (!_reflectOk)
				{
					return null;
				}
				object value = _fInstance.GetValue(null);
				if (value == null)
				{
					return null;
				}
				if (!(_fCameras.GetValue(value) is IEnumerable enumerable))
				{
					return null;
				}
				foreach (object item in enumerable)
				{
					if (item == null)
					{
						continue;
					}
					object? value2 = _fUnityCam.GetValue(item);
					Camera val = (Camera)((value2 is Camera) ? value2 : null);
					if ((Object)(object)val == (Object)null || (Object)(object)val != (Object)(object)cam)
					{
						continue;
					}
					string text = _fName.GetValue(item) as string;
					if (string.IsNullOrEmpty(text))
					{
						return null;
					}
					string text2 = ((_fLoc != null) ? (_fLoc.GetValue(item) as string) : null);
					return string.IsNullOrEmpty(text2) ? text : (text + " (" + text2 + ")");
				}
			}
			catch
			{
			}
			return null;
		}

		private static void EnsureReflect()
		{
			if (_reflectInit)
			{
				return;
			}
			_reflectInit = true;
			try
			{
				Type type = FindType("NetEye.NetEyeMod", "NetEye");
				Type type2 = FindType("NetEye.NetEyeCamera", "NetEye");
				if (!(type == null) && !(type2 == null))
				{
					_fInstance = type.GetField("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					_fCameras = type.GetField("_cameras", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					_fActiveIdx = type.GetField("_activeCameraIdx", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					_fUnityCam = type2.GetField("UnityCam", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					_fName = type2.GetField("Name", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					_fLoc = type2.GetField("Location", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					_fIsVanilla = type2.GetField("IsVanilla", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					_mDestroy = type2.GetMethod("Destroy", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
					_reflectOk = _fInstance != null && _fCameras != null && _fUnityCam != null && _fName != null;
				}
			}
			catch
			{
				_reflectOk = false;
			}
		}

		private static Type FindType(string fullName, string asmSimpleName)
		{
			try
			{
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				foreach (Assembly assembly in assemblies)
				{
					if (assembly.GetName().Name == asmSimpleName)
					{
						Type type = assembly.GetType(fullName);
						if (type != null)
						{
							return type;
						}
					}
				}
			}
			catch
			{
			}
			try
			{
				return Type.GetType(fullName + ", " + asmSimpleName);
			}
			catch
			{
				return null;
			}
		}

		internal static void Reset()
		{
			_all.Clear();
			_niceCache.Clear();
			_feedCam = null;
			_feedCache = null;
			_nextAllScan = 0f;
			_lastCount = -1;
		}
	}
	public class PvpCameraEspMod : MelonMod
	{
		private float _nextSensorScan;

		private float _nextStaleScan;

		private bool _wasMatchActive;

		public override void OnInitializeMelon()
		{
			EspConfig.Load();
			CameraGuard.Apply();
			MelonLogger.Msg("[PvpCameraEsp] ready — symmetric camera ESP for MultiplayerPVP via NetEye cameras.");
		}

		public override void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			try
			{
				NetEyeBridge.Reset();
				FeedOverlay.Reset();
				SightingReporter.Reset();
				CameraOwnership.Reset();
				CameraBuildTracker.Reset();
				_wasMatchActive = false;
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[PvpCameraEsp] OnSceneWasLoaded: " + ex.Message);
			}
		}

		public override void OnUpdate()
		{
			try
			{
				if (!EspConfig.Enabled.Value)
				{
					FeedOverlay.HideAll();
					_wasMatchActive = false;
					return;
				}
				float unscaledTime = Time.unscaledTime;
				bool isHost = PvpApi.IsHost;
				bool isTeamsMatchActive = PvpApi.IsTeamsMatchActive;
				bool isMatchActive = PvpApi.IsMatchActive;
				CameraOwnership.Tick(EspConfig.OwnPlacementRadius.Value);
				if (isHost && EspConfig.CleanStaleCameras.Value && PvpApi.IsMultiplayer && unscaledTime >= _nextStaleScan)
				{
					_nextStaleScan = unscaledTime + 5f;
					int num = NetEyeBridge.RemoveStaleCameras();
					if (num > 0 && EspConfig.DebugLog.Value)
					{
						MelonLogger.Msg($"[PvpCameraEsp] removed {num} stale camera(s)");
					}
				}
				if (_wasMatchActive && !isMatchActive && EspConfig.CleanupOwnCamerasOnRoundEnd.Value)
				{
					CameraOwnership.QueuePickUpMine();
				}
				else if (!_wasMatchActive && isMatchActive)
				{
					CameraOwnership.AbortPickup();
				}
				_wasMatchActive = isMatchActive;
				CameraOwnership.TickPickupRetry();
				if (!isTeamsMatchActive)
				{
					FeedOverlay.HideAll();
					return;
				}
				if (unscaledTime >= _nextSensorScan)
				{
					_nextSensorScan = unscaledTime + 0.25f;
					IReadOnlyList<CamEntry> readOnlyList = NetEyeBridge.AllCameras();
					for (int i = 0; i < readOnlyList.Count; i++)
					{
						if (CameraOwnership.IsMineCamera(readOnlyList[i].Cam))
						{
							List<VisibleEnemy> list = EnemyTracker.Scan(readOnlyList[i].Cam);
							if (list.Count > 0)
							{
								SightingReporter.Report(list, readOnlyList[i].Name);
							}
						}
					}
				}
				if (NetEyeBridge.TryGetLive(out var cam, out var feed, out var _) && CameraOwnership.IsMineCamera(cam))
				{
					FeedOverlay.Update(feed, EnemyTracker.Scan(cam));
				}
				else
				{
					FeedOverlay.HideAll();
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[PvpCameraEsp] OnUpdate: " + ex.Message);
			}
		}
	}
	internal static class SightingReporter
	{
		private static readonly Dictionary<string, float> _lastSeen = new Dictionary<string, float>();

		private static readonly Dictionary<string, float> _lastFired = new Dictionary<string, float>();

		internal static void Report(List<VisibleEnemy> enemies, string cameraName)
		{
			float unscaledTime = Time.unscaledTime;
			float num = Mathf.Max(0.5f, EspConfig.ReportCooldownSeconds.Value);
			float value = EspConfig.RemindWhileVisibleSeconds.Value;
			for (int i = 0; i < enemies.Count; i++)
			{
				VisibleEnemy visibleEnemy = enemies[i];
				string text = ((visibleEnemy.SteamId != 0L) ? visibleEnemy.SteamId.ToString() : ("n:" + visibleEnemy.Persona));
				string key = text + "@" + cameraName;
				float value2;
				bool flag = !_lastSeen.TryGetValue(key, out value2) || unscaledTime - value2 > num;
				float value3;
				bool flag2 = value > 0f && _lastFired.TryGetValue(key, out value3) && unscaledTime - value3 >= value;
				_lastSeen[key] = unscaledTime;
				if (flag || flag2)
				{
					_lastFired[key] = unscaledTime;
					if (EspConfig.DebugLog.Value)
					{
						MelonLogger.Msg($"[PvpCameraEsp] ALERT{((flag2 && !flag) ? " (reminder)" : "")}: {visibleEnemy.Persona} (team {visibleEnemy.Team}, steamId {visibleEnemy.SteamId}) @ {cameraName}");
					}
					PvpApi.ReportCameraSighting(visibleEnemy.Team, visibleEnemy.SteamId, visibleEnemy.Persona, cameraName);
				}
			}
			if (_lastSeen.Count > 128)
			{
				Prune(unscaledTime, num);
			}
		}

		private static void Prune(float now, float rearm)
		{
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, float> item in _lastSeen)
			{
				if (now - item.Value > rearm * 4f + 10f)
				{
					list.Add(item.Key);
				}
			}
			for (int i = 0; i < list.Count; i++)
			{
				_lastSeen.Remove(list[i]);
				_lastFired.Remove(list[i]);
			}
		}

		internal static void Reset()
		{
			try
			{
				_lastSeen.Clear();
				_lastFired.Clear();
			}
			catch
			{
			}
		}
	}
}

PvpCameraEsp.MONO.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using HarmonyLib;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using MultiplayerPVP.Core;
using PvpCameraEsp;
using ScheduleOne.EntityFramework;
using ScheduleOne.ItemFramework;
using ScheduleOne.PlayerScripts;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonAdditionalDependencies(new string[] { "MultiplayerPVP" })]
[assembly: MelonOptionalDependencies(new string[] { "NetEye" })]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: MelonInfo(typeof(PvpCameraEspMod), "PvpCameraEsp", "1.0.3", "Virtunerd", null)]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: AssemblyFileVersion("1.0.3")]
[assembly: AssemblyInformationalVersion("1.0.3")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.3.0")]
[module: UnverifiableCode]
[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 PvpCameraEsp
{
	internal static class CameraBuildTracker
	{
		private static bool _active;

		private static float _graceUntil;

		private const float GraceSeconds = 2.5f;

		private static bool _hooked;

		internal static bool Hooked => _hooked;

		internal static bool LocalPlacingCamera
		{
			get
			{
				try
				{
					return _active || Time.unscaledTime < _graceUntil;
				}
				catch
				{
					return false;
				}
			}
		}

		internal static void Apply(Harmony h)
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Expected O, but got Unknown
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Expected O, but got Unknown
			try
			{
				Type type = ResolveBuildManager();
				if (type == null)
				{
					MelonLogger.Warning("[PvpCameraEsp] BuildManager type not found — ownership falls back to proximity.");
					return;
				}
				MethodInfo methodInfo = FindMethod(type, "StartBuilding");
				if (methodInfo == null)
				{
					MelonLogger.Warning("[PvpCameraEsp] BuildManager.StartBuilding not found — ownership falls back to proximity.");
					return;
				}
				MethodInfo method = typeof(CameraBuildTracker).GetMethod("StartPostfix", BindingFlags.Static | BindingFlags.NonPublic);
				h.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				MethodInfo methodInfo2 = FindMethod(type, "StopBuilding");
				if (methodInfo2 != null)
				{
					MethodInfo method2 = typeof(CameraBuildTracker).GetMethod("StopPostfix", BindingFlags.Static | BindingFlags.NonPublic);
					h.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				_hooked = true;
				MelonLogger.Msg("[PvpCameraEsp] camera-placement tracker armed (BuildManager hooked).");
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[PvpCameraEsp] CameraBuildTracker.Apply: " + ex.Message);
			}
		}

		private static void StartPostfix(ItemInstance __0)
		{
			try
			{
				string text = ItemId(__0);
				if (EspConfig.DebugLog.Value)
				{
					MelonLogger.Msg("[PvpCameraEsp] StartBuilding item='" + (text ?? "?") + "'");
				}
				if (!string.IsNullOrEmpty(text) && text.IndexOf("NetEye", StringComparison.OrdinalIgnoreCase) >= 0 && text.IndexOf("Camera", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					_active = true;
					_graceUntil = Time.unscaledTime + 2.5f;
					if (EspConfig.DebugLog.Value)
					{
						MelonLogger.Msg("[PvpCameraEsp] local CAMERA placement STARTED → next new camera = mine");
					}
				}
			}
			catch
			{
			}
		}

		private static void StopPostfix()
		{
			try
			{
				bool active = _active;
				_active = false;
				if (active)
				{
					_graceUntil = Time.unscaledTime + 2.5f;
					if (EspConfig.DebugLog.Value)
					{
						MelonLogger.Msg("[PvpCameraEsp] local camera placement STOPPED (grace armed)");
					}
				}
			}
			catch
			{
			}
		}

		private static string ItemId(ItemInstance item)
		{
			try
			{
				if (item == null)
				{
					return null;
				}
				object member = GetMember(item, "Definition");
				if (member == null)
				{
					return null;
				}
				return GetMember(member, "ID") as string;
			}
			catch
			{
				return null;
			}
		}

		private static object GetMember(object target, string name)
		{
			if (target == null)
			{
				return null;
			}
			Type type = target.GetType();
			try
			{
				PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
				if (property != null)
				{
					return property.GetValue(target);
				}
			}
			catch
			{
			}
			try
			{
				FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
				if (field != null)
				{
					return field.GetValue(target);
				}
			}
			catch
			{
			}
			return null;
		}

		private static MethodInfo FindMethod(Type t, string name)
		{
			try
			{
				return t.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			}
			catch (AmbiguousMatchException)
			{
				MethodInfo methodInfo = null;
				MethodInfo[] methods = t.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (MethodInfo methodInfo2 in methods)
				{
					if (!(methodInfo2.Name != name))
					{
						if (methodInfo == null)
						{
							methodInfo = methodInfo2;
						}
						ParameterInfo[] parameters = methodInfo2.GetParameters();
						if (parameters.Length == 1)
						{
							methodInfo = methodInfo2;
							break;
						}
					}
				}
				return methodInfo;
			}
			catch
			{
				return null;
			}
		}

		private static Type ResolveBuildManager()
		{
			Type type = FindType("Il2CppScheduleOne.Building.BuildManager") ?? FindType("ScheduleOne.Building.BuildManager");
			if (type != null)
			{
				return type;
			}
			try
			{
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				foreach (Assembly assembly in assemblies)
				{
					if (assembly.GetName().Name != "Assembly-CSharp")
					{
						continue;
					}
					Type[] types;
					try
					{
						types = assembly.GetTypes();
					}
					catch
					{
						continue;
					}
					Type[] array = types;
					foreach (Type type2 in array)
					{
						if (type2.Name == "BuildManager" && type2.Namespace != null && type2.Namespace.IndexOf("ScheduleOne", StringComparison.Ordinal) >= 0)
						{
							return type2;
						}
					}
				}
			}
			catch
			{
			}
			return null;
		}

		private static Type FindType(string fullName)
		{
			try
			{
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				foreach (Assembly assembly in assemblies)
				{
					Type type = assembly.GetType(fullName);
					if (type != null)
					{
						return type;
					}
				}
			}
			catch
			{
			}
			try
			{
				return Type.GetType(fullName + ", Assembly-CSharp");
			}
			catch
			{
				return null;
			}
		}

		internal static void Reset()
		{
			_active = false;
			_graceUntil = 0f;
		}
	}
	internal static class CameraGuard
	{
		internal static void Apply()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			try
			{
				Harmony h = new Harmony("com.virtunerd.pvpcameraesp");
				Type typeFromHandle = typeof(BuildableItem);
				PatchVoid(h, typeFromHandle, "PickupItem");
				PatchCan(h, typeFromHandle, "CanBePickedUp");
				PatchCan(h, typeFromHandle, "CanBeDestroyed");
				CameraBuildTracker.Apply(h);
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[PvpCameraEsp] guard apply: " + ex.Message);
			}
		}

		private static bool ShouldBlock(BuildableItem bi)
		{
			try
			{
				if (!EspConfig.ProtectCameras.Value)
				{
					return false;
				}
				if (!PvpApi.IsMatchActive)
				{
					return false;
				}
				if ((Object)(object)bi == (Object)null)
				{
					return false;
				}
				GameObject gameObject = ((Component)bi).gameObject;
				if ((Object)(object)gameObject == (Object)null)
				{
					return false;
				}
				if (!IsNetEyeCameraDeployable(gameObject))
				{
					return false;
				}
				if (CameraOwnership.IsMine(((Object)gameObject).GetInstanceID()))
				{
					return false;
				}
				return true;
			}
			catch
			{
				return false;
			}
		}

		private static bool IsNetEyeCameraDeployable(GameObject go)
		{
			try
			{
				Transform transform = go.transform;
				int childCount = transform.childCount;
				for (int i = 0; i < childCount; i++)
				{
					Transform child = transform.GetChild(i);
					if ((Object)(object)child != (Object)null && ((Object)child).name != null && ((Object)child).name.StartsWith("NetEye_"))
					{
						return true;
					}
				}
			}
			catch
			{
			}
			return false;
		}

		private static bool BlockVoidPrefix(BuildableItem __instance)
		{
			try
			{
				if (ShouldBlock(__instance))
				{
					return false;
				}
			}
			catch
			{
			}
			return true;
		}

		private static bool CanPrefix(BuildableItem __instance, ref string reason, ref bool __result)
		{
			try
			{
				if (ShouldBlock(__instance))
				{
					reason = "Protected PvP camera";
					__result = false;
					return false;
				}
			}
			catch
			{
			}
			return true;
		}

		private static void PatchVoid(Harmony h, Type t, string method)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			try
			{
				MethodInfo method2 = t.GetMethod(method, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (method2 == null)
				{
					MelonLogger.Warning("[PvpCameraEsp] guard: " + method + " not found");
					return;
				}
				MethodInfo method3 = typeof(CameraGuard).GetMethod("BlockVoidPrefix", BindingFlags.Static | BindingFlags.NonPublic);
				h.Patch((MethodBase)method2, new HarmonyMethod(method3), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[PvpCameraEsp] guard patch " + method + ": " + ex.Message);
			}
		}

		private static void PatchCan(Harmony h, Type t, string method)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			try
			{
				MethodInfo method2 = t.GetMethod(method, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (!(method2 == null))
				{
					MethodInfo method3 = typeof(CameraGuard).GetMethod("CanPrefix", BindingFlags.Static | BindingFlags.NonPublic);
					h.Patch((MethodBase)method2, new HarmonyMethod(method3), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[PvpCameraEsp] guard patch " + method + ": " + ex.Message);
			}
		}
	}
	internal static class CameraOwnership
	{
		private static readonly HashSet<int> _known = new HashSet<int>();

		private static readonly Dictionary<int, float> _pending = new Dictionary<int, float>();

		private static readonly Dictionary<int, BuildableItem> _mine = new Dictionary<int, BuildableItem>();

		private const float ClaimWindow = 2.5f;

		private const float PlacingClaimRadius = 10f;

		private static readonly Dictionary<int, BuildableItem> _pendingPickup = new Dictionary<int, BuildableItem>();

		private static float _nextPickupTry;

		private static int _pickupRounds;

		private const float PickupInterval = 1.5f;

		private const int MaxPickupRounds = 12;

		internal static bool PickupPending => _pendingPickup.Count > 0;

		internal static bool IsMine(int deployableInstanceId)
		{
			return _mine.ContainsKey(deployableInstanceId);
		}

		internal static bool IsMineCamera(Camera cam)
		{
			try
			{
				if ((Object)(object)cam == (Object)null)
				{
					return false;
				}
				BuildableItem val = FindDeployable(cam);
				if ((Object)(object)val == (Object)null)
				{
					return false;
				}
				return _mine.ContainsKey(((Object)((Component)val).gameObject).GetInstanceID());
			}
			catch
			{
				return false;
			}
		}

		internal static void Tick(float radius)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: 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)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				bool localPlacingCamera = CameraBuildTracker.LocalPlacingCamera;
				bool hooked = CameraBuildTracker.Hooked;
				float unscaledTime = Time.unscaledTime;
				Player localPlayer = PvpApi.LocalPlayer;
				bool flag = (Object)(object)localPlayer != (Object)null;
				Vector3 val = Vector3.zero;
				if (flag)
				{
					try
					{
						val = ((Component)localPlayer).transform.position;
					}
					catch
					{
						flag = false;
					}
				}
				IReadOnlyList<CamEntry> readOnlyList = NetEyeBridge.AllCameras();
				for (int i = 0; i < readOnlyList.Count; i++)
				{
					Camera cam = readOnlyList[i].Cam;
					if ((Object)(object)cam == (Object)null)
					{
						continue;
					}
					BuildableItem val2 = FindDeployable(cam);
					if ((Object)(object)val2 == (Object)null)
					{
						continue;
					}
					int instanceID;
					try
					{
						instanceID = ((Object)((Component)val2).gameObject).GetInstanceID();
					}
					catch
					{
						continue;
					}
					if (_mine.ContainsKey(instanceID) || _known.Contains(instanceID) || _pendingPickup.ContainsKey(instanceID))
					{
						continue;
					}
					if (localPlacingCamera)
					{
						bool flag2 = !flag;
						if (flag)
						{
							try
							{
								Vector3 val3 = ((Component)val2).transform.position - val;
								val3.y = 0f;
								flag2 = ((Vector3)(ref val3)).magnitude <= 10f;
							}
							catch
							{
								flag2 = true;
							}
						}
						if (flag2)
						{
							_mine[instanceID] = val2;
							_pending.Remove(instanceID);
							_known.Add(instanceID);
							if (EspConfig.DebugLog.Value)
							{
								MelonLogger.Msg("[PvpCameraEsp] claimed own camera (local build flow)");
							}
						}
						continue;
					}
					if (hooked)
					{
						_known.Add(instanceID);
						_pending.Remove(instanceID);
						continue;
					}
					if (!_pending.TryGetValue(instanceID, out var value))
					{
						_pending[instanceID] = unscaledTime;
						value = unscaledTime;
					}
					bool flag3 = false;
					if (flag)
					{
						try
						{
							Vector3 val4 = ((Component)val2).transform.position - val;
							val4.y = 0f;
							flag3 = ((Vector3)(ref val4)).magnitude <= radius;
						}
						catch
						{
						}
					}
					if (flag3)
					{
						_mine[instanceID] = val2;
						_pending.Remove(instanceID);
						_known.Add(instanceID);
					}
					else if (unscaledTime - value > 2.5f)
					{
						_pending.Remove(instanceID);
						_known.Add(instanceID);
					}
				}
			}
			catch
			{
			}
		}

		private static BuildableItem FindDeployable(Camera cam)
		{
			try
			{
				Transform val = ((Component)cam).transform;
				int num = 0;
				while ((Object)(object)val != (Object)null && num++ < 64)
				{
					BuildableItem component = ((Component)val).GetComponent<BuildableItem>();
					if ((Object)(object)component != (Object)null)
					{
						return component;
					}
					val = val.parent;
				}
			}
			catch
			{
			}
			return null;
		}

		internal static void QueuePickUpMine()
		{
			foreach (KeyValuePair<int, BuildableItem> item in _mine)
			{
				if ((Object)(object)item.Value != (Object)null)
				{
					_pendingPickup[item.Key] = item.Value;
				}
			}
			_pickupRounds = 0;
			_nextPickupTry = 0f;
			_mine.Clear();
			_known.Clear();
			_pending.Clear();
		}

		internal static void TickPickupRetry()
		{
			if (_pendingPickup.Count == 0)
			{
				return;
			}
			float unscaledTime = Time.unscaledTime;
			if (unscaledTime < _nextPickupTry)
			{
				return;
			}
			_nextPickupTry = unscaledTime + 1.5f;
			bool value = EspConfig.DebugLog.Value;
			List<int> list = new List<int>();
			foreach (KeyValuePair<int, BuildableItem> item in _pendingPickup)
			{
				BuildableItem value2 = item.Value;
				if ((Object)(object)value2 == (Object)null)
				{
					list.Add(item.Key);
					continue;
				}
				bool flag = false;
				try
				{
					flag = value2.IsDestroyed;
				}
				catch
				{
				}
				if (flag)
				{
					list.Add(item.Key);
					continue;
				}
				string arg = null;
				bool flag2 = false;
				try
				{
					flag2 = value2.CanBePickedUp(ref arg);
				}
				catch
				{
				}
				if (value)
				{
					MelonLogger.Msg($"[PvpCameraEsp] pickup-retry: can={flag2} reason='{arg}' host={PvpApi.IsHost}");
				}
				if (!flag2)
				{
					continue;
				}
				try
				{
					value2.PickupItem();
				}
				catch (Exception ex)
				{
					if (value)
					{
						MelonLogger.Msg("[PvpCameraEsp] pickup-retry threw: " + ex.Message);
					}
				}
			}
			for (int i = 0; i < list.Count; i++)
			{
				_pendingPickup.Remove(list[i]);
			}
			if (_pendingPickup.Count > 0 && ++_pickupRounds >= 12)
			{
				if (value)
				{
					MelonLogger.Warning($"[PvpCameraEsp] gave up restoring {_pendingPickup.Count} camera(s) after {12} tries");
				}
				_pendingPickup.Clear();
			}
		}

		internal static void AbortPickup()
		{
			_pendingPickup.Clear();
			_pickupRounds = 0;
		}

		internal static void Reset()
		{
			_known.Clear();
			_mine.Clear();
			_pending.Clear();
			_pendingPickup.Clear();
			_pickupRounds = 0;
		}
	}
	internal struct VisibleEnemy
	{
		internal Player Player;

		internal int Team;

		internal ulong SteamId;

		internal string Persona;

		internal Vector3 ViewportFeet;

		internal Vector3 ViewportTop;
	}
	internal static class EnemyTracker
	{
		private static readonly List<VisibleEnemy> _result = new List<VisibleEnemy>(8);

		internal static List<VisibleEnemy> Scan(Camera cam)
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: 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_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_0259: Unknown result type (might be due to invalid IL or missing references)
			//IL_025b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0262: Unknown result type (might be due to invalid IL or missing references)
			//IL_0264: Unknown result type (might be due to invalid IL or missing references)
			_result.Clear();
			if ((Object)(object)cam == (Object)null)
			{
				return _result;
			}
			int localTeam = PvpApi.LocalTeam;
			if (localTeam < 0)
			{
				return _result;
			}
			Player localPlayer = PvpApi.LocalPlayer;
			List<Player> players = PvpApi.Players;
			float value = EspConfig.MaxDistance.Value;
			float num = Mathf.Max(0.5f, EspConfig.BodyHeight.Value);
			bool value2 = EspConfig.RequireLineOfSight.Value;
			Vector3 position = ((Component)cam).transform.position;
			ulong steamId = default(ulong);
			string persona = default(string);
			for (int i = 0; i < players.Count; i++)
			{
				Player val = players[i];
				if ((Object)(object)val == (Object)null || ((Object)(object)localPlayer != (Object)null && (val == localPlayer || (Object)(object)val == (Object)(object)localPlayer)))
				{
					continue;
				}
				int team = PvpApi.GetTeam(val);
				if (team < 0 || team == localTeam)
				{
					continue;
				}
				Vector3 position2;
				Vector3 val2;
				Vector3 val3;
				try
				{
					position2 = ((Component)val).transform.position;
					val2 = position2 + Vector3.up * num;
					val3 = position2 + Vector3.up * (num * 0.5f);
				}
				catch
				{
					continue;
				}
				if (Vector3.Distance(position, val3) > value)
				{
					continue;
				}
				Vector3 val4;
				Vector3 val5;
				try
				{
					val4 = cam.WorldToViewportPoint(position2);
					val5 = cam.WorldToViewportPoint(val2);
				}
				catch
				{
					continue;
				}
				if (!(val4.z <= 0f) && !(val5.z <= 0f))
				{
					float num2 = (val4.x + val5.x) * 0.5f;
					float num3 = (val4.y + val5.y) * 0.5f;
					if (!(num2 < -0.2f) && !(num2 > 1.2f) && !(num3 < -0.2f) && !(num3 > 1.2f) && (!value2 || !IsOccluded(position, val3, val)))
					{
						PvpApi.TryGetIdentity(val, ref steamId, ref persona);
						_result.Add(new VisibleEnemy
						{
							Player = val,
							Team = team,
							SteamId = steamId,
							Persona = persona,
							ViewportFeet = val4,
							ViewportTop = val5
						});
					}
				}
			}
			return _result;
		}

		private static bool IsOccluded(Vector3 from, Vector3 to, Player target)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Vector3 val = to - from;
				float magnitude = ((Vector3)(ref val)).magnitude;
				if (magnitude < 0.05f)
				{
					return false;
				}
				RaycastHit val2 = default(RaycastHit);
				if (!Physics.Raycast(from, val / magnitude, ref val2, magnitude - 0.3f))
				{
					return false;
				}
				if ((Object)(object)((RaycastHit)(ref val2)).collider == (Object)null)
				{
					return false;
				}
				Player componentInParent = ((Component)((RaycastHit)(ref val2)).collider).GetComponentInParent<Player>();
				return !((Object)(object)componentInParent != (Object)null) || (componentInParent != target && !((Object)(object)componentInParent == (Object)(object)target));
			}
			catch
			{
				return false;
			}
		}
	}
	internal static class EspConfig
	{
		private static MelonPreferences_Category _cat;

		internal static MelonPreferences_Entry<bool> Enabled;

		internal static MelonPreferences_Entry<float> MaxDistance;

		internal static MelonPreferences_Entry<bool> RequireLineOfSight;

		internal static MelonPreferences_Entry<float> ReportCooldownSeconds;

		internal static MelonPreferences_Entry<float> RemindWhileVisibleSeconds;

		internal static MelonPreferences_Entry<bool> ShowBox;

		internal static MelonPreferences_Entry<int> BoxThickness;

		internal static MelonPreferences_Entry<float> BodyHeight;

		internal static MelonPreferences_Entry<string> BoxColorMode;

		internal static MelonPreferences_Entry<string> BoxColor;

		internal static MelonPreferences_Entry<bool> ShowLabels;

		internal static MelonPreferences_Entry<int> LabelFontSize;

		internal static MelonPreferences_Entry<bool> DebugLog;

		internal static MelonPreferences_Entry<bool> ProtectCameras;

		internal static MelonPreferences_Entry<float> OwnPlacementRadius;

		internal static MelonPreferences_Entry<bool> CleanupOwnCamerasOnRoundEnd;

		internal static MelonPreferences_Entry<bool> CleanStaleCameras;

		internal static void Load()
		{
			_cat = MelonPreferences.CreateCategory("PvpCameraEsp");
			Enabled = _cat.CreateEntry<bool>("Enabled", true, (string)null, "Master toggle for the camera ESP.", false, false, (ValueValidator)null, (string)null);
			MaxDistance = _cat.CreateEntry<float>("MaxDistance", 80f, (string)null, "Max distance (m) from the camera to detect an enemy (camera far clip is ~80).", false, false, (ValueValidator)null, (string)null);
			RequireLineOfSight = _cat.CreateEntry<bool>("RequireLineOfSight", true, (string)null, "Only detect enemies with a clear line of sight (not behind walls). Disable if detection misses.", false, false, (ValueValidator)null, (string)null);
			ReportCooldownSeconds = _cat.CreateEntry<float>("ReportCooldownSeconds", 5f, (string)null, "Re-arm window: an enemy must be GONE from a camera this long before a NEW alert fires (edge-triggered, no spam while they stay in view).", false, false, (ValueValidator)null, (string)null);
			RemindWhileVisibleSeconds = _cat.CreateEntry<float>("RemindWhileVisibleSeconds", 0f, (string)null, "Optional: re-alert every N seconds while an enemy stays continuously in view (0 = off, alert only on enter).", false, false, (ValueValidator)null, (string)null);
			ShowBox = _cat.CreateEntry<bool>("ShowBox", true, (string)null, "Draw a box around each spotted enemy on the camera feed (ESP box).", false, false, (ValueValidator)null, (string)null);
			BoxThickness = _cat.CreateEntry<int>("BoxThickness", 2, (string)null, "Border thickness (px) of the ESP box.", false, false, (ValueValidator)null, (string)null);
			BodyHeight = _cat.CreateEntry<float>("BodyHeight", 2f, (string)null, "Assumed player height (m) used to size the box from feet to head.", false, false, (ValueValidator)null, (string)null);
			BoxColorMode = _cat.CreateEntry<string>("BoxColorMode", "enemyteam", (string)null, "Box/label colour source: 'enemyteam' (spotted enemy's team colour), 'ownteam' (your team = the camera owner's team), or 'custom' (use BoxColor).", false, false, (ValueValidator)null, (string)null);
			BoxColor = _cat.CreateEntry<string>("BoxColor", "FF3030", (string)null, "Custom box/label colour as hex RGB or RGBA (e.g. FF3030 or FF3030C0). Used only when BoxColorMode = custom.", false, false, (ValueValidator)null, (string)null);
			ShowLabels = _cat.CreateEntry<bool>("ShowLabels", true, (string)null, "Draw the enemy's Steam name above the box on the camera feed.", false, false, (ValueValidator)null, (string)null);
			LabelFontSize = _cat.CreateEntry<int>("LabelFontSize", 20, (string)null, "Font size of the on-feed name labels.", false, false, (ValueValidator)null, (string)null);
			DebugLog = _cat.CreateEntry<bool>("DebugLog", false, (string)null, "Verbose logging (cameras found, alerts) for diagnosing the live test.", false, false, (ValueValidator)null, (string)null);
			ProtectCameras = _cat.CreateEntry<bool>("ProtectCameras", true, (string)null, "During a Teams match, block players from picking up / demolishing cameras they didn't place (protects client cameras from the host & host-team, and vice-versa).", false, false, (ValueValidator)null, (string)null);
			OwnPlacementRadius = _cat.CreateEntry<float>("OwnPlacementRadius", 4f, (string)null, "FALLBACK ONLY (used if the BuildManager hook isn't available): a newly-placed camera within this horizontal distance (m) of you is treated as YOURS. Normally ownership comes from the local build flow and this is ignored.", false, false, (ValueValidator)null, (string)null);
			CleanupOwnCamerasOnRoundEnd = _cat.CreateEntry<bool>("CleanupOwnCamerasOnRoundEnd", true, (string)null, "Pick up your own cameras (back into your inventory) automatically when a match ends, so they don't linger in the NetEye app. Applies to both host and client.", false, false, (ValueValidator)null, (string)null);
			CleanStaleCameras = _cat.CreateEntry<bool>("CleanStaleCameras", true, (string)null, "HOST: remove stale camera entries (loaded from a previous session's cameras.txt, shown in the app but not backed by a live camera) while in a multiplayer match.", false, false, (ValueValidator)null, (string)null);
		}

		internal static Color ResolveBoxColor(int enemyTeam)
		{
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			string text = (BoxColorMode.Value ?? "").Trim().ToLowerInvariant();
			if (text == "ownteam")
			{
				int localTeam = PvpApi.LocalTeam;
				return PvpApi.TeamColor((localTeam >= 0) ? localTeam : 0);
			}
			if (text == "custom")
			{
				string value = BoxColor.Value;
				Color result = default(Color);
				if (!string.IsNullOrEmpty(value) && ColorUtility.TryParseHtmlString((value[0] == '#') ? value : ("#" + value), ref result))
				{
					return result;
				}
				return Color.red;
			}
			return PvpApi.TeamColor(enemyTeam);
		}
	}
	internal static class FeedOverlay
	{
		private sealed class EnemyBox
		{
			internal RectTransform Root;

			internal RawImage Top;

			internal RawImage Bottom;

			internal RawImage Left;

			internal RawImage Right;

			internal TextMeshProUGUI Label;
		}

		private static RawImage _bound;

		private static RectTransform _container;

		private static TMP_FontAsset _font;

		private static bool _fontResolved;

		private static bool _warnedNoFont;

		private static Texture2D _white;

		private static readonly Dictionary<string, EnemyBox> _boxes = new Dictionary<string, EnemyBox>();

		private static readonly HashSet<string> _seen = new HashSet<string>();

		private static Texture2D White
		{
			get
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_001d: Expected O, but got Unknown
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)_white == (Object)null)
				{
					_white = new Texture2D(1, 1);
					_white.SetPixel(0, 0, Color.white);
					_white.Apply();
				}
				return _white;
			}
		}

		internal static void Update(RawImage feed, List<VisibleEnemy> enemies)
		{
			//IL_0075: 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_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_0233: Unknown result type (might be due to invalid IL or missing references)
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)feed == (Object)null)
			{
				HideAll();
				return;
			}
			bool value = EspConfig.ShowBox.Value;
			bool value2 = EspConfig.ShowLabels.Value;
			if (!value && !value2)
			{
				HideAll();
				return;
			}
			EnsureContainer(feed);
			if ((Object)(object)_container == (Object)null)
			{
				return;
			}
			TMP_FontAsset font = ResolveFont();
			Rect rect = ((Graphic)feed).rectTransform.rect;
			Vector2 size = ((Rect)(ref rect)).size;
			int value3 = EspConfig.LabelFontSize.Value;
			_seen.Clear();
			Vector2 val = default(Vector2);
			Vector2 val2 = default(Vector2);
			Vector2 anchoredPosition = default(Vector2);
			for (int i = 0; i < enemies.Count; i++)
			{
				VisibleEnemy visibleEnemy = enemies[i];
				string text = ((visibleEnemy.SteamId != 0L) ? visibleEnemy.SteamId.ToString() : ("n:" + visibleEnemy.Persona));
				_seen.Add(text);
				EnemyBox orCreate = GetOrCreate(text, font);
				if (orCreate == null)
				{
					continue;
				}
				((Vector2)(ref val))..ctor((visibleEnemy.ViewportFeet.x - 0.5f) * size.x, (visibleEnemy.ViewportFeet.y - 0.5f) * size.y);
				((Vector2)(ref val2))..ctor((visibleEnemy.ViewportTop.x - 0.5f) * size.x, (visibleEnemy.ViewportTop.y - 0.5f) * size.y);
				float num = Mathf.Max(6f, Mathf.Abs(val2.y - val.y));
				float num2 = Mathf.Clamp(num * 0.4f, 6f, num);
				((Vector2)(ref anchoredPosition))..ctor((val.x + val2.x) * 0.5f, (val.y + val2.y) * 0.5f);
				orCreate.Root.anchoredPosition = anchoredPosition;
				orCreate.Root.sizeDelta = new Vector2(num2, num);
				Color val3 = EspConfig.ResolveBoxColor(visibleEnemy.Team);
				SetEdge(orCreate.Top, value, val3);
				SetEdge(orCreate.Bottom, value, val3);
				SetEdge(orCreate.Left, value, val3);
				SetEdge(orCreate.Right, value, val3);
				if ((Object)(object)orCreate.Label != (Object)null)
				{
					((Component)orCreate.Label).gameObject.SetActive(value2);
					if (value2)
					{
						((TMP_Text)orCreate.Label).text = visibleEnemy.Persona;
						((TMP_Text)orCreate.Label).fontSize = value3;
						((Graphic)orCreate.Label).color = val3;
					}
				}
				if (!((Component)orCreate.Root).gameObject.activeSelf)
				{
					((Component)orCreate.Root).gameObject.SetActive(true);
				}
			}
			foreach (KeyValuePair<string, EnemyBox> box in _boxes)
			{
				if (!_seen.Contains(box.Key) && (Object)(object)box.Value.Root != (Object)null && ((Component)box.Value.Root).gameObject.activeSelf)
				{
					((Component)box.Value.Root).gameObject.SetActive(false);
				}
			}
		}

		private static void SetEdge(RawImage edge, bool show, Color col)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)edge == (Object)null))
			{
				if (((Component)edge).gameObject.activeSelf != show)
				{
					((Component)edge).gameObject.SetActive(show);
				}
				if (show)
				{
					((Graphic)edge).color = col;
				}
			}
		}

		internal static void HideAll()
		{
			try
			{
				foreach (KeyValuePair<string, EnemyBox> box in _boxes)
				{
					if ((Object)(object)box.Value.Root != (Object)null && ((Component)box.Value.Root).gameObject.activeSelf)
					{
						((Component)box.Value.Root).gameObject.SetActive(false);
					}
				}
			}
			catch
			{
			}
		}

		private static void EnsureContainer(RawImage feed)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_bound == (Object)(object)feed && (Object)(object)_container != (Object)null)
			{
				return;
			}
			_boxes.Clear();
			_bound = feed;
			try
			{
				GameObject val = new GameObject("PvpCamEsp_Overlay");
				RectTransform val2 = val.AddComponent<RectTransform>();
				((Transform)val2).SetParent(((Component)feed).transform, false);
				val2.anchorMin = Vector2.zero;
				val2.anchorMax = Vector2.one;
				val2.offsetMin = Vector2.zero;
				val2.offsetMax = Vector2.zero;
				val.AddComponent<RectMask2D>();
				_container = val2;
				if (EspConfig.DebugLog.Value)
				{
					MelonLogger.Msg("[PvpCameraEsp] overlay container attached to feed");
				}
			}
			catch
			{
				_container = null;
			}
		}

		private static EnemyBox GetOrCreate(string key, TMP_FontAsset font)
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: 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_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0216: Unknown result type (might be due to invalid IL or missing references)
			if (_boxes.TryGetValue(key, out var value) && (Object)(object)value.Root != (Object)null)
			{
				return value;
			}
			try
			{
				int num = Mathf.Max(1, EspConfig.BoxThickness.Value);
				RectTransform val = NewRect("box_" + key, (Transform)(object)_container, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f));
				value = new EnemyBox
				{
					Root = val
				};
				value.Top = Edge((Transform)(object)val, new Vector2(0f, 1f), new Vector2(1f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, (float)num));
				value.Bottom = Edge((Transform)(object)val, new Vector2(0f, 0f), new Vector2(1f, 0f), new Vector2(0.5f, 0f), new Vector2(0f, (float)num));
				value.Left = Edge((Transform)(object)val, new Vector2(0f, 0f), new Vector2(0f, 1f), new Vector2(0f, 0.5f), new Vector2((float)num, 0f));
				value.Right = Edge((Transform)(object)val, new Vector2(1f, 0f), new Vector2(1f, 1f), new Vector2(1f, 0.5f), new Vector2((float)num, 0f));
				if ((Object)(object)font != (Object)null)
				{
					RectTransform val2 = NewRect("name", (Transform)(object)val, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0.5f, 0f));
					val2.sizeDelta = new Vector2(260f, 28f);
					val2.anchoredPosition = new Vector2(0f, 4f);
					TextMeshProUGUI val3 = ((Component)val2).gameObject.AddComponent<TextMeshProUGUI>();
					((TMP_Text)val3).font = font;
					((TMP_Text)val3).alignment = (TextAlignmentOptions)1026;
					((TMP_Text)val3).enableWordWrapping = false;
					((TMP_Text)val3).richText = false;
					((TMP_Text)val3).fontStyle = (FontStyles)1;
					((TMP_Text)val3).overflowMode = (TextOverflowModes)0;
					((Graphic)val3).raycastTarget = false;
					value.Label = val3;
				}
				else if (!_warnedNoFont)
				{
					_warnedNoFont = true;
					MelonLogger.Warning("[PvpCameraEsp] No TMP font found — boxes still draw, name labels disabled.");
				}
				_boxes[key] = value;
				return value;
			}
			catch
			{
				return null;
			}
		}

		private static RectTransform NewRect(string name, Transform parent, Vector2 aMin, Vector2 aMax, Vector2 pivot)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			RectTransform val2 = val.AddComponent<RectTransform>();
			((Transform)val2).SetParent(parent, false);
			val2.anchorMin = aMin;
			val2.anchorMax = aMax;
			val2.pivot = pivot;
			val2.anchoredPosition = Vector2.zero;
			return val2;
		}

		private static RawImage Edge(Transform parent, Vector2 aMin, Vector2 aMax, Vector2 pivot, Vector2 sizeDelta)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = NewRect("edge", parent, aMin, aMax, pivot);
			val.sizeDelta = sizeDelta;
			RawImage val2 = ((Component)val).gameObject.AddComponent<RawImage>();
			val2.texture = (Texture)(object)White;
			((Graphic)val2).raycastTarget = false;
			return val2;
		}

		private static TMP_FontAsset ResolveFont()
		{
			if (_fontResolved)
			{
				return _font;
			}
			_fontResolved = true;
			try
			{
				TMP_FontAsset[] array = Resources.FindObjectsOfTypeAll<TMP_FontAsset>();
				if (array != null)
				{
					TMP_FontAsset[] array2 = array;
					foreach (TMP_FontAsset val in array2)
					{
						if ((Object)(object)val != (Object)null && ((Object)val).name != null && ((Object)val).name.Contains("OpenSans"))
						{
							_font = val;
							return _font;
						}
					}
					TMP_FontAsset[] array3 = array;
					foreach (TMP_FontAsset val2 in array3)
					{
						if ((Object)(object)val2 != (Object)null && ((Object)val2).name != null && (((Object)val2).name.Contains("Inter") || ((Object)val2).name.Contains("Roboto") || ((Object)val2).name.Contains("Liberation") || ((Object)val2).name.Contains("Arial")))
						{
							_font = val2;
							return _font;
						}
					}
					TMP_FontAsset[] array4 = array;
					foreach (TMP_FontAsset val3 in array4)
					{
						if ((Object)(object)val3 != (Object)null)
						{
							_font = val3;
							return _font;
						}
					}
				}
			}
			catch
			{
			}
			return _font;
		}

		internal static void Reset()
		{
			try
			{
				if ((Object)(object)_container != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)_container).gameObject);
				}
			}
			catch
			{
			}
			_container = null;
			_bound = null;
			_boxes.Clear();
		}
	}
	internal struct CamEntry
	{
		internal Camera Cam;

		internal string Name;

		internal CamEntry(Camera cam, string name)
		{
			Cam = cam;
			Name = name;
		}
	}
	internal static class NetEyeBridge
	{
		internal const string RtPrefix = "NetEye_RT_";

		private const string RootPrefix = "NetEye_";

		private static readonly List<CamEntry> _all = new List<CamEntry>(8);

		private static float _nextAllScan;

		private static int _lastCount = -1;

		private static Camera _feedCam;

		private static RawImage _feedCache;

		private static readonly Dictionary<int, string> _niceCache = new Dictionary<int, string>();

		private static bool _reflectInit;

		private static bool _reflectOk;

		private static FieldInfo _fInstance;

		private static FieldInfo _fCameras;

		private static FieldInfo _fUnityCam;

		private static FieldInfo _fName;

		private static FieldInfo _fLoc;

		private static FieldInfo _fIsVanilla;

		private static FieldInfo _fActiveIdx;

		private static MethodInfo _mDestroy;

		internal static IReadOnlyList<CamEntry> AllCameras()
		{
			float unscaledTime = Time.unscaledTime;
			if (unscaledTime >= _nextAllScan)
			{
				_nextAllScan = unscaledTime + 1f;
				RebuildAll();
			}
			return _all;
		}

		private static void RebuildAll()
		{
			_all.Clear();
			try
			{
				Camera[] array = Resources.FindObjectsOfTypeAll<Camera>();
				if (array != null)
				{
					Camera[] array2 = array;
					foreach (Camera val in array2)
					{
						if (!((Object)(object)val == (Object)null))
						{
							RenderTexture targetTexture = val.targetTexture;
							if (!((Object)(object)targetTexture == (Object)null) && ((Object)targetTexture).name != null && ((Object)targetTexture).name.StartsWith("NetEye_RT_"))
							{
								_all.Add(new CamEntry(val, ResolveName(val, targetTexture)));
							}
						}
					}
				}
			}
			catch
			{
			}
			if (EspConfig.DebugLog.Value && _all.Count != _lastCount)
			{
				_lastCount = _all.Count;
				MelonLogger.Msg("[PvpCameraEsp] NetEye cameras detected: " + _all.Count);
			}
		}

		internal static bool TryGetLive(out Camera cam, out RawImage feed, out string name)
		{
			cam = null;
			feed = null;
			name = null;
			try
			{
				IReadOnlyList<CamEntry> readOnlyList = AllCameras();
				for (int i = 0; i < readOnlyList.Count; i++)
				{
					Camera cam2 = readOnlyList[i].Cam;
					if ((Object)(object)cam2 != (Object)null && ((Behaviour)cam2).enabled)
					{
						cam = cam2;
						name = readOnlyList[i].Name;
						break;
					}
				}
				if ((Object)(object)cam == (Object)null)
				{
					return false;
				}
				feed = ResolveFeed(cam);
				return (Object)(object)feed != (Object)null;
			}
			catch
			{
				return false;
			}
		}

		private static RawImage ResolveFeed(Camera cam)
		{
			if ((Object)(object)_feedCache != (Object)null && (Object)(object)_feedCam == (Object)(object)cam && (Object)(object)_feedCache.texture == (Object)(object)cam.targetTexture)
			{
				return _feedCache;
			}
			_feedCache = null;
			_feedCam = cam;
			try
			{
				Texture targetTexture = (Texture)(object)cam.targetTexture;
				RawImage[] array = Resources.FindObjectsOfTypeAll<RawImage>();
				if (array != null)
				{
					RawImage[] array2 = array;
					foreach (RawImage val in array2)
					{
						if (!((Object)(object)val == (Object)null) && (Object)(object)val.texture != (Object)null && (Object)(object)val.texture == (Object)(object)targetTexture)
						{
							_feedCache = val;
							break;
						}
					}
				}
			}
			catch
			{
				_feedCache = null;
			}
			return _feedCache;
		}

		private static string ResolveName(Camera cam, RenderTexture rt)
		{
			int instanceID = ((Object)cam).GetInstanceID();
			if (_niceCache.TryGetValue(instanceID, out var value))
			{
				return value;
			}
			string text = TryReflectName(cam);
			if (!string.IsNullOrEmpty(text))
			{
				_niceCache[instanceID] = text;
				return text;
			}
			return GoName(cam, rt);
		}

		private static string GoName(Camera cam, RenderTexture rt)
		{
			try
			{
				Transform val = ((Component)cam).transform;
				while ((Object)(object)val.parent != (Object)null)
				{
					val = val.parent;
				}
				string name = ((Object)((Component)val).gameObject).name;
				if (!string.IsNullOrEmpty(name) && name.StartsWith("NetEye_"))
				{
					return name.Substring("NetEye_".Length);
				}
				if ((Object)(object)rt != (Object)null && ((Object)rt).name != null && ((Object)rt).name.StartsWith("NetEye_RT_"))
				{
					return ((Object)rt).name.Substring("NetEye_RT_".Length);
				}
				return string.IsNullOrEmpty(name) ? "?" : name;
			}
			catch
			{
				return "?";
			}
		}

		internal static int RemoveStaleCameras()
		{
			int num = 0;
			try
			{
				EnsureReflect();
				if (!_reflectOk || _fIsVanilla == null || _mDestroy == null || _fCameras == null)
				{
					return 0;
				}
				object value = _fInstance.GetValue(null);
				if (value == null)
				{
					return 0;
				}
				if (!(_fCameras.GetValue(value) is IList list))
				{
					return 0;
				}
				for (int num2 = list.Count - 1; num2 >= 0; num2--)
				{
					object obj = list[num2];
					if (obj == null)
					{
						continue;
					}
					bool flag;
					try
					{
						flag = (bool)_fIsVanilla.GetValue(obj);
					}
					catch
					{
						continue;
					}
					if (!flag)
					{
						try
						{
							_mDestroy.Invoke(obj, null);
						}
						catch
						{
						}
						try
						{
							list.RemoveAt(num2);
							num++;
						}
						catch
						{
						}
					}
				}
				if (num > 0 && _fActiveIdx != null)
				{
					try
					{
						int num3 = (int)_fActiveIdx.GetValue(value);
						if (num3 >= list.Count)
						{
							_fActiveIdx.SetValue(value, list.Count - 1);
						}
					}
					catch
					{
					}
				}
			}
			catch
			{
			}
			return num;
		}

		private static string TryReflectName(Camera cam)
		{
			try
			{
				EnsureReflect();
				if (!_reflectOk)
				{
					return null;
				}
				object value = _fInstance.GetValue(null);
				if (value == null)
				{
					return null;
				}
				if (!(_fCameras.GetValue(value) is IEnumerable enumerable))
				{
					return null;
				}
				foreach (object item in enumerable)
				{
					if (item == null)
					{
						continue;
					}
					object? value2 = _fUnityCam.GetValue(item);
					Camera val = (Camera)((value2 is Camera) ? value2 : null);
					if ((Object)(object)val == (Object)null || (Object)(object)val != (Object)(object)cam)
					{
						continue;
					}
					string text = _fName.GetValue(item) as string;
					if (string.IsNullOrEmpty(text))
					{
						return null;
					}
					string text2 = ((_fLoc != null) ? (_fLoc.GetValue(item) as string) : null);
					return string.IsNullOrEmpty(text2) ? text : (text + " (" + text2 + ")");
				}
			}
			catch
			{
			}
			return null;
		}

		private static void EnsureReflect()
		{
			if (_reflectInit)
			{
				return;
			}
			_reflectInit = true;
			try
			{
				Type type = FindType("NetEye.NetEyeMod", "NetEye");
				Type type2 = FindType("NetEye.NetEyeCamera", "NetEye");
				if (!(type == null) && !(type2 == null))
				{
					_fInstance = type.GetField("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					_fCameras = type.GetField("_cameras", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					_fActiveIdx = type.GetField("_activeCameraIdx", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					_fUnityCam = type2.GetField("UnityCam", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					_fName = type2.GetField("Name", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					_fLoc = type2.GetField("Location", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					_fIsVanilla = type2.GetField("IsVanilla", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					_mDestroy = type2.GetMethod("Destroy", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
					_reflectOk = _fInstance != null && _fCameras != null && _fUnityCam != null && _fName != null;
				}
			}
			catch
			{
				_reflectOk = false;
			}
		}

		private static Type FindType(string fullName, string asmSimpleName)
		{
			try
			{
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				foreach (Assembly assembly in assemblies)
				{
					if (assembly.GetName().Name == asmSimpleName)
					{
						Type type = assembly.GetType(fullName);
						if (type != null)
						{
							return type;
						}
					}
				}
			}
			catch
			{
			}
			try
			{
				return Type.GetType(fullName + ", " + asmSimpleName);
			}
			catch
			{
				return null;
			}
		}

		internal static void Reset()
		{
			_all.Clear();
			_niceCache.Clear();
			_feedCam = null;
			_feedCache = null;
			_nextAllScan = 0f;
			_lastCount = -1;
		}
	}
	public class PvpCameraEspMod : MelonMod
	{
		private float _nextSensorScan;

		private float _nextStaleScan;

		private bool _wasMatchActive;

		public override void OnInitializeMelon()
		{
			EspConfig.Load();
			CameraGuard.Apply();
			MelonLogger.Msg("[PvpCameraEsp] ready — symmetric camera ESP for MultiplayerPVP via NetEye cameras.");
		}

		public override void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			try
			{
				NetEyeBridge.Reset();
				FeedOverlay.Reset();
				SightingReporter.Reset();
				CameraOwnership.Reset();
				CameraBuildTracker.Reset();
				_wasMatchActive = false;
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[PvpCameraEsp] OnSceneWasLoaded: " + ex.Message);
			}
		}

		public override void OnUpdate()
		{
			try
			{
				if (!EspConfig.Enabled.Value)
				{
					FeedOverlay.HideAll();
					_wasMatchActive = false;
					return;
				}
				float unscaledTime = Time.unscaledTime;
				bool isHost = PvpApi.IsHost;
				bool isTeamsMatchActive = PvpApi.IsTeamsMatchActive;
				bool isMatchActive = PvpApi.IsMatchActive;
				CameraOwnership.Tick(EspConfig.OwnPlacementRadius.Value);
				if (isHost && EspConfig.CleanStaleCameras.Value && PvpApi.IsMultiplayer && unscaledTime >= _nextStaleScan)
				{
					_nextStaleScan = unscaledTime + 5f;
					int num = NetEyeBridge.RemoveStaleCameras();
					if (num > 0 && EspConfig.DebugLog.Value)
					{
						MelonLogger.Msg($"[PvpCameraEsp] removed {num} stale camera(s)");
					}
				}
				if (_wasMatchActive && !isMatchActive && EspConfig.CleanupOwnCamerasOnRoundEnd.Value)
				{
					CameraOwnership.QueuePickUpMine();
				}
				else if (!_wasMatchActive && isMatchActive)
				{
					CameraOwnership.AbortPickup();
				}
				_wasMatchActive = isMatchActive;
				CameraOwnership.TickPickupRetry();
				if (!isTeamsMatchActive)
				{
					FeedOverlay.HideAll();
					return;
				}
				if (unscaledTime >= _nextSensorScan)
				{
					_nextSensorScan = unscaledTime + 0.25f;
					IReadOnlyList<CamEntry> readOnlyList = NetEyeBridge.AllCameras();
					for (int i = 0; i < readOnlyList.Count; i++)
					{
						if (CameraOwnership.IsMineCamera(readOnlyList[i].Cam))
						{
							List<VisibleEnemy> list = EnemyTracker.Scan(readOnlyList[i].Cam);
							if (list.Count > 0)
							{
								SightingReporter.Report(list, readOnlyList[i].Name);
							}
						}
					}
				}
				if (NetEyeBridge.TryGetLive(out var cam, out var feed, out var _) && CameraOwnership.IsMineCamera(cam))
				{
					FeedOverlay.Update(feed, EnemyTracker.Scan(cam));
				}
				else
				{
					FeedOverlay.HideAll();
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[PvpCameraEsp] OnUpdate: " + ex.Message);
			}
		}
	}
	internal static class SightingReporter
	{
		private static readonly Dictionary<string, float> _lastSeen = new Dictionary<string, float>();

		private static readonly Dictionary<string, float> _lastFired = new Dictionary<string, float>();

		internal static void Report(List<VisibleEnemy> enemies, string cameraName)
		{
			float unscaledTime = Time.unscaledTime;
			float num = Mathf.Max(0.5f, EspConfig.ReportCooldownSeconds.Value);
			float value = EspConfig.RemindWhileVisibleSeconds.Value;
			for (int i = 0; i < enemies.Count; i++)
			{
				VisibleEnemy visibleEnemy = enemies[i];
				string text = ((visibleEnemy.SteamId != 0L) ? visibleEnemy.SteamId.ToString() : ("n:" + visibleEnemy.Persona));
				string key = text + "@" + cameraName;
				float value2;
				bool flag = !_lastSeen.TryGetValue(key, out value2) || unscaledTime - value2 > num;
				float value3;
				bool flag2 = value > 0f && _lastFired.TryGetValue(key, out value3) && unscaledTime - value3 >= value;
				_lastSeen[key] = unscaledTime;
				if (flag || flag2)
				{
					_lastFired[key] = unscaledTime;
					if (EspConfig.DebugLog.Value)
					{
						MelonLogger.Msg(string.Format("[PvpCameraEsp] ALERT{0}: {1} (team {2}, steamId {3}) @ {4}", (flag2 && !flag) ? " (reminder)" : "", visibleEnemy.Persona, visibleEnemy.Team, visibleEnemy.SteamId, cameraName));
					}
					PvpApi.ReportCameraSighting(visibleEnemy.Team, visibleEnemy.SteamId, visibleEnemy.Persona, cameraName);
				}
			}
			if (_lastSeen.Count > 128)
			{
				Prune(unscaledTime, num);
			}
		}

		private static void Prune(float now, float rearm)
		{
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, float> item in _lastSeen)
			{
				if (now - item.Value > rearm * 4f + 10f)
				{
					list.Add(item.Key);
				}
			}
			for (int i = 0; i < list.Count; i++)
			{
				_lastSeen.Remove(list[i]);
				_lastFired.Remove(list[i]);
			}
		}

		internal static void Reset()
		{
			try
			{
				_lastSeen.Clear();
				_lastFired.Clear();
			}
			catch
			{
			}
		}
	}
}

PvpWhistle.IL2CPP.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using Il2CppScheduleOne.PlayerScripts;
using Il2CppScheduleOne.PlayerScripts.Health;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using MultiplayerPVP.Addons;
using MultiplayerPVP.Core;
using PvpWhistle;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonAdditionalDependencies(new string[] { "MultiplayerPVP" })]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: MelonInfo(typeof(PvpWhistleMod), "PvpWhistle", "1.0.2", "Virtunerd", null)]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: AssemblyFileVersion("1.0.2")]
[assembly: AssemblyInformationalVersion("1.0.2")]
[assembly: AssemblyVersion("1.0.2.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 PvpWhistle
{
	public class PvpWhistleMod : MelonMod
	{
		private WhistleAddon _addon;

		public override void OnInitializeMelon()
		{
			_addon = new WhistleAddon();
			if (PvpApi.RegisterAddon((IPvpAddon)(object)_addon))
			{
				MelonLogger.Msg("[PvpWhistle] registered with MultiplayerPVP.");
			}
			else
			{
				MelonLogger.Warning("[PvpWhistle] registration failed — is MultiplayerPVP loaded?");
			}
		}

		public override void OnDeinitializeMelon()
		{
			try
			{
				PvpApi.UnregisterAddon((IPvpAddon)(object)_addon);
			}
			catch
			{
			}
		}
	}
	internal sealed class WhistleAddon : PvpAddonBase
	{
		private sealed class Ping
		{
			internal Vector3 Pos;

			internal string Name;

			internal float Until;
		}

		private MelonPreferences_Entry<float> _intervalSeconds;

		private MelonPreferences_Entry<float> _pingSeconds;

		private MelonPreferences_Entry<bool> _seekersOnly;

		private readonly List<Ping> _pings = new List<Ping>();

		private float _nextWhistle;

		private bool _show;

		private static GUIStyle _center;

		public override string Id => "PvpWhistle";

		private float Interval => Mathf.Max(3f, _intervalSeconds.Value);

		private static GUIStyle CenterStyle
		{
			get
			{
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				//IL_001c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_003a: Expected O, but got Unknown
				if (_center == null)
				{
					_center = new GUIStyle(GUI.skin.label)
					{
						alignment = (TextAnchor)4,
						fontSize = 14,
						fontStyle = (FontStyle)1
					};
				}
				return _center;
			}
		}

		public override void OnRegistered()
		{
			MelonPreferences_Category val = MelonPreferences.CreateCategory("PvpWhistle", "PVP Hider Whistle");
			_intervalSeconds = val.CreateEntry<float>("WhistleIntervalSeconds", 10f, "Whistle interval (s)", "Seconds between automatic hider whistles during Hide & Seek (min 3).", false, false, (ValueValidator)null, (string)null);
			_pingSeconds = val.CreateEntry<float>("PingVisibleSeconds", 4f, "Ping visible (s)", "How long each whistle ping stays on screen (1-15).", false, false, (ValueValidator)null, (string)null);
			_seekersOnly = val.CreateEntry<bool>("SeekersOnlyDisplay", true, "Seekers only", "Only seekers see the pings (hiders just whistle). Off = everyone sees them.", false, false, (ValueValidator)null, (string)null);
		}

		public override void OnGo(GameModeType mode)
		{
			_pings.Clear();
			_nextWhistle = Time.realtimeSinceStartup + Interval;
		}

		public override void OnDayEnded(GameModeType mode, int day)
		{
			_pings.Clear();
		}

		public override void OnMatchEnded(GameModeType mode)
		{
			_pings.Clear();
		}

		public override void OnSceneLoaded(int buildIndex, string sceneName)
		{
			_pings.Clear();
		}

		public override void OnDeinit()
		{
			_pings.Clear();
		}

		public override void OnUpdate(float dt)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Invalid comparison between Unknown and I4
			if ((int)PvpApi.Mode != 6 || (int)PvpApi.Phase != 2)
			{
				if (_pings.Count > 0)
				{
					_pings.Clear();
				}
				return;
			}
			_show = true;
			if (_seekersOnly.Value)
			{
				_show = false;
				try
				{
					Player localPlayer = PvpApi.LocalPlayer;
					bool show = default(bool);
					if ((Object)(object)localPlayer != (Object)null && PvpApi.TryGetHideSeekRole(localPlayer, ref show))
					{
						_show = show;
					}
				}
				catch
				{
				}
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (realtimeSinceStartup >= _nextWhistle)
			{
				_nextWhistle = realtimeSinceStartup + Interval;
				Whistle(realtimeSinceStartup);
			}
			for (int num = _pings.Count - 1; num >= 0; num--)
			{
				if (_pings[num].Until <= realtimeSinceStartup)
				{
					_pings.RemoveAt(num);
				}
			}
		}

		private void Whistle(float now)
		{
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Clamp(_pingSeconds.Value, 1f, 15f);
			Player localPlayer = PvpApi.LocalPlayer;
			List<Player> players = PvpApi.Players;
			bool flag = default(bool);
			for (int i = 0; i < players.Count; i++)
			{
				Player val = players[i];
				try
				{
					if (!((Object)(object)val == (Object)null) && (!((Object)(object)localPlayer != (Object)null) || !((Object)(object)val == (Object)(object)localPlayer)) && !(!PvpApi.TryGetHideSeekRole(val, ref flag) || flag))
					{
						PlayerHealth componentInChildren = ((Component)val).GetComponentInChildren<PlayerHealth>(true);
						if (!((Object)(object)componentInChildren != (Object)null) || componentInChildren.IsAlive)
						{
							_pings.Add(new Ping
							{
								Pos = ((Component)val).transform.position,
								Name = val.PlayerName,
								Until = now + num
							});
						}
					}
				}
				catch
				{
				}
			}
		}

		public override void OnGui()
		{
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Invalid comparison between Unknown and I4
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: 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_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: 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_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			if (!_show || _pings.Count == 0 || (int)PvpApi.Phase != 2)
			{
				return;
			}
			Camera main = Camera.main;
			if ((Object)(object)main == (Object)null)
			{
				return;
			}
			Vector3 val = Vector3.zero;
			bool flag = false;
			try
			{
				Player localPlayer = PvpApi.LocalPlayer;
				if ((Object)(object)localPlayer != (Object)null)
				{
					val = ((Component)localPlayer).transform.position;
					flag = true;
				}
			}
			catch
			{
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			float num = Mathf.Clamp(_pingSeconds.Value, 1f, 15f);
			Color color = GUI.color;
			Rect val3 = default(Rect);
			for (int i = 0; i < _pings.Count; i++)
			{
				Ping ping = _pings[i];
				Vector3 val2;
				try
				{
					val2 = main.WorldToScreenPoint(ping.Pos + Vector3.up * 1.8f);
				}
				catch
				{
					continue;
				}
				if (!(val2.z <= 0f))
				{
					float num2 = Mathf.Clamp01((ping.Until - realtimeSinceStartup) / num);
					string text = (flag ? $"♪ {ping.Name} · {Vector3.Distance(val, ping.Pos):0}m" : ("♪ " + ping.Name));
					((Rect)(ref val3))..ctor(val2.x - 80f, (float)Screen.height - val2.y - 12f, 160f, 24f);
					GUI.color = new Color(0f, 0f, 0f, num2 * 0.8f);
					GUI.Label(new Rect(((Rect)(ref val3)).x + 1f, ((Rect)(ref val3)).y + 1f, ((Rect)(ref val3)).width, ((Rect)(ref val3)).height), text, CenterStyle);
					GUI.color = new Color(1f, 0.92f, 0.35f, num2);
					GUI.Label(val3, text, CenterStyle);
				}
			}
			GUI.color = color;
		}
	}
}

PvpWhistle.MONO.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using MultiplayerPVP.Addons;
using MultiplayerPVP.Core;
using PvpWhistle;
using ScheduleOne.PlayerScripts;
using ScheduleOne.PlayerScripts.Health;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonAdditionalDependencies(new string[] { "MultiplayerPVP" })]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: MelonInfo(typeof(PvpWhistleMod), "PvpWhistle", "1.0.2", "Virtunerd", null)]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: AssemblyFileVersion("1.0.2")]
[assembly: AssemblyInformationalVersion("1.0.2")]
[assembly: AssemblyVersion("1.0.2.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 PvpWhistle
{
	public class PvpWhistleMod : MelonMod
	{
		private WhistleAddon _addon;

		public override void OnInitializeMelon()
		{
			_addon = new WhistleAddon();
			if (PvpApi.RegisterAddon((IPvpAddon)(object)_addon))
			{
				MelonLogger.Msg("[PvpWhistle] registered with MultiplayerPVP.");
			}
			else
			{
				MelonLogger.Warning("[PvpWhistle] registration failed — is MultiplayerPVP loaded?");
			}
		}

		public override void OnDeinitializeMelon()
		{
			try
			{
				PvpApi.UnregisterAddon((IPvpAddon)(object)_addon);
			}
			catch
			{
			}
		}
	}
	internal sealed class WhistleAddon : PvpAddonBase
	{
		private sealed class Ping
		{
			internal Vector3 Pos;

			internal string Name;

			internal float Until;
		}

		private MelonPreferences_Entry<float> _intervalSeconds;

		private MelonPreferences_Entry<float> _pingSeconds;

		private MelonPreferences_Entry<bool> _seekersOnly;

		private readonly List<Ping> _pings = new List<Ping>();

		private float _nextWhistle;

		private bool _show;

		private static GUIStyle _center;

		public override string Id => "PvpWhistle";

		private float Interval => Mathf.Max(3f, _intervalSeconds.Value);

		private static GUIStyle CenterStyle
		{
			get
			{
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				//IL_001c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_003a: Expected O, but got Unknown
				if (_center == null)
				{
					_center = new GUIStyle(GUI.skin.label)
					{
						alignment = (TextAnchor)4,
						fontSize = 14,
						fontStyle = (FontStyle)1
					};
				}
				return _center;
			}
		}

		public override void OnRegistered()
		{
			MelonPreferences_Category val = MelonPreferences.CreateCategory("PvpWhistle", "PVP Hider Whistle");
			_intervalSeconds = val.CreateEntry<float>("WhistleIntervalSeconds", 10f, "Whistle interval (s)", "Seconds between automatic hider whistles during Hide & Seek (min 3).", false, false, (ValueValidator)null, (string)null);
			_pingSeconds = val.CreateEntry<float>("PingVisibleSeconds", 4f, "Ping visible (s)", "How long each whistle ping stays on screen (1-15).", false, false, (ValueValidator)null, (string)null);
			_seekersOnly = val.CreateEntry<bool>("SeekersOnlyDisplay", true, "Seekers only", "Only seekers see the pings (hiders just whistle). Off = everyone sees them.", false, false, (ValueValidator)null, (string)null);
		}

		public override void OnGo(GameModeType mode)
		{
			_pings.Clear();
			_nextWhistle = Time.realtimeSinceStartup + Interval;
		}

		public override void OnDayEnded(GameModeType mode, int day)
		{
			_pings.Clear();
		}

		public override void OnMatchEnded(GameModeType mode)
		{
			_pings.Clear();
		}

		public override void OnSceneLoaded(int buildIndex, string sceneName)
		{
			_pings.Clear();
		}

		public override void OnDeinit()
		{
			_pings.Clear();
		}

		public override void OnUpdate(float dt)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Invalid comparison between Unknown and I4
			if ((int)PvpApi.Mode != 6 || (int)PvpApi.Phase != 2)
			{
				if (_pings.Count > 0)
				{
					_pings.Clear();
				}
				return;
			}
			_show = true;
			if (_seekersOnly.Value)
			{
				_show = false;
				try
				{
					Player localPlayer = PvpApi.LocalPlayer;
					bool show = default(bool);
					if ((Object)(object)localPlayer != (Object)null && PvpApi.TryGetHideSeekRole(localPlayer, ref show))
					{
						_show = show;
					}
				}
				catch
				{
				}
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (realtimeSinceStartup >= _nextWhistle)
			{
				_nextWhistle = realtimeSinceStartup + Interval;
				Whistle(realtimeSinceStartup);
			}
			for (int num = _pings.Count - 1; num >= 0; num--)
			{
				if (_pings[num].Until <= realtimeSinceStartup)
				{
					_pings.RemoveAt(num);
				}
			}
		}

		private void Whistle(float now)
		{
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Clamp(_pingSeconds.Value, 1f, 15f);
			Player localPlayer = PvpApi.LocalPlayer;
			List<Player> players = PvpApi.Players;
			bool flag = default(bool);
			for (int i = 0; i < players.Count; i++)
			{
				Player val = players[i];
				try
				{
					if (!((Object)(object)val == (Object)null) && (!((Object)(object)localPlayer != (Object)null) || !((Object)(object)val == (Object)(object)localPlayer)) && !(!PvpApi.TryGetHideSeekRole(val, ref flag) || flag))
					{
						PlayerHealth componentInChildren = ((Component)val).GetComponentInChildren<PlayerHealth>(true);
						if (!((Object)(object)componentInChildren != (Object)null) || componentInChildren.IsAlive)
						{
							_pings.Add(new Ping
							{
								Pos = ((Component)val).transform.position,
								Name = val.PlayerName,
								Until = now + num
							});
						}
					}
				}
				catch
				{
				}
			}
		}

		public override void OnGui()
		{
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Invalid comparison between Unknown and I4
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: 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_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: 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_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			if (!_show || _pings.Count == 0 || (int)PvpApi.Phase != 2)
			{
				return;
			}
			Camera main = Camera.main;
			if ((Object)(object)main == (Object)null)
			{
				return;
			}
			Vector3 val = Vector3.zero;
			bool flag = false;
			try
			{
				Player localPlayer = PvpApi.LocalPlayer;
				if ((Object)(object)localPlayer != (Object)null)
				{
					val = ((Component)localPlayer).transform.position;
					flag = true;
				}
			}
			catch
			{
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			float num = Mathf.Clamp(_pingSeconds.Value, 1f, 15f);
			Color color = GUI.color;
			Rect val3 = default(Rect);
			for (int i = 0; i < _pings.Count; i++)
			{
				Ping ping = _pings[i];
				Vector3 val2;
				try
				{
					val2 = main.WorldToScreenPoint(ping.Pos + Vector3.up * 1.8f);
				}
				catch
				{
					continue;
				}
				if (!(val2.z <= 0f))
				{
					float num2 = Mathf.Clamp01((ping.Until - realtimeSinceStartup) / num);
					string text = (flag ? $"♪ {ping.Name} · {Vector3.Distance(val, ping.Pos):0}m" : ("♪ " + ping.Name));
					((Rect)(ref val3))..ctor(val2.x - 80f, (float)Screen.height - val2.y - 12f, 160f, 24f);
					GUI.color = new Color(0f, 0f, 0f, num2 * 0.8f);
					GUI.Label(new Rect(((Rect)(ref val3)).x + 1f, ((Rect)(ref val3)).y + 1f, ((Rect)(ref val3)).width, ((Rect)(ref val3)).height), text, CenterStyle);
					GUI.color = new Color(1f, 0.92f, 0.35f, num2);
					GUI.Label(val3, text, CenterStyle);
				}
			}
			GUI.color = color;
		}
	}
}

Riot.IL2CPP.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using Il2CppFishNet;
using Il2CppFishNet.Managing;
using Il2CppFishNet.Object;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppScheduleOne.Cartel;
using Il2CppScheduleOne.Combat;
using Il2CppScheduleOne.Doors;
using Il2CppScheduleOne.NPCs;
using Il2CppScheduleOne.NPCs.Behaviour;
using Il2CppScheduleOne.PlayerScripts;
using Il2CppScheduleOne.PlayerScripts.Health;
using Il2CppScheduleOne.Police;
using Il2CppSystem.Collections.Generic;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using MultiplayerPVP.Addons;
using MultiplayerPVP.Core;
using Riot;
using UnityEngine;
using UnityEngine.AI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonAdditionalDependencies(new string[] { "MultiplayerPVP" })]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: MelonInfo(typeof(RiotMod), "Riot", "1.0.1", "Virtunerd", null)]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: AssemblyFileVersion("1.0.1")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: AssemblyVersion("1.0.1.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 Riot
{
	internal static class ChaosDirector
	{
		private const float RETARGET_INTERVAL = 1.5f;

		private const float NPC_GIVE_UP = 200f;

		private static readonly List<NPC> _engaged = new List<NPC>();

		private static readonly List<NPC> _civilians = new List<NPC>();

		private static float _cd;

		internal static bool On { get; private set; }

		internal static void SetOn(bool on)
		{
			if (On != on)
			{
				On = on;
				if (!on)
				{
					Teardown();
				}
				else
				{
					_cd = 0f;
				}
				MelonLogger.Msg("[Riot] CHAOS " + (on ? "ON — the city hunts the players." : "OFF."));
			}
		}

		internal static void Reset()
		{
			_engaged.Clear();
			_civilians.Clear();
			On = false;
		}

		internal static void Tick(float dt)
		{
			//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			if (!On)
			{
				return;
			}
			try
			{
				if (!RiotCompat.IsAuthority)
				{
					SetOn(on: false);
					return;
				}
				_cd -= dt;
				if (_cd > 0f)
				{
					return;
				}
				_cd = 1.5f;
				float num = Mathf.Clamp(RiotConfig.ChaosRadius.Value, 15f, 200f);
				try
				{
					List<PoliceOfficer> officers = PoliceOfficer.Officers;
					if (officers != null)
					{
						for (int i = 0; i < officers.Count; i++)
						{
							try
							{
								PoliceOfficer val = officers[i];
								if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).transform == (Object)null)
								{
									continue;
								}
								NPCHealth health = ((NPC)val).Health;
								if (!((Object)(object)health == (Object)null) && !health.IsDead && !health.IsKnockedOut)
								{
									Player val2 = NearestAlivePlayer(((Component)val).transform.position, num);
									if (!((Object)(object)val2 == (Object)null))
									{
										SicNpc((NPC)(object)val, val2, civilian: false);
									}
								}
							}
							catch
							{
							}
						}
					}
				}
				catch
				{
				}
				if (!RiotConfig.CiviliansJoinChaos.Value)
				{
					return;
				}
				PruneCivilians();
				int num2 = Mathf.Clamp(RiotConfig.MaxChaosCivilians.Value, 1, 16);
				try
				{
					List<NPC> nPCRegistry = NPCManager.NPCRegistry;
					if (nPCRegistry != null)
					{
						for (int j = 0; j < nPCRegistry.Count; j++)
						{
							if (_civilians.Count >= num2)
							{
								break;
							}
							try
							{
								NPC val3 = nPCRegistry[j];
								if ((Object)(object)val3 == (Object)null || (Object)(object)((Component)val3).transform == (Object)null || (Object)(object)RiotCompat.Cast<PoliceOfficer>((Object)(object)val3) != (Object)null || (Object)(object)RiotCompat.Cast<CartelGoon>((Object)(object)val3) != (Object)null)
								{
									continue;
								}
								NPCHealth health2 = val3.Health;
								if (!((Object)(object)health2 == (Object)null) && !health2.IsDead && !health2.IsKnockedOut)
								{
									Player val4 = NearestAlivePlayer(((Component)val3).transform.position, num);
									if (!((Object)(object)val4 == (Object)null) && SicNpc(val3, val4, civilian: true) && !_civilians.Contains(val3))
									{
										_civilians.Add(val3);
									}
								}
							}
							catch
							{
							}
						}
					}
				}
				catch
				{
				}
				for (int k = 0; k < _civilians.Count; k++)
				{
					try
					{
						NPC val5 = _civilians[k];
						if (!((Object)(object)val5 == (Object)null) && !((Object)(object)((Component)val5).transform == (Object)null))
						{
							Player val6 = NearestAlivePlayer(((Component)val5).transform.position, num * 2f);
							if ((Object)(object)val6 != (Object)null)
							{
								SicNpc(val5, val6, civilian: true);
							}
						}
					}
					catch
					{
					}
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[Riot] Chaos tick: " + ex.Message);
			}
		}

		private static bool SicNpc(NPC npc, Player target, bool civilian)
		{
			try
			{
				object obj;
				if (target == null)
				{
					obj = null;
				}
				else
				{
					GameObject gameObject = ((Component)target).gameObject;
					obj = ((gameObject != null) ? gameObject.GetComponent<NetworkObject>() : null);
				}
				NetworkObject val = (NetworkObject)obj;
				object obj2;
				if (npc == null)
				{
					obj2 = null;
				}
				else
				{
					NPCBehaviour behaviour = npc.Behaviour;
					obj2 = ((behaviour != null) ? behaviour.CombatBehaviour : null);
				}
				CombatBehaviour val2 = (CombatBehaviour)obj2;
				if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
				{
					return false;
				}
				try
				{
					val2.GiveUpRange = 200f;
				}
				catch
				{
				}
				val2.SetTargetAndEnable_Server(val);
				if (!_engaged.Contains(npc))
				{
					_engaged.Add(npc);
				}
				return true;
			}
			catch
			{
				return false;
			}
		}

		private static void PruneCivilians()
		{
			for (int num = _civilians.Count - 1; num >= 0; num--)
			{
				try
				{
					NPC val = _civilians[num];
					NPCHealth val2 = (((Object)(object)val != (Object)null) ? val.Health : null);
					if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).transform == (Object)null || (Object)(object)val2 == (Object)null || val2.IsDead || val2.IsKnockedOut)
					{
						_civilians.RemoveAt(num);
					}
				}
				catch
				{
					_civilians.RemoveAt(num);
				}
			}
		}

		internal static Player NearestAlivePlayer(Vector3 pos, float radius)
		{
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			Player result = null;
			float num = radius;
			try
			{
				List<Player> playerList = Player.PlayerList;
				if (playerList == null)
				{
					return null;
				}
				for (int i = 0; i < playerList.Count; i++)
				{
					try
					{
						Player val = playerList[i];
						if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).transform == (Object)null)
						{
							continue;
						}
						PlayerHealth componentInChildren = ((Component)val).GetComponentInChildren<PlayerHealth>(true);
						if (!((Object)(object)componentInChildren != (Object)null) || componentInChildren.IsAlive)
						{
							float num2 = Vector3.Distance(((Component)val).transform.position, pos);
							if (num2 < num)
							{
								num = num2;
								result = val;
							}
						}
					}
					catch
					{
					}
				}
			}
			catch
			{
			}
			return result;
		}

		private static void Teardown()
		{
			for (int i = 0; i < _engaged.Count; i++)
			{
				try
				{
					NPC obj = _engaged[i];
					object obj2;
					if (obj == null)
					{
						obj2 = null;
					}
					else
					{
						NPCBehaviour behaviour = obj.Behaviour;
						obj2 = ((behaviour != null) ? behaviour.CombatBehaviour : null);
					}
					CombatBehaviour val = (CombatBehaviour)obj2;
					if ((Object)(object)val != (Object)null)
					{
						try
						{
							((Behaviour)val).Deactivate();
						}
						catch
						{
						}
						try
						{
							((Behaviour)val).Disable();
						}
						catch
						{
						}
					}
				}
				catch
				{
				}
			}
			_engaged.Clear();
			_civilians.Clear();
		}
	}
	internal sealed class RiotAddon : PvpAddonBase
	{
		private PvpMatchToggle _riotToggle;

		private PvpMatchToggle _chaosToggle;

		private PvpChannel _channel;

		private int _seq;

		private readonly Dictionary<ulong, string> _seen = new Dictionary<ulong, string>();

		private bool _chaosActiveLocal;

		private string _lastState = "";

		private bool _prevRiotReq;

		private bool _prevChaosReq;

		public override string Id => "Riot";

		public override void OnRegistered()
		{
			RiotConfig.Load();
			_channel = PvpApi.Channel("riot");
			if (_channel != null)
			{
				_channel.OnMessage += OnRiotMsg;
			}
			_riotToggle = PvpApi.RegisterMatchToggle("riot", "Riot", "City riot for this round: Benzies storm out of the door nearest each cop and brawl with the police while you play. Mutually exclusive with Chaos.");
			_chaosToggle = PvpApi.RegisterMatchToggle("chaos", "Chaos", "The city turns on YOU for this round: cops, Benzies and civilians hunt every player on sight until KO. NPC knock-outs confiscate weapons. Mutually exclusive with Riot.");
			if (_riotToggle != null)
			{
				_riotToggle.Activated += OnRiotActivated;
				_riotToggle.Deactivated += OnRoundDeactivated;
			}
			if (_chaosToggle != null)
			{
				_chaosToggle.Activated += OnChaosActivated;
				_chaosToggle.Deactivated += OnRoundDeactivated;
			}
			PvpApi.RegisterNpcKoAttributor((Func<bool>)IsKoFromChaos);
		}

		private void OnRiotActivated()
		{
			if (PvpApi.IsMultiplayer && RiotCompat.IsAuthority)
			{
				ChaosDirector.SetOn(on: false);
				RiotManager.SetOn(on: true);
				PublishState();
			}
		}

		private void OnChaosActivated()
		{
			if (PvpApi.IsMultiplayer && RiotCompat.IsAuthority)
			{
				ChaosDirector.SetOn(on: true);
				RiotManager.SetOn(on: true);
				_chaosActiveLocal = true;
				PublishState();
			}
		}

		private void OnRoundDeactivated()
		{
			bool flag = RiotManager.On || ChaosDirector.On;
			ChaosDirector.SetOn(on: false);
			RiotManager.SetOn(on: false);
			_chaosActiveLocal = false;
			if (flag)
			{
				PublishState();
			}
		}

		public override void OnUpdate(float dt)
		{
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Invalid comparison between Unknown and I4
			try
			{
				if (_chaosToggle != null && _riotToggle != null)
				{
					bool requested = _riotToggle.Requested;
					bool requested2 = _chaosToggle.Requested;
					if (requested && requested2)
					{
						if (requested2 && !_prevChaosReq)
						{
							_riotToggle.Requested = false;
						}
						else
						{
							_chaosToggle.Requested = false;
						}
					}
					_prevRiotReq = _riotToggle.Requested;
					_prevChaosReq = _chaosToggle.Requested;
				}
			}
			catch
			{
			}
			bool flag = (int)PvpApi.Phase != 2 || !PvpApi.IsMultiplayer;
			if (ChaosDirector.On && flag)
			{
				ChaosDirector.SetOn(on: false);
				_chaosActiveLocal = false;
			}
			if (RiotManager.On && flag)
			{
				RiotManager.SetOn(on: false);
			}
			RiotManager.Tick(dt);
			ChaosDirector.Tick(dt);
			if (_channel != null)
			{
				List<KeyValuePair<ulong, string>> list = _channel.ReadAll();
				for (int i = 0; i < list.Count; i++)
				{
					OnRiotMsg(list[i].Key, list[i].Value);
				}
			}
		}

		private void PublishState()
		{
			bool flag = RiotManager.On && !ChaosDirector.On;
			string text = (flag ? "1" : "0") + "~" + (ChaosDirector.On ? "1" : "0");
			ShowState(flag, ChaosDirector.On);
			PvpChannel channel = _channel;
			if (channel != null)
			{
				int num = ++_seq;
				channel.Publish(num + "~" + text);
			}
		}

		private void OnRiotMsg(ulong fromSteamId, string record)
		{
			if (string.IsNullOrEmpty(record) || (_seen.TryGetValue(fromSteamId, out var value) && value == record))
			{
				return;
			}
			_seen[fromSteamId] = record;
			if (!RiotCompat.IsAuthority)
			{
				string[] array = record.Split('~');
				if (array.Length >= 3)
				{
					bool riot = array[1] == "1";
					ShowState(riot, _chaosActiveLocal = array[2] == "1");
				}
			}
		}

		private void ShowState(bool riot, bool chaos)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			string text = (riot ? "r" : "") + (chaos ? "c" : "");
			if (!(text == _lastState))
			{
				_lastState = text;
				if (chaos)
				{
					PvpApi.ShowLocalBanner("☠ CHAOS — the whole city is out for YOUR blood!", 5f, new Color(1f, 0.15f, 0.15f));
				}
				else if (riot)
				{
					PvpApi.ShowLocalBanner("⚠ RIOT — the Benzies are out!", 5f, new Color(1f, 0.35f, 0.2f));
				}
				else
				{
					PvpApi.ShowLocalBanner("The streets calm down.", 4f, Color.white);
				}
			}
		}

		private bool IsKoFromChaos()
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			if (!_chaosActiveLocal)
			{
				return false;
			}
			try
			{
				Player local = Player.Local;
				if ((Object)(object)local == (Object)null || (Object)(object)((Component)local).transform == (Object)null)
				{
					return false;
				}
				Vector3 position = ((Component)local).transform.position;
				float num = float.MaxValue;
				List<Player> playerList = Player.PlayerList;
				if (playerList != null)
				{
					for (int i = 0; i < playerList.Count; i++)
					{
						try
						{
							Player val = playerList[i];
							if ((Object)(object)val == (Object)null || (Object)(object)val == (Object)(object)local || (Object)(object)((Component)val).transform == (Object)null)
							{
								continue;
							}
							PlayerHealth componentInChildren = ((Component)val).GetComponentInChildren<PlayerHealth>(true);
							if (!((Object)(object)componentInChildren != (Object)null) || componentInChildren.IsAlive)
							{
								float num2 = Vector3.Distance(position, ((Component)val).transform.position);
								if (num2 < num)
								{
									num = num2;
								}
							}
						}
						catch
						{
						}
					}
				}
				float num3 = float.MaxValue;
				try
				{
					List<PoliceOfficer> officers = PoliceOfficer.Officers;
					if (officers != null)
					{
						for (int j = 0; j < officers.Count; j++)
						{
							try
							{
								PoliceOfficer val2 = officers[j];
								if (!((Object)(object)val2 == (Object)null) && !((Object)(object)((Component)val2).transform == (Object)null))
								{
									float num4 = Vector3.Distance(position, ((Component)val2).transform.position);
									if (num4 < num3)
									{
										num3 = num4;
									}
								}
							}
							catch
							{
							}
						}
					}
				}
				catch
				{
				}
				try
				{
					Il2CppArrayBase<CartelGoon> val3 = Object.FindObjectsOfType<CartelGoon>();
					if (val3 != null)
					{
						for (int k = 0; k < val3.Length; k++)
						{
							try
							{
								CartelGoon val4 = val3[k];
								if (!((Object)(object)val4 == (Object)null) && val4.IsGoonSpawned && !((Object)(object)((Component)val4).transform == (Object)null))
								{
									float num5 = Vector3.Distance(position, ((Component)val4).transform.position);
									if (num5 < num3)
									{
										num3 = num5;
									}
								}
							}
							catch
							{
							}
						}
					}
				}
				catch
				{
				}
				return (num3 <= 25f && num3 < num) || num > 60f;
			}
			catch
			{
				return false;
			}
		}

		public override void OnSceneLoaded(int buildIndex, string sceneName)
		{
			RiotManager.Reset();
			ChaosDirector.Reset();
			_chaosActiveLocal = false;
			_seen.Clear();
			_lastState = "";
		}

		public override void OnDeinit()
		{
			ChaosDirector.SetOn(on: false);
			RiotManager.SetOn(on: false);
			RiotManager.Reset();
			ChaosDirector.Reset();
			try
			{
				PvpApi.UnregisterNpcKoAttributor((Func<bool>)IsKoFromChaos);
			}
			catch
			{
			}
			try
			{
				PvpApi.UnregisterMatchToggle(_riotToggle);
			}
			catch
			{
			}
			try
			{
				PvpApi.UnregisterMatchToggle(_chaosToggle);
			}
			catch
			{
			}
		}
	}
	internal static class RiotCompat
	{
		public static bool IsAuthority
		{
			get
			{
				try
				{
					NetworkManager networkManager = InstanceFinder.NetworkManager;
					if ((Object)(object)networkManager == (Object)null)
					{
						return true;
					}
					return networkManager.IsServer;
				}
				catch
				{
					return true;
				}
			}
		}

		public static T Cast<T>(Object o) where T : Object
		{
			return (o == (Object)null) ? default(T) : ((Il2CppObjectBase)o).TryCast<T>();
		}

		public static T CastTargetable<T>(Il2CppObjectBase o) where T : Il2CppObjectBase
		{
			return (o == null) ? default(T) : o.TryCast<T>();
		}
	}
	internal static class RiotConfig
	{
		internal static MelonPreferences_Entry<int> BenziesPerOfficer;

		internal static MelonPreferences_Entry<int> BenziesMax;

		internal static MelonPreferences_Entry<float> OfficerScanRadius;

		internal static MelonPreferences_Entry<float> DoorMaxDistance;

		internal static MelonPreferences_Entry<float> WaveCooldownSeconds;

		internal static MelonPreferences_Entry<bool> OfficersFightBack;

		internal static MelonPreferences_Entry<float> ChaosRadius;

		internal static MelonPreferences_Entry<bool> CiviliansJoinChaos;

		internal static MelonPreferences_Entry<int> MaxChaosCivilians;

		private static bool _loaded;

		internal static void Load()
		{
			if (!_loaded)
			{
				_loaded = true;
				MelonPreferences_Category val = MelonPreferences.CreateCategory("Riot", "Riot");
				BenziesPerOfficer = val.CreateEntry<int>("BenziesPerOfficer", 2, "Benzies per officer", "How many Benzies gang up on each targeted officer (1-4).", false, false, (ValueValidator)null, (string)null);
				BenziesMax = val.CreateEntry<int>("BenziesMax", 8, "Max active Benzies", "Hard cap of simultaneously active riot Benzies (1-16).", false, false, (ValueValidator)null, (string)null);
				OfficerScanRadius = val.CreateEntry<float>("OfficerScanRadius", 80f, "Officer scan radius (m)", "Waves target the nearest under-staffed officer within this radius of ANY player.", false, false, (ValueValidator)null, (string)null);
				DoorMaxDistance = val.CreateEntry<float>("DoorMaxDistance", 80f, "Door search radius (m)", "The Benzies spawn at the door nearest to the targeted officer within this radius (ring fallback beyond).", false, false, (ValueValidator)null, (string)null);
				WaveCooldownSeconds = val.CreateEntry<float>("WaveCooldownSeconds", 20f, "Wave cooldown (s)", "Minimum seconds between spawn waves while the riot runs (min 5).", false, false, (ValueValidator)null, (string)null);
				OfficersFightBack = val.CreateEntry<bool>("OfficersFightBack", true, "Officers fight back", "Explicitly trigger officer counter-attacks (vanilla cops NEVER retaliate against NPCs on their own).", false, false, (ValueValidator)null, (string)null);
				ChaosRadius = val.CreateEntry<float>("ChaosRadius", 60f, "Chaos radius (m)", "CHAOS toggle: cops/civilians within this radius of a player join the hunt against the players.", false, false, (ValueValidator)null, (string)null);
				CiviliansJoinChaos = val.CreateEntry<bool>("CiviliansJoinChaos", true, "Civilians join chaos", "CHAOS toggle: nearby civilian NPCs also attack players (fists). CAUTION: this can pull in other mods' NPCs that stand near a player.", false, false, (ValueValidator)null, (string)null);
				MaxChaosCivilians = val.CreateEntry<int>("MaxChaosCivilians", 8, "Max chaos civilians", "CHAOS toggle: cap of civilians simultaneously hunting players (1-16).", false, false, (ValueValidator)null, (string)null);
			}
		}
	}
	internal static class RiotManager
	{
		private sealed class ActiveGoon
		{
			internal CartelGoon Goon;

			internal PoliceOfficer Target;

			internal Player TargetPlayer;

			internal float DespawnAt;
		}

		private const int POOL_RESERVE = 1;

		private const float GOON_GIVE_UP = 200f;

		private const float RETARGET_INTERVAL = 1.5f;

		private const float GOON_LIFETIME = 180f;

		private const float ORPHAN_RADIUS = 90f;

		private const float DOOR_FALLBACK_DIST = 18f;

		private static readonly List<ActiveGoon> _active = new List<ActiveGoon>();

		private static readonly List<PoliceOfficer> _engagedOfficers = new List<PoliceOfficer>();

		private static float _nextWave;

		private static float _retargetCd;

		internal static bool On { get; private set; }

		internal static int ActiveCount => _active.Count;

		internal static void SetOn(bool on)
		{
			if (On != on)
			{
				On = on;
				if (!on)
				{
					Teardown();
				}
				else
				{
					_nextWave = 0f;
					_retargetCd = 0f;
				}
				MelonLogger.Msg("[Riot] " + (on ? "ON — Benzies are hunting the badges." : "OFF — streets calm down."));
			}
		}

		internal static void Reset()
		{
			_active.Clear();
			_engagedOfficers.Clear();
			On = false;
		}

		internal static void Tick(float dt)
		{
			if (!On)
			{
				return;
			}
			try
			{
				if (!RiotCompat.IsAuthority)
				{
					SetOn(on: false);
					return;
				}
				float time = Time.time;
				Prune(time);
				_retargetCd -= dt;
				if (_retargetCd <= 0f)
				{
					_retargetCd = 1.5f;
					Retarget();
				}
				if (time >= _nextWave && _active.Count < Mathf.Clamp(RiotConfig.BenziesMax.Value, 1, 16))
				{
					_nextWave = time + Mathf.Max(5f, RiotConfig.WaveCooldownSeconds.Value);
					SpawnWave();
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[Riot] Tick: " + ex.Message);
			}
		}

		private static void SpawnWave()
		{
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: 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_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			int num = Mathf.Clamp(RiotConfig.BenziesPerOfficer.Value, 1, 4);
			int num2 = Mathf.Clamp(RiotConfig.BenziesMax.Value, 1, 16);
			if (_active.Count >= num2)
			{
				return;
			}
			PoliceOfficer val;
			Vector3 officerPos;
			if (ChaosDirector.On)
			{
				val = NearestOfficerToAnyPlayer(RiotConfig.OfficerScanRadius.Value, int.MaxValue, out officerPos);
				if ((Object)(object)val == (Object)null && !TryAnyAlivePlayerPos(out officerPos))
				{
					return;
				}
			}
			else
			{
				val = NearestOfficerToAnyPlayer(RiotConfig.OfficerScanRadius.Value, num, out officerPos);
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
			}
			if (!TryNearestDoor(officerPos, RiotConfig.DoorMaxDistance.Value, out var doorPos))
			{
				doorPos = officerPos + RandomRingDir() * 18f;
			}
			doorPos = NavPoint(doorPos);
			GoonPool val2 = Object.FindObjectOfType<GoonPool>(true);
			if ((Object)(object)val2 == (Object)null)
			{
				return;
			}
			int num3;
			try
			{
				num3 = val2.UnspawnedGoonCount - 1;
			}
			catch
			{
				return;
			}
			int num4 = (ChaosDirector.On ? num : (num - AssignedCount(val)));
			int num5 = Mathf.Min(num4, Mathf.Min(num3, num2 - _active.Count));
			if (num5 <= 0)
			{
				return;
			}
			List<CartelGoon> val3 = val2.SpawnMultipleGoons(doorPos, num5, false);
			if (val3 == null)
			{
				return;
			}
			int num6 = 0;
			for (int i = 0; i < val3.Count; i++)
			{
				CartelGoon val4 = val3[i];
				if ((Object)(object)val4 == (Object)null)
				{
					continue;
				}
				try
				{
					NPCBehaviour behaviour = ((NPC)val4).Behaviour;
					CombatBehaviour val5 = ((behaviour != null) ? behaviour.CombatBehaviour : null);
					if ((Object)(object)val5 != (Object)null)
					{
						val5.GiveUpRange = 200f;
					}
				}
				catch
				{
				}
				ActiveGoon activeGoon = new ActiveGoon
				{
					Goon = val4,
					DespawnAt = Time.time + 180f
				};
				if (ChaosDirector.On)
				{
					Player val6 = ChaosDirector.NearestAlivePlayer(doorPos, 180f);
					if ((Object)(object)val6 != (Object)null && SicPlayer(activeGoon, val6))
					{
						num6++;
					}
				}
				else if (Sic(activeGoon, val))
				{
					num6++;
				}
				_active.Add(activeGoon);
			}
			if (num6 > 0)
			{
				MelonLogger.Msg($"[Riot] Wave: {num6} Benzies out of the door at {doorPos} → officer hunt ({_active.Count} active).");
			}
		}

		private static int AssignedCount(PoliceOfficer officer)
		{
			int num = 0;
			for (int i = 0; i < _active.Count; i++)
			{
				try
				{
					if ((Object)(object)_active[i].Target == (Object)(object)officer)
					{
						num++;
					}
				}
				catch
				{
				}
			}
			return num;
		}

		private static void Retarget()
		{
			//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)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			for (int num = _active.Count - 1; num >= 0; num--)
			{
				ActiveGoon activeGoon = _active[num];
				Vector3 position;
				try
				{
					position = ((Component)activeGoon.Goon).transform.position;
				}
				catch
				{
					Despawn(num);
					continue;
				}
				if (ChaosDirector.On)
				{
					if (PlayerInvalid(activeGoon.TargetPlayer))
					{
						Player val = ChaosDirector.NearestAlivePlayer(position, 180f);
						if ((Object)(object)val != (Object)null)
						{
							SicPlayer(activeGoon, val);
						}
					}
					continue;
				}
				activeGoon.TargetPlayer = null;
				if (TargetInvalid(activeGoon.Target))
				{
					PoliceOfficer val2 = NearestOfficerTo(position, 90f);
					if ((Object)(object)val2 == (Object)null)
					{
						Despawn(num);
					}
					else
					{
						Sic(activeGoon, val2);
					}
				}
			}
		}

		private static bool SicPlayer(ActiveGoon ag, Player prey)
		{
			try
			{
				ICombatTargetable val = RiotCompat.CastTargetable<ICombatTargetable>((Il2CppObjectBase)(object)prey);
				if (val == null)
				{
					return false;
				}
				bool flag = false;
				try
				{
					flag = !val.IsNull() && val.IsCurrentlyTargetable;
				}
				catch
				{
				}
				if (!flag)
				{
					return false;
				}
				ag.Goon.AttackEntity(val, false);
				ag.TargetPlayer = prey;
				ag.Target = null;
				return true;
			}
			catch
			{
				return false;
			}
		}

		private static bool PlayerInvalid(Player p)
		{
			try
			{
				if ((Object)(object)p == (Object)null || (Object)(object)((Component)p).transform == (Object)null)
				{
					return true;
				}
				PlayerHealth componentInChildren = ((Component)p).GetComponentInChildren<PlayerHealth>(true);
				return (Object)(object)componentInChildren != (Object)null && !componentInChildren.IsAlive;
			}
			catch
			{
				return true;
			}
		}

		private static bool TryAnyAlivePlayerPos(out Vector3 pos)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: 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)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			pos = Vector3.zero;
			try
			{
				List<Player> playerList = Player.PlayerList;
				if (playerList == null)
				{
					return false;
				}
				for (int i = 0; i < playerList.Count; i++)
				{
					Player val = playerList[i];
					if (!PlayerInvalid(val))
					{
						pos = ((Component)val).transform.position;
						return true;
					}
				}
			}
			catch
			{
			}
			return false;
		}

		private static void Prune(float now)
		{
			for (int num = _active.Count - 1; num >= 0; num--)
			{
				ActiveGoon activeGoon = _active[num];
				bool flag;
				try
				{
					flag = (Object)(object)activeGoon.Goon == (Object)null || !activeGoon.Goon.IsGoonSpawned;
				}
				catch
				{
					flag = true;
				}
				if (flag)
				{
					_active.RemoveAt(num);
				}
				else if (now >= activeGoon.DespawnAt)
				{
					Despawn(num);
				}
			}
		}

		private static void Despawn(int idx)
		{
			try
			{
				CartelGoon goon = _active[idx].Goon;
				if ((Object)(object)goon != (Object)null && goon.IsGoonSpawned)
				{
					goon.Despawn();
				}
			}
			catch
			{
			}
			_active.RemoveAt(idx);
		}

		private static bool Sic(ActiveGoon ag, PoliceOfficer officer)
		{
			try
			{
				ICombatTargetable val = RiotCompat.CastTargetable<ICombatTargetable>((Il2CppObjectBase)(object)officer);
				if (val == null)
				{
					return false;
				}
				bool flag = false;
				try
				{
					flag = !val.IsNull() && val.IsCurrentlyTargetable;
				}
				catch
				{
				}
				if (!flag)
				{
					return false;
				}
				ag.Goon.AttackEntity(val, false);
				ag.Target = officer;
				ag.TargetPlayer = null;
				if (RiotConfig.OfficersFightBack.Value && !ChaosDirector.On)
				{
					try
					{
						CartelGoon goon = ag.Goon;
						object obj2;
						if (goon == null)
						{
							obj2 = null;
						}
						else
						{
							GameObject gameObject = ((Component)goon).gameObject;
							obj2 = ((gameObject != null) ? gameObject.GetComponent<NetworkObject>() : null);
						}
						NetworkObject val2 = (NetworkObject)obj2;
						object obj3;
						if (officer == null)
						{
							obj3 = null;
						}
						else
						{
							NPCBehaviour behaviour = ((NPC)officer).Behaviour;
							obj3 = ((behaviour != null) ? behaviour.CombatBehaviour : null);
						}
						CombatBehaviour val3 = (CombatBehaviour)obj3;
						if ((Object)(object)val2 != (Object)null && (Object)(object)val3 != (Object)null)
						{
							val3.SetTargetAndEnable_Server(val2);
							if (!_engagedOfficers.Contains(officer))
							{
								_engagedOfficers.Add(officer);
							}
						}
					}
					catch
					{
					}
				}
				return true;
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[Riot] Sic: " + ex.Message);
				return false;
			}
		}

		private static void Teardown()
		{
			for (int i = 0; i < _engagedOfficers.Count; i++)
			{
				try
				{
					PoliceOfficer obj = _engagedOfficers[i];
					object obj2;
					if (obj == null)
					{
						obj2 = null;
					}
					else
					{
						NPCBehaviour behaviour = ((NPC)obj).Behaviour;
						obj2 = ((behaviour != null) ? behaviour.CombatBehaviour : null);
					}
					CombatBehaviour val = (CombatBehaviour)obj2;
					if ((Object)(object)val != (Object)null)
					{
						try
						{
							((Behaviour)val).Deactivate();
						}
						catch
						{
						}
						try
						{
							((Behaviour)val).Disable();
						}
						catch
						{
						}
					}
				}
				catch
				{
				}
			}
			_engagedOfficers.Clear();
			for (int j = 0; j < _active.Count; j++)
			{
				try
				{
					CartelGoon goon = _active[j].Goon;
					if ((Object)(object)goon != (Object)null && goon.IsGoonSpawned)
					{
						goon.Despawn();
					}
				}
				catch
				{
				}
			}
			_active.Clear();
		}

		private static bool TargetInvalid(PoliceOfficer o)
		{
			try
			{
				if ((Object)(object)o == (Object)null || (Object)(object)((Component)o).transform == (Object)null)
				{
					return true;
				}
				NPCHealth health = ((NPC)o).Health;
				return (Object)(object)health == (Object)null || health.IsDead || health.IsKnockedOut;
			}
			catch
			{
				return true;
			}
		}

		private static PoliceOfficer NearestOfficerToAnyPlayer(float radius, int perOfficer, out Vector3 officerPos)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			officerPos = Vector3.zero;
			PoliceOfficer result = null;
			float num = float.MaxValue;
			try
			{
				List<PoliceOfficer> officers = PoliceOfficer.Officers;
				List<Player> playerList = Player.PlayerList;
				if (officers == null || playerList == null)
				{
					return null;
				}
				for (int i = 0; i < officers.Count; i++)
				{
					try
					{
						PoliceOfficer val = officers[i];
						if (TargetInvalid(val) || AssignedCount(val) >= perOfficer)
						{
							continue;
						}
						Vector3 position = ((Component)val).transform.position;
						for (int j = 0; j < playerList.Count; j++)
						{
							Player val2 = playerList[j];
							if (!((Object)(object)val2 == (Object)null))
							{
								float num2 = Vector3.Distance(position, ((Component)val2).transform.position);
								if (num2 <= radius && num2 < num)
								{
									num = num2;
									result = val;
									officerPos = position;
								}
							}
						}
					}
					catch
					{
					}
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[Riot] OfficerScan: " + ex.Message);
			}
			return result;
		}

		private static PoliceOfficer NearestOfficerTo(Vector3 pos, float radius)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			PoliceOfficer result = null;
			float num = radius;
			try
			{
				List<PoliceOfficer> officers = PoliceOfficer.Officers;
				if (officers == null)
				{
					return null;
				}
				for (int i = 0; i < officers.Count; i++)
				{
					try
					{
						PoliceOfficer val = officers[i];
						if (!TargetInvalid(val))
						{
							float num2 = Vector3.Distance(((Component)val).transform.position, pos);
							if (num2 < num)
							{
								num = num2;
								result = val;
							}
						}
					}
					catch
					{
					}
				}
			}
			catch
			{
			}
			return result;
		}

		private static bool TryNearestDoor(Vector3 from, float maxDistance, out Vector3 doorPos)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: 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_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: 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)
			doorPos = from;
			try
			{
				Il2CppArrayBase<StaticDoor> val = Object.FindObjectsOfType<StaticDoor>();
				if (val == null || val.Length == 0)
				{
					return false;
				}
				float num = maxDistance * maxDistance;
				bool result = false;
				for (int i = 0; i < val.Length; i++)
				{
					StaticDoor val2;
					try
					{
						val2 = val[i];
					}
					catch
					{
						continue;
					}
					if (!((Object)(object)val2 == (Object)null))
					{
						Vector3 val3;
						try
						{
							Transform accessPoint = val2.AccessPoint;
							val3 = (((Object)(object)accessPoint != (Object)null) ? accessPoint.position : ((Component)val2).transform.position);
						}
						catch
						{
							continue;
						}
						Vector3 val4 = val3 - from;
						float sqrMagnitude = ((Vector3)(ref val4)).sqrMagnitude;
						if (sqrMagnitude < num)
						{
							num = sqrMagnitude;
							doorPos = val3;
							result = true;
						}
					}
				}
				return result;
			}
			catch
			{
				return false;
			}
		}

		private static Vector3 RandomRingDir()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: 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)
			//IL_0032: 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)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			Vector2 insideUnitCircle = Random.insideUnitCircle;
			Vector2 val = ((Vector2)(ref insideUnitCircle)).normalized;
			if (((Vector2)(ref val)).sqrMagnitude < 0.01f)
			{
				val = Vector2.right;
			}
			return new Vector3(val.x, 0f, val.y);
		}

		private static Vector3 NavPoint(Vector3 p)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				NavMeshHit val = default(NavMeshHit);
				if (NavMesh.SamplePosition(p + Vector3.up * 1.5f, ref val, 12f, -1))
				{
					return ((NavMeshHit)(ref val)).position;
				}
			}
			catch
			{
			}
			return p;
		}
	}
	public class RiotMod : MelonMod
	{
		private RiotAddon _addon;

		public override void OnInitializeMelon()
		{
			_addon = new RiotAddon();
			if (PvpApi.RegisterAddon((IPvpAddon)(object)_addon))
			{
				MelonLogger.Msg("[Riot] registered with MultiplayerPVP.");
			}
			else
			{
				MelonLogger.Warning("[Riot] registration failed — is MultiplayerPVP loaded?");
			}
		}

		public override void OnDeinitializeMelon()
		{
			try
			{
				PvpApi.UnregisterAddon((IPvpAddon)(object)_addon);
			}
			catch
			{
			}
		}
	}
}

Riot.MONO.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using FishNet;
using FishNet.Managing;
using FishNet.Object;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using MultiplayerPVP.Addons;
using MultiplayerPVP.Core;
using Riot;
using ScheduleOne.Cartel;
using ScheduleOne.Combat;
using ScheduleOne.Doors;
using ScheduleOne.NPCs;
using ScheduleOne.NPCs.Behaviour;
using ScheduleOne.PlayerScripts;
using ScheduleOne.PlayerScripts.Health;
using ScheduleOne.Police;
using UnityEngine;
using UnityEngine.AI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonAdditionalDependencies(new string[] { "MultiplayerPVP" })]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: MelonInfo(typeof(RiotMod), "Riot", "1.0.1", "Virtunerd", null)]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: AssemblyFileVersion("1.0.1")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.1.0")]
[module: UnverifiableCode]
[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 Riot
{
	internal static class ChaosDirector
	{
		private const float RETARGET_INTERVAL = 1.5f;

		private const float NPC_GIVE_UP = 200f;

		private static readonly List<NPC> _engaged = new List<NPC>();

		private static readonly List<NPC> _civilians = new List<NPC>();

		private static float _cd;

		internal static bool On { get; private set; }

		internal static void SetOn(bool on)
		{
			if (On != on)
			{
				On = on;
				if (!on)
				{
					Teardown();
				}
				else
				{
					_cd = 0f;
				}
				MelonLogger.Msg("[Riot] CHAOS " + (on ? "ON — the city hunts the players." : "OFF."));
			}
		}

		internal static void Reset()
		{
			_engaged.Clear();
			_civilians.Clear();
			On = false;
		}

		internal static void Tick(float dt)
		{
			//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			if (!On)
			{
				return;
			}
			try
			{
				if (!RiotCompat.IsAuthority)
				{
					SetOn(on: false);
					return;
				}
				_cd -= dt;
				if (_cd > 0f)
				{
					return;
				}
				_cd = 1.5f;
				float num = Mathf.Clamp(RiotConfig.ChaosRadius.Value, 15f, 200f);
				try
				{
					List<PoliceOfficer> officers = PoliceOfficer.Officers;
					if (officers != null)
					{
						for (int i = 0; i < officers.Count; i++)
						{
							try
							{
								PoliceOfficer val = officers[i];
								if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).transform == (Object)null)
								{
									continue;
								}
								NPCHealth health = ((NPC)val).Health;
								if (!((Object)(object)health == (Object)null) && !health.IsDead && !health.IsKnockedOut)
								{
									Player val2 = NearestAlivePlayer(((Component)val).transform.position, num);
									if (!((Object)(object)val2 == (Object)null))
									{
										SicNpc((NPC)(object)val, val2, civilian: false);
									}
								}
							}
							catch
							{
							}
						}
					}
				}
				catch
				{
				}
				if (!RiotConfig.CiviliansJoinChaos.Value)
				{
					return;
				}
				PruneCivilians();
				int num2 = Mathf.Clamp(RiotConfig.MaxChaosCivilians.Value, 1, 16);
				try
				{
					List<NPC> nPCRegistry = NPCManager.NPCRegistry;
					if (nPCRegistry != null)
					{
						for (int j = 0; j < nPCRegistry.Count; j++)
						{
							if (_civilians.Count >= num2)
							{
								break;
							}
							try
							{
								NPC val3 = nPCRegistry[j];
								if ((Object)(object)val3 == (Object)null || (Object)(object)((Component)val3).transform == (Object)null || (Object)(object)RiotCompat.Cast<PoliceOfficer>((Object)(object)val3) != (Object)null || (Object)(object)RiotCompat.Cast<CartelGoon>((Object)(object)val3) != (Object)null)
								{
									continue;
								}
								NPCHealth health2 = val3.Health;
								if (!((Object)(object)health2 == (Object)null) && !health2.IsDead && !health2.IsKnockedOut)
								{
									Player val4 = NearestAlivePlayer(((Component)val3).transform.position, num);
									if (!((Object)(object)val4 == (Object)null) && SicNpc(val3, val4, civilian: true) && !_civilians.Contains(val3))
									{
										_civilians.Add(val3);
									}
								}
							}
							catch
							{
							}
						}
					}
				}
				catch
				{
				}
				for (int k = 0; k < _civilians.Count; k++)
				{
					try
					{
						NPC val5 = _civilians[k];
						if (!((Object)(object)val5 == (Object)null) && !((Object)(object)((Component)val5).transform == (Object)null))
						{
							Player val6 = NearestAlivePlayer(((Component)val5).transform.position, num * 2f);
							if ((Object)(object)val6 != (Object)null)
							{
								SicNpc(val5, val6, civilian: true);
							}
						}
					}
					catch
					{
					}
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[Riot] Chaos tick: " + ex.Message);
			}
		}

		private static bool SicNpc(NPC npc, Player target, bool civilian)
		{
			try
			{
				object obj;
				if (target == null)
				{
					obj = null;
				}
				else
				{
					GameObject gameObject = ((Component)target).gameObject;
					obj = ((gameObject != null) ? gameObject.GetComponent<NetworkObject>() : null);
				}
				NetworkObject val = (NetworkObject)obj;
				CombatBehaviour val2 = ((npc == null) ? null : npc.Behaviour?.CombatBehaviour);
				if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
				{
					return false;
				}
				try
				{
					val2.GiveUpRange = 200f;
				}
				catch
				{
				}
				val2.SetTargetAndEnable_Server(val);
				if (!_engaged.Contains(npc))
				{
					_engaged.Add(npc);
				}
				return true;
			}
			catch
			{
				return false;
			}
		}

		private static void PruneCivilians()
		{
			for (int num = _civilians.Count - 1; num >= 0; num--)
			{
				try
				{
					NPC val = _civilians[num];
					NPCHealth val2 = (((Object)(object)val != (Object)null) ? val.Health : null);
					if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).transform == (Object)null || (Object)(object)val2 == (Object)null || val2.IsDead || val2.IsKnockedOut)
					{
						_civilians.RemoveAt(num);
					}
				}
				catch
				{
					_civilians.RemoveAt(num);
				}
			}
		}

		internal static Player NearestAlivePlayer(Vector3 pos, float radius)
		{
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			Player result = null;
			float num = radius;
			try
			{
				List<Player> playerList = Player.PlayerList;
				if (playerList == null)
				{
					return null;
				}
				for (int i = 0; i < playerList.Count; i++)
				{
					try
					{
						Player val = playerList[i];
						if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).transform == (Object)null)
						{
							continue;
						}
						PlayerHealth componentInChildren = ((Component)val).GetComponentInChildren<PlayerHealth>(true);
						if (!((Object)(object)componentInChildren != (Object)null) || componentInChildren.IsAlive)
						{
							float num2 = Vector3.Distance(((Component)val).transform.position, pos);
							if (num2 < num)
							{
								num = num2;
								result = val;
							}
						}
					}
					catch
					{
					}
				}
			}
			catch
			{
			}
			return result;
		}

		private static void Teardown()
		{
			for (int i = 0; i < _engaged.Count; i++)
			{
				try
				{
					NPC obj = _engaged[i];
					CombatBehaviour val = ((obj == null) ? null : obj.Behaviour?.CombatBehaviour);
					if ((Object)(object)val != (Object)null)
					{
						try
						{
							((Behaviour)val).Deactivate();
						}
						catch
						{
						}
						try
						{
							((Behaviour)val).Disable();
						}
						catch
						{
						}
					}
				}
				catch
				{
				}
			}
			_engaged.Clear();
			_civilians.Clear();
		}
	}
	internal sealed class RiotAddon : PvpAddonBase
	{
		private PvpMatchToggle _riotToggle;

		private PvpMatchToggle _chaosToggle;

		private PvpChannel _channel;

		private int _seq;

		private readonly Dictionary<ulong, string> _seen = new Dictionary<ulong, string>();

		private bool _chaosActiveLocal;

		private string _lastState = "";

		private bool _prevRiotReq;

		private bool _prevChaosReq;

		public override string Id => "Riot";

		public override void OnRegistered()
		{
			RiotConfig.Load();
			_channel = PvpApi.Channel("riot");
			if (_channel != null)
			{
				_channel.OnMessage += OnRiotMsg;
			}
			_riotToggle = PvpApi.RegisterMatchToggle("riot", "Riot", "City riot for this round: Benzies storm out of the door nearest each cop and brawl with the police while you play. Mutually exclusive with Chaos.");
			_chaosToggle = PvpApi.RegisterMatchToggle("chaos", "Chaos", "The city turns on YOU for this round: cops, Benzies and civilians hunt every player on sight until KO. NPC knock-outs confiscate weapons. Mutually exclusive with Riot.");
			if (_riotToggle != null)
			{
				_riotToggle.Activated += OnRiotActivated;
				_riotToggle.Deactivated += OnRoundDeactivated;
			}
			if (_chaosToggle != null)
			{
				_chaosToggle.Activated += OnChaosActivated;
				_chaosToggle.Deactivated += OnRoundDeactivated;
			}
			PvpApi.RegisterNpcKoAttributor((Func<bool>)IsKoFromChaos);
		}

		private void OnRiotActivated()
		{
			if (PvpApi.IsMultiplayer && RiotCompat.IsAuthority)
			{
				ChaosDirector.SetOn(on: false);
				RiotManager.SetOn(on: true);
				PublishState();
			}
		}

		private void OnChaosActivated()
		{
			if (PvpApi.IsMultiplayer && RiotCompat.IsAuthority)
			{
				ChaosDirector.SetOn(on: true);
				RiotManager.SetOn(on: true);
				_chaosActiveLocal = true;
				PublishState();
			}
		}

		private void OnRoundDeactivated()
		{
			bool flag = RiotManager.On || ChaosDirector.On;
			ChaosDirector.SetOn(on: false);
			RiotManager.SetOn(on: false);
			_chaosActiveLocal = false;
			if (flag)
			{
				PublishState();
			}
		}

		public override void OnUpdate(float dt)
		{
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Invalid comparison between Unknown and I4
			try
			{
				if (_chaosToggle != null && _riotToggle != null)
				{
					bool requested = _riotToggle.Requested;
					bool requested2 = _chaosToggle.Requested;
					if (requested && requested2)
					{
						if (requested2 && !_prevChaosReq)
						{
							_riotToggle.Requested = false;
						}
						else
						{
							_chaosToggle.Requested = false;
						}
					}
					_prevRiotReq = _riotToggle.Requested;
					_prevChaosReq = _chaosToggle.Requested;
				}
			}
			catch
			{
			}
			bool flag = (int)PvpApi.Phase != 2 || !PvpApi.IsMultiplayer;
			if (ChaosDirector.On && flag)
			{
				ChaosDirector.SetOn(on: false);
				_chaosActiveLocal = false;
			}
			if (RiotManager.On && flag)
			{
				RiotManager.SetOn(on: false);
			}
			RiotManager.Tick(dt);
			ChaosDirector.Tick(dt);
			if (_channel != null)
			{
				List<KeyValuePair<ulong, string>> list = _channel.ReadAll();
				for (int i = 0; i < list.Count; i++)
				{
					OnRiotMsg(list[i].Key, list[i].Value);
				}
			}
		}

		private void PublishState()
		{
			bool flag = RiotManager.On && !ChaosDirector.On;
			string text = (flag ? "1" : "0") + "~" + (ChaosDirector.On ? "1" : "0");
			ShowState(flag, ChaosDirector.On);
			PvpChannel channel = _channel;
			if (channel != null)
			{
				int num = ++_seq;
				channel.Publish(num + "~" + text);
			}
		}

		private void OnRiotMsg(ulong fromSteamId, string record)
		{
			if (string.IsNullOrEmpty(record) || (_seen.TryGetValue(fromSteamId, out var value) && value == record))
			{
				return;
			}
			_seen[fromSteamId] = record;
			if (!RiotCompat.IsAuthority)
			{
				string[] array = record.Split(new char[1] { '~' });
				if (array.Length >= 3)
				{
					bool riot = array[1] == "1";
					ShowState(riot, _chaosActiveLocal = array[2] == "1");
				}
			}
		}

		private void ShowState(bool riot, bool chaos)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			string text = (riot ? "r" : "") + (chaos ? "c" : "");
			if (!(text == _lastState))
			{
				_lastState = text;
				if (chaos)
				{
					PvpApi.ShowLocalBanner("☠ CHAOS — the whole city is out for YOUR blood!", 5f, new Color(1f, 0.15f, 0.15f));
				}
				else if (riot)
				{
					PvpApi.ShowLocalBanner("⚠ RIOT — the Benzies are out!", 5f, new Color(1f, 0.35f, 0.2f));
				}
				else
				{
					PvpApi.ShowLocalBanner("The streets calm down.", 4f, Color.white);
				}
			}
		}

		private bool IsKoFromChaos()
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: 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)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			if (!_chaosActiveLocal)
			{
				return false;
			}
			try
			{
				Player local = Player.Local;
				if ((Object)(object)local == (Object)null || (Object)(object)((Component)local).transform == (Object)null)
				{
					return false;
				}
				Vector3 position = ((Component)local).transform.position;
				float num = float.MaxValue;
				List<Player> playerList = Player.PlayerList;
				if (playerList != null)
				{
					for (int i = 0; i < playerList.Count; i++)
					{
						try
						{
							Player val = playerList[i];
							if ((Object)(object)val == (Object)null || (Object)(object)val == (Object)(object)local || (Object)(object)((Component)val).transform == (Object)null)
							{
								continue;
							}
							PlayerHealth componentInChildren = ((Component)val).GetComponentInChildren<PlayerHealth>(true);
							if (!((Object)(object)componentInChildren != (Object)null) || componentInChildren.IsAlive)
							{
								float num2 = Vector3.Distance(position, ((Component)val).transform.position);
								if (num2 < num)
								{
									num = num2;
								}
							}
						}
						catch
						{
						}
					}
				}
				float num3 = float.MaxValue;
				try
				{
					List<PoliceOfficer> officers = PoliceOfficer.Officers;
					if (officers != null)
					{
						for (int j = 0; j < officers.Count; j++)
						{
							try
							{
								PoliceOfficer val2 = officers[j];
								if (!((Object)(object)val2 == (Object)null) && !((Object)(object)((Component)val2).transform == (Object)null))
								{
									float num4 = Vector3.Distance(position, ((Component)val2).transform.position);
									if (num4 < num3)
									{
										num3 = num4;
									}
								}
							}
							catch
							{
							}
						}
					}
				}
				catch
				{
				}
				try
				{
					CartelGoon[] array = Object.FindObjectsOfType<CartelGoon>();
					if (array != null)
					{
						for (int k = 0; k < array.Length; k++)
						{
							try
							{
								CartelGoon val3 = array[k];
								if (!((Object)(object)val3 == (Object)null) && val3.IsGoonSpawned && !((Object)(object)((Component)val3).transform == (Object)null))
								{
									float num5 = Vector3.Distance(position, ((Component)val3).transform.position);
									if (num5 < num3)
									{
										num3 = num5;
									}
								}
							}
							catch
							{
							}
						}
					}
				}
				catch
				{
				}
				return (num3 <= 25f && num3 < num) || num > 60f;
			}
			catch
			{
				return false;
			}
		}

		public override void OnSceneLoaded(int buildIndex, string sceneName)
		{
			RiotManager.Reset();
			ChaosDirector.Reset();
			_chaosActiveLocal = false;
			_seen.Clear();
			_lastState = "";
		}

		public override void OnDeinit()
		{
			ChaosDirector.SetOn(on: false);
			RiotManager.SetOn(on: false);
			RiotManager.Reset();
			ChaosDirector.Reset();
			try
			{
				PvpApi.UnregisterNpcKoAttributor((Func<bool>)IsKoFromChaos);
			}
			catch
			{
			}
			try
			{
				PvpApi.UnregisterMatchToggle(_riotToggle);
			}
			catch
			{
			}
			try
			{
				PvpApi.UnregisterMatchToggle(_chaosToggle);
			}
			catch
			{
			}
		}
	}
	internal static class RiotCompat
	{
		public static bool IsAuthority
		{
			get
			{
				try
				{
					NetworkManager networkManager = InstanceFinder.NetworkManager;
					if ((Object)(object)networkManager == (Object)null)
					{
						return true;
					}
					return networkManager.IsServer;
				}
				catch
				{
					return true;
				}
			}
		}

		public static T Cast<T>(Object o) where T : Object
		{
			return (T)(object)((o is T) ? o : null);
		}

		public static T CastTargetable<T>(object o) where T : class
		{
			return o as T;
		}
	}
	internal static class RiotConfig
	{
		internal static MelonPreferences_Entry<int> BenziesPerOfficer;

		internal static MelonPreferences_Entry<int> BenziesMax;

		internal static MelonPreferences_Entry<float> OfficerScanRadius;

		internal static MelonPreferences_Entry<float> DoorMaxDistance;

		internal static MelonPreferences_Entry<float> WaveCooldownSeconds;

		internal static MelonPreferences_Entry<bool> OfficersFightBack;

		internal static MelonPreferences_Entry<float> ChaosRadius;

		internal static MelonPreferences_Entry<bool> CiviliansJoinChaos;

		internal static MelonPreferences_Entry<int> MaxChaosCivilians;

		private static bool _loaded;

		internal static void Load()
		{
			if (!_loaded)
			{
				_loaded = true;
				MelonPreferences_Category val = MelonPreferences.CreateCategory("Riot", "Riot");
				BenziesPerOfficer = val.CreateEntry<int>("BenziesPerOfficer", 2, "Benzies per officer", "How many Benzies gang up on each targeted officer (1-4).", false, false, (ValueValidator)null, (string)null);
				BenziesMax = val.CreateEntry<int>("BenziesMax", 8, "Max active Benzies", "Hard cap of simultaneously active riot Benzies (1-16).", false, false, (ValueValidator)null, (string)null);
				OfficerScanRadius = val.CreateEntry<float>("OfficerScanRadius", 80f, "Officer scan radius (m)", "Waves target the nearest under-staffed officer within this radius of ANY player.", false, false, (ValueValidator)null, (string)null);
				DoorMaxDistance = val.CreateEntry<float>("DoorMaxDistance", 80f, "Door search radius (m)", "The Benzies spawn at the door nearest to the targeted officer within this radius (ring fallback beyond).", false, false, (ValueValidator)null, (string)null);
				WaveCooldownSeconds = val.CreateEntry<float>("WaveCooldownSeconds", 20f, "Wave cooldown (s)", "Minimum seconds between spawn waves while the riot runs (min 5).", false, false, (ValueValidator)null, (string)null);
				OfficersFightBack = val.CreateEntry<bool>("OfficersFightBack", true, "Officers fight back", "Explicitly trigger officer counter-attacks (vanilla cops NEVER retaliate against NPCs on their own).", false, false, (ValueValidator)null, (string)null);
				ChaosRadius = val.CreateEntry<float>("ChaosRadius", 60f, "Chaos radius (m)", "CHAOS toggle: cops/civilians within this radius of a player join the hunt against the players.", false, false, (ValueValidator)null, (string)null);
				CiviliansJoinChaos = val.CreateEntry<bool>("CiviliansJoinChaos", true, "Civilians join chaos", "CHAOS toggle: nearby civilian NPCs also attack players (fists). CAUTION: this can pull in other mods' NPCs that stand near a player.", false, false, (ValueValidator)null, (string)null);
				MaxChaosCivilians = val.CreateEntry<int>("MaxChaosCivilians", 8, "Max chaos civilians", "CHAOS toggle: cap of civilians simultaneously hunting players (1-16).", false, false, (ValueValidator)null, (string)null);
			}
		}
	}
	internal static class RiotManager
	{
		private sealed class ActiveGoon
		{
			internal CartelGoon Goon;

			internal PoliceOfficer Target;

			internal Player TargetPlayer;

			internal float DespawnAt;
		}

		private const int POOL_RESERVE = 1;

		private const float GOON_GIVE_UP = 200f;

		private const float RETARGET_INTERVAL = 1.5f;

		private const float GOON_LIFETIME = 180f;

		private const float ORPHAN_RADIUS = 90f;

		private const float DOOR_FALLBACK_DIST = 18f;

		private static readonly List<ActiveGoon> _active = new List<ActiveGoon>();

		private static readonly List<PoliceOfficer> _engagedOfficers = new List<PoliceOfficer>();

		private static float _nextWave;

		private static float _retargetCd;

		internal static bool On { get; private set; }

		internal static int ActiveCount => _active.Count;

		internal static void SetOn(bool on)
		{
			if (On != on)
			{
				On = on;
				if (!on)
				{
					Teardown();
				}
				else
				{
					_nextWave = 0f;
					_retargetCd = 0f;
				}
				MelonLogger.Msg("[Riot] " + (on ? "ON — Benzies are hunting the badges." : "OFF — streets calm down."));
			}
		}

		internal static void Reset()
		{
			_active.Clear();
			_engagedOfficers.Clear();
			On = false;
		}

		internal static void Tick(float dt)
		{
			if (!On)
			{
				return;
			}
			try
			{
				if (!RiotCompat.IsAuthority)
				{
					SetOn(on: false);
					return;
				}
				float time = Time.time;
				Prune(time);
				_retargetCd -= dt;
				if (_retargetCd <= 0f)
				{
					_retargetCd = 1.5f;
					Retarget();
				}
				if (time >= _nextWave && _active.Count < Mathf.Clamp(RiotConfig.BenziesMax.Value, 1, 16))
				{
					_nextWave = time + Mathf.Max(5f, RiotConfig.WaveCooldownSeconds.Value);
					SpawnWave();
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[Riot] Tick: " + ex.Message);
			}
		}

		private static void SpawnWave()
		{
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: 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_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0292: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			int num = Mathf.Clamp(RiotConfig.BenziesPerOfficer.Value, 1, 4);
			int num2 = Mathf.Clamp(RiotConfig.BenziesMax.Value, 1, 16);
			if (_active.Count >= num2)
			{
				return;
			}
			PoliceOfficer val;
			Vector3 officerPos;
			if (ChaosDirector.On)
			{
				val = NearestOfficerToAnyPlayer(RiotConfig.OfficerScanRadius.Value, int.MaxValue, out officerPos);
				if ((Object)(object)val == (Object)null && !TryAnyAlivePlayerPos(out officerPos))
				{
					return;
				}
			}
			else
			{
				val = NearestOfficerToAnyPlayer(RiotConfig.OfficerScanRadius.Value, num, out officerPos);
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
			}
			if (!TryNearestDoor(officerPos, RiotConfig.DoorMaxDistance.Value, out var doorPos))
			{
				doorPos = officerPos + RandomRingDir() * 18f;
			}
			doorPos = NavPoint(doorPos);
			GoonPool val2 = Object.FindObjectOfType<GoonPool>(true);
			if ((Object)(object)val2 == (Object)null)
			{
				return;
			}
			int num3;
			try
			{
				num3 = val2.UnspawnedGoonCount - 1;
			}
			catch
			{
				return;
			}
			int num4 = (ChaosDirector.On ? num : (num - AssignedCount(val)));
			int num5 = Mathf.Min(num4, Mathf.Min(num3, num2 - _active.Count));
			if (num5 <= 0)
			{
				return;
			}
			List<CartelGoon> list = val2.SpawnMultipleGoons(doorPos, num5, false);
			if (list == null)
			{
				return;
			}
			int num6 = 0;
			for (int i = 0; i < list.Count; i++)
			{
				CartelGoon val3 = list[i];
				if ((Object)(object)val3 == (Object)null)
				{
					continue;
				}
				try
				{
					CombatBehaviour val4 = ((NPC)val3).Behaviour?.CombatBehaviour;
					if ((Object)(object)val4 != (Object)null)
					{
						val4.GiveUpRange = 200f;
					}
				}
				catch
				{
				}
				ActiveGoon activeGoon = new ActiveGoon
				{
					Goon = val3,
					DespawnAt = Time.time + 180f
				};
				if (ChaosDirector.On)
				{
					Player val5 = ChaosDirector.NearestAlivePlayer(doorPos, 180f);
					if ((Object)(object)val5 != (Object)null && SicPlayer(activeGoon, val5))
					{
						num6++;
					}
				}
				else if (Sic(activeGoon, val))
				{
					num6++;
				}
				_active.Add(activeGoon);
			}
			if (num6 > 0)
			{
				MelonLogger.Msg($"[Riot] Wave: {num6} Benzies out of the door at {doorPos} → officer hunt ({_active.Count} active).");
			}
		}

		private static int AssignedCount(PoliceOfficer officer)
		{
			int num = 0;
			for (int i = 0; i < _active.Count; i++)
			{
				try
				{
					if ((Object)(object)_active[i].Target == (Object)(object)officer)
					{
						num++;
					}
				}
				catch
				{
				}
			}
			return num;
		}

		private static void Retarget()
		{
			//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)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			for (int num = _active.Count - 1; num >= 0; num--)
			{
				ActiveGoon activeGoon = _active[num];
				Vector3 position;
				try
				{
					position = ((Component)activeGoon.Goon).transform.position;
				}
				catch
				{
					Despawn(num);
					continue;
				}
				if (ChaosDirector.On)
				{
					if (PlayerInvalid(activeGoon.TargetPlayer))
					{
						Player val = ChaosDirector.NearestAlivePlayer(position, 180f);
						if ((Object)(object)val != (Object)null)
						{
							SicPlayer(activeGoon, val);
						}
					}
					continue;
				}
				activeGoon.TargetPlayer = null;
				if (TargetInvalid(activeGoon.Target))
				{
					PoliceOfficer val2 = NearestOfficerTo(position, 90f);
					if ((Object)(object)val2 == (Object)null)
					{
						Despawn(num);
					}
					else
					{
						Sic(activeGoon, val2);
					}
				}
			}
		}

		private static bool SicPlayer(ActiveGoon ag, Player prey)
		{
			try
			{
				ICombatTargetable val = RiotCompat.CastTargetable<ICombatTargetable>(prey);
				if (val == null)
				{
					return false;
				}
				bool flag = false;
				try
				{
					flag = !val.IsNull() && val.IsCurrentlyTargetable;
				}
				catch
				{
				}
				if (!flag)
				{
					return false;
				}
				ag.Goon.AttackEntity(val, false);
				ag.TargetPlayer = prey;
				ag.Target = null;
				return true;
			}
			catch
			{
				return false;
			}
		}

		private static bool PlayerInvalid(Player p)
		{
			try
			{
				if ((Object)(object)p == (Object)null || (Object)(object)((Component)p).transform == (Object)null)
				{
					return true;
				}
				PlayerHealth componentInChildren = ((Component)p).GetComponentInChildren<PlayerHealth>(true);
				return (Object)(object)componentInChildren != (Object)null && !componentInChildren.IsAlive;
			}
			catch
			{
				return true;
			}
		}

		private static bool TryAnyAlivePlayerPos(out Vector3 pos)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: 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)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			pos = Vector3.zero;
			try
			{
				List<Player> playerList = Player.PlayerList;
				if (playerList == null)
				{
					return false;
				}
				for (int i = 0; i < playerList.Count; i++)
				{
					Player val = playerList[i];
					if (!PlayerInvalid(val))
					{
						pos = ((Component)val).transform.position;
						return true;
					}
				}
			}
			catch
			{
			}
			return false;
		}

		private static void Prune(float now)
		{
			for (int num = _active.Count - 1; num >= 0; num--)
			{
				ActiveGoon activeGoon = _active[num];
				bool flag;
				try
				{
					flag = (Object)(object)activeGoon.Goon == (Object)null || !activeGoon.Goon.IsGoonSpawned;
				}
				catch
				{
					flag = true;
				}
				if (flag)
				{
					_active.RemoveAt(num);
				}
				else if (now >= activeGoon.DespawnAt)
				{
					Despawn(num);
				}
			}
		}

		private static void Despawn(int idx)
		{
			try
			{
				CartelGoon goon = _active[idx].Goon;
				if ((Object)(object)goon != (Object)null && goon.IsGoonSpawned)
				{
					goon.Despawn();
				}
			}
			catch
			{
			}
			_active.RemoveAt(idx);
		}

		private static bool Sic(ActiveGoon ag, PoliceOfficer officer)
		{
			try
			{
				ICombatTargetable val = RiotCompat.CastTargetable<ICombatTargetable>(officer);
				if (val == null)
				{
					return false;
				}
				bool flag = false;
				try
				{
					flag = !val.IsNull() && val.IsCurrentlyTargetable;
				}
				catch
				{
				}
				if (!flag)
				{
					return false;
				}
				ag.Goon.AttackEntity(val, false);
				ag.Target = officer;
				ag.TargetPlayer = null;
				if (RiotConfig.OfficersFightBack.Value && !ChaosDirector.On)
				{
					try
					{
						CartelGoon goon = ag.Goon;
						object obj2;
						if (goon == null)
						{
							obj2 = null;
						}
						else
						{
							GameObject gameObject = ((Component)goon).gameObject;
							obj2 = ((gameObject != null) ? gameObject.GetComponent<NetworkObject>() : null);
						}
						NetworkObject val2 = (NetworkObject)obj2;
						CombatBehaviour val3 = ((officer == null) ? null : ((NPC)officer).Behaviour?.CombatBehaviour);
						if ((Object)(object)val2 != (Object)null && (Object)(object)val3 != (Object)null)
						{
							val3.SetTargetAndEnable_Server(val2);
							if (!_engagedOfficers.Contains(officer))
							{
								_engagedOfficers.Add(officer);
							}
						}
					}
					catch
					{
					}
				}
				return true;
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[Riot] Sic: " + ex.Message);
				return false;
			}
		}

		private static void Teardown()
		{
			for (int i = 0; i < _engagedOfficers.Count; i++)
			{
				try
				{
					PoliceOfficer obj = _engagedOfficers[i];
					CombatBehaviour val = ((obj == null) ? null : ((NPC)obj).Behaviour?.CombatBehaviour);
					if ((Object)(object)val != (Object)null)
					{
						try
						{
							((Behaviour)val).Deactivate();
						}
						catch
						{
						}
						try
						{
							((Behaviour)val).Disable();
						}
						catch
						{
						}
					}
				}
				catch
				{
				}
			}
			_engagedOfficers.Clear();
			for (int j = 0; j < _active.Count; j++)
			{
				try
				{
					CartelGoon goon = _active[j].Goon;
					if ((Object)(object)goon != (Object)null && goon.IsGoonSpawned)
					{
						goon.Despawn();
					}
				}
				catch
				{
				}
			}
			_active.Clear();
		}

		private static bool TargetInvalid(PoliceOfficer o)
		{
			try
			{
				if ((Object)(object)o == (Object)null || (Object)(object)((Component)o).transform == (Object)null)
				{
					return true;
				}
				NPCHealth health = ((NPC)o).Health;
				return (Object)(object)health == (Object)null || health.IsDead || health.IsKnockedOut;
			}
			catch
			{
				return true;
			}
		}

		private static PoliceOfficer NearestOfficerToAnyPlayer(float radius, int perOfficer, out Vector3 officerPos)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			officerPos = Vector3.zero;
			PoliceOfficer result = null;
			float num = float.MaxValue;
			try
			{
				List<PoliceOfficer> officers = PoliceOfficer.Officers;
				List<Player> playerList = Player.PlayerList;
				if (officers == null || playerList == null)
				{
					return null;
				}
				for (int i = 0; i < officers.Count; i++)
				{
					try
					{
						PoliceOfficer val = officers[i];
						if (TargetInvalid(val) || AssignedCount(val) >= perOfficer)
						{
							continue;
						}
						Vector3 position = ((Component)val).transform.position;
						for (int j = 0; j < playerList.Count; j++)
						{
							Player val2 = playerList[j];
							if (!((Object)(object)val2 == (Object)null))
							{
								float num2 = Vector3.Distance(position, ((Component)val2).transform.position);
								if (num2 <= radius && num2 < num)
								{
									num = num2;
									result = val;
									officerPos = position;
								}
							}
						}
					}
					catch
					{
					}
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[Riot] OfficerScan: " + ex.Message);
			}
			return result;
		}

		private static PoliceOfficer NearestOfficerTo(Vector3 pos, float radius)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			PoliceOfficer result = null;
			float num = radius;
			try
			{
				List<PoliceOfficer> officers = PoliceOfficer.Officers;
				if (officers == null)
				{
					return null;
				}
				for (int i = 0; i < officers.Count; i++)
				{
					try
					{
						PoliceOfficer val = officers[i];
						if (!TargetInvalid(val))
						{
							float num2 = Vector3.Distance(((Component)val).transform.position, pos);
							if (num2 < num)
							{
								num = num2;
								result = val;
							}
						}
					}
					catch
					{
					}
				}
			}
			catch
			{
			}
			return result;
		}

		private static bool TryNearestDoor(Vector3 from, float maxDistance, out Vector3 doorPos)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: 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_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			doorPos = from;
			try
			{
				StaticDoor[] array = Object.FindObjectsOfType<StaticDoor>();
				if (array == null || array.Length == 0)
				{
					return false;
				}
				float num = maxDistance * maxDistance;
				bool result = false;
				for (int i = 0; i < array.Length; i++)
				{
					StaticDoor val;
					try
					{
						val = array[i];
					}
					catch
					{
						continue;
					}
					if (!((Object)(object)val == (Object)null))
					{
						Vector3 val2;
						try
						{
							Transform accessPoint = val.AccessPoint;
							val2 = (((Object)(object)accessPoint != (Object)null) ? accessPoint.position : ((Component)val).transform.position);
						}
						catch
						{
							continue;
						}
						Vector3 val3 = val2 - from;
						float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude;
						if (sqrMagnitude < num)
						{
							num = sqrMagnitude;
							doorPos = val2;
							result = true;
						}
					}
				}
				return result;
			}
			catch
			{
				return false;
			}
		}

		private static Vector3 RandomRingDir()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: 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)
			//IL_0032: 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)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			Vector2 insideUnitCircle = Random.insideUnitCircle;
			Vector2 val = ((Vector2)(ref insideUnitCircle)).normalized;
			if (((Vector2)(ref val)).sqrMagnitude < 0.01f)
			{
				val = Vector2.right;
			}
			return new Vector3(val.x, 0f, val.y);
		}

		private static Vector3 NavPoint(Vector3 p)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				NavMeshHit val = default(NavMeshHit);
				if (NavMesh.SamplePosition(p + Vector3.up * 1.5f, ref val, 12f, -1))
				{
					return ((NavMeshHit)(ref val)).position;
				}
			}
			catch
			{
			}
			return p;
		}
	}
	public class RiotMod : MelonMod
	{
		private RiotAddon _addon;

		public override void OnInitializeMelon()
		{
			_addon = new RiotAddon();
			if (PvpApi.RegisterAddon((IPvpAddon)(object)_addon))
			{
				MelonLogger.Msg("[Riot] registered with MultiplayerPVP.");
			}
			else
			{
				MelonLogger.Warning("[Riot] registration failed — is MultiplayerPVP loaded?");
			}
		}

		public override void OnDeinitializeMelon()
		{
			try
			{
				PvpApi.UnregisterAddon((IPvpAddon)(object)_addon);
			}
			catch
			{
			}
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}