Decompiled source of GunGame v1.2.4

plugins/GunGameMod.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using FishNet;
using FishNet.Connection;
using FishNet.Managing;
using FishNet.Managing.Scened;
using FishNet.Object;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("GunGameMod")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+87e1819de472829ee4359e1459224afd33ef4312")]
[assembly: AssemblyProduct("GunGameMod")]
[assembly: AssemblyTitle("GunGameMod")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace GunGameMod
{
	public static class GunGamePatches
	{
		private static Harmony _harmony;

		private static Dictionary<int, int> _killsPerPlayer = new Dictionary<int, int>();

		private static HashSet<int> _waitingForSetStartTime = new HashSet<int>();

		private static HashSet<string> _pendingPlaceableReplace = new HashSet<string>();

		private static Dictionary<int, GameObject> _playerRagdolls = new Dictionary<int, GameObject>();

		private static bool _winSequenceInProgress = false;

		private static HashSet<int> _respawnInProgress = new HashSet<int>();

		private static Dictionary<int, int> _respawnRequestSeq = new Dictionary<int, int>();

		private static HashSet<int> _playersAwaitingRespawn = new HashSet<int>();

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

		private static float _nextRespawnWatchdogTime;

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

		private static Dictionary<int, int> _lastKillAwardCount = new Dictionary<int, int>();

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

		private static HashSet<int> _minigunDropQueued = new HashSet<int>();

		private const float MultiKillAwardSuppressSeconds = 0.35f;

		private const float ThrowableOpenSuppressSeconds = 0.35f;

		private const int MaxRespawnAttempts = 3;

		private const float RespawnValidationSeconds = 2f;

		private const float RespawnRetryDelaySeconds = 0.25f;

		private const float RespawnWatchdogIntervalSeconds = 0.5f;

		private const float RespawnRecoveryDelaySeconds = 1f;

		private static MethodInfo _miCmdRespawnLogic;

		private static MethodInfo _miRoundWon;

		private static FieldInfo _fiSpawnedObject;

		private static MethodInfo _miRpcLogic_DropObjectServer;

		private static MethodInfo _miRpcLogic_DropObjectObserver;

		private static MethodInfo _miMatchLogsSendToAll;

		private static FieldInfo _fiRightIdlePosition;

		private static FieldInfo _fiRigBuilder;

		private static Type _particleSystemType;

		public static void Apply()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Expected O, but got Unknown
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_024c: Expected O, but got Unknown
			if (_harmony != null)
			{
				return;
			}
			_harmony = new Harmony("com.modder.gungame.patches");
			CacheReflectionMethods();
			try
			{
				PatchPrefix(typeof(GameManager), "WaitForDraw", "GameManager_WaitForDraw_Prefix");
				PatchPrefix(typeof(GameManager), "RpcLogic___PlayerDied_3316948804", "GameManager_RpcLogic_PlayerDied_Prefix");
				PatchPrefix(typeof(RoundManager), "CmdEndRound", "RoundManager_CmdEndRound_Prefix");
				PatchPrefix(typeof(GameManager), "SetStartTime", "GameManager_SetStartTime_Prefix");
				PatchPrefix(typeof(PlayerManager), "RpcLogic___SetPlayerMove_1140765316", "PlayerManager_RpcLogic_SetPlayerMove_Prefix");
				PatchPrefix(typeof(KillCam), "Update", "KillCam_Update_Prefix");
				PatchPrefix(typeof(ItemBehaviour), "Start", "ItemBehaviour_Start_Prefix");
				PatchPostfixReflected(typeof(PlayerPickup), "RpcLogic___SetObjectInHandObserver_46969756", "PlayerPickup_SetObjectInHandObserver_Postfix");
				PatchPrefix(typeof(ItemBehaviour), "StickOnGround", "ItemBehaviour_StickOnGround_Prefix");
				PatchPrefix(typeof(Spawner), "Update", "Spawner_Update_Prefix");
				PatchPrefix(typeof(PlayerPickup), "RightHandFix", "PlayerPickup_RightHandFix_Prefix");
				PatchPrefix(typeof(PlayerPickup), "LeftHandFix", "PlayerPickup_LeftHandFix_Prefix");
				PatchPrefix(typeof(PlayerPickup), "HandsReconstruct", "PlayerPickup_HandsReconstruct_Prefix");
				PatchPrefix(typeof(PlayerPickup), "RightHandDrop", "PlayerPickup_RightHandDrop_Prefix");
				PatchPrefix(typeof(PlayerPickup), "RightHandPickup", "PlayerPickup_RightHandPickup_Prefix");
				PatchPrefix(typeof(PlayerPickup), "SwitchWeapons", "PlayerPickup_SwitchWeapons_Prefix");
				PatchPrefix(typeof(PlayerPickup), "LeftHandPickup", "PlayerPickup_LeftHandPickup_Prefix");
				if (_miRpcLogic_DropObjectServer != null)
				{
					_harmony.Patch((MethodBase)_miRpcLogic_DropObjectServer, new HarmonyMethod(typeof(GunGamePatches).GetMethod("PlayerPickup_RpcLogic_DropObjectServer_Prefix", BindingFlags.Static | BindingFlags.Public)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				if (_miRpcLogic_DropObjectObserver != null)
				{
					_harmony.Patch((MethodBase)_miRpcLogic_DropObjectObserver, new HarmonyMethod(typeof(GunGamePatches).GetMethod("PlayerPickup_RpcLogic_DropObjectObserver_Prefix", BindingFlags.Static | BindingFlags.Public)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				PatchPrefix(typeof(PauseManager), "StartRoundDelay", "PauseManager_StartRoundDelay_Prefix");
				PatchPrefix(typeof(ProximityMine), "KillShockWave", "ProximityMine_KillShockWave_Prefix");
				PatchPrefix(typeof(Claymore), "KillShockWave", "Claymore_KillShockWave_Prefix");
				PatchPostfix(typeof(Minigun), "Update", "Minigun_Update_Postfix");
				PatchPrefix(typeof(DualLauncher), "SetBool", "DualLauncher_SetBool_Prefix");
				PatchPostfix(typeof(WeaponHandSpawner), "RpcLogic___SpawnObject_2587446063", "WeaponHandSpawner_SpawnObject_Postfix");
				PatchPrefix(typeof(MatchLogs), "RpcLogic___RpcSendChatLine_3615296227", "MatchLogs_RpcSendChatLine_Prefix");
				PatchPostfix(typeof(PlayerManager), "SpawnPlayer", "PlayerManager_SpawnPlayer_Postfix", new Type[2]
				{
					typeof(int),
					typeof(int)
				});
				PatchPostfix(typeof(PlayerHealth), "RpcLogic___ExplodeForAll_576886416", "PlayerHealth_ExplodeForAll_Postfix");
				PatchPostfixReflected(typeof(PlayerValues), "sync___set_value_playerClient", "PlayerValues_SetPlayerClient_Postfix");
				PatchPrefix(typeof(DamageZone), "OnEnable", "DamageZone_OnEnable_Prefix");
				PatchPrefix(typeof(FirstPersonController), "OnTriggerStay", "FirstPersonController_OnTriggerStay_Prefix");
			}
			catch
			{
			}
		}

		private static void CacheReflectionMethods()
		{
			_miCmdRespawnLogic = typeof(PlayerManager).GetMethod("RpcLogic___CmdRespawn_2166136261", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (_miCmdRespawnLogic == null)
			{
				ManualLogSource log = GunGamePlugin.Log;
				if (log != null)
				{
					log.LogError((object)"[GunGame Respawn] native PlayerManager respawn method was not found");
				}
			}
			_miRoundWon = typeof(GameManager).GetMethod("RoundWon", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			_fiSpawnedObject = typeof(PlayerManager).GetField("SpawnedObject", BindingFlags.Instance | BindingFlags.NonPublic);
			_miRpcLogic_DropObjectServer = typeof(PlayerPickup).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name.Contains("RpcLogic___DropObjectServer"));
			_miRpcLogic_DropObjectObserver = typeof(PlayerPickup).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name.Contains("RpcLogic___DropObjectObserver"));
			_miMatchLogsSendToAll = typeof(MatchLogs).GetMethod("RpcSendChatLineToAllObservers", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			_fiRightIdlePosition = typeof(PlayerPickup).GetField("RightIdlePosition", BindingFlags.Instance | BindingFlags.NonPublic);
			_fiRigBuilder = typeof(PlayerPickup).GetField("RigBuilder", BindingFlags.Instance | BindingFlags.NonPublic);
		}

		private static void PatchPrefix(Type type, string methodName, string patchName, Type[] paramTypes = null)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			MethodInfo methodInfo = ((paramTypes == null) ? type.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) : type.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, paramTypes, null));
			if (!(methodInfo == null))
			{
				_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(GunGamePatches).GetMethod(patchName, BindingFlags.Static | BindingFlags.Public)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}

		private static void PatchPostfix(Type type, string methodName, string patchName, Type[] paramTypes = null)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			MethodInfo methodInfo = ((paramTypes == null) ? type.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) : type.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, paramTypes, null));
			if (!(methodInfo == null))
			{
				_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(GunGamePatches).GetMethod(patchName, BindingFlags.Static | BindingFlags.Public)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}

		private static void PatchPostfixReflected(Type type, string methodName, string patchName)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			MethodInfo method = type.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (!(method == null))
			{
				_harmony.Patch((MethodBase)method, (HarmonyMethod)null, new HarmonyMethod(typeof(GunGamePatches).GetMethod(patchName, BindingFlags.Static | BindingFlags.Public)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}

		public static void ResetState()
		{
			_killsPerPlayer.Clear();
			_waitingForSetStartTime.Clear();
			_pendingPlaceableReplace.Clear();
			_playerRagdolls.Clear();
			_winSequenceInProgress = false;
			_respawnInProgress.Clear();
			_respawnRequestSeq.Clear();
			_playersAwaitingRespawn.Clear();
			_nextRespawnRecoveryTime.Clear();
			_nextRespawnWatchdogTime = 0f;
			_lastKillAwardTime.Clear();
			_lastKillAwardCount.Clear();
			_suppressThrowableOpenUntil.Clear();
			_minigunDropQueued.Clear();
		}

		public static int GetCurrentWeaponIndex(int playerId)
		{
			int progressStage = GetProgressStage(playerId);
			int orderedWeaponCount = GunGamePlugin.GetOrderedWeaponCount();
			if (orderedWeaponCount <= 0)
			{
				return 0;
			}
			return (progressStage - 1) % orderedWeaponCount;
		}

		private static int GetProgressStage(int playerId)
		{
			if (!_killsPerPlayer.TryGetValue(playerId, out var value) || value <= 0)
			{
				return 1;
			}
			return value;
		}

		private static int GetCompletedKillCount(int playerId)
		{
			return GetProgressStage(playerId) - 1;
		}

		public static bool GameManager_WaitForDraw_Prefix(ref IEnumerator __result)
		{
			if (!GunGamePlugin.MatchOver)
			{
				__result = EmptyCoroutine();
				return false;
			}
			return true;
		}

		public static bool KillCam_Update_Prefix()
		{
			return !GunGamePlugin.Enabled.Value;
		}

		private static IEnumerator EmptyCoroutine()
		{
			yield break;
		}

		public static bool GameManager_RpcLogic_PlayerDied_Prefix(int playerId)
		{
			if (!GunGamePlugin.Enabled.Value)
			{
				return true;
			}
			if (GunGamePlugin.MatchOver)
			{
				return false;
			}
			try
			{
				if ((Object)(object)InstanceFinder.NetworkManager != (Object)null && InstanceFinder.NetworkManager.IsServer)
				{
					PlayerPickup val = GunGamePlugin.FindPickupForPlayerId(playerId);
					if ((Object)(object)val != (Object)null)
					{
						GunGameWeaponManager.DespawnHeldWeapon(val);
					}
					ClearPlacedExplosivesForPlayer(playerId);
					GunGameWeaponManager.QueueWeaponUpgrade(playerId, GetCurrentWeaponIndex(playerId));
				}
				if (GameManager.Instance?.alivePlayers != null && !GameManager.Instance.alivePlayers.Contains(playerId))
				{
					GameManager.Instance.alivePlayers.Add(playerId);
				}
				if ((Object)(object)InstanceFinder.NetworkManager == (Object)null || !InstanceFinder.NetworkManager.IsServer)
				{
					return true;
				}
				int num = FindKillerId(playerId);
				if (num >= 0 && num != playerId)
				{
					float unscaledTime = Time.unscaledTime;
					int progressStage = GetProgressStage(num);
					int completedKillCount = GetCompletedKillCount(num);
					int num2 = progressStage + 1;
					if (progressStage > 1 && _lastKillAwardTime.TryGetValue(num, out var value) && unscaledTime - value <= 0.35f && _lastKillAwardCount.TryGetValue(num, out var value2) && value2 == progressStage)
					{
						string playerName = GetPlayerName(num);
						string playerName2 = GetPlayerName(playerId);
						int orderedWeaponCount = GunGamePlugin.GetOrderedWeaponCount();
						GameObject orderedWeaponPrefab = GunGamePlugin.GetOrderedWeaponPrefab((orderedWeaponCount > 0) ? ((completedKillCount - 1 + orderedWeaponCount) % orderedWeaponCount) : 0);
						string text = ((orderedWeaponPrefab != null) ? ((Object)orderedWeaponPrefab).name : null) ?? "Unknown";
						BroadcastChat($"<b><color=yellow>[Gun Game]</color></b> <b>{playerName}</b> <color=red>killed</color> <b>{playerName2}</b> with <b><color=white>{text}</color></b> <color=#00FFFF>[{completedKillCount}/{GunGamePlugin.KillsToWin.Value}]</color>");
					}
					else
					{
						_lastKillAwardTime[num] = unscaledTime;
						_lastKillAwardCount[num] = num2;
						_killsPerPlayer[num] = num2;
						int num3 = num2 - 1;
						int orderedWeaponCount2 = GunGamePlugin.GetOrderedWeaponCount();
						int weaponIndex = ((orderedWeaponCount2 > 0) ? ((num2 - 1) % orderedWeaponCount2) : 0);
						GameObject orderedWeaponPrefab2 = GunGamePlugin.GetOrderedWeaponPrefab((orderedWeaponCount2 > 0) ? ((num2 - 2 + orderedWeaponCount2) % orderedWeaponCount2) : 0);
						string text2 = ((orderedWeaponPrefab2 != null) ? ((Object)orderedWeaponPrefab2).name : null) ?? "Unknown";
						string playerName3 = GetPlayerName(num);
						string playerName4 = GetPlayerName(playerId);
						BroadcastChat((num3 >= GunGamePlugin.KillsToWin.Value) ? ("<b><color=yellow>[Gun Game]</color></b> <b>" + playerName3 + "</b> <color=red>killed</color> <b>" + playerName4 + "</b> with <b><color=white>" + text2 + "</color></b> — <b><color=yellow>WINS THE ROUND!</color></b>") : $"<b><color=yellow>[Gun Game]</color></b> <b>{playerName3}</b> <color=red>killed</color> <b>{playerName4}</b> with <b><color=white>{text2}</color></b> <color=#00FFFF>[{num3}/{GunGamePlugin.KillsToWin.Value}]</color>");
						GunGameWeaponManager.GiveWeaponToPlayer(num, weaponIndex);
						((MonoBehaviour)GameManager.Instance).StartCoroutine(DelayedKillWeaponGive(num, weaponIndex));
						switch (text2)
						{
						case "ProximityMine":
						case "APMine":
						case "Claymore":
							ClearPlacedExplosivesForPlayer(num);
							break;
						}
						if (num3 >= GunGamePlugin.KillsToWin.Value && !_winSequenceInProgress)
						{
							_winSequenceInProgress = true;
							GunGamePlugin.MatchOver = true;
							((MonoBehaviour)GameManager.Instance).StartCoroutine(WinSequenceCoroutine(num));
							return false;
						}
					}
				}
				else
				{
					string playerName5 = GetPlayerName(playerId);
					BroadcastChat("<b><color=yellow>[Gun Game]</color></b> <b>" + playerName5 + "</b> <color=#888888>killed themselves</color>");
				}
				ScheduleRespawn(playerId);
			}
			catch
			{
				try
				{
					ScheduleRespawn(playerId);
				}
				catch
				{
				}
			}
			return false;
		}

		public static void PlayerManager_SpawnPlayer_Postfix(PlayerManager __instance)
		{
			if (!GunGamePlugin.Enabled.Value || (Object)(object)__instance == (Object)null)
			{
				return;
			}
			ClientInstance component = ((Component)__instance).GetComponent<ClientInstance>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			int playerId = component.PlayerId;
			if (playerId < 0)
			{
				return;
			}
			if ((Object)(object)InstanceFinder.NetworkManager != (Object)null && InstanceFinder.NetworkManager.IsServer)
			{
				int num;
				if (!_respawnInProgress.Contains(playerId))
				{
					num = (GunGameWeaponManager.HasPendingWeapon(playerId) ? 1 : 0);
					if (num == 0)
					{
						if (_killsPerPlayer.ContainsKey(playerId))
						{
							_killsPerPlayer.Remove(playerId);
						}
						GunGameWeaponManager.ClearPendingForPlayer(playerId);
					}
				}
				else
				{
					num = 1;
				}
				if (GameManager.Instance?.alivePlayers != null && !GameManager.Instance.alivePlayers.Contains(playerId))
				{
					GameManager.Instance.alivePlayers.Add(playerId);
				}
				_waitingForSetStartTime.Add(playerId);
				if (num == 0 && GunGamePlugin.GetOrderedWeaponCount() > 0)
				{
					GunGameWeaponManager.GiveWeaponToPlayer(playerId, 0);
					GameManager instance = GameManager.Instance;
					if (instance != null)
					{
						((MonoBehaviour)instance).StartCoroutine(DelayedInitialSpawnFallback(playerId));
					}
				}
			}
			if (((NetworkBehaviour)__instance).IsOwner)
			{
				if ((Object)(object)PauseManager.Instance != (Object)null)
				{
					PauseManager.Instance.startRound = false;
				}
				GameManager instance2 = GameManager.Instance;
				if (instance2 != null)
				{
					((MonoBehaviour)instance2).StartCoroutine(KeepPlayerMovable(__instance, 4f));
				}
			}
		}

		public static void GameManager_SetStartTime_Prefix(ref float serverTimeTillStart)
		{
			if (GunGamePlugin.Enabled.Value && !GunGamePlugin.MatchOver)
			{
				serverTimeTillStart = 0f;
			}
		}

		public static bool PlayerManager_RpcLogic_SetPlayerMove_Prefix(PlayerManager __instance, bool state)
		{
			if (!GunGamePlugin.Enabled.Value || GunGamePlugin.MatchOver)
			{
				return true;
			}
			ClientInstance component = ((Component)__instance).GetComponent<ClientInstance>();
			if ((Object)(object)component == (Object)null)
			{
				return true;
			}
			int playerId = component.PlayerId;
			if (playerId < 0)
			{
				return true;
			}
			if (!state && _waitingForSetStartTime.Contains(playerId))
			{
				_waitingForSetStartTime.Remove(playerId);
				try
				{
					if ((Object)(object)__instance.player != (Object)null)
					{
						__instance.player.sync___set_value_canMove(true, true);
						__instance.player.startOfRound = false;
					}
					if ((Object)(object)PauseManager.Instance != (Object)null)
					{
						PauseManager.Instance.startRound = false;
						PauseManager.Instance.pause = false;
						PauseManager.Instance.otherPauseBools = false;
					}
				}
				catch
				{
				}
				return false;
			}
			return true;
		}

		public static bool ItemBehaviour_Start_Prefix(ItemBehaviour __instance)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance == (Object)null)
			{
				return true;
			}
			__instance.dispenserStart = true;
			Rigidbody component = ((Component)__instance).GetComponent<Rigidbody>();
			if ((Object)(object)component != (Object)null)
			{
				component.isKinematic = true;
				component.useGravity = false;
				component.velocity = Vector3.zero;
				component.angularVelocity = Vector3.zero;
			}
			return true;
		}

		public static void PlayerPickup_SetObjectInHandObserver_Postfix(PlayerPickup __instance, GameObject obj)
		{
			if (!((Object)(object)obj == (Object)null))
			{
				ItemBehaviour component = obj.GetComponent<ItemBehaviour>();
				if ((Object)(object)component != (Object)null)
				{
					component.dispenserStart = false;
				}
			}
		}

		public static bool ItemBehaviour_StickOnGround_Prefix(ItemBehaviour __instance)
		{
			if ((Object)(object)__instance.cam == (Object)null)
			{
				return false;
			}
			return true;
		}

		public static bool Spawner_Update_Prefix()
		{
			return !GunGamePlugin.Enabled.Value;
		}

		public static bool PlayerPickup_RightHandFix_Prefix(PlayerPickup __instance)
		{
			//IL_0076: 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)
			if (!GunGamePlugin.Enabled.Value)
			{
				return true;
			}
			if (__instance.sync___get_value_hasObjectInHand() && (Object)(object)__instance.sync___get_value_objInHand() == (Object)null)
			{
				__instance.sync___set_value_hasObjectInHand(false, true);
				return false;
			}
			GameObject val = __instance.sync___get_value_objInHand();
			if ((Object)(object)val == (Object)null)
			{
				return true;
			}
			if (val.layer == 7 || val.layer == 9)
			{
				MethodInfo setObjectInHandObserverLogic = GunGameWeaponManager.SetObjectInHandObserverLogic;
				if (setObjectInHandObserverLogic != null)
				{
					try
					{
						setObjectInHandObserverLogic.Invoke(__instance, new object[5]
						{
							val,
							val.transform.position,
							val.transform.rotation,
							((Component)__instance).gameObject,
							true
						});
					}
					catch
					{
					}
				}
				return false;
			}
			return true;
		}

		public static bool PlayerPickup_LeftHandFix_Prefix(PlayerPickup __instance)
		{
			//IL_0076: 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)
			if (!GunGamePlugin.Enabled.Value)
			{
				return true;
			}
			if (__instance.sync___get_value_hasObjectInLeftHand() && (Object)(object)__instance.sync___get_value_objInLeftHand() == (Object)null)
			{
				__instance.sync___set_value_hasObjectInLeftHand(false, true);
				return false;
			}
			GameObject val = __instance.sync___get_value_objInLeftHand();
			if ((Object)(object)val == (Object)null)
			{
				return true;
			}
			if (val.layer == 7 || val.layer == 9)
			{
				MethodInfo setObjectInHandObserverLogic = GunGameWeaponManager.SetObjectInHandObserverLogic;
				if (setObjectInHandObserverLogic != null)
				{
					try
					{
						setObjectInHandObserverLogic.Invoke(__instance, new object[5]
						{
							val,
							val.transform.position,
							val.transform.rotation,
							((Component)__instance).gameObject,
							false
						});
					}
					catch
					{
					}
				}
				return false;
			}
			return true;
		}

		public static bool PlayerPickup_RightHandDrop_Prefix(PlayerPickup __instance)
		{
			if (!GunGamePlugin.Enabled.Value)
			{
				return true;
			}
			GameObject val = __instance.sync___get_value_objInHand();
			if (__instance.sync___get_value_hasObjectInHand() && ((Object)(object)val == (Object)null || (Object)(object)val.GetComponent<ItemBehaviour>() == (Object)null))
			{
				__instance.sync___set_value_hasObjectInHand(false, true);
				__instance.sync___set_value_objInHand((GameObject)null, true);
				return false;
			}
			PlayerHealth componentInParent = ((Component)__instance).GetComponentInParent<PlayerHealth>();
			if ((Object)(object)componentInParent != (Object)null && componentInParent.sync___get_value_isKilled())
			{
				return false;
			}
			return true;
		}

		public static bool PlayerPickup_HandsReconstruct_Prefix(PlayerPickup __instance)
		{
			if (!GunGamePlugin.Enabled.Value || (Object)(object)__instance == (Object)null)
			{
				return true;
			}
			try
			{
				GameObject val = __instance.sync___get_value_objInLeftHand();
				GameObject val2 = __instance.sync___get_value_objInHand();
				if ((Object)(object)val == (Object)null || (Object)(object)val2 != (Object)null)
				{
					return true;
				}
				object? obj = _fiRightIdlePosition?.GetValue(__instance);
				Transform rightIKTarget = (Transform)((obj is Transform) ? obj : null);
				ItemBehaviour component = val.GetComponent<ItemBehaviour>();
				__instance.SetRightIKTarget(rightIKTarget);
				__instance.SetLeftIKTarget(((Object)(object)component != (Object)null) ? component.gripLeft : null);
				object obj2 = _fiRigBuilder?.GetValue(__instance);
				obj2?.GetType().GetMethod("Build", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.Invoke(obj2, null);
				return false;
			}
			catch
			{
				return true;
			}
		}

		public static bool PlayerPickup_RightHandPickup_Prefix()
		{
			return !GunGamePlugin.Enabled.Value;
		}

		public static bool PlayerPickup_SwitchWeapons_Prefix()
		{
			return !GunGamePlugin.Enabled.Value;
		}

		public static bool PlayerPickup_LeftHandPickup_Prefix()
		{
			return !GunGamePlugin.Enabled.Value;
		}

		public static bool PlayerPickup_RpcLogic_DropObjectServer_Prefix(PlayerPickup __instance, GameObject obj, bool rightHand)
		{
			if (!GunGamePlugin.Enabled.Value)
			{
				return true;
			}
			if (!InstanceFinder.NetworkManager.IsServer)
			{
				return true;
			}
			string droppedName = (((Object)(object)obj != (Object)null) ? ((Object)obj).name.Replace("(Clone)", "").Trim() : "");
			bool flag = IsPlaceableDrop(droppedName);
			bool flag2 = IsThrowableDrop(droppedName);
			try
			{
				int pickupPlayerId = GetPickupPlayerId(__instance);
				int weaponIndex = ((pickupPlayerId >= 0) ? GetCurrentWeaponIndex(pickupPlayerId) : 0);
				bool rightHand2;
				bool flag3 = TryGetHeldObjectHand(__instance, obj, out rightHand2);
				if (IsUnsafeDropObject(obj) || IsDeathOrRespawnDrop(__instance, pickupPlayerId))
				{
					if (flag3)
					{
						ClearHeldHand(__instance, rightHand2);
					}
					return false;
				}
				if ((flag || flag2) && (Object)(object)obj != (Object)null)
				{
					obj.transform.SetParent((Transform)null);
				}
				if (!flag3)
				{
					return false;
				}
				if (pickupPlayerId >= 0 && GunGameWeaponManager.IsDropProtected(pickupPlayerId) && IsProtectedHeldDrop(__instance, obj, rightHand2))
				{
					return false;
				}
				object obj2 = ((object)GameManager.Instance) ?? ((object)GunGamePlugin.Instance);
				if (obj2 != null)
				{
					((MonoBehaviour)obj2).StartCoroutine(DeferredDropCleanup(__instance, obj, flag, flag2, pickupPlayerId, weaponIndex, rightHand2));
				}
			}
			catch
			{
			}
			return false;
		}

		public static bool PlayerPickup_RpcLogic_DropObjectObserver_Prefix(PlayerPickup __instance, GameObject obj, bool rightHand)
		{
			if (!GunGamePlugin.Enabled.Value)
			{
				return true;
			}
			try
			{
				int pickupPlayerId = GetPickupPlayerId(__instance);
				if (IsUnsafeDropObject(obj) || IsDeathOrRespawnDrop(__instance, pickupPlayerId))
				{
					return false;
				}
			}
			catch
			{
				return false;
			}
			return true;
		}

		private static int GetPickupPlayerId(PlayerPickup pickup)
		{
			try
			{
				int? obj;
				if (pickup == null)
				{
					obj = null;
				}
				else
				{
					PlayerValues playerValues = pickup.playerValues;
					obj = ((playerValues == null) ? ((int?)null) : playerValues.sync___get_value_playerClient()?.PlayerId);
				}
				return obj ?? (-1);
			}
			catch
			{
				return -1;
			}
		}

		private static bool IsUnsafeDropObject(GameObject obj)
		{
			if ((Object)(object)obj == (Object)null)
			{
				return true;
			}
			try
			{
				return (Object)(object)obj.GetComponent<ItemBehaviour>() == (Object)null || (Object)(object)obj.GetComponent<Weapon>() == (Object)null;
			}
			catch
			{
				return true;
			}
		}

		private static bool IsDeathOrRespawnDrop(PlayerPickup pickup, int playerId)
		{
			if (playerId >= 0 && (_playersAwaitingRespawn.Contains(playerId) || _respawnInProgress.Contains(playerId)))
			{
				return true;
			}
			try
			{
				if ((Object)(object)pickup == (Object)null || !((Component)pickup).gameObject.activeInHierarchy)
				{
					return true;
				}
				PlayerHealth componentInParent = ((Component)pickup).GetComponentInParent<PlayerHealth>();
				if ((Object)(object)componentInParent == (Object)null)
				{
					return false;
				}
				return componentInParent.sync___get_value_health() <= 0f || componentInParent.sync___get_value_isKilled();
			}
			catch
			{
				return true;
			}
		}

		private static void ClearHeldHand(PlayerPickup pickup, bool rightHand)
		{
			if ((Object)(object)pickup == (Object)null)
			{
				return;
			}
			try
			{
				if (rightHand)
				{
					pickup.sync___set_value_hasObjectInHand(false, true);
					pickup.sync___set_value_objInHand((GameObject)null, true);
				}
				else
				{
					pickup.sync___set_value_hasObjectInLeftHand(false, true);
					pickup.sync___set_value_objInLeftHand((GameObject)null, true);
				}
			}
			catch
			{
			}
		}

		private static bool TryGetHeldObjectHand(PlayerPickup pickup, GameObject obj, out bool rightHand)
		{
			rightHand = true;
			if ((Object)(object)pickup == (Object)null || (Object)(object)obj == (Object)null)
			{
				return false;
			}
			if ((Object)(object)pickup.sync___get_value_objInHand() == (Object)(object)obj)
			{
				return true;
			}
			if (pickup.sync___get_value_hasObjectInLeftHand() && (Object)(object)pickup.sync___get_value_objInLeftHand() == (Object)(object)obj)
			{
				rightHand = false;
				return true;
			}
			return false;
		}

		private static bool IsPlaceableDrop(string droppedName)
		{
			switch (droppedName)
			{
			default:
				return droppedName == "tptrap";
			case "Claymore":
			case "ProximityMine":
			case "APMine":
			case "Teleport Mine":
			case "TPTrap":
				return true;
			}
		}

		private static bool IsThrowableDrop(string droppedName)
		{
			switch (droppedName)
			{
			default:
				return droppedName == "repulsiongrenade";
			case "HandGrenade":
			case "GlandGrenade":
			case "Repulsion Grenade":
			case "RepulsionGrenade":
			case "RepulsorGrenadeMerged":
			case "KBGrenade":
				return true;
			}
		}

		private static bool IsProtectedHeldDrop(PlayerPickup pickup, GameObject obj, bool rightHand)
		{
			if ((Object)(object)pickup == (Object)null || (Object)(object)obj == (Object)null)
			{
				return false;
			}
			if ((Object)(object)(rightHand ? pickup.sync___get_value_objInHand() : (pickup.sync___get_value_hasObjectInLeftHand() ? pickup.sync___get_value_objInLeftHand() : null)) != (Object)(object)obj)
			{
				return false;
			}
			Weapon component = obj.GetComponent<Weapon>();
			if ((Object)(object)component == (Object)null)
			{
				return false;
			}
			try
			{
				return component.sync___get_value_currentAmmo() > 0;
			}
			catch
			{
				return false;
			}
		}

		private static IEnumerator DeferredDropCleanup(PlayerPickup pickup, GameObject obj, bool isPlaceable, bool isThrowable, int playerId, int weaponIndex, bool rightHand)
		{
			yield return null;
			try
			{
				if (rightHand)
				{
					pickup.sync___set_value_hasObjectInHand(false, true);
					pickup.sync___set_value_objInHand((GameObject)null, true);
				}
				else
				{
					pickup.sync___set_value_hasObjectInLeftHand(false, true);
					pickup.sync___set_value_objInLeftHand((GameObject)null, true);
				}
			}
			catch
			{
			}
			if (!isPlaceable && !isThrowable && (Object)(object)obj != (Object)null)
			{
				NetworkObject component = obj.GetComponent<NetworkObject>();
				if ((Object)(object)component != (Object)null && component.IsSpawned)
				{
					try
					{
						InstanceFinder.ServerManager.Despawn(component, (DespawnType?)null);
					}
					catch
					{
					}
				}
				else
				{
					try
					{
						Object.Destroy((Object)(object)obj);
					}
					catch
					{
					}
				}
			}
			yield return (object)new WaitForSeconds(0.1f);
			if (playerId < 0 || GunGamePlugin.MatchOver)
			{
				yield break;
			}
			if (isPlaceable)
			{
				string handReplaceKey = GetHandReplaceKey(playerId, rightHand);
				if (!_pendingPlaceableReplace.Contains(handReplaceKey))
				{
					_pendingPlaceableReplace.Add(handReplaceKey);
					object obj5 = ((object)GameManager.Instance) ?? ((object)GunGamePlugin.Instance);
					if (obj5 != null)
					{
						((MonoBehaviour)obj5).StartCoroutine(EnsurePlaceableReplaced(playerId, rightHand));
					}
				}
			}
			else
			{
				GunGameWeaponManager.ReplaceWeaponInHand(playerId, weaponIndex, rightHand);
			}
		}

		private static IEnumerator DelayedKillWeaponGive(int killerId, int weaponIndex)
		{
			yield return (object)new WaitForSeconds(3f);
			if (GunGamePlugin.MatchOver)
			{
				yield break;
			}
			try
			{
				PlayerPickup val = GunGamePlugin.FindPickupForPlayerId(killerId);
				if ((Object)(object)val != (Object)null && !val.sync___get_value_hasObjectInHand())
				{
					GunGameWeaponManager.GiveWeaponToPlayer(killerId, weaponIndex);
				}
			}
			catch
			{
			}
		}

		private static IEnumerator DelayedInitialSpawnFallback(int playerId)
		{
			yield return (object)new WaitForSeconds(7f);
			if (GunGamePlugin.MatchOver)
			{
				yield break;
			}
			try
			{
				if (!GunGameWeaponManager.IsGivingWeapon(playerId))
				{
					PlayerPickup val = GunGamePlugin.FindPickupForPlayerId(playerId);
					if ((Object)(object)val != (Object)null && !val.sync___get_value_hasObjectInHand())
					{
						GunGameWeaponManager.GiveWeaponToPlayer(playerId, GetCurrentWeaponIndex(playerId));
					}
				}
			}
			catch
			{
			}
		}

		private static IEnumerator DelayedRespawnWeaponFallback(int playerId)
		{
			yield return (object)new WaitForSeconds(3f);
			if (GunGamePlugin.MatchOver)
			{
				yield break;
			}
			try
			{
				if (!GunGameWeaponManager.IsGivingWeapon(playerId))
				{
					PlayerPickup val = GunGamePlugin.FindPickupForPlayerId(playerId);
					if ((Object)(object)val != (Object)null && !val.sync___get_value_hasObjectInHand())
					{
						GunGameWeaponManager.GiveWeaponToPlayer(playerId, GetCurrentWeaponIndex(playerId));
					}
				}
			}
			catch
			{
			}
		}

		private static IEnumerator EnsurePlaceableReplaced(int playerId, bool rightHand)
		{
			bool gave = false;
			try
			{
				for (int attempt = 0; attempt < 12; attempt++)
				{
					yield return (object)new WaitForSeconds(0.5f);
					if (GunGamePlugin.MatchOver)
					{
						yield break;
					}
					if (GunGameWeaponManager.IsGivingWeaponInHand(playerId, rightHand))
					{
						continue;
					}
					PlayerPickup val = GunGamePlugin.FindPickupForPlayerId(playerId);
					if (!((Object)(object)val == (Object)null))
					{
						if (IsHandEmpty(val, rightHand))
						{
							int currentWeaponIndex = GetCurrentWeaponIndex(playerId);
							GunGameWeaponManager.ReplaceWeaponInHand(playerId, currentWeaponIndex, rightHand);
						}
						yield break;
					}
				}
				if (!gave && !GunGamePlugin.MatchOver)
				{
					PlayerPickup val2 = GunGamePlugin.FindPickupForPlayerId(playerId);
					if ((Object)(object)val2 != (Object)null && IsHandEmpty(val2, rightHand))
					{
						GunGameWeaponManager.ReplaceWeaponInHand(playerId, GetCurrentWeaponIndex(playerId), rightHand);
					}
				}
			}
			finally
			{
				_pendingPlaceableReplace.Remove(GetHandReplaceKey(playerId, rightHand));
			}
		}

		private static string GetHandReplaceKey(int playerId, bool rightHand)
		{
			return playerId + (rightHand ? ":R" : ":L");
		}

		private static bool IsHandEmpty(PlayerPickup pickup, bool rightHand)
		{
			if ((Object)(object)pickup == (Object)null)
			{
				return false;
			}
			if (!rightHand)
			{
				return !pickup.sync___get_value_hasObjectInLeftHand();
			}
			return !pickup.sync___get_value_hasObjectInHand();
		}

		public static bool RoundManager_CmdEndRound_Prefix(int winningTeamId)
		{
			if (!GunGamePlugin.MatchOver)
			{
				return false;
			}
			return true;
		}

		private static IEnumerator WinSequenceCoroutine(int winnerPlayerId)
		{
			yield return (object)new WaitForSeconds(1.5f);
			bool endRoundCalled = false;
			try
			{
				int playerTeam = GetPlayerTeam(winnerPlayerId);
				BroadcastChat("<b><color=yellow>[Gun Game]</color></b> <b><color=white>" + GetPlayerName(winnerPlayerId) + "</color></b> wins the round!");
				if ((Object)(object)ScoreManager.Instance != (Object)null)
				{
					ScoreManager.Instance.AddRoundScore(playerTeam, 1);
				}
				if (_miRoundWon != null)
				{
					_miRoundWon.Invoke(GameManager.Instance, new object[1] { playerTeam });
				}
				if ((Object)(object)RoundManager.Instance != (Object)null)
				{
					RoundManager.Instance.CmdEndRound(playerTeam);
					endRoundCalled = true;
				}
			}
			catch
			{
			}
			yield return (object)new WaitForSeconds(4f);
			if (endRoundCalled)
			{
				try
				{
					if ((Object)(object)SceneMotor.Instance != (Object)null)
					{
						SceneMotor.Instance.ChangeNetworkScene();
					}
				}
				catch
				{
				}
			}
			GunGamePlugin.MatchOver = false;
			ResetState();
		}

		private static Type GetParticleSystemType()
		{
			if (_particleSystemType != null)
			{
				return _particleSystemType;
			}
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			for (int i = 0; i < assemblies.Length; i++)
			{
				Type type = assemblies[i].GetType("UnityEngine.ParticleSystem");
				if (type != null)
				{
					_particleSystemType = type;
					break;
				}
			}
			return _particleSystemType;
		}

		private static void CleanupBloodAndHats()
		{
			try
			{
				Type particleSystemType = GetParticleSystemType();
				if (particleSystemType != null)
				{
					Object[] array = Object.FindObjectsOfType(particleSystemType, true);
					foreach (Object val in array)
					{
						try
						{
							Component val2 = (Component)(object)((val is Component) ? val : null);
							if ((Object)(object)val2 != (Object)null && (Object)(object)val2.transform.parent == (Object)null)
							{
								Object.Destroy((Object)(object)val2.gameObject);
							}
						}
						catch
						{
						}
					}
				}
				HatPosition[] array2 = Object.FindObjectsOfType<HatPosition>(true);
				foreach (HatPosition val3 in array2)
				{
					try
					{
						if ((Object)(object)((Component)val3).transform.parent == (Object)null)
						{
							Object.Destroy((Object)(object)((Component)val3).gameObject);
						}
					}
					catch
					{
					}
				}
			}
			catch
			{
			}
		}

		internal static void CleanupWorldEffects()
		{
			try
			{
				foreach (KeyValuePair<int, GameObject> playerRagdoll in _playerRagdolls)
				{
					try
					{
						if ((Object)(object)playerRagdoll.Value != (Object)null)
						{
							Object.Destroy((Object)(object)playerRagdoll.Value);
						}
					}
					catch
					{
					}
				}
				_playerRagdolls.Clear();
				RagdollDress[] array = Object.FindObjectsOfType<RagdollDress>(true);
				foreach (RagdollDress val in array)
				{
					try
					{
						Object.Destroy((Object)(object)((Component)val).gameObject);
					}
					catch
					{
					}
				}
			}
			catch
			{
			}
			CleanupBloodAndHats();
		}

		private static void ScheduleRespawn(int deadPlayerId)
		{
			if (deadPlayerId >= 0 && !GunGamePlugin.MatchOver && !((Object)(object)GameManager.Instance == (Object)null) && !((Object)(object)InstanceFinder.NetworkManager == (Object)null) && InstanceFinder.NetworkManager.IsServer)
			{
				if (!_respawnRequestSeq.ContainsKey(deadPlayerId))
				{
					_respawnRequestSeq[deadPlayerId] = 0;
				}
				_playersAwaitingRespawn.Add(deadPlayerId);
				int num = ++_respawnRequestSeq[deadPlayerId];
				float num2 = Mathf.Max(0.25f, GunGamePlugin.RespawnDelay.Value);
				_nextRespawnRecoveryTime[deadPlayerId] = Time.time + num2 + 6.75f + 1f;
				LogRespawn(deadPlayerId, 0, $"queued sequence={num} delay={num2:0.00}s");
				((MonoBehaviour)GameManager.Instance).StartCoroutine(SinglePlayerRespawnCoroutine(deadPlayerId, num, num2));
			}
		}

		public static void ServerRespawnWatchdogUpdate()
		{
			if (!GunGamePlugin.Enabled.Value || GunGamePlugin.MatchOver || (Object)(object)InstanceFinder.NetworkManager == (Object)null || !InstanceFinder.NetworkManager.IsServer || Time.time < _nextRespawnWatchdogTime)
			{
				return;
			}
			_nextRespawnWatchdogTime = Time.time + 0.5f;
			int[] array = _playersAwaitingRespawn.ToArray();
			foreach (int num in array)
			{
				if (!_respawnInProgress.Contains(num))
				{
					PlayerManager pm = FindPlayerManagerForId(num);
					float value;
					if (IsPlayerRespawnValid(num, pm, out var _))
					{
						CompleteRespawn(num, pm, "watchdog found valid player");
					}
					else if (!_nextRespawnRecoveryTime.TryGetValue(num, out value) || !(Time.time < value))
					{
						LogRespawn(num, 0, "watchdog restarting failed respawn");
						ScheduleRespawn(num);
					}
				}
			}
		}

		private static IEnumerator SinglePlayerRespawnCoroutine(int deadPlayerId, int seq, float delay)
		{
			yield return (object)new WaitForSeconds(delay);
			if (GunGamePlugin.MatchOver || (Object)(object)GameManager.Instance == (Object)null || (Object)(object)InstanceFinder.NetworkManager == (Object)null || !InstanceFinder.NetworkManager.IsServer || !_respawnRequestSeq.TryGetValue(deadPlayerId, out var value) || value != seq)
			{
				yield break;
			}
			float gateTimeout = Time.time + 1.5f;
			while (_respawnInProgress.Contains(deadPlayerId) && Time.time < gateTimeout)
			{
				yield return null;
			}
			if (_respawnInProgress.Contains(deadPlayerId))
			{
				yield break;
			}
			_respawnInProgress.Add(deadPlayerId);
			bool spawned = false;
			PlayerManager spawnedManager = null;
			try
			{
				for (int attempt = 1; attempt <= 3; attempt++)
				{
					if (GunGamePlugin.MatchOver)
					{
						break;
					}
					PlayerManager val = FindPlayerManagerForId(deadPlayerId);
					if ((Object)(object)val == (Object)null)
					{
						LogRespawn(deadPlayerId, attempt, "missing PlayerManager");
						yield return (object)new WaitForSeconds(0.25f);
						continue;
					}
					CleanupRespawnArtifacts(deadPlayerId);
					if (!TryInvokeRespawn(val, deadPlayerId, attempt))
					{
						yield return (object)new WaitForSeconds(0.25f);
						continue;
					}
					string failureReason = "spawn did not become valid";
					float validationDeadline = Time.time + 2f;
					while (Time.time < validationDeadline && !GunGamePlugin.MatchOver)
					{
						if (_respawnRequestSeq.TryGetValue(deadPlayerId, out value) && value == seq)
						{
							val = FindPlayerManagerForId(deadPlayerId);
							if (IsPlayerRespawnValid(deadPlayerId, val, out failureReason))
							{
								spawned = true;
								spawnedManager = val;
								break;
							}
							yield return null;
							continue;
						}
						yield break;
					}
					if (spawned)
					{
						LogRespawn(deadPlayerId, attempt, "native respawn verified");
						break;
					}
					LogRespawn(deadPlayerId, attempt, "verify failed: " + failureReason);
					yield return (object)new WaitForSeconds(0.25f);
				}
			}
			finally
			{
				_respawnInProgress.Remove(deadPlayerId);
			}
			if (spawned)
			{
				CompleteRespawn(deadPlayerId, spawnedManager, "respawn finalized");
				yield break;
			}
			LogRespawn(deadPlayerId, 3, "respawn failed after all attempts");
			_nextRespawnRecoveryTime[deadPlayerId] = Time.time + 1f;
		}

		private static void CompleteRespawn(int playerId, PlayerManager pm, string source)
		{
			if (_playersAwaitingRespawn.Remove(playerId))
			{
				_nextRespawnRecoveryTime.Remove(playerId);
				ForcePlayerReady(pm);
				if (GunGameWeaponManager.HasPendingWeapon(playerId))
				{
					GunGameWeaponManager.ApplyPendingWeaponOnSpawn(playerId);
				}
				else
				{
					GunGameWeaponManager.GiveWeaponToPlayer(playerId, GetCurrentWeaponIndex(playerId));
				}
				GameManager instance = GameManager.Instance;
				if (instance != null)
				{
					((MonoBehaviour)instance).StartCoroutine(DelayedRespawnWeaponFallback(playerId));
				}
				LogRespawn(playerId, 0, source);
			}
		}

		private static bool TryInvokeRespawn(PlayerManager pm, int playerId, int attempt)
		{
			if (_miCmdRespawnLogic == null || (Object)(object)pm == (Object)null)
			{
				return false;
			}
			try
			{
				_miCmdRespawnLogic.Invoke(pm, null);
				LogRespawn(playerId, attempt, "native respawn invoked");
				return true;
			}
			catch (Exception ex)
			{
				Exception ex2 = ((ex is TargetInvocationException && ex.InnerException != null) ? ex.InnerException : ex);
				LogRespawn(playerId, attempt, "native respawn failed: " + ex2.GetType().Name + " - " + ex2.Message);
				return false;
			}
		}

		private static bool IsPlayerRespawnValid(int playerId, PlayerManager pm, out string reason)
		{
			reason = "";
			if ((Object)(object)pm == (Object)null)
			{
				reason = "missing PlayerManager";
				return false;
			}
			if ((Object)(object)pm.player == (Object)null)
			{
				reason = "missing player controller";
				return false;
			}
			GameObject gameObject = ((Component)pm.player).gameObject;
			if ((Object)(object)gameObject == (Object)null || !gameObject.activeInHierarchy)
			{
				reason = "inactive player object";
				return false;
			}
			PlayerValues component = gameObject.GetComponent<PlayerValues>();
			if ((((component == null) ? ((int?)null) : component.sync___get_value_playerClient()?.PlayerId) ?? (-1)) != playerId)
			{
				reason = "player id mismatch";
				return false;
			}
			PlayerHealth component2 = gameObject.GetComponent<PlayerHealth>();
			if ((Object)(object)component2 == (Object)null)
			{
				reason = "missing PlayerHealth";
				return false;
			}
			if (component2.sync___get_value_health() <= 0f || component2.sync___get_value_isKilled())
			{
				reason = "still dead";
				return false;
			}
			if ((Object)(object)gameObject.GetComponentInChildren<PlayerPickup>(true) == (Object)null)
			{
				reason = "missing PlayerPickup";
				return false;
			}
			NetworkObject component3 = gameObject.GetComponent<NetworkObject>();
			if ((Object)(object)component3 == (Object)null || !component3.IsSpawned)
			{
				reason = "player NetworkObject is not spawned";
				return false;
			}
			CharacterController component4 = gameObject.GetComponent<CharacterController>();
			if ((Object)(object)component4 == (Object)null || !((Collider)component4).enabled)
			{
				reason = "character controller is not ready";
				return false;
			}
			return true;
		}

		private static void ForcePlayerReady(PlayerManager pm)
		{
			if ((Object)(object)pm == (Object)null)
			{
				return;
			}
			try
			{
				pm.SetPlayerMove(true);
				if ((Object)(object)pm.player != (Object)null)
				{
					pm.player.sync___set_value_canMove(true, true);
					pm.player.startOfRound = false;
				}
				if ((Object)(object)PauseManager.Instance != (Object)null)
				{
					PauseManager.Instance.startRound = false;
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = GunGamePlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[GunGame Respawn] could not finalize player movement: " + ex.GetType().Name));
				}
			}
			GameManager instance = GameManager.Instance;
			if (instance != null)
			{
				((MonoBehaviour)instance).StartCoroutine(KeepPlayerMovable(pm, 4f));
			}
		}

		private static void CleanupRespawnArtifacts(int playerId)
		{
			try
			{
				if (_playerRagdolls.TryGetValue(playerId, out var value) && (Object)(object)value != (Object)null)
				{
					Object.Destroy((Object)(object)value);
				}
				_playerRagdolls.Remove(playerId);
				CleanupBloodAndHats();
			}
			catch
			{
			}
		}

		private static void LogRespawn(int playerId, int attempt, string message)
		{
			try
			{
				ManualLogSource log = GunGamePlugin.Log;
				if (log != null)
				{
					log.LogInfo((object)$"[GunGame Respawn] player={playerId} attempt={attempt}: {message}");
				}
			}
			catch
			{
			}
		}

		private static IEnumerator KeepPlayerMovable(PlayerManager pm, float duration)
		{
			float end = Time.time + duration;
			while (Time.time < end)
			{
				try
				{
					if ((Object)(object)pm != (Object)null)
					{
						pm.SetPlayerMove(true);
						if ((Object)(object)pm.player != (Object)null)
						{
							pm.player.sync___set_value_canMove(true, true);
							pm.player.startOfRound = false;
						}
						if ((Object)(object)PauseManager.Instance != (Object)null)
						{
							PauseManager.Instance.startRound = false;
						}
					}
				}
				catch
				{
				}
				yield return null;
			}
		}

		private static int FindKillerId(int deadPlayerId)
		{
			PlayerHealth val = FindPlayerHealth(deadPlayerId);
			if ((Object)(object)val == (Object)null)
			{
				return -1;
			}
			Transform killer = val.killer;
			if ((Object)(object)killer == (Object)null)
			{
				return -1;
			}
			ClientInstance componentInParent = ((Component)killer).GetComponentInParent<ClientInstance>(true);
			if ((Object)(object)componentInParent != (Object)null)
			{
				return componentInParent.PlayerId;
			}
			PlayerValues obj = ((Component)killer).GetComponentInParent<PlayerValues>(true) ?? ((Component)killer).GetComponentInChildren<PlayerValues>(true);
			int? num = ((obj == null) ? ((int?)null) : obj.sync___get_value_playerClient()?.PlayerId);
			if (num.HasValue)
			{
				int valueOrDefault = num.GetValueOrDefault();
				if (valueOrDefault >= 0)
				{
					return valueOrDefault;
				}
			}
			GameObject val2 = null;
			ProximityMine val3 = ((Component)killer).GetComponentInParent<ProximityMine>(true) ?? ((Component)killer).GetComponentInChildren<ProximityMine>(true);
			if ((Object)(object)val3 != (Object)null)
			{
				val2 = val3.sync___get_value__rootObject();
			}
			else
			{
				Claymore val4 = ((Component)killer).GetComponentInParent<Claymore>(true) ?? ((Component)killer).GetComponentInChildren<Claymore>(true);
				if ((Object)(object)val4 != (Object)null)
				{
					val2 = val4.sync___get_value__rootObject();
				}
			}
			if ((Object)(object)val2 != (Object)null)
			{
				int ownerIdFromRootObject = GetOwnerIdFromRootObject(val2);
				if (ownerIdFromRootObject >= 0)
				{
					return ownerIdFromRootObject;
				}
			}
			return -1;
		}

		public static bool DamageZone_OnEnable_Prefix(DamageZone __instance)
		{
			if (!GunGamePlugin.Enabled.Value)
			{
				return true;
			}
			try
			{
				Collider[] componentsInChildren = ((Component)__instance).GetComponentsInChildren<Collider>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					componentsInChildren[i].enabled = false;
				}
				if ((Object)(object)__instance.toDestroy != (Object)null)
				{
					Object.Destroy((Object)(object)__instance.toDestroy);
				}
				Object.Destroy((Object)(object)((Component)__instance).gameObject);
			}
			catch
			{
			}
			return false;
		}

		public static bool FirstPersonController_OnTriggerStay_Prefix(Collider col)
		{
			if (GunGamePlugin.Enabled.Value && ((Component)col).CompareTag("DamageZone"))
			{
				return false;
			}
			return true;
		}

		public static void PlayerHealth_ExplodeForAll_Postfix(PlayerHealth __instance)
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			if (!GunGamePlugin.Enabled.Value)
			{
				return;
			}
			try
			{
				PlayerValues playerValues = __instance.playerValues;
				int num = ((playerValues == null) ? ((int?)null) : playerValues.sync___get_value_playerClient()?.PlayerId) ?? (-1);
				if (num < 0)
				{
					return;
				}
				RagdollDress val = null;
				float num2 = float.MaxValue;
				RagdollDress[] array = Object.FindObjectsOfType<RagdollDress>(true);
				foreach (RagdollDress val2 in array)
				{
					float num3 = Vector3.Distance(((Component)val2).transform.position, ((Component)__instance).transform.position);
					if (num3 < num2)
					{
						num2 = num3;
						val = val2;
					}
				}
				if ((Object)(object)val != (Object)null)
				{
					_playerRagdolls[num] = ((Component)val).gameObject;
				}
			}
			catch
			{
			}
		}

		public static void PlayerValues_SetPlayerClient_Postfix(ClientInstance __0)
		{
			if (!GunGamePlugin.Enabled.Value || (Object)(object)__0 == (Object)null)
			{
				return;
			}
			try
			{
				int playerId = __0.PlayerId;
				if (playerId >= 0)
				{
					if (_playerRagdolls.TryGetValue(playerId, out var value) && (Object)(object)value != (Object)null)
					{
						Object.Destroy((Object)(object)value);
						_playerRagdolls.Remove(playerId);
					}
					CleanupBloodAndHats();
				}
			}
			catch
			{
			}
		}

		private static PlayerHealth FindPlayerHealth(int deadPlayerId)
		{
			PlayerHealth[] array = Object.FindObjectsOfType<PlayerHealth>(true);
			foreach (PlayerHealth val in array)
			{
				if (val != null)
				{
					PlayerValues playerValues = val.playerValues;
					if (((playerValues == null) ? ((int?)null) : playerValues.sync___get_value_playerClient()?.PlayerId) == deadPlayerId)
					{
						return val;
					}
				}
			}
			return null;
		}

		private static PlayerManager FindPlayerManagerForId(int playerId)
		{
			if (ClientInstance.playerInstances.TryGetValue(playerId, out var value) && (Object)(object)value != (Object)null)
			{
				return ((Component)value).GetComponent<PlayerManager>();
			}
			return null;
		}

		public static bool PauseManager_StartRoundDelay_Prefix(PauseManager __instance)
		{
			if (!GunGamePlugin.Enabled.Value)
			{
				return true;
			}
			try
			{
				__instance.InvokeRoundStarted();
				__instance.onStartRoundScreen = true;
				MonoBehaviour val = (MonoBehaviour)(((object)GunGamePlugin.Instance) ?? ((object)GameManager.Instance));
				if ((Object)(object)val != (Object)null)
				{
					val.StartCoroutine(ClearOnStartRoundScreen(__instance));
				}
			}
			catch
			{
			}
			return false;
		}

		private static IEnumerator ClearOnStartRoundScreen(PauseManager pm)
		{
			yield return (object)new WaitForSeconds(0.8f);
			if ((Object)(object)pm != (Object)null)
			{
				pm.onStartRoundScreen = false;
			}
		}

		public static bool ProximityMine_KillShockWave_Prefix(ProximityMine __instance)
		{
			GameObject val = __instance.sync___get_value__rootObject();
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			if ((Object)(object)val.GetComponent<FirstPersonController>() == (Object)null)
			{
				return false;
			}
			return true;
		}

		public static bool Claymore_KillShockWave_Prefix(Claymore __instance)
		{
			GameObject val = __instance.sync___get_value__rootObject();
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			if ((Object)(object)val.GetComponent<FirstPersonController>() == (Object)null)
			{
				return false;
			}
			return true;
		}

		public static void Minigun_Update_Postfix(Minigun __instance)
		{
			if (!GunGamePlugin.Enabled.Value || (Object)(object)__instance == (Object)null)
			{
				return;
			}
			try
			{
				if ((Object)(object)__instance == (Object)null || ((Weapon)__instance).sync___get_value_currentAmmo() > 0)
				{
					if ((Object)(object)__instance != (Object)null)
					{
						_minigunDropQueued.Remove(((Object)__instance).GetInstanceID());
					}
					return;
				}
				object obj = ((Weapon)__instance).behaviour?.playerPickup;
				if (obj == null)
				{
					GameObject rootObject = ((Weapon)__instance).rootObject;
					obj = ((rootObject != null) ? rootObject.GetComponent<PlayerPickup>() : null);
				}
				PlayerPickup val = (PlayerPickup)obj;
				if ((Object)(object)val == (Object)null || !TryGetHeldObjectHand(val, ((Component)__instance).gameObject, out var rightHand))
				{
					return;
				}
				int instanceID = ((Object)__instance).GetInstanceID();
				if (_minigunDropQueued.Add(instanceID))
				{
					if (rightHand)
					{
						val.RightHandDrop();
					}
					else
					{
						val.LeftHandDrop();
					}
				}
			}
			catch
			{
			}
		}

		public static bool DualLauncher_SetBool_Prefix(DualLauncher __instance, bool value)
		{
			if (!GunGamePlugin.Enabled.Value || (Object)(object)__instance == (Object)null || !value)
			{
				return true;
			}
			try
			{
				object obj = ((Weapon)(__instance?)).behaviour?.playerPickup;
				if (obj == null)
				{
					if (__instance == null)
					{
						obj = null;
					}
					else
					{
						GameObject rootObject = ((Weapon)__instance).rootObject;
						obj = ((rootObject != null) ? rootObject.GetComponent<PlayerPickup>() : null);
					}
				}
				PlayerPickup val = (PlayerPickup)obj;
				if ((Object)(object)__instance == (Object)null || (Object)(object)val == (Object)null)
				{
					return true;
				}
				if (!TryGetHeldObjectHand(val, ((Component)__instance).gameObject, out var rightHand))
				{
					return true;
				}
				PlayerValues playerValues = val.playerValues;
				int num = ((playerValues == null) ? ((int?)null) : playerValues.sync___get_value_playerClient()?.PlayerId) ?? (-1);
				if (num < 0)
				{
					return true;
				}
				string handReplaceKey = GetHandReplaceKey(num, rightHand);
				if (_suppressThrowableOpenUntil.TryGetValue(handReplaceKey, out var value2) && Time.unscaledTime <= value2)
				{
					return false;
				}
			}
			catch
			{
			}
			return true;
		}

		public static void WeaponHandSpawner_SpawnObject_Postfix(WeaponHandSpawner __instance)
		{
			if (!GunGamePlugin.Enabled.Value || (Object)(object)__instance == (Object)null)
			{
				return;
			}
			try
			{
				object obj = ((Weapon)(__instance?)).behaviour?.playerPickup;
				if (obj == null)
				{
					if (__instance == null)
					{
						obj = null;
					}
					else
					{
						GameObject rootObject = ((Weapon)__instance).rootObject;
						obj = ((rootObject != null) ? rootObject.GetComponent<PlayerPickup>() : null);
					}
				}
				PlayerPickup val = (PlayerPickup)obj;
				if (!((Object)(object)__instance == (Object)null) && !((Object)(object)val == (Object)null) && TryGetHeldObjectHand(val, ((Component)__instance).gameObject, out var rightHand) && IsThrowableHeldWeapon((!rightHand) ? val.sync___get_value_objInHand() : (val.sync___get_value_hasObjectInLeftHand() ? val.sync___get_value_objInLeftHand() : null)))
				{
					PlayerValues playerValues = val.playerValues;
					int num = ((playerValues == null) ? ((int?)null) : playerValues.sync___get_value_playerClient()?.PlayerId) ?? (-1);
					if (num >= 0)
					{
						_suppressThrowableOpenUntil[GetHandReplaceKey(num, !rightHand)] = Time.unscaledTime + 0.35f;
					}
				}
			}
			catch
			{
			}
		}

		private static bool IsThrowableHeldWeapon(GameObject obj)
		{
			if ((Object)(object)obj == (Object)null)
			{
				return false;
			}
			if (!IsThrowableDrop(((Object)obj).name?.Replace("(Clone)", "").Trim() ?? ""))
			{
				return (Object)(object)obj.GetComponent<DualLauncher>() != (Object)null;
			}
			return true;
		}

		public static bool MatchLogs_RpcSendChatLine_Prefix()
		{
			return !GunGamePlugin.Enabled.Value;
		}

		private static int GetOwnerIdFromRootObject(GameObject root)
		{
			if ((Object)(object)root == (Object)null)
			{
				return -1;
			}
			ClientInstance val = root.GetComponentInParent<ClientInstance>(true) ?? root.GetComponentInChildren<ClientInstance>(true);
			if ((Object)(object)val != (Object)null)
			{
				return val.PlayerId;
			}
			PlayerValues obj = root.GetComponentInParent<PlayerValues>(true) ?? root.GetComponentInChildren<PlayerValues>(true);
			int num = ((obj == null) ? ((int?)null) : obj.sync___get_value_playerClient()?.PlayerId) ?? (-1);
			if (num >= 0)
			{
				return num;
			}
			foreach (KeyValuePair<int, ClientInstance> playerInstance in ClientInstance.playerInstances)
			{
				try
				{
					ClientInstance value = playerInstance.Value;
					PlayerManager val2 = ((value != null) ? ((Component)value).GetComponent<PlayerManager>() : null);
					if (!((Object)(object)val2 == (Object)null))
					{
						if ((Object)(object)val2.player != (Object)null && ((Object)(object)((Component)val2.player).gameObject == (Object)(object)root || root.transform.IsChildOf(((Component)val2.player).transform)))
						{
							return playerInstance.Key;
						}
						object? obj2 = _fiSpawnedObject?.GetValue(val2);
						GameObject val3 = (GameObject)((obj2 is GameObject) ? obj2 : null);
						if ((Object)(object)val3 != (Object)null && ((Object)(object)val3 == (Object)(object)root || root.transform.IsChildOf(val3.transform)))
						{
							return playerInstance.Key;
						}
					}
				}
				catch
				{
				}
			}
			return -1;
		}

		private static void ClearPlacedExplosivesForPlayer(int playerId)
		{
			try
			{
				ProximityMine[] array = Object.FindObjectsOfType<ProximityMine>(true);
				foreach (ProximityMine val in array)
				{
					try
					{
						if (GetOwnerIdFromRootObject(val.sync___get_value__rootObject()) == playerId)
						{
							NetworkObject component = ((Component)val).GetComponent<NetworkObject>();
							if ((Object)(object)component != (Object)null && component.IsSpawned)
							{
								InstanceFinder.ServerManager.Despawn(component, (DespawnType?)null);
							}
							else
							{
								Object.Destroy((Object)(object)((Component)val).gameObject);
							}
						}
					}
					catch
					{
					}
				}
				Claymore[] array2 = Object.FindObjectsOfType<Claymore>(true);
				foreach (Claymore val2 in array2)
				{
					try
					{
						if (GetOwnerIdFromRootObject(val2.sync___get_value__rootObject()) == playerId)
						{
							NetworkObject component2 = ((Component)val2).GetComponent<NetworkObject>();
							if ((Object)(object)component2 != (Object)null && component2.IsSpawned)
							{
								InstanceFinder.ServerManager.Despawn(component2, (DespawnType?)null);
							}
							else
							{
								Object.Destroy((Object)(object)((Component)val2).gameObject);
							}
						}
					}
					catch
					{
					}
				}
			}
			catch
			{
			}
		}

		internal static void BroadcastChat(string text)
		{
			if ((Object)(object)MatchLogs.Instance == (Object)null || (Object)(object)InstanceFinder.NetworkManager == (Object)null || !InstanceFinder.NetworkManager.IsServer)
			{
				return;
			}
			try
			{
				_miMatchLogsSendToAll?.Invoke(MatchLogs.Instance, new object[1] { text });
			}
			catch
			{
			}
		}

		private static string GetPlayerName(int playerId)
		{
			try
			{
				if (ClientInstance.playerInstances.TryGetValue(playerId, out var value) && (Object)(object)value != (Object)null)
				{
					return value.PlayerNameTag;
				}
			}
			catch
			{
			}
			return $"Player {playerId}";
		}

		private static int GetPlayerTeam(int playerId)
		{
			if ((Object)(object)ScoreManager.Instance != (Object)null)
			{
				try
				{
					return ScoreManager.Instance.GetTeamId(playerId);
				}
				catch
				{
				}
			}
			return playerId;
		}
	}
	public static class GunGameWeaponManager
	{
		private static Dictionary<int, int> _pendingWeaponIndex = new Dictionary<int, int>();

		private static MethodInfo _miSetObjectInHandRpcLogic;

		private static MethodInfo _miSetObjectInHandObserver;

		private static MethodInfo _miSetObjectInHandObserverLogic;

		private static bool _initialSpawnDelayDone = false;

		private static Dictionary<int, int> _giveSequence = new Dictionary<int, int>();

		private static HashSet<int> _givingInProgress = new HashSet<int>();

		private static HashSet<string> _handGivingInProgress = new HashSet<string>();

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

		internal static MethodInfo SetObjectInHandObserverLogic
		{
			get
			{
				CacheMethods();
				return _miSetObjectInHandObserverLogic;
			}
		}

		public static void QueueWeaponUpgrade(int playerId, int weaponIndex)
		{
			_pendingWeaponIndex[playerId] = weaponIndex;
		}

		public static int GetAndClearPendingWeapon(int playerId)
		{
			if (_pendingWeaponIndex.TryGetValue(playerId, out var value))
			{
				_pendingWeaponIndex.Remove(playerId);
				return value;
			}
			return -1;
		}

		public static bool HasPendingWeapon(int playerId)
		{
			return _pendingWeaponIndex.ContainsKey(playerId);
		}

		public static void ClearPendingForPlayer(int playerId)
		{
			_pendingWeaponIndex.Remove(playerId);
			_giveSequence.Remove(playerId);
			_dropProtectionUntil.Remove(playerId);
		}

		public static void ClearAllPending()
		{
			_pendingWeaponIndex.Clear();
			_giveSequence.Clear();
			_givingInProgress.Clear();
			_handGivingInProgress.Clear();
			_dropProtectionUntil.Clear();
			_initialSpawnDelayDone = false;
		}

		private static void CacheMethods()
		{
			if (!(_miSetObjectInHandRpcLogic != null))
			{
				_miSetObjectInHandRpcLogic = typeof(PlayerPickup).GetMethod("RpcLogic___SetObjectInHandServer_46969756", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				_miSetObjectInHandObserver = typeof(PlayerPickup).GetMethod("SetObjectInHandObserver", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				_miSetObjectInHandObserverLogic = typeof(PlayerPickup).GetMethod("RpcLogic___SetObjectInHandObserver_46969756", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			}
		}

		public static bool IsGivingWeapon(int playerId)
		{
			if (!_givingInProgress.Contains(playerId))
			{
				return IsReplacingAnyHand(playerId);
			}
			return true;
		}

		public static bool IsGivingWeaponInHand(int playerId, bool rightHand)
		{
			if (!_givingInProgress.Contains(playerId))
			{
				return _handGivingInProgress.Contains(GetHandGiveKey(playerId, rightHand));
			}
			return true;
		}

		private static bool IsReplacingAnyHand(int playerId)
		{
			string value = playerId + ":";
			foreach (string item in _handGivingInProgress)
			{
				if (item.StartsWith(value, StringComparison.Ordinal))
				{
					return true;
				}
			}
			return false;
		}

		private static string GetHandGiveKey(int playerId, bool rightHand)
		{
			return playerId + (rightHand ? ":R" : ":L");
		}

		public static int GetGiveSequence(int playerId)
		{
			if (!_giveSequence.TryGetValue(playerId, out var value))
			{
				return 0;
			}
			return value;
		}

		public static void GiveWeaponToPlayer(int playerId, int weaponIndex)
		{
			if (!((Object)(object)InstanceFinder.NetworkManager == (Object)null) && InstanceFinder.NetworkManager.IsServer && !GunGamePlugin.MatchOver)
			{
				if (!_giveSequence.ContainsKey(playerId))
				{
					_giveSequence[playerId] = 0;
				}
				int seq = ++_giveSequence[playerId];
				MonoBehaviour val = (MonoBehaviour)(((object)GameManager.Instance) ?? ((object)GunGamePlugin.Instance));
				if ((Object)(object)val != (Object)null)
				{
					val.StartCoroutine(GiveWeaponCoroutine(playerId, weaponIndex, seq));
				}
			}
		}

		public static void ReplaceWeaponInHand(int playerId, int weaponIndex, bool rightHand)
		{
			if (!((Object)(object)InstanceFinder.NetworkManager == (Object)null) && InstanceFinder.NetworkManager.IsServer && !GunGamePlugin.MatchOver)
			{
				MonoBehaviour val = (MonoBehaviour)(((object)GameManager.Instance) ?? ((object)GunGamePlugin.Instance));
				if ((Object)(object)val != (Object)null)
				{
					val.StartCoroutine(ReplaceWeaponInHandCoroutine(playerId, weaponIndex, rightHand));
				}
			}
		}

		private static IEnumerator GiveWeaponCoroutine(int playerId, int weaponIndex, int seq)
		{
			NetworkManager nm = InstanceFinder.NetworkManager;
			if ((Object)(object)nm == (Object)null || !nm.IsServer)
			{
				yield break;
			}
			_givingInProgress.Add(playerId);
			bool flag = false;
			try
			{
				if ((Object)(object)GunGamePlugin.GetOrderedWeaponPrefab(weaponIndex) == (Object)null)
				{
					flag = true;
				}
			}
			finally
			{
				if (flag)
				{
					_givingInProgress.Remove(playerId);
				}
			}
			if (flag)
			{
				yield break;
			}
			float num = (_initialSpawnDelayDone ? 0f : 2f);
			_initialSpawnDelayDone = true;
			yield return (object)new WaitForSeconds(num);
			if (GunGamePlugin.MatchOver)
			{
				_givingInProgress.Remove(playerId);
				yield break;
			}
			if (_giveSequence.TryGetValue(playerId, out var value) && value != seq)
			{
				_givingInProgress.Remove(playerId);
				yield break;
			}
			PlayerPickup pickup = null;
			for (int attempt = 0; attempt < 8; attempt++)
			{
				pickup = GunGamePlugin.FindPickupForPlayerId(playerId);
				if ((Object)(object)pickup != (Object)null)
				{
					break;
				}
				yield return (object)new WaitForSeconds(0.5f);
			}
			if ((Object)(object)pickup == (Object)null)
			{
				_givingInProgress.Remove(playerId);
				yield break;
			}
			while (HasUnplacedTeleportMine(pickup))
			{
				if (GunGamePlugin.MatchOver)
				{
					_givingInProgress.Remove(playerId);
					yield break;
				}
				if (_giveSequence.TryGetValue(playerId, out var value2) && value2 != seq)
				{
					_givingInProgress.Remove(playerId);
					yield break;
				}
				yield return (object)new WaitForSeconds(0.25f);
				pickup = GunGamePlugin.FindPickupForPlayerId(playerId);
				if ((Object)(object)pickup == (Object)null)
				{
					_givingInProgress.Remove(playerId);
					yield break;
				}
			}
			GameObject heldRight = pickup.sync___get_value_objInHand();
			GameObject heldLeft = (pickup.sync___get_value_hasObjectInLeftHand() ? pickup.sync___get_value_objInLeftHand() : null);
			pickup.sync___set_value_hasObjectInHand(false, true);
			pickup.sync___set_value_hasObjectInLeftHand(false, true);
			pickup.sync___set_value_objInHand((GameObject)null, true);
			pickup.sync___set_value_objInLeftHand((GameObject)null, true);
			yield return (object)new WaitForSeconds(0.3f);
			if (_giveSequence.TryGetValue(playerId, out var value3) && value3 != seq)
			{
				_givingInProgress.Remove(playerId);
				yield break;
			}
			GameObject[] array = (GameObject[])(object)new GameObject[2] { heldRight, heldLeft };
			foreach (GameObject val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				NetworkObject componentInParent = val.GetComponentInParent<NetworkObject>();
				if ((Object)(object)componentInParent != (Object)null)
				{
					try
					{
						InstanceFinder.ServerManager.Despawn(componentInParent, (DespawnType?)null);
					}
					catch
					{
					}
				}
				else
				{
					try
					{
						Object.Destroy((Object)(object)val);
					}
					catch
					{
					}
				}
			}
			try
			{
				pickup = GunGamePlugin.FindPickupForPlayerId(playerId);
				if ((Object)(object)pickup != (Object)null)
				{
					ItemBehaviour[] componentsInChildren = ((Component)((Component)pickup).transform.root).GetComponentsInChildren<ItemBehaviour>(true);
					foreach (ItemBehaviour val2 in componentsInChildren)
					{
						if ((Object)(object)val2 == (Object)null)
						{
							continue;
						}
						NetworkObject component = ((Component)val2).GetComponent<NetworkObject>();
						if ((Object)(object)component != (Object)null && component.IsSpawned)
						{
							try
							{
								InstanceFinder.ServerManager.Despawn(component, (DespawnType?)null);
							}
							catch
							{
							}
						}
						else
						{
							try
							{
								Object.Destroy((Object)(object)((Component)val2).gameObject);
							}
							catch
							{
							}
						}
					}
				}
			}
			catch
			{
			}
			yield return (object)new WaitForSeconds(0.15f);
			pickup = GunGamePlugin.FindPickupForPlayerId(playerId);
			if ((Object)(object)pickup == (Object)null)
			{
				_givingInProgress.Remove(playerId);
				yield break;
			}
			GameObject playerGO = null;
			try
			{
				if (ClientInstance.playerInstances.TryGetValue(playerId, out var value4))
				{
					PlayerManager val3 = ((value4 != null) ? ((Component)value4).GetComponent<PlayerManager>() : null);
					object obj6;
					if (val3 == null)
					{
						obj6 = null;
					}
					else
					{
						FirstPersonController player = val3.player;
						obj6 = ((player != null) ? ((Component)player).gameObject : null);
					}
					playerGO = (GameObject)obj6;
				}
			}
			catch
			{
			}
			if ((Object)(object)playerGO == (Object)null)
			{
				playerGO = ((Component)((Component)pickup).transform.root).gameObject;
			}
			GameObject orderedWeaponPrefab = GunGamePlugin.GetOrderedWeaponPrefab(weaponIndex);
			GameObject secondPrefab = GunGamePlugin.GetSecondWeaponPrefab(weaponIndex);
			GameObject rightWeapon = null;
			GameObject leftWeapon = null;
			ItemBehaviour rightIb = null;
			ItemBehaviour leftIb = null;
			try
			{
				rightWeapon = SpawnWeaponPrefab(nm, orderedWeaponPrefab, playerGO, out rightIb);
				if ((Object)(object)secondPrefab != (Object)null)
				{
					leftWeapon = SpawnWeaponPrefab(nm, secondPrefab, playerGO, out leftIb);
				}
			}
			catch (Exception)
			{
				DespawnOrDestroy(rightWeapon);
				DespawnOrDestroy(leftWeapon);
				_givingInProgress.Remove(playerId);
				yield break;
			}
			yield return (object)new WaitForSeconds(0.1f);
			if ((Object)(object)rightWeapon == (Object)null || ((Object)(object)secondPrefab != (Object)null && (Object)(object)leftWeapon == (Object)null) || (Object)(object)pickup == (Object)null)
			{
				DespawnOrDestroy(rightWeapon);
				DespawnOrDestroy(leftWeapon);
				_givingInProgress.Remove(playerId);
				yield break;
			}
			CacheMethods();
			AssignWeaponToHand(pickup, rightWeapon, rightIb, playerGO, rightHand: true);
			if ((Object)(object)secondPrefab != (Object)null)
			{
				AssignWeaponToHand(pickup, leftWeapon, leftIb, playerGO, rightHand: false);
			}
			ProtectRecentGrant(playerId);
			_givingInProgress.Remove(playerId);
		}

		private static IEnumerator ReplaceWeaponInHandCoroutine(int playerId, int weaponIndex, bool rightHand)
		{
			NetworkManager nm = InstanceFinder.NetworkManager;
			if ((Object)(object)nm == (Object)null || !nm.IsServer)
			{
				yield break;
			}
			GameObject prefab = (rightHand ? GunGamePlugin.GetOrderedWeaponPrefab(weaponIndex) : GunGamePlugin.GetSecondWeaponPrefab(weaponIndex));
			if ((Object)(object)prefab == (Object)null)
			{
				yield break;
			}
			string handKey = GetHandGiveKey(playerId, rightHand);
			if (!_handGivingInProgress.Add(handKey))
			{
				yield break;
			}
			try
			{
				PlayerPickup pickup = null;
				for (int attempt = 0; attempt < 8; attempt++)
				{
					pickup = GunGamePlugin.FindPickupForPlayerId(playerId);
					if ((Object)(object)pickup != (Object)null)
					{
						break;
					}
					yield return (object)new WaitForSeconds(0.5f);
				}
				if ((Object)(object)pickup == (Object)null)
				{
					yield break;
				}
				while (HasUnplacedTeleportMineInHand(pickup, rightHand))
				{
					if (GunGamePlugin.MatchOver)
					{
						yield break;
					}
					yield return (object)new WaitForSeconds(0.25f);
					pickup = GunGamePlugin.FindPickupForPlayerId(playerId);
					if ((Object)(object)pickup == (Object)null)
					{
						yield break;
					}
				}
				GameObject weapon = (rightHand ? pickup.sync___get_value_objInHand() : (pickup.sync___get_value_hasObjectInLeftHand() ? pickup.sync___get_value_objInLeftHand() : null));
				if (rightHand)
				{
					pickup.sync___set_value_hasObjectInHand(false, true);
					pickup.sync___set_value_objInHand((GameObject)null, true);
				}
				else
				{
					pickup.sync___set_value_hasObjectInLeftHand(false, true);
					pickup.sync___set_value_objInLeftHand((GameObject)null, true);
				}
				DespawnOrDestroy(weapon);
				yield return (object)new WaitForSeconds(0.1f);
				pickup = GunGamePlugin.FindPickupForPlayerId(playerId);
				if ((Object)(object)pickup == (Object)null)
				{
					yield break;
				}
				GameObject playerGO = null;
				try
				{
					if (ClientInstance.playerInstances.TryGetValue(playerId, out var value))
					{
						PlayerManager val = ((value != null) ? ((Component)value).GetComponent<PlayerManager>() : null);
						object obj;
						if (val == null)
						{
							obj = null;
						}
						else
						{
							FirstPersonController player = val.player;
							obj = ((player != null) ? ((Component)player).gameObject : null);
						}
						playerGO = (GameObject)obj;
					}
				}
				catch
				{
				}
				if ((Object)(object)playerGO == (Object)null)
				{
					playerGO = ((Component)((Component)pickup).transform.root).gameObject;
				}
				GameObject weapon2 = null;
				ItemBehaviour ib = null;
				try
				{
					weapon2 = SpawnWeaponPrefab(nm, prefab, playerGO, out ib);
				}
				catch
				{
					DespawnOrDestroy(weapon2);
					yield break;
				}
				yield return (object)new WaitForSeconds(0.1f);
				if (!((Object)(object)weapon2 == (Object)null))
				{
					CacheMethods();
					AssignWeaponToHand(pickup, weapon2, ib, playerGO, rightHand);
					ProtectRecentGrant(playerId);
				}
			}
			finally
			{
				_handGivingInProgress.Remove(handKey);
			}
		}

		private static GameObject SpawnWeaponPrefab(NetworkManager nm, GameObject prefab, GameObject playerGO, out ItemBehaviour ib)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = Object.Instantiate<GameObject>(prefab, playerGO.transform.position, playerGO.transform.rotation);
			ib = val.GetComponent<ItemBehaviour>();
			if ((Object)(object)ib != (Object)null)
			{
				ib.dispenserStart = true;
			}
			Rigidbody component = val.GetComponent<Rigidbody>();
			if ((Object)(object)component != (Object)null)
			{
				component.isKinematic = true;
				component.useGravity = false;
			}
			nm.ServerManager.Spawn(val, (NetworkConnection)null);
			Weapon component2 = val.GetComponent<Weapon>();
			if ((Object)(object)component2 != (Object)null && IsTeleportMinePrefab(val))
			{
				SetWeaponAmmo(component2, 2);
			}
			return val;
		}

		private static void AssignWeaponToHand(PlayerPickup pickup, GameObject weapon, ItemBehaviour ib, GameObject playerGO, bool rightHand)
		{
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: 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_0032: 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)
			if ((Object)(object)pickup == (Object)null || (Object)(object)weapon == (Object)null)
			{
				return;
			}
			try
			{
				_miSetObjectInHandRpcLogic?.Invoke(pickup, new object[5]
				{
					weapon,
					weapon.transform.position,
					weapon.transform.rotation,
					playerGO,
					rightHand
				});
			}
			catch
			{
			}
			if ((Object)(object)ib != (Object)null)
			{
				ib.dispenserStart = false;
			}
			try
			{
				if (rightHand)
				{
					pickup.sync___set_value_hasObjectInHand(true, true);
					pickup.sync___set_value_objInHand(weapon, true);
				}
				else
				{
					pickup.sync___set_value_hasObjectInLeftHand(true, true);
					pickup.sync___set_value_objInLeftHand(weapon, true);
				}
			}
			catch
			{
			}
			try
			{
				_miSetObjectInHandObserver?.Invoke(pickup, new object[5]
				{
					weapon,
					weapon.transform.position,
					weapon.transform.rotation,
					playerGO,
					rightHand
				});
			}
			catch
			{
			}
			try
			{
				_miSetObjectInHandObserverLogic?.Invoke(pickup, new object[5]
				{
					weapon,
					weapon.transform.position,
					weapon.transform.rotation,
					playerGO,
					rightHand
				});
			}
			catch
			{
			}
		}

		private static void ProtectRecentGrant(int playerId)
		{
			_dropProtectionUntil[playerId] = Time.time + 2f;
		}

		internal static bool IsDropProtected(int playerId)
		{
			if (!_dropProtectionUntil.TryGetValue(playerId, out var value))
			{
				return false;
			}
			if (Time.time <= value)
			{
				return true;
			}
			_dropProtectionUntil.Remove(playerId);
			return false;
		}

		private static bool IsTeleportMinePrefab(GameObject prefab)
		{
			if ((Object)(object)prefab == (Object)null)
			{
				return false;
			}
			string a = ((Object)prefab).name?.Replace("(Clone)", "").Trim();
			if (!string.Equals(a, "Teleport Mine", StringComparison.Ordinal) && !string.Equals(a, "TPTrap", StringComparison.Ordinal))
			{
				return string.Equals(a, "tptrap", StringComparison.Ordinal);
			}
			return true;
		}

		private static bool HasUnplacedTeleportMine(PlayerPickup pickup)
		{
			if ((Object)(object)pickup == (Object)null)
			{
				return false;
			}
			if (!HasUnplacedTeleportMine(pickup.sync___get_value_objInHand()))
			{
				return HasUnplacedTeleportMine(pickup.sync___get_value_hasObjectInLeftHand() ? pickup.sync___get_value_objInLeftHand() : null);
			}
			return true;
		}

		private static bool HasUnplacedTeleportMineInHand(PlayerPickup pickup, bool rightHand)
		{
			if ((Object)(object)pickup == (Object)null)
			{
				return false;
			}
			return HasUnplacedTeleportMine(rightHand ? pickup.sync___get_value_objInHand() : (pickup.sync___get_value_hasObjectInLeftHand() ? pickup.sync___get_value_objInLeftHand() : null));
		}

		private static bool HasUnplacedTeleportMine(GameObject weapon)
		{
			if ((Object)(object)weapon == (Object)null || !IsTeleportMinePrefab(weapon))
			{
				return false;
			}
			Weapon component = weapon.GetComponent<Weapon>();
			if ((Object)(object)component != (Object)null)
			{
				return component.sync___get_value_currentAmmo() > 0;
			}
			return false;
		}

		private static void SetWeaponAmmo(Weapon weapon, int ammo)
		{
			try
			{
				weapon.currentAmmo = ammo;
			}
			catch
			{
			}
			try
			{
				weapon.sync___set_value_currentAmmo(ammo, true);
			}
			catch
			{
			}
		}

		private static void DespawnOrDestroy(GameObject weapon)
		{
			if ((Object)(object)weapon == (Object)null)
			{
				return;
			}
			NetworkObject component = weapon.GetComponent<NetworkObject>();
			if ((Object)(object)component != (Object)null && component.IsSpawned)
			{
				try
				{
					InstanceFinder.ServerManager.Despawn(component, (DespawnType?)null);
					return;
				}
				catch
				{
					return;
				}
			}
			try
			{
				Object.Destroy((Object)(object)weapon);
			}
			catch
			{
			}
		}

		internal static void DespawnHeldWeapon(PlayerPickup pickup)
		{
			if ((Object)(object)pickup == (Object)null)
			{
				return;
			}
			GameObject val = pickup.sync___get_value_objInHand();
			GameObject val2 = (pickup.sync___get_value_hasObjectInLeftHand() ? pickup.sync___get_value_objInLeftHand() : null);
			pickup.sync___set_value_hasObjectInHand(false, true);
			pickup.sync___set_value_hasObjectInLeftHand(false, true);
			pickup.sync___set_value_objInHand((GameObject)null, true);
			pickup.sync___set_value_objInLeftHand((GameObject)null, true);
			GameObject[] array = (GameObject[])(object)new GameObject[2] { val, val2 };
			foreach (GameObject val3 in array)
			{
				if ((Object)(object)val3 == (Object)null)
				{
					continue;
				}
				NetworkObject componentInParent = val3.GetComponentInParent<NetworkObject>();
				if ((Object)(object)componentInParent != (Object)null)
				{
					try
					{
						InstanceFinder.ServerManager.Despawn(componentInParent, (DespawnType?)null);
					}
					catch
					{
					}
				}
				else
				{
					try
					{
						Object.Destroy((Object)(object)val3);
					}
					catch
					{
					}
				}
			}
			try
			{
				ItemBehaviour[] componentsInChildren = ((Component)((Component)pickup).transform.root).GetComponentsInChildren<ItemBehaviour>(true);
				foreach (ItemBehaviour val4 in componentsInChildren)
				{
					if ((Object)(object)val4 == (Object)null)
					{
						continue;
					}
					NetworkObject component = ((Component)val4).GetComponent<NetworkObject>();
					if ((Object)(object)component != (Object)null && component.IsSpawned)
					{
						try
						{
							InstanceFinder.ServerManager.Despawn(component, (DespawnType?)null);
						}
						catch
						{
						}
					}
					else
					{
						try
						{
							Object.Destroy((Object)(object)((Component)val4).gameObject);
						}
						catch
						{
						}
					}
				}
			}
			catch
			{
			}
		}

		public static void ApplyPendingWeaponOnSpawn(int playerId)
		{
			if (!((Object)(object)InstanceFinder.NetworkManager == (Object)null) && InstanceFinder.NetworkManager.IsServer)
			{
				int andClearPendingWeapon = GetAndClearPendingWeapon(playerId);
				if (andClearPendingWeapon >= 0)
				{
					GiveWeaponToPlayer(playerId, andClearPendingWeapon);
				}
			}
		}
	}
	[BepInPlugin("com.modder.gungame", "Gun Game", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class GunGamePlugin : BaseUnityPlugin
	{
		public const string PluginGUID = "com.modder.gungame";

		public const string PluginName = "Gun Game";

		public const string PluginVersion = "1.0.0";

		public const uint ModId = 774411u;

		private const string KokiWeaponsPluginGUID = "com.koki.weapons";

		private const string CmrPluginGUID = "straftatcmr.rebalance";

		internal static ManualLogSource Log;

		private static GunGamePlugin _instance;

		public static ConfigEntry<bool> Enabled;

		public static ConfigEntry<int> KillsToWin;

		public static ConfigEntry<float> RespawnDelay;

		public static ConfigEntry<bool> KillSelfNow;

		public static ConfigEntry<KeyboardShortcut> KillSelfShortcut;

		public static ConfigEntry<string>[] WeaponSlots;

		public static ConfigEntry<string>[] SecondWeaponSlots;

		public static bool MatchOver = false;

		private bool _fishNetHooked;

		private const int WeaponSlotCount = 100;

		private const string NoSecondWeapon = "None";

		private const string DualPlaceableWarning = "Certain dual weilded combinations may have unpredictible results.";

		private const float ModMenuDropdownWidth = 332f;

		private const float ModMenuDropdownWidthTolerance = 1f;

		private float _nextDropdownResizeTime;

		private static Dictionary<string, string[]> WeaponConfigValueToNames = new Dictionary<string, string[]>(StringComparer.Ordinal);

		private static Dictionary<string, GameObject> ResourceWeaponPrefabs = new Dictionary<string, GameObject>(StringComparer.Ordinal);

		private static HashSet<string> MissingResourceWeaponNames = new HashSet<string>(StringComparer.Ordinal);

		private static GameObject[] CachedResourceWeapons = (GameObject[])(object)new GameObject[0];

		private static bool ResourceWeaponsLoaded = false;

		private static readonly string[] DefaultWeaponNames = new string[71]
		{
			"Gun", "Glock", "Revolver", "Silenzzio", "Webley", "Keso", "Bender", "BeamLoad", "Mac10", "SMG",
			"Bukanee", "Dispenser", "Yangtse", "Hill_H15", "Crisis", "DF_Torrent", "GlaiveGun", "Tromblonj", "SawedOff", "Shotgun",
			"Havoc", "AAA12", "Kusma", "AR15", "AK-K", "QCW05", "FG42", "HK_G11", "HK_Caws", "SmithCarbine",
			"Gust", "Warden", "Kanye", "Elephant", "M2000", "Bayshore", "HandCanon", "Minigun", "Nugget", "Mortini",
			"DualLauncher", "RocketLauncher", "Prophet", "Phoenix", "Gamma", "GammaGen2", "BlankState", "Bublee", "DF_Blister", "DF_Cyst",
			"HandGrenade", "GlandGrenade", "ProximityMine", "APMine", "Claymore", "StunMine", "StunGrenade", "FlashLight", "HandGrenadeTwo", "RepulsiveGun",
			"BaseballBat", "Stylus", "Nizeh", "JahvalMahmaerd", "BigFattyBro", "CurvedKnife", "Couperet", "Katana", "Flamberge", "DF_GodSword",
			"Impetus"
		};

		private static readonly string[][] VanillaWeaponNameGroups = new string[5][]
		{
			new string[2] { "StunMine", "stunMine" },
			new string[2] { "StunGrenade", "stunGrenade" },
			new string[2] { "FlashLight", "flashLight" },
			new string[2] { "RepulsiveGun", "repulsiveGun" },
			new string[2] { "HandGrenadeTwo", "handGrenadeTwo" }
		};

		private static readonly string[][] KokiWeaponNameGroups = new string[2][]
		{
			new string[3] { "Teleport Mine", "TPTrap", "tptrap" },
			new string[5] { "Repulsion Grenade", "RepulsionGrenade", "RepulsorGrenadeMerged", "KBGrenade", "repulsiongrenade" }
		};

		private static readonly string[][] CmrWeaponNameGroups = new string[1][] { new string[2] { "Katana", "kuz-yakich" } };

		public static GunGamePlugin Instance => _instance;

		private void Awake()
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			_instance = this;
			LogDetectedCompatibility();
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable Gun Game mode.");
			KillsToWin = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Kills To Win", DefaultWeaponNames.Length, new ConfigDescription("Kills before round ends.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>()));
			RespawnDelay = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Respawn Delay", 3f, "Seconds before a dead player respawns.");
			KillSelfNow = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "Kill Self Now", false, "Turn this on to kill your local player once for respawn testing. It resets itself to off.");
			KillSelfShortcut = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Debug", "Kill Self Shortcut", new KeyboardShortcut((KeyCode)287, Array.Empty<KeyCode>()), "Hotkey that kills your local player for respawn testing.");
			BindWeaponSlots();
			GunGamePatches.Apply();
			SceneManager.sceneLoaded += OnSceneLoaded;
		}

		private void OnEnable()
		{
			_instance = this;
		}

		private void OnDisable()
		{
			if ((Object)(object)_instance == (Object)(object)this)
			{
				_instance = null;
			}
		}

		private void OnDestroy()
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
			if (_fishNetHooked && (Object)(object)InstanceFinder.SceneManager != (Object)null)
			{
				InstanceFinder.SceneManager.OnLoadEnd -= OnFishNetSceneLoaded;
			}
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			ResetGunGameState();
		}

		private void OnFishNetSceneLoaded(SceneLoadEndEventArgs args)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			Scene[] loadedScenes = args.LoadedScenes;
			for (int i = 0; i < loadedScenes.Length; i++)
			{
				_ = ref loadedScenes[i];
				ResetGunGameState();
			}
		}

		private void ResetGunGameState()
		{
			FullReset();
		}

		internal static void FullReset()
		{
			MatchOver = false;
			GunGameWeaponManager.ClearAllPending();
			GunGamePatches.ResetState();
			GunGamePatches.CleanupWorldEffects();
			try
			{
				if ((Object)(object)PauseManager.Instance != (Object)null)
				{
					PauseManager.Instance.startRound = false;
					PauseManager.Instance.onStartRoundScreen = false;
				}
			}
			catch
			{
			}
		}

		private void Update()
		{
			//IL_008e: 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)
			SceneManager sceneManager = InstanceFinder.SceneManager;
			if (!_fishNetHooked && (Object)(object)sceneManager != (Object)null)
			{
				sceneManager.OnLoadEnd += OnFishNetSceneLoaded;
				_fishNetHooked = true;
			}
			else if (_fishNetHooked && (Object)(object)sceneManager == (Object)null)
			{
				_fishNetHooked = false;
				FullReset();
			}
			WidenModMenuDropdowns();
			if (Enabled.Value && KillSelfNow.Value)
			{
				KillSelfNow.Value = false;
				KillLocalPlayerForTesting();
			}
			if (Enabled.Value)
			{
				KeyboardShortcut value = KillSelfShortcut.Value;
				if (((KeyboardShortcut)(ref value)).IsDown())
				{
					KillLocalPlayerForTesting();
				}
			}
			if (!Enabled.Value || (Object)(object)GameManager.Instance == (Object)null || MatchOver || (Object)(object)InstanceFinder.NetworkManager == (Object)null || !InstanceFinder.NetworkManager.IsServer)
			{
				return;
			}
			GunGamePatches.ServerRespawnWatchdogUpdate();
			foreach (KeyValuePair<int, ClientInstance> playerInstance in ClientInstance.playerInstances)
			{
				if (!GameManager.Instance.alivePlayers.Contains(playerInstance.Key))
				{
					GameManager.Instance.alivePlayers.Add(playerInstance.Key);
				}
			}
		}

		private static void KillLocalPlayerForTesting()
		{
			try
			{
				int num = (((Object)(object)ClientInstance.Instance != (Object)null) ? ClientInstance.Instance.PlayerId : (-1));
				if (num < 0)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogWarning((object)"Kill Self requested, but no local ClientInstance player id was found.");
					}
					return;
				}
				PlayerHealth val = FindPlayerHealthById(num);
				if ((Object)(object)val == (Object)null)
				{
					ManualLogSource log2 = Log;
					if (log2 != null)
					{
						log2.LogWarning((object)$"Kill Self requested, but no PlayerHealth was found for player {num}.");
					}
				}
				else if (!val.sync___get_value_isKilled())
				{
					if ((Object)(object)InstanceFinder.NetworkManager != (Object)null && InstanceFinder.NetworkManager.IsServer)
					{
						val.RpcLogic___RemoveHealth_431000436(9999f);
					}
					else
					{
						val.RemoveHealth(9999f);
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log3 = Log;
				if (log3 != null)
				{
					log3.LogWarning((object)("Kill Self failed: " + ex.GetType().Name));
				}
			}
		}

		private static PlayerHealth FindPlayerHealthById(int playerId)
		{
			try
			{
				PlayerHealth[] array = Object.FindObjectsOfType<PlayerHealth>(true);
				foreach (PlayerHealth val in array)
				{
					if (!((Object)(object)val == (Object)null))
					{
						PlayerValues playerValues = val.playerValues;
						if ((((playerValues == null) ? ((int?)null) : playerValues.sync___get_value_playerClient()?.PlayerId) ?? (-1)) == playerId)
						{
							return val;
						}
					}
				}
			}
			catch
			{
			}
			return null;
		}

		public static int GetOrderedWeaponCount()
		{
			_instance?.EnsureWeaponSlotsBound();
			if (WeaponSlots != null && WeaponSlots.Length != 0)
			{
				return WeaponSlots.Length;
			}
			RefreshResourceWeapons();
			return ResourceWeaponPrefabs.Count;
		}

		public static GameObject GetOrderedWeaponPrefab(int index)
		{
			_instance?.EnsureWeaponSlotsBound();
			if (WeaponSlots != null && index >= 0 && index < WeaponSlots.Length)
			{
				if (TryResolveConfiguredWeaponPrefab(WeaponSlots[index]?.Value?.Trim(), out var prefab))
				{
					return prefab;
				}
				return null;
			}
			GameObject[] array = LoadResourceWeapons();
			if (array != null && index >= 0 && index < array.Length)
			{
				return array[index];
			}
			return null;
		}

		public static GameObject GetSecondWeaponPrefab(int index)
		{
			_instance?.EnsureWeaponSlotsBound();
			if (SecondWeaponSlots == null || index < 0 || index >= SecondWeaponSlots.Length)
			{
				return null;
			}
			string text = SecondWeaponSlots[index]?.Value?.Trim();
			if (string.IsNullOrWhiteSpace(text) || string.Equals(text, "None", StringComparison.Ordinal))
			{
				return null;
			}
			if (TryResolveConfiguredWeaponPrefab(text, out var prefab))
			{
				return prefab;
			}
			return null;
		}

		private void EnsureWeaponSlotsBound()
		{
			if (WeaponSlots == null || SecondWeaponSlots == null)
			{
				BindWeaponSlots();
			}
		}

		private void BindWeaponSlots()
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Expected O, but got Unknown
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Expected O, but got Unknown
			WeaponSlots = new ConfigEntry<string>[100];
			SecondWeaponSlots = new ConfigEntry<string>[100];
			string[] availableWeaponConfigValues = GetAvailableWeaponConfigValues();
			AcceptableValueList<string> val = new AcceptableValueList<string>(availableWeaponConfigValues);
			AcceptableValueList<string> val2 = new AcceptableValueList<string>(BuildSecondWeaponConfigValues(availableWeaponConfigValues));
			for (int i = 0; i < WeaponSlots.Length; i++)
			{
				WeaponSlots[i] = ((BaseUnityPlugin)this).Config.Bind<string>("Weapon Progression", $"Weapon {i + 1}", DefaultWeaponNames[i % DefaultWeaponNames.Length], new ConfigDescription(string.Format("Weapon given at progression slot {0}. {1}", i + 1, "Certain dual weilded combinations may have unpredictible results."), (AcceptableValueBase)(object)val, Array.Empty<object>()));
				SecondWeaponSlots[i] = ((BaseUnityPlugin)this).Config.Bind<string>("Weapon Progression", $"Weapon {i + 1} Off Hand", "None", new ConfigDescription(string.Format("Optional left-hand weapon given at progression slot {0}. {1}", i + 1, "Certain dual weilded combinations may have unpredictible results."), (AcceptableValueBase)(object)val2, Array.Empty<object>()));
			}
		}

		private static string[] BuildSecondWeaponConfigValues(string[] weaponValues)
		{
			List<string> list = new List<string> { "None" };
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal) { "None" };
			foreach (string text in weaponValues)
			{
				if (!string.IsNullOrWhiteSpace(text) && hashSet.Add(text))
				{
					list.Add(text);
				}
			}
			return list.ToArray();
		}

		private static string[] GetAvailableWeaponConfigValues()
		{
			List<string> list = new List<string>();
			HashSet<string> seen = new HashSet<string>(StringComparer.Ordinal);
			for (int i = 0; i < DefaultWeaponNames.Length; i++)
			{
				AddWeaponName(DefaultWeaponNames[i], list, seen);
			}
			try
			{
				GameObject[] array = LoadResourceWeapons();
				foreach (GameObject val in array)
				{
					if ((Object)(object)val != (Object)null)
					{
						AddWeaponName(((Object)val).name, list, seen);
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)("Could not discover resource weapons for config dropdowns: " + ex.GetType().Name));
				}
			}
			list.Sort(StringComparer.OrdinalIgnoreCase);
			return BuildWeaponConfigValues(list);
		}

		private static void AddWeaponName(string weaponName, List<string> names, HashSet<string> seen)
		{
			if (!string.IsNullOrWhiteSpace(weaponName))
			{
				weaponName = weaponName.Replace("(Clone)", "").Trim();
				if (seen.Add(weaponName))
				{
					names.Add(weaponName);
				}
			}
		}

		private static string[] BuildWeaponConfigValues(List<string> weaponNames)
		{
			List<string> list = new List<string>();
			HashSet<string> usedValues = new HashSet<string>(StringComparer.Ordinal);
			Dictionary<string, string[]> dictionary = new Dictionary<string, string[]>(StringComparer.Ordinal);
			foreach (string weaponName in weaponNames)
			{
				string current;
				string[] weaponNameCandidates = GetWeaponNameCandidates(current = weaponName);
				current = MakeUniqueConfigValue(current, usedValues);
				list.Add(current);
				dictionary[current] = weaponNameCandidates;
				string[] array = weaponNameCandidates;
				foreach (string key in array)
				{
					if (!dictionary.ContainsKey(key))
					{
						dictionary[key] = weaponNameCandidates;
					}
				}
			}
			WeaponConfigValueToNames = dictionary;
			return list.ToArray();
		}

		private static string MakeUniqueConfigValue(string configValue, HashSet<string> usedValues)
		{
			if (usedValues.Add(configValue))
			{
				return configValue;
			}
			int num = 2;
			string text2;
			while (true)
			{
				string text = $" #{num}";
				text2 = configValue + text;
				if (usedValues.Add(text2))
				{
					break;
				}
				num++;
			}
			return text2;
		}

		private static string[] GetWeaponNameCandidates(string weaponName)
		{
			foreach (string[] activeWeaponNameGroup in GetActiveWeaponNameGroups())
			{
				string[] array = activeWeaponNameGroup;
				for (int i = 0; i < array.Length; i++)
				{
					if (string.Equals(array[i], weaponName, StringComparison.Ordinal))
					{
						return activeWeaponNameGroup;
					}
				}
			}
			return new string[1] { weaponName };
		}

		private static IEnumerable<string[]> GetActiveWeaponNameGroups()
		{
			string[][] vanillaWeaponNameGroups = VanillaWeaponNameGroups;
			for (int i = 0; i < vanillaWeaponNameGroups.Length; i++)
			{
				yield return vanillaWeaponNameGroups[i];
			}
			if (IsKokiWeaponsLoaded())
			{
				vanillaWeaponNameGroups = KokiWeaponNameGroups;
				for (int i = 0; i < vanillaWeaponNameGroups.Length; i++)
				{
					yield return vanillaWeaponNameGroups[i];
				}
			}
			if (IsCmrLoaded())
			{
				vanillaWeaponNameGroups = CmrWeaponNameGroups;
				for (int i = 0; i < vanillaWeaponNameGroups.Length; i++)
				{
					yield return vanillaWeaponNameGroups[i];
				}
			}
		}

		private static bool IsKokiWeaponsLoaded()
		{
			return IsPluginLoaded("com.koki.weapons");
		}

		private static bool IsCmrLoaded()
		{
			return IsPluginLoaded("straftatcmr.rebalance");
		}

		private static bool IsPluginLoaded(string pluginGuid)
		{
			try
			{
				return Chainloader.PluginInfos != null && Chainloader.PluginInfos.ContainsKey(pluginGuid);
			}
			catch
			{
				return false;
			}
		}

		private static void LogDetectedCompatibility()
		{
			bool flag = IsKokiWeaponsLoaded();
			bool flag2 = IsCmrLoa