Decompiled source of Juggurnaught v1.0.0

BepInEx/plugins/JuggernautMod.dll

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace JuggernautMod
{
	public class JuggernautHud : 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("JuggernautPanel");
			_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("JuggernautText");
			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 = JuggernautPlugin.ShowHud.Value && JuggernautManager.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=#FF6A00>JUGGURNAUGHT</color></b>  <color=#AAAAAA>first to ").Append(JuggernautManager.EffectivePointsToWin).Append(" • ")
				.Append(JuggernautManager.EffectiveTakesToWin)
				.Append((JuggernautManager.EffectiveTakesToWin == 1) ? " take wins" : " takes win")
				.Append("</color>");
			int jugId = JuggernautManager.JugPlayerId;
			List<KeyValuePair<int, int>> list = new List<KeyValuePair<int, int>>();
			foreach (KeyValuePair<int, ClientInstance> playerInstance in ClientInstance.playerInstances)
			{
				JuggernautManager.Points.TryGetValue(playerInstance.Key, out var value);
				list.Add(new KeyValuePair<int, int>(playerInstance.Key, value));
			}
			foreach (KeyValuePair<int, int> item in from r in list
				orderby r.Key == jugId descending, r.Value descending
				select r)
			{
				stringBuilder.Append('\n');
				string playerNameTag = JuggernautManager.GetPlayerNameTag(item.Key);
				if (item.Key == jugId)
				{
					stringBuilder.Append("<color=#FF6A00><b>").Append(playerNameTag).Append("</b>  ")
						.Append(item.Value)
						.Append("  <b>JUG</b></color>");
				}
				else
				{
					stringBuilder.Append("<color=#DDDDDD>").Append(playerNameTag).Append("  ")
						.Append(item.Value)
						.Append("</color>");
				}
				int takeWins = GetTakeWins(item.Key);
				if (takeWins > 0)
				{
					stringBuilder.Append("  <color=#FFD24A>").Append((takeWins == 1) ? "1 take" : (takeWins + " takes")).Append("</color>");
				}
			}
			if (jugId < 0)
			{
				stringBuilder.Append("\n<color=#AAAAAA>First blood claims the crown!</color>");
			}
			try
			{
				return ClientInstance.ReplaceAllPlayerNameTags(stringBuilder.ToString());
			}
			catch
			{
				return stringBuilder.ToString();
			}
		}

		private static int GetTakeWins(int playerId)
		{
			try
			{
				if ((Object)(object)ScoreManager.Instance == (Object)null)
				{
					return 0;
				}
				return ScoreManager.Instance.GetRoundScore(ScoreManager.Instance.GetTeamId(playerId));
			}
			catch
			{
				return 0;
			}
		}
	}
	public static class JuggernautManager
	{
		private const string ChatTag = "<b><color=#FF6A00>[JUGGURNAUGHT]</color></b>";

		private const string SyncMarker = "[[JUGSYNC]]|";

		public static int JugPlayerId = -1;

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

		public static int EffectivePointsToWin = 100;

		public static int EffectiveTakesToWin = 2;

		public static int EffectiveSpeedBoostPercent = 0;

		public static float LastSyncTime = -1000f;

		private static float _pointAccumulator = 0f;

		private static float _nextBroadcastTime = 0f;

		private static float _lastAnnounceTime = -1000f;

		private static bool _winSequenceInProgress = false;

		private static readonly HashSet<int> _grantedHealthInstances = new HashSet<int>();

		private static MethodInfo _miRoundWon;

		private static MethodInfo _miUpdateMatchPointsHud;

		private static bool _reflectionCached = false;

		public static void ResetState()
		{
			JugPlayerId = -1;
			Points.Clear();
			_pointAccumulator = 0f;
			_nextBroadcastTime = 0f;
			_winSequenceInProgress = false;
			_grantedHealthInstances.Clear();
		}

		private static void CacheReflection()
		{
			if (_reflectionCached)
			{
				return;
			}
			_reflectionCached = true;
			_miRoundWon = typeof(GameManager).GetMethod("RoundWon", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (_miRoundWon == null)
			{
				ManualLogSource log = JuggernautPlugin.Log;
				if (log != null)
				{
					log.LogError((object)"[Juggernaut] GameManager.RoundWon was not found");
				}
			}
			_miUpdateMatchPointsHud = typeof(GameManager).GetMethod("UpdateMatchPointsHUD", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (_miUpdateMatchPointsHud == null)
			{
				ManualLogSource log2 = JuggernautPlugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)"[Juggernaut] GameManager.UpdateMatchPointsHUD was not found");
				}
			}
		}

		public static bool ModeActiveLocally()
		{
			if ((Object)(object)GameManager.Instance == (Object)null)
			{
				return false;
			}
			if ((Object)(object)InstanceFinder.NetworkManager != (Object)null && InstanceFinder.NetworkManager.IsServer)
			{
				return JuggernautPlugin.Enabled.Value;
			}
			return Time.unscaledTime - LastSyncTime < 4f;
		}

		public static void ServerUpdate()
		{
			EffectivePointsToWin = JuggernautPlugin.PointsToWin.Value;
			EffectiveTakesToWin = JuggernautPlugin.TakesToWin.Value;
			EffectiveSpeedBoostPercent = JuggernautPlugin.SpeedBoostPercent.Value;
			if (JugPlayerId >= 0 && !ClientInstance.playerInstances.ContainsKey(JugPlayerId))
			{
				JugPlayerId = -1;
				_pointAccumulator = 0f;
				BroadcastChat("<b><color=#FF6A00>[JUGGURNAUGHT]</color></b> The Juggernaut left the game! <color=#FF6A00>First blood claims the crown!</color>");
				BroadcastState();
			}
			if (JugPlayerId >= 0 && !_winSequenceInProgress)
			{
				PlayerHealth val = FindPlayerHealthById(JugPlayerId);
				if ((Object)(object)val != (Object)null && ((Component)val).gameObject.activeInHierarchy && !val.sync___get_value_isKilled() && val.sync___get_value_health() > 0f)
				{
					int instanceID = ((Object)val).GetInstanceID();
					if (!_grantedHealthInstances.Contains(instanceID))
					{
						_grantedHealthInstances.Add(instanceID);
						GrantBonusHealth(val);
					}
					_pointAccumulator += Time.deltaTime;
					bool flag = false;
					while (_pointAccumulator >= 1f)
					{
						_pointAccumulator -= 1f;
						AddPoints(JugPlayerId, JuggernautPlugin.PointsPerSecond.Value);
						flag = true;
					}
					if (flag && Points[JugPlayerId] >= EffectivePointsToWin)
					{
						Points[JugPlayerId] = EffectivePointsToWin;
						StartWinSequence(JugPlayerId);
						BroadcastState();
						return;
					}
				}
				else
				{
					_pointAccumulator = 0f;
				}
			}
			ServerBroadcastTick();
		}

		public static void ServerBroadcastTick()
		{
			if (Time.unscaledTime >= _nextBroadcastTime)
			{
				_nextBroadcastTime = Time.unscaledTime + 1f;
				BroadcastState();
			}
		}

		public static void OnServerKill(int deadPlayerId, int killerId)
		{
			if (_winSequenceInProgress || JuggernautPlugin.MatchOver)
			{
				return;
			}
			bool flag = killerId >= 0 && killerId != deadPlayerId;
			if (JugPlayerId < 0)
			{
				if (flag)
				{
					BecomeJuggernaut(killerId, string.Format("{0} <b>{1}</b> drew <color=red>first blood</color> and <color=#FF6A00>IS THE JUGGERNAUT!</color> <color=#AAAAAA>(+{2} HP)</color>", "<b><color=#FF6A00>[JUGGURNAUGHT]</color></b>", GetPlayerNameTag(killerId), JuggernautPlugin.BonusHealth.Value));
				}
			}
			else if (deadPlayerId == JugPlayerId)
			{
				if (flag)
				{
					BecomeJuggernaut(killerId, string.Format("{0} <b>{1}</b> <color=red>slayed</color> the Juggernaut <b>{2}</b> and <color=#FF6A00>CLAIMED THE CROWN!</color> <color=#AAAAAA>(+{3} HP)</color>", "<b><color=#FF6A00>[JUGGURNAUGHT]</color></b>", GetPlayerNameTag(killerId), GetPlayerNameTag(deadPlayerId), JuggernautPlugin.BonusHealth.Value));
				}
				else
				{
					BroadcastChat("<b><color=#FF6A00>[JUGGURNAUGHT]</color></b> The Juggernaut <b>" + GetPlayerNameTag(deadPlayerId) + "</b> <color=#888888>died... but keeps the crown.</color>");
				}
			}
			else
			{
				if (!flag || killerId != JugPlayerId || JuggernautPlugin.HealthPerKill.Value <= 0)
				{
					return;
				}
				PlayerHealth val = FindPlayerHealthById(killerId);
				if (!((Object)(object)val != (Object)null) || !((Component)val).gameObject.activeInHierarchy || val.sync___get_value_isKilled() || !(val.sync___get_value_health() > 0f))
				{
					return;
				}
				try
				{
					val.RpcLogic___RemoveHealth_431000436(0f - (float)JuggernautPlugin.HealthPerKill.Value / 25f);
					BroadcastChat(string.Format("{0} <b>{1}</b> <color=#66DD66>+{2} HP</color> <color=#AAAAAA>for the kill</color>", "<b><color=#FF6A00>[JUGGURNAUGHT]</color></b>", GetPlayerNameTag(killerId), JuggernautPlugin.HealthPerKill.Value));
				}
				catch (Exception ex)
				{
					ManualLogSource log = JuggernautPlugin.Log;
					if (log != null)
					{
						log.LogWarning((object)("[Juggernaut] health-per-kill grant failed: " + ex.GetType().Name));
					}
				}
			}
		}

		private static void BecomeJuggernaut(int playerId, string announcement)
		{
			JugPlayerId = playerId;
			_pointAccumulator = 0f;
			_grantedHealthInstances.Clear();
			PlayerHealth val = FindPlayerHealthById(playerId);
			if ((Object)(object)val != (Object)null && ((Component)val).gameObject.activeInHierarchy && !val.sync___get_value_isKilled() && val.sync___get_value_health() > 0f)
			{
				_grantedHealthInstances.Add(((Object)val).GetInstanceID());
				GrantBonusHealth(val);
			}
			BroadcastChat(announcement);
			BroadcastState();
		}

		private static void GrantBonusHealth(PlayerHealth health)
		{
			try
			{
				float num = (float)JuggernautPlugin.BonusHealth.Value / 25f;
				health.RpcLogic___RemoveHealth_431000436(0f - num);
				ManualLogSource log = JuggernautPlugin.Log;
				if (log != null)
				{
					log.LogInfo((object)$"[Juggernaut] granted +{JuggernautPlugin.BonusHealth.Value} HP to player {JugPlayerId}");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = JuggernautPlugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("[Juggernaut] bonus health grant failed: " + ex.GetType().Name));
				}
			}
		}

		private static void AddPoints(int playerId, int amount)
		{
			Points.TryGetValue(playerId, out var value);
			Points[playerId] = value + amount;
		}

		private static void StartWinSequence(int winnerPlayerId)
		{
			if (!_winSequenceInProgress)
			{
				_winSequenceInProgress = true;
				JuggernautPlugin.MatchOver = true;
				object obj = ((object)GameManager.Instance) ?? ((object)JuggernautPlugin.Instance);
				if (obj != null)
				{
					((MonoBehaviour)obj).StartCoroutine(WinSequenceCoroutine(winnerPlayerId));
				}
			}
		}

		private static IEnumerator WinSequenceCoroutine(int winnerPlayerId)
		{
			CacheReflection();
			yield return (object)new WaitForSeconds(1.5f);
			int num = GetPlayerTeam(winnerPlayerId);
			bool flag = false;
			int num2 = 0;
			try
			{
				if ((Object)(object)ScoreManager.Instance != (Object)null)
				{
					ScoreManager.Instance.RoundScoreRequiredToWin = EffectiveTakesToWin;
					ScoreManager.Instance.AddRoundScore(num, 1);
					num2 = ScoreManager.Instance.GetRoundScore(num);
					int num3 = default(int);
					flag = ScoreManager.Instance.CheckForRoundWin(ref num3);
					if (flag)
					{
						num = num3;
					}
					_miUpdateMatchPointsHud?.Invoke(GameManager.Instance, new object[2]
					{
						flag ? num : (-1),
						ScoreManager.Instance.GetRoundScoreDictionary()
					});
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = JuggernautPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[Juggernaut] take scoring error: " + ex.GetType().Name));
				}
			}
			if (flag)
			{
				bool endRoundCalled = false;
				try
				{
					BroadcastChat("<b><color=#FF6A00>[JUGGURNAUGHT]</color></b> <b>" + GetPlayerNameTag(winnerPlayerId) + "</b> takes the final take and <color=yellow>WINS THE ROUND!</color>");
					if (_miRoundWon != null)
					{
						_miRoundWon.Invoke(GameManager.Instance, new object[1] { num });
					}
					if ((Object)(object)RoundManager.Instance != (Object)null)
					{
						RoundManager.Instance.CmdEndRound(num);
						endRoundCalled = true;
					}
				}
				catch (Exception ex2)
				{
					ManualLogSource log2 = JuggernautPlugin.Log;
					if (log2 != null)
					{
						log2.LogWarning((object)("[Juggernaut] round win sequence error: " + ex2.GetType().Name));
					}
				}
				yield return (object)new WaitForSeconds(4f);
				if (endRoundCalled)
				{
					try
					{
						if ((Object)(object)SceneMotor.Instance != (Object)null)
						{
							SceneMotor.Instance.ChangeNetworkScene();
						}
					}
					catch
					{
					}
				}
				JuggernautPlugin.MatchOver = false;
				ResetState();
				yield break;
			}
			BroadcastChat(string.Format("{0} <b>{1}</b> reached <b>{2}</b> points and <color=yellow>WINS THE TAKE!</color> <color=#AAAAAA>({3}/{4} takes)</color>", "<b><color=#FF6A00>[JUGGURNAUGHT]</color></b>", GetPlayerNameTag(winnerPlayerId), EffectivePointsToWin, num2, EffectiveTakesToWin));
			yield return (object)new WaitForSeconds(2f);
			JuggernautPatches.ResetState();
			ResetState();
			JuggernautPlugin.MatchOver = false;
			try
			{
				GameManager instance = GameManager.Instance;
				if (instance != null)
				{
					instance.ProgressToNextTake();
				}
			}
			catch (Exception ex3)
			{
				ManualLogSource log3 = JuggernautPlugin.Log;
				if (log3 != null)
				{
					log3.LogWarning((object)("[Juggernaut] take transition error: " + ex3.GetType().Name));
				}
			}
			BroadcastState();
			yield return (object)new WaitForSeconds(2.5f);
			if (JuggernautPlugin.Enabled.Value && !JuggernautPlugin.MatchOver && JugPlayerId < 0)
			{
				BroadcastChat("<b><color=#FF6A00>[JUGGURNAUGHT]</color></b> <color=#FF6A00>New take — first blood claims the crown!</color>");
			}
		}

		public static void AnnounceRoundStartDelayed()
		{
			JuggernautPlugin instance = JuggernautPlugin.Instance;
			if (instance != null)
			{
				((MonoBehaviour)instance).StartCoroutine(AnnounceRoundStartCoroutine());
			}
		}

		private static IEnumerator AnnounceRoundStartCoroutine()
		{
			yield return (object)new WaitForSeconds(3f);
			if (JuggernautPlugin.Enabled.Value && !JuggernautPlugin.MatchOver && !((Object)(object)GameManager.Instance == (Object)null) && JugPlayerId < 0 && !(Time.unscaledTime - _lastAnnounceTime < 15f))
			{
				_lastAnnounceTime = Time.unscaledTime;
				BroadcastChat(string.Format("{0} <color=#FF6A00>First blood claims the crown!</color> Hold it to earn points — first to <b>{1}</b> wins the round.", "<b><color=#FF6A00>[JUGGURNAUGHT]</color></b>", JuggernautPlugin.PointsToWin.Value));
			}
		}

		internal static void BroadcastState()
		{
			if (!((Object)(object)InstanceFinder.NetworkManager == (Object)null) && InstanceFinder.NetworkManager.IsServer && !JuggernautPlugin.TryBroadcastStateOverMycelium())
			{
				JuggernautPatches.SendChatLineToAll(string.Format("{0}{1}|{2}|{3}|{4}|{5}", "[[JUGSYNC]]|", JugPlayerId, EffectivePointsToWin, EffectiveTakesToWin, EffectiveSpeedBoostPercent, SerializePoints()));
			}
		}

		internal static bool TryHandleSyncLine(string line)
		{
			if (line == null || !line.StartsWith("[[JUGSYNC]]|", StringComparison.Ordinal))
			{
				return false;
			}
			try
			{
				if ((Object)(object)InstanceFinder.NetworkManager == (Object)null || !InstanceFinder.NetworkManager.IsServer)
				{
					string[] array = line.Substring("[[JUGSYNC]]|".Length).Split(new char[1] { '|' });
					if (array.Length >= 5 && int.TryParse(array[0], out var result) && int.TryParse(array[1], out var result2) && int.TryParse(array[2], out var result3) && int.TryParse(array[3], out var result4))
					{
						ApplySyncedState(result, result2, result3, result4, array[4]);
					}
				}
			}
			catch
			{
			}
			return true;
		}

		public static string SerializePoints()
		{
			StringBuilder stringBuilder = new StringBuilder();
			foreach (KeyValuePair<int, int> point in Points)
			{
				if (stringBuilder.Length > 0)
				{
					stringBuilder.Append(';');
				}
				stringBuilder.Append(point.Key).Append(':').Append(point.Value);
			}
			return stringBuilder.ToString();
		}

		public static void ApplySyncedState(int jugPlayerId, int pointsToWin, int takesToWin, int speedBoostPercent, string pointsData)
		{
			JugPlayerId = jugPlayerId;
			EffectivePointsToWin = pointsToWin;
			EffectiveTakesToWin = takesToWin;
			EffectiveSpeedBoostPercent = speedBoostPercent;
			LastSyncTime = Time.unscaledTime;
			Points.Clear();
			if (string.IsNullOrEmpty(pointsData))
			{
				return;
			}
			string[] array = pointsData.Split(new char[1] { ';' });
			foreach (string text in array)
			{
				int num = text.IndexOf(':');
				if (num > 0 && int.TryParse(text.Substring(0, num), out var result) && int.TryParse(text.Substring(num + 1), out var result2))
				{
					Points[result] = result2;
				}
			}
		}

		internal static void BroadcastChat(string text)
		{
			JuggernautPatches.SendChatLineToAll(text);
		}

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

		internal static int GetPlayerTeam(int playerId)
		{
			if ((Object)(object)ScoreManager.Instance != (Object)null)
			{
				try
				{
					return ScoreManager.Instance.GetTeamId(playerId);
				}
				catch
				{
				}
			}
			return playerId;
		}

		internal static PlayerHealth FindPlayerHealthById(int playerId)
		{
			if (playerId < 0)
			{
				return null;
			}
			try
			{
				PlayerHealth[] array = Object.FindObjectsOfType<PlayerHealth>(true);
				foreach (PlayerHealth val in array)
				{
					if (!((Object)(object)val == (Object)null))
					{
						PlayerValues obj = val.sync___get_value_playerValues();
						if ((((obj == null) ? ((int?)null) : obj.sync___get_value_playerClient()?.PlayerId) ?? (-1)) == playerId)
						{
							return val;
						}
					}
				}
			}
			catch
			{
			}
			return null;
		}
	}
	public static class JuggernautOutline
	{
		private const string HeadMeshName = "SM_Aboubi_Head00";

		private static int _outlinedPlayerId = -1;

		private static readonly List<SkinnedMeshRenderer> _outlinedRenderers = new List<SkinnedMeshRenderer>();

		private static readonly FieldInfo _fiBodyMeshes = typeof(PlayerSetup).GetField("gameObjectsToDisableForMe", BindingFlags.Instance | BindingFlags.NonPublic);

		public static void ResetState()
		{
			_outlinedPlayerId = -1;
			_outlinedRenderers.Clear();
		}

		public static void EnforceOutline()
		{
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			int num = (JuggernautManager.ModeActiveLocally() ? JuggernautManager.JugPlayerId : (-1));
			if (num != _outlinedPlayerId)
			{
				ClearOutline();
				_outlinedPlayerId = num;
			}
			if (num < 0 || ((Object)(object)ClientInstance.Instance != (Object)null && ClientInstance.Instance.PlayerId == num))
			{
				return;
			}
			try
			{
				PlayerHealth val = JuggernautManager.FindPlayerHealthById(num);
				if ((Object)(object)val == (Object)null || !((Component)val).gameObject.activeInHierarchy)
				{
					return;
				}
				PlayerSetup component = ((Component)val).GetComponent<PlayerSetup>();
				if ((Object)(object)component == (Object)null)
				{
					return;
				}
				GameObject[] array = _fiBodyMeshes?.GetValue(component) as GameObject[];
				if (array == null || array.Length == 0)
				{
					array = component.meshesToChange;
				}
				if (array == null)
				{
					return;
				}
				_outlinedRenderers.Clear();
				GameObject[] array2 = array;
				foreach (GameObject val2 in array2)
				{
					if ((Object)(object)val2 == (Object)null)
					{
						continue;
					}
					SkinnedMeshRenderer component2 = val2.GetComponent<SkinnedMeshRenderer>();
					if (!((Object)(object)component2 == (Object)null))
					{
						Material[] materials = ((Renderer)component2).materials;
						if (materials != null && materials.Length != 0 && !((Object)(object)materials[0] == (Object)null) && materials[0].HasProperty("_ASEOutlineWidth"))
						{
							float num2 = ((((Object)val2).name == "SM_Aboubi_Head00") ? 0.02f : 0.04f) * OutlineHandler.OutlineWidthMultiplier;
							materials[0].SetFloat("_ASEOutlineWidth", num2);
							materials[0].SetColor("_ASEOutlineColor", OutlineHandler.TeamColor);
							((Renderer)component2).materials = materials;
							_outlinedRenderers.Add(component2);
						}
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = JuggernautPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[Juggernaut] outline enforcement failed: " + ex.GetType().Name));
				}
			}
		}

		private static void ClearOutline()
		{
			foreach (SkinnedMeshRenderer outlinedRenderer in _outlinedRenderers)
			{
				try
				{
					if (!((Object)(object)outlinedRenderer == (Object)null))
					{
						Material[] materials = ((Renderer)outlinedRenderer).materials;
						if (materials != null && materials.Length != 0 && !((Object)(object)materials[0] == (Object)null) && materials[0].HasProperty("_ASEOutlineWidth"))
						{
							materials[0].SetFloat("_ASEOutlineWidth", 0f);
							((Renderer)outlinedRenderer).materials = materials;
						}
					}
				}
				catch
				{
				}
			}
			_outlinedRenderers.Clear();
		}
	}
	public static class JuggernautPatches
	{
		private static Harmony _harmony;

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

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

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

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

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

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

		private static float _nextRespawnWatchdogTime;

		private const float DeathDedupeSeconds = 0.35f;

		private const int MaxRespawnAttempts = 3;

		private const float RespawnValidationSeconds = 2f;

		private const float RespawnRetryDelaySeconds = 0.25f;

		private const float RespawnWatchdogIntervalSeconds = 0.5f;

		private const float RespawnRecoveryDelaySeconds = 1f;

		private static MethodInfo _miCmdRespawnLogic;

		private static MethodInfo _miMatchLogsSendToAll;

		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)
			{
				return;
			}
			_harmony = new Harmony("com.willofkabr.juggurnaught.patches");
			_miCmdRespawnLogic = typeof(PlayerManager).GetMethod("RpcLogic___CmdRespawn_2166136261", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (_miCmdRespawnLogic == null)
			{
				ManualLogSource log = JuggernautPlugin.Log;
				if (log != null)
				{
					log.LogError((object)"[Juggernaut Respawn] native PlayerManager respawn method was not found");
				}
			}
			_miMatchLogsSendToAll = typeof(MatchLogs).GetMethod("RpcSendChatLineToAllObservers", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (_miMatchLogsSendToAll == null)
			{
				ManualLogSource log2 = JuggernautPlugin.Log;
				if (log2 != null)
				{
					log2.LogError((object)"[Juggernaut] MatchLogs chat broadcast method was not found");
				}
			}
			try
			{
				PatchPrefix(typeof(GameManager), "WaitForDraw", "GameManager_WaitForDraw_Prefix");
				PatchPrefix(typeof(GameManager), "RpcLogic___PlayerDied_3316948804", "GameManager_RpcLogic_PlayerDied_Prefix");
				PatchPrefix(typeof(GameManager), "SetStartTime", "GameManager_SetStartTime_Prefix");
				PatchPrefix(typeof(RoundManager), "CmdEndRound", "RoundManager_CmdEndRound_Prefix");
				PatchPrefix(typeof(PlayerManager), "RpcLogic___SetPlayerMove_1140765316", "PlayerManager_RpcLogic_SetPlayerMove_Prefix");
				PatchPrefix(typeof(KillCam), "Update", "KillCam_Update_Prefix");
				PatchPrefix(typeof(PauseManager), "StartRoundDelay", "PauseManager_StartRoundDelay_Prefix");
				PatchPrefix(typeof(MatchLogs), "RpcLogic___RpcSendChatLineToAllObservers_3615296227", "MatchLogs_ChatLine_Prefix");
				PatchPostfix(typeof(PlayerManager), "SpawnPlayer", "PlayerManager_SpawnPlayer_Postfix", new Type[2]
				{
					typeof(int),
					typeof(int)
				});
				PatchPostfix(typeof(PlayerManager), "SpawnPlayer", "PlayerManager_SpawnPlayer_Postfix", new Type[4]
				{
					typeof(int),
					typeof(int),
					typeof(Vector3),
					typeof(Quaternion)
				});
				PatchPostfix(typeof(PlayerHealth), "RpcLogic___ExplodeForAll_576886416", "PlayerHealth_ExplodeForAll_Postfix");
				PatchPostfix(typeof(PlayerValues), "sync___set_value_playerClient", "PlayerValues_SetPlayerClient_Postfix");
			}
			catch (Exception arg)
			{
				ManualLogSource log3 = JuggernautPlugin.Log;
				if (log3 != null)
				{
					log3.LogError((object)$"[Juggernaut] patching failed: {arg}");
				}
			}
		}

		private static void PatchPrefix(Type type, string methodName, string patchName, Type[] paramTypes = null)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Expected O, but got Unknown
			MethodInfo methodInfo = ((paramTypes == null) ? type.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) : type.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, paramTypes, null));
			if (methodInfo == null)
			{
				ManualLogSource log = JuggernautPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[Juggernaut] patch target missing: " + type.Name + "." + methodName));
				}
			}
			else
			{
				_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(JuggernautPatches).GetMethod(patchName, BindingFlags.Static | BindingFlags.Public)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}

		private static void PatchPostfix(Type type, string methodName, string patchName, Type[] paramTypes = null)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Expected O, but got Unknown
			MethodInfo methodInfo = ((paramTypes == null) ? type.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) : type.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, paramTypes, null));
			if (methodInfo == null)
			{
				ManualLogSource log = JuggernautPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[Juggernaut] patch target missing: " + type.Name + "." + methodName));
				}
			}
			else
			{
				_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(JuggernautPatches).GetMethod(patchName, BindingFlags.Static | BindingFlags.Public)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}

		public static void ResetState()
		{
			_playerRagdolls.Clear();
			_respawnInProgress.Clear();
			_respawnRequestSeq.Clear();
			_playersAwaitingRespawn.Clear();
			_nextRespawnRecoveryTime.Clear();
			_lastDeathHandledTime.Clear();
			_nextRespawnWatchdogTime = 0f;
		}

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

		public static bool MatchLogs_ChatLine_Prefix(string line)
		{
			return !JuggernautManager.TryHandleSyncLine(line);
		}

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

		private static IEnumerator EmptyCoroutine()
		{
			yield break;
		}

		public static bool RoundManager_CmdEndRound_Prefix(int winningTeamId)
		{
			if (!JuggernautPlugin.Enabled.Value)
			{
				return true;
			}
			return JuggernautPlugin.MatchOver;
		}

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

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

		public static bool GameManager_RpcLogic_PlayerDied_Prefix(int playerId)
		{
			if (!JuggernautPlugin.Enabled.Value)
			{
				return true;
			}
			if (JuggernautPlugin.MatchOver)
			{
				return false;
			}
			try
			{
				if (GameManager.Instance?.alivePlayers != null && !GameManager.Instance.alivePlayers.Contains(playerId))
				{
					GameManager.Instance.alivePlayers.Add(playerId);
				}
				if ((Object)(object)InstanceFinder.NetworkManager == (Object)null || !InstanceFinder.NetworkManager.IsServer)
				{
					return true;
				}
				float unscaledTime = Time.unscaledTime;
				float value;
				bool num = _lastDeathHandledTime.TryGetValue(playerId, out value) && unscaledTime - value <= 0.35f;
				_lastDeathHandledTime[playerId] = unscaledTime;
				if (!num)
				{
					int killerId = FindKillerId(playerId);
					JuggernautManager.OnServerKill(playerId, killerId);
				}
				ScheduleRespawn(playerId);
			}
			catch
			{
				try
				{
					ScheduleRespawn(playerId);
				}
				catch
				{
				}
			}
			return false;
		}

		public static void PlayerManager_SpawnPlayer_Postfix(PlayerManager __instance)
		{
			if (!JuggernautPlugin.Enabled.Value || (Object)(object)__instance == (Object)null)
			{
				return;
			}
			ClientInstance component = ((Component)__instance).GetComponent<ClientInstance>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			int playerId = component.PlayerId;
			if (playerId < 0)
			{
				return;
			}
			if ((Object)(object)InstanceFinder.NetworkManager != (Object)null && InstanceFinder.NetworkManager.IsServer && GameManager.Instance?.alivePlayers != null && !GameManager.Instance.alivePlayers.Contains(playerId))
			{
				GameManager.Instance.alivePlayers.Add(playerId);
			}
			if (((NetworkBehaviour)__instance).IsOwner)
			{
				if ((Object)(object)PauseManager.Instance != (Object)null)
				{
					PauseManager.Instance.startRound = false;
				}
				GameManager instance = GameManager.Instance;
				if (instance != null)
				{
					((MonoBehaviour)instance).StartCoroutine(KeepPlayerMovable(__instance, 4f));
				}
			}
		}

		public static bool PlayerManager_RpcLogic_SetPlayerMove_Prefix(PlayerManager __instance, bool state)
		{
			if (!JuggernautPlugin.Enabled.Value || JuggernautPlugin.MatchOver)
			{
				return true;
			}
			if (state)
			{
				return true;
			}
			try
			{
				if ((Object)(object)__instance.player != (Object)null)
				{
					__instance.player.sync___set_value_canMove(true, true);
					__instance.player.startOfRound = false;
				}
				if ((Object)(object)PauseManager.Instance != (Object)null)
				{
					PauseManager.Instance.startRound = false;
					PauseManager.Instance.pause = false;
					PauseManager.Instance.otherPauseBools = false;
				}
			}
			catch
			{
			}
			return false;
		}

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

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

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

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

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

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

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

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

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

		private static void CompleteRespawn(int playerId, PlayerManager pm, string source)
		{
			if (_playersAwaitingRespawn.Remove(playerId))
			{
				_nextRespawnRecoveryTime.Remove(playerId);
				ForcePlayerReady(pm);
				LogRespawn(playerId, 0, source);
			}
		}

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

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

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

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

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

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

		private static int FindKillerId(int deadPlayerId)
		{
			PlayerHealth val = JuggernautManager.FindPlayerHealthById(deadPlayerId);
			if ((Object)(object)val == (Object)null)
			{
				return -1;
			}
			Transform val2 = val.sync___get_value_killer();
			if ((Object)(object)val2 == (Object)null)
			{
				return -1;
			}
			ClientInstance componentInParent = ((Component)val2).GetComponentInParent<ClientInstance>(true);
			if ((Object)(object)componentInParent != (Object)null)
			{
				return componentInParent.PlayerId;
			}
			PlayerValues obj = ((Component)val2).GetComponentInParent<PlayerValues>(true) ?? ((Component)val2).GetComponentInChildren<PlayerValues>(true);
			int? num = ((obj == null) ? ((int?)null) : obj.sync___get_value_playerClient()?.PlayerId);
			if (num.HasValue)
			{
				int valueOrDefault = num.GetValueOrDefault();
				if (valueOrDefault >= 0)
				{
					return valueOrDefault;
				}
			}
			GameObject 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)
			{
				int ownerIdFromRootObject = GetOwnerIdFromRootObject(val3);
				if (ownerIdFromRootObject >= 0)
				{
					return ownerIdFromRootObject;
				}
			}
			return -1;
		}

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

		private static PlayerManager FindPlayerManagerForId(int playerId)
		{
			if (ClientInstance.playerInstances.TryGetValue(playerId, out var value) && (Object)(object)value != (Object)null)
			{
				return ((Component)value).GetComponent<PlayerManager>();
			}
			return null;
		}
	}
	public static class JuggernautSpeed
	{
		private static readonly string[] SpeedFieldNames = new string[6] { "walkSpeed", "sprintSpeed", "crouchSpeed", "slopeSpeed", "airSpeed", "sprintAirSpeed" };

		private static FieldInfo[] _fields;

		private static FirstPersonController _boostedController;

		private static float[] _baseValues;

		private static int _appliedPercent;

		private static void CacheFields()
		{
			if (_fields != null)
			{
				return;
			}
			_fields = new FieldInfo[SpeedFieldNames.Length];
			for (int i = 0; i < SpeedFieldNames.Length; i++)
			{
				_fields[i] = typeof(FirstPersonController).GetField(SpeedFieldNames[i], BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (_fields[i] == null)
				{
					ManualLogSource log = JuggernautPlugin.Log;
					if (log != null)
					{
						log.LogWarning((object)("[Juggernaut] speed field missing: " + SpeedFieldNames[i]));
					}
				}
			}
		}

		public static void ResetState()
		{
			_boostedController = null;
			_baseValues = null;
			_appliedPercent = 0;
		}

		public static void EnforceSpeed()
		{
			CacheFields();
			int effectiveSpeedBoostPercent = JuggernautManager.EffectiveSpeedBoostPercent;
			int num;
			object obj;
			if (effectiveSpeedBoostPercent > 0 && JuggernautManager.ModeActiveLocally() && JuggernautManager.JugPlayerId >= 0 && (Object)(object)ClientInstance.Instance != (Object)null)
			{
				num = ((ClientInstance.Instance.PlayerId == JuggernautManager.JugPlayerId) ? 1 : 0);
				if (num != 0)
				{
					obj = FindLocalController();
					goto IL_004a;
				}
			}
			else
			{
				num = 0;
			}
			obj = null;
			goto IL_004a;
			IL_004a:
			FirstPersonController val = (FirstPersonController)obj;
			if ((Object)(object)_boostedController != (Object)null && ((Object)(object)_boostedController != (Object)(object)val || _appliedPercent != effectiveSpeedBoostPercent))
			{
				RestoreBoost();
			}
			if (num == 0 || (Object)(object)val == (Object)null || (Object)(object)_boostedController == (Object)(object)val)
			{
				return;
			}
			try
			{
				_baseValues = new float[_fields.Length];
				float num2 = 1f + (float)effectiveSpeedBoostPercent / 100f;
				for (int i = 0; i < _fields.Length; i++)
				{
					if (!(_fields[i] == null))
					{
						_baseValues[i] = (float)_fields[i].GetValue(val);
						_fields[i].SetValue(val, _baseValues[i] * num2);
					}
				}
				_boostedController = val;
				_appliedPercent = effectiveSpeedBoostPercent;
				ManualLogSource log = JuggernautPlugin.Log;
				if (log != null)
				{
					log.LogInfo((object)$"[Juggernaut] speed boost +{effectiveSpeedBoostPercent}% applied");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = JuggernautPlugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("[Juggernaut] speed boost failed: " + ex.GetType().Name));
				}
				_boostedController = null;
				_baseValues = null;
			}
		}

		private static void RestoreBoost()
		{
			try
			{
				if ((Object)(object)_boostedController != (Object)null && _baseValues != null)
				{
					for (int i = 0; i < _fields.Length; i++)
					{
						if (!(_fields[i] == null))
						{
							_fields[i].SetValue(_boostedController, _baseValues[i]);
						}
					}
				}
			}
			catch
			{
			}
			_boostedController = null;
			_baseValues = null;
			_appliedPercent = 0;
		}

		private static FirstPersonController FindLocalController()
		{
			try
			{
				ClientInstance instance = ClientInstance.Instance;
				PlayerManager val = ((instance != null) ? ((Component)instance).GetComponent<PlayerManager>() : null);
				if ((Object)(object)val?.player != (Object)null && ((Component)val.player).gameObject.activeInHierarchy)
				{
					return val.player;
				}
			}
			catch
			{
			}
			try
			{
				FirstPersonController val2 = Settings.Instance?.localPlayer;
				if ((Object)(object)val2 != (Object)null && ((Component)val2).gameObject.activeInHierarchy)
				{
					return val2;
				}
			}
			catch
			{
			}
			return null;
		}
	}
	[BepInPlugin("com.willofkabr.juggurnaught", "Juggurnaught", "1.1.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class JuggernautPlugin : BaseUnityPlugin
	{
		public const string PluginGUID = "com.willofkabr.juggurnaught";

		public const string PluginName = "Juggurnaught";

		public const string PluginVersion = "1.1.0";

		public const uint ModId = 774477u;

		private const string MyceliumGUID = "RugbugRedfern.MyceliumNetworking";

		private const string ModMenuGUID = "kestrel.straftat.modmenu";

		internal static ManualLogSource Log;

		private static JuggernautPlugin _instance;

		public static ConfigEntry<bool> Enabled;

		public static ConfigEntry<int> TakesToWin;

		public static ConfigEntry<int> PointsToWin;

		public static ConfigEntry<int> PointsPerSecond;

		public static ConfigEntry<int> BonusHealth;

		public static ConfigEntry<int> HealthPerKill;

		public static ConfigEntry<int> SpeedBoostPercent;

		public static ConfigEntry<float> RespawnDelay;

		public static ConfigEntry<bool> ShowHud;

		public static bool MatchOver;

		private bool _fishNetHooked;

		private float _nextOutlineTime;

		public static JuggernautPlugin Instance => _instance;

		private void Awake()
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Expected O, but got Unknown
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Expected O, but got Unknown
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Expected O, but got Unknown
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Expected O, but got Unknown
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Expected O, but got Unknown
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Expected O, but got Unknown
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			_instance = this;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable Juggernaut mode. Only the host's setting matters for gameplay.");
			PointsToWin = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Points To Win", 100, new ConfigDescription("Points the Juggernaut must accumulate to win a take.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 1000), Array.Empty<object>()));
			TakesToWin = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Takes To Win Round", 2, new ConfigDescription("Take wins needed to win the round, like the base game. Reaching the point target wins one take.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 5), Array.Empty<object>()));
			PointsPerSecond = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Points Per Second", 5, new ConfigDescription("Points the Juggernaut earns for every second they stay alive.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 50), Array.Empty<object>()));
			BonusHealth = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Juggernaut Bonus Health", 100, new ConfigDescription("Extra health granted when a player becomes the Juggernaut (in HUD health units, 100 = one full health bar). Stacks on top of their current health.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(25, 400), Array.Empty<object>()));
			HealthPerKill = ((BaseUnityPlugin)this).Config.Bind<int>("Perks", "Jug Health Per Kill", 0, new ConfigDescription("Extra health the Juggernaut gains for each kill, in HUD health units (0 = off).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 200), Array.Empty<object>()));
			SpeedBoostPercent = ((BaseUnityPlugin)this).Config.Bind<int>("Perks", "Jug Speed Boost %", 0, new ConfigDescription("Extra movement speed for the Juggernaut, as a percentage (0 = off).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
			RespawnDelay = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Respawn Delay", 3f, new ConfigDescription("Seconds before a dead player respawns.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 10f), Array.Empty<object>()));
			ShowHud = ((BaseUnityPlugin)this).Config.Bind<bool>("HUD", "Show Point Counter", true, "Show the on-screen Juggernaut point counter.");
			JuggernautPatches.Apply();
			MyceliumNetwork.RegisterNetworkObject((object)this, 774477u, 0);
			SceneManager.sceneLoaded += OnSceneLoaded;
			GameObject val = new GameObject("JuggernautHud");
			val.transform.SetParent(((Component)this).transform, false);
			val.AddComponent<JuggernautHud>();
			Log.LogInfo((object)"Juggurnaught 1.1.0 loaded.");
		}

		private void OnEnable()
		{
			_instance = this;
		}

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

		private void OnDestroy()
		{
			MyceliumNetwork.DeregisterNetworkObject((object)this, 774477u, 0);
			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();
			if (Enabled.Value && (Object)(object)InstanceFinder.NetworkManager != (Object)null && InstanceFinder.NetworkManager.IsServer)
			{
				JuggernautManager.AnnounceRoundStartDelayed();
			}
		}

		internal static void FullReset()
		{
			MatchOver = false;
			JuggernautManager.ResetState();
			JuggernautOutline.ResetState();
			JuggernautSpeed.ResetState();
			JuggernautPatches.ResetState();
			JuggernautPatches.CleanupWorldEffects();
			try
			{
				if ((Object)(object)PauseManager.Instance != (Object)null)
				{
					PauseManager.Instance.startRound = false;
					PauseManager.Instance.onStartRoundScreen = false;
				}
			}
			catch
			{
			}
		}

		private void Update()
		{
			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 (Time.unscaledTime >= _nextOutlineTime)
			{
				_nextOutlineTime = Time.unscaledTime + 0.2f;
				JuggernautOutline.EnforceOutline();
				JuggernautSpeed.EnforceSpeed();
			}
			if (!Enabled.Value || (Object)(object)GameManager.Instance == (Object)null || (Object)(object)InstanceFinder.NetworkManager == (Object)null || !InstanceFinder.NetworkManager.IsServer)
			{
				return;
			}
			if (MatchOver)
			{
				JuggernautManager.ServerBroadcastTick();
				return;
			}
			JuggernautPatches.ServerRespawnWatchdogUpdate();
			JuggernautManager.ServerUpdate();
			foreach (KeyValuePair<int, ClientInstance> playerInstance in ClientInstance.playerInstances)
			{
				if (!GameManager.Instance.alivePlayers.Contains(playerInstance.Key))
				{
					GameManager.Instance.alivePlayers.Add(playerInstance.Key);
				}
			}
		}

		internal static bool TryBroadcastStateOverMycelium()
		{
			try
			{
				if (!MyceliumNetwork.InLobby)
				{
					return false;
				}
				MyceliumNetwork.RPC(774477u, "SyncJuggernautState", (ReliableType)1, new object[5]
				{
					JuggernautManager.JugPlayerId,
					JuggernautManager.EffectivePointsToWin,
					JuggernautManager.EffectiveTakesToWin,
					JuggernautManager.EffectiveSpeedBoostPercent,
					JuggernautManager.SerializePoints()
				});
				return true;
			}
			catch (Exception ex)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)("Mycelium state broadcast failed: " + ex.GetType().Name));
				}
				return false;
			}
		}

		[CustomRPC]
		public void SyncJuggernautState(int jugPlayerId, int pointsToWin, int takesToWin, int speedBoostPercent, string pointsData)
		{
			if (!((Object)(object)InstanceFinder.NetworkManager != (Object)null) || !InstanceFinder.NetworkManager.IsServer)
			{
				JuggernautManager.ApplySyncedState(jugPlayerId, pointsToWin, takesToWin, speedBoostPercent, pointsData);
			}
		}
	}
}