Decompiled source of StraftatDeathmatch v1.1.0

StraftatDeathmatch.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FishNet;
using FishNet.Connection;
using FishNet.Managing;
using FishNet.Managing.Object;
using FishNet.Managing.Scened;
using FishNet.Object;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using MyceliumNetworking;
using Steamworks;
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.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("StraftatDeathmatch")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0")]
[assembly: AssemblyProduct("StraftatDeathmatch")]
[assembly: AssemblyTitle("StraftatDeathmatch")]
[assembly: AssemblyVersion("1.1.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace StraftatDeathmatch
{
	public class DeathmatchHud : MonoBehaviour
	{
		private const float RefreshInterval = 0.25f;

		private GameObject _panel;

		private TextMeshProUGUI _text;

		private float _nextRefreshTime;

		private void Awake()
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Expected O, but got Unknown
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Expected O, but got Unknown
			Canvas obj = ((Component)this).gameObject.AddComponent<Canvas>();
			obj.renderMode = (RenderMode)0;
			obj.sortingOrder = 1000;
			CanvasScaler obj2 = ((Component)this).gameObject.AddComponent<CanvasScaler>();
			obj2.uiScaleMode = (ScaleMode)1;
			obj2.referenceResolution = new Vector2(1920f, 1080f);
			_panel = new GameObject("DeathmatchPanel");
			_panel.transform.SetParent(((Component)this).transform, false);
			RectTransform obj3 = _panel.AddComponent<RectTransform>();
			obj3.anchorMin = new Vector2(1f, 1f);
			obj3.anchorMax = new Vector2(1f, 1f);
			obj3.pivot = new Vector2(1f, 1f);
			obj3.anchoredPosition = new Vector2(-18f, -440f);
			((Graphic)_panel.AddComponent<Image>()).color = new Color(0f, 0f, 0f, 0.45f);
			VerticalLayoutGroup obj4 = _panel.AddComponent<VerticalLayoutGroup>();
			((LayoutGroup)obj4).padding = new RectOffset(12, 12, 8, 8);
			((LayoutGroup)obj4).childAlignment = (TextAnchor)0;
			((HorizontalOrVerticalLayoutGroup)obj4).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj4).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj4).childForceExpandWidth = false;
			((HorizontalOrVerticalLayoutGroup)obj4).childForceExpandHeight = false;
			ContentSizeFitter obj5 = _panel.AddComponent<ContentSizeFitter>();
			obj5.horizontalFit = (FitMode)2;
			obj5.verticalFit = (FitMode)2;
			GameObject val = new GameObject("DeathmatchText");
			val.transform.SetParent(_panel.transform, false);
			val.AddComponent<RectTransform>();
			_text = val.AddComponent<TextMeshProUGUI>();
			((TMP_Text)_text).fontSize = 22f;
			((TMP_Text)_text).richText = true;
			((TMP_Text)_text).enableWordWrapping = false;
			((TMP_Text)_text).alignment = (TextAlignmentOptions)257;
			((Graphic)_text).raycastTarget = false;
			_panel.SetActive(false);
		}

		private void Update()
		{
			if (!(Time.unscaledTime < _nextRefreshTime))
			{
				_nextRefreshTime = Time.unscaledTime + 0.25f;
				bool flag = DeathmatchPlugin.ShowScoreboard.Value && ScoreKeeper.ModeActiveLocally() && (Object)(object)PauseManager.Instance != (Object)null && !PauseManager.Instance.inMainMenu && !PauseManager.Instance.inVictoryMenu && ClientInstance.playerInstances.Count > 0;
				if (_panel.activeSelf != flag)
				{
					_panel.SetActive(flag);
				}
				if (flag)
				{
					((TMP_Text)_text).text = BuildText();
				}
			}
		}

		private static string BuildText()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("<b><color=#FF4040>DEATHMATCH</color></b>  <color=#AAAAAA>first to ").Append(ScoreKeeper.EffectiveKillsToWin).Append("</color>");
			int secondsLeft = ScoreKeeper.SecondsLeft;
			if (secondsLeft >= 0)
			{
				stringBuilder.Append("  <color=#AAAAAA>-  ").Append(secondsLeft / 60).Append(':')
					.Append((secondsLeft % 60).ToString("00"))
					.Append("</color>");
			}
			int localPlayerId = PlayerLookup.LocalPlayerId;
			List<ScoreKeeper.Row> rows = ScoreKeeper.GetRows();
			for (int i = 0; i < rows.Count; i++)
			{
				ScoreKeeper.Row row = rows[i];
				string name = PlayerLookup.GetName(row.PlayerId);
				stringBuilder.Append('\n');
				string value = ((row.PlayerId == localPlayerId) ? "#FFD24A" : "#DDDDDD");
				stringBuilder.Append("<color=").Append(value).Append('>');
				int num;
				if (i == 0)
				{
					num = ((row.Kills > 0) ? 1 : 0);
					if (num != 0)
					{
						stringBuilder.Append("<b>");
					}
				}
				else
				{
					num = 0;
				}
				stringBuilder.Append(name).Append("  ").Append(row.Kills)
					.Append(" <color=#888888>/ ")
					.Append(row.Deaths)
					.Append("</color>");
				if (num != 0)
				{
					stringBuilder.Append("</b>");
				}
				stringBuilder.Append("</color>");
			}
			if (ScoreKeeper.MatchOver)
			{
				stringBuilder.Append("\n<color=#AAAAAA>Round over</color>");
			}
			return stringBuilder.ToString();
		}
	}
	internal static class DeathmatchPatches
	{
		private static Harmony _harmony;

		private static FieldInfo _fiRoundHasStarted;

		private static bool Active => ScoreKeeper.ModeActiveLocally();

		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
			if (_harmony == null)
			{
				_harmony = new Harmony("com.clst.straftatdeathmatch.patches");
				_fiRoundHasStarted = AccessTools.Field(typeof(FirstPersonController), "roundHasStarted");
				Type[] args = new Type[4]
				{
					typeof(int),
					typeof(int),
					typeof(Vector3),
					typeof(Quaternion)
				};
				Type[] args2 = new Type[2]
				{
					typeof(int),
					typeof(int)
				};
				Prefix(typeof(GameManager), "RpcLogic___PlayerDied_3316948804", "GameManager_PlayerDied_Prefix");
				Prefix(typeof(GameManager), "WaitForDraw", "GameManager_WaitForDraw_Prefix");
				Prefix(typeof(RoundManager), "CmdEndRound", "RoundManager_CmdEndRound_Prefix");
				Postfix(typeof(GameManager), "RpcLogic___SetStartTime_431000436", "GameManager_SetStartTime_Postfix");
				Prefix(typeof(PlayerManager), "ReturnSpawnPoint", "PlayerManager_ReturnSpawnPoint_Prefix");
				Prefix(typeof(PlayerManager), "SpawnPlayer", "PlayerManager_SpawnPlayer2_Prefix", args2);
				Postfix(typeof(PlayerManager), "SpawnPlayer", "PlayerManager_SpawnPlayer4_Postfix", args);
				Prefix(typeof(PlayerManager), "WaitForRoundStart", "PlayerManager_WaitForRoundStart_Prefix");
				Prefix(typeof(KillCam), "Update", "KillCam_Update_Prefix");
				Postfix(typeof(PlayerHealth), "RpcLogic___ExplodeForAll_576886416", "PlayerHealth_ExplodeForAll_Postfix");
				Postfix(typeof(PlayerHealth), "RpcLogic___DespawnObject_2166136261", "PlayerHealth_DespawnObject_Postfix");
				Postfix(typeof(PlayerValues), "sync___set_value_playerClient", "PlayerValues_SetPlayerClient_Postfix");
				Prefix(typeof(PlayerPickup), "RightHandDrop", "PlayerPickup_RightHandDrop_Prefix");
				Prefix(typeof(PlayerPickup), "LeftHandDrop", "PlayerPickup_LeftHandDrop_Prefix");
				Prefix(typeof(PlayerPickup), "RpcLogic___DropObjectServer_2127535046", "PlayerPickup_DropObjectServer_Prefix");
				Prefix(typeof(PlayerPickup), "RpcLogic___DropObjectObserver_2127535046", "PlayerPickup_DropObjectObserver_Prefix");
				Postfix(typeof(PlayerPickup), "OnStartClient", "PlayerPickup_OnStartClient_Postfix");
				Prefix(typeof(PlayerSetup), "OnDisable", "PlayerSetup_OnDisable_Prefix");
				Prefix(typeof(ProximityMine), "KillShockWave", "ProximityMine_KillShockWave_Prefix");
				Prefix(typeof(Claymore), "KillShockWave", "Claymore_KillShockWave_Prefix");
				Prefix(typeof(DamageZone), "OnEnable", "DamageZone_OnEnable_Prefix");
				Prefix(typeof(FirstPersonController), "OnTriggerStay", "FirstPersonController_OnTriggerStay_Prefix");
			}
		}

		private static void Prefix(Type type, string method, string patch, Type[] args = null)
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Expected O, but got Unknown
			try
			{
				MethodInfo methodInfo = ((args == null) ? AccessTools.Method(type, method, (Type[])null, (Type[])null) : AccessTools.Method(type, method, args, (Type[])null));
				if (methodInfo == null)
				{
					ManualLogSource log = DeathmatchPlugin.Log;
					if (log != null)
					{
						log.LogWarning((object)("[Patch] " + type.Name + "." + method + " not found"));
					}
				}
				else
				{
					_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(DeathmatchPatches), patch, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = DeathmatchPlugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("[Patch] " + type.Name + "." + method + ": " + ex.GetType().Name + " - " + ex.Message));
				}
			}
		}

		private static void Postfix(Type type, string method, string patch, Type[] args = null)
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Expected O, but got Unknown
			try
			{
				MethodInfo methodInfo = ((args == null) ? AccessTools.Method(type, method, (Type[])null, (Type[])null) : AccessTools.Method(type, method, args, (Type[])null));
				if (methodInfo == null)
				{
					ManualLogSource log = DeathmatchPlugin.Log;
					if (log != null)
					{
						log.LogWarning((object)("[Patch] " + type.Name + "." + method + " not found"));
					}
				}
				else
				{
					_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(DeathmatchPatches), patch, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = DeathmatchPlugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("[Patch] " + type.Name + "." + method + ": " + ex.GetType().Name + " - " + ex.Message));
				}
			}
		}

		public static bool GameManager_PlayerDied_Prefix(int playerId)
		{
			if (!Active || !PlayerLookup.IsServer)
			{
				return true;
			}
			if (ScoreKeeper.MatchOver)
			{
				return false;
			}
			try
			{
				if ((Object)(object)GameManager.Instance != (Object)null)
				{
					GameManager.Instance.alivePlayers.Add(playerId);
				}
				if (!ScoreKeeper.TryBeginDeath(playerId))
				{
					return false;
				}
				RespawnController.OnServerDeath(playerId);
				MonoBehaviour val = (MonoBehaviour)(object)(((Object)(object)GameManager.Instance != (Object)null) ? ((DeathmatchPlugin)(object)GameManager.Instance) : DeathmatchPlugin.Instance);
				if ((Object)(object)val != (Object)null)
				{
					val.StartCoroutine(ResolveKill(playerId));
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = DeathmatchPlugin.Log;
				if (log != null)
				{
					log.LogError((object)("[Death] handling player " + playerId + ": " + ex));
				}
				try
				{
					RespawnController.Schedule(playerId);
				}
				catch
				{
				}
			}
			return false;
		}

		private static IEnumerator ResolveKill(int victimId)
		{
			yield return (object)new WaitForSeconds(0.1f);
			if (!ScoreKeeper.MatchOver)
			{
				int killerId = -1;
				try
				{
					killerId = PlayerLookup.FindKillerId(victimId);
				}
				catch
				{
				}
				ScoreKeeper.OnServerKill(victimId, killerId);
			}
		}

		public static bool GameManager_WaitForDraw_Prefix(ref IEnumerator __result)
		{
			if (Active && PlayerLookup.IsServer && !ScoreKeeper.MatchOver)
			{
				__result = Empty();
				return false;
			}
			return true;
		}

		private static IEnumerator Empty()
		{
			yield break;
		}

		public static bool RoundManager_CmdEndRound_Prefix()
		{
			if (Active && PlayerLookup.IsServer && !ScoreKeeper.MatchOver)
			{
				return false;
			}
			return true;
		}

		public static void GameManager_SetStartTime_Postfix(float serverTimeTillStart)
		{
			ScoreKeeper.OnStartTimeIssued(serverTimeTillStart);
		}

		public static bool PlayerManager_ReturnSpawnPoint_Prefix(PlayerManager __instance, ref Transform __result)
		{
			if (!Active || !PlayerLookup.IsServer)
			{
				return true;
			}
			try
			{
				ClientInstance component = ((Component)__instance).GetComponent<ClientInstance>();
				if (SpawnSelector.TryPick(((Object)(object)component != (Object)null) ? component.PlayerId : (-1), out var point, out var _, out var _))
				{
					__result = ((Component)point).transform;
					return false;
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = DeathmatchPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[Spawn] ReturnSpawnPoint: " + ex.GetType().Name));
				}
			}
			return true;
		}

		public static bool PlayerManager_SpawnPlayer2_Prefix(PlayerManager __instance, int __0, int __1)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			if (!Active || !PlayerLookup.IsServer)
			{
				return true;
			}
			try
			{
				ClientInstance component = ((Component)__instance).GetComponent<ClientInstance>();
				int forPlayerId = (((Object)(object)component != (Object)null) ? component.PlayerId : (-1));
				if (SpawnSelector.TryPick(forPlayerId, out var point, out var position, out var rotation) && RespawnController.InvokeSpawnPlayer(__instance, __0, __1, position, rotation))
				{
					ManualLogSource log = DeathmatchPlugin.Log;
					if (log != null)
					{
						log.LogInfo((object)("[Spawn] player=" + forPlayerId + " take-start spawn at '" + ((Object)point).name + "'"));
					}
					return false;
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = DeathmatchPlugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("[Spawn] SpawnPlayer: " + ex.GetType().Name + " - " + ex.Message));
				}
			}
			return true;
		}

		public static void PlayerManager_SpawnPlayer4_Postfix(PlayerManager __instance, int __0, int __1)
		{
			if (!Active || (Object)(object)__instance == (Object)null)
			{
				return;
			}
			try
			{
				ClientInstance component = ((Component)__instance).GetComponent<ClientInstance>();
				if (!((Object)(object)component == (Object)null) && component.PlayerId >= 0 && PlayerLookup.IsServer)
				{
					RespawnController.RememberCosmetics(component.PlayerId, __0, __1);
					RespawnController.OnServerSpawned(component.PlayerId);
					if ((Object)(object)GameManager.Instance != (Object)null)
					{
						GameManager.Instance.alivePlayers.Add(component.PlayerId);
					}
				}
			}
			catch
			{
			}
		}

		public static bool PlayerManager_WaitForRoundStart_Prefix(PlayerManager __instance, ref IEnumerator __result)
		{
			if (!Active || !ScoreKeeper.IsMidMatchLocally())
			{
				return true;
			}
			__result = QuickStart(__instance);
			return false;
		}

		private static IEnumerator QuickStart(PlayerManager pm)
		{
			yield return null;
			for (int i = 0; i < 5; i++)
			{
				if (!((Object)(object)pm != (Object)null))
				{
					break;
				}
				if (!((Object)(object)pm.player == (Object)null))
				{
					break;
				}
				yield return null;
			}
			if ((Object)(object)pm == (Object)null)
			{
				yield break;
			}
			try
			{
				pm.SetPlayerMove(true);
			}
			catch
			{
			}
			try
			{
				if ((Object)(object)PauseManager.Instance != (Object)null)
				{
					PauseManager.Instance.startRound = false;
				}
			}
			catch
			{
			}
			try
			{
				if ((Object)(object)pm.player != (Object)null)
				{
					pm.player.startOfRound = false;
					if (_fiRoundHasStarted != null)
					{
						_fiRoundHasStarted.SetValue(pm.player, true);
					}
				}
			}
			catch
			{
			}
			try
			{
				if ((Object)(object)pm.player != (Object)null && (Object)(object)pm.player.setupScript != (Object)null)
				{
					pm.player.setupScript.EnableTaserEffectServer();
				}
			}
			catch
			{
			}
			float end = Time.time + 3f;
			while (Time.time < end)
			{
				if ((Object)(object)pm == (Object)null)
				{
					yield break;
				}
				try
				{
					if ((Object)(object)pm.player != (Object)null && !pm.player.sync___get_value_canMove())
					{
						pm.SetPlayerMove(true);
					}
					if ((Object)(object)PauseManager.Instance != (Object)null && PauseManager.Instance.startRound)
					{
						PauseManager.Instance.startRound = false;
					}
				}
				catch
				{
				}
				yield return (object)new WaitForSeconds(0.25f);
			}
			if ((Object)(object)pm != (Object)null)
			{
				pm.waitForRoundStartCoroutine = null;
			}
		}

		public static bool KillCam_Update_Prefix()
		{
			if (Active)
			{
				return !ScoreKeeper.IsMidMatchLocally();
			}
			return true;
		}

		public static void PlayerHealth_ExplodeForAll_Postfix(PlayerHealth __instance)
		{
			if (Active && !((Object)(object)__instance == (Object)null))
			{
				RespawnController.TrackRagdoll(__instance);
			}
		}

		public static void PlayerHealth_DespawnObject_Postfix(PlayerHealth __instance)
		{
			try
			{
				if ((Object)(object)__instance != (Object)null && ((NetworkBehaviour)__instance).IsOwner)
				{
					ScoreKeeper.LocalDiedThisMap = true;
				}
			}
			catch
			{
			}
		}

		public static void PlayerValues_SetPlayerClient_Postfix(ClientInstance __0)
		{
			if (!Active || (Object)(object)__0 == (Object)null)
			{
				return;
			}
			try
			{
				if (__0.PlayerId >= 0)
				{
					RespawnController.DestroyRagdoll(__0.PlayerId);
				}
			}
			catch
			{
			}
		}

		private static bool IsDead(PlayerPickup pickup)
		{
			PlayerHealth val = (((Object)(object)pickup != (Object)null) ? ((Component)pickup).GetComponentInParent<PlayerHealth>() : null);
			if ((Object)(object)val != (Object)null)
			{
				if (!(val.sync___get_value_health() <= 0f))
				{
					return val.sync___get_value_isKilled();
				}
				return true;
			}
			return false;
		}

		public static bool PlayerPickup_RightHandDrop_Prefix(PlayerPickup __instance)
		{
			try
			{
				if (Active)
				{
					LoadoutKeeper.OnHandDropping(__instance);
				}
			}
			catch
			{
			}
			if (!Active || !ScoreKeeper.CleanupItemsEffective)
			{
				return true;
			}
			try
			{
				if (__instance.sync___get_value_hasObjectInHand())
				{
					GameObject val = __instance.sync___get_value_objInHand();
					if ((Object)(object)val == (Object)null || (Object)(object)val.GetComponent<ItemBehaviour>() == (Object)null)
					{
						RespawnController.ClearHand(__instance, rightHand: true);
						return false;
					}
				}
				if (IsDead(__instance))
				{
					return false;
				}
			}
			catch
			{
			}
			return true;
		}

		public static bool PlayerPickup_LeftHandDrop_Prefix(PlayerPickup __instance)
		{
			try
			{
				if (Active)
				{
					LoadoutKeeper.OnHandDropping(__instance);
				}
			}
			catch
			{
			}
			if (!Active || !ScoreKeeper.CleanupItemsEffective)
			{
				return true;
			}
			try
			{
				if (__instance.sync___get_value_hasObjectInLeftHand())
				{
					GameObject val = __instance.sync___get_value_objInLeftHand();
					if ((Object)(object)val == (Object)null || (Object)(object)val.GetComponent<ItemBehaviour>() == (Object)null)
					{
						RespawnController.ClearHand(__instance, rightHand: false);
						return false;
					}
				}
				if (IsDead(__instance))
				{
					return false;
				}
			}
			catch
			{
			}
			return true;
		}

		public static bool PlayerPickup_DropObjectServer_Prefix(PlayerPickup __instance, GameObject obj, bool rightHand)
		{
			if (!Active || !PlayerLookup.IsServer || !ScoreKeeper.CleanupItemsEffective)
			{
				return true;
			}
			try
			{
				if ((Object)(object)obj == (Object)null)
				{
					RespawnController.ClearHand(__instance, rightHand);
					return false;
				}
				NetworkObject component = obj.GetComponent<NetworkObject>();
				if ((Object)(object)component != (Object)null && !component.IsSpawned)
				{
					RespawnController.ClearHand(__instance, rightHand);
					return false;
				}
				if (IsDead(__instance))
				{
					RespawnController.ClearHand(__instance, rightHand);
					RespawnController.DespawnOrDestroy(obj);
					return false;
				}
			}
			catch
			{
			}
			return true;
		}

		public static bool PlayerPickup_DropObjectObserver_Prefix(GameObject obj)
		{
			if (!Active)
			{
				return true;
			}
			return (Object)(object)obj != (Object)null;
		}

		public static void PlayerPickup_OnStartClient_Postfix(PlayerPickup __instance)
		{
			if (!Active || (Object)(object)__instance == (Object)null)
			{
				return;
			}
			try
			{
				LoadoutKeeper.OnPickupStarted(__instance);
			}
			catch (Exception ex)
			{
				ManualLogSource log = DeathmatchPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[Loadout] OnStartClient: " + ex.GetType().Name + " - " + ex.Message));
				}
			}
		}

		public static bool PlayerSetup_OnDisable_Prefix(PlayerSetup __instance)
		{
			if (!Active || (Object)(object)__instance == (Object)null)
			{
				return true;
			}
			try
			{
				if (((NetworkBehaviour)__instance).IsOwner)
				{
					return true;
				}
				GameObject val = PlayerLookup.FindBody(PlayerLookup.LocalPlayerId);
				if ((Object)(object)val != (Object)null && (Object)(object)((Component)__instance).gameObject == (Object)(object)val)
				{
					return true;
				}
			}
			catch
			{
				return true;
			}
			return false;
		}

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

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

		public static bool DamageZone_OnEnable_Prefix(DamageZone __instance)
		{
			if (!Active || !ScoreKeeper.RemoveDamageZonesEffective)
			{
				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 (Active && ScoreKeeper.RemoveDamageZonesEffective && (Object)(object)col != (Object)null && ((Component)col).CompareTag("DamageZone"))
			{
				return false;
			}
			return true;
		}
	}
	[BepInPlugin("com.clst.straftatdeathmatch", "Straftat Deathmatch", "1.1.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class DeathmatchPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.clst.straftatdeathmatch";

		public const string PluginName = "Straftat Deathmatch";

		public const string PluginVersion = "1.1.0";

		public const uint ModId = 20260905u;

		internal static ManualLogSource Log;

		public static ConfigEntry<bool> Enabled;

		public static ConfigEntry<int> KillsToWin;

		public static ConfigEntry<int> TimeLimitMinutes;

		public static ConfigEntry<float> RespawnDelay;

		public static ConfigEntry<float> MinEnemyDistance;

		public static ConfigEntry<bool> AvoidLineOfSight;

		public static ConfigEntry<float> SpawnJitter;

		public static ConfigEntry<bool> CleanupItemsOnDeath;

		public static ConfigEntry<bool> CleanupMinesOnDeath;

		public static ConfigEntry<bool> RemoveDamageZones;

		public static ConfigEntry<bool> RestoreLoadoutOnRespawn;

		public static ConfigEntry<string> DefaultWeapon;

		public static ConfigEntry<string> LoadoutExcludedClasses;

		public static ConfigEntry<string> LoadoutExcludedWeapons;

		public static ConfigEntry<bool> ShowScoreboard;

		public static ConfigEntry<bool> KillFeedInChat;

		public static ConfigEntry<KeyboardShortcut> KillSelfShortcut;

		private bool _fishNetHooked;

		public static DeathmatchPlugin Instance { get; private set; }

		private void Awake()
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Expected O, but got Unknown
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Expected O, but got Unknown
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Expected O, but got Unknown
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Expected O, but got Unknown
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Expected O, but got Unknown
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0343: Unknown result type (might be due to invalid IL or missing references)
			//IL_0348: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			Instance = this;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable Deathmatch mode. Only the host's setting matters for gameplay.");
			KillsToWin = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Kills To Win", 20, new ConfigDescription("Kills needed to win the round.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>()));
			TimeLimitMinutes = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Time Limit Minutes", 0, new ConfigDescription("Round time limit in minutes. 0 disables it. When time runs out the player with the most kills wins; a tie goes to sudden death.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 60), Array.Empty<object>()));
			RespawnDelay = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Respawn Delay", 2f, new ConfigDescription("Seconds before a dead player respawns.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 10f), Array.Empty<object>()));
			MinEnemyDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Spawning", "Min Enemy Spawn Distance", 12f, new ConfigDescription("Spawn points closer than this to a living enemy are avoided when any other point exists.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 50f), Array.Empty<object>()));
			AvoidLineOfSight = ((BaseUnityPlugin)this).Config.Bind<bool>("Spawning", "Avoid Enemy Line Of Sight", true, "Prefer spawn points that no living enemy can currently see.");
			SpawnJitter = ((BaseUnityPlugin)this).Config.Bind<float>("Spawning", "Spawn Jitter", 0.5f, new ConfigDescription("Random offset in meters applied around the chosen spawn point. 0 spawns exactly on the point.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>()));
			CleanupItemsOnDeath = ((BaseUnityPlugin)this).Config.Bind<bool>("Cleanup", "Cleanup Items On Death", true, "Remove whatever a player was holding when they die instead of dropping it on the ground.");
			CleanupMinesOnDeath = ((BaseUnityPlugin)this).Config.Bind<bool>("Cleanup", "Cleanup Mines On Death", true, "Remove mines and claymores placed by a player when they die.");
			RemoveDamageZones = ((BaseUnityPlugin)this).Config.Bind<bool>("Cleanup", "Remove Damage Zones", false, "Disable map damage zones for continuous play.");
			RestoreLoadoutOnRespawn = ((BaseUnityPlugin)this).Config.Bind<bool>("Loadout", "Restore Loadout On Respawn", true, "Respawn holding the weapons you had when you were killed. Pick a weapon up once, then swap at map spawners when you want something else.");
			DefaultWeapon = ((BaseUnityPlugin)this).Config.Bind<string>("Loadout", "Default Weapon", "Gun", "Prefab name of the weapon given to a player who died empty-handed (Gun is the pistol; other examples: Glock, Revolver, AK-K, Shotgun). Empty gives nothing.");
			LoadoutExcludedClasses = ((BaseUnityPlugin)this).Config.Bind<string>("Loadout", "Excluded Weapon Classes", "DualLauncher", "Comma-separated Weapon component classes that are never restored. DualLauncher covers grenades and all launchers.");
			LoadoutExcludedWeapons = ((BaseUnityPlugin)this).Config.Bind<string>("Loadout", "Excluded Weapons", "", "Comma-separated weapon prefab names that are never restored.");
			ShowScoreboard = ((BaseUnityPlugin)this).Config.Bind<bool>("HUD", "Show Scoreboard", true, "Show the on-screen kill scoreboard.");
			KillFeedInChat = ((BaseUnityPlugin)this).Config.Bind<bool>("HUD", "Kill Feed In Chat", false, "Post the killer's running score to chat after every kill. The game already announces the kill itself.");
			KillSelfShortcut = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Debug", "Kill Self Shortcut", new KeyboardShortcut((KeyCode)287, Array.Empty<KeyCode>()), "Hotkey that kills your own player for respawn testing.");
			ScoreKeeper.Init();
			RespawnController.Init();
			LoadoutKeeper.Init();
			DeathmatchPatches.Apply();
			try
			{
				MyceliumNetwork.RegisterNetworkObject((object)this, 20260905u, 0);
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Mycelium registration failed: " + ex.GetType().Name + " - " + ex.Message));
			}
			try
			{
				MyceliumNetwork.PlayerEntered += OnMyceliumPlayerEntered;
			}
			catch
			{
			}
			SceneManager.sceneLoaded += OnSceneLoaded;
			GameObject val = new GameObject("DeathmatchHud");
			val.transform.SetParent(((Component)this).transform, false);
			val.AddComponent<DeathmatchHud>();
			Log.LogInfo((object)"Straftat Deathmatch 1.1.0 loaded.");
		}

		private void OnDestroy()
		{
			try
			{
				MyceliumNetwork.DeregisterNetworkObject((object)this, 20260905u, 0);
			}
			catch
			{
			}
			try
			{
				MyceliumNetwork.PlayerEntered -= OnMyceliumPlayerEntered;
			}
			catch
			{
			}
			SceneManager.sceneLoaded -= OnSceneLoaded;
			if (_fishNetHooked && (Object)(object)InstanceFinder.SceneManager != (Object)null)
			{
				InstanceFinder.SceneManager.OnLoadEnd -= OnFishNetSceneLoaded;
			}
		}

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

		private void OnFishNetSceneLoaded(SceneLoadEndEventArgs args)
		{
			FullReset();
		}

		private void OnMyceliumPlayerEntered(CSteamID id)
		{
			ScoreKeeper.MarkDirty();
		}

		internal static void FullReset()
		{
			ScoreKeeper.Reset();
			RespawnController.Reset();
			LoadoutKeeper.Reset();
			LoadoutSpawner.Reset();
			SpawnSelector.Reset();
			RespawnController.CleanupWorldEffects();
			try
			{
				if ((Object)(object)PauseManager.Instance != (Object)null)
				{
					PauseManager.Instance.startRound = false;
					PauseManager.Instance.onStartRoundScreen = false;
				}
			}
			catch
			{
			}
		}

		private void Update()
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			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();
			}
			if (Enabled.Value)
			{
				KeyboardShortcut value = KillSelfShortcut.Value;
				if (((KeyboardShortcut)(ref value)).IsDown())
				{
					KillLocalPlayerForTesting();
				}
			}
			LoadoutKeeper.ClientTick();
			if (!Enabled.Value || (Object)(object)GameManager.Instance == (Object)null || !PlayerLookup.IsServer)
			{
				return;
			}
			ScoreKeeper.ServerTick();
			RespawnController.ServerTick();
			LoadoutSpawner.ServerTick();
			HashSet<int> alivePlayers = GameManager.Instance.alivePlayers;
			foreach (KeyValuePair<int, ClientInstance> playerInstance in ClientInstance.playerInstances)
			{
				if (!alivePlayers.Contains(playerInstance.Key))
				{
					alivePlayers.Add(playerInstance.Key);
				}
			}
		}

		internal void BroadcastState()
		{
			try
			{
				if (MyceliumNetwork.InLobby)
				{
					MyceliumNetwork.RPC(20260905u, "SyncDeathmatchState", (ReliableType)1, new object[11]
					{
						Enabled.Value,
						ScoreKeeper.MatchLive,
						KillsToWin.Value,
						ScoreKeeper.SecondsLeft,
						CleanupItemsOnDeath.Value,
						RemoveDamageZones.Value,
						ScoreKeeper.Serialize(),
						RestoreLoadoutOnRespawn.Value,
						DefaultWeapon.Value ?? "",
						LoadoutExcludedClasses.Value ?? "",
						LoadoutExcludedWeapons.Value ?? ""
					});
				}
			}
			catch (Exception ex)
			{
				if (Log != null)
				{
					Log.LogWarning((object)("Mycelium broadcast failed: " + ex.GetType().Name + " - " + ex.Message));
				}
			}
		}

		[CustomRPC]
		public void SyncDeathmatchState(bool active, bool matchLive, int killsToWin, int secondsLeft, bool cleanupItems, bool removeZones, string scores, bool restoreLoadout, string defaultWeapon, string excludedClasses, string excludedWeapons)
		{
			if (!PlayerLookup.IsServer)
			{
				ScoreKeeper.ApplySynced(active, matchLive, killsToWin, secondsLeft, cleanupItems, removeZones, scores, restoreLoadout, defaultWeapon, excludedClasses, excludedWeapons);
			}
		}

		[CustomRPC]
		public void RequestLoadout(int playerId, string right, string left, RPCInfo info)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if (!PlayerLookup.IsServer)
			{
				return;
			}
			try
			{
				LoadoutSpawner.HandleRemoteRequest(playerId, right ?? "", left ?? "", info.SenderSteamID);
			}
			catch (Exception ex)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)("[Loadout] request from player " + playerId + " failed: " + ex.GetType().Name + " - " + ex.Message));
				}
			}
		}

		[CustomRPC]
		public void LoadoutSpawned(int playerId, int rightId, int leftId)
		{
			try
			{
				LoadoutKeeper.OnLoadoutSpawned(playerId, rightId, leftId);
			}
			catch
			{
			}
		}

		private static void KillLocalPlayerForTesting()
		{
			try
			{
				int localPlayerId = PlayerLookup.LocalPlayerId;
				if (localPlayerId < 0)
				{
					if (Log != null)
					{
						Log.LogWarning((object)"Kill Self: no local player id.");
					}
					return;
				}
				PlayerHealth val = PlayerLookup.FindHealth(localPlayerId);
				if ((Object)(object)val == (Object)null)
				{
					if (Log != null)
					{
						Log.LogWarning((object)("Kill Self: no PlayerHealth for player " + localPlayerId + "."));
					}
				}
				else if (!val.sync___get_value_isKilled() && !(val.sync___get_value_health() <= 0f))
				{
					if (PlayerLookup.IsServer)
					{
						val.RpcLogic___RemoveHealth_431000436(9999f);
					}
					else
					{
						val.RemoveHealth(9999f);
					}
				}
			}
			catch (Exception ex)
			{
				if (Log != null)
				{
					Log.LogWarning((object)("Kill Self failed: " + ex.GetType().Name + " - " + ex.Message));
				}
			}
		}
	}
	internal static class LoadoutKeeper
	{
		private const float PollSeconds = 0.1f;

		private static MethodInfo _miSetObjectInHandServer;

		private static FieldInfo _fiCam;

		private static FieldInfo _fiRigBuilder;

		private static FieldInfo _fiPickupClip;

		private static string _aliveRight = "";

		private static string _aliveRightClass = "";

		private static string _aliveLeft = "";

		private static string _aliveLeftClass = "";

		private static bool _hasDeathSnapshot;

		private static string _deathRight = "";

		private static string _deathRightClass = "";

		private static string _deathLeft = "";

		private static string _deathLeftClass = "";

		private static GameObject _lastBody;

		private static bool _lastAlive;

		private static bool _capturedThisLife;

		private static float _nextPoll;

		private static bool _replyPending;

		private static int _replyRight = -1;

		private static int _replyLeft = -1;

		private static Coroutine _restore;

		public static bool Available
		{
			get
			{
				if (_miSetObjectInHandServer != null)
				{
					return _fiCam != null;
				}
				return false;
			}
		}

		public static void Init()
		{
			BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
			_miSetObjectInHandServer = typeof(PlayerPickup).GetMethod("SetObjectInHandServer", bindingAttr, null, new Type[5]
			{
				typeof(GameObject),
				typeof(Vector3),
				typeof(Quaternion),
				typeof(GameObject),
				typeof(bool)
			}, null);
			_fiCam = typeof(PlayerPickup).GetField("cam", bindingAttr);
			_fiRigBuilder = typeof(PlayerPickup).GetField("RigBuilder", bindingAttr);
			_fiPickupClip = typeof(PlayerPickup).GetField("pickupClip", bindingAttr);
			if (!Available)
			{
				ManualLogSource log = DeathmatchPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)"[Loadout] PlayerPickup internals not found; loadout restore disabled.");
				}
			}
		}

		public static void Reset()
		{
			_aliveRight = (_aliveRightClass = (_aliveLeft = (_aliveLeftClass = "")));
			_hasDeathSnapshot = false;
			_deathRight = (_deathRightClass = (_deathLeft = (_deathLeftClass = "")));
			_lastBody = null;
			_lastAlive = false;
			_capturedThisLife = false;
			_nextPoll = 0f;
			_replyPending = false;
			_replyRight = (_replyLeft = -1);
			if (_restore != null && (Object)(object)DeathmatchPlugin.Instance != (Object)null)
			{
				((MonoBehaviour)DeathmatchPlugin.Instance).StopCoroutine(_restore);
			}
			_restore = null;
		}

		public static void ClientTick()
		{
			if (Time.time < _nextPoll)
			{
				return;
			}
			_nextPoll = Time.time + 0.1f;
			if (!Available || !ScoreKeeper.ModeActiveLocally())
			{
				return;
			}
			int localPlayerId = PlayerLookup.LocalPlayerId;
			if (localPlayerId < 0)
			{
				return;
			}
			GameObject val = PlayerLookup.FindBody(localPlayerId);
			bool num = IsAlive(val);
			if (num)
			{
				if ((Object)(object)val != (Object)(object)_lastBody)
				{
					_lastBody = val;
					_capturedThisLife = false;
					_aliveRight = (_aliveRightClass = (_aliveLeft = (_aliveLeftClass = "")));
				}
				PlayerPickup val2 = val.GetComponent<PlayerPickup>() ?? val.GetComponentInChildren<PlayerPickup>(true);
				if ((Object)(object)val2 != (Object)null)
				{
					ReadHands(val2, out _aliveRight, out _aliveRightClass, out _aliveLeft, out _aliveLeftClass);
				}
			}
			else if (_lastAlive && !_capturedThisLife)
			{
				Capture(_aliveRight, _aliveRightClass, _aliveLeft, _aliveLeftClass, "last sample");
			}
			_lastAlive = num;
		}

		public static void OnHandDropping(PlayerPickup pickup)
		{
			if (Available && !((Object)(object)pickup == (Object)null) && ((NetworkBehaviour)pickup).IsOwner && IsDead(pickup))
			{
				if ((Object)(object)_lastBody != (Object)(object)((Component)pickup).gameObject)
				{
					_lastBody = ((Component)pickup).gameObject;
					_capturedThisLife = false;
				}
				if (!_capturedThisLife)
				{
					ReadHands(pickup, out var right, out var rightClass, out var left, out var leftClass);
					Capture(right, rightClass, left, leftClass, "death drop");
				}
			}
		}

		private static void ReadHands(PlayerPickup pickup, out string right, out string rightClass, out string left, out string leftClass)
		{
			right = (rightClass = (left = (leftClass = "")));
			try
			{
				GameObject go = (pickup.sync___get_value_hasObjectInHand() ? pickup.sync___get_value_objInHand() : null);
				GameObject go2 = (pickup.sync___get_value_hasObjectInLeftHand() ? pickup.sync___get_value_objInLeftHand() : null);
				right = LoadoutRules.PrefabName(go);
				rightClass = LoadoutRules.WeaponClass(go);
				left = LoadoutRules.PrefabName(go2);
				leftClass = LoadoutRules.WeaponClass(go2);
			}
			catch
			{
			}
		}

		private static void Capture(string right, string rightClass, string left, string leftClass, string source)
		{
			_deathRight = right ?? "";
			_deathRightClass = rightClass ?? "";
			_deathLeft = left ?? "";
			_deathLeftClass = leftClass ?? "";
			_hasDeathSnapshot = true;
			_capturedThisLife = true;
			ManualLogSource log = DeathmatchPlugin.Log;
			if (log != null)
			{
				log.LogInfo((object)("[Loadout] died holding right='" + _deathRight + "' left='" + _deathLeft + "' (" + source + ")"));
			}
		}

		public static void OnPickupStarted(PlayerPickup pickup)
		{
			if (Available && !((Object)(object)pickup == (Object)null) && ((NetworkBehaviour)pickup).IsOwner && ScoreKeeper.ModeActiveLocally() && LoadoutRules.RestoreEnabled && _hasDeathSnapshot && !((Object)(object)DeathmatchPlugin.Instance == (Object)null))
			{
				if (_restore != null)
				{
					((MonoBehaviour)DeathmatchPlugin.Instance).StopCoroutine(_restore);
				}
				_restore = ((MonoBehaviour)DeathmatchPlugin.Instance).StartCoroutine(RestoreRoutine(pickup));
			}
		}

		public static void OnLoadoutSpawned(int playerId, int rightId, int leftId)
		{
			if (playerId == PlayerLookup.LocalPlayerId)
			{
				_replyRight = rightId;
				_replyLeft = leftId;
				_replyPending = false;
			}
		}

		private static IEnumerator RestoreRoutine(PlayerPickup pickup)
		{
			GameObject body = ((Component)pickup).gameObject;
			int playerId = PlayerLookup.LocalPlayerId;
			float deadline = Time.time + 6f;
			while (Time.time < deadline)
			{
				if ((Object)(object)pickup == (Object)null)
				{
					_restore = null;
					yield break;
				}
				if (IsAlive(body) && (Object)/*isinst with value type is only supported in some contexts*/ != (Object)null && (_fiRigBuilder == null || _fiRigBuilder.GetValue(pickup) != null) && pickup.pickupPositionRightHand != null && pickup.pickupPositionRightHand.Length != 0)
				{
					break;
				}
				yield return null;
			}
			if ((Object)(object)pickup == (Object)null || !IsAlive(body))
			{
				_restore = null;
				yield break;
			}
			FirstPersonController controller = ((Component)pickup).GetComponent<FirstPersonController>();
			deadline = Time.time + 3f;
			while (Time.time < deadline && (Object)(object)controller != (Object)null && !controller.sync___get_value_canMove())
			{
				yield return null;
			}
			yield return (object)new WaitForSeconds(0.1f);
			if ((Object)(object)pickup == (Object)null || !IsAlive(body))
			{
				_restore = null;
				yield break;
			}
			BuildRequest(out var right, out var left);
			if (right.Length == 0 && left.Length == 0)
			{
				ManualLogSource log = DeathmatchPlugin.Log;
				if (log != null)
				{
					log.LogInfo((object)"[Loadout] nothing restorable, respawning empty-handed");
				}
				_restore = null;
				yield break;
			}
			_replyPending = true;
			_replyLeft = -1;
			_replyRight = -1;
			if (PlayerLookup.IsServer)
			{
				LoadoutSpawner.HandleLocalRequest(playerId, right, left);
			}
			else
			{
				bool flag = false;
				try
				{
					if (MyceliumNetwork.InLobby)
					{
						MyceliumNetwork.RPCTarget(20260905u, "RequestLoadout", MyceliumNetwork.LobbyHost, (ReliableType)1, new object[3] { playerId, right, left });
						flag = true;
					}
				}
				catch (Exception ex)
				{
					ManualLogSource log2 = DeathmatchPlugin.Log;
					if (log2 != null)
					{
						log2.LogWarning((object)("[Loadout] request failed: " + ex.GetType().Name + " - " + ex.Message));
					}
				}
				if (!flag)
				{
					_replyPending = false;
					_restore = null;
					yield break;
				}
			}
			deadline = Time.time + 4f;
			while (_replyPending && Time.time < deadline)
			{
				yield return null;
			}
			if (_replyPending)
			{
				ManualLogSource log3 = DeathmatchPlugin.Log;
				if (log3 != null)
				{
					log3.LogWarning((object)"[Loadout] no reply from the host; respawning empty-handed");
				}
				_replyPending = false;
				_restore = null;
				yield break;
			}
			GameObject rightGo = null;
			GameObject leftGo = null;
			deadline = Time.time + 3f;
			while (Time.time < deadline)
			{
				if ((Object)(object)rightGo == (Object)null && _replyRight >= 0)
				{
					rightGo = ResolveReady(_replyRight);
				}
				if ((Object)(object)leftGo == (Object)null && _replyLeft >= 0)
				{
					leftGo = ResolveReady(_replyLeft);
				}
				bool num = _replyRight >= 0 && (Object)(object)rightGo == (Object)null;
				bool flag2 = _replyLeft >= 0 && (Object)(object)leftGo == (Object)null;
				if (!num && !flag2)
				{
					break;
				}
				yield return null;
			}
			if ((Object)(object)pickup == (Object)null || !IsAlive(body))
			{
				_restore = null;
				yield break;
			}
			int num2 = 0;
			if ((Object)(object)rightGo != (Object)null && !pickup.sync___get_value_hasObjectInHand() && Equip(pickup, rightGo, rightHand: true))
			{
				num2++;
			}
			if ((Object)(object)leftGo != (Object)null)
			{
				GameObject val = (pickup.sync___get_value_hasObjectInHand() ? pickup.sync___get_value_objInHand() : null);
				Weapon val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Weapon>() : null);
				if ((!((Object)(object)val2 != (Object)null) || !val2.requireBothHands) && !pickup.sync___get_value_hasObjectInLeftHand() && Equip(pickup, leftGo, rightHand: false))
				{
					num2++;
				}
			}
			ManualLogSource log4 = DeathmatchPlugin.Log;
			if (log4 != null)
			{
				log4.LogInfo((object)("[Loadout] restored " + num2 + " weapon(s): right='" + right + "' left='" + left + "'"));
			}
			_restore = null;
		}

		private static void BuildRequest(out string right, out string left)
		{
			List<string> list = new List<string>(2);
			if (LoadoutRules.IsRestorable(_deathRight, _deathRightClass))
			{
				list.Add(_deathRight);
			}
			if (LoadoutRules.IsRestorable(_deathLeft, _deathLeftClass))
			{
				list.Add(_deathLeft);
			}
			if (list.Count == 0)
			{
				string defaultWeapon = LoadoutRules.DefaultWeapon;
				if (defaultWeapon.Length > 0)
				{
					if (LoadoutRules.IsKnownWeapon(defaultWeapon))
					{
						list.Add(defaultWeapon);
					}
					else
					{
						ManualLogSource log = DeathmatchPlugin.Log;
						if (log != null)
						{
							log.LogWarning((object)("[Loadout] default weapon '" + defaultWeapon + "' is not a known weapon prefab"));
						}
					}
				}
			}
			right = ((list.Count > 0) ? list[0] : "");
			left = ((list.Count > 1) ? list[1] : "");
		}

		private static GameObject ResolveReady(int objectId)
		{
			if (!TryFindSpawned(objectId, out var nob) || (Object)(object)nob == (Object)null)
			{
				return null;
			}
			GameObject gameObject = ((Component)nob).gameObject;
			ItemBehaviour component = gameObject.GetComponent<ItemBehaviour>();
			if ((Object)(object)component == (Object)null || (Object)(object)component.gripRight == (Object)null || (Object)(object)component.gripLeft == (Object)null)
			{
				return null;
			}
			return gameObject;
		}

		private static bool TryFindSpawned(int objectId, out NetworkObject nob)
		{
			nob = null;
			if (objectId < 0)
			{
				return false;
			}
			NetworkManager networkManager = InstanceFinder.NetworkManager;
			if ((Object)(object)networkManager == (Object)null)
			{
				return false;
			}
			try
			{
				if (networkManager.IsServer && (Object)(object)networkManager.ServerManager != (Object)null && ((ManagedObjects)networkManager.ServerManager.Objects).Spawned.TryGetValue(objectId, out nob) && (Object)(object)nob != (Object)null)
				{
					return true;
				}
				if (networkManager.IsClient && (Object)(object)networkManager.ClientManager != (Object)null && ((ManagedObjects)networkManager.ClientManager.Objects).Spawned.TryGetValue(objectId, out nob) && (Object)(object)nob != (Object)null)
				{
					return true;
				}
			}
			catch
			{
			}
			nob = null;
			return false;
		}

		private static bool Equip(PlayerPickup pickup, GameObject go, bool rightHand)
		{
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				ItemBehaviour component = go.GetComponent<ItemBehaviour>();
				Weapon component2 = go.GetComponent<Weapon>();
				object? value = _fiCam.GetValue(pickup);
				Camera val = (Camera)((value is Camera) ? value : null);
				if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null || (Object)(object)val == (Object)null)
				{
					return false;
				}
				if (rightHand)
				{
					Transform val2 = Slot(component2.requireBothHands ? pickup.pickupPositionBothHand : pickup.pickupPositionRightHand, component.camChildIndex);
					if ((Object)(object)val2 == (Object)null)
					{
						return false;
					}
					PlayPickupSound(pickup);
					pickup.sync___set_value_objInHand(go, true);
					pickup.sync___set_value_hasObjectInHand(true, true);
					_miSetObjectInHandServer.Invoke(pickup, new object[5]
					{
						go,
						val2.position,
						val2.rotation,
						((Component)val).gameObject,
						true
					});
					pickup.SetRightIKTarget(component.gripRight);
					if (component2.requireBothHands)
					{
						pickup.SetLeftIKTarget(component.gripLeft);
					}
				}
				else
				{
					Transform val3 = Slot(pickup.pickupPositionLeftHand, component.camChildIndexLeftHand);
					if ((Object)(object)val3 == (Object)null)
					{
						return false;
					}
					PlayPickupSound(pickup);
					_miSetObjectInHandServer.Invoke(pickup, new object[5]
					{
						go,
						val3.position,
						val3.rotation,
						((Component)val).gameObject,
						false
					});
					pickup.sync___set_value_objInLeftHand(go, true);
					pickup.sync___set_value_hasObjectInLeftHand(true, true);
					pickup.SetLeftIKTarget(component.gripLeft);
				}
				component.dispenserStart = false;
				RigBuild(pickup);
				return true;
			}
			catch (Exception ex)
			{
				Exception ex2 = ((ex is TargetInvocationException && ex.InnerException != null) ? ex.InnerException : ex);
				ManualLogSource log = DeathmatchPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[Loadout] equip failed: " + ex2.GetType().Name + " - " + ex2.Message));
				}
				return false;
			}
		}

		private static Transform Slot(Transform[] slots, int index)
		{
			if (slots == null || slots.Length == 0)
			{
				return null;
			}
			if (index < 0 || index >= slots.Length)
			{
				index = 0;
			}
			return slots[index];
		}

		private static void RigBuild(PlayerPickup pickup)
		{
			try
			{
				object obj = ((_fiRigBuilder != null) ? _fiRigBuilder.GetValue(pickup) : null);
				if (obj != null)
				{
					MethodInfo method = obj.GetType().GetMethod("Build", Type.EmptyTypes);
					if (method != null)
					{
						method.Invoke(obj, null);
					}
				}
			}
			catch
			{
			}
		}

		private static void PlayPickupSound(PlayerPickup pickup)
		{
			try
			{
				AudioClip val = (AudioClip)((_fiPickupClip != null) ? /*isinst with value type is only supported in some contexts*/: null);
				if ((Object)(object)val != (Object)null && (Object)(object)SoundManager.Instance != (Object)null)
				{
					SoundManager.Instance.PlaySound(val);
				}
			}
			catch
			{
			}
		}

		private static bool IsAlive(GameObject body)
		{
			if ((Object)(object)body == (Object)null || !body.activeInHierarchy)
			{
				return false;
			}
			PlayerHealth component = body.GetComponent<PlayerHealth>();
			if ((Object)(object)component == (Object)null)
			{
				return false;
			}
			if (component.sync___get_value_health() > 0f)
			{
				return !component.sync___get_value_isKilled();
			}
			return false;
		}

		private static bool IsDead(PlayerPickup pickup)
		{
			PlayerHealth val = (((Object)(object)pickup != (Object)null) ? ((Component)pickup).GetComponentInParent<PlayerHealth>() : null);
			if ((Object)(object)val != (Object)null)
			{
				if (!(val.sync___get_value_health() <= 0f))
				{
					return val.sync___get_value_isKilled();
				}
				return true;
			}
			return false;
		}
	}
	internal static class LoadoutRules
	{
		public static bool RestoreEnabled
		{
			get
			{
				if (!PlayerLookup.IsServer)
				{
					return ScoreKeeper.SyncedRestoreLoadout;
				}
				return DeathmatchPlugin.RestoreLoadoutOnRespawn.Value;
			}
		}

		public static string DefaultWeapon => ((PlayerLookup.IsServer ? DeathmatchPlugin.DefaultWeapon.Value : ScoreKeeper.SyncedDefaultWeapon) ?? "").Trim();

		private static string ExcludedClasses => (PlayerLookup.IsServer ? DeathmatchPlugin.LoadoutExcludedClasses.Value : ScoreKeeper.SyncedExcludedClasses) ?? "";

		private static string ExcludedWeapons => (PlayerLookup.IsServer ? DeathmatchPlugin.LoadoutExcludedWeapons.Value : ScoreKeeper.SyncedExcludedWeapons) ?? "";

		public static string PrefabName(GameObject go)
		{
			if ((Object)(object)go == (Object)null)
			{
				return "";
			}
			if ((Object)(object)go.GetComponent<Weapon>() == (Object)null || (Object)(object)go.GetComponent<ItemBehaviour>() == (Object)null)
			{
				return "";
			}
			string text = ((Object)go).name ?? "";
			int num = text.IndexOf("(Clone)", StringComparison.Ordinal);
			if (num >= 0)
			{
				text = text.Substring(0, num);
			}
			return text.Trim();
		}

		public static string WeaponClass(GameObject go)
		{
			Weapon val = (((Object)(object)go != (Object)null) ? go.GetComponent<Weapon>() : null);
			if (!((Object)(object)val != (Object)null))
			{
				return "";
			}
			return ((object)val).GetType().Name;
		}

		public static bool IsKnownWeapon(string prefabName)
		{
			if (string.IsNullOrEmpty(prefabName))
			{
				return false;
			}
			try
			{
				SpawnerManager.PopulateAllWeapons();
				GameObject value;
				return SpawnerManager.NameToWeaponDict.TryGetValue(prefabName, out value) && (Object)(object)value != (Object)null;
			}
			catch
			{
				return false;
			}
		}

		public static GameObject GetPrefab(string prefabName)
		{
			if (!IsKnownWeapon(prefabName))
			{
				return null;
			}
			return SpawnerManager.NameToWeaponDict[prefabName];
		}

		public static bool IsRestorable(string prefabName, string weaponClass)
		{
			if (!IsKnownWeapon(prefabName))
			{
				return false;
			}
			if (InList(ExcludedWeapons, prefabName))
			{
				return false;
			}
			if (IsExcludedClass(ResolveType(weaponClass)))
			{
				return false;
			}
			return true;
		}

		public static bool IsRestorablePrefab(string prefabName)
		{
			GameObject prefab = GetPrefab(prefabName);
			if ((Object)(object)prefab == (Object)null)
			{
				return false;
			}
			if (InList(ExcludedWeapons, prefabName))
			{
				return false;
			}
			Weapon component = prefab.GetComponent<Weapon>();
			if ((Object)(object)component != (Object)null)
			{
				return !IsExcludedClass(((object)component).GetType());
			}
			return false;
		}

		private static Type ResolveType(string weaponClass)
		{
			if (string.IsNullOrEmpty(weaponClass))
			{
				return null;
			}
			try
			{
				return typeof(Weapon).Assembly.GetType(weaponClass);
			}
			catch
			{
				return null;
			}
		}

		private static bool IsExcludedClass(Type type)
		{
			Type type2 = type;
			while (type2 != null && type2 != typeof(object))
			{
				if (InList(ExcludedClasses, type2.Name))
				{
					return true;
				}
				type2 = type2.BaseType;
			}
			return false;
		}

		private static bool InList(string csv, string value)
		{
			if (string.IsNullOrEmpty(csv) || string.IsNullOrEmpty(value))
			{
				return false;
			}
			string[] array = csv.Split(',', ';');
			for (int i = 0; i < array.Length; i++)
			{
				if (string.Equals(array[i].Trim(), value, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}
	}
	internal static class LoadoutSpawner
	{
		private class Pending
		{
			public NetworkObject Nob;

			public int PlayerId;

			public float Deadline;
		}

		private const float UnclaimedSeconds = 6f;

		private static readonly List<Pending> _pending = new List<Pending>();

		public static void Reset()
		{
			_pending.Clear();
		}

		public static void HandleLocalRequest(int playerId, string right, string left)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			Handle(playerId, right, left, CSteamID.Nil, local: true);
		}

		public static void HandleRemoteRequest(int playerId, string right, string left, CSteamID sender)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			Handle(playerId, right, left, sender, local: false);
		}

		private static void Handle(int playerId, string right, string left, CSteamID sender, bool local)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			if (!PlayerLookup.IsServer || !ScoreKeeper.ModeActiveLocally() || !DeathmatchPlugin.RestoreLoadoutOnRespawn.Value)
			{
				return;
			}
			GameObject val = PlayerLookup.FindBody(playerId);
			if ((Object)(object)val == (Object)null || !val.activeInHierarchy)
			{
				ManualLogSource log = DeathmatchPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[Loadout] player=" + playerId + " asked for a loadout without a body"));
				}
				Reply(playerId, -1, -1, sender, local);
				return;
			}
			List<string> list = new List<string>(2);
			if (LoadoutRules.IsRestorablePrefab(right ?? ""))
			{
				list.Add(right);
			}
			if (LoadoutRules.IsRestorablePrefab(left ?? ""))
			{
				list.Add(left);
			}
			if (list.Count == 0)
			{
				string defaultWeapon = LoadoutRules.DefaultWeapon;
				if (defaultWeapon.Length > 0 && LoadoutRules.IsKnownWeapon(defaultWeapon))
				{
					list.Add(defaultWeapon);
				}
			}
			if (list.Count > 1)
			{
				GameObject prefab = LoadoutRules.GetPrefab(list[0]);
				Weapon val2 = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<Weapon>() : null);
				if ((Object)(object)val2 != (Object)null && val2.requireBothHands)
				{
					list.RemoveAt(1);
				}
			}
			int rightId = ((list.Count > 0) ? SpawnOne(list[0], val, playerId) : (-1));
			int leftId = ((list.Count > 1) ? SpawnOne(list[1], val, playerId) : (-1));
			ManualLogSource log2 = DeathmatchPlugin.Log;
			if (log2 != null)
			{
				log2.LogInfo((object)("[Loadout] player=" + playerId + " spawned right='" + ((list.Count > 0) ? list[0] : "") + "' left='" + ((list.Count > 1) ? list[1] : "") + "' (ids " + rightId + ", " + leftId + ")"));
			}
			Reply(playerId, rightId, leftId, sender, local);
		}

		private static void Reply(int playerId, int rightId, int leftId, CSteamID sender, bool local)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			if (local)
			{
				LoadoutKeeper.OnLoadoutSpawned(playerId, rightId, leftId);
				return;
			}
			try
			{
				MyceliumNetwork.RPCTarget(20260905u, "LoadoutSpawned", sender, (ReliableType)1, new object[3] { playerId, rightId, leftId });
			}
			catch (Exception ex)
			{
				ManualLogSource log = DeathmatchPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[Loadout] reply to player " + playerId + " failed: " + ex.GetType().Name + " - " + ex.Message));
				}
			}
		}

		private static int SpawnOne(string prefabName, GameObject body, int playerId)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				GameObject prefab = LoadoutRules.GetPrefab(prefabName);
				if ((Object)(object)prefab == (Object)null)
				{
					return -1;
				}
				Vector3 val = body.transform.position + body.transform.forward * 0.5f + Vector3.up * 1.2f;
				GameObject val2 = Object.Instantiate<GameObject>(prefab, val, body.transform.rotation);
				ItemBehaviour component = val2.GetComponent<ItemBehaviour>();
				if ((Object)(object)component != (Object)null)
				{
					component.dispenserStart = true;
				}
				Rigidbody component2 = val2.GetComponent<Rigidbody>();
				if ((Object)(object)component2 != (Object)null)
				{
					component2.isKinematic = true;
					component2.useGravity = false;
				}
				InstanceFinder.ServerManager.Spawn(val2, (NetworkConnection)null);
				NetworkObject component3 = val2.GetComponent<NetworkObject>();
				if ((Object)(object)component3 == (Object)null)
				{
					Object.Destroy((Object)(object)val2);
					return -1;
				}
				_pending.Add(new Pending
				{
					Nob = component3,
					PlayerId = playerId,
					Deadline = Time.time + 6f
				});
				return component3.ObjectId;
			}
			catch (Exception ex)
			{
				ManualLogSource log = DeathmatchPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[Loadout] spawning '" + prefabName + "' failed: " + ex.GetType().Name + " - " + ex.Message));
				}
				return -1;
			}
		}

		public static void ServerTick()
		{
			if (_pending.Count == 0)
			{
				return;
			}
			for (int num = _pending.Count - 1; num >= 0; num--)
			{
				Pending pending = _pending[num];
				if ((Object)(object)pending.Nob == (Object)null)
				{
					_pending.RemoveAt(num);
				}
				else
				{
					GameObject gameObject = ((Component)pending.Nob).gameObject;
					ItemBehaviour component = gameObject.GetComponent<ItemBehaviour>();
					if (IsHeld(gameObject, component))
					{
						if ((Object)(object)component != (Object)null)
						{
							component.dispenserStart = false;
						}
						_pending.RemoveAt(num);
					}
					else if (!(Time.time < pending.Deadline))
					{
						ManualLogSource log = DeathmatchPlugin.Log;
						if (log != null)
						{
							log.LogInfo((object)("[Loadout] player=" + pending.PlayerId + " never picked up '" + ((Object)gameObject).name + "'; removing it"));
						}
						RespawnController.DespawnOrDestroy(gameObject);
						_pending.RemoveAt(num);
					}
				}
			}
		}

		private static bool IsHeld(GameObject go, ItemBehaviour item)
		{
			if ((Object)(object)go == (Object)null)
			{
				return false;
			}
			if (go.layer == 8 || (Object)(object)go.transform.parent != (Object)null)
			{
				return true;
			}
			if ((Object)(object)item != (Object)null)
			{
				if (!item.isTaken)
				{
					return (Object)(object)item.rootObject != (Object)null;
				}
				return true;
			}
			return false;
		}
	}
	internal static class PlayerLookup
	{
		public static bool IsServer
		{
			get
			{
				if ((Object)(object)InstanceFinder.NetworkManager != (Object)null)
				{
					return InstanceFinder.NetworkManager.IsServer;
				}
				return false;
			}
		}

		public static int LocalPlayerId
		{
			get
			{
				if (!((Object)(object)ClientInstance.Instance != (Object)null))
				{
					return -1;
				}
				return ClientInstance.Instance.PlayerId;
			}
		}

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

		public static GameObject FindBody(int playerId)
		{
			PlayerManager val = FindPlayerManager(playerId);
			if ((Object)(object)val != (Object)null && (Object)(object)val.player != (Object)null)
			{
				return ((Component)val.player).gameObject;
			}
			return null;
		}

		public static PlayerHealth FindHealth(int playerId)
		{
			GameObject val = FindBody(playerId);
			if ((Object)(object)val != (Object)null)
			{
				PlayerHealth component = val.GetComponent<PlayerHealth>();
				if ((Object)(object)component != (Object)null)
				{
					return component;
				}
			}
			PlayerHealth[] array = Object.FindObjectsOfType<PlayerHealth>(true);
			foreach (PlayerHealth val2 in array)
			{
				if ((Object)(object)val2 != (Object)null && GetPlayerId(val2.sync___get_value_playerValues()) == playerId)
				{
					return val2;
				}
			}
			return null;
		}

		public static PlayerPickup FindPickup(int playerId)
		{
			GameObject val = FindBody(playerId);
			if ((Object)(object)val != (Object)null)
			{
				PlayerPickup componentInChildren = val.GetComponentInChildren<PlayerPickup>(true);
				if ((Object)(object)componentInChildren != (Object)null)
				{
					return componentInChildren;
				}
			}
			PlayerPickup[] array = Object.FindObjectsOfType<PlayerPickup>(true);
			foreach (PlayerPickup val2 in array)
			{
				if ((Object)(object)val2 != (Object)null && (Object)(object)val2.playerValues != (Object)null && GetPlayerId(val2.playerValues) == playerId)
				{
					return val2;
				}
			}
			return null;
		}

		public static int GetPlayerId(PlayerValues values)
		{
			if ((Object)(object)values == (Object)null)
			{
				return -1;
			}
			ClientInstance val = values.sync___get_value_playerClient();
			if (!((Object)(object)val != (Object)null))
			{
				return -1;
			}
			return val.PlayerId;
		}

		public static string GetNameTag(int playerId)
		{
			if (ClientInstance.playerInstances.TryGetValue(playerId, out var value) && (Object)(object)value != (Object)null)
			{
				return value.PlayerNameTag;
			}
			return "Player " + playerId;
		}

		public static string GetName(int playerId)
		{
			if (ClientInstance.playerInstances.TryGetValue(playerId, out var value) && (Object)(object)value != (Object)null && !string.IsNullOrEmpty(value.PlayerName))
			{
				return value.PlayerName;
			}
			return "Player " + playerId;
		}

		public static bool IsBodyAlive(int playerId, out string reason)
		{
			reason = "";
			PlayerManager val = FindPlayerManager(playerId);
			if ((Object)(object)val == (Object)null)
			{
				reason = "missing PlayerManager";
				return false;
			}
			if ((Object)(object)val.player == (Object)null)
			{
				reason = "no body";
				return false;
			}
			GameObject gameObject = ((Component)val.player).gameObject;
			if ((Object)(object)gameObject == (Object)null || !gameObject.activeInHierarchy)
			{
				reason = "inactive body";
				return false;
			}
			if (GetPlayerId(gameObject.GetComponent<PlayerValues>()) != playerId)
			{
				reason = "player id mismatch";
				return false;
			}
			PlayerHealth component = gameObject.GetComponent<PlayerHealth>();
			if ((Object)(object)component == (Object)null)
			{
				reason = "missing PlayerHealth";
				return false;
			}
			if (component.sync___get_value_health() <= 0f || component.sync___get_value_isKilled())
			{
				reason = "dead";
				return false;
			}
			NetworkObject component2 = gameObject.GetComponent<NetworkObject>();
			if ((Object)(object)component2 == (Object)null || !component2.IsSpawned)
			{
				reason = "body not spawned";
				return false;
			}
			CharacterController component3 = gameObject.GetComponent<CharacterController>();
			if ((Object)(object)component3 == (Object)null || !((Collider)component3).enabled)
			{
				reason = "character controller not ready";
				return false;
			}
			return true;
		}

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

		public static int FindKillerId(int victimId)
		{
			PlayerHealth val = FindHealth(victimId);
			if ((Object)(object)val == (Object)null)
			{
				return -1;
			}
			Transform val2 = null;
			try
			{
				val2 = val.sync___get_value_killer();
			}
			catch
			{
			}
			if ((Object)(object)val2 == (Object)null)
			{
				return -1;
			}
			ClientInstance componentInParent = ((Component)val2).GetComponentInParent<ClientInstance>(true);
			if ((Object)(object)componentInParent != (Object)null)
			{
				return componentInParent.PlayerId;
			}
			int playerId = GetPlayerId(((Component)val2).GetComponentInParent<PlayerValues>(true) ?? ((Component)val2).GetComponentInChildren<PlayerValues>(true));
			if (playerId >= 0)
			{
				return playerId;
			}
			GameObject val3 = null;
			ProximityMine val4 = ((Component)val2).GetComponentInParent<ProximityMine>(true) ?? ((Component)val2).GetComponentInChildren<ProximityMine>(true);
			if ((Object)(object)val4 != (Object)null)
			{
				val3 = val4.sync___get_value__rootObject();
			}
			else
			{
				Claymore val5 = ((Component)val2).GetComponentInParent<Claymore>(true) ?? ((Component)val2).GetComponentInChildren<Claymore>(true);
				if ((Object)(object)val5 != (Object)null)
				{
					val3 = val5.sync___get_value__rootObject();
				}
			}
			if (!((Object)(object)val3 != (Object)null))
			{
				return -1;
			}
			return GetOwnerIdFromRootObject(val3);
		}
	}
	internal static class RespawnController
	{
		private class Pending
		{
			public float RespawnAt;

			public float LastAttempt = -999f;

			public int Attempts;
		}

		private const float TickSeconds = 0.25f;

		private const float RetrySeconds = 2.5f;

		private const float BodilessGraceSeconds = 4f;

		private const float SweepSeconds = 1f;

		private static float _nextSweep;

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

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

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

		private static readonly Dictionary<int, KeyValuePair<int, int>> _cosmetics = new Dictionary<int, KeyValuePair<int, int>>();

		private static float _nextTick;

		private static FieldInfo _fiSpawnedObject;

		private static MethodInfo _miSpawnPlayer4;

		private static MethodInfo _miCmdRespawnLogic;

		public static void Init()
		{
			BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
			_fiSpawnedObject = typeof(PlayerManager).GetField("SpawnedObject", bindingAttr);
			_miSpawnPlayer4 = typeof(PlayerManager).GetMethod("SpawnPlayer", bindingAttr, null, new Type[4]
			{
				typeof(int),
				typeof(int),
				typeof(Vector3),
				typeof(Quaternion)
			}, null);
			_miCmdRespawnLogic = typeof(PlayerManager).GetMethod("RpcLogic___CmdRespawn_2166136261", bindingAttr);
			if (_fiSpawnedObject == null || _miSpawnPlayer4 == null)
			{
				ManualLogSource log = DeathmatchPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)"[Respawn] PlayerManager internals not found; falling back to the native respawn RPC.");
				}
			}
			if (_miCmdRespawnLogic == null)
			{
				ManualLogSource log2 = DeathmatchPlugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)"[Respawn] native respawn RPC logic not found.");
				}
			}
		}

		public static void Reset()
		{
			_pending.Clear();
			_bodilessSince.Clear();
			_ragdolls.Clear();
			_nextTick = 0f;
		}

		public static void OnServerDeath(int playerId)
		{
			if (DeathmatchPlugin.CleanupItemsOnDeath.Value)
			{
				DespawnHeldItems(playerId);
				SweepOrphanedItems(PlayerLookup.FindBody(playerId));
			}
			if (DeathmatchPlugin.CleanupMinesOnDeath.Value)
			{
				ClearPlacedExplosives(playerId);
			}
			Schedule(playerId);
		}

		public static void Schedule(int playerId)
		{
			float num = Mathf.Max(0.25f, DeathmatchPlugin.RespawnDelay.Value);
			_pending[playerId] = new Pending
			{
				RespawnAt = Time.time + num
			};
			Log(playerId, 0, "respawn queued in " + num.ToString("0.00") + "s");
		}

		public static void OnServerSpawned(int playerId)
		{
			_pending.Remove(playerId);
			_bodilessSince.Remove(playerId);
		}

		public static void RememberCosmetics(int playerId, int suit, int cig)
		{
			_cosmetics[playerId] = new KeyValuePair<int, int>(suit, cig);
		}

		public static void ServerTick()
		{
			if (ScoreKeeper.MatchOver || Time.time < _nextTick)
			{
				return;
			}
			_nextTick = Time.time + 0.25f;
			if (DeathmatchPlugin.CleanupItemsOnDeath.Value && Time.time >= _nextSweep)
			{
				_nextSweep = Time.time + 1f;
				SweepOrphanedItems(null);
			}
			foreach (int item in new List<int>(ClientInstance.playerInstances.Keys))
			{
				if (PlayerLookup.IsBodyAlive(item, out var reason))
				{
					_pending.Remove(item);
					_bodilessSince.Remove(item);
					continue;
				}
				if (!_pending.TryGetValue(item, out var value))
				{
					if (!ScoreKeeper.MatchLive)
					{
						continue;
					}
					if (!_bodilessSince.TryGetValue(item, out var value2))
					{
						_bodilessSince[item] = Time.time;
						continue;
					}
					if (Time.time - value2 < 4f)
					{
						continue;
					}
					Log(item, 0, "no living body (" + reason + "); scheduling spawn");
					Schedule(item);
					value = _pending[item];
				}
				if (!(Time.time < value.RespawnAt) && !(Time.time - value.LastAttempt < 2.5f) && (value.Attempts < 6 || !(Time.time - value.LastAttempt < 6f)))
				{
					value.LastAttempt = Time.time;
					value.Attempts++;
					TryRespawn(item, value.Attempts);
				}
			}
		}

		private static void TryRespawn(int playerId, int attempt)
		{
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			PlayerManager val = PlayerLookup.FindPlayerManager(playerId);
			if ((Object)(object)val == (Object)null)
			{
				Log(playerId, attempt, "missing PlayerManager");
				return;
			}
			DestroyRagdoll(playerId);
			GetCosmetics(playerId, val, out var suit, out var cig);
			if (_fiSpawnedObject == null || _miSpawnPlayer4 == null || !SpawnSelector.TryPick(playerId, out var point, out var position, out var rotation))
			{
				NativeRespawn(val, playerId, attempt);
				return;
			}
			try
			{
				object? value = _fiSpawnedObject.GetValue(val);
				GameObject val2 = (GameObject)((value is GameObject) ? value : null);
				if ((Object)(object)val2 != (Object)null)
				{
					if (val2.activeSelf)
					{
						val2.SetActive(false);
					}
					if (DeathmatchPlugin.CleanupItemsOnDeath.Value)
					{
						SweepOrphanedItems(val2);
					}
					DespawnOrDestroy(val2);
				}
				_miSpawnPlayer4.Invoke(val, new object[4] { suit, cig, position, rotation });
				Log(playerId, attempt, "spawned at '" + ((Object)point).name + "'");
			}
			catch (Exception ex)
			{
				Log(playerId, attempt, "direct spawn failed: " + ex.GetType().Name + " - " + ex.Message);
				NativeRespawn(val, playerId, attempt);
			}
		}

		private static void NativeRespawn(PlayerManager pm, int playerId, int attempt)
		{
			if (_miCmdRespawnLogic == null)
			{
				return;
			}
			try
			{
				_miCmdRespawnLogic.Invoke(pm, null);
				Log(playerId, attempt, "native respawn invoked");
			}
			catch (Exception ex)
			{
				Exception ex2 = ((ex is TargetInvocationException { InnerException: not null } ex3) ? ex3.InnerException : ex);
				Log(playerId, attempt, "native respawn failed: " + ex2.GetType().Name + " - " + ex2.Message);
			}
		}

		public static bool InvokeSpawnPlayer(PlayerManager pm, int suit, int cig, Vector3 pos, Quaternion rot)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			if (_miSpawnPlayer4 == null)
			{
				return false;
			}
			_miSpawnPlayer4.Invoke(pm, new object[4] { suit, cig, pos, rot });
			return true;
		}

		private static void GetCosmetics(int playerId, PlayerManager pm, out int suit, out int cig)
		{
			if (_cosmetics.TryGetValue(playerId, out var value))
			{
				suit = value.Key;
				cig = value.Value;
				return;
			}
			try
			{
				PlayerSetup val = (((Object)(object)pm.player != (Object)null) ? ((Component)pm.player).GetComponent<PlayerSetup>() : null);
				if ((Object)(object)val != (Object)null)
				{
					suit = val.sync___get_value_mat();
					cig = val.sync___get_value_cig();
					return;
				}
			}
			catch
			{
			}
			suit = (((Object)(object)CosmeticsManager.Instance != (Object)null) ? CosmeticsManager.Instance.currentsuitIndex : 0);
			cig = (((Object)(object)CosmeticsManager.Instance != (Object)null) ? CosmeticsManager.Instance.currentcigIndex : 0);
		}

		public static void DespawnHeldItems(int playerId)
		{
			PlayerPickup val = PlayerLookup.FindPickup(playerId);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			try
			{
				GameObject obj = val.sync___get_value_objInHand();
				GameObject obj2 = (val.sync___get_value_hasObjectInLeftHand() ? val.sync___get_value_objInLeftHand() : null);
				val.sync___set_value_hasObjectInHand(false, true);
				val.sync___set_value_hasObjectInLeftHand(false, true);
				val.sync___set_value_objInHand((GameObject)null, true);
				val.sync___set_value_objInLeftHand((GameObject)null, true);
				DespawnOrDestroy(obj);
				DespawnOrDestroy(obj2);
				ItemBehaviour[] componentsInChildren = ((Component)((Component)val).transform.root).GetComponentsInChildren<ItemBehaviour>(true);
				foreach (ItemBehaviour val2 in componentsInChildren)
				{
					if ((Object)(object)val2 != (Object)null)
					{
						DespawnOrDestroy(((Component)val2).gameObject);
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = DeathmatchPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[Cleanup] held items for player " + playerId + ": " + ex.GetType().Name));
				}
			}
		}

		public static void ClearPlacedExplosives(int playerId)
		{
			int num = 0;
			try
			{
				ProximityMine[] array = Object.FindObjectsOfType<ProximityMine>(true);
				foreach (ProximityMine val in array)
				{
					if (!((Object)(object)val == (Object)null) && PlayerLookup.GetOwnerIdFromRootObject(val.sync___get_value__rootObject()) == playerId)
					{
						DespawnOrDestroy(((Component)val).gameObject);
						num++;
					}
				}
				Claymore[] array2 = Object.FindObjectsOfType<Claymore>(true);
				foreach (Claymore val2 in array2)
				{
					if (!((Object)(object)val2 == (Object)null) && PlayerLookup.GetOwnerIdFromRootObject(val2.sync___get_value__rootObject()) == playerId)
					{
						DespawnOrDestroy(((Component)val2).gameObject);
						num++;
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = DeathmatchPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[Cleanup] explosives for player " + playerId + ": " + ex.GetType().Name));
				}
			}
			if (num > 0)
			{
				ManualLogSource log2 = DeathmatchPlugin.Log;
				if (log2 != null)
				{
					log2.LogInfo((object)("[Cleanup] removed " + num + " placed explosive(s) of player " + playerId));
				}
			}
		}

		public static int SweepOrphanedItems(GameObject dyingBody)
		{
			int num = 0;
			try
			{
				ItemBehaviour[] array = Object.FindObjectsOfType<ItemBehaviour>(true);
				foreach (ItemBehaviour val in array)
				{
					if (!((Object)(object)val == (Object)null) && IsOrphan(val, dyingBody))
					{
						DespawnOrDestroy(((Component)val).gameObject);
						num++;
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = DeathmatchPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[Cleanup] orphan sweep: " + ex.GetType().Name + " - " + ex.Message));
				}
			}
			if (num > 0)
			{
				ManualLogSource log2 = DeathmatchPlugin.Log;
				if (log2 != null)
				{
					log2.LogInfo((object)("[Cleanup] removed " + num + " orphaned item(s)"));
				}
			}
			return num;
		}

		private static bool IsOrphan(ItemBehaviour item, GameObject dyingBody)
		{
			GameObject val = null;
			if (item.rootObject != null)
			{
				if ((Object)(object)item.rootObject == (Object)null)
				{
					return true;
				}
				val = item.rootObject;
			}
			if ((Object)(object)val == (Object)null && item.playerPickup != null)
			{
				if ((Object)(object)item.playerPickup == (Object)null)
				{
					return true;
				}
				val = ((Component)item.playerPickup).gameObject;
			}
			if ((Object)(object)val == (Object)null)
			{
				PlayerHealth componentInParent = ((Component)item).GetComponentInParent<PlayerHealth>(true);
				if ((Object)(object)componentInParent != (Object)null)
				{
					val = ((Component)componentInParent).gameObject;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			if ((Object)(object)dyingBody != (Object)null && (Object)(object)val == (Object)(object)dyingBody)
			{
				return true;
			}
			if (!val.activeInHierarchy)
			{
				return true;
			}
			PlayerHealth component = val.GetComponent<PlayerHealth>();
			if ((Object)(object)component != (Object)null && (component.sync___get_value_health() <= 0f || component.sync___get_value_isKilled()))
			{
				return true;
			}
			return false;
		}

		public static void ClearHand(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
			{
			}
		}

		public static void DespawnOrDestroy(GameObject obj)
		{
			if ((Object)(object)obj == (Object)null)
			{
				return;
			}
			try
			{
				NetworkObject componentInParent = obj.GetComponentInParent<NetworkObject>();
				if ((Object)(object)componentInParent != (Object)null && componentInParent.IsSpawned && (Object)(object)InstanceFinder.ServerManager != (Object)null)
				{
					InstanceFinder.ServerManager.Despawn(componentInParent, (DespawnType?)null);
					return;
				}
			}
			catch
			{
			}
			try
			{
				Object.Destroy((Object)(object)obj);
			}
			catch
			{
			}
		}

		public static void TrackRagdoll(PlayerHealth health)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				int playerId = PlayerLookup.GetPlayerId(health.sync___get_value_playerValues());
				if (playerId < 0)
				{
					return;
				}
				RagdollDress val = null;
				float num = float.MaxValue;
				RagdollDress[] array = Object.FindObjectsOfType<RagdollDress>(true);
				foreach (RagdollDress val2 in array)
				{
					float num2 = Vector3.Distance(((Component)val2).transform.position, ((Component)health).transform.position);
					if (num2 < num)
					{
						num = num2;
						val = val2;
					}
				}
				if ((Object)(object)val != (Object)null)
				{
					_ragdolls[playerId] = ((Component)val).gameObject;
				}
			}
			catch
			{
			}
		}

		public static void DestroyRagdoll(int playerId)
		{
			try
			{
				if (_ragdolls.TryGetValue(playerId, out var value) && (Object)(object)value != (Object)null)
				{
					Object.Destroy((Object)(object)value);
				}
				_ragdolls.Remove(playerId);
				HatPosition[] array = Object.FindObjectsOfType<HatPosition>(true);
				foreach (HatPosition val in array)
				{
					if ((Object)(object)val != (Object)null && (Object)(object)((Component)val).transform.parent == (Object)null)
					{
						Object.Destroy((Object)(object)((Component)val).gameObject);
					}
				}
			}
			catch
			{
			}
		}

		public static void CleanupWorldEffects()
		{
			try
			{
				foreach (KeyValuePair<int, GameObject> ragdoll in _ragdolls)
				{
					if ((Object)(object)ragdoll.Value != (Object)null)
					{
						Object.Destroy((Object)(object)ragdoll.Value);
					}
				}
				_ragdolls.Clear();
				RagdollDress[] array = Object.FindObjectsOfType<RagdollDress>(true);
				for (int i = 0; i < array.Length; i++)
				{
					Object.Destroy((Object)(object)((Component)array[i]).gameObject);
				}
			}
			catch
			{
			}
		}

		private static void Log(int playerId, int attempt, string message)
		{
			ManualLogSource log = DeathmatchPlugin.Log;
			if (log != null)
			{
				log.LogInfo((object)("[Respawn] player=" + playerId + " attempt=" + attempt + ": " + message));
			}
		}
	}
	internal static class ScoreKeeper
	{
		public struct Row
		{
			public int PlayerId;

			public int Kills;

			public int Deaths;
		}

		public const string Tag = "<b><color=#FF4040>[DM]</color></b>";

		public static readonly Dictionary<int, int> Kills = new Dictionary<int, int>();

		public static readonly Dictionary<int, int> Deaths = new Dictionary<int, int>();

		public static bool MatchOver;

		public static bool AnyDeathThisMap;

		public static bool LocalDiedThisMap;

		public static bool SyncedActive;

		public static bool SyncedMatchLive;

		public static int SyncedKillsToWin;

		public static int SyncedSecondsLeft = -1;

		public static bool SyncedCleanupItems = true;

		public static bool SyncedRemoveDamageZones;

		public static float LastSyncTime = -999f;

		public static bool SyncedRestoreLoadout = true;

		public static string SyncedDefaultWeapon = "Gun";

		public static string SyncedExcludedClasses = "DualLauncher";

		public static string SyncedExcludedWeapons = "";

		private static float _mapStartTime;

		private static float _countdownEndsAt = -1f;

		private static bool _winInProgress;

		private static bool _suddenDeathAnnounced;

		private static bool _dirty;

		private static float _nextBroadcast;

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

		private static MethodInfo _miRoundWon;

		public static bool MatchLive
		{
			get
			{
				if (!PlayerLookup.IsServer)
				{
					return SyncedMatchLive;
				}
				return IsMidMatchLocally();
			}
		}

		public static int EffectiveKillsToWin
		{
			get
			{
				if (PlayerLookup.IsServer)
				{
					return DeathmatchPlugin.KillsToWin.Value;
				}
				if (SyncedKillsToWin <= 0)
				{
					return DeathmatchPlugin.KillsToWin.Value;
				}
				return SyncedKillsToWin;
			}
		}

		public static bool CleanupItemsEffective
		{
			get
			{
				if (!PlayerLookup.IsServer)
				{
					return SyncedCleanupItems;
				}
				return DeathmatchPlugin.CleanupItemsOnDeath.Value;
			}
		}

		public static bool RemoveDamageZonesEffective
		{
			get
			{
				if (!PlayerLookup.IsServer)
				{
					return SyncedRemoveDamageZones;
				}
				return DeathmatchPlugin.RemoveDamageZones.Value;
			}
		}

		public static int SecondsLeft
		{
			get
			{
				if (!PlayerLookup.IsServer)
				{
					return SyncedSecondsLeft;
				}
				int value = DeathmatchPlugin.TimeLimitMinutes.Value;
				if (value <= 0)
				{
					return -1;
				}
				return Mathf.Max(0, Mathf.CeilToInt((float)value * 60f - (Time.time - _mapStartTime)));
			}
		}

		public static void Init()
		{
			_miRoundWon = typeof(GameManager).GetMethod("RoundWon", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (_miRoundWon == null)
			{
				ManualLogSource log = DeathmatchPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)"GameManager.RoundWon not found; round wins will not award match points.");
				}
			}
		}

		public static void Reset()
		{
			Kills.Clear();
			Deaths.Clear();
			MatchOver = false;
			AnyDeathThisMap = false;
			LocalDiedThisMap = false;
			_mapStartTime = Time.time;
			_countdownEndsAt = -1f;
			_winInProgress = false;
			_suddenDeathAnnounced = false;
			_lastDeathHandled.Clear();
			_dirty = true;
			_nextBroadcast = 0f;
		}

		public static bool ModeActiveLocally()
		{
			if ((Object)(object)GameManager.Instance == (Object)null)
			{
				return false;
			}
			if (PlayerLookup.IsServer)
			{
				return DeathmatchPlugin.Enabled.Value;
			}
			if (Time.unscaledTime - LastSyncTime < 6f)
			{
				return SyncedActive;
			}
			return DeathmatchPlugin.Enabled.Value;
		}

		public static bool IsMidMatchLocally()
		{
			if (AnyDeathThisMap || LocalDiedThisMap)
			{
				return true;
			}
			if (_countdownEndsAt > 0f && Time.time > _countdownEndsAt + 1f)
			{
				return true;
			}
			if (PlayerLookup.IsServer)
			{
				return false;
			}
			if (Time.unscaledTime - LastSyncTime < 6f)
			{
				return SyncedMatchLive;
			}
			return Time.timeSinceLevelLoad > 20f;
		}

		public static void OnStartTimeIssued(float secondsTillStart)
		{
			_countdownEndsAt = Time.time + Mathf.Max(0f, secondsTillStart);
		}

		public static void MarkDirty()
		{
			_dirty = true;
		}

		public static bool TryBeginDeath(int victimId)
		{
			float unscaledTime = Time.unscaledTime;
			if (_lastDeathHandled.TryGetValue(victimId, out var value) && unscaledTime - value < 0.5f)
			{
				return false;
			}
			_lastDeathHandled[victimId] = unscaledTime;
			AnyDeathThisMap = true;
			return true;
		}

		public static void OnServerKill(int victimId, int killerId)
		{
			if (MatchOver)
			{
				return;
			}
			Deaths[victimId] = ((!Deaths.TryGetValue(victimId, out var value)) ? 1 : (value + 1));
			if (killerId >= 0 && killerId != victimId)
			{
				int value2;
				int num = ((!Kills.TryGetValue(killerId, out value2)) ? 1 : (value2 + 1));
				Kills[killerId] = num;
				int value3 = DeathmatchPlugin.KillsToWin.Value;
				if (DeathmatchPlugin.KillFeedInChat.Value)
				{
					Chat("<b><color=#FF4040>[DM]</color></b> <b>" + PlayerLookup.GetNameTag(killerId) + "</b> <color=#00FFFF>[" + num + "/" + value3 + "]</color>");
				}
				if (num >= value3)
				{
					StartWin(killerId, "reached the kill target");
				}
			}
			_dirty = true;
		}

		public static void ServerTick()
		{
			if (MatchOver || _winInProgress)
			{
				BroadcastIfDue();
				return;
			}
			int value = DeathmatchPlugin.TimeLimitMinutes.Value;
			if (value > 0 && MatchLive && Time.time - _mapStartTime >= (float)value * 60f)
			{
				int num = -1;
				int num2 = -1;
				bool flag = false;
				foreach (KeyValuePair<int, ClientInstance> playerInstance in ClientInstance.playerInstances)
				{
					int value2;
					int num3 = (Kills.TryGetValue(playerInstance.Key, out value2) ? value2 : 0);
					if (num3 > num2)
					{
						num2 = num3;
						num = playerInstance.Key;
						flag = false;
					}
					else if (num3 == num2)
					{
						flag = true;
					}
				}
				if (num >= 0 && !flag)
				{
					StartWin(num, _suddenDeathAnnounced ? "sudden death" : "time is up");
				}
				else if (!_suddenDeathAnnounced)
				{
					_suddenDeathAnnounced = true;
					Chat("<b><color=#FF4040>[DM]</color></b> Time is up and the lead is tied. <b>Sudden death:</b> next kill wins!");
				}
			}
			BroadcastIfDue();
		}

		private static void BroadcastIfDue()
		{
			if (_dirty || !(Time.time < _nextBroadcast))
			{
				_dirty = false;
				_nextBroadcast = Time.time + 2f;
				if ((Object)(object)DeathmatchPlugin.Instance != (Object)null)
				{
					DeathmatchPlugin.Instance.BroadcastState();
				}
			}
		}

		private static void StartWin(int winnerId, string why)
		{
			if (!_winInProgress && !MatchOver)
			{
				_winInProgress = true;
				MatchOver = true;
				_dirty = true;
				ManualLogSource log = DeathmatchPlugin.Log;
				if (log != null)
				{
					log.LogInfo((object)("[Score] player " + winnerId + " wins (" + why + ")"));
				}
				MonoBehaviour val = (MonoBehaviour)(object)(((Object)(object)GameManager.Instance != (Object)null) ? ((DeathmatchPlugin)(object)GameManager.Instance) : DeathmatchPlugin.Instance);
				if ((Object)(object)val != (Object)null)
				{
					val.StartCoroutine(WinSequence(winnerId));
				}
			}
		}

		private static IEnumerator WinSequence(int winnerId)
		{
			yield return (object)new WaitForSeconds(1.5f);
			bool roundEnded = false;
			try
			{
				int num = (((Object)(object)ScoreManager.Instance != (Object)null) ? ScoreManager.Instance.GetTeamId(winnerId) : winnerId);
				int value;
				int num2 = (Kills.TryGetValue(winnerId, out value) ? value : 0);
				Chat("<b><color=#FF4040>[DM]</color></b> <b><color=white>" + PlayerLookup.GetNameTag(winnerId) + "</color></b> wins the round with <b>" + num2 + "</b> kills!");
				if ((Object)(object)ScoreManager.Instance != (Object)null)
				{
					ScoreManager.Instance.AddRoundScore(num, 1);
				}
				if (_miRoundWon != null && (Object)(object)GameManager.Instance != (Object)null)
				{
					_miRoundWon.Invoke(GameManager.Instance, new object[1] { num });
				}
				if ((Object)(object)RoundManager.Instance != (Object)null)
				{
					RoundManager.Instance.CmdEndRound(num);
					roundEnded = true;
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = DeathmatchPlugin.Log;
				if (log != null)
				{
					log.LogError((object)("[Score] win sequence failed: " + ex));
				}
			}
			yield return (object)new WaitForSeconds(4f);
			if (roundEnded)
			{
				try
				{
					if ((Object)(object)SceneMotor.Instance != (Object)null)
					{
						SceneMotor.Instance.ChangeNetworkScene();
					}
					yield break;
				}
				catch (Exception ex2)
				{
					ManualLogSource log2 = DeathmatchPlugin.Log;
					if (log2 != null)
					{
						log2.LogError((object)("[Score] scene change failed: " + ex2));
					}
					yield break;
				}
			}
			MatchOver = false;
			_winInProgress = false;
			_dirty = true;
		}

		public static void Chat(string text)
		{
			try
			{
				if (PlayerLookup.IsServer && !((Object)(object)PauseManager.Instance == (Object)null))
				{
					PauseManager.Instance.WriteLog(text);
				}
			}
			catch
			{
			}
		}

		public static string Serialize()
		{
			StringBuilder stringBuilder = new StringBuilder();
			foreach (KeyValuePair<int, ClientInstance> playerInstance in ClientInstance.playerInstances)
			{
				int key = playerInstance.Key;
				int value2;
				int value = (Kills.TryGetValue(key, out value2) ? value2 : 0);
				int value4;
				int value3 = (Deaths.TryGetValue(key, out value4) ? value4 : 0);
				if (stringBuilder.Length > 0)
				{
					stringBuilder.Append(';');
				}
				stringBuilder.Append(key).Append(':').Append(value)
					.Append(':')
					.Append(value3);
			}
			return stringBuilder.ToString();
		}

		public static void ApplySynced(bool active, bool matchLive, int killsToWin, int secondsLeft, bool cleanupItems, bool removeZones, string data, bool restoreLoadout, string defaultWeapon, string excludedClasses, string excludedWeapons)
		{
			SyncedRestoreLoadout = restoreLoadout;
			SyncedDefaultWeapon = defaultWeapon ?? "";
			SyncedExcludedClasses = excludedClasses ?? "";
			SyncedExcludedWeapons = excludedWeapons ?? "";
			SyncedActive = active;
			SyncedMatchLive = matchLive;
			SyncedKillsToWin = killsToWin;
			SyncedSecondsLeft = secondsLeft;
			SyncedCleanupItems = cleanupItems;
			SyncedRemoveDamageZones = removeZones;
			LastSyncTime = Time.unscaledTime;
			Kills.Clear();
			Deaths.Clear();
			if (string.IsNullOrEmpty(data))
			{
				return;
			}
			string[] array = data.Split(new char[1] { ';' });
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split(new char[1] { ':' });
				if (array2.Length == 3 && int.TryParse(array2[0], out var result) && int.TryParse(array2[1], out var result2) && int.TryParse(array2[2], out var result3))
				{
					Kills[result] = result2;
					Deaths[result] = result3;
				}
			}
		}

		public static List<Row> GetRows()
		{
			List<Row> list = new List<Row>();
			foreach (KeyValuePair<int, ClientInstance> playerInstance in ClientInstance.playerInstances)
			{
				list.Add(new Row
				{
					PlayerId = playerInstance.Key,
					Kills = (Kills.TryGetValue(playerInstance.Key, out var value) ? value : 0),
					Deaths = (Deaths.TryGetValue(playerInstance.Key, out var value2) ? value2 : 0)
				});
			}
			list.Sort((Row a, Row b) => (a.Kills == b.Kills) ? a.Deaths.CompareTo(b.Deaths) : b.Kills.CompareTo(a.Kills));
			return list;
		}
	}
	internal static class SpawnSelector
	{
		private struct Candidate
		{
			public SpawnPoint Point;

			public float EnemyDistance;

			public bool Visible;

			public bool Recent;
		}

		private struct Enemy
		{
			public Vector3 Position;

			public Transform Root;
		}

		private const float RecentSeconds = 4f;

		private const float RecentRadiusSqr = 4f;

		private const float LineOfSightRange = 45f;

		private const float EyeHeight = 1.6f;

		private static SpawnPoint[] _points = Array.Empty<SpawnPoint>();

		private static string _scene;

		private static readonly List<KeyValuePair<Vector3, float>> _recent = new List<KeyValuePair<Vector3, float>>();

		public static void Reset()
		{
			_points = Array.Empty<SpawnPoint>();
			_scene = null;
			_recent.Clear();
		}

		private static SpawnPoint[] GetPoints()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			string name = ((Scene)(ref activeScene)).name;
			bool flag = _scene != name || _points.Length == 0;
			if (!flag)
			{
				for (int i = 0; i < _points.Length; i++)
				{
					if ((Object)(object)_points[i] == (Object)null)
					{
						flag = true;
						break;
					}
				}
			}
			if (flag)
			{
				_points = Object.FindObjectsOfType<SpawnPoint>(true) ?? Array.Empty<SpawnPoint>();
				_scene = name;
				ManualLogSource log = DeathmatchPlugin.Log;
				if (log != null)
				{
					log.LogInfo((object)("[Spawn] cached " + _points.Length + " spawn points in " + name));
				}
			}
			return _points;
		}

		public static bool TryPick(int forPlayerId, out SpawnPoint point, out Vector3 position, out Quaternion rotation)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0374: Unknown result type (might be due to invalid IL or missing references)
			//IL_0331: Unknown result type (might be due to invalid IL or missing references)
			//IL_0338: Unknown result type (might be due to invalid IL or missing references)
			//IL_033d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0341: Unknown result type (might be due to invalid IL or missing references)
			//IL_0346: Unknown result type (might be due to invalid IL or missing references)
			//IL_0352: Unknown result type (might be due to invalid IL or missing references)
			//IL_0359: Unknown result type (might be due to invalid IL or missing references)
			//IL_035e: Unknown