Decompiled source of UnknOwnUtilities v1.0.1

UnknOwnUtilities.dll

Decompiled 3 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Extensions;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mirror;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("UnknOwnUtilities")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("UnknOwnUtilities")]
[assembly: AssemblyTitle("UnknOwnUtilities")]
[assembly: AssemblyVersion("1.0.0.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 UnknOwnUtilities
{
	public enum ProtectionMode
	{
		HostOnly,
		EveryoneAlwaysOn,
		OnKeypress
	}
	public static class ModConfig
	{
		public static ConfigEntry<bool> EnableSacrifice;

		public static ConfigEntry<float> MoneyPercentPerPart;

		public static ConfigEntry<int> TicketsPerPart;

		public static ConfigEntry<KeyCode> SacrificeKey;

		public static ConfigEntry<bool> EnableProtection;

		public static ConfigEntry<ProtectionMode> ProtectionBehavior;

		public static ConfigEntry<KeyCode> ProtectionKey;

		public static void Initialize(BaseUnityPlugin plugin)
		{
			EnableSacrifice = plugin.Config.Bind<bool>("Sacrifice", "Enabled", true, "Enable organ sacrifice with a Bat.");
			MoneyPercentPerPart = plugin.Config.Bind<float>("Sacrifice", "MoneyPercentPerPart", 15f, "Percentage of the current quota awarded per sacrificed organ.");
			TicketsPerPart = plugin.Config.Bind<int>("Sacrifice", "TicketsPerPart", 5, "Tickets awarded per sacrificed organ.");
			SacrificeKey = plugin.Config.Bind<KeyCode>("Sacrifice", "TriggerKey", (KeyCode)306, "Key held while hitting another player with a Bat.");
			EnableProtection = plugin.Config.Bind<bool>("Protection", "Enabled", true, "Enable Bat protection.");
			ProtectionBehavior = plugin.Config.Bind<ProtectionMode>("Protection", "Mode", ProtectionMode.OnKeypress, "HostOnly, EveryoneAlwaysOn, or OnKeypress.");
			ProtectionKey = plugin.Config.Bind<KeyCode>("Protection", "TriggerKey", (KeyCode)324, "Key held for protection in OnKeypress mode.");
		}
	}
	[StructLayout(LayoutKind.Sequential, Size = 1)]
	public struct ConfigRequestMessage : NetworkMessage
	{
	}
	public struct ConfigSyncMessage : NetworkMessage
	{
		public bool enableSacrifice;

		public float moneyPercentPerPart;

		public int ticketsPerPart;

		public int sacrificeKey;

		public bool enableProtection;

		public int protectionMode;

		public int protectionKey;
	}
	public static class RuntimeConfig
	{
		private static bool _initialized;

		private static bool _requestSent;

		private static bool _hasHostConfig;

		public static bool EnableSacrifice { get; private set; } = true;

		public static float MoneyPercentPerPart { get; private set; } = 15f;

		public static int TicketsPerPart { get; private set; } = 5;

		public static KeyCode SacrificeKey { get; private set; } = (KeyCode)306;

		public static bool EnableProtection { get; private set; } = true;

		public static ProtectionMode ProtectionBehavior { get; private set; } = ProtectionMode.OnKeypress;

		public static KeyCode ProtectionKey { get; private set; } = (KeyCode)324;

		public static bool HasHostConfig
		{
			get
			{
				if (!NetworkServer.active)
				{
					return _hasHostConfig;
				}
				return true;
			}
		}

		public static void Initialize()
		{
			if (!_initialized)
			{
				_initialized = true;
				Writer<ConfigRequestMessage>.write = delegate
				{
				};
				Reader<ConfigRequestMessage>.read = (NetworkReader reader) => default(ConfigRequestMessage);
				Writer<ConfigSyncMessage>.write = delegate(NetworkWriter writer, ConfigSyncMessage message)
				{
					NetworkWriterExtensions.WriteBool(writer, message.enableSacrifice);
					NetworkWriterExtensions.WriteFloat(writer, message.moneyPercentPerPart);
					NetworkWriterExtensions.WriteInt(writer, message.ticketsPerPart);
					NetworkWriterExtensions.WriteInt(writer, message.sacrificeKey);
					NetworkWriterExtensions.WriteBool(writer, message.enableProtection);
					NetworkWriterExtensions.WriteInt(writer, message.protectionMode);
					NetworkWriterExtensions.WriteInt(writer, message.protectionKey);
				};
				Reader<ConfigSyncMessage>.read = (NetworkReader reader) => new ConfigSyncMessage
				{
					enableSacrifice = NetworkReaderExtensions.ReadBool(reader),
					moneyPercentPerPart = NetworkReaderExtensions.ReadFloat(reader),
					ticketsPerPart = NetworkReaderExtensions.ReadInt(reader),
					sacrificeKey = NetworkReaderExtensions.ReadInt(reader),
					enableProtection = NetworkReaderExtensions.ReadBool(reader),
					protectionMode = NetworkReaderExtensions.ReadInt(reader),
					protectionKey = NetworkReaderExtensions.ReadInt(reader)
				};
				NetworkServer.RegisterHandler<ConfigRequestMessage>((Action<NetworkConnectionToClient, ConfigRequestMessage>)HandleConfigRequest, false);
				NetworkClient.RegisterHandler<ConfigSyncMessage>((Action<ConfigSyncMessage>)ReceiveHostConfig, false);
				LoadLocalConfig();
			}
		}

		private static void LoadLocalConfig()
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			EnableSacrifice = ModConfig.EnableSacrifice.Value;
			MoneyPercentPerPart = Mathf.Clamp(ModConfig.MoneyPercentPerPart.Value, 0f, 100f);
			TicketsPerPart = Mathf.Max(0, ModConfig.TicketsPerPart.Value);
			SacrificeKey = ModConfig.SacrificeKey.Value;
			EnableProtection = ModConfig.EnableProtection.Value;
			ProtectionBehavior = ModConfig.ProtectionBehavior.Value;
			ProtectionKey = ModConfig.ProtectionKey.Value;
		}

		public static void Tick()
		{
			if (NetworkServer.active)
			{
				LoadLocalConfig();
				_hasHostConfig = true;
				_requestSent = false;
			}
			else if (!NetworkClient.active || !NetworkClient.isConnected)
			{
				_requestSent = false;
				_hasHostConfig = false;
			}
			else if (!_requestSent)
			{
				_requestSent = true;
				_hasHostConfig = false;
				NetworkClient.Send<ConfigRequestMessage>(default(ConfigRequestMessage), 0);
			}
		}

		private static void HandleConfigRequest(NetworkConnectionToClient sender, ConfigRequestMessage message)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected I4, but got Unknown
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Expected I4, but got Unknown
			if (NetworkServer.active && sender != null && ((NetworkConnection)sender).isAuthenticated)
			{
				LoadLocalConfig();
				((NetworkConnection)sender).Send<ConfigSyncMessage>(new ConfigSyncMessage
				{
					enableSacrifice = EnableSacrifice,
					moneyPercentPerPart = MoneyPercentPerPart,
					ticketsPerPart = TicketsPerPart,
					sacrificeKey = (int)SacrificeKey,
					enableProtection = EnableProtection,
					protectionMode = (int)ProtectionBehavior,
					protectionKey = (int)ProtectionKey
				}, 0);
			}
		}

		private static void ReceiveHostConfig(ConfigSyncMessage message)
		{
			EnableSacrifice = message.enableSacrifice;
			MoneyPercentPerPart = Mathf.Clamp(message.moneyPercentPerPart, 0f, 100f);
			TicketsPerPart = Mathf.Max(0, message.ticketsPerPart);
			SacrificeKey = (KeyCode)message.sacrificeKey;
			EnableProtection = message.enableProtection;
			ProtectionBehavior = (ProtectionMode)Mathf.Clamp(message.protectionMode, 0, 2);
			ProtectionKey = (KeyCode)message.protectionKey;
			_hasHostConfig = true;
			if (UnknOwnUtilities.Log != null)
			{
				UnknOwnUtilities.Log.LogInfo((object)"Received authoritative settings from the host.");
			}
		}

		public static bool IsPlayerProtected(PlayerController player, bool keypressProtected)
		{
			if ((Object)(object)player == (Object)null || !EnableProtection)
			{
				return false;
			}
			switch (ProtectionBehavior)
			{
			case ProtectionMode.HostOnly:
				if (NetworkServer.active)
				{
					return ((NetworkBehaviour)player).isLocalPlayer;
				}
				return false;
			case ProtectionMode.EveryoneAlwaysOn:
				return true;
			case ProtectionMode.OnKeypress:
				return keypressProtected;
			default:
				return false;
			}
		}
	}
	[BepInPlugin("com.unknownlv.unknownutilities", "UnknOwn Utilities", "1.0.1")]
	public class UnknOwnUtilities : BaseUnityPlugin
	{
		internal static ManualLogSource Log;

		private Harmony _harmony;

		private bool _serverHandlersRegistered;

		private void Awake()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			ModConfig.Initialize((BaseUnityPlugin)(object)this);
			RuntimeConfig.Initialize();
			_harmony = new Harmony("com.unknownlv.unknownutilities");
			_harmony.PatchAll(typeof(BatPatches));
			_harmony.PatchAll(typeof(KnockbackPatches));
			_harmony.PatchAll(typeof(OrganProtectionPatches));
			RegisterMirrorMessageTypes();
			NetworkServer.OnDisconnectedEvent = (Action<NetworkConnectionToClient>)Delegate.Combine(NetworkServer.OnDisconnectedEvent, new Action<NetworkConnectionToClient>(OnServerDisconnected));
			((BaseUnityPlugin)this).Logger.LogInfo((object)"UnknOwn Utilities loaded.");
		}

		private static void RegisterMirrorMessageTypes()
		{
			Writer<OrganHitMessage>.write = delegate(NetworkWriter writer, OrganHitMessage msg)
			{
				NetworkWriterExtensions.WriteUInt(writer, msg.victimNetId);
			};
			Reader<OrganHitMessage>.read = (NetworkReader reader) => new OrganHitMessage
			{
				victimNetId = NetworkReaderExtensions.ReadUInt(reader)
			};
			Writer<ProtectionStateMessage>.write = delegate(NetworkWriter writer, ProtectionStateMessage msg)
			{
				NetworkWriterExtensions.WriteBool(writer, msg.isProtected);
			};
			Reader<ProtectionStateMessage>.read = (NetworkReader reader) => new ProtectionStateMessage
			{
				isProtected = NetworkReaderExtensions.ReadBool(reader)
			};
			Log.LogInfo((object)"Custom Mirror serializers registered.");
		}

		private void Update()
		{
			try
			{
				RuntimeConfig.Tick();
				if (NetworkServer.active)
				{
					if (!_serverHandlersRegistered)
					{
						NetworkServer.RegisterHandler<OrganHitMessage>((Action<NetworkConnectionToClient, OrganHitMessage>)BatPatches.ServerHandleOrganHit, true);
						NetworkServer.RegisterHandler<ProtectionStateMessage>((Action<NetworkConnectionToClient, ProtectionStateMessage>)ServerProtection.HandleProtectionState, true);
						_serverHandlersRegistered = true;
						((BaseUnityPlugin)this).Logger.LogInfo((object)"Custom Mirror server handlers registered.");
					}
				}
				else
				{
					_serverHandlersRegistered = false;
				}
				UpdateProtectionState();
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)$"Update failed: {arg}");
			}
		}

		private static void UpdateProtectionState()
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!NetworkClient.active || !NetworkClient.isConnected)
				{
					ServerProtection.LocalLastSentState = false;
				}
				else if (RuntimeConfig.HasHostConfig)
				{
					bool flag = RuntimeConfig.EnableProtection && RuntimeConfig.ProtectionBehavior == ProtectionMode.OnKeypress && IsConfiguredKeyHeld(RuntimeConfig.ProtectionKey);
					if (flag != ServerProtection.LocalLastSentState)
					{
						NetworkClient.Send<ProtectionStateMessage>(new ProtectionStateMessage
						{
							isProtected = flag
						}, 0);
						ServerProtection.LocalLastSentState = flag;
						Log.LogInfo((object)$"Sent protection state to server: {flag}");
					}
				}
			}
			catch (Exception ex)
			{
				if (Log != null)
				{
					Log.LogWarning((object)("Could not update protection state: " + ex.Message));
				}
			}
		}

		internal static bool IsConfiguredKeyHeld(KeyCode key)
		{
			//IL_0006: 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)
			//IL_001e: Expected I4, but got Unknown
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Invalid comparison between Unknown and I4
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Invalid comparison between Unknown and I4
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Invalid comparison between Unknown and I4
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Expected I4, but got Unknown
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Invalid comparison between Unknown and I4
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Invalid comparison between Unknown and I4
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Invalid comparison between Unknown and I4
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Expected I4, but got Unknown
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Expected I4, but got Unknown
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Invalid comparison between Unknown and I4
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Invalid comparison between Unknown and I4
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Expected I4, but got Unknown
			try
			{
				Mouse current = Mouse.current;
				switch (key - 323)
				{
				case 0:
					return current != null && current.leftButton.isPressed;
				case 1:
					return current != null && current.rightButton.isPressed;
				case 2:
					return current != null && current.middleButton.isPressed;
				default:
				{
					Keyboard current2 = Keyboard.current;
					if (current2 == null)
					{
						return false;
					}
					if ((int)key <= 27)
					{
						if ((int)key <= 9)
						{
							if ((int)key == 8)
							{
								return ((ButtonControl)current2.backspaceKey).isPressed;
							}
							if ((int)key == 9)
							{
								return ((ButtonControl)current2.tabKey).isPressed;
							}
						}
						else
						{
							if ((int)key == 13)
							{
								return ((ButtonControl)current2.enterKey).isPressed;
							}
							if ((int)key == 27)
							{
								return ((ButtonControl)current2.escapeKey).isPressed;
							}
						}
					}
					else if ((int)key <= 53)
					{
						if ((int)key == 32)
						{
							return ((ButtonControl)current2.spaceKey).isPressed;
						}
						switch (key - 49)
						{
						case 0:
							return ((ButtonControl)current2.digit1Key).isPressed;
						case 1:
							return ((ButtonControl)current2.digit2Key).isPressed;
						case 2:
							return ((ButtonControl)current2.digit3Key).isPressed;
						case 3:
							return ((ButtonControl)current2.digit4Key).isPressed;
						case 4:
							return ((ButtonControl)current2.digit5Key).isPressed;
						}
					}
					else
					{
						switch (key - 97)
						{
						default:
							switch (key - 113)
							{
							default:
								switch (key - 303)
								{
								case 3:
									return ((ButtonControl)current2.leftCtrlKey).isPressed;
								case 2:
									return ((ButtonControl)current2.rightCtrlKey).isPressed;
								case 1:
									return ((ButtonControl)current2.leftShiftKey).isPressed;
								case 0:
									return ((ButtonControl)current2.rightShiftKey).isPressed;
								case 5:
									return ((ButtonControl)current2.leftAltKey).isPressed;
								case 4:
									return ((ButtonControl)current2.rightAltKey).isPressed;
								}
								break;
							case 0:
								return ((ButtonControl)current2.qKey).isPressed;
							case 1:
								return ((ButtonControl)current2.rKey).isPressed;
							case 5:
								return ((ButtonControl)current2.vKey).isPressed;
							case 6:
								return ((ButtonControl)current2.wKey).isPressed;
							case 2:
								return ((ButtonControl)current2.sKey).isPressed;
							case 3:
							case 4:
								break;
							}
							break;
						case 4:
							return ((ButtonControl)current2.eKey).isPressed;
						case 5:
							return ((ButtonControl)current2.fKey).isPressed;
						case 2:
							return ((ButtonControl)current2.cKey).isPressed;
						case 0:
							return ((ButtonControl)current2.aKey).isPressed;
						case 3:
							return ((ButtonControl)current2.dKey).isPressed;
						case 1:
							break;
						}
					}
					return false;
				}
				}
			}
			catch
			{
				return false;
			}
		}

		private static void OnServerDisconnected(NetworkConnectionToClient conn)
		{
			if (conn != null)
			{
				ServerProtection.Clear(conn.connectionId);
			}
		}

		private void OnGUI()
		{
			StatusHud.Draw();
		}

		private void OnDestroy()
		{
			NetworkServer.OnDisconnectedEvent = (Action<NetworkConnectionToClient>)Delegate.Remove(NetworkServer.OnDisconnectedEvent, new Action<NetworkConnectionToClient>(OnServerDisconnected));
			if (_harmony != null)
			{
				_harmony.UnpatchSelf();
			}
		}
	}
	public struct OrganHitMessage : NetworkMessage
	{
		public uint victimNetId;
	}
	public struct ProtectionStateMessage : NetworkMessage
	{
		public bool isProtected;
	}
	public static class ServerProtection
	{
		private static readonly Dictionary<int, bool> ProtectedConnections = new Dictionary<int, bool>();

		public static bool LocalLastSentState;

		public static void HandleProtectionState(NetworkConnectionToClient sender, ProtectionStateMessage msg)
		{
			try
			{
				if (NetworkServer.active && sender != null && ((NetworkConnection)sender).isAuthenticated && !((Object)(object)((NetworkConnection)sender).identity == (Object)null))
				{
					ProtectedConnections[sender.connectionId] = msg.isProtected;
				}
			}
			catch (Exception arg)
			{
				UnknOwnUtilities.Log.LogError((object)$"HandleProtectionState failed: {arg}");
			}
		}

		public static bool IsProtected(PlayerController player)
		{
			if ((Object)(object)player == (Object)null || !RuntimeConfig.EnableProtection)
			{
				return false;
			}
			bool value = false;
			NetworkConnectionToClient connectionToClient = ((NetworkBehaviour)player).connectionToClient;
			if (connectionToClient != null)
			{
				ProtectedConnections.TryGetValue(connectionToClient.connectionId, out value);
			}
			return RuntimeConfig.IsPlayerProtected(player, value);
		}

		public static void Clear(int connectionId)
		{
			ProtectedConnections.Remove(connectionId);
			BatPatches.ClearConnectionCooldowns(connectionId);
		}
	}
	public static class BatPatches
	{
		private const float LocalOrganHitCooldown = 0.3f;

		private const float ServerOrganHitCooldown = 0.3f;

		private static readonly Dictionary<uint, float> LastOrganHitTime = new Dictionary<uint, float>();

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

		internal static void ClearConnectionCooldowns(int connectionId)
		{
			string value = connectionId + ":";
			List<string> list = new List<string>();
			foreach (string key in ServerLastOrganHitTime.Keys)
			{
				if (key.StartsWith(value, StringComparison.Ordinal))
				{
					list.Add(key);
				}
			}
			foreach (string item in list)
			{
				ServerLastOrganHitTime.Remove(item);
			}
		}

		private static bool IsLocalCtrlHeld()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return UnknOwnUtilities.IsConfiguredKeyHeld(RuntimeConfig.SacrificeKey);
		}

		[HarmonyPatch(typeof(Bat), "OnTriggerEnter")]
		[HarmonyPrefix]
		private static void Pre_OnTriggerEnter(Bat __instance, Collider hit)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Invalid comparison between Unknown and I4
			try
			{
				if (!RuntimeConfig.EnableSacrifice || (Object)(object)__instance == (Object)null || (Object)(object)((Item)__instance).NetworkHolder == (Object)null || !((NetworkBehaviour)((Item)__instance).NetworkHolder).isLocalPlayer || (Object)(object)hit == (Object)null || hit.isTrigger)
				{
					return;
				}
				GameManager instance = NetworkSingleton<GameManager>.Instance;
				if ((Object)(object)instance == (Object)null || (int)instance.state != 1 || !IsLocalCtrlHeld() || (Object)(object)hit.attachedRigidbody == (Object)null)
				{
					return;
				}
				PlayerController component = ((Component)hit.attachedRigidbody).GetComponent<PlayerController>();
				if (!((Object)(object)component == (Object)null) && ((NetworkBehaviour)component).netId != ((NetworkBehaviour)((Item)__instance).NetworkHolder).netId && NetworkClient.active && NetworkClient.isConnected)
				{
					float time = Time.time;
					if (!LastOrganHitTime.TryGetValue(((NetworkBehaviour)component).netId, out var value) || !(time - value < 0.3f))
					{
						LastOrganHitTime[((NetworkBehaviour)component).netId] = time;
						NetworkClient.Send<OrganHitMessage>(new OrganHitMessage
						{
							victimNetId = ((NetworkBehaviour)component).netId
						}, 0);
						UnknOwnUtilities.Log.LogInfo((object)$"Sacrifice key + bat hit detected on player {((NetworkBehaviour)component).netId}.");
					}
				}
			}
			catch (Exception arg)
			{
				UnknOwnUtilities.Log.LogError((object)$"Pre_OnTriggerEnter failed: {arg}");
			}
		}

		public static void ServerHandleOrganHit(NetworkConnectionToClient sender, OrganHitMessage msg)
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Invalid comparison between Unknown and I4
			//IL_0068: 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_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0262: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!NetworkServer.active || !RuntimeConfig.EnableSacrifice || sender == null || !((NetworkConnection)sender).isAuthenticated || (Object)(object)((NetworkConnection)sender).identity == (Object)null)
				{
					return;
				}
				GameManager instance = NetworkSingleton<GameManager>.Instance;
				MoneyManager instance2 = NetworkSingleton<MoneyManager>.Instance;
				OrganManager instance3 = NetworkSingleton<OrganManager>.Instance;
				if ((Object)(object)instance == (Object)null || (Object)(object)instance2 == (Object)null || (Object)(object)instance3 == (Object)null || (int)instance.state != 1 || instance2.balance >= instance.currentQuota || !NetworkServer.spawned.TryGetValue(msg.victimNetId, out var value) || (Object)(object)value == (Object)null)
				{
					return;
				}
				PlayerController component = ((Component)value).GetComponent<PlayerController>();
				if ((Object)(object)component == (Object)null || ((NetworkBehaviour)component).connectionToClient == null)
				{
					return;
				}
				NetworkIdentity identity = ((NetworkConnection)sender).identity;
				PlayerController component2 = ((Component)identity).GetComponent<PlayerController>();
				if ((Object)(object)component2 == (Object)null || ((NetworkBehaviour)component2).netId == ((NetworkBehaviour)component).netId)
				{
					return;
				}
				PlayerInventory component3 = ((Component)identity).GetComponent<PlayerInventory>();
				if ((Object)(object)component3 == (Object)null || !(component3.NetworkholdingItem is Bat))
				{
					return;
				}
				int connectionId = sender.connectionId;
				string key = connectionId + ":" + ((NetworkBehaviour)component).netId;
				float time = Time.time;
				if (ServerLastOrganHitTime.TryGetValue(key, out var value2) && time - value2 < 0.3f)
				{
					return;
				}
				ServerLastOrganHitTime[key] = time;
				if (ServerProtection.IsProtected(component))
				{
					UnknOwnUtilities.Log.LogInfo((object)$"Organ removal blocked: player {((NetworkBehaviour)component).netId} is protected.");
					return;
				}
				PlayerOrgans component4 = ((Component)component).GetComponent<PlayerOrgans>();
				if ((Object)(object)component4 == (Object)null)
				{
					return;
				}
				PlayerOrganData organData = instance3.GetOrganData(component4);
				if (organData != null)
				{
					List<OrganType> list = new List<OrganType>();
					if (organData.body)
					{
						list.Add((OrganType)2);
					}
					if (organData.mouth)
					{
						list.Add((OrganType)3);
					}
					if (organData.leftEye && organData.rightEye)
					{
						list.Add((OrganType)(!(Random.value > 0.5f)));
					}
					if (list.Count == 0)
					{
						UnknOwnUtilities.Log.LogInfo((object)$"No removable organs remain on player {((NetworkBehaviour)component).netId}.");
						return;
					}
					OrganType val = list[Random.Range(0, list.Count)];
					instance3.ServerToggleOrgan(component4, val, false);
					UnknOwnUtilities.Log.LogInfo((object)$"Removed {val} from player {((NetworkBehaviour)component).netId}.");
					AwardRewards();
				}
			}
			catch (Exception arg)
			{
				UnknOwnUtilities.Log.LogError((object)$"ServerHandleOrganHit failed: {arg}");
			}
		}

		private static void AwardRewards()
		{
			//IL_0031: 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_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: 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)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: 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_0078: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				MoneyManager instance = NetworkSingleton<MoneyManager>.Instance;
				GameManager instance2 = NetworkSingleton<GameManager>.Instance;
				if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance2 == (Object)null))
				{
					instance.TryChangeTicketBalance((long)RuntimeConfig.TicketsPerPart);
					BigNumber currentQuota = instance2.currentQuota;
					BigNumber val = currentQuota * (double)(RuntimeConfig.MoneyPercentPerPart / 100f);
					BigNumber val2 = ((BigNumber)(ref val)).RoundByFirstNDigits(2);
					BigNumber val3 = currentQuota - instance.balance;
					if (val2 > val3)
					{
						val2 = val3;
					}
					if (val2 > BigNumber.Zero)
					{
						instance.TryChangeBalance(val2, (PlayerProfile)null, (ChangeType)2);
					}
					UnknOwnUtilities.Log.LogInfo((object)($"Awarded {RuntimeConfig.TicketsPerPart} tickets and " + $"{val2} quota progress."));
				}
			}
			catch (Exception arg)
			{
				UnknOwnUtilities.Log.LogError((object)$"AwardRewards failed: {arg}");
			}
		}
	}
	public static class StatusHud
	{
		private class HudIndicator
		{
			public string Label;

			public Color Background;

			public Func<bool> IsActive;
		}

		private static readonly List<HudIndicator> Indicators = new List<HudIndicator>
		{
			new HudIndicator
			{
				Label = "D",
				Background = new Color(0.15f, 0.45f, 1f, 0.9f),
				IsActive = IsRightClickHeld
			},
			new HudIndicator
			{
				Label = "S",
				Background = new Color(1f, 0.15f, 0.15f, 0.9f),
				IsActive = IsSacrificeModeActive
			}
		};

		private const float BoxSize = 64f;

		private const float Spacing = 12f;

		private const float BottomMargin = 32f;

		private const int CornerRadius = 14;

		private const int FontSize = 32;

		private static Texture2D _whiteRounded;

		private static GUIStyle _labelStyle;

		public static bool IsRightClickHeld()
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (RuntimeConfig.EnableProtection && RuntimeConfig.ProtectionBehavior == ProtectionMode.OnKeypress)
			{
				return UnknOwnUtilities.IsConfiguredKeyHeld(RuntimeConfig.ProtectionKey);
			}
			return false;
		}

		public static bool IsCtrlHeld()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			if (RuntimeConfig.EnableSacrifice)
			{
				return UnknOwnUtilities.IsConfiguredKeyHeld(RuntimeConfig.SacrificeKey);
			}
			return false;
		}

		private static PlayerController GetLocalPlayer()
		{
			try
			{
				if ((Object)(object)NetworkClient.localPlayer != (Object)null)
				{
					PlayerController component = ((Component)NetworkClient.localPlayer).GetComponent<PlayerController>();
					if ((Object)(object)component != (Object)null)
					{
						return component;
					}
				}
				PlayerController[] array = Object.FindObjectsByType<PlayerController>((FindObjectsSortMode)0);
				foreach (PlayerController val in array)
				{
					if ((Object)(object)val != (Object)null && ((NetworkBehaviour)val).isLocalPlayer)
					{
						return val;
					}
				}
			}
			catch (Exception ex)
			{
				if (UnknOwnUtilities.Log != null)
				{
					UnknOwnUtilities.Log.LogWarning((object)("Could not find local player for HUD: " + ex.Message));
				}
			}
			return null;
		}

		public static bool IsSacrificeModeActive()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Invalid comparison between Unknown and I4
			if (!IsCtrlHeld())
			{
				return false;
			}
			try
			{
				GameManager instance = NetworkSingleton<GameManager>.Instance;
				if ((Object)(object)instance == (Object)null || (int)instance.state != 1)
				{
					return false;
				}
				PlayerController localPlayer = GetLocalPlayer();
				if ((Object)(object)localPlayer == (Object)null)
				{
					return false;
				}
				PlayerInventory component = ((Component)localPlayer).GetComponent<PlayerInventory>();
				return (Object)(object)component != (Object)null && component.NetworkholdingItem is Bat;
			}
			catch
			{
				return false;
			}
		}

		private static Texture2D GetRoundedTexture()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_whiteRounded != (Object)null)
			{
				return _whiteRounded;
			}
			_whiteRounded = new Texture2D(64, 64, (TextureFormat)5, false);
			((Texture)_whiteRounded).wrapMode = (TextureWrapMode)1;
			float num = 14f;
			float num2 = 31.5f;
			float num3 = 31.5f;
			for (int i = 0; i < 64; i++)
			{
				for (int j = 0; j < 64; j++)
				{
					float num4 = Mathf.Max(Mathf.Abs((float)j - num2) - (32f - num), 0f);
					float num5 = Mathf.Max(Mathf.Abs((float)i - num3) - (32f - num), 0f);
					float num6 = Mathf.Sqrt(num4 * num4 + num5 * num5);
					float num7 = Mathf.Clamp01(num - num6 + 0.5f);
					_whiteRounded.SetPixel(j, i, new Color(1f, 1f, 1f, num7));
				}
			}
			_whiteRounded.Apply();
			return _whiteRounded;
		}

		private static GUIStyle GetLabelStyle()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			if (_labelStyle != null)
			{
				return _labelStyle;
			}
			_labelStyle = new GUIStyle(GUI.skin.label)
			{
				alignment = (TextAnchor)4,
				fontStyle = (FontStyle)1,
				fontSize = 32
			};
			_labelStyle.normal.textColor = Color.white;
			return _labelStyle;
		}

		public static void Draw()
		{
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				int num = 0;
				foreach (HudIndicator indicator in Indicators)
				{
					if (indicator.IsActive())
					{
						num++;
					}
				}
				if (num == 0)
				{
					return;
				}
				float num2 = (float)num * 64f + (float)(num - 1) * 12f;
				float num3 = ((float)Screen.width - num2) / 2f;
				float num4 = (float)Screen.height - 32f - 64f;
				Texture2D roundedTexture = GetRoundedTexture();
				GUIStyle labelStyle = GetLabelStyle();
				float num5 = num3;
				Rect val = default(Rect);
				foreach (HudIndicator indicator2 in Indicators)
				{
					if (indicator2.IsActive())
					{
						((Rect)(ref val))..ctor(num5, num4, 64f, 64f);
						Color color = GUI.color;
						GUI.color = indicator2.Background;
						GUI.DrawTexture(val, (Texture)(object)roundedTexture, (ScaleMode)0, true);
						GUI.color = color;
						Rect val2 = new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).y + 2f, ((Rect)(ref val)).width, ((Rect)(ref val)).height);
						labelStyle.normal.textColor = new Color(0f, 0f, 0f, 0.5f);
						GUI.Label(val2, indicator2.Label, labelStyle);
						labelStyle.normal.textColor = Color.white;
						GUI.Label(val, indicator2.Label, labelStyle);
						num5 += 76f;
					}
				}
			}
			catch (Exception ex)
			{
				if (UnknOwnUtilities.Log != null)
				{
					UnknOwnUtilities.Log.LogWarning((object)("HUD drawing failed: " + ex.Message));
				}
			}
		}
	}
	public static class KnockbackPatches
	{
		private static bool IsLocalRightClickHeld()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return UnknOwnUtilities.IsConfiguredKeyHeld(RuntimeConfig.ProtectionKey);
		}

		[HarmonyPatch(typeof(PlayerController), "ServerKnockback")]
		[HarmonyPrefix]
		private static bool Pre_ServerKnockback(PlayerController __instance)
		{
			if (NetworkServer.active && ServerProtection.IsProtected(__instance))
			{
				UnknOwnUtilities.Log.LogInfo((object)$"Blocked knockback on protected player {((NetworkBehaviour)__instance).netId}.");
				return false;
			}
			return true;
		}

		[HarmonyPatch(typeof(PlayerController), "UserCode_TargetKnockback__NetworkConnection__Vector3__Vector3")]
		[HarmonyPrefix]
		private static bool Pre_TargetKnockback(PlayerController __instance)
		{
			if ((Object)(object)__instance != (Object)null && ((NetworkBehaviour)__instance).isLocalPlayer && RuntimeConfig.EnableProtection && RuntimeConfig.ProtectionBehavior == ProtectionMode.OnKeypress && IsLocalRightClickHeld())
			{
				UnknOwnUtilities.Log.LogInfo((object)"Blocked knockback: local player is protected.");
				return false;
			}
			return true;
		}
	}
	public static class OrganProtectionPatches
	{
		[HarmonyPatch(typeof(OrganManager), "ServerToggleOrgan")]
		[HarmonyPrefix]
		private static bool Pre_ServerToggleOrgan(PlayerOrgans organs, OrganType organType, bool isEnabled)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			if (isEnabled || !NetworkServer.active || (Object)(object)organs == (Object)null)
			{
				return true;
			}
			PlayerController component = ((Component)organs).GetComponent<PlayerController>();
			if ((Object)(object)component == (Object)null || !ServerProtection.IsProtected(component))
			{
				return true;
			}
			UnknOwnUtilities.Log.LogInfo((object)$"Blocked {organType} removal from protected player {((NetworkBehaviour)component).netId}.");
			return false;
		}
	}
}