Decompiled source of AdminHelper v1.3.1

BepInEx/plugins/AdminHelper/AdminHelper.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using HoldfastGame;
using Microsoft.CodeAnalysis;
using RyLib;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
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: AssemblyFileVersion("1.3.1.0")]
[assembly: AssemblyVersion("1.3.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 AdminHelper
{
	[BepInPlugin("com.ryannlt.adminhelper", "AdminHelper", "1.3.1")]
	[BepInDependency("com.ryannlt.rylib", "1.1.1")]
	public class AdminHelperMod : BaseUnityPlugin
	{
		private struct Remembered
		{
			public Color Color;

			public float Time;
		}

		public const string Guid = "com.ryannlt.adminhelper";

		private const float RememberSeconds = 3f;

		private static readonly IsolationTracker Tracker = new IsolationTracker();

		private static readonly Dictionary<int, Remembered> Recent = new Dictionary<int, Remembered>();

		private static readonly List<int> Stale = new List<int>();

		private readonly FlagTracker _flags = new FlagTracker();

		private readonly Hotkey _hotkey = new Hotkey();

		private WorldLayer _world;

		private MinimapLayer _map;

		private Driver _driver;

		private float _accumulator;

		private bool _wasInRound;

		internal static bool OverlayVisible => Settings.RamboUi.Value switch
		{
			RamboUiMode.On => true, 
			RamboUiMode.FreeflightOnly => GameAccess.InFreeflight, 
			_ => false, 
		};

		private void Awake()
		{
			//IL_0097: 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)
			Settings.Create(((BaseUnityPlugin)this).Config);
			_world = new WorldLayer(Tracker, _flags);
			_world.Register();
			_map = new MinimapLayer(_flags);
			_map.Register();
			HelperTab.Register(new MapOverlay(Tracker, _flags));
			RowActions.Register();
			SceneManager.sceneLoaded += OnSceneLoaded;
			EnsureDriver();
			PatchPMenu();
			Log.Info("Ready. Toggle key " + ((object)Settings.ToggleKeyCode/*cast due to .constrained prefix*/).ToString() + ", overlay " + Settings.RamboUi.Value.ToString() + ", RequireAdminLogin=" + Settings.RequireAdminLogin.Value);
		}

		private void OnDestroy()
		{
			Log.Info("plugin component destroyed");
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			Log.Info("scene loaded " + ((Scene)(ref scene)).name + " driverAlive=" + ((Object)(object)_driver != (Object)null));
			EnsureDriver();
			GameAccess.ClearSceneCache();
			MeleeTracker.Reset();
			RowActions.Reset();
			Tracker.Reset();
			_flags.Reset();
			_accumulator = 0f;
			_wasInRound = false;
		}

		private void EnsureDriver()
		{
			if (!((Object)(object)_driver != (Object)null))
			{
				_driver = Driver.Attach(this);
			}
		}

		private static void PatchPMenu()
		{
			try
			{
				Harmony.CreateAndPatchAll(typeof(AdminHelperMod).Assembly, "com.ryannlt.adminhelper");
			}
			catch (Exception ex)
			{
				Log.Error("P menu class filter could not be patched in: " + ex.Message);
			}
		}

		internal void Tick()
		{
			Settings.PollForExternalEdits();
			RowActions.Tick();
			if (!Settings.Enabled.Value)
			{
				_world.Visible = false;
				_map.Visible = false;
				return;
			}
			_hotkey.Poll();
			if (!GameAccess.InRound)
			{
				if (_wasInRound)
				{
					Tracker.Reset();
				}
				_wasInRound = false;
				_flags.Flags.Clear();
				_world.Visible = false;
				_map.Visible = false;
				return;
			}
			_wasInRound = true;
			MeleeTracker.Tick();
			KillLogTabs.Warm();
			_accumulator += Time.deltaTime;
			float num = 1f / Mathf.Clamp(Settings.TickHz.Value, 1f, 30f);
			if (_accumulator >= num)
			{
				Tracker.Tick(_accumulator);
				_accumulator = 0f;
				Remember();
			}
			if (CanReveal())
			{
				RamboSpectate.Poll(Tracker.Watched);
			}
			bool overlayVisible = OverlayVisible;
			bool flag = CanReveal() && overlayVisible && Settings.FlagHighlightEnabled.Value;
			bool flag2 = Settings.FlagHighlightEnabled.Value && Settings.FlagMinimapMarkers.Value;
			bool flag3 = CanReveal() && Settings.FlagHighlightEnabled.Value && Settings.MapEnabled.Value;
			if (flag || flag2 || flag3)
			{
				_flags.Tick();
			}
			else
			{
				_flags.Flags.Clear();
			}
			_world.Visible = CanReveal() && overlayVisible;
			_world.ShowFlags = flag;
			_map.Visible = flag2;
		}

		internal static bool TryStateColor(int playerId, out Color color)
		{
			//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_0036: 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_0093: 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)
			color = Color.clear;
			for (int i = 0; i < Tracker.Watched.Count; i++)
			{
				ScoredPlayer scored = Tracker.Watched[i];
				if (scored.PlayerId == playerId)
				{
					color = WorldLayer.StateColor(scored);
					return true;
				}
			}
			if (!Recent.TryGetValue(playerId, out var value) || Time.time - value.Time > 3f)
			{
				return false;
			}
			color = value.Color;
			return true;
		}

		private static void Remember()
		{
			//IL_0020: 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)
			float time = Time.time;
			Remembered value = default(Remembered);
			for (int i = 0; i < Tracker.Watched.Count; i++)
			{
				ScoredPlayer scored = Tracker.Watched[i];
				value.Color = WorldLayer.StateColor(scored);
				value.Time = time;
				Recent[scored.PlayerId] = value;
			}
			Stale.Clear();
			foreach (KeyValuePair<int, Remembered> item in Recent)
			{
				if (time - item.Value.Time > 3f)
				{
					Stale.Add(item.Key);
				}
			}
			for (int j = 0; j < Stale.Count; j++)
			{
				Recent.Remove(Stale[j]);
			}
		}

		internal static bool CanReveal()
		{
			return !Settings.RequireAdminLogin.Value || GameAccess.IsLoggedInAdmin;
		}
	}
	internal sealed class Driver : MonoBehaviour
	{
		internal AdminHelperMod Owner;

		internal static Driver Attach(AdminHelperMod owner)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			GameObject val = new GameObject("AdminHelper_Driver");
			Object.DontDestroyOnLoad((Object)(object)val);
			Driver driver = val.AddComponent<Driver>();
			driver.Owner = owner;
			return driver;
		}

		private void Awake()
		{
			Log.Info("driver awake");
		}

		private void OnDestroy()
		{
			Log.Info("driver destroyed");
		}

		private void Update()
		{
			if (Owner != null)
			{
				Owner.Tick();
			}
		}
	}
	internal sealed class Hotkey
	{
		private RamboUiMode _lastShown = RamboUiMode.On;

		public void Poll()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			RamboUiMode value = Settings.RamboUi.Value;
			if (value != RamboUiMode.Off)
			{
				_lastShown = value;
			}
			if (Input.GetKeyDown(Settings.ToggleKeyCode) && !GameAccess.IsTyping)
			{
				Settings.Write(Settings.RamboUi, (value == RamboUiMode.Off) ? _lastShown : RamboUiMode.Off);
			}
		}
	}
	internal static class Log
	{
		private static readonly ManualLogSource Source = Logger.CreateLogSource("AdminHelper");

		public static void Info(string message)
		{
			Source.LogInfo((object)message);
		}

		public static void Warn(string message)
		{
			Source.LogWarning((object)message);
		}

		public static void Error(string message)
		{
			Source.LogError((object)message);
		}
	}
	internal static class RamboSpectate
	{
		private static readonly List<ScoredPlayer> Candidates = new List<ScoredPlayer>();

		public static void Poll(List<ScoredPlayer> watched)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			bool keyDown = Input.GetKeyDown(Settings.SpectateNextKeyCode);
			bool keyDown2 = Input.GetKeyDown(Settings.SpectatePrevKeyCode);
			if (keyDown != keyDown2 && !GameAccess.IsTyping)
			{
				Candidates.Clear();
				Candidates.AddRange(watched);
				if (Candidates.Count != 0)
				{
					Candidates.Sort(Worst);
					int num = IndexOf(GameAccess.SpectatedPlayerId);
					int index = ((num >= 0) ? ((num + (keyDown ? 1 : (Candidates.Count - 1))) % Candidates.Count) : ((!keyDown) ? (Candidates.Count - 1) : 0));
					GameAccess.Spectate(Candidates[index].PlayerId);
				}
			}
		}

		private static int IndexOf(int playerId)
		{
			if (playerId < 0)
			{
				return -1;
			}
			for (int i = 0; i < Candidates.Count; i++)
			{
				if (Candidates[i].PlayerId == playerId)
				{
					return i;
				}
			}
			return -1;
		}

		private static int Worst(ScoredPlayer a, ScoredPlayer b)
		{
			int num = Tier(a).CompareTo(Tier(b));
			if (num != 0)
			{
				return num;
			}
			int num2 = b.Danger.CompareTo(a.Danger);
			if (num2 != 0)
			{
				return num2;
			}
			int num3 = b.Isolation.CompareTo(a.Isolation);
			if (num3 != 0)
			{
				return num3;
			}
			return a.PlayerId.CompareTo(b.PlayerId);
		}

		private static int Tier(ScoredPlayer player)
		{
			if (player.Flagged)
			{
				return 0;
			}
			if (player.CavCharge)
			{
				return 1;
			}
			return player.Afk ? 3 : 2;
		}
	}
	public enum RamboUiMode
	{
		On,
		FreeflightOnly,
		Off
	}
	internal static class Settings
	{
		private sealed class KeyBinding
		{
			private readonly ConfigEntry<string> _entry;

			private readonly KeyCode _fallback;

			private string _source;

			private KeyCode _key;

			public KeyCode Key
			{
				get
				{
					//IL_00ba: 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_00e6: Unknown result type (might be due to invalid IL or missing references)
					//IL_00eb: 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_0040: 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_002c: 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_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_007b: 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)
					string text = _entry.Value ?? string.Empty;
					if (text == _source)
					{
						return _key;
					}
					_source = text;
					_key = _fallback;
					string text2 = text.Trim();
					if (text2.Length == 0)
					{
						return _key;
					}
					try
					{
						_key = (KeyCode)Enum.Parse(typeof(KeyCode), text2, ignoreCase: true);
					}
					catch (Exception)
					{
						Log.Warn(((ConfigEntryBase)_entry).Definition.Key + " '" + text2 + "' is not a KeyCode name. Falling back to " + ((object)_fallback/*cast due to .constrained prefix*/).ToString() + ".");
					}
					return _key;
				}
			}

			public KeyBinding(ConfigEntry<string> entry, KeyCode fallback)
			{
				//IL_0010: 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)
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				_entry = entry;
				_fallback = fallback;
				_key = fallback;
			}
		}

		public static ConfigEntry<bool> Enabled;

		public static ConfigEntry<float> TickHz;

		public static ConfigEntry<bool> RequireAdminLogin;

		public static ConfigEntry<float> ClusterNearMeters;

		public static ConfigEntry<float> ClusterFarMeters;

		public static ConfigEntry<float> RiseSeconds;

		public static ConfigEntry<float> RecoverMultiplier;

		public static ConfigEntry<float> EnemyRadius;

		public static ConfigEntry<int> EnemyCrowd;

		public static ConfigEntry<float> FormationSuppression;

		public static ConfigEntry<float> LineRadius;

		public static ConfigEntry<int> LineMinMates;

		public static ConfigEntry<int> LineMaxMates;

		public static ConfigEntry<float> LineResidual;

		public static ConfigEntry<int> ClusterMinMates;

		public static ConfigEntry<float> ClusterFormationRadius;

		public static ConfigEntry<int> RingThreshold;

		public static ConfigEntry<int> RamboThreshold;

		public static ConfigEntry<float> RamboHoldSeconds;

		public static ConfigEntry<string> ExemptClasses;

		public static ConfigEntry<bool> ShowRings;

		public static ConfigEntry<bool> ShowLabels;

		public static ConfigEntry<bool> ShowGlow;

		public static ConfigEntry<int> MaxLabels;

		public static ConfigEntry<RamboUiMode> RamboUi;

		public static ConfigEntry<string> ToggleKey;

		public static ConfigEntry<bool> CompactLabels;

		public static ConfigEntry<string> SpectatePrevKey;

		public static ConfigEntry<string> SpectateNextKey;

		public static ConfigEntry<bool> ClassFilterEnabled;

		public static ConfigEntry<bool> RegimentSearchEnabled;

		public static ConfigEntry<bool> FactionSearchEnabled;

		public static ConfigEntry<bool> RowActionsEnabled;

		public static ConfigEntry<bool> ShowRulesTab;

		public static ConfigEntry<bool> MeleeGraceEnabled;

		public static ConfigEntry<bool> FlagHighlightEnabled;

		public static ConfigEntry<bool> FlagMinimapMarkers;

		public static ConfigEntry<bool> FlagMinimapAlways;

		public static ConfigEntry<bool> ShowFlagLabels;

		public static ConfigEntry<bool> AfkMarkEnabled;

		public static ConfigEntry<float> AfkSeconds;

		public static ConfigEntry<float> AfkMoveMeters;

		public static ConfigEntry<bool> MeleeMarkerEnabled;

		public static ConfigEntry<bool> TeamkillFilterEnabled;

		public static ConfigEntry<float> MeleeChainMeters;

		public static ConfigEntry<float> MeleeWindowSeconds;

		public static ConfigEntry<bool> ColorKey;

		public static ConfigEntry<bool> KillLogColorsWithoutUi;

		public static ConfigEntry<bool> CavalryRules;

		public static ConfigEntry<float> CompassRangeMeters;

		public static ConfigEntry<float> CavalryFarMultiplier;

		public static ConfigEntry<float> CavalryChainMeters;

		public static ConfigEntry<float> CavalryEngageMeters;

		public static ConfigEntry<bool> MultichargeCheck;

		public static ConfigEntry<int> MultichargeMinRiders;

		public static ConfigEntry<bool> MapEnabled;

		private static readonly HashSet<PlayerClass> ExemptSet = new HashSet<PlayerClass>();

		private static string _exemptSource;

		private static KeyBinding _toggleKey;

		private static KeyBinding _spectatePrevKey;

		private static KeyBinding _spectateNextKey;

		private static ConfigFile _config;

		private static DateTime _stamp;

		private static float _nextCheck;

		public static bool KillLogColors
		{
			get
			{
				if (!AdminHelperMod.CanReveal())
				{
					return false;
				}
				return RamboUi.Value != RamboUiMode.Off || (KillLogColorsWithoutUi != null && KillLogColorsWithoutUi.Value);
			}
		}

		public static KeyCode ToggleKeyCode => _toggleKey.Key;

		public static KeyCode SpectatePrevKeyCode => _spectatePrevKey.Key;

		public static KeyCode SpectateNextKeyCode => _spectateNextKey.Key;

		public static void Create(ConfigFile config)
		{
			_config = config;
			Enabled = config.Bind<bool>("General", "Enabled", true, "Master switch. Turning this off stops the scorer as well as the HUD.");
			TickHz = config.Bind<float>("General", "TickHz", 5f, "Scoring ticks per second. Higher costs more and buys nothing.");
			RequireAdminLogin = config.Bind<bool>("General", "RequireAdminLogin", true, "Only show other players once the server has authenticated an 'rc login'. Turning this off makes the mod a wallhack.");
			ClusterNearMeters = config.Bind<float>("Isolation", "ClusterNearMeters", 10f, "Distance from the midpoint of your two nearest mates at which isolation starts counting.");
			ClusterFarMeters = config.Bind<float>("Isolation", "ClusterFarMeters", 30f, "Distance at which isolation is fully saturated.");
			RiseSeconds = config.Bind<float>("Scoring", "RiseSeconds", 6f, "Time constant for the score climbing. Larger is slower to flag.");
			RecoverMultiplier = config.Bind<float>("Scoring", "RecoverMultiplier", 3f, "How much faster the score falls than it climbs when a player rejoins.");
			EnemyRadius = config.Bind<float>("Danger", "EnemyRadius", 30f, "How close an enemy has to be before any isolation counts as danger.");
			EnemyCrowd = config.Bind<int>("Danger", "EnemyCrowd", 3, "Enemies inside the radius that count as being fully inside their formation.");
			FormationSuppression = config.Bind<float>("Formation", "FormationSuppression", 0.9f, "Fraction of the raw isolation signal removed while a player is in formation.");
			LineRadius = config.Bind<float>("Formation", "LineRadius", 10f, "Radius searched for formation mates.");
			LineMinMates = config.Bind<int>("Formation", "LineMinMates", 2, "Mates needed before the line fit is attempted.");
			LineMaxMates = config.Bind<int>("Formation", "LineMaxMates", 6, "Most mates fed into the line fit.");
			LineResidual = config.Bind<float>("Formation", "LineResidual", 2f, "Meters of spread either side of the best-fit line still counted as a line.");
			ClusterMinMates = config.Bind<int>("Formation", "ClusterMinMates", 3, "Mates within ClusterFormationRadius that count as a square or skirmisher knot.");
			ClusterFormationRadius = config.Bind<float>("Formation", "ClusterFormationRadius", 8f, "Radius for the tight cluster test.");
			RingThreshold = config.Bind<int>("Flagging", "RingThreshold", 40, "Isolation score at which a marker appears. Tracks the live score, so it clears as a player returns.");
			RamboThreshold = config.Bind<int>("Flagging", "RamboThreshold", 75, "Isolation score at which the dwell timer starts running.");
			RamboHoldSeconds = config.Bind<float>("Flagging", "RamboHoldSeconds", 5f, "Seconds above the threshold before a player is flagged.");
			ExemptClasses = config.Bind<string>("Flagging", "ExemptClasses", "", "Comma-separated PlayerClass names that are never flagged, e.g. Surgeon,Sapper.");
			MeleeGraceEnabled = config.Bind<bool>("Flagging", "MeleeGrace", true, "Do not flag a player who was not already ramboing when their melee started, until the melee window has run out. Covers the last one or two left in a fight their mates started.");
			FlagHighlightEnabled = config.Bind<bool>("CTF", "FlagHighlightEnabled", false, "Track flags. Admins get a glow on every flag in its faction's color, and flags are drawn on the Map tab. ShowFlagLabels and FlagMinimapMarkers add labels and minimap markers.");
			FlagMinimapMarkers = config.Bind<bool>("CTF", "FlagMinimapMarkers", false, "Mark flags on the minimap by the game's own rules: blue on your side, red on the enemy's, and the enemy's only while their faction is revealed. A carried flag counts as the carrier's. Needs FlagHighlightEnabled.");
			ShowFlagLabels = config.Bind<bool>("CTF", "ShowFlagLabels", false, "Label each flag with its faction, or with who is carrying it. Separate from the player labels. Needs FlagHighlightEnabled.");
			FlagMinimapAlways = config.Bind<bool>("CTF", "FlagMinimapAlways", false, "Admins see every flag on the minimap whatever the reveal rules. Needs FlagMinimapMarkers and an rc login.");
			AfkMarkEnabled = config.Bind<bool>("AFK", "AfkMarkEnabled", true, "Gray out players who have not moved for a while, so a parked player is not read as someone worth watching.");
			AfkSeconds = config.Bind<float>("AFK", "AfkSeconds", 90f, "Seconds without moving before a player counts as AFK.");
			AfkMoveMeters = config.Bind<float>("AFK", "AfkMoveMeters", 0.75f, "Meters a player has to move to reset their AFK timer.");
			ShowRings = config.Bind<bool>("Display", "ShowRings", true, "Draw a ground ring under each watched player.");
			ShowLabels = config.Bind<bool>("Display", "ShowLabels", true, "Draw the floating name and score label over each watched player. Flag labels have their own switch, ShowFlagLabels.");
			ShowGlow = config.Bind<bool>("Display", "ShowGlow", true, "Glow around watched players and flags in their color, visible through walls and terrain.");
			MaxLabels = config.Bind<int>("Display", "MaxLabels", 12, "Most floating labels drawn at once, worst first.");
			RamboUi = config.Bind<RamboUiMode>("Display", "RamboUi", RamboUiMode.Off, "When the rambo overlay shows, like the game's Admin Raygun: On, FreeflightOnly or Off. ToggleKey and the P menu button both change it, and it is remembered between launches.");
			ToggleKey = config.Bind<string>("Display", "ToggleKey", "F6", "Key that hides the overlay and brings it back in the mode it was in. Any UnityEngine.KeyCode name.");
			CompactLabels = config.Bind<bool>("Display", "CompactLabels", false, "Labels show only the player's name, in their state color, with no state or scores.");
			SpectatePrevKey = config.Bind<string>("Spectate", "SpectatePrevKey", "LeftBracket", "Spectate the previous watched player. The list runs worst first: RAMBO, then CAV CHARGE, then ISOLATED and MELEE GRACE by danger, then AFK. Any UnityEngine.KeyCode name.");
			SpectateNextKey = config.Bind<string>("Spectate", "SpectateNextKey", "RightBracket", "Spectate the next watched player, worst first. Any UnityEngine.KeyCode name.");
			ClassFilterEnabled = config.Bind<bool>("PMenu", "ClassFilterEnabled", true, "Let the P menu player search box filter by class, e.g. 'rifleman', 'surgeon' or 'cavalry'.");
			RegimentSearchEnabled = config.Bind<bool>("PMenu", "RegimentSearchEnabled", true, "Also match regiment tags in that box, ignoring punctuation and accents, so [45e] is found by 45.");
			RowActionsEnabled = config.Bind<bool>("PMenu", "RowActionsEnabled", true, "Add 'Reg TP' and 'Rez + Reg TP' to a player's action buttons. They send the player to the middle of their regiment's players of the same class, or to the closest friendly player if there are none.");
			FactionSearchEnabled = config.Bind<bool>("PMenu", "FactionSearchEnabled", true, "Also match factions and sides there, e.g. 'french', 'allied', 'attackers' or 'defenders'. Combines with a class, e.g. 'french cav'.");
			ShowRulesTab = config.Bind<bool>("PMenu", "ShowRulesTab", false, "Show the game's Rules tab in the P menu.");
			MeleeMarkerEnabled = config.Bind<bool>("KillLog", "MeleeMarkerEnabled", true, "Mark kills in the admin kill log with crossed swords when the victim was in a melee.");
			TeamkillFilterEnabled = config.Bind<bool>("KillLog", "TeamkillFilterEnabled", true, "Add a teamkills only toggle to the kill log tab, and accept 'tk' in its search box.");
			MeleeChainMeters = config.Bind<float>("KillLog", "MeleeChainMeters", 10f, "How close a player must be to someone fighting to count as being in that melee themselves.");
			MeleeWindowSeconds = config.Bind<float>("KillLog", "MeleeWindowSeconds", 10f, "Seconds without a hit or a block anywhere in the melee before it is treated as over.");
			ColorKey = config.Bind<bool>("KillLog", "ColorKey", true, "Show a key under the kill log title that explains the name colors and icons.");
			KillLogColorsWithoutUi = config.Bind<bool>("KillLog", "KillLogColorsWithoutUi", false, "Color kill log names, and list the colors in the key, while Rambo UI is Off. With Rambo UI on they always show.");
			CavalryRules = config.Bind<bool>("Cavalry", "CavalryRules", true, "Score mounted players against the other mounted players on their side, at compass range. Off leaves mounted players unscored. A dismounted cavalryman is scored like any other class.");
			CompassRangeMeters = config.Bind<float>("Cavalry", "CompassRangeMeters", 0f, "Compass range in meters. 0 reads it from the game: the distance at which a friendly drops off the compass.");
			CavalryFarMultiplier = config.Bind<float>("Cavalry", "CavalryFarMultiplier", 2f, "A rider's isolation reaches full at compass range times this, measured to the nearest mounted teammate.");
			CavalryChainMeters = config.Bind<float>("Cavalry", "CavalryChainMeters", 40f, "How close a mounted player must be to a mounted player in a melee to count as in it too.");
			CavalryEngageMeters = config.Bind<float>("Cavalry", "CavalryEngageMeters", 30f, "A mounted player in a melee stays in it while any enemy is this close.");
			MultichargeCheck = config.Bind<bool>("Cavalry", "MultichargeCheck", true, "Mark a mounted player's kill in the kill log when fewer than MultichargeMinRiders riders were chained together at compass range.");
			MultichargeMinRiders = config.Bind<int>("Cavalry", "MultichargeMinRiders", 3, "Riders, the killer included, that must be chained together at compass range for a mounted kill to be valid.");
			MapEnabled = config.Bind<bool>("Map", "MapEnabled", true, "Add a Minimap tab to the P menu: an overhead picture of the battle with every player drawn by class in their faction's color, and admin actions on them. Rambo outlines are drawn on it while the overlay is showing, and flags with FlagHighlightEnabled.");
			Migrate(config, "Isolation", "ClusterNearMetres", ClusterNearMeters);
			Migrate(config, "Isolation", "ClusterFarMetres", ClusterFarMeters);
			Migrate(config, "AFK", "AfkMoveMetres", AfkMoveMeters);
			Migrate(config, "KillLog", "MeleeChainMetres", MeleeChainMeters);
			Drop(config, "Flagging", "ScoreCavalry");
			config.Save();
			_toggleKey = new KeyBinding(ToggleKey, (KeyCode)287);
			_spectatePrevKey = new KeyBinding(SpectatePrevKey, (KeyCode)91);
			_spectateNextKey = new KeyBinding(SpectateNextKey, (KeyCode)93);
			_stamp = Stamp();
		}

		public static void ResetAll()
		{
			if (_config == null)
			{
				return;
			}
			bool saveOnConfigSet = _config.SaveOnConfigSet;
			_config.SaveOnConfigSet = false;
			try
			{
				foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item in _config)
				{
					Reset(item.Value);
				}
			}
			finally
			{
				_config.SaveOnConfigSet = saveOnConfigSet;
			}
			_config.Save();
			_stamp = Stamp();
			Reset((ConfigEntryBase)(object)GlowStyle.ScaleWithDistance);
			Reset((ConfigEntryBase)(object)GlowStyle.OutlineWidth);
			Reset((ConfigEntryBase)(object)GlowStyle.Brightness);
			Reset((ConfigEntryBase)(object)GlowStyle.Glow);
			Reset((ConfigEntryBase)(object)GlowStyle.GlowWidth);
			Reset((ConfigEntryBase)(object)MapStyle.IconSize);
			Log.Info("settings reset to their defaults.");
		}

		private static void Reset(ConfigEntryBase entry)
		{
			if (entry != null)
			{
				entry.BoxedValue = entry.DefaultValue;
			}
		}

		private static void Migrate(ConfigFile config, string section, string oldKey, ConfigEntry<float> target)
		{
			ConfigEntry<float> val = config.Bind<float>(section, oldKey, float.NaN, string.Empty);
			if (!float.IsNaN(val.Value))
			{
				target.Value = val.Value;
			}
			config.Remove(((ConfigEntryBase)val).Definition);
		}

		private static void Drop(ConfigFile config, string section, string oldKey)
		{
			ConfigEntry<bool> val = config.Bind<bool>(section, oldKey, false, string.Empty);
			config.Remove(((ConfigEntryBase)val).Definition);
		}

		public static void Write<T>(ConfigEntry<T> entry, T value)
		{
			entry.Value = value;
			_stamp = Stamp();
		}

		public static void PollForExternalEdits()
		{
			if (_config != null && !(Time.unscaledTime < _nextCheck))
			{
				_nextCheck = Time.unscaledTime + 1f;
				DateTime dateTime = Stamp();
				if (!(dateTime == _stamp))
				{
					_stamp = dateTime;
					_config.Reload();
				}
			}
		}

		private static DateTime Stamp()
		{
			try
			{
				return File.GetLastWriteTimeUtc(_config.ConfigFilePath);
			}
			catch (Exception)
			{
				return _stamp;
			}
		}

		public static bool IsExempt(PlayerClass playerClass)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			RefreshExemptSet();
			return ExemptSet.Contains(playerClass);
		}

		private static void RefreshExemptSet()
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			string text = ExemptClasses.Value ?? string.Empty;
			if (text == _exemptSource)
			{
				return;
			}
			_exemptSource = text;
			ExemptSet.Clear();
			string[] array = text.Split(',');
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim();
				if (text2.Length != 0)
				{
					try
					{
						ExemptSet.Add((PlayerClass)Enum.Parse(typeof(PlayerClass), text2, ignoreCase: true));
					}
					catch (Exception)
					{
						Log.Warn("Unknown PlayerClass in ExemptClasses: " + text2);
					}
				}
			}
		}
	}
	internal static class GameAccess
	{
		private const float FallbackCompassRange = 50f;

		private static GameConsolePanel _consolePanel;

		private static float _nextConsoleLookup;

		private static float _gameCompassRange = -1f;

		private static string _compassReport;

		public static ClientComponentReferenceManager Client => ClientComponentReferenceManager.ClientInstance;

		public static bool IsLoggedInAdmin => ClientRemoteConsoleAccessManager.loggedOn;

		public static bool InRound
		{
			get
			{
				ClientComponentReferenceManager client = Client;
				return (Object)(object)client != (Object)null && (Object)(object)client.clientRoundPlayerManager != (Object)null;
			}
		}

		public static Camera ActiveCamera
		{
			get
			{
				ClientComponentReferenceManager client = Client;
				if ((Object)(object)client == (Object)null || (Object)(object)client.ownerCameraManager == (Object)null)
				{
					return null;
				}
				Camera val = client.ownerCameraManager.ActiveCamera;
				if ((Object)(object)val == (Object)null)
				{
					val = client.ownerCameraManager.ownerCamera;
				}
				return val;
			}
		}

		public static bool InFreeflight
		{
			get
			{
				ClientComponentReferenceManager client = Client;
				return (Object)(object)client != (Object)null && (Object)(object)client.clientFreeflightCameraManager != (Object)null && client.clientFreeflightCameraManager.currentlyUsingFreeflightCamera;
			}
		}

		public static int SpectatedPlayerId
		{
			get
			{
				ClientComponentReferenceManager client = Client;
				if ((Object)(object)client == (Object)null || (Object)(object)client.clientSpectatorManager == (Object)null)
				{
					return -1;
				}
				return ((RoundPlayer)(client.clientSpectatorManager.currentlySpectatingPlayer?)).NetworkPlayerID ?? (-1);
			}
		}

		public static FactionCountry AttackingFaction => RoundFaction(attacking: true);

		public static FactionCountry DefendingFaction => RoundFaction(attacking: false);

		public static int LocalPlayerId
		{
			get
			{
				ClientComponentReferenceManager client = Client;
				if ((Object)(object)client == (Object)null || (Object)(object)client.clientRoundPlayerManager == (Object)null)
				{
					return -1;
				}
				return ((RoundPlayer)(client.clientRoundPlayerManager.LocalPlayer?)).NetworkPlayerID ?? (-1);
			}
		}

		public static bool IsTyping
		{
			get
			{
				ClientComponentReferenceManager client = Client;
				if ((Object)(object)client != (Object)null && (Object)(object)client.clientChatHandler != (Object)null && client.clientChatHandler.isChatPaneOpened)
				{
					return true;
				}
				if (FieldFocused())
				{
					return true;
				}
				if ((Object)(object)_consolePanel == (Object)null && Time.unscaledTime >= _nextConsoleLookup)
				{
					_nextConsoleLookup = Time.unscaledTime + 2f;
					_consolePanel = Object.FindObjectOfType<GameConsolePanel>();
				}
				return (Object)(object)_consolePanel != (Object)null && _consolePanel.Showing;
			}
		}

		public static InteractableObjectCollection Interactables
		{
			get
			{
				ClientComponentReferenceManager client = Client;
				if ((Object)(object)client == (Object)null || (Object)(object)client.clientEnvironmentInteractableObjectManager == (Object)null)
				{
					return null;
				}
				return ((EnvironmentInteractableObjectManager)client.clientEnvironmentInteractableObjectManager).AllObjects;
			}
		}

		public static void Spectate(int playerId)
		{
			ClientComponentReferenceManager client = Client;
			if (!((Object)(object)client == (Object)null) && !((Object)(object)client.clientSpectatorManager == (Object)null))
			{
				client.clientSpectatorManager.SpectateStartRequest(playerId);
			}
		}

		private static FactionCountry RoundFaction(bool attacking)
		{
			//IL_0024: 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_0055: 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_0045: 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)
			ClientComponentReferenceManager client = Client;
			if ((Object)(object)client == (Object)null || (Object)(object)client.clientGameModeManager == (Object)null)
			{
				return (FactionCountry)0;
			}
			RoundGameDetails currentRoundGameDetails = ((GameModeManager)client.clientGameModeManager).CurrentRoundGameDetails;
			if (currentRoundGameDetails == null)
			{
				return (FactionCountry)0;
			}
			return attacking ? currentRoundGameDetails.AttackingFaction : currentRoundGameDetails.DefendingFaction;
		}

		private static bool FieldFocused()
		{
			EventSystem current = EventSystem.current;
			if ((Object)(object)current == (Object)null)
			{
				return false;
			}
			GameObject currentSelectedGameObject = current.currentSelectedGameObject;
			if ((Object)(object)currentSelectedGameObject == (Object)null)
			{
				return false;
			}
			TMP_InputField component = currentSelectedGameObject.GetComponent<TMP_InputField>();
			if ((Object)(object)component != (Object)null && component.isFocused)
			{
				return true;
			}
			InputField component2 = currentSelectedGameObject.GetComponent<InputField>();
			return (Object)(object)component2 != (Object)null && component2.isFocused;
		}

		public static void ClearSceneCache()
		{
			_consolePanel = null;
			_nextConsoleLookup = 0f;
			_gameCompassRange = -1f;
			_compassReport = null;
		}

		public static float CompassRange()
		{
			float num = ((Settings.CompassRangeMeters == null) ? 0f : Settings.CompassRangeMeters.Value);
			if (num > 0f)
			{
				ReportCompass(num, "from config");
				return num;
			}
			float num2 = GameCompassRange();
			if (num2 > 0f)
			{
				ReportCompass(num2, "from the game");
				return num2;
			}
			ReportCompass(50f, "fallback, the game's compass range could not be read");
			return 50f;
		}

		public static float GameCompassRange()
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			if (_gameCompassRange > 0f)
			{
				return _gameCompassRange;
			}
			ClientComponentReferenceManager client = Client;
			if ((Object)(object)client == (Object)null || (Object)(object)client.uiMinimapPanelTracking == (Object)null || (Object)(object)client.clientGameManager == (Object)null)
			{
				return -1f;
			}
			RoundGameDetails currentRoundGameDetails = client.clientGameManager.CurrentRoundGameDetails;
			if (currentRoundGameDetails == null)
			{
				return -1f;
			}
			MiniMapPanelTrackingPointerProperties val = client.uiMinimapPanelTracking.ResolveTrackingPointerProperties(currentRoundGameDetails.GameType);
			if ((Object)(object)val == (Object)null || !val.hideAllysOnDistance || val.hideAllysDistance <= 0f)
			{
				return -1f;
			}
			_gameCompassRange = val.hideAllysDistance;
			return _gameCompassRange;
		}

		private static void ReportCompass(float range, string source)
		{
			string text = range.ToString("0") + " m (" + source + ")";
			if (!(text == _compassReport))
			{
				_compassReport = text;
				Log.Info("compass range " + text);
			}
		}

		public static bool IsMounted(RoundPlayer player)
		{
			if (player == null || (Object)(object)player.PlayerBase == (Object)null)
			{
				return false;
			}
			PlayerVehicleRider playerVehicleRider = player.PlayerBase.playerVehicleRider;
			return (Object)(object)playerVehicleRider != (Object)null && playerVehicleRider.IsRidingOrAnimatingWithMountable;
		}

		public static void CollectPlayers(List<PlayerSnapshot> into)
		{
			into.Clear();
			ClientComponentReferenceManager client = Client;
			if ((Object)(object)client == (Object)null)
			{
				return;
			}
			ClientRoundPlayerManager clientRoundPlayerManager = client.clientRoundPlayerManager;
			if ((Object)(object)clientRoundPlayerManager == (Object)null)
			{
				return;
			}
			List<ClientRoundPlayerProxy> roundPlayersList = clientRoundPlayerManager.roundPlayersList;
			for (int i = 0; i < roundPlayersList.Count; i++)
			{
				if (TrySnapshot((RoundPlayer)(object)roundPlayersList[i], out var snapshot))
				{
					into.Add(snapshot);
				}
			}
			if (TrySnapshot((RoundPlayer)(object)clientRoundPlayerManager.LocalPlayer, out var snapshot2))
			{
				into.Add(snapshot2);
			}
		}

		private static bool TrySnapshot(RoundPlayer player, out PlayerSnapshot snapshot)
		{
			//IL_0081: 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_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_00a3: 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)
			snapshot = default(PlayerSnapshot);
			if (player == null || (Object)(object)player.PlayerBase == (Object)null || !player.PlayerBase.SpawnedAndAlive)
			{
				return false;
			}
			if (player.PlayerTransformData == null || player.PlayerStartData == null)
			{
				return false;
			}
			PlayerBase playerBase = player.PlayerBase;
			snapshot.Player = player;
			snapshot.PlayerId = player.NetworkPlayerID;
			snapshot.Name = ResolveName(player);
			snapshot.Position = player.PlayerTransformData.position;
			snapshot.Faction = player.PlayerStartData.Faction;
			snapshot.Class = player.PlayerStartData.ClassType;
			snapshot.IsCavalry = playerBase.IsCavalry;
			snapshot.Mounted = (Object)(object)playerBase.playerVehicleRider != (Object)null && playerBase.playerVehicleRider.IsRidingOrAnimatingWithMountable;
			snapshot.IsArtillery = playerBase.IsArty;
			snapshot.IsBot = player.PlayerRoundInformation != null && player.PlayerRoundInformation.IsCarbonPlayer;
			return true;
		}

		private static string ResolveName(RoundPlayer player)
		{
			RoundPlayerInformation playerRoundInformation = player.PlayerRoundInformation;
			if (playerRoundInformation == null || playerRoundInformation.InitialDetails == null)
			{
				return "Player " + player.NetworkPlayerID;
			}
			PlayerInitialDetails initialDetails = playerRoundInformation.InitialDetails;
			string text = (string.IsNullOrEmpty(initialDetails.DisplayName) ? initialDetails.Name : initialDetails.DisplayName);
			if (string.IsNullOrEmpty(text))
			{
				return "Player " + player.NetworkPlayerID;
			}
			return text;
		}

		public static RoundPlayer ResolvePlayer(int playerId)
		{
			if (playerId < 0)
			{
				return null;
			}
			ClientComponentReferenceManager client = Client;
			if ((Object)(object)client == (Object)null || (Object)(object)client.clientRoundPlayerManager == (Object)null)
			{
				return null;
			}
			return client.clientRoundPlayerManager.ResolveRoundPlayer(playerId);
		}

		public static bool AreEnemies(int firstId, int secondId)
		{
			if (firstId == secondId)
			{
				return false;
			}
			RoundPlayer val = ResolvePlayer(firstId);
			RoundPlayer val2 = ResolvePlayer(secondId);
			if (val == null || val2 == null)
			{
				return true;
			}
			return AreEnemies(val, val2);
		}

		public static bool AreEnemies(RoundPlayer first, RoundPlayer second)
		{
			//IL_0035: 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)
			if (first == null || second == null)
			{
				return true;
			}
			if (first.PlayerStartData == null || second.PlayerStartData == null)
			{
				return true;
			}
			return first.PlayerStartData.Faction != second.PlayerStartData.Faction;
		}

		public static bool IsCarryingFlag(int playerId, out CarryableObjectType flag)
		{
			//IL_0058: 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_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected I4, but got Unknown
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected I4, but got Unknown
			flag = (CarryableObjectType)0;
			if (playerId < 0)
			{
				return false;
			}
			ClientComponentReferenceManager client = Client;
			if ((Object)(object)client == (Object)null || (Object)(object)client.clientCarryableObjectManager == (Object)null)
			{
				return false;
			}
			CarryableObjectType val = default(CarryableObjectType);
			CarryableObjectType val2 = default(CarryableObjectType);
			if (!((CarryableObjectManager)client.clientCarryableObjectManager).ResolvePlayerCarryableObjects(playerId, ref val, ref val2))
			{
				return false;
			}
			if (FlagTypes.IsFlag(val))
			{
				flag = (CarryableObjectType)(int)val;
				return true;
			}
			if (FlagTypes.IsFlag(val2))
			{
				flag = (CarryableObjectType)(int)val2;
				return true;
			}
			return false;
		}

		public static bool IsInsideOfficerLine(RoundPlayer player)
		{
			ClientComponentReferenceManager client = Client;
			if ((Object)(object)client == (Object)null || (Object)(object)client.clientHighCommandOrderManager == (Object)null)
			{
				return false;
			}
			return ((HighCommandOrderManager)client.clientHighCommandOrderManager).IsPlayerInsideAnyOfficerLine(player);
		}
	}
	internal struct PlayerSnapshot
	{
		public RoundPlayer Player;

		public int PlayerId;

		public string Name;

		public Vector3 Position;

		public FactionCountry Faction;

		public PlayerClass Class;

		public bool IsCavalry;

		public bool Mounted;

		public bool IsArtillery;

		public bool IsBot;
	}
	internal struct ScoredPlayer
	{
		public int PlayerId;

		public GameObject Body;

		public string Name;

		public Vector3 Position;

		public int Isolation;

		public int Danger;

		public float DwellSeconds;

		public bool Flagged;

		public float MateDistance;

		public float EnemyDistance;

		public int EnemyCount;

		public bool InFormation;

		public bool Afk;

		public float AfkSeconds;

		public bool InHonestMelee;

		public bool Mounted;

		public bool CavCharge;
	}
	internal static class TextSearch
	{
		private static readonly StringBuilder Builder = new StringBuilder(48);

		public static string Normalize(string text)
		{
			if (string.IsNullOrEmpty(text))
			{
				return string.Empty;
			}
			string text2 = Decompose(text);
			Builder.Length = 0;
			foreach (char c in text2)
			{
				if (CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark)
				{
					string text3 = Fold(c);
					if (text3 != null)
					{
						Builder.Append(text3);
					}
					else if (char.IsLetterOrDigit(c))
					{
						Builder.Append(char.ToLowerInvariant(c));
					}
				}
			}
			return Builder.ToString();
		}

		public static bool Contains(string haystack, string normalizedNeedle)
		{
			if (string.IsNullOrEmpty(haystack) || string.IsNullOrEmpty(normalizedNeedle))
			{
				return false;
			}
			return Normalize(haystack).IndexOf(normalizedNeedle, StringComparison.Ordinal) >= 0;
		}

		private static string Fold(char character)
		{
			switch (character)
			{
			case 'ß':
			case 'ẞ':
				return "ss";
			case 'Æ':
			case 'æ':
				return "ae";
			case 'Œ':
			case 'œ':
				return "oe";
			case 'Ø':
			case 'ø':
				return "o";
			case 'Ł':
			case 'ł':
				return "l";
			case 'Ð':
			case 'ð':
			case 'Đ':
			case 'đ':
				return "d";
			case 'Þ':
			case 'þ':
				return "th";
			case 'ı':
				return "i";
			default:
				return null;
			}
		}

		private static string Decompose(string text)
		{
			try
			{
				return text.Normalize(NormalizationForm.FormD);
			}
			catch (Exception)
			{
				return text;
			}
		}
	}
	internal sealed class MapOverlay
	{
		private static readonly List<ScoredPlayer> NoPlayers = new List<ScoredPlayer>();

		private readonly IsolationTracker _tracker;

		private readonly FlagTracker _flags;

		public MapOverlay(IsolationTracker tracker, FlagTracker flags)
		{
			_tracker = tracker;
			_flags = flags;
		}

		public void Register(HeaderTab header)
		{
			Page val = header.MapPage("com.ryannlt.adminhelper", "Minimap", "hui-p-tab-maps", (Func<bool>)Shown);
			if (val != null)
			{
				val.MapLayer("com.ryannlt.adminhelper", (Action<List<MapMark>>)Fill);
			}
		}

		private static bool Shown()
		{
			return Settings.MapEnabled.Value;
		}

		private void Fill(List<MapMark> marks)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: 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_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: 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_019f: 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_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			if (!AdminHelperMod.CanReveal())
			{
				return;
			}
			List<ScoredPlayer> list = (AdminHelperMod.OverlayVisible ? _tracker.Watched : NoPlayers);
			for (int i = 0; i < list.Count; i++)
			{
				ScoredPlayer scored = list[i];
				marks.Add(new MapMark
				{
					Key = "player-" + scored.PlayerId,
					OnPlayer = true,
					PlayerId = scored.PlayerId,
					Shape = (MapShape)3,
					Color = WorldLayer.StateColor(scored),
					Tooltip = WorldLayer.State(scored) + "\nISO " + scored.Isolation + "  DGR " + scored.Danger
				});
			}
			if (!Settings.FlagHighlightEnabled.Value)
			{
				return;
			}
			List<FlagMark> flags = _flags.Flags;
			for (int j = 0; j < flags.Count; j++)
			{
				FlagMark flagMark = flags[j];
				if (!((Object)(object)flagMark.Follow == (Object)null))
				{
					marks.Add(new MapMark
					{
						Key = (flagMark.Carried ? "carried-" : "flag-") + flagMark.Key,
						PlayerId = -1,
						Position = flagMark.Follow.transform.position,
						Shape = (MapShape)1,
						Color = WorldLayer.FactionColor(flagMark.Type),
						Tooltip = (flagMark.Carried ? ("FLAG: " + flagMark.Name) : (flagMark.Name + " FLAG"))
					});
				}
			}
		}
	}
	internal sealed class MinimapLayer
	{
		private const float LayerHz = 4f;

		private readonly FlagTracker _flags;

		public bool Visible;

		public MinimapLayer(FlagTracker flags)
		{
			_flags = flags;
		}

		public void Register()
		{
			Minimap.Layer("com.ryannlt.adminhelper", (Action<List<MinimapMark>>)Fill, 4f);
		}

		private void Fill(List<MinimapMark> marks)
		{
			//IL_005f: 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_00b1: 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)
			//IL_00bf: 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_00c9: 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)
			if (!Visible)
			{
				return;
			}
			bool alwaysShow = Settings.FlagMinimapAlways.Value && AdminHelperMod.CanReveal();
			List<FlagMark> flags = _flags.Flags;
			for (int i = 0; i < flags.Count; i++)
			{
				FlagMark flagMark = flags[i];
				if (!((Object)(object)flagMark.Follow == (Object)null))
				{
					marks.Add(new MinimapMark
					{
						Key = (flagMark.Carried ? "carried-" : "flag-") + flagMark.Key,
						Follow = flagMark.Follow.transform,
						Shape = (MapShape)1,
						Faction = flagMark.Side,
						Color = WorldLayer.FactionColor(flagMark.Type),
						AlwaysShow = alwaysShow
					});
				}
			}
		}
	}
	internal sealed class WorldLayer
	{
		private const float LayerHz = 10f;

		private const float PlayerRing = 1.6f;

		private const float HorseRing = 2.6f;

		private const float PlayerLabelHeight = 2.1f;

		private const float FlagLabelHeight = 2.6f;

		internal static readonly Color CalmColor = new Color(0.35f, 0.9f, 0.3f);

		internal static readonly Color IsolatedColor = new Color(1f, 0.85f, 0.15f);

		internal static readonly Color DangerColor = new Color(1f, 0.55f, 0.1f);

		internal static readonly Color DeadlyColor = new Color(1f, 0.15f, 0.12f);

		internal static readonly Color AfkColor = new Color(0.6f, 0.62f, 0.65f);

		internal static readonly Color MeleeColor = new Color(0.55f, 0.85f, 1f);

		internal static readonly Color CavChargeColor = new Color(0.78f, 0.6f, 1f);

		private static readonly Color FlagColor = new Color(0.3f, 0.95f, 1f);

		private readonly IsolationTracker _tracker;

		private readonly FlagTracker _flags;

		public bool Visible;

		public bool ShowFlags;

		public WorldLayer(IsolationTracker tracker, FlagTracker flags)
		{
			_tracker = tracker;
			_flags = flags;
		}

		public void Register()
		{
			World.Layer("com.ryannlt.adminhelper", (Action<List<WorldMark>>)Fill, 10f);
		}

		private void Fill(List<WorldMark> marks)
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: 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_00e7: 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_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: 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_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: 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)
			//IL_0297: Unknown result type (might be due to invalid IL or missing references)
			if (!Visible)
			{
				return;
			}
			bool value = Settings.ShowRings.Value;
			bool value2 = Settings.ShowLabels.Value;
			bool value3 = Settings.ShowFlagLabels.Value;
			bool value4 = Settings.ShowGlow.Value;
			List<FlagMark> flags = _flags.Flags;
			int num = 0;
			while (ShowFlags && num < flags.Count)
			{
				FlagMark flagMark = flags[num];
				marks.Add(new WorldMark
				{
					Key = (flagMark.Carried ? "carried-" : "flag-") + flagMark.Key,
					Follow = (((Object)(object)flagMark.Follow == (Object)null) ? null : flagMark.Follow.transform),
					Position = flagMark.Position,
					Glow = (value4 ? flagMark.Glow : null),
					Color = FactionColor(flagMark.Type),
					Label = (value3 ? (flagMark.Carried ? ("FLAG: " + flagMark.Name) : (flagMark.Name + " FLAG")) : null),
					LabelHeight = 2.6f
				});
				num++;
			}
			int localPlayerId = GameAccess.LocalPlayerId;
			int num2 = 0;
			int num3 = Mathf.Max(0, Settings.MaxLabels.Value);
			List<ScoredPlayer> watched = _tracker.Watched;
			for (int i = 0; i < watched.Count; i++)
			{
				ScoredPlayer scored = watched[i];
				if (scored.PlayerId != localPlayerId)
				{
					bool flag = value2 && num2 < num3;
					if (flag)
					{
						num2++;
					}
					marks.Add(new WorldMark
					{
						Key = "player-" + scored.PlayerId,
						Follow = (((Object)(object)scored.Body == (Object)null) ? null : scored.Body.transform),
						Position = scored.Position,
						Glow = (value4 ? scored.Body : null),
						Color = StateColor(scored),
						Label = (flag ? Describe(scored) : null),
						LabelHeight = 2.1f,
						RingRadius = ((!value) ? 0f : (scored.Mounted ? 2.6f : 1.6f))
					});
				}
			}
		}

		private static string Describe(ScoredPlayer scored)
		{
			if (Settings.CompactLabels.Value)
			{
				return scored.Name;
			}
			return scored.Name + "\n" + State(scored) + "\nISO: " + scored.Isolation + "  DGR: " + scored.Danger;
		}

		internal static string State(ScoredPlayer scored)
		{
			if (scored.CavCharge)
			{
				return "CAV CHARGE";
			}
			if (scored.Afk)
			{
				return "AFK " + Mathf.FloorToInt(scored.AfkSeconds) + "s";
			}
			if (scored.Flagged)
			{
				return "RAMBO: " + Mathf.FloorToInt(scored.DwellSeconds) + "s";
			}
			return scored.InHonestMelee ? "MELEE GRACE" : "ISOLATED";
		}

		internal static Color FactionColor(CarryableObjectType type)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//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_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Invalid comparison between Unknown and I4
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Invalid comparison between Unknown and I4
			//IL_0022: 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_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: 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)
			FactionCountry val = FlagTypes.Faction(type);
			if ((int)val == 0 || (int)val == 6 || (int)val == 7)
			{
				return FlagColor;
			}
			return Factions.Color(val);
		}

		internal static Color StateColor(ScoredPlayer scored)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: 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_009f: 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_0039: 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_0091: 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_009c: 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)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			if (scored.CavCharge)
			{
				return CavChargeColor;
			}
			if (scored.Afk)
			{
				return AfkColor;
			}
			if (scored.InHonestMelee)
			{
				return MeleeColor;
			}
			if (scored.Danger > 0)
			{
				return Color.Lerp(DangerColor, DeadlyColor, Mathf.Clamp01((float)scored.Danger / 100f));
			}
			float num = Mathf.InverseLerp((float)Settings.RingThreshold.Value, 100f, (float)scored.Isolation);
			return Color.Lerp(CalmColor, IsolatedColor, num);
		}
	}
	internal static class ClassFilter
	{
		private enum Match
		{
			Exact,
			Prefix,
			Contains
		}

		private static readonly Dictionary<string, PlayerClass> Aliases = new Dictionary<string, PlayerClass>(StringComparer.OrdinalIgnoreCase)
		{
			{
				"line",
				(PlayerClass)1
			},
			{
				"linf",
				(PlayerClass)1
			},
			{
				"lineinfantry",
				(PlayerClass)1
			},
			{
				"officer",
				(PlayerClass)6
			},
			{
				"off",
				(PlayerClass)6
			},
			{
				"sarge",
				(PlayerClass)20
			},
			{
				"sgt",
				(PlayerClass)20
			},
			{
				"light",
				(PlayerClass)11
			},
			{
				"medic",
				(PlayerClass)9
			},
			{
				"doc",
				(PlayerClass)9
			},
			{
				"engineer",
				(PlayerClass)23
			},
			{
				"flag",
				(PlayerClass)12
			},
			{
				"bearer",
				(PlayerClass)12
			},
			{
				"drummer",
				(PlayerClass)19
			},
			{
				"fifer",
				(PlayerClass)19
			},
			{
				"piper",
				(PlayerClass)19
			},
			{
				"marine",
				(PlayerClass)2
			},
			{
				"captain",
				(PlayerClass)3
			},
			{
				"gren",
				(PlayerClass)18
			},
			{
				"cannon",
				(PlayerClass)21
			},
			{
				"gunner",
				(PlayerClass)21
			},
			{
				"sap",
				(PlayerClass)23
			},
			{
				"rank",
				(PlayerClass)1
			},
			{
				"file",
				(PlayerClass)1
			},
			{
				"rankandfile",
				(PlayerClass)1
			},
			{
				"ranker",
				(PlayerClass)1
			},
			{
				"rnf",
				(PlayerClass)1
			},
			{
				"private",
				(PlayerClass)1
			},
			{
				"doctor",
				(PlayerClass)9
			},
			{
				"colour",
				(PlayerClass)12
			},
			{
				"color",
				(PlayerClass)12
			},
			{
				"standard",
				(PlayerClass)12
			},
			{
				"band",
				(PlayerClass)19
			},
			{
				"music",
				(PlayerClass)19
			},
			{
				"drum",
				(PlayerClass)19
			},
			{
				"guardsman",
				(PlayerClass)16
			}
		};

		private static readonly Dictionary<string, PlayerClass[]> Groups;

		private static readonly PlayerClass[] AllClasses;

		private static readonly string[] AllNames;

		private static readonly List<PlayerClass> Found;

		public static List<PlayerClass> Resolve(string text)
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			Found.Clear();
			string text2 = ((text == null) ? string.Empty : text.Trim());
			if (text2.Length < 3)
			{
				return Found;
			}
			if (Groups.TryGetValue(text2, out var value))
			{
				Found.AddRange(value);
				return Found;
			}
			if (Aliases.TryGetValue(text2, out var value2))
			{
				Found.Add(value2);
				return Found;
			}
			AddByName(text2, Match.Exact);
			if (Found.Count == 0)
			{
				AddByName(text2, Match.Prefix);
			}
			if (Found.Count == 0)
			{
				AddByName(text2, Match.Contains);
			}
			return Found;
		}

		private static void AddByName(string token, Match mode)
		{
			for (int i = 0; i < AllClasses.Length; i++)
			{
				if (AllClasses[i])
				{
					string text = AllNames[i];
					if (mode switch
					{
						Match.Exact => string.Equals(text, token, StringComparison.OrdinalIgnoreCase), 
						Match.Prefix => text.StartsWith(token, StringComparison.OrdinalIgnoreCase), 
						_ => text.IndexOf(token, StringComparison.OrdinalIgnoreCase) >= 0, 
					})
					{
						Found.Add(AllClasses[i]);
					}
				}
			}
		}

		private static string[] BuildNames()
		{
			string[] array = new string[AllClasses.Length];
			for (int i = 0; i < AllClasses.Length; i++)
			{
				array[i] = ((object)Unsafe.As<PlayerClass, PlayerClass>(ref AllClasses[i])/*cast due to .constrained prefix*/).ToString();
			}
			return array;
		}

		static ClassFilter()
		{
			Dictionary<string, PlayerClass[]> dictionary = new Dictionary<string, PlayerClass[]>(StringComparer.OrdinalIgnoreCase)
			{
				{
					"cav",
					(PlayerClass[])(object)new PlayerClass[2]
					{
						(PlayerClass)24,
						(PlayerClass)25
					}
				},
				{
					"cavalry",
					(PlayerClass[])(object)new PlayerClass[2]
					{
						(PlayerClass)24,
						(PlayerClass)25
					}
				},
				{
					"horse",
					(PlayerClass[])(object)new PlayerClass[2]
					{
						(PlayerClass)24,
						(PlayerClass)25
					}
				},
				{
					"skirm",
					(PlayerClass[])(object)new PlayerClass[2]
					{
						(PlayerClass)10,
						(PlayerClass)11
					}
				},
				{
					"skirmish",
					(PlayerClass[])(object)new PlayerClass[2]
					{
						(PlayerClass)10,
						(PlayerClass)11
					}
				},
				{
					"skirmisher",
					(PlayerClass[])(object)new PlayerClass[2]
					{
						(PlayerClass)10,
						(PlayerClass)11
					}
				}
			};
			PlayerClass[] array = new PlayerClass[5];
			RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
			dictionary.Add("inf", (PlayerClass[])(object)array);
			PlayerClass[] array2 = new PlayerClass[5];
			RuntimeHelpers.InitializeArray(array2, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
			dictionary.Add("foot", (PlayerClass[])(object)array2);
			PlayerClass[] array3 = new PlayerClass[5];
			RuntimeHelpers.InitializeArray(array3, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
			dictionary.Add("infantry", (PlayerClass[])(object)array3);
			PlayerClass[] array4 = new PlayerClass[5];
			RuntimeHelpers.InitializeArray(array4, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
			dictionary.Add("support", (PlayerClass[])(object)array4);
			dictionary.Add("arty", (PlayerClass[])(object)new PlayerClass[2]
			{
				(PlayerClass)21,
				(PlayerClass)22
			});
			dictionary.Add("artillery", (PlayerClass[])(object)new PlayerClass[2]
			{
				(PlayerClass)21,
				(PlayerClass)22
			});
			dictionary.Add("sailor", (PlayerClass[])(object)new PlayerClass[2]
			{
				(PlayerClass)4,
				(PlayerClass)5
			});
			PlayerClass[] array5 = new PlayerClass[3];
			RuntimeHelpers.InitializeArray(array5, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
			dictionary.Add("officers", (PlayerClass[])(object)array5);
			PlayerClass[] array6 = new PlayerClass[4];
			RuntimeHelpers.InitializeArray(array6, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
			dictionary.Add("naval", (PlayerClass[])(object)array6);
			PlayerClass[] array7 = new PlayerClass[4];
			RuntimeHelpers.InitializeArray(array7, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
			dictionary.Add("navy", (PlayerClass[])(object)array7);
			Groups = dictionary;
			AllClasses = (PlayerClass[])Enum.GetValues(typeof(PlayerClass));
			AllNames = BuildNames();
			Found = new List<PlayerClass>();
		}
	}
	[HarmonyPatch(typeof(UIRoundPlayersControlPanel), "UpdateFilteredLists")]
	internal static class UpdateFilteredListsPatch
	{
		private static bool Prefix(UIRoundPlayersControlPanel __instance, RoundPlayersRefreshNeeded refreshPriority, RoundPlayerInfoFilter ___playersInfoFilter, List<ClientRoundPlayer> ___roundPlayers, List<ClientRoundPlayer> ___roundPlayersListFiltered, ref RoundPlayersRefreshNeeded ___rowPlayerRefreshNeeded)
		{
			//IL_009c: 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_0215: Invalid comparison between Unknown and I4
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Invalid comparison between Unknown and I4
			if (___playersInfoFilter == null)
			{
				return true;
			}
			RoundPlayersQuery roundPlayerQuery = ___playersInfoFilter.RoundPlayerQuery;
			if (roundPlayerQuery == null)
			{
				return true;
			}
			string text = SearchText(__instance);
			SearchTerms searchTerms = PlayerSearch.Resolve(text, Enabled(Settings.ClassFilterEnabled), Enabled(Settings.FactionSearchEnabled));
			if (searchTerms.Resolved && searchTerms.Factions.Count == 0 && searchTerms.Classes.Count == 1)
			{
				roundPlayerQuery.PlayerName = null;
				roundPlayerQuery.PlayerID = null;
				roundPlayerQuery.PlayerClass = searchTerms.Classes[0];
				return true;
			}
			string text2 = (Enabled(Settings.RegimentSearchEnabled) ? TextSearch.Normalize(text) : string.Empty);
			bool flag = text2.Length >= 2;
			if (!searchTerms.Resolved && !flag)
			{
				roundPlayerQuery.PlayerClass = null;
				return true;
			}
			roundPlayerQuery.PlayerClass = null;
			if (searchTerms.Resolved)
			{
				roundPlayerQuery.PlayerName = null;
				roundPlayerQuery.PlayerID = null;
			}
			___roundPlayersListFiltered.Clear();
			for (int i = 0; i < ___roundPlayers.Count; i++)
			{
				ClientRoundPlayer val = ___roundPlayers[i];
				if (val == null || (Object)(object)((RoundPlayer)val).PlayerBase == (Object)null)
				{
					continue;
				}
				if (searchTerms.Resolved)
				{
					if (searchTerms.Matches(((RoundPlayer)val).PlayerStartData))
					{
						___roundPlayersListFiltered.Add(val);
					}
				}
				else if (((RoundPlayer)val).MatchesQuery(roundPlayerQuery) || TagMatches(val, text2))
				{
					___roundPlayersListFiltered.Add(val);
				}
			}
			if ((Object)(object)__instance.playerCountText != (Object)null)
			{
				__instance.playerCountText.text = ___roundPlayersListFiltered.Count.ToString();
			}
			if ((int)refreshPriority == 2)
			{
				___rowPlayerRefreshNeeded = (RoundPlayersRefreshNeeded)2;
			}
			else if ((int)___rowPlayerRefreshNeeded == 0 && (int)refreshPriority == 1)
			{
				___rowPlayerRefreshNeeded = (RoundPlayersRefreshNeeded)1;
			}
			return false;
		}

		private static bool TagMatches(ClientRoundPlayer player, string tag)
		{
			if (tag.Length == 0)
			{
				return false;
			}
			RoundPlayerInformation playerRoundInformation = ((RoundPlayer)player).PlayerRoundInformation;
			if (playerRoundInformation == null || playerRoundInformation.InitialDetails == null)
			{
				return false;
			}
			PlayerInitialDetails initialDetails = playerRoundInformation.InitialDetails;
			return TextSearch.Contains(initialDetails.RegimentTag, tag) || TextSearch.Contains(initialDetails.DisplayName, tag);
		}

		private static bool Enabled(ConfigEntry<bool> entry)
		{
			return entry?.Value ?? false;
		}

		private static string SearchText(UIRoundPlayersControlPanel panel)
		{
			if ((Object)(object)panel == (Object)null || (Object)(object)panel.searchFilterInputField == (Object)null)
			{
				return null;
			}
			return panel.searchFilterInputField.text;
		}
	}
	internal static class HelperTab
	{
		private const string TabName = "AdminHelper";

		private const string MinimapHeaderName = "Minimap";

		public static void Register(MapOverlay map)
		{
			PlayersBar.Cycle<RamboUiMode>("com.ryannlt.adminhelper", "Rambo UI", Settings.RamboUi, (Func<RamboUiMode, string>)RamboText, (Func<RamboUiMode, bool>)Showing, "hui-p-tab-players");
			KeyHints.Add("com.ryannlt.adminhelper", "Spectate Rambos", (Func<KeyCode[]>)SpectateKeys, (Func<bool>)HintVisible);
			KillLog.EnableActions("com.ryannlt.adminhelper", (Func<bool>)null);
			PMenu.StockTabVisible("com.ryannlt.adminhelper", (StockTab)0, (Func<bool>)RulesVisible);
			HeaderTab val = PMenu.Header("com.ryannlt.adminhelper", "Minimap", "hui-p-tab-maps");
			if (val != null)
			{
				map.Register(val);
			}
			ModTab val2 = PMenu.ModTab("com.ryannlt.adminhelper", "AdminHelper", "Shield", true, (Func<bool>)null);
			if (val2 != null)
			{
				val2.Section("com.ryannlt.adminhelper", "Rambo UI", (Action<Section>)BuildRamboUi);
				val2.Section("com.ryannlt.adminhelper", "Detection", (Action<Section>)BuildDetection);
				val2.Section("com.ryannlt.adminhelper", "Danger", (Action<Section>)BuildDanger);
				val2.Section("com.ryannlt.adminhelper", "Formation", (Action<Section>)BuildFormation);
				val2.Section("com.ryannlt.adminhelper", "Melee", (Action<Section>)BuildMelee);
				val2.Section("com.ryannlt.adminhelper", "Cavalry", (Action<Section>)BuildCavalry);
				val2.Section("com.ryannlt.adminhelper", "AFK", (Action<Section>)BuildAfk);
				val2.Section("com.ryannlt.adminhelper", "Flags", (Action<Section>)BuildFlags);
				val2.Section("com.ryannlt.adminhelper", "Players Tab", (Action<Section>)BuildPlayers);
				val2.Section("com.ryannlt.adminhelper", "Kill Log", (Action<Section>)BuildKillLog);
				val2.Section("com.ryannlt.adminhelper", "Minimap", (Action<Section>)BuildMinimap);
				val2.Section("com.ryannlt.adminhelper", "Spectate", (Action<Section>)BuildSpectate);
				val2.Section("com.ryannlt.adminhelper", "Glow", (Action<Section>)BuildGlow);
				val2.Section("com.ryannlt.adminhelper", "General", (Action<Section>)BuildGeneral);
			}
		}

		private static string RamboText(RamboUiMode mode)
		{
			return mode switch
			{
				RamboUiMode.On => "Rambo UI Always On", 
				RamboUiMode.FreeflightOnly => "Rambo UI Freeflight", 
				_ => "Rambo UI Off", 
			};
		}

		private static string ModeText(RamboUiMode mode)
		{
			return mode switch
			{
				RamboUiMode.On => "Always On", 
				RamboUiMode.FreeflightOnly => "Freeflight", 
				_ => "Off", 
			};
		}

		private static bool Showing(RamboUiMode mode)
		{
			return mode != RamboUiMode.Off;
		}

		private static bool HintVisible()
		{
			return Showing(Settings.RamboUi.Value) && AdminHelperMod.CanReveal();
		}

		private static bool RulesVisible()
		{
			return Settings.ShowRulesTab.Value;
		}

		private static KeyCode[] SpectateKeys()
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Expected I4, but got Unknown
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected I4, but got Unknown
			return (KeyCode[])(object)new KeyCode[2]
			{
				(KeyCode)(int)Settings.SpectatePrevKeyCode,
				(KeyCode)(int)Settings.SpectateNextKeyCode
			};
		}

		private static void BuildRamboUi(Section section)
		{
			section.Toggle("Compact labels", Settings.CompactLabels, "hui-p-tab-players");
			section.Toggle("Labels", Settings.ShowLabels, "hui-p-tab-players");
			section.Toggle("Rings", Settings.ShowRings, "hui-p-players-regiment");
			section.Toggle("Glow", Settings.ShowGlow, "hui-p-tab-players");
			section.Dropdown<RamboUiMode>("Rambo UI", Settings.RamboUi, (Func<RamboUiMode, string>)ModeText);
			section.Slider("Most labels", Settings.MaxLabels, 0, 32);
			section.TextField("Toggle key", Settings.ToggleKey);
		}

		private static void BuildDetection(Section section)
		{
			section.Slider("Marked at isolation", Settings.RingThreshold, 0, 100);
			section.Slider("Rambo at isolation", Settings.RamboThreshold, 0, 100);
			section.Slider("Rambo hold seconds", Settings.RamboHoldSeconds, 0f, 30f, 0.5f, "0.0");
			section.Slider("Isolation starts (m)", Settings.ClusterNearMeters, 0f, 50f, 1f, "0");
			section.Slider("Isolation full (m)", Settings.ClusterFarMeters, 5f, 100f, 1f, "0");
			section.Slider("Rise seconds", Settings.RiseSeconds, 0.5f, 30f, 0.5f, "0.0");
			section.Slider("Recover multiplier", Settings.RecoverMultiplier, 1f, 10f, 0.5f, "0.0");
			section.TextField("Exempt classes", Settings.ExemptClasses);
		}

		private static void BuildDanger(Section section)
		{
			section.Slider("Enemy radius (m)", Settings.EnemyRadius, 5f, 100f, 1f, "0");
			section.Slider("Enemy crowd", Settings.EnemyCrowd, 1, 10);
		}

		private static void BuildFormation(Section section)
		{
			section.Slider("Suppression", Settings.FormationSuppression, 0f, 1f, 0.05f, "0.00");
			section.Slider("Line radius (m)", Settings.LineRadius, 2f, 30f, 1f, "0");
			section.Slider("Line min mates", Settings.LineMinMates, 1, 10);
			section.Slider("Line max mates", Settings.LineMaxMates, 2, 12);
			section.Slider("Line spread (m)", Settings.LineResidual, 0.5f, 10f, 0.5f, "0.0");
			section.Slider("Cluster mates", Settings.ClusterMinMates, 1, 10);
			section.Slider("Cluster radius (m)", Settings.ClusterFormationRadius, 2f, 30f, 1f, "0");
		}

		private static void BuildMelee(Section section)
		{
			section.Toggle("Melee grace", Settings.MeleeGraceEnabled, "hui-p-slay");
			section.Slider("Chain distance (m)", Settings.MeleeChainMeters, 0f, 30f, 1f, "0");
			section.Slider("Melee window seconds", Settings.MeleeWindowSeconds, 1f, 60f, 1f, "0");
		}

		private static void BuildCavalry(Section section)
		{
			section.Toggle("Cavalry rules", Settings.CavalryRules, "hui-p-tab-players");
			section.Toggle("Multicharge check", Settings.MultichargeCheck, "hui-p-slay");
			section.Slider("Compass range (0 = game)", Settings.CompassRangeMeters, 0f, 300f, 5f, "0");
			section.Slider("Isolation full (x range)", Settings.CavalryFarMultiplier, 1f, 5f, 0.25f, "0.00");
			section.Slider("Charge chain (m)", Settings.CavalryChainMeters, 5f, 150f, 5f, "0");
			section.Slider("Engaged within (m)", Settings.CavalryEngageMeters, 5f, 100f, 5f, "0");
			section.Slider("Multicharge riders", Settings.MultichargeMinRiders, 1, 10);
		}

		private static void BuildAfk(Section section)
		{
			section.Toggle("AFK marks", Settings.AfkMarkEnabled, "hui-p-players-unspawned");
			section.Slider("AFK after seconds", Settings.AfkSeconds, 10f, 600f, 10f, "0");
			section.Slider("AFK move (m)", Settings.AfkMoveMeters, 0.1f, 5f, 0.05f, "0.00");
		}

		private static void BuildFlags(Section section)
		{
			section.Toggle("Flag highlight", Settings.FlagHighlightEnabled, "hui-p-tab-maps");
			section.Toggle("Flag labels", Settings.ShowFlagLabels, "hui-p-tab-maps");
			section.Toggle("Flag minimap", Settings.FlagMinimapMarkers, "hui-p-tab-maps");
			section.Toggle("All flags (admin)", Settings.FlagMinimapAlways, "hui-p-tab-maps");
		}

		private static void BuildPlayers(Section section)
		{
			section.Toggle("Class search", Settings.ClassFilterEnabled, "hui-p-tab-players");
			section.Toggle("Regiment search", Settings.RegimentSearchEnabled, "hui-p-players-regiment");
			section.Toggle("Faction search", Settings.FactionSearchEnabled, "Shield");
			section.Toggle("Row buttons", Settings.RowActionsEnabled, "hui-p-tab-admin");
			section.Toggle("Rules tab", Settings.ShowRulesTab, "hui-p-tab-rules");
		}

		private static void BuildKillLog(Section section)
		{
			section.Toggle("Kill log marks", Settings.MeleeMarkerEnabled, "hui-p-slay");
			section.Toggle("Teamkill filter", Settings.TeamkillFilterEnabled, "hui-p-slay");
			section.Toggle("Color key", Settings.ColorKey, "hui-p-slay");
			section.Toggle("Colors without Rambo UI", Settings.KillLogColorsWithoutUi, "hui-p-slay");
		}

		private static void BuildMinimap(Section section)
		{
			section.Toggle("Minimap tab", Settings.MapEnabled, "hui-p-tab-maps");
			section.Slider("Icon size", MapStyle.IconSize, 10f, 40f, 1f, "0");
		}

		private static void BuildSpectate(Section section)
		{
			section.TextField("Previous key", Settings.SpectatePrevKey);
			section.TextField("Next key", Settings.SpectateNextKey);
		}

		private static void BuildGlow(Section section)
		{
			section.Toggle("Scale with distance", GlowStyle.ScaleWithDistance, "hui-p-tab-players");
			section.Slider("Outline", GlowStyle.OutlineWidth, 0f, 3f, 0.1f, "0.0");
			section.Slider("Brightness", GlowStyle.Brightness, 0.5f, 6f, 0.1f, "0.0");
			section.Slider("Halo", GlowStyle.Glow, 0f, 3f, 0.1f, "0.0");
			section.Slider("Halo width", GlowStyle.GlowWidth, 0f, 1f, 0.01f, "0.00");
		}

		private static void BuildGeneral(Section section)
		{
			section.Toggle("Enabled", Settings.Enabled, "Shield");
			section.ConfirmButton("Reset to defaults", (Action)Settings.ResetAll, "hui-p-tab-admin");
			section.Slider("Scoring per second", Settings.TickHz, 1f, 30f, 1f, "0");
		}
	}
	internal sealed class KillMark
	{
		public MeleeTracker.State Melee;

		public bool Teamkill;

		public bool Multicharge;

		public string KillerColor = string.Empty;

		public string VictimColor = string.Empty;
	}
	internal static class KillLogMarks
	{
		public const string InMeleeText = "IN MELEE";

		public const string MeleeIcon = "hui-trait-sword-specialisation";

		public const string MeleeIconSize = "125%";

		public const string MultichargeIcon = "hui-trait-mounted-sword-specialist";

		public const string MultichargeText = "OUT OF SPACING";

		public const string MultichargeHex = "E03C31";

		private static readonly List<PlayerSnapshot> Riders = new List<PlayerSnapshot>();

		private static readonly List<PlayerSnapshot> Chain = new List<PlayerSnapshot>();

		private static readonly Dictionary<KillLogInfo, KillMark> Marks = new Dictionary<KillLogInfo, KillMark>();

		public static bool TeamkillOnly;

		public static KillMark For(KillLogInfo info)
		{
			if (info == null)
			{
				return null;
			}
			KillMark value;
			return Marks.TryGetValue(info, out value) ? value : null;
		}

		public static void Record(KillLogInfo info, KillMark mark)
		{
			if (info != null && mark != null)
			{
				Marks[info] = mark;
			}
		}

		public static void Clear()
		{
			Marks.Clear();
			TeamkillOnly = false;
		}

		public static bool MultichargeBroken(ClientRoundPlayer killer, ClientRoundPlayer victim, bool killerIsVictim)
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: 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_00ad: 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_00c6: 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)
			if (Settings.CavalryRules == null || !Settings.CavalryRules.Value || !Settings.MultichargeCheck.Value)
			{
				return false;
			}
			if (killerIsVictim || killer == null || victim == null)
			{
				return false;
			}
			if (((RoundPlayer)killer).PlayerStartData == null || ((RoundPlayer)victim).PlayerStartData == null)
			{
				return false;
			}
			if (((RoundPlayer)killer).PlayerStartData.Faction == ((RoundPlayer)victim).PlayerStartData.Faction)
			{
				return false;
			}
			if (!GameAccess.IsMounted((RoundPlayer)(object)killer))
			{
				return false;
			}
			Vector3 origin = ((((RoundPlayer)killer).PlayerTransformData == null) ? Vector3.zero : ((RoundPlayer)killer).PlayerTransformData.position);
			int num = ChainSize(((RoundPlayer)killer).NetworkPlayerID, ((RoundPlayer)killer).PlayerStartData.Faction, origin, GameAccess.CompassRange());
			return num < Mathf.Max(1, Settings.MultichargeMinRiders.Value);
		}

		private static int ChainSize(int killerId, FactionCountry faction, Vector3 origin, float range)
		{
			//IL_0087: 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_0042: 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_00af: 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_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: 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)
			GameAccess.CollectPlayers(Riders);
			Chain.Clear();
			for (int num = Riders.Count - 1; num >= 0; num--)
			{
				PlayerSnapshot playerSnapshot = Riders[num];
				if (playerSnapshot.PlayerId == killerId || playerSnapshot.Faction != faction || !playerSnapshot.Mounted)
				{
					Riders.RemoveAt(num);
				}
			}
			float num2 = range * range;
			int num3 = 1;
			int num4 = 0;
			Vector3 val = origin;
			while (true)
			{
				for (int num5 = Riders.Count - 1; num5 >= 0; num5--)
				{
					float num6 = Riders[num5].Position.x - val.x;
					float num7 = Riders[num5].Position.z - val.z;
					if (!(num6 * num6 + num7 * num7 > num2))
					{
						Chain.Add(Riders[num5]);
						Riders.RemoveAt(num5);
						num3++;
					}
				}
				if (num4 >= Chain.Count)
				{
					break;
				}
				val = Chain[num4++].Position;
			}
			Riders.Clear();
			Chain.Clear();
			return num3;
		}

		public static bool IsTeamkill(ClientRoundPlayer killer, ClientRoundPlayer victim, bool killerIsVictim)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			if (killerIsVictim || killer == null || victim == null)
			{
				return false;
			}
			if (((RoundPlayer)killer).NetworkPlayerID == ((RoundPlayer)victim).NetworkPlayerID)
			{
				return false;
			}
			if (((RoundPlayer)killer).PlayerStartData == null || ((RoundPlayer)victim).PlayerStartData == null)
			{
				return false;
			}
			return ((RoundPlayer)killer).PlayerStartData.Faction == ((RoundPlayer)victim).PlayerStartData.Faction;
		}
	}
	[HarmonyPatch(typeof(UIAdminPlayerKillLogPanel), "AddKillLog")]
	internal static class AddKillLogPatch
	{
		private static void Postfix(ClientRoundPlayer killer, ClientRoundPlayer victim, bool killerIsVictim, List<KillLogInfo> ___queuedKillLogInfo)
		{
			if (___queuedKillLogInfo != null && ___queuedKillLogInfo.Count != 0)
			{
				KillLogInfo val = ___queuedKillLogInfo[0];
				if (val != null)
				{
					KillMark killMark = new KillMark();
					killMark.Teamkill = KillLogMarks.IsTeamkill(killer, victim, killerIsVictim);
					killMark.Melee = ((Marked() && victim != null) ? MeleeTracker.Query(((RoundPlayer)victim).NetworkPlayerID) : MeleeTracker.State.Unknown);
					killMark.Multicharge = KillLogMarks.MultichargeBroken(killer, victim, killerIsVictim);
					killMark.KillerColor = HexOf(killer);
					killMark.VictimColor = HexOf(victim);
					KillLogMarks.Record(val, killMark);
					Stamp(val, killMark);
				}
			}
		}

		private static string HexOf(ClientRoundPlayer player)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			if (player == null || !AdminHelperMod.TryStateColor(((RoundPlayer)player).NetworkPlayerID, out var color))
			{
				return string.Empty;
			}
			return ColorUtility.ToHtmlStringRGB(color);
		}

		private static void Stamp(KillLogInfo info, KillMark mark)
		{
			if (mark.Melee == MeleeTracker.State.InMelee)
			{
				string text = TextIcons.Tag("hui-trait-sword-specialisation");
				Append(info, (text == null) ? "IN MELEE" : Large(text));
			}
			if (mark.Multicharge)
			{
				string text2 = TextIcons.Tag("hui-trait-mounted-sword-specialist");
				string text3 = ((text2 == null) ? "OUT OF SPACING" : Large(text2));
				Append(info, "<color=#E03C31>" + text3 + "</color>");
			}
		}

		private static string Large(string icon)
		{
			return "</size><size=125%>" + icon + "</size><size=75%>";
		}

		private static void Append(KillLogInfo info, string text)
		{
			info.KillRange = (string.IsNullOrEmpty(info.KillRange) ? text : (info.KillRange + "  " + text));
		}

		private static bool Marked()
		{
			return Settings.MeleeMarkerEnabled != null && Settings.MeleeMarkerEnabled.Value;
		}
	}
	[HarmonyPatch(typeof(UIAdminPlayerKillLogPanelRow), "Setup")]
	internal static class KillLogRowColorPatch
	{
		private static void Postfix(UIAdminPlayerKillLogPanelRow __instance, KillLogInfo killLogInfo)
		{
			if (killLogInfo != null && !((Object)(object)__instance.scoreLogUiEntry == (Object)null) && Settings.KillLogColors)
			{
				KillMark killMark = KillLogMarks.For(killLogInfo);
				if (killMark != null && (killMark.KillerColor.Length != 0 || killMark.VictimColor.Length != 0))
				{
					__instance.scoreLogUiEntry.BuildScoreLogEntry(killLogInfo.KillerIcon, Paint(killLogInfo.KillerName, killMark.KillerColor), string.Empty, killLogInfo.KillMethod, killLogInfo.VictimIcon, Paint(killLogInfo.VictimName, killMark.VictimColor), string.Empty, killLogInfo.KillRange, false, killLogInfo.KillerIsVictim);
				}
			}
		}

		private static string Paint(string name, string hex)
		{
			if (string.IsNullOrEmpty(name) || hex.Length == 0)
			{
				return name;
			}
			return "<color=#" + hex + ">" + name + "</color>";
		}
	}
	[HarmonyPatch(typeof(PlayerDamageManager), "ProcessPlayerHealthChanged")]
	internal static class MeleeHitPatch
	{
		private static void Postfix(RoundPlayer hitPlayer, PlayerHealthChangedEventArgs args)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Invalid comparison between Unknown and I4
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Invalid comparison between Unknown and I4
			if (hitPlayer == null || args == null)
			{
				return;
			}
			PlayerHealthChangedReason changeReason = ((EntityHealthChangedEventArgs<PlayerHealthChangedPacket>)(object)args).ChangeReason;
			if ((int)changeReason != 2 && (int)changeReason != 13)
			{
				return;
			}
			HitByMeleeWeaponPlayerHealthChangedData val = MeleeData(args);
			if (val == null)
			{
				MeleeTracker.Touch(hitPlayer.NetworkPlayerID);
				return;
			}
			RoundPlayer first = GameAccess.ResolvePlayer(val.AttackingPlayerID);
			if (GameAccess.AreEnemies(first, hitPlayer))
			{
				MeleeTracker.Touch(hitPlayer.NetworkPlayerID);
				MeleeTracker.Touch(val.AttackingPlayerID);
			}
		}

		private static HitByMeleeWeaponPlayerHealthChangedData MeleeData(PlayerHealthChangedEventArgs args)
		{
			if (((EntityHealthChangedEventArgs<PlayerHealthChangedPacket>)(object)args).Packet == null)
			{
				return null;
			}
			PlayerHealthChangedData healthChangedData = ((EntityHealthChangedEventArgs<PlayerHealthChangedPacket>)(object)args).Packet.HealthChangedData;
			return (HitByMeleeWeaponPlayerHealthChangedData)(object)((healthChangedData is HitByMeleeWeaponPlayerHealthChangedData) ? healthChangedData : null);
		}
	}
	[HarmonyPatch(typeof(PlayerDamageManager), "MeleeAttackBlockedRPC")]
	internal static class MeleeBlockedPatch
	{
		private static void Postfix(PlayerMeleeBlockedData data)
		{
			//IL_0001: 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_001b: 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)
			if (GameAccess.AreEnemies(data.AttackingPlayerID, data.BlockingPlayerID))
			{
				MeleeTracker.Touch(data.AttackingPlayerID);
				MeleeTracker.Touch(data.BlockingPlayerID);
			}
		}
	}
	[HarmonyPatch(typeof(UIAdminPlayerKillLogPanel), "UpdateFilteredPlayers")]
	internal static class KillLogFilterPatch
	{
		private static bool Prefix(string searchText, UIAdminPlayerKillLogPanelRow[] ___allRows, int ___currentActiveRows)
		{
			if (___allRows == null)
			{
				return true;
			}
			string text = ((searchText == null) ? string.Empty : searchText.Trim());
			bool flag = text.Equals("tk", StringComparison.OrdinalIgnoreCase) || text.Equals("teamkill", StringComparison.OrdinalIgnoreCase) || text.Equals("teamkills", StringComparison.OrdinalIgnoreCase);
			if (!Enabled() || !(KillLogMarks.TeamkillOnly || flag))
			{
				return true;
			}
			string text2 = (flag ? string.Empty : text);
			for (int i = 0; i < ___currentActiveRows && i < ___allRows.Length; i++)
			{
				UIAdminPlayerKillLogPanelRow val = ___allRows[i];
				if (!((Object)(object)val == (Object)null))
				{
					KillLogInfo currentInfo = val.CurrentInfo;
					KillMark killMark = KillLogMarks.For(currentInfo);
					bool active = killMark != null && killMark.Teamkill && (text2.Length == 0 || NameMatches(currentInfo, text2));
					((Component)val).gameObject.SetActive(active);
				}
			}
			return false;
		}

		private static bool NameMatches(KillLogInfo info, string search)
		{
			if (info == null)
			{
				return false;
			}
			return dfStringExtensions.Contains(info.KillerName, search, true) || dfStringExtensions.Contains(info.VictimName, search, true);
		}

		private static bool Enabled()
		{
			return Settings.TeamkillFilterEnabled != null && Settings.TeamkillFilterEnabled.Value;
		}
	}
	[HarmonyPatch(typeof(UIAdminPlayerKillLogPanel), "_ToggleShowing")]
	internal static class KillLogToggleShowingPatch
	{
		private static void Postfix(UIAdminPlayerKillLogPanel __instance, bool show)
		{
			if (!show)
			{
				KillLogTabs.Hide();
				return;
			}
			KillLogTabs.Show(__instance);
			KillLogTip.Show(__instance);
		}
	}
	[HarmonyPatch(typeof(UIAdminPlayerKillLogPanel), "_ResetObject")]
	internal static class KillLogResetPatch
	{
		private static void Postfix()
		{
			KillLogMarks.Clear();
			MeleeTracker.Reset();
			KillLogTabs.Forget();
		}
	}
	internal static class KillLogTabs
	{
		private const string ObjectName = "AdminHelper_TeamkillToggle";

		private const string TeamkillTitle = "TEAM KILL LOG";

		private static UIAdminPlayerKillLogPanel _panel;

		private static float _side;

		private static GameObject _toggleObject;

		private static Toggle _toggle;

		private static TMP_Text _title;

		private static string _titleText;

		private static bool _failed;

		private static bool _suppress;

		public static void Attach(UIAdminPlayerKillLogPanel panel)
		{
			if (_failed || (Object)(object)_toggleObject != (Object)null || Settings.TeamkillFilterEnabled == null || !Settings.TeamkillFilterEnabled.Value)
			{
				return;
			}
			try
			{
				Build(panel);
			}
			catch (Exception ex)
			{
				_failed = true;
				Log.Warn("Could not add the teamkill toggle, so type 'tk' in the search box instead. " + ex.Message);
			}
		}

		private static void Build(UIAdminPlayerKillLogPanel panel)
		{
			if ((Object)(object)panel == (Object)null || (Object)(object)panel.searchFilterInputField == (Object)null)
			{
				return;
			}
			Transform transform = ((Component)panel.searchFilterInputField).transform;
			RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			Transform transform2 = ((Component)panel).transform;
			if ((Object)(object)transform2 == (Object)null)
			{
				return;
			}
			Sweep(transform2);
			PMenuChildTabButton val2 = FindSource();
			if ((Object)(object)val2 == (Object)null)
			{
				_failed = true;
				Log.Warn("No child tab button to copy, so the teamkill toggle was skipped. Type 'tk' instead.");
				return;
			}
			GameObject val3 = Object.Instantiate<GameObject>(((Component)val2).gameObject, transform2);
			((Object)val3).name = "AdminHelper_TeamkillToggle";
			val3.SetActive(false);
			PMenuChildTabButton component = val3.GetComponent<PMenuChildTabButton>();
			if ((Object)(object)component != (Object)null)
			{
				Object.Destroy((Object)(object)component);
			}
			StripLocalizers(val3);
			Toggle val4 = val3.GetComponent<Toggle>();
			if ((Object)(object)val4 == (Object)null)
			{
				val4 = val3.GetComponentInChildren<Toggle>(true);
			}
			if ((Object)(object)val4 == (Object)null)
			{
				Object.Destroy((Object)(object)val3);
				_failed = true;
				Log.Warn("The cloned tab carried no toggle, so the teamkill toggle was skipped.");
				return;
			}
			MuteInspectorListeners(val4);
			val4.group = null;
			((Selectable)val4).interactable = true;
			WhitenIcon(val3);
			BlankText(val3);
			_panel = panel;
			Transform transform3 = ((Component)val2).transform;
			_side = Side((RectTransform)(object)((transform3 is RectTransform) ? transform3 : null), val);
			Transform transform4 = val3.transform;
			Place((RectTransform)(object)((transform4 is RectTransform) ? transform4 : null), val, _side);
			Clickable(val3, val4);
			_suppress = true;
			val4.isOn = KillLogMarks.TeamkillOnly;
			_suppress = false;
			val3.SetActive(true);
			val3.transform.SetAsLastSibling();
			((UnityEvent<bool>)(object)val4.onValueChanged).AddListener((UnityAction<bool>)OnToggled);
			_toggleObject = val3;
			_toggle = val4;
			ClaimTitle(panel, val, val3.transform);
			SetTitle();
		}

		public static void Warm()
		{
			if (!((Object)(object)_toggleObject != (Object)null) && !_failed)
			{
				ClientComponentReferenceManager clientInstance = ClientComponentReferenceManager.ClientInstance;
				if (!((Object)(object)clientInstance == (Object)null) && !((Object)(object)clientInstance.uiAdminPlayerKillLogPanel == (Object)null))
				{
					Attach(clientInstance.uiAdminPlayerKillLogPanel);
				}
			}
		}

		public static void Show(UIAdminPlayerKillLogPanel panel)
		{
			Attach(panel);
			Reposition();
			Reapply(panel);
		}

		private static void Reposition()
		{
			if (!((Object)(object)_toggleObject == (Object)null) && !((Object)(object)_panel == (Object)null) && !((Object)(object)_panel.searchFilterInputField == (Object)null))
			{
				Transform transform = _toggleObject.transform;
				Transform rect = ((transform is RectTransform) ? transform : null);
				Transform transform2 = ((Component)_panel.searchFilterInputField).transform;
				Place((RectTransform)(object)rect, (RectTransform)(object)((transform2 is RectTransform) ? transform2 : null), _side);
			}
		}

		private static void Sweep(Transform parent)
		{
			Transform val = parent.Find("AdminHelper_TeamkillToggle");
			while ((Object)(object)val != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)((Component)val).gameObject);
				val = parent.Find("AdminHelper_TeamkillToggle");
			}
		}

		private static PMenuChildTabButton FindSource()
		{
			ClientComponentReferenceManager clientInstance = ClientComponentReferenceManager.ClientInstance;
			if ((Object)(object)clientInstance == (Object)null || (Object)(object)clientInstance.pMenuPanel == (Object)null)
			{
				return null;
			}
			GameObject playerChildTabButtonsRoot = clientInstance.pMenuPanel.playerChildTabButtonsRoot;
			if ((Object)(object)playerChildTabButtonsRoot == (Object)null)
			{
				return null;
			}
			PMenuChildTabButton[] componentsInChildren = playerChildTabButtonsRoot.GetComponentsInChildren<PMenuChildTabButton>(true);
			PMenuChildTabButton val = null;
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				if ((Object)(object)val == (Object)null)
				{
					val = componentsInChildren[i];
				}
				if ((Object)(object)componentsInChildren[i].toggle != (Object)null && !componentsInChildren[i].toggle.isOn)
				{
					return componentsInChildren[i];
				}
			}
			return val;
		}

		private static void MuteInspectorListeners(Toggle toggle)
		{
			int persistentEventCount = ((UnityEventBase)toggle.onValueChanged).GetPersistentEventCount();
			for (int i = 0; i < persistentEventCount; i++)
			{
				((UnityEventBase)toggle.onValueChanged).SetPersistentListenerState(i, (UnityEventCallState)0);
			}
		}

		private static void WhitenIcon(GameObject clone)
		{
			//IL_0044: 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)
			Image[] componentsInChildren = clone.GetComponentsInChildren<Image>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				if (((Object)((Component)componentsInChildren[i]).gameObject).name.IndexOf("Icon", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					((Graphic)componentsInChildren[i]).color = new Color(1f, 1f, 1f, ((Graphic)componentsInChildren[i]).color.a);
				}
			}
		}

		private static void Clickable(GameObject clone, Toggle toggle)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			Image val = clone.GetComponent<Image>();
			if ((Object)(object)val == (Object)null)
			{
				val = clone.AddComponent<Image>();
				((Graphic)val).color = new Color(1f, 1f, 1f, 0f);
			}
			((Graphic)val).raycastTarget = true;
			if ((Object)(object)((Selectable)toggle).targetGraphic == (Object)null)
			{
				((Selectable)toggle).targetGraphic = (Graphic)(object)val;
			}
			Graphic[] componentsInChildren = clone.GetComponentsInChildren<Graphic>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				if (!((Object)(object)componentsInChildren[i] == (Object)(object)val))
				{
					componentsInChildren[i].raycastTarget = false;
				}
			}
		}

		private static void BlankText(GameObject clone)
		{
			TMP_Text[] componentsInChildren = clone.GetComponentsInChildren<TMP_Text>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				componentsInChildren[i].text = string.Empty;
			}
		}

		private static float Side(RectTransform source, RectTransform searchRect)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0041: 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)
			float num = 0f;
			Rect rect;
			if ((Object)(object)source != (Object)null)
			{
				rect = source.rect;
				float width = ((Rect)(ref rect)).width;
				rect = source.rect;
				num = Mathf.Max(width, ((Rect)(ref rect)).height);
			}
			if (num < 1f)
			{
				rect = searchRect.rect;
				num = ((Rect)(ref rect)).height;
			}
			if (num < 1f)
			{
				num = 55f;
			}
			return num;
		}

		private static void Place(RectTransform rect, RectTransform searchRect, float side)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: 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_0178: 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_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: 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)
			if ((Object)(object)rect == (Object)null)
			{
				return;
			}
			((Transform)rect).localScale = Vector3.one;
			((Transform)rect).localRotation = Quaternion.identity;
			rect.anchorMin = new Vector2(0f, 0.5f);
			rect.anchorMax = new Vector2(0f, 0.5f);
			rect.pivot = new Vector2(0.5f, 0.5f);
			rect.sizeDelta = new Vector2(side, side);
			Vector3[] array = (Vector3[])(object)new Vector3[4];
			searchRect.GetWorldCorners(array);
			float num = (array[0].y + array[1].y) * 0.5f;
			float num2 = PlayersTabsRightEdge();
			if (float.IsNaN(num2))
			{
				Transform parent = ((Transform)rect).parent;
				RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null);
				if ((Object)(object)val == (Object)null)
				{
					((Transform)rect).position = new Vector3(array[2].x, num, array[0].z);
					rect.anchoredPosition += new Vector2(side * 0.5f + 14f, 0f);
					return;
				}
				Vector3[] array2 = (Vector3[])(object)new Vector3[4];
				val.GetWorldCorners(array2);
				num2 = array2[2].x;
			}
			((Transform)rect).position = new Vector3(num2, num, array[0].z);
			rect.anchoredPositio