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(); obj.renderMode = (RenderMode)0; obj.sortingOrder = 1000; CanvasScaler obj2 = ((Component)this).gameObject.AddComponent(); 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(); 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()).color = new Color(0f, 0f, 0f, 0.45f); VerticalLayoutGroup obj4 = _panel.AddComponent(); ((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(); obj5.horizontalFit = (FitMode)2; obj5.verticalFit = (FitMode)2; GameObject val = new GameObject("JuggernautText"); val.transform.SetParent(_panel.transform, false); val.AddComponent(); _text = val.AddComponent(); ((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("JUGGURNAUGHT first to ").Append(JuggernautManager.EffectivePointsToWin).Append(" • ") .Append(JuggernautManager.EffectiveTakesToWin) .Append((JuggernautManager.EffectiveTakesToWin == 1) ? " take wins" : " takes win") .Append(""); int jugId = JuggernautManager.JugPlayerId; List> list = new List>(); foreach (KeyValuePair playerInstance in ClientInstance.playerInstances) { JuggernautManager.Points.TryGetValue(playerInstance.Key, out var value); list.Add(new KeyValuePair(playerInstance.Key, value)); } foreach (KeyValuePair 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("").Append(playerNameTag).Append(" ") .Append(item.Value) .Append(" JUG"); } else { stringBuilder.Append("").Append(playerNameTag).Append(" ") .Append(item.Value) .Append(""); } int takeWins = GetTakeWins(item.Key); if (takeWins > 0) { stringBuilder.Append(" ").Append((takeWins == 1) ? "1 take" : (takeWins + " takes")).Append(""); } } if (jugId < 0) { stringBuilder.Append("\nFirst blood claims the crown!"); } 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 = "[JUGGURNAUGHT]"; private const string SyncMarker = "[[JUGSYNC]]|"; public static int JugPlayerId = -1; public static readonly Dictionary Points = new Dictionary(); 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 _grantedHealthInstances = new HashSet(); 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("[JUGGURNAUGHT] The Juggernaut left the game! First blood claims the crown!"); 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} {1} drew first blood and IS THE JUGGERNAUT! (+{2} HP)", "[JUGGURNAUGHT]", GetPlayerNameTag(killerId), JuggernautPlugin.BonusHealth.Value)); } } else if (deadPlayerId == JugPlayerId) { if (flag) { BecomeJuggernaut(killerId, string.Format("{0} {1} slayed the Juggernaut {2} and CLAIMED THE CROWN! (+{3} HP)", "[JUGGURNAUGHT]", GetPlayerNameTag(killerId), GetPlayerNameTag(deadPlayerId), JuggernautPlugin.BonusHealth.Value)); } else { BroadcastChat("[JUGGURNAUGHT] The Juggernaut " + GetPlayerNameTag(deadPlayerId) + " died... but keeps the crown."); } } 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} {1} +{2} HP for the kill", "[JUGGURNAUGHT]", 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("[JUGGURNAUGHT] " + GetPlayerNameTag(winnerPlayerId) + " takes the final take and WINS THE ROUND!"); 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} {1} reached {2} points and WINS THE TAKE! ({3}/{4} takes)", "[JUGGURNAUGHT]", 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("[JUGGURNAUGHT] New take — first blood claims the crown!"); } } 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} First blood claims the crown! Hold it to earn points — first to {1} wins the round.", "[JUGGURNAUGHT]", 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 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(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 _outlinedRenderers = new List(); 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(); 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(); 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 _playerRagdolls = new Dictionary(); private static HashSet _respawnInProgress = new HashSet(); private static Dictionary _respawnRequestSeq = new Dictionary(); private static HashSet _playersAwaitingRespawn = new HashSet(); private static Dictionary _nextRespawnRecoveryTime = new Dictionary(); private static Dictionary _lastDeathHandledTime = new Dictionary(); 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(); 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(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(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(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 playerRagdoll in _playerRagdolls) { try { if ((Object)(object)playerRagdoll.Value != (Object)null) { Object.Destroy((Object)(object)playerRagdoll.Value); } } catch { } } _playerRagdolls.Clear(); RagdollDress[] array = Object.FindObjectsOfType(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(); if ((((component == null) ? ((int?)null) : component.sync___get_value_playerClient()?.PlayerId) ?? (-1)) != playerId) { reason = "player id mismatch"; return false; } PlayerHealth component2 = gameObject.GetComponent(); 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(); if ((Object)(object)component3 == (Object)null || !component3.IsSpawned) { reason = "player NetworkObject is not spawned"; return false; } CharacterController component4 = gameObject.GetComponent(); 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(true); if ((Object)(object)componentInParent != (Object)null) { return componentInParent.PlayerId; } PlayerValues obj = ((Component)val2).GetComponentInParent(true) ?? ((Component)val2).GetComponentInChildren(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(true) ?? ((Component)val2).GetComponentInChildren(true); if ((Object)(object)val4 != (Object)null) { val3 = val4.sync___get_value__rootObject(); } else { Claymore val5 = ((Component)val2).GetComponentInParent(true) ?? ((Component)val2).GetComponentInChildren(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(true) ?? root.GetComponentInChildren(true); if ((Object)(object)val != (Object)null) { return val.PlayerId; } PlayerValues obj = root.GetComponentInParent(true) ?? root.GetComponentInChildren(true); int num = ((obj == null) ? ((int?)null) : obj.sync___get_value_playerClient()?.PlayerId) ?? (-1); if (num >= 0) { return num; } foreach (KeyValuePair playerInstance in ClientInstance.playerInstances) { try { ClientInstance value = playerInstance.Value; PlayerManager val2 = ((value != null) ? ((Component)value).GetComponent() : 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(); } 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() : 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 Enabled; public static ConfigEntry TakesToWin; public static ConfigEntry PointsToWin; public static ConfigEntry PointsPerSecond; public static ConfigEntry BonusHealth; public static ConfigEntry HealthPerKill; public static ConfigEntry SpeedBoostPercent; public static ConfigEntry RespawnDelay; public static ConfigEntry 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("General", "Enabled", true, "Enable Juggernaut mode. Only the host's setting matters for gameplay."); PointsToWin = ((BaseUnityPlugin)this).Config.Bind("General", "Points To Win", 100, new ConfigDescription("Points the Juggernaut must accumulate to win a take.", (AcceptableValueBase)(object)new AcceptableValueRange(10, 1000), Array.Empty())); TakesToWin = ((BaseUnityPlugin)this).Config.Bind("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(1, 5), Array.Empty())); PointsPerSecond = ((BaseUnityPlugin)this).Config.Bind("General", "Points Per Second", 5, new ConfigDescription("Points the Juggernaut earns for every second they stay alive.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 50), Array.Empty())); BonusHealth = ((BaseUnityPlugin)this).Config.Bind("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(25, 400), Array.Empty())); HealthPerKill = ((BaseUnityPlugin)this).Config.Bind("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(0, 200), Array.Empty())); SpeedBoostPercent = ((BaseUnityPlugin)this).Config.Bind("Perks", "Jug Speed Boost %", 0, new ConfigDescription("Extra movement speed for the Juggernaut, as a percentage (0 = off).", (AcceptableValueBase)(object)new AcceptableValueRange(0, 100), Array.Empty())); RespawnDelay = ((BaseUnityPlugin)this).Config.Bind("General", "Respawn Delay", 3f, new ConfigDescription("Seconds before a dead player respawns.", (AcceptableValueBase)(object)new AcceptableValueRange(0.25f, 10f), Array.Empty())); ShowHud = ((BaseUnityPlugin)this).Config.Bind("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(); 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 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); } } } }