using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using FMOD.Studio; using FMODUnity; using HarmonyLib; using Microsoft.CodeAnalysis; using Mirror; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("SbgShields")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+6117a8cb81b860e7f21d94cef7865cd7fba20110")] [assembly: AssemblyProduct("SbgShields")] [assembly: AssemblyTitle("SbgShields")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace SbgShields { internal static class Hud { private struct ShakeStep { public float pct; public float secs; } private static Font _font; private static bool _fontSearched; private static Texture2D _bubbleTex; private static Texture2D _dotTex; private static GUIStyle _percentStyle; private static GUIStyle _timerStyle; private static GUIStyle _labelStyle; private static double _shakeStart = double.MinValue; private static float _shakeSeed; private static int _cachedPct = int.MinValue; private static int _cachedFontSize = -1; private static readonly GUIContent _pctContent = new GUIContent(); private static Vector2 _pctSize; private static Vector2 _pctMax; private static bool _pipsWereShown; private static double _pipsShownAt = double.MinValue; private static Vector2 _lastOffset; private static ShakeStep[] _shakeTable; private static string _shakeTableSource; private static GUIStyle _noticeBig; private static GUIStyle _noticeSmall; private static Texture2D _panelTex; internal static void Init() { ShieldState.PercentIncreased -= OnPercentIncreased; ShieldState.PercentIncreased += OnPercentIncreased; } internal static void Shutdown() { ShieldState.PercentIncreased -= OnPercentIncreased; if ((Object)(object)_panelTex != (Object)null) { Object.Destroy((Object)(object)_panelTex); _panelTex = null; } if ((Object)(object)_bubbleTex != (Object)null) { Object.Destroy((Object)(object)_bubbleTex); _bubbleTex = null; } if ((Object)(object)_dotTex != (Object)null) { Object.Destroy((Object)(object)_dotTex); _dotTex = null; } _percentStyle = null; _fontSearched = false; _cachedPct = int.MinValue; } internal static void InvalidateFont() { _fontSearched = false; _percentStyle = null; _cachedPct = int.MinValue; } private static void OnPercentIncreased(float _) { _shakeStart = Time.timeAsDouble; _shakeSeed = Random.value * 100f; } private static void EnsureAssets() { //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Expected O, but got Unknown //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Expected O, but got Unknown //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Expected O, but got Unknown if (!_fontSearched) { _fontSearched = true; _font = FindFont(Plugin.PercentFontName.Value); if ((Object)(object)_font == (Object)null) { Plugin.Log.LogWarning((object)("Font '" + Plugin.PercentFontName.Value + "' not installed on this machine; using the default. Install DF Gothic as a system font and restart to use it.")); } else { Plugin.Log.LogInfo((object)("Percent font: " + ((Object)_font).name)); } } if ((Object)(object)_bubbleTex == (Object)null) { _bubbleTex = MakeBubbleTexture(128); } if ((Object)(object)_dotTex == (Object)null) { _dotTex = MakeDotTexture(24); } if (_percentStyle == null) { _percentStyle = new GUIStyle(GUI.skin.label) { alignment = (TextAnchor)6, fontStyle = (FontStyle)1, wordWrap = false, clipping = (TextClipping)0 }; if ((Object)(object)_font != (Object)null) { _percentStyle.font = _font; } _percentStyle.normal.textColor = Color.white; _timerStyle = new GUIStyle(_percentStyle) { alignment = (TextAnchor)4 }; _labelStyle = new GUIStyle(_percentStyle) { alignment = (TextAnchor)4, fontStyle = (FontStyle)0 }; } } private static Font FindFont(string wanted) { if (string.IsNullOrEmpty(wanted)) { return null; } try { string[] oSInstalledFontNames = Font.GetOSInstalledFontNames(); string text = Normalize(wanted); string text2 = null; string[] array = oSInstalledFontNames; foreach (string text3 in array) { string text4 = Normalize(text3); if (text4 == text) { text2 = text3; break; } if (text2 == null && text4.Contains(text)) { text2 = text3; } } if (text2 == null) { return null; } return Font.CreateDynamicFontFromOSFont(text2, 64); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Font lookup failed: " + ex.Message)); return null; } } private static string Normalize(string s) { return s.Replace(" ", "").Replace("-", "").Replace("_", "") .ToLowerInvariant(); } private static Texture2D MakeBubbleTexture(int size) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(size, size, (TextureFormat)4, false) { wrapMode = (TextureWrapMode)1, filterMode = (FilterMode)1 }; float num = (float)size * 0.5f; Color[] array = (Color[])(object)new Color[size * size]; for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { float num2 = ((float)j + 0.5f - num) / num; float num3 = ((float)i + 0.5f - num) / num; float num4 = Mathf.Sqrt(num2 * num2 + num3 * num3); float num5 = 0f; if (num4 < 1f) { float num6 = Mathf.Lerp(0.22f, 0.55f, Mathf.Pow(num4, 2.5f)); float num7 = Mathf.Exp(0f - Mathf.Pow((num4 - 0.93f) / 0.05f, 2f)) * 0.9f; float num8 = num2 + 0.42f; float num9 = num3 - 0.42f; float num10 = Mathf.Exp((0f - (num8 * num8 + num9 * num9)) / 0.05f) * 0.85f; num5 = Mathf.Clamp01(num6 + num7 + num10); num5 *= Mathf.Clamp01((1f - num4) / 0.03f); } array[i * size + j] = new Color(1f, 1f, 1f, num5); } } val.SetPixels(array); val.Apply(); return val; } private static Texture2D MakeDotTexture(int size) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(size, size, (TextureFormat)4, false) { wrapMode = (TextureWrapMode)1 }; float num = (float)size * 0.5f; Color[] array = (Color[])(object)new Color[size * size]; for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { float num2 = Vector2.Distance(new Vector2((float)j + 0.5f, (float)i + 0.5f), new Vector2(num, num)) / num; array[i * size + j] = new Color(1f, 1f, 1f, Mathf.Clamp01((1f - num2) / 0.12f)); } } val.SetPixels(array); val.Apply(); return val; } internal static void Draw() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_02d4: Unknown result type (might be due to invalid IL or missing references) if (Event.current == null || (int)Event.current.type != 7 || !Plugin.ShowHud.Value) { return; } if (!ModHandshake.GameplayEnabled) { DrawStandDownNotice(); return; } PlayerInfo localPlayerInfo = GameManager.LocalPlayerInfo; if ((Object)(object)localPlayerInfo == (Object)null || !ShouldShow()) { return; } try { if ((Object)(object)localPlayerInfo.Movement != (Object)null && localPlayerInfo.Movement.IsRespawningOrDrowning) { return; } } catch { } if (!KillZone.IsLingering) { EnsureAssets(); float value = Plugin.HudScale.Value; float num = (float)Screen.height - Plugin.HudBottomMargin.Value * value; bool inPlayableHole = ShieldState.InPlayableHole; int num2 = Mathf.RoundToInt((float)Plugin.PercentFontSize.Value * value); int num3 = Mathf.RoundToInt(ShieldState.Percent); if (num3 != _cachedPct || num2 != _cachedFontSize) { _cachedPct = num3; _cachedFontSize = num2; _pctContent.text = num3 + "%"; _percentStyle.fontSize = Mathf.RoundToInt((float)num2 * (1f + Plugin.PercentShakePunch.Value)); _pctMax = _percentStyle.CalcSize(_pctContent); _percentStyle.fontSize = num2; _pctSize = _percentStyle.CalcSize(_pctContent); } float num4 = (inPlayableHole ? (((float)Screen.width - _pctSize.x) * 0.5f + Plugin.HudHorizontalOffset.Value * value) : ((float)Screen.width * 0.5f + Plugin.HudHorizontalOffset.Value * value)); float num5 = num + Plugin.PercentVerticalOffset.Value * value; if (inPlayableHole) { DrawPercent(new Rect(num4, num5 - _pctSize.y, _pctSize.x, _pctSize.y), _pctContent.text, num2); } bool isElectromagnetShieldActive = localPlayerInfo.IsElectromagnetShieldActive; bool flag = ShieldState.IsOnBreakCooldown || (ShieldState.Pips <= 0 && !Plugin.RestoreAfterBreakCooldown.Value); bool flag2 = !isElectromagnetShieldActive && Plugin.ActivationBlockedByState(localPlayerInfo, forHud: true); bool flag3 = isElectromagnetShieldActive || !flag2 || flag; bool flag4 = Plugin.ShowPipDots.Value && flag3 && !flag && ShieldState.Pips > 0; if (flag4 && !_pipsWereShown) { _pipsShownAt = Time.timeAsDouble; } _pipsWereShown = flag4; if (flag3) { float num6 = Plugin.BubbleHudSize.Value * value; float num7 = Plugin.BubbleHudGap.Value * value; float num8 = ((!inPlayableHole) ? (num4 - num6 * 0.5f) : (Plugin.BubbleHudOnLeft.Value ? (num4 - num7 - num6) : (num4 + _pctMax.x + num7))); float num9 = num - num6; DrawBubble(localPlayerInfo, new Rect(num8, num9, num6, num6), value, isElectromagnetShieldActive, flag, flag4); } } } private static float PopEase(float t) { if (t <= 0f) { return 0f; } if (t >= 1f) { return 1f; } float num = t - 1f; return 1f + 2.70158f * num * num * num + 1.70158f * num * num; } private static bool ShouldShow() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Invalid comparison between Unknown and I4 try { if (PauseMenu.IsPaused) { return false; } if (Scoreboard.IsVisible) { return false; } if (ShieldState.InDrivingRange) { return true; } MatchState matchState = CourseManager.MatchState; if (matchState - 2 <= 3) { return true; } return false; } catch { return true; } } private static void DrawPercent(Rect rect, string text, int fontSize) { //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_028a: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_0291: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) float num = ShakeDuration(ShieldState.Percent); float num2 = ((num <= 0.01f) ? 1f : ((float)((Time.timeAsDouble - _shakeStart) / (double)num))); float num3 = 0f; float num4 = 1f; if (num2 >= 0f && num2 < 1f) { float num5 = (1f - num2) * (1f - num2); num3 = Plugin.PercentShakePixels.Value * num5; num4 = 1f + Plugin.PercentShakePunch.Value * num5 * num5; } Vector2 zero = Vector2.zero; if (num3 > 0.01f) { float num6 = Time.time * Plugin.PercentShakeSpeed.Value + _shakeSeed; ((Vector2)(ref zero))..ctor((Mathf.PerlinNoise(num6, 0.3f) - 0.5f) * 2f * num3, (Mathf.PerlinNoise(0.7f, num6) - 0.5f) * 2f * num3); } Rect r = default(Rect); ((Rect)(ref r))..ctor(((Rect)(ref rect)).x + zero.x, ((Rect)(ref rect)).yMax - _pctSize.y + zero.y, _pctSize.x, _pctSize.y); Color val = PercentColor(ShieldState.Percent); float thickness = Mathf.Max(1f, 3f * Plugin.HudScale.Value); Matrix4x4 matrix = GUI.matrix; if (num4 != 1f) { GUIUtility.ScaleAroundPivot(new Vector2(num4, num4), ((Rect)(ref r)).center); } _percentStyle.fontSize = fontSize; int num7 = Mathf.RoundToInt(Plugin.PercentBlurSamples.Value); if (num7 > 0 && num3 > 0.5f) { Vector2 val2 = zero - _lastOffset; if (((Vector2)(ref val2)).sqrMagnitude > 0.01f) { float num8 = Mathf.Clamp01(num3 / Mathf.Max(1f, Plugin.PercentShakePixels.Value)); Rect val3 = default(Rect); for (int i = 1; i <= num7; i++) { float num9 = (float)i / (float)(num7 + 1); ((Rect)(ref val3))..ctor(((Rect)(ref r)).x - val2.x * num9 * Plugin.PercentBlurLength.Value, ((Rect)(ref r)).y - val2.y * num9 * Plugin.PercentBlurLength.Value, ((Rect)(ref r)).width, ((Rect)(ref r)).height); Color color = val; color.a = val.a * (1f - num9) * 0.5f * num8; Color color2 = GUI.color; GUI.color = color; GUI.Label(val3, text, _percentStyle); GUI.color = color2; } } } _lastOffset = zero; DrawOutlined(r, text, _percentStyle, val, Color.black, thickness); GUI.matrix = matrix; } private static float ShakeDuration(float pct) { ShakeStep[] array = ShakeTable(); if (array == null || array.Length == 0) { return Plugin.PercentShakeDuration.Value; } if (pct <= array[0].pct) { return array[0].secs; } for (int i = 1; i < array.Length; i++) { if (!(pct > array[i].pct)) { ShakeStep shakeStep = array[i - 1]; ShakeStep shakeStep2 = array[i]; float num = Mathf.Max(0.001f, shakeStep2.pct - shakeStep.pct); return Mathf.Lerp(shakeStep.secs, shakeStep2.secs, (pct - shakeStep.pct) / num); } } return array[^1].secs; } internal static void InvalidateShakeTable() { _shakeTable = null; } private static ShakeStep[] ShakeTable() { string value = Plugin.PercentShakeDurationTable.Value; if (_shakeTable != null && value == _shakeTableSource) { return _shakeTable; } _shakeTableSource = value; List list = new List(); string[] array = value.Split(','); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split(':'); if (array2.Length == 2 && float.TryParse(array2[0].Trim(), out var result) && float.TryParse(array2[1].Trim(), out var result2)) { list.Add(new ShakeStep { pct = result, secs = Mathf.Max(0f, result2) }); } } list.Sort((ShakeStep x, ShakeStep y) => x.pct.CompareTo(y.pct)); if (list.Count == 0) { Plugin.Log.LogWarning((object)("Could not read PercentShakeDurationTable '" + value + "'; using PercentShakeDuration instead.")); } _shakeTable = list.ToArray(); return _shakeTable; } private static void DrawStandDownNotice() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Expected O, but got Unknown //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) string blockReason = ModHandshake.BlockReason; if (!string.IsNullOrEmpty(blockReason)) { if (_noticeBig == null) { _noticeBig = new GUIStyle(GUI.skin.label) { alignment = (TextAnchor)4, wordWrap = true, fontStyle = (FontStyle)1 }; _noticeSmall = new GUIStyle(GUI.skin.label) { alignment = (TextAnchor)4, wordWrap = true }; } if ((Object)(object)_panelTex == (Object)null) { _panelTex = new Texture2D(1, 1, (TextureFormat)4, false); _panelTex.SetPixel(0, 0, new Color(0f, 0f, 0f, 0.78f)); _panelTex.Apply(); } float value = Plugin.HudScale.Value; if (!(Time.timeAsDouble - ModHandshake.BlockedSince < (double)Plugin.MismatchPopupDuration.Value)) { _noticeSmall.fontSize = Mathf.RoundToInt(16f * value); string text = "SBG Shields inactive - " + blockReason; Vector2 val = _noticeSmall.CalcSize(new GUIContent(text)); DrawOutlined(new Rect(((float)Screen.width - val.x) * 0.5f, 8f * value, val.x, val.y), text, _noticeSmall, new Color(1f, 0.78f, 0.25f), Color.black, 2f); return; } _noticeBig.fontSize = Mathf.RoundToInt(26f * value); _noticeSmall.fontSize = Mathf.RoundToInt(17f * value); float num = Mathf.Min((float)Screen.width * 0.7f, 720f * value); float num2 = 150f * value; Rect val2 = default(Rect); ((Rect)(ref val2))..ctor(((float)Screen.width - num) * 0.5f, (float)Screen.height * 0.22f, num, num2); GUI.DrawTexture(val2, (Texture)(object)_panelTex, (ScaleMode)0); DrawOutlined(new Rect(((Rect)(ref val2)).x, ((Rect)(ref val2)).y + 14f * value, ((Rect)(ref val2)).width, 34f * value), "SBG Shields is standing down", _noticeBig, new Color(1f, 0.78f, 0.25f), Color.black, 2f); Rect r = new Rect(((Rect)(ref val2)).x + 20f * value, ((Rect)(ref val2)).y + 54f * value, ((Rect)(ref val2)).width - 40f * value, 80f * value); string text2 = (blockReason.Contains("public lobby") ? "The shield is disabled in public lobbies on purpose.\n\nHost a Friends or Invite Only lobby to use it." : (blockReason + ".\n\nThe match is running vanilla rules so nothing desyncs. Everyone needs SBG Shields 0.7.7 for the shield to work.")); DrawOutlined(r, text2, _noticeSmall, Color.white, Color.black, 1.5f); } } private static Color PercentColor(float pct) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Clamp01(pct / Mathf.Max(1f, Plugin.PercentForMaxScaling.Value)); if (num < 0.33f) { return Color.Lerp(Color.white, new Color(1f, 0.92f, 0.25f), num / 0.33f); } if (num < 0.66f) { return Color.Lerp(new Color(1f, 0.92f, 0.25f), new Color(1f, 0.55f, 0.1f), (num - 0.33f) / 0.33f); } return Color.Lerp(new Color(1f, 0.55f, 0.1f), new Color(0.9f, 0.08f, 0.08f), (num - 0.66f) / 0.34f); } private static void DrawBubble(PlayerInfo player, Rect rect, float scale, bool up, bool onBreakCd, bool showPips) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) Color val = Skin.Of(player); string reason; bool flag = ShieldState.CanActivate(out reason); float secondsUntilReady = ShieldState.SecondsUntilReady; Color color = val; if (up) { color = Color.Lerp(val, Color.white, 0.25f); rect = Grow(rect, 6f * scale); } else if (!flag) { color = val * 0.3f; color.a = 1f; } Color color2 = GUI.color; GUI.color = color; GUI.DrawTexture(rect, (Texture)(object)_bubbleTex, (ScaleMode)2, true); GUI.color = color2; if (!flag) { _timerStyle.fontSize = Mathf.RoundToInt((float)Plugin.PercentFontSize.Value * 0.42f * scale); string text = (float.IsInfinity(secondsUntilReady) ? "X" : ((secondsUntilReady >= 10f) ? $"{secondsUntilReady:0}" : $"{secondsUntilReady:0.0}")); DrawOutlined(rect, text, _timerStyle, Color.white, Color.black, Mathf.Max(1f, 2f * scale)); } if (!showPips) { GUI.color = color2; return; } int num = Mathf.Max(1, Plugin.MaxPips.Value); float num2 = 12f * scale; float num3 = 5f * scale; float num4 = (float)num * num2 + (float)(num - 1) * num3; float num5 = ((Rect)(ref rect)).center.x - num4 * 0.5f; float num6 = ((Rect)(ref rect)).yMax + 4f * scale; double num7 = Time.timeAsDouble - _pipsShownAt; for (int i = 0; i < num; i++) { bool flag2 = i < ShieldState.Pips; float num8 = PopEase((float)((num7 - (double)i * 0.06) / 0.16)); if (!(num8 <= 0f)) { float num9 = num2 * num8; float num10 = num5 + (float)i * (num2 + num3) + num2 * 0.5f; float num11 = num6 + num2 * 0.5f; GUI.color = (Color)(flag2 ? val : new Color(0f, 0f, 0f, 0.55f)); GUI.DrawTexture(new Rect(num10 - num9 * 0.5f, num11 - num9 * 0.5f, num9, num9), (Texture)(object)_dotTex, (ScaleMode)2, true); } } GUI.color = color2; } private static Rect Grow(Rect r, float by) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) return new Rect(((Rect)(ref r)).x - by, ((Rect)(ref r)).y - by, ((Rect)(ref r)).width + 2f * by, ((Rect)(ref r)).height + 2f * by); } private static void DrawOutlined(Rect r, string text, GUIStyle style, Color fill, Color outline, float thickness) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) Color textColor = style.normal.textColor; style.normal.textColor = outline; GUI.Label(new Rect(((Rect)(ref r)).x - thickness, ((Rect)(ref r)).y, ((Rect)(ref r)).width, ((Rect)(ref r)).height), text, style); GUI.Label(new Rect(((Rect)(ref r)).x + thickness, ((Rect)(ref r)).y, ((Rect)(ref r)).width, ((Rect)(ref r)).height), text, style); GUI.Label(new Rect(((Rect)(ref r)).x, ((Rect)(ref r)).y - thickness, ((Rect)(ref r)).width, ((Rect)(ref r)).height), text, style); GUI.Label(new Rect(((Rect)(ref r)).x, ((Rect)(ref r)).y + thickness, ((Rect)(ref r)).width, ((Rect)(ref r)).height), text, style); GUI.Label(new Rect(((Rect)(ref r)).x + thickness, ((Rect)(ref r)).y + thickness, ((Rect)(ref r)).width, ((Rect)(ref r)).height), text, style); style.normal.textColor = fill; GUI.Label(r, text, style); style.normal.textColor = textColor; } } internal static class KillZone { private static bool _armed; private static double _armedAt; private static bool _wentUp; private static bool _lingering; private static double _respawnAt; private static GameObject _flashGo; private static ParticleSystem _flashPs; private static ParticleSystem _sparkPs; private static Material _flashMat; private static Material _sparkMat; private static Texture2D _starTex; private static Texture2D _dotTex; internal static bool IsArmed => _armed; internal static bool IsLingering => _lingering; internal static void Arm() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) _armed = true; _armedAt = Time.timeAsDouble; _wentUp = false; float value = Plugin.KillZoneUpwardBoost.Value; if (value > 0f) { ShieldState.PendingVelocityCorrection += Vector3.up * value; ShieldState.HasPendingVelocityCorrection = true; ShieldState.LaunchDragUntil = double.MinValue; } if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)$"Kill zone armed at {ShieldState.Percent:0}%: +{value:0} m/s up, waiting for the apex."); } } internal static void Disarm() { _armed = false; } internal static void Tick() { //IL_0075: Unknown result type (might be due to invalid IL or missing references) if (_lingering) { TickLinger(); } else { if (!_armed) { return; } PlayerInfo localPlayerInfo = GameManager.LocalPlayerInfo; PlayerMovement val = (((Object)(object)localPlayerInfo != (Object)null) ? localPlayerInfo.Movement : null); if ((Object)(object)val == (Object)null) { _armed = false; return; } double timeAsDouble = Time.timeAsDouble; if (val.IsRespawningOrDrowning) { _armed = false; return; } if (!val.IsKnockedOut) { if (timeAsDouble - _armedAt > 1.0) { _armed = false; } return; } float y = val.Velocity.y; if (y > 0.5f) { _wentUp = true; } bool num = _wentUp && y <= 0f; bool flag = !_wentUp && timeAsDouble - _armedAt > 0.35; bool flag2 = timeAsDouble - _armedAt > (double)Plugin.KillZoneMaxRiseTime.Value; if (num || flag || flag2) { Fire(localPlayerInfo, val); } } } private static void Fire(PlayerInfo p, PlayerMovement mv) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) _armed = false; Vector3 val = (((Object)(object)p.ChestBone != (Object)null) ? p.ChestBone.position : (((Component)p).transform.position + Vector3.up)); if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)$"STAR KO at {ShieldState.Percent:0}% (height {val.y:0.0})."); } if (Plugin.KillZoneFlash.Value) { try { PlayFlash(val, Skin.Of(p)); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Kill flash failed: " + ex.Message)); } } if (Plugin.KillZoneBoom.Value) { try { RuntimeManager.PlayOneShot(GameManager.AudioSettings.ElectromagnetShieldExplosionEvent, val); } catch (Exception ex2) { if (Plugin.VerboseLogging.Value) { Plugin.Log.LogWarning((object)("Kill boom failed: " + ex2.Message)); } } try { CameraModuleController.Shake(GameManager.CameraGameplaySettings.RocketExplosionScreenshakeSettings, val, 1.6f, 1.4f); } catch { try { CameraModuleController.Shake(GameManager.CameraGameplaySettings.ElectromagnetExplosionScreenshakeSettings, val, 1f, 1f); } catch { } } } ShieldState.Percent = Mathf.Max(0f, Plugin.PercentAfterKillZoneDeath.Value); ShieldState.BreakStunUntil = double.MinValue; ShieldState.LastKnockoutWasBreakStun = false; float num = Mathf.Max(0f, Plugin.KillZoneDeathLinger.Value); if (num > 0.01f && Hide(mv)) { _lingering = true; _respawnAt = Time.timeAsDouble + (double)num; } else { BeginRespawn(mv); } } private static bool Hide(PlayerMovement mv) { try { mv.NetworkisVisible = false; return true; } catch (Exception ex) { Plugin.Log.LogWarning((object)("Kill zone could not hide the player: " + ex.Message)); return false; } } private static void TickLinger() { PlayerInfo localPlayerInfo = GameManager.LocalPlayerInfo; PlayerMovement val = (((Object)(object)localPlayerInfo != (Object)null) ? localPlayerInfo.Movement : null); if ((Object)(object)val == (Object)null) { _lingering = false; } else if (val.IsRespawningOrDrowning) { _lingering = false; } else if (!(Time.timeAsDouble < _respawnAt)) { _lingering = false; BeginRespawn(val); } } private static void BeginRespawn(PlayerMovement mv) { ShieldState.KillZoneDeathPending = true; bool flag = false; try { flag = mv.TryBeginRespawn(false, (RespawnTarget)0, true); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Kill respawn failed: " + ex.Message)); } if (!flag) { ShieldState.KillZoneDeathPending = false; Plugin.Log.LogWarning((object)"Kill zone: the game refused the respawn (already respawning / match resolved)."); try { mv.NetworkisVisible = true; } catch { } } } internal static void CancelLinger() { if (!_lingering) { return; } _lingering = false; PlayerMovement val = (((Object)(object)GameManager.LocalPlayerInfo != (Object)null) ? GameManager.LocalPlayerInfo.Movement : null); if (!((Object)(object)val != (Object)null)) { return; } try { val.NetworkisVisible = true; } catch { } } private static void EnsureFlash() { //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Expected O, but got Unknown //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Expected O, but got Unknown //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_027b: Expected O, but got Unknown //IL_02af: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Unknown result type (might be due to invalid IL or missing references) //IL_02e6: Unknown result type (might be due to invalid IL or missing references) //IL_02fc: Unknown result type (might be due to invalid IL or missing references) //IL_0312: Unknown result type (might be due to invalid IL or missing references) //IL_0323: Unknown result type (might be due to invalid IL or missing references) //IL_033b: Unknown result type (might be due to invalid IL or missing references) //IL_0340: Unknown result type (might be due to invalid IL or missing references) //IL_0351: Unknown result type (might be due to invalid IL or missing references) //IL_036c: Unknown result type (might be due to invalid IL or missing references) //IL_0371: Unknown result type (might be due to invalid IL or missing references) //IL_0380: Unknown result type (might be due to invalid IL or missing references) //IL_0385: Unknown result type (might be due to invalid IL or missing references) //IL_03a8: Unknown result type (might be due to invalid IL or missing references) //IL_03ad: Unknown result type (might be due to invalid IL or missing references) //IL_03d0: Unknown result type (might be due to invalid IL or missing references) //IL_03d5: Unknown result type (might be due to invalid IL or missing references) //IL_03e6: Unknown result type (might be due to invalid IL or missing references) //IL_03eb: Unknown result type (might be due to invalid IL or missing references) //IL_03f0: Unknown result type (might be due to invalid IL or missing references) //IL_03fa: Expected O, but got Unknown //IL_03f5: Unknown result type (might be due to invalid IL or missing references) //IL_0404: Unknown result type (might be due to invalid IL or missing references) //IL_0409: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_flashGo != (Object)null)) { if ((Object)(object)_starTex == (Object)null) { _starTex = MakeStarTexture(128); } if ((Object)(object)_dotTex == (Object)null) { _dotTex = MakeDotTexture(32); } if ((Object)(object)_flashMat == (Object)null) { _flashMat = LaunchVfx.MakeUnlitMaterial(_starTex, additive: true); } if ((Object)(object)_sparkMat == (Object)null) { _sparkMat = LaunchVfx.MakeUnlitMaterial(_dotTex, additive: true); } if (!((Object)(object)_flashMat == (Object)null)) { _flashGo = new GameObject("SbgKillFlash"); _flashPs = _flashGo.AddComponent(); _flashPs.Stop(true, (ParticleSystemStopBehavior)0); MainModule main = _flashPs.main; ((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1; ((MainModule)(ref main)).loop = false; ((MainModule)(ref main)).playOnAwake = false; ((MainModule)(ref main)).duration = 0.1f; ((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(0.55f); ((MainModule)(ref main)).startSpeed = MinMaxCurve.op_Implicit(0f); ((MainModule)(ref main)).startSize = MinMaxCurve.op_Implicit(1f); ((MainModule)(ref main)).gravityModifier = MinMaxCurve.op_Implicit(0f); ((MainModule)(ref main)).maxParticles = 4; EmissionModule emission = _flashPs.emission; ((EmissionModule)(ref emission)).enabled = true; ((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(0f); ((EmissionModule)(ref emission)).SetBursts((Burst[])(object)new Burst[1] { new Burst(0f, (short)1) }); ShapeModule shape = _flashPs.shape; ((ShapeModule)(ref shape)).enabled = false; SizeOverLifetimeModule sizeOverLifetime = _flashPs.sizeOverLifetime; ((SizeOverLifetimeModule)(ref sizeOverLifetime)).enabled = true; ((SizeOverLifetimeModule)(ref sizeOverLifetime)).size = new MinMaxCurve(1f, new AnimationCurve((Keyframe[])(object)new Keyframe[4] { new Keyframe(0f, 0.05f), new Keyframe(0.12f, 1f), new Keyframe(0.5f, 1.15f), new Keyframe(1f, 1.4f) })); ColorOverLifetimeModule colorOverLifetime = _flashPs.colorOverLifetime; ((ColorOverLifetimeModule)(ref colorOverLifetime)).enabled = true; RotationOverLifetimeModule rotationOverLifetime = _flashPs.rotationOverLifetime; ((RotationOverLifetimeModule)(ref rotationOverLifetime)).enabled = true; ((RotationOverLifetimeModule)(ref rotationOverLifetime)).z = MinMaxCurve.op_Implicit(0.9f); ParticleSystemRenderer component = _flashGo.GetComponent(); ((Renderer)component).sharedMaterial = _flashMat; component.renderMode = (ParticleSystemRenderMode)0; ((Renderer)component).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)component).receiveShadows = false; GameObject val = new GameObject("Sparks"); val.transform.SetParent(_flashGo.transform, false); _sparkPs = val.AddComponent(); _sparkPs.Stop(true, (ParticleSystemStopBehavior)0); MainModule main2 = _sparkPs.main; ((MainModule)(ref main2)).simulationSpace = (ParticleSystemSimulationSpace)1; ((MainModule)(ref main2)).loop = false; ((MainModule)(ref main2)).playOnAwake = false; ((MainModule)(ref main2)).duration = 0.1f; ((MainModule)(ref main2)).startLifetime = new MinMaxCurve(0.4f, 0.8f); ((MainModule)(ref main2)).startSpeed = new MinMaxCurve(6f, 14f); ((MainModule)(ref main2)).startSize = new MinMaxCurve(0.25f, 0.6f); ((MainModule)(ref main2)).gravityModifier = MinMaxCurve.op_Implicit(0.3f); ((MainModule)(ref main2)).maxParticles = 64; EmissionModule emission2 = _sparkPs.emission; ((EmissionModule)(ref emission2)).enabled = true; ((EmissionModule)(ref emission2)).rateOverTime = MinMaxCurve.op_Implicit(0f); ((EmissionModule)(ref emission2)).SetBursts((Burst[])(object)new Burst[1] { new Burst(0f, (short)28) }); ShapeModule shape2 = _sparkPs.shape; ((ShapeModule)(ref shape2)).enabled = true; ((ShapeModule)(ref shape2)).shapeType = (ParticleSystemShapeType)0; ((ShapeModule)(ref shape2)).radius = 0.3f; SizeOverLifetimeModule sizeOverLifetime2 = _sparkPs.sizeOverLifetime; ((SizeOverLifetimeModule)(ref sizeOverLifetime2)).enabled = true; ((SizeOverLifetimeModule)(ref sizeOverLifetime2)).size = new MinMaxCurve(1f, new AnimationCurve((Keyframe[])(object)new Keyframe[2] { new Keyframe(0f, 1f), new Keyframe(1f, 0f) })); ColorOverLifetimeModule colorOverLifetime2 = _sparkPs.colorOverLifetime; ((ColorOverLifetimeModule)(ref colorOverLifetime2)).enabled = true; ParticleSystemRenderer component2 = val.GetComponent(); ((Renderer)component2).sharedMaterial = _sparkMat; component2.renderMode = (ParticleSystemRenderMode)1; component2.lengthScale = 3f; component2.velocityScale = 0.05f; ((Renderer)component2).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)component2).receiveShadows = false; } } } private static void PlayFlash(Vector3 pos, Color skin) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: 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_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Expected O, but got Unknown //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) EnsureFlash(); if (!((Object)(object)_flashGo == (Object)null)) { float value = Plugin.KillZoneFlashSize.Value; MainModule main = _flashPs.main; ((MainModule)(ref main)).startSize = MinMaxCurve.op_Implicit(value); Color val = Color.Lerp(Color.white, skin, 0.6f); Gradient val2 = new Gradient(); val2.SetKeys((GradientColorKey[])(object)new GradientColorKey[3] { new GradientColorKey(Color.white, 0f), new GradientColorKey(Color.white, 0.35f), new GradientColorKey(val, 1f) }, (GradientAlphaKey[])(object)new GradientAlphaKey[3] { new GradientAlphaKey(1f, 0f), new GradientAlphaKey(1f, 0.4f), new GradientAlphaKey(0f, 1f) }); ColorOverLifetimeModule colorOverLifetime = _flashPs.colorOverLifetime; ((ColorOverLifetimeModule)(ref colorOverLifetime)).color = new MinMaxGradient(val2); Gradient val3 = new Gradient(); val3.SetKeys((GradientColorKey[])(object)new GradientColorKey[2] { new GradientColorKey(Color.white, 0f), new GradientColorKey(val, 1f) }, (GradientAlphaKey[])(object)new GradientAlphaKey[2] { new GradientAlphaKey(1f, 0f), new GradientAlphaKey(0f, 1f) }); ColorOverLifetimeModule colorOverLifetime2 = _sparkPs.colorOverLifetime; ((ColorOverLifetimeModule)(ref colorOverLifetime2)).color = new MinMaxGradient(val3); _flashGo.transform.position = pos; _flashPs.Play(true); } } private static Texture2D MakeStarTexture(int size) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(size, size, (TextureFormat)4, true) { wrapMode = (TextureWrapMode)1, filterMode = (FilterMode)1 }; Color[] array = (Color[])(object)new Color[size * size]; float num = (float)size * 0.5f; for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { float num2 = ((float)j + 0.5f - num) / num; float num3 = ((float)i + 0.5f - num) / num; float num4 = Mathf.Sqrt(num2 * num2 + num3 * num3); float num5 = Mathf.Atan2(num3, num2); float num6 = Mathf.Pow(Mathf.Abs(Mathf.Cos(2f * num5)), 12f); float num7 = Mathf.Pow(Mathf.Abs(Mathf.Cos(4f * num5)), 20f) * 0.45f; float num8 = Mathf.Clamp01((0.18f + 0.82f * Mathf.Max(num6, num7) - num4) / 0.06f); float num9 = Mathf.Exp((0f - num4) * num4 * 9f) * 0.8f; float num10 = Mathf.Clamp01(num8 + num9); array[i * size + j] = new Color(num10, num10, num10, num10); } } val.SetPixels(array); val.Apply(true); return val; } private static Texture2D MakeDotTexture(int size) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(size, size, (TextureFormat)4, false) { wrapMode = (TextureWrapMode)1 }; Color[] array = (Color[])(object)new Color[size * size]; float num = (float)size * 0.5f; for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { float num2 = Vector2.Distance(new Vector2((float)j + 0.5f, (float)i + 0.5f), new Vector2(num, num)) / num; float num3 = Mathf.Clamp01(1f - num2 * num2); array[i * size + j] = new Color(num3, num3, num3, num3); } } val.SetPixels(array); val.Apply(); return val; } internal static void DestroyAll() { CancelLinger(); if ((Object)(object)_flashGo != (Object)null) { Object.Destroy((Object)(object)_flashGo); } if ((Object)(object)_flashMat != (Object)null) { Object.Destroy((Object)(object)_flashMat); } if ((Object)(object)_sparkMat != (Object)null) { Object.Destroy((Object)(object)_sparkMat); } if ((Object)(object)_starTex != (Object)null) { Object.Destroy((Object)(object)_starTex); } if ((Object)(object)_dotTex != (Object)null) { Object.Destroy((Object)(object)_dotTex); } _flashGo = null; _flashPs = null; _sparkPs = null; _flashMat = null; _sparkMat = null; _starTex = null; _dotTex = null; _armed = false; } } [HarmonyPatch(typeof(PlayerMovement), "LocalPlayerUpdateVisibility")] internal static class LocalPlayerUpdateVisibilityPatch { [HarmonyPriority(200)] private static bool Prefix(PlayerMovement __instance) { if (!KillZone.IsLingering) { return true; } PlayerInfo localPlayerInfo = GameManager.LocalPlayerInfo; if ((Object)(object)localPlayerInfo == (Object)null || __instance.PlayerInfo != localPlayerInfo) { return true; } try { if (__instance.IsVisible) { __instance.NetworkisVisible = false; } } catch { } return false; } } internal static class Launch { private static bool _active; private static bool _cloudHit; private static double _startedAt; internal static bool Active => _active; internal static bool IsCloudHit { get { if (_active) { return _cloudHit; } return false; } } internal static void Begin() { _active = true; _cloudHit = ShieldState.Percent >= Plugin.CloudHitMinPercent.Value; _startedAt = Time.timeAsDouble; } internal static void Cancel() { _active = false; } internal static void Tick(PlayerMovement mv, Rigidbody rb) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Invalid comparison between Unknown and I4 if (_active) { double timeAsDouble = Time.timeAsDouble; if (mv.IsRespawningOrDrowning || KillZone.IsLingering || timeAsDouble - _startedAt > 12.0) { End("cancelled"); } else if ((mv.IsGrounded || (int)mv.KnockoutState == 1) && timeAsDouble - _startedAt > 0.2) { End("landed"); } else if (!mv.IsKnockedOutOrRecovering && timeAsDouble - _startedAt > 0.2) { End("recovered"); } } } private static void End(string how) { _active = false; if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)$"Launch ended ({how}) after {Time.timeAsDouble - _startedAt:0.00}s."); } } } internal static class LaunchVfx { private class Trail { public GameObject Go; public ParticleSystem Ps; public ParticleSystemRenderer Renderer; public Material Material; public bool Emitting; public double StartedAt; } private static readonly Dictionary _trails = new Dictionary(); private static readonly List _scratch = new List(); private static readonly List _dead = new List(); private static Texture2D _puffTex; private static Shader _shader; private static bool _shaderSearched; internal static Shader FindShader() { if (!_shaderSearched) { _shaderSearched = true; _shader = Shader.Find("Universal Render Pipeline/Particles/Unlit") ?? Shader.Find("Universal Render Pipeline/Unlit") ?? Shader.Find("Sprites/Default"); if ((Object)(object)_shader != (Object)null) { Plugin.Log.LogInfo((object)("Trail shader: " + ((Object)_shader).name)); } else { Plugin.Log.LogWarning((object)"No shader for the launch trail / kill flash."); } } return _shader; } internal static Material MakeUnlitMaterial(Texture2D tex, bool additive) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) Shader val = FindShader(); if ((Object)(object)val == (Object)null) { return null; } Material val2 = new Material(val); if (val2.HasProperty("_Surface")) { val2.SetFloat("_Surface", 1f); } if (val2.HasProperty("_Blend")) { val2.SetFloat("_Blend", additive ? 2f : 0f); } if (val2.HasProperty("_SrcBlend")) { val2.SetInt("_SrcBlend", additive ? 1 : 5); } if (val2.HasProperty("_DstBlend")) { val2.SetInt("_DstBlend", additive ? 1 : 10); } if (val2.HasProperty("_ZWrite")) { val2.SetInt("_ZWrite", 0); } if (val2.HasProperty("_ColorMode")) { val2.SetFloat("_ColorMode", additive ? 1f : 0f); } val2.SetOverrideTag("RenderType", "Transparent"); val2.EnableKeyword("_SURFACE_TYPE_TRANSPARENT"); val2.DisableKeyword("_ALPHATEST_ON"); val2.renderQueue = 3000; if (val2.HasProperty("_BaseMap")) { val2.SetTexture("_BaseMap", (Texture)(object)tex); } else { val2.mainTexture = (Texture)(object)tex; } if (val2.HasProperty("_BaseColor")) { val2.SetColor("_BaseColor", Color.white); } else { val2.color = Color.white; } return val2; } internal static void Tick() { //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.LaunchTrail.Value) { if (_trails.Count > 0) { StopAll(); } return; } _scratch.Clear(); PlayerInfo localPlayerInfo = GameManager.LocalPlayerInfo; if ((Object)(object)localPlayerInfo != (Object)null) { _scratch.Add(localPlayerInfo); } try { List remotePlayers = GameManager.RemotePlayers; if (remotePlayers != null) { _scratch.AddRange(remotePlayers); } } catch { } _dead.Clear(); foreach (KeyValuePair trail in _trails) { if ((Object)(object)trail.Key == (Object)null || !_scratch.Contains(trail.Key)) { _dead.Add(trail.Key); } } foreach (PlayerInfo item in _dead) { Destroy(_trails[item]); _trails.Remove(item); } double timeAsDouble = Time.timeAsDouble; foreach (PlayerInfo item2 in _scratch) { if ((Object)(object)item2 == (Object)null) { continue; } bool flag = false; float num = 0f; try { PlayerMovement movement = item2.Movement; flag = (Object)(object)movement != (Object)null && movement.IsKnockedOutOrRecovering && !movement.IsGrounded; float num2; if (!((Object)(object)movement != (Object)null)) { num2 = 0f; } else { Vector3 velocity = movement.Velocity; num2 = ((Vector3)(ref velocity)).magnitude; } num = num2; } catch { } bool flag2 = item2 != localPlayerInfo || ShieldState.Percent >= Plugin.LaunchTrailMinPercent.Value || KillZone.IsArmed; _trails.TryGetValue(item2, out var value); if (value == null || !value.Emitting) { if (!(flag && flag2) || !(num >= Plugin.LaunchTrailStartSpeed.Value)) { continue; } if (value == null) { value = Create(item2); if (value == null) { continue; } _trails[item2] = value; } Start(value, item2); value.StartedAt = timeAsDouble; } else { Transform val = (((Object)(object)item2.ChestBone != (Object)null) ? item2.ChestBone : ((Component)item2).transform); value.Go.transform.position = val.position; if ((!flag || !(num >= Plugin.LaunchTrailStopSpeed.Value)) && timeAsDouble - value.StartedAt > 0.15) { Stop(value); } } } } private static Trail Create(PlayerInfo p) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Expected O, but got Unknown //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)_puffTex == (Object)null) { _puffTex = MakePuffTexture(64); } if ((Object)(object)FindShader() == (Object)null) { return null; } GameObject val = new GameObject("SbgLaunchTrail"); val.transform.SetParent((Transform)null, false); ParticleSystem val2 = val.AddComponent(); val2.Stop(true, (ParticleSystemStopBehavior)0); MainModule main = val2.main; ((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1; ((MainModule)(ref main)).loop = true; ((MainModule)(ref main)).playOnAwake = false; ((MainModule)(ref main)).startSpeed = new MinMaxCurve(0.3f, 0.9f); ((MainModule)(ref main)).startRotation = new MinMaxCurve(0f, MathF.PI * 2f); ((MainModule)(ref main)).gravityModifier = MinMaxCurve.op_Implicit(-0.03f); ((MainModule)(ref main)).maxParticles = 800; EmissionModule emission = val2.emission; ((EmissionModule)(ref emission)).enabled = true; ShapeModule shape = val2.shape; ((ShapeModule)(ref shape)).enabled = true; ((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)0; ((ShapeModule)(ref shape)).radius = 0.45f; SizeOverLifetimeModule sizeOverLifetime = val2.sizeOverLifetime; ((SizeOverLifetimeModule)(ref sizeOverLifetime)).enabled = true; AnimationCurve val3 = new AnimationCurve((Keyframe[])(object)new Keyframe[3] { new Keyframe(0f, 0.45f), new Keyframe(0.25f, 0.9f), new Keyframe(1f, 1.25f) }); ((SizeOverLifetimeModule)(ref sizeOverLifetime)).size = new MinMaxCurve(1f, val3); ColorOverLifetimeModule colorOverLifetime = val2.colorOverLifetime; ((ColorOverLifetimeModule)(ref colorOverLifetime)).enabled = true; RotationOverLifetimeModule rotationOverLifetime = val2.rotationOverLifetime; ((RotationOverLifetimeModule)(ref rotationOverLifetime)).enabled = true; ((RotationOverLifetimeModule)(ref rotationOverLifetime)).z = new MinMaxCurve(-0.4f, 0.4f); ParticleSystemRenderer component = val.GetComponent(); Material val4 = MakeUnlitMaterial(_puffTex, additive: false); if ((Object)(object)val4 == (Object)null) { Object.Destroy((Object)(object)val); return null; } ((Renderer)component).sharedMaterial = val4; component.renderMode = (ParticleSystemRenderMode)0; component.sortMode = (ParticleSystemSortMode)1; ((Renderer)component).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)component).receiveShadows = false; return new Trail { Go = val, Ps = val2, Renderer = component, Material = val4 }; } catch (Exception ex) { Plugin.Log.LogWarning((object)("Launch trail create failed: " + ex.Message)); return null; } } private static void Start(Trail t, PlayerInfo p) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: 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_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Expected O, but got Unknown //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) Color val = Skin.Of(p); Color val2 = Color.Lerp(val, Color.white, 0.5f); float num = Mathf.Clamp01(Plugin.LaunchTrailAlpha.Value); MainModule main = t.Ps.main; float value = Plugin.LaunchTrailLifetime.Value; ((MainModule)(ref main)).startLifetime = new MinMaxCurve(value * 0.75f, value); ((MainModule)(ref main)).startSize = new MinMaxCurve(Plugin.LaunchTrailSize.Value * 0.7f, Plugin.LaunchTrailSize.Value); ((MainModule)(ref main)).startColor = new MinMaxGradient(new Color(val2.r, val2.g, val2.b, num), new Color(val.r, val.g, val.b, num)); EmissionModule emission = t.Ps.emission; ((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(Plugin.LaunchTrailRate.Value); ((EmissionModule)(ref emission)).rateOverDistance = MinMaxCurve.op_Implicit(Plugin.LaunchTrailRatePerMetre.Value); Gradient val3 = new Gradient(); val3.SetKeys((GradientColorKey[])(object)new GradientColorKey[3] { new GradientColorKey(val2, 0f), new GradientColorKey(val, 0.45f), new GradientColorKey(val * 0.85f, 1f) }, (GradientAlphaKey[])(object)new GradientAlphaKey[4] { new GradientAlphaKey(1f, 0f), new GradientAlphaKey(0.9f, 0.55f), new GradientAlphaKey(0.35f, 0.85f), new GradientAlphaKey(0f, 1f) }); ColorOverLifetimeModule colorOverLifetime = t.Ps.colorOverLifetime; ((ColorOverLifetimeModule)(ref colorOverLifetime)).color = new MinMaxGradient(val3); Transform val4 = (((Object)(object)p.ChestBone != (Object)null) ? p.ChestBone : ((Component)p).transform); t.Go.transform.position = val4.position; t.Go.SetActive(true); t.Ps.Play(true); t.Emitting = true; } private static void Stop(Trail t) { if (t == null || !t.Emitting) { return; } t.Emitting = false; try { t.Ps.Stop(true, (ParticleSystemStopBehavior)1); } catch { } } private static void Destroy(Trail t) { if (t != null) { if ((Object)(object)t.Material != (Object)null) { Object.Destroy((Object)(object)t.Material); } if ((Object)(object)t.Go != (Object)null) { Object.Destroy((Object)(object)t.Go); } } } internal static void StopAll() { foreach (KeyValuePair trail in _trails) { Destroy(trail.Value); } _trails.Clear(); } internal static void DestroyAll() { StopAll(); if ((Object)(object)_puffTex != (Object)null) { Object.Destroy((Object)(object)_puffTex); _puffTex = null; } _shader = null; _shaderSearched = false; } private static Texture2D MakePuffTexture(int size) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(size, size, (TextureFormat)4, true) { wrapMode = (TextureWrapMode)1, filterMode = (FilterMode)1 }; Color[] array = (Color[])(object)new Color[size * size]; float num = (float)size * 0.5f; for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { float num2 = ((float)j + 0.5f - num) / num; float num3 = ((float)i + 0.5f - num) / num; float num4 = Mathf.Sqrt(num2 * num2 + num3 * num3); float num5 = Mathf.Atan2(num3, num2); float num6 = 0.1f * Mathf.Sin(num5 * 5f) + 0.07f * Mathf.Sin(num5 * 3f + 1.3f) + 0.04f * Mathf.Sin(num5 * 8f + 0.4f); float num7 = 0.9f + num6; float num8 = Mathf.Clamp01((num7 - num4) / (num7 * 0.55f)); num8 = num8 * num8 * (3f - 2f * num8); array[i * size + j] = new Color(1f, 1f, 1f, num8); } } val.SetPixels(array); val.Apply(true); return val; } } internal static class ModHandshake { private class Peer { public string Version; public double FirstSeen; public bool Announced; public bool Warned; } internal const string Token = "SBGSHIELDS"; private static readonly Dictionary _peers = new Dictionary(); private static readonly List _scratch = new List(); private static readonly HashSet _present = new HashSet(); private static readonly List _gone = new List(); private static readonly List _forget = new List(); private const double MinAnnounceInterval = 3.0; private static double _lastAnnounce = double.MinValue; private static double _nextAnnounceDue = double.MaxValue; private static bool _announcePending = true; private static bool _gateOpen; private static bool _evaluatedOnce; private static string _blockReason; internal static bool GameplayEnabled => _gateOpen; internal static string BlockReason => _blockReason; internal static double BlockedSince { get; private set; } = double.MinValue; internal static void Reset(string why) { _forget.Clear(); foreach (KeyValuePair peer in _peers) { if (!peer.Value.Announced) { _forget.Add(peer.Key); } } foreach (ulong item in _forget) { _peers.Remove(item); } _gateOpen = false; _evaluatedOnce = false; _blockReason = null; _announcePending = true; _nextAnnounceDue = Time.timeAsDouble + 1.5; if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)("Handshake reset (" + why + ").")); } } private static bool Announce() { double timeAsDouble = Time.timeAsDouble; if (timeAsDouble - _lastAnnounce < 3.0) { return false; } string text = "SBGSHIELDS/0.7.7"; if (!ChatBypass.Send(text)) { return false; } _lastAnnounce = timeAsDouble; if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)("Handshake announced: " + text)); } return true; } internal static bool TryConsume(string message, PlayerInfo sender) { if (message == null || (Object)(object)sender == (Object)null) { return false; } if (!message.StartsWith("SBGSHIELDS/", StringComparison.Ordinal)) { return false; } string text = message.Substring("SBGSHIELDS".Length + 1).Trim(); if (sender == GameManager.LocalPlayerInfo) { return true; } ulong num = GuidOf(sender); if (num == 0L) { return true; } Peer value; bool num2 = !_peers.TryGetValue(num, out value) || !value.Announced; if (value == null) { value = new Peer { FirstSeen = Time.timeAsDouble }; _peers[num] = value; } value.Version = text; value.Announced = true; Plugin.Log.LogInfo((object)(NameOf(sender) + " is running SBG Shields " + text + ".")); if (num2) { _announcePending = true; _nextAnnounceDue = Time.timeAsDouble + (double)Random.Range(0.3f, 1.2f); } Evaluate(); return true; } internal static void Tick() { if (!LobbyAllowed(out var why)) { _announcePending = false; SetGate(open: false, why); return; } if (!Plugin.RequireAllPlayersModded.Value) { SetGate(open: true, null); return; } double timeAsDouble = Time.timeAsDouble; if (_announcePending && timeAsDouble >= _nextAnnounceDue) { if (Announce()) { _announcePending = false; } else { _nextAnnounceDue = timeAsDouble + 1.0; } } _scratch.Clear(); try { List remotePlayers = GameManager.RemotePlayers; if (remotePlayers != null) { _scratch.AddRange(remotePlayers); } } catch { } foreach (PlayerInfo item in _scratch) { ulong num = GuidOf(item); if (num != 0L && !_peers.TryGetValue(num, out var _)) { _peers[num] = new Peer { FirstSeen = timeAsDouble }; _announcePending = true; _nextAnnounceDue = timeAsDouble + (double)Random.Range(0.3f, 1.2f); if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)$"Handshake: new player {num}, will announce."); } } } _present.Clear(); foreach (PlayerInfo item2 in _scratch) { ulong num2 = GuidOf(item2); if (num2 != 0L) { _present.Add(num2); } } _gone.Clear(); foreach (KeyValuePair peer in _peers) { if (!_present.Contains(peer.Key)) { _gone.Add(peer.Key); } } foreach (ulong item3 in _gone) { _peers.Remove(item3); if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)$"Handshake: forgetting departed player {item3}."); } } Evaluate(); } internal static LobbyMode CurrentLobbyMode() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) try { if (SingletonNetworkBehaviour.HasInstance) { MatchSetupMenu instance = SingletonNetworkBehaviour.Instance; if ((Object)(object)instance != (Object)null) { return instance.lobbyMode; } } return BNetworkManager.LobbyMode; } catch { return (LobbyMode)0; } } private static bool LobbyAllowed(out string why) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) why = null; if ((int)CurrentLobbyMode() != 0) { return true; } why = "this is a public lobby"; return false; } private static void Evaluate() { double timeAsDouble = Time.timeAsDouble; float num = Mathf.Max(2f, Plugin.HandshakeTimeout.Value); _scratch.Clear(); try { List remotePlayers = GameManager.RemotePlayers; if (remotePlayers != null) { _scratch.AddRange(remotePlayers); } } catch { } if (!LobbyAllowed(out var why)) { SetGate(open: false, why); return; } foreach (PlayerInfo item in _scratch) { ulong num2 = GuidOf(item); if (num2 == 0L || !_peers.TryGetValue(num2, out var value)) { continue; } if (value.Announced) { if (value.Version != "0.7.7") { why = NameOf(item) + " is on SBG Shields " + value.Version + ", you are on 0.7.7"; if (!value.Warned) { value.Warned = true; Plugin.Log.LogWarning((object)("Version mismatch: " + why)); } break; } } else if (timeAsDouble - value.FirstSeen > (double)num) { why = NameOf(item) + " does not have SBG Shields installed"; if (!value.Warned) { value.Warned = true; Plugin.Log.LogWarning((object)(why + "; the mod is standing down.")); } break; } } SetGate(why == null, why); } private static void SetGate(bool open, string problem) { if (open != _gateOpen || !_evaluatedOnce) { _gateOpen = open; if (!open) { BlockedSince = Time.timeAsDouble; } Plugin.Log.LogWarning((object)(open ? "SBG Shields is active." : ("SBG Shields is inactive: " + problem + ". Vanilla rules apply."))); if (!open) { Plugin.ForceReleaseForHandshake(); } } _evaluatedOnce = true; _blockReason = problem; } private static ulong GuidOf(PlayerInfo p) { try { return ((Object)(object)p != (Object)null && (Object)(object)p.PlayerId != (Object)null) ? p.PlayerId.Guid : 0; } catch { return 0uL; } } private static string NameOf(PlayerInfo p) { try { return p.PlayerId.PlayerNameNoRichText; } catch { return "A player"; } } } internal static class ChatBypass { private static MethodInfo _cmd; private static bool _looked; internal static bool Send(string message) { try { if (!SingletonNetworkBehaviour.HasInstance) { return false; } TextChatManager instance = SingletonNetworkBehaviour.Instance; if ((Object)(object)instance == (Object)null) { return false; } if (!_looked) { _looked = true; _cmd = AccessTools.Method(typeof(TextChatManager), "CmdSendMessageInternal", new Type[2] { typeof(string), typeof(NetworkConnectionToClient) }, (Type[])null); if (_cmd == null) { Plugin.Log.LogWarning((object)"Chat command not found; falling back to the normal send path."); } } if (_cmd != null) { _cmd.Invoke(instance, new object[2] { message, null }); return true; } TextChatManager.SendChatMessage(message); return true; } catch (Exception ex) { Plugin.Log.LogWarning((object)("Handshake send failed: " + ex.Message)); return false; } } } [HarmonyPatch(typeof(TextChatManager), "UserCode_RpcMessage__String__PlayerInfo")] internal static class ChatHandshakePatch { [HarmonyPriority(200)] private static bool Prefix(string message, PlayerInfo sender) { try { return !ModHandshake.TryConsume(message, sender); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Handshake receive failed: " + ex.Message)); return true; } } } internal static class Local { internal static bool Is(PlayerInfo p) { if ((Object)(object)p != (Object)null) { return p == GameManager.LocalPlayerInfo; } return false; } internal static bool IsRooted(PlayerInfo p) { if (Is(p) && p.IsElectromagnetShieldActive) { return Plugin.WeActivated; } return false; } } [HarmonyPatch(typeof(PlayerMovement), "CanMove")] internal static class RootMovementPatch { private static void Postfix(PlayerMovement __instance, ref bool __result) { if (__result && Plugin.RootWhileShielded.Value && Local.IsRooted(__instance.PlayerInfo)) { __result = false; } } } [HarmonyPatch(typeof(PlayerMovement), "CanJump")] internal static class RootJumpPatch { private static void Postfix(PlayerMovement __instance, ref bool __result) { if (__result && Plugin.BlockJumpWhileShielded.Value && Local.IsRooted(__instance.PlayerInfo)) { __result = false; } } } [HarmonyPatch(typeof(PlayerMovement), "TryDive")] internal static class RootDivePatch { [HarmonyPriority(200)] private static bool Prefix(PlayerMovement __instance, ref bool __result) { if (Plugin.BlockDiveWhileShielded.Value && Local.IsRooted(__instance.PlayerInfo)) { __result = false; return false; } return true; } } [HarmonyPatch(typeof(PlayerGolfer), "TryStartChargingSwing")] internal static class RootSwingPatch { [HarmonyPriority(200)] private static bool Prefix(PlayerGolfer __instance, ref bool __result) { if (Plugin.BlockSwingWhileShielded.Value && Local.IsRooted(__instance.PlayerInfo)) { __result = false; return false; } return true; } } [HarmonyPatch(typeof(PlayerMovement), "TryKnockOut")] internal static class KnockoutEconomyPatch { [HarmonyPriority(200)] private static bool Prefix(PlayerMovement __instance, KnockoutType knockoutType, Vector3 localOrigin, float distance, Vector3 incomingVelocityChange, ref bool __result, ref bool isNewKnockout, ref bool blockedByTeamProtection, out bool __state) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) __state = false; if (!Local.Is(__instance.PlayerInfo)) { return true; } __state = true; ShieldState.PendingHitDistance = distance; ShieldState.PendingHitLocalOrigin = localOrigin; if (!ShieldState.ResolveKnockout(__instance.PlayerInfo, knockoutType, incomingVelocityChange)) { __result = false; isNewKnockout = false; blockedByTeamProtection = false; return false; } return true; } private static void Postfix(bool __result, bool __state) { if (__state) { ShieldState.OnKnockoutResolved(__result); } } } [HarmonyPatch(typeof(PlayerMovement), "OnLocalPlayerWillApplySwingProjectileHitPhysics")] internal static class ProjectileTargetingPatch { private static void Prefix(PlayerMovement __instance, Hittable hitter) { if (!Local.Is(__instance.PlayerInfo)) { return; } try { Hittable val = (((Object)(object)hitter != (Object)null) ? hitter.NetworkhomingTargetHittable : null); ShieldState.PendingProjectileWasTargeted = (Object)(object)val != (Object)null && val == __instance.PlayerInfo.AsHittable; } catch { ShieldState.PendingProjectileWasTargeted = false; } } } [HarmonyPatch(typeof(PlayerMovement), "SetKnockOutState")] internal static class HitstunPatch { private static FieldRef _timeUntilRecovery; private static bool _loggedTimeouts; private static bool Prepare() { try { _timeUntilRecovery = AccessTools.FieldRefAccess("timeUntilKnockoutRecovery"); return true; } catch (Exception ex) { Plugin.Log.LogWarning((object)("timeUntilKnockoutRecovery not found; hitstun scaling disabled. " + ex.Message)); return false; } } private static void Prefix(PlayerMovement __instance, out bool __state) { __state = __instance.IsKnockedOutOrRecovering; } private static void Postfix(PlayerMovement __instance, KnockoutState state, bool __state) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 if ((int)state != 2 || !Local.Is(__instance.PlayerInfo) || __state || !__instance.IsKnockedOutOrRecovering) { return; } ref float reference = ref _timeUntilRecovery.Invoke(__instance); float num = reference; if (!_loggedTimeouts) { _loggedTimeouts = true; try { PlayerMovementSettings playerMovementSettings = GameManager.PlayerMovementSettings; Plugin.Log.LogInfo((object)$"Game knockout constants: KnockoutDuration={playerMovementSettings.KnockoutDuration:0.00}s, KnockoutTimeOutDuration={playerMovementSettings.KnockoutTimeOutDuration:0.00}s, LongImmunity={playerMovementSettings.PostKnockoutImmunityLongDuration:0.00}s"); } catch { } } if (ShieldState.PendingHitstunAbsolute >= 0f) { reference = ShieldState.PendingHitstunAbsolute; ShieldState.BreakStunUntil = Time.timeAsDouble + (double)reference; ShieldState.LastKnockoutWasBreakStun = true; BreakTrace.Log($"stun applied: timer={reference:0.00}s, hold until +{reference:0.00}s"); } else { ShieldState.BreakStunUntil = double.MinValue; ShieldState.LastKnockoutWasBreakStun = false; if (ShieldState.PendingHitstunMultiplier >= 0f) { reference *= ShieldState.PendingHitstunMultiplier; } else { reference *= ShieldState.HitstunMultiplier; } } ShieldState.PendingHitstunAbsolute = -1f; ShieldState.PendingHitstunMultiplier = -1f; if (Plugin.VerboseLogging.Value && Mathf.Abs(num - reference) > 0.01f) { Plugin.Log.LogInfo((object)$"Hitstun {num:0.00}s -> {reference:0.00}s"); } } } internal static class BreakTrace { private static double _start = double.MinValue; private static double _until = double.MinValue; internal static bool Active => Time.timeAsDouble < _until; internal static void Begin(float seconds) { _start = Time.timeAsDouble; _until = _start + (double)seconds + 1.5; } internal static void Log(string what) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) if (Active) { PlayerMovement val = (((Object)(object)GameManager.LocalPlayerInfo != (Object)null) ? GameManager.LocalPlayerInfo.Movement : null); string text = (((Object)(object)val != (Object)null) ? ((object)val.KnockoutState/*cast due to .constrained prefix*/).ToString() : "?"); double num = ShieldState.BreakStunUntil - Time.timeAsDouble; string text2 = ((ShieldState.BreakStunUntil == double.MinValue) ? "none" : num.ToString("0.00")); Plugin.Log.LogInfo((object)$"[break +{Time.timeAsDouble - _start:0.00}s] {what} | state={text} holdLeft={text2}"); } } } [HarmonyPatch(typeof(PlayerMovement), "SetKnockOutState")] internal static class KnockoutStateTracePatch { private static void Prefix(PlayerMovement __instance, KnockoutState state) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) if (BreakTrace.Active && Local.Is(__instance.PlayerInfo) && state != __instance.KnockoutState) { BreakTrace.Log($"SetKnockOutState {__instance.KnockoutState} -> {state}"); } } } [HarmonyPatch(typeof(PlayerMovement), "StartKnockoutImmunity")] internal static class ImmunityTracePatch { private static void Prefix(PlayerMovement __instance, bool fromPlayerAggression) { if (BreakTrace.Active && Local.Is(__instance.PlayerInfo)) { BreakTrace.Log($"StartKnockoutImmunity(fromPlayerAggression={fromPlayerAggression})"); } } } [HarmonyPatch(typeof(PlayerMovement), "CanBeKnockedOutBy")] internal static class CanBeKnockedOutTracePatch { private static void Postfix(PlayerMovement __instance, bool __result, bool suppressKnockoutImmunity, bool blockedByTeamProtection) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) if (BreakTrace.Active && Local.Is(__instance.PlayerInfo)) { BreakTrace.Log($"CanBeKnockedOutBy -> {__result} (immunitySuppressed={suppressKnockoutImmunity}, team={blockedByTeamProtection}, hasImmunity={__instance.KnockoutImmunityStatus.hasImmunity}, shieldActive={__instance.PlayerInfo.IsElectromagnetShieldActive})"); } } } [HarmonyPatch(typeof(PlayerMovement), "RecoverFromKnockout")] internal static class BreakStunHoldPatch { private static double _lastLog = double.MinValue; [HarmonyPriority(200)] private static bool Prefix(PlayerMovement __instance) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Invalid comparison between Unknown and I4 if (!Local.Is(__instance.PlayerInfo)) { return true; } double timeAsDouble = Time.timeAsDouble; if (timeAsDouble >= ShieldState.BreakStunUntil) { BreakTrace.Log("RecoverFromKnockout allowed (hold expired)"); return true; } if (!__instance.IsKnockedOut) { BreakTrace.Log("RecoverFromKnockout allowed (not knocked out)"); return true; } try { if ((int)__instance.PlayerInfo.AsHittable.FrozenState == 2) { return true; } } catch { } if (__instance.IsRespawningOrDrowning) { return true; } if (timeAsDouble - _lastLog > 0.5) { _lastLog = timeAsDouble; BreakTrace.Log("RecoverFromKnockout BLOCKED by hold"); } return false; } } [HarmonyPatch(typeof(PlayerMovement), "StartKnockoutImmunity")] internal static class BreakImmunityPatch { private static FieldRef _routine; private static FieldRef> _recent; private static bool Prepare() { try { _routine = AccessTools.FieldRefAccess("knockoutImmunityRoutine"); _recent = AccessTools.FieldRefAccess>("recentKnockoutImmunityTimestamps"); return true; } catch (Exception ex) { Plugin.Log.LogWarning((object)("Knockout immunity fields not found; break immunity stays vanilla. " + ex.Message)); return false; } } [HarmonyPriority(200)] private static bool Prefix(PlayerMovement __instance, bool fromPlayerAggression) { //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) if (!fromPlayerAggression || !Local.Is(__instance.PlayerInfo)) { return true; } if (!Plugin.BreakImmunityScalesWithPercent.Value) { return true; } if (!ShieldState.ConsumeBreakStunImmunity()) { return true; } float breakImmunityDuration = ShieldState.BreakImmunityDuration; if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)$"Break immunity: {breakImmunityDuration:0.00}s at {ShieldState.Percent:0}%."); } try { _recent.Invoke(__instance)?.Add(Time.timeAsDouble); ref Coroutine reference = ref _routine.Invoke(__instance); if (reference != null) { ((MonoBehaviour)__instance).StopCoroutine(reference); } if (breakImmunityDuration <= 0.05f) { reference = null; __instance.NetworkknockoutImmunityStatus = KnockOutImmunity.Reset(__instance.KnockoutImmunityStatus); return false; } reference = ((MonoBehaviour)__instance).StartCoroutine(Immunity(__instance, breakImmunityDuration)); return false; } catch (Exception ex) { Plugin.Log.LogWarning((object)("Break immunity failed, falling back to vanilla: " + ex.Message)); return true; } } private static IEnumerator Immunity(PlayerMovement m, float duration) { m.NetworkknockoutImmunityStatus = KnockOutImmunity.Get((KnockOutVfxColor)0); while ((Object)(object)m != (Object)null && ((int)m.KnockoutState == 3 || (!m.IsKnockedOutOrRecovering && Time.timeAsDouble - m.IsKnockedOutTimestamp < (double)duration))) { yield return null; } if ((Object)(object)m != (Object)null) { m.NetworkknockoutImmunityStatus = KnockOutImmunity.Reset(m.KnockoutImmunityStatus); } } } [HarmonyPatch(typeof(PlayerMovement), "FixedUpdate")] internal static class VelocityCorrectionPatch { private static FieldRef _rigidbody; private static bool Prepare() { try { _rigidbody = AccessTools.FieldRefAccess("rigidbody"); return true; } catch (Exception ex) { Plugin.Log.LogWarning((object)("rigidbody field not found; knockback scaling disabled. " + ex.Message)); return false; } } private static void Prefix(PlayerMovement __instance) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) if (!Local.Is(__instance.PlayerInfo)) { return; } Rigidbody val = _rigidbody.Invoke(__instance); if ((Object)(object)val == (Object)null || val.isKinematic) { return; } if (ShieldState.HasPendingVelocityCorrection) { ShieldState.HasPendingVelocityCorrection = false; val.linearVelocity += ShieldState.PendingVelocityCorrection; ShieldState.PendingVelocityCorrection = Vector3.zero; } Launch.Tick(__instance, val); if (Time.timeAsDouble < ShieldState.LaunchDragUntil && __instance.IsKnockedOutOrRecovering && !__instance.IsGrounded) { Vector3 linearVelocity = val.linearVelocity; float value = Plugin.LaunchDragAboveSpeed.Value; float num = Plugin.LaunchDrag.Value * Time.fixedDeltaTime; Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(linearVelocity.x, linearVelocity.z); float magnitude = ((Vector2)(ref val2)).magnitude; if (magnitude > value) { float num2 = magnitude - value; num2 *= 1f - Mathf.Clamp01(num); val2 = val2 / magnitude * (value + num2); linearVelocity.x = val2.x; linearVelocity.z = val2.y; } if (linearVelocity.y > value) { float num3 = linearVelocity.y - value; num3 *= 1f - Mathf.Clamp01(num * Plugin.LaunchVerticalDragFactor.Value); linearVelocity.y = value + num3; } val.linearVelocity = linearVelocity; } if (Plugin.LaunchHangTime.Value > 0f && Launch.IsCloudHit && ShieldState.LaunchHangUntil > Time.timeAsDouble && __instance.IsKnockedOutOrRecovering && !__instance.IsGrounded) { Vector3 linearVelocity2 = val.linearVelocity; float num4 = 1f - Mathf.Clamp01(Mathf.Abs(linearVelocity2.y) / Mathf.Max(1f, Plugin.LaunchHangWindow.Value)); if (num4 > 0f) { float num5 = Plugin.LaunchHangTime.Value * num4 * ShieldState.LaunchHangScale; val.linearVelocity = linearVelocity2 - Physics.gravity * num5 * Time.fixedDeltaTime; } } } } [HarmonyPatch(typeof(PlayerInfo), "PlayElectromagnetShieldHitInternal")] internal static class ReflectionChargePatch { private static readonly Collider[] _buffer = (Collider[])(object)new Collider[32]; private static int _mask; private static bool _maskReady; private static int Mask() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) if (_maskReady) { return _mask; } try { LayerSettings layerSettings = GameManager.LayerSettings; _mask = LayerMask.op_Implicit(layerSettings.HittablesMask) | LayerMask.op_Implicit(layerSettings.BallMask) | LayerMask.op_Implicit(layerSettings.DynamicBallMask) | LayerMask.op_Implicit(layerSettings.ProjectileHittablesMask); _maskReady = true; if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)$"Reflection search mask: {_mask:X}"); } } catch (Exception ex) { _mask = -1; _maskReady = true; Plugin.Log.LogWarning((object)("Layer masks unavailable; reflection search will scan all layers. " + ex.Message)); } return _mask; } private static void Postfix(PlayerInfo __instance, bool isExplosion) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) if (isExplosion || !Local.Is(__instance) || !__instance.IsElectromagnetShieldActive || Time.timeAsDouble - ShieldState.LastKnockoutChargeTime < 0.2) { return; } SphereCollider electromagnetShieldCollider = __instance.ElectromagnetShieldCollider; if ((Object)(object)electromagnetShieldCollider == (Object)null) { return; } float num = electromagnetShieldCollider.radius * Mathf.Max(new float[3] { ((Component)electromagnetShieldCollider).transform.lossyScale.x, ((Component)electromagnetShieldCollider).transform.lossyScale.y, ((Component)electromagnetShieldCollider).transform.lossyScale.z }); int num2 = Physics.OverlapSphereNonAlloc(((Component)electromagnetShieldCollider).transform.position, num + Plugin.ReflectionSearchMargin.Value, _buffer, Mask(), (QueryTriggerInteraction)2); int cost = 1; string what = "unknown projectile"; bool flag = false; for (int i = 0; i < num2; i++) { if (flag) { break; } Collider val = _buffer[i]; if ((Object)(object)val == (Object)null) { continue; } if ((Object)(object)((Component)val).GetComponentInParent() != (Object)null) { cost = 1000; what = "rocket"; flag = true; break; } if ((Object)(object)((Component)val).GetComponentInParent() != (Object)null) { cost = 1000; what = "freeze bomb"; flag = true; break; } Hittable componentInParent = ((Component)val).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null && (Object)(object)componentInParent.AsEntity != (Object)null && !componentInParent.AsEntity.IsPlayer && (int)componentInParent.SwingProjectileState != 0) { bool flag2 = false; try { flag2 = (Object)(object)componentInParent.NetworkhomingTargetHittable != (Object)null && componentInParent.NetworkhomingTargetHittable == __instance.AsHittable; } catch { } cost = ((!flag2) ? 1 : 1000); what = (flag2 ? "targeted ball" : "ball"); flag = true; break; } } ShieldState.ChargeReflection(__instance, cost, what); } } [HarmonyPatch(typeof(PlayerMovement), "LocalPlayerBeginRespawn")] internal static class RespawnPercentPatch { private static void Postfix(PlayerMovement __instance) { if (Local.Is(__instance.PlayerInfo)) { ShieldState.OnRespawn(); } } } [HarmonyPatch(/*Could not decode attribute arguments.*/)] internal static class BlockAimWhileShieldedPatch { private static FieldRef _playerInfo; private static bool Prepare() { try { _playerInfo = AccessTools.FieldRefAccess("playerInfo"); return true; } catch (Exception ex) { Plugin.Log.LogWarning((object)("PlayerInput.playerInfo not found; aiming will not be blocked while shielded. " + ex.Message)); return false; } } private static void Prefix(PlayerInput __instance, ref bool value) { if (!value || !Plugin.BlockAimWhileShielded.Value) { return; } try { if (Local.IsRooted(_playerInfo.Invoke(__instance))) { value = false; } } catch { } } } [HarmonyPatch(typeof(PlayerInventory), "TryUseItem")] internal static class BlockItemUseWhileShieldedPatch { [HarmonyPriority(200)] private static bool Prefix(PlayerInventory __instance, ref bool shouldEatInput, ref bool __result) { if (!Plugin.BlockItemUseWhileShielded.Value) { return true; } if (!Local.IsRooted(__instance.PlayerInfo)) { return true; } shouldEatInput = true; __result = false; return false; } } [HarmonyPatch(typeof(PlayerInventory), "TryUseSpringBoots")] internal static class BlockSpringBootsWhileShieldedPatch { [HarmonyPriority(200)] private static bool Prefix(PlayerInventory __instance, ref bool __result) { if (!Plugin.BlockItemUseWhileShielded.Value) { return true; } if (!Local.IsRooted(__instance.PlayerInfo)) { return true; } __result = false; return false; } } [HarmonyPatch(typeof(PlayerMovement), "CanBeKnockedOutBy")] internal static class BreakBypassesImmunityPatch { private static void Prefix(PlayerMovement __instance, ref bool suppressKnockoutImmunity) { if (!suppressKnockoutImmunity && ShieldState.ForcingBreakKnockout && Local.Is(__instance.PlayerInfo)) { suppressKnockoutImmunity = true; if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)"Shield break overriding comeback immunity so the stun actually lands."); } } } } [HarmonyPatch(typeof(PlayerAudio), "SetElectromagnetShieldActiveLocalOnly")] internal static class SuppressShieldAudioPatch { private static FieldRef _muffle; private static FieldRef _hum; private static bool Prepare() { try { _muffle = AccessTools.FieldRefAccess("electromagnetShieldMuffleSnapshotInstance"); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Muffle field not found; muffle will still play. " + ex.Message)); } try { _hum = AccessTools.FieldRefAccess("electromagnetShieldHumInstance"); } catch (Exception ex2) { Plugin.Log.LogWarning((object)("Hum field not found; hum will still play. " + ex2.Message)); } if (_muffle == null) { return _hum != null; } return true; } private static void Postfix(PlayerAudio __instance, bool isActive) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) if (!isActive || !Plugin.WeActivated) { return; } if (Plugin.SuppressMuffle.Value && _muffle != null) { ref EventInstance reference = ref _muffle.Invoke(__instance); if (((EventInstance)(ref reference)).isValid()) { ((EventInstance)(ref reference)).stop((STOP_MODE)1); } } if (Plugin.SuppressHum.Value && _hum != null) { ref EventInstance reference2 = ref _hum.Invoke(__instance); if (((EventInstance)(ref reference2)).isValid()) { ((EventInstance)(ref reference2)).stop((STOP_MODE)1); } } } } [BepInPlugin("com.sbg.shields", "SBG Shields", "0.7.7")] public class Plugin : BaseUnityPlugin { public const string Guid = "com.sbg.shields"; public const string Name = "SBG Shields"; public const string Version = "0.7.7"; internal static ManualLogSource Log; internal static ConfigEntry SuppressMuffle; internal static ConfigEntry SuppressHum; internal static ConfigEntry ActivationCooldown; internal static ConfigEntry ShieldAbsorbsHits; internal static ConfigEntry MaxPips; internal static ConfigEntry UseCooldown; internal static ConfigEntry BreakCooldown; internal static ConfigEntry RestoreAfterBreakCooldown; internal static ConfigEntry BreakStunDuration; internal static ConfigEntry BreakStunScalesWithPercent; internal static ConfigEntry BreakStunDurationAtMax; internal static ConfigEntry PartialBreakLaunches; internal static ConfigEntry RefundPipsOnRefusedKnockout; internal static ConfigEntry BreakImmunityScalesWithPercent; internal static ConfigEntry BreakImmunityAtZeroPercent; internal static ConfigEntry BreakImmunityAtMaxPercent; internal static ConfigEntry AbsorbedHitsCancelKnockback; internal static ConfigEntry ReflectionSearchMargin; internal static ConfigEntry CostOverrides; internal static ConfigEntry MaxPercent; internal static ConfigEntry PerfectParry; internal static ConfigEntry PerfectParryWindow; internal static ConfigEntry PerfectParryBeatsFullBreak; internal static ConfigEntry PerfectParryBeatsUnblockable; internal static ConfigEntry PerfectParryRefundsUse; internal static ConfigEntry PerfectParrySound; internal static ConfigEntry ParryLinger; internal static ConfigEntry ParryGlow; internal static ConfigEntry ParryGlowDuration; internal static ConfigEntry ParryGlowBoost; internal static ConfigEntry PercentForMaxScaling; internal static ConfigEntry ForceMultiplierAtKill; internal static ConfigEntry KnockbackExponent; internal static ConfigEntry HitstunMultiplierAtMax; internal static ConfigEntry PercentPerHitBase; internal static ConfigEntry PercentPerPip; internal static ConfigEntry PercentPerFullBreakHit; internal static ConfigEntry PercentPerUnblockableHit; internal static ConfigEntry ExplosionPercentFalloff; internal static ConfigEntry ExplosionFalloffRadius; internal static ConfigEntry ExplosionPercentAtEdge; internal static ConfigEntry ExplosionForceAtEdge; internal static ConfigEntry ExplosionRadialLaunch; internal static ConfigEntry ExplosionRadialWeight; internal static ConfigEntry PercentGainOnFullBreak; internal static ConfigEntry PercentReductionBetweenHoles; internal static ConfigEntry PercentLostOnRespawn; internal static ConfigEntry RespawnFatigueWindow; internal static ConfigEntry KillZoneEnabled; internal static ConfigEntry KillPercent; internal static ConfigEntry PercentAfterKillZoneDeath; internal static ConfigEntry KillZoneFlash; internal static ConfigEntry KillZoneFlashSize; internal static ConfigEntry KillZoneUpwardBoost; internal static ConfigEntry KillZoneMaxRiseTime; internal static ConfigEntry KillZoneDeathLinger; internal static ConfigEntry KillZoneBoom; internal static ConfigEntry ShapeLaunches; internal static ConfigEntry MinLaunchAngleAtZero; internal static ConfigEntry MinLaunchAngleAtMax; internal static ConfigEntry MaxHorizontalLaunchSpeed; internal static ConfigEntry HorizontalMultiplierAtKill; internal static ConfigEntry LaunchDrag; internal static ConfigEntry LaunchVerticalDragFactor; internal static ConfigEntry LaunchDragDuration; internal static ConfigEntry LaunchDragAboveSpeed; internal static ConfigEntry LaunchHangTime; internal static ConfigEntry LaunchHangWindow; internal static ConfigEntry LaunchHangDuration; internal static ConfigEntry CloudHitMinPercent; internal static ConfigEntry LaunchTrail; internal static ConfigEntry LaunchTrailStartSpeed; internal static ConfigEntry LaunchTrailMinPercent; internal static ConfigEntry LaunchTrailStopSpeed; internal static ConfigEntry LaunchTrailRate; internal static ConfigEntry LaunchTrailRatePerMetre; internal static ConfigEntry LaunchTrailSize; internal static ConfigEntry LaunchTrailLifetime; internal static ConfigEntry LaunchTrailAlpha; internal static ConfigEntry RootWhileShielded; internal static ConfigEntry BlockJumpWhileShielded; internal static ConfigEntry BlockSwingWhileShielded; internal static ConfigEntry BlockDiveWhileShielded; internal static ConfigEntry AllowMidAirActivation; internal static ConfigEntry BlockActivationDuringSwing; internal static ConfigEntry BlockActivationDuringSpringBoots; internal static ConfigEntry BlockActivationInMenus; internal static ConfigEntry BlockActivationDuringImmunity; internal static ConfigEntry BlockItemUseWhileShielded; internal static ConfigEntry BlockAimWhileShielded; internal static ConfigEntry BreakStunIgnoresComebackImmunity; internal static ConfigEntry RequireAllPlayersModded; internal static ConfigEntry HandshakeTimeout; internal const bool PrivateLobbiesOnly = true; internal static ConfigEntry MismatchPopupDuration; internal static ConfigEntry TintVanillaShield; internal static ConfigEntry ShowHud; internal static ConfigEntry HudScale; internal static ConfigEntry HudBottomMargin; internal static ConfigEntry HudHorizontalOffset; internal static ConfigEntry BubbleHudSize; internal static ConfigEntry BubbleHudGap; internal static ConfigEntry BubbleHudOnLeft; internal static ConfigEntry ShowPipDots; internal static ConfigEntry ConfigVersion; internal static ConfigEntry PercentFontName; internal static ConfigEntry PercentFontSize; internal static ConfigEntry PercentShakeDuration; internal static ConfigEntry PercentShakePixels; internal static ConfigEntry PercentShakeDurationTable; internal static ConfigEntry PercentShakeSpeed; internal static ConfigEntry PercentBlurSamples; internal static ConfigEntry PercentBlurLength; internal static ConfigEntry PercentShakePunch; internal static ConfigEntry PercentVerticalOffset; internal static ConfigEntry VerboseLogging; private Harmony _harmony; private static Plugin _instance; private static FieldRef _activationTimestamp; private static double _lastActivationTime = double.MinValue; private static bool _weActivated; internal static double LastOurShieldReleaseTime = double.MinValue; private static double _lingerUntil = double.MinValue; private static readonly string[] RetunedThisVersion = new string[18] { "Percent.PercentGainOnFullBreak", "Percent.PercentReductionBetweenHoles", "Percent.PercentAfterKillZoneDeath", "Percent.KillZoneDeathLinger", "HUD.PercentShakeDuration", "HUD.PercentShakePixels", "HUD.PercentShakePunch", "Debug.VerboseLogging", "HUD.PercentShakeDuration", "HUD.PercentShakePixels", "HUD.PercentShakePunch", "HUD.PercentShakeSpeed", "Launch.LaunchDrag", "Percent.PercentForMaxScaling", "Launch.LaunchHangTime", "Percent.HitstunMultiplierAtMax", "Launch.MaxHorizontalLaunchSpeed", "Launch.HorizontalMultiplierAtKill" }; internal static bool WeActivated => _weActivated; internal static double LastActivationTime => _lastActivationTime; internal static bool ShieldLingering => Time.timeAsDouble < _lingerUntil; internal static void RunCoroutine(IEnumerator routine) { if ((Object)(object)_instance != (Object)null && routine != null) { ((MonoBehaviour)_instance).StartCoroutine(routine); } } private void Awake() { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; BindConfig(); ResetConfigIfVersionChanged(); try { _activationTimestamp = AccessTools.FieldRefAccess("localPlayerElectromagnetShieldActivationTimestamp"); } catch (Exception ex) { Log.LogError((object)("Could not bind the shield activation timestamp field. The game probably updated and renamed it. " + ex)); return; } _instance = this; _harmony = new Harmony("com.sbg.shields"); _harmony.PatchAll(); ShieldState.Pips = MaxPips.Value; Hud.Init(); ModHandshake.Reset("startup"); try { CourseManager.MatchStateChanged += OnMatchStateChanged; } catch (Exception ex2) { Log.LogWarning((object)("Could not subscribe to MatchStateChanged; pips will not reset per hole. " + ex2.Message)); } Log.LogInfo((object)string.Format("{0} {1} loaded ({2}). Hold Left Shift to shield. Pips={3}, break cooldown={4}s.", "SBG Shields", "0.7.7", "RELEASE build: no debug tooling", MaxPips.Value, BreakCooldown.Value)); } private void BindConfig() { SuppressMuffle = ((BaseUnityPlugin)this).Config.Bind("Audio", "SuppressMuffle", true, "Stop the underwater/lowpass snapshot when the shield goes up. The activation sound still plays."); SuppressHum = ((BaseUnityPlugin)this).Config.Bind("Audio", "SuppressHum", true, "Stop the looping shield hum for the Shift shield. The vanilla magnet item always keeps its hum."); ActivationCooldown = ((BaseUnityPlugin)this).Config.Bind("Shield", "ActivationCooldown", 0.6f, "Hard minimum seconds between activations. Keep at or above 0.5 -- the server's 'Activate electromagnet' rate checker flags activations closer than 0.5s apart."); ShieldAbsorbsHits = ((BaseUnityPlugin)this).Config.Bind("Shield", "ShieldAbsorbsHits", true, "Master switch for the pip economy. Off = vanilla shield behaviour (blocks everything, never breaks)."); MaxPips = ((BaseUnityPlugin)this).Config.Bind("Shield", "MaxPips", 5, "Shield HP. Chip hits cost 1-3, big hits break it outright. No regeneration."); UseCooldown = ((BaseUnityPlugin)this).Config.Bind("Shield", "UseCooldown", 1f, "Seconds after releasing the shield before it can be raised again. Anti-flicker."); BreakCooldown = ((BaseUnityPlugin)this).Config.Bind("Shield", "BreakCooldown", 8f, "Seconds the shield is unavailable after it breaks. The punish."); RestoreAfterBreakCooldown = ((BaseUnityPlugin)this).Config.Bind("Shield", "RestoreAfterBreakCooldown", true, "When the break cooldown ends, restore the shield to full pips. Off = no shield until the next hole."); BreakStunDuration = ((BaseUnityPlugin)this).Config.Bind("Shield", "BreakStunDuration", 2.5f, "Seconds you are stunned in place when a hit breaks the shield, at 0%."); BreakStunScalesWithPercent = ((BaseUnityPlugin)this).Config.Bind("Shield", "BreakStunScalesWithPercent", true, "Break stun grows with percent, from BreakStunDuration to BreakStunDurationAtMax. Turn this off with the rest of the percent rules and every break costs the same flat BreakStunDuration."); BreakStunDurationAtMax = ((BaseUnityPlugin)this).Config.Bind("Shield", "BreakStunDurationAtMax", 3.5f, "Break stun at PercentForMaxScaling. Note this runs OPPOSITE to HitstunMultiplierAtMax on purpose: a launch gives you the air back sooner the more beaten up you are, but a break pins you longer. Getting launched is survivable; losing the shield at high percent should be the moment that costs you. BreakImmunityAtMaxPercent is the compensation."); PartialBreakLaunches = ((BaseUnityPlugin)this).Config.Bind("Shield", "PartialBreakLaunches", false, "Off (default): EVERY break stuns in place, and only percent takes the uncovered fraction of the hit. On: a hit that beat your remaining pips launches you at that fraction with a shortened knockdown instead of stunning. This was the old behaviour and is why partial breaks felt like an instant wake-up."); RefundPipsOnRefusedKnockout = ((BaseUnityPlugin)this).Config.Bind("Shield", "RefundPipsOnRefusedKnockout", true, "If the game refuses the knockout after your shield spent pips on the hit (comeback immunity, team protection, frozen, self hit), give the pips back. The bubble still pops, but a hit that could never stun you does not cost you the shield."); BreakImmunityScalesWithPercent = ((BaseUnityPlugin)this).Config.Bind("Shield", "BreakImmunityScalesWithPercent", true, "After a break stun, the knockout-immunity bubble (the blue one) lasts a percent-scaled time instead of the match rule. Every other knockout keeps the vanilla immunity, including the orange repeat protection."); BreakImmunityAtZeroPercent = ((BaseUnityPlugin)this).Config.Bind("Shield", "BreakImmunityAtZeroPercent", 0.5f, "Seconds of immunity after a break stun at 0%. Swap the two values to make high percent LESS protected instead."); BreakImmunityAtMaxPercent = ((BaseUnityPlugin)this).Config.Bind("Shield", "BreakImmunityAtMaxPercent", 3f, "Seconds of immunity after a break stun at PercentForMaxScaling. Default gives more breathing room the more beaten up you are."); AbsorbedHitsCancelKnockback = ((BaseUnityPlugin)this).Config.Bind("Shield", "AbsorbedHitsCancelKnockback", true, "Chip hits that the shield absorbs also cancel the pushback. Off = vanilla shove-while-shielded."); ReflectionSearchMargin = ((BaseUnityPlugin)this).Config.Bind("Shield", "ReflectionSearchMargin", 1.5f, "Metres beyond the shield radius to search for the projectile that just bounced off, to identify it."); CostOverrides = ((BaseUnityPlugin)this).Config.Bind("Costs", "Overrides", "", "Per-type pip cost overrides, comma separated. Values: a number, 'full', or 'unblockable'. Example: Landmine=2, Rocket=4, GolfCart=full. Type names are KnockoutType enum names: Swing, SwingProjectile, ReturnedBall, DuelingPistol, ElephantGun, GolfCart, Rocket, RocketBackBlast, Landmine, ReflectedSwingProjectile, ReflectedRocket, DeflectedDuelingPistolShot, DeflectedElephantGunShot, OrbitalLaserPeripheralHit, RocketDriverSwing, RocketDriverSwingPostHitSpin, RocketDriverSwingProjectile, FreezeBomb, ReflectedFreezeBomb, ThunderstormPeripheralHit, ThunderstormDirectHit, OrbitalLaserDirectHit, RailgunDirectHit, TrafficVehicle, JumboBurgerGiantSwing, JumboBurgerGiantSwingProjectile, JumboBurgerGiantCollision, ElectromagnetShieldExplosion. Defaults: pistols/untargeted balls 1; backblast/peripheral 2; carts/vehicles/rocket driver/mines 3; swings/targeted balls/rockets/freeze/giant = full; laser/thunder/railgun direct = unblockable."); MaxPercent = ((BaseUnityPlugin)this).Config.Bind("Percent", "MaxPercent", 300f, "Percent cap."); PerfectParry = ((BaseUnityPlugin)this).Config.Bind("Parry", "PerfectParry", true, "A hit that lands just as you DROP the shield is a perfect parry: fully absorbed, no pips spent, no percent gained. Holding the shield out and getting hit is an ordinary block; letting go into the hit is the read."); PerfectParryWindow = ((BaseUnityPlugin)this).Config.Bind("Parry", "PerfectParryWindow", 0.2f, "Seconds after you release the shield key during which a hit counts as a perfect parry. This is the whole difficulty knob: 0.2 is forgiving, 0.1 asks for a real read. Only a deliberate release opens it -- a shield that broke does not."); PerfectParryBeatsFullBreak = ((BaseUnityPlugin)this).Config.Bind("Parry", "PerfectParryBeatsFullBreak", true, "A perfect parry stops the hits that normally break the shield outright (swings, carts, targeted balls). This is the point of the mechanic: timing beats a hit that pips cannot."); PerfectParryBeatsUnblockable = ((BaseUnityPlugin)this).Config.Bind("Parry", "PerfectParryBeatsUnblockable", false, "Whether a perfect parry also stops railgun/orbital/thunderstorm direct hits. Off: unblockable stays unblockable."); PerfectParryRefundsUse = ((BaseUnityPlugin)this).Config.Bind("Parry", "PerfectParryRefundsUse", true, "Clear the use cooldown on a parry, so reading a hit correctly does not cost you the next shield."); PerfectParrySound = ((BaseUnityPlugin)this).Config.Bind("Parry", "PerfectParrySound", true, "Play the game's own blocked-knockout sound on a parry, over the normal shield hit."); ParryLinger = ((BaseUnityPlugin)this).Config.Bind("Parry", "ParryLinger", 0.2f, "Seconds the shield stays physically up after you let go of the key. You get your movement back immediately -- only the shield's body lingers. This is what makes a parry visible to everyone else: while the shield exists the game does its own work, so homing balls bounce back at whoever threw them and the shield-hit sound plays on every client. 0 = the shield vanishes with the keypress and parries are silent to everyone but you."); ParryGlow = ((BaseUnityPlugin)this).Config.Bind("Parry", "ParryGlow", true, "Flash the shield bright when a parry lands."); ParryGlowDuration = ((BaseUnityPlugin)this).Config.Bind("Parry", "ParryGlowDuration", 0.35f, "How long the parry flash lasts, in seconds."); ParryGlowBoost = ((BaseUnityPlugin)this).Config.Bind("Parry", "ParryGlowBoost", 3f, "How much brighter the flash is than your normal shield colour. The tint pipeline scales by the material's own intensity, so this multiplies rather than washing out to white."); PercentForMaxScaling = ((BaseUnityPlugin)this).Config.Bind("Percent", "PercentForMaxScaling", 100f, "Percent at which the things that SATURATE (angle floor, hang time, hitstun, break immunity, HUD shake) reach their max. Knockback itself does not use this -- it keeps climbing to KillPercent."); ForceMultiplierAtKill = ((BaseUnityPlugin)this).Config.Bind("Percent", "ForceMultiplierAtKill", 6f, "Knockback speed multiplier at the kill line. 1.0x at 0%, and the curve between is set by KnockbackExponent. Defaults give roughly: 40% 1.4x, 80% 1.9x, 100% 2.3x, 150% 3.3x, 200% 4.6x, 250% 6x."); KnockbackExponent = ((BaseUnityPlugin)this).Config.Bind("Percent", "KnockbackExponent", 1.5f, "Shape of the knockback curve. 1 = straight line to the kill line. Higher = flatter early, steeper late. 2 is very back-loaded."); HitstunMultiplierAtMax = ((BaseUnityPlugin)this).Config.Bind("Percent", "HitstunMultiplierAtMax", 0.8f, "Knockout duration multiplier at PercentForMaxScaling, interpolated from 1.0x at 0%. BELOW 1 by default: the hit that sends you furthest is also the one that gives you back the earliest, so on a big launch the stun runs out mid-air and you dive where you want to land. Above 1 gives the old behaviour (longer stun the more beaten up you are), which reads as being juggled. Set 1.0 for vanilla stun at every percent."); PercentPerHitBase = ((BaseUnityPlugin)this).Config.Bind("Percent", "PercentPerHitBase", 5f, "Percent gained by any chip-class hit, before the per-pip part."); PercentPerPip = ((BaseUnityPlugin)this).Config.Bind("Percent", "PercentPerPip", 4f, "Extra percent per pip of the hit's cost (a 3-pip hit = base + 3*this)."); PercentPerFullBreakHit = ((BaseUnityPlugin)this).Config.Bind("Percent", "PercentPerFullBreakHit", 25f, "Percent gained from a full-break-class hit landing unshielded."); ExplosionPercentFalloff = ((BaseUnityPlugin)this).Config.Bind("Percent", "ExplosionPercentFalloff", true, "Scale percent from explosions by how far you were from the blast, the way the game already scales the knockback."); ExplosionFalloffRadius = ((BaseUnityPlugin)this).Config.Bind("Percent", "ExplosionFalloffRadius", 8f, "Distance in metres at which an explosion does its minimum percent. Closer than this scales between full and minimum."); ExplosionPercentAtEdge = ((BaseUnityPlugin)this).Config.Bind("Percent", "ExplosionPercentAtEdge", 0.3f, "Fraction of the normal percent for a hit at the edge of the blast (0.3 = 30%)."); ExplosionForceAtEdge = ((BaseUnityPlugin)this).Config.Bind("Launch", "ExplosionForceAtEdge", 0.25f, "How much of the PERCENT force bonus applies at the edge of a blast (0.25 = a quarter). At the centre it is the full bonus. This is why 100% does not mean 100% knockback from a distant explosion."); ExplosionRadialLaunch = ((BaseUnityPlugin)this).Config.Bind("Launch", "ExplosionRadialLaunch", true, "Launch explosions away from where the blast actually was, instead of the game's forced-upward direction."); ExplosionRadialWeight = ((BaseUnityPlugin)this).Config.Bind("Launch", "ExplosionRadialWeight", 0.8f, "0 = the game's direction, 1 = purely away from the blast. 0.8 keeps a little of the vanilla lift so a blast at your feet still pops you up."); PercentPerUnblockableHit = ((BaseUnityPlugin)this).Config.Bind("Percent", "PercentPerUnblockableHit", 30f, "Percent gained from an unblockable hit."); PercentGainOnFullBreak = ((BaseUnityPlugin)this).Config.Bind("Percent", "PercentGainOnFullBreak", 0f, "Fraction of the hit's percent you still take when the shield breaks and you are stunned in place."); PercentReductionBetweenHoles = ((BaseUnityPlugin)this).Config.Bind("Percent", "PercentReductionBetweenHoles", 1f, "Fraction of percent removed at the start of each hole. 1 = full wipe."); PercentLostOnRespawn = ((BaseUnityPlugin)this).Config.Bind("Percent", "PercentLostOnRespawn", 25f, "Flat percent removed when you respawn (not a fraction). Small enough that dying on purpose is not attractive."); RespawnFatigueWindow = ((BaseUnityPlugin)this).Config.Bind("Percent", "RespawnFatigueWindow", 45f, "Seconds after a respawn during which another respawn gives NO percent reduction. Stops suicide-resetting."); KillZoneEnabled = ((BaseUnityPlugin)this).Config.Bind("Percent", "KillZoneEnabled", true, "At or above KillPercent, the apex of the launch that got you there is a star KO: flash, respawn."); KillPercent = ((BaseUnityPlugin)this).Config.Bind("Percent", "KillPercent", 250f, "The kill line."); PercentAfterKillZoneDeath = ((BaseUnityPlugin)this).Config.Bind("Percent", "PercentAfterKillZoneDeath", 25f, "Percent you respawn with after a star KO. The normal respawn halving does not apply on top."); KillZoneFlash = ((BaseUnityPlugin)this).Config.Bind("Percent", "KillZoneFlash", true, "Star flash + screenshake on a star KO (local only for now)."); KillZoneFlashSize = ((BaseUnityPlugin)this).Config.Bind("Percent", "KillZoneFlashSize", 9f, "Star flash size in metres."); KillZoneUpwardBoost = ((BaseUnityPlugin)this).Config.Bind("Percent", "KillZoneUpwardBoost", 45f, "Extra upward speed (m/s) added to the killing blow. You are already dead, so this is pure showmanship: you rocket off screen."); KillZoneMaxRiseTime = ((BaseUnityPlugin)this).Config.Bind("Percent", "KillZoneMaxRiseTime", 2.5f, "Seconds to wait for the apex before killing anyway, so a boost off a ceiling cannot stall the death."); KillZoneDeathLinger = ((BaseUnityPlugin)this).Config.Bind("Percent", "KillZoneDeathLinger", 5f, "Seconds you stay gone after the star flash before respawning. The camera holds on the spot."); KillZoneBoom = ((BaseUnityPlugin)this).Config.Bind("Percent", "KillZoneBoom", true, "Play the shield-explosion boom and a heavy screenshake on a star KO. Placeholder until custom SFX."); ShapeLaunches = ((BaseUnityPlugin)this).Config.Bind("Launch", "ShapeLaunches", true, "Raise the launch angle with percent and cap horizontal speed. Vertical launches stop juggling."); MinLaunchAngleAtZero = ((BaseUnityPlugin)this).Config.Bind("Launch", "MinLaunchAngleAtZero", 8f, "Minimum launch elevation in degrees at 0%. Low = the hit direction decides."); MinLaunchAngleAtMax = ((BaseUnityPlugin)this).Config.Bind("Launch", "MinLaunchAngleAtMax", 28f, "Minimum launch elevation in degrees at PercentForMaxScaling. 90 = straight up. Kept low so launches stay punishable."); HorizontalMultiplierAtKill = ((BaseUnityPlugin)this).Config.Bind("Launch", "HorizontalMultiplierAtKill", 2f, "EXTRA horizontal multiplier at the kill line, on top of the force multiplier, on the same curve. This is what makes late hits go away rather than up. The cap below still applies afterwards."); MaxHorizontalLaunchSpeed = ((BaseUnityPlugin)this).Config.Bind("Launch", "MaxHorizontalLaunchSpeed", 34f, "Horizontal speed cap (m/s); excess becomes height. 0 = no cap. This is the knob that decides how much of a big launch reads as distance versus altitude: lower it and high-percent hits turn into elevator rides. Mostly a lake guard now."); LaunchDrag = ((BaseUnityPlugin)this).Config.Bind("Launch", "LaunchDrag", 0.8f, "Extra air drag per second on the part of your speed above LaunchDragAboveSpeed, while tumbling after a launch. 0 = off."); LaunchVerticalDragFactor = ((BaseUnityPlugin)this).Config.Bind("Launch", "LaunchVerticalDragFactor", 0.5f, "How much of LaunchDrag applies to upward speed (0-1). Lower = higher, floatier arc."); LaunchDragDuration = ((BaseUnityPlugin)this).Config.Bind("Launch", "LaunchDragDuration", 1.5f, "Seconds after a hit that LaunchDrag applies."); LaunchDragAboveSpeed = ((BaseUnityPlugin)this).Config.Bind("Launch", "LaunchDragAboveSpeed", 14f, "Drag only touches speed ABOVE this (m/s). Everything below travels freely, so a launch keeps its sideways distance; only the extreme burst of a huge hit gets tamed."); LaunchHangTime = ((BaseUnityPlugin)this).Config.Bind("Launch", "LaunchHangTime", 0f, "How much gravity is cancelled at the top of a cloud-hit arc (0.55 = 55% at the very apex, tapering to none as you speed up). OFF by default: it reads as slowing down mid-air then speeding up, because that is what it is. Try 0.3-0.5 on cloud hits only."); LaunchHangWindow = ((BaseUnityPlugin)this).Config.Bind("Launch", "LaunchHangWindow", 7f, "Vertical speed (m/s) within which hang time applies. Only near the apex, where vertical speed is small, so the rise and fall keep their shape."); LaunchHangDuration = ((BaseUnityPlugin)this).Config.Bind("Launch", "LaunchHangDuration", 3f, "Seconds after a launch during which hang time can apply."); CloudHitMinPercent = ((BaseUnityPlugin)this).Config.Bind("Launch", "CloudHitMinPercent", 125f, "Percent at or above which a launch counts as a cloud hit. Hang time is the only thing left that reads it."); LaunchTrail = ((BaseUnityPlugin)this).Config.Bind("Launch", "LaunchTrail", true, "Skin-colored smoke trail on any player flying fast while knocked out."); LaunchTrailStartSpeed = ((BaseUnityPlugin)this).Config.Bind("Launch", "LaunchTrailStartSpeed", 12f, "Speed (m/s) needed to start the trail. Small shoves do not get one."); LaunchTrailMinPercent = ((BaseUnityPlugin)this).Config.Bind("Launch", "LaunchTrailMinPercent", 75f, "Percent you must be at before your launches smoke. Other players' percent is not synced yet, so their trails still use the speed threshold alone."); LaunchTrailStopSpeed = ((BaseUnityPlugin)this).Config.Bind("Launch", "LaunchTrailStopSpeed", 5f, "Speed (m/s) below which the trail stops."); LaunchTrailRate = ((BaseUnityPlugin)this).Config.Bind("Launch", "LaunchTrailRate", 45f, "Smoke puffs per second, on top of the per-metre rate."); LaunchTrailRatePerMetre = ((BaseUnityPlugin)this).Config.Bind("Launch", "LaunchTrailRatePerMetre", 5f, "Extra puffs per metre travelled, so a fast launch leaves a continuous cloud rather than dots."); LaunchTrailSize = ((BaseUnityPlugin)this).Config.Bind("Launch", "LaunchTrailSize", 2.2f, "Puff size in metres at its largest."); LaunchTrailLifetime = ((BaseUnityPlugin)this).Config.Bind("Launch", "LaunchTrailLifetime", 1.7f, "Seconds each puff lingers."); LaunchTrailAlpha = ((BaseUnityPlugin)this).Config.Bind("Launch", "LaunchTrailAlpha", 1f, "Puff opacity at spawn."); RootWhileShielded = ((BaseUnityPlugin)this).Config.Bind("Rooting", "RootWhileShielded", true, "Shielding pins you in place: no walking. Existing momentum carries until ground drag stops you."); BlockJumpWhileShielded = ((BaseUnityPlugin)this).Config.Bind("Rooting", "BlockJumpWhileShielded", true, "Disallow jumping while the shield is up."); BlockSwingWhileShielded = ((BaseUnityPlugin)this).Config.Bind("Rooting", "BlockSwingWhileShielded", true, "Cannot start charging a swing while the shield is up."); BlockDiveWhileShielded = ((BaseUnityPlugin)this).Config.Bind("Rooting", "BlockDiveWhileShielded", true, "Cannot dive while the shield is up. Forced dives are unaffected."); AllowMidAirActivation = ((BaseUnityPlugin)this).Config.Bind("Rooting", "AllowMidAirActivation", true, "Shield can be raised in the air. Momentum carries; you are rooted on landing."); BlockActivationDuringSwing = ((BaseUnityPlugin)this).Config.Bind("Rooting", "BlockActivationDuringSwing", true, "Shield cannot be raised while charging or mid-swing."); BlockActivationDuringSpringBoots = ((BaseUnityPlugin)this).Config.Bind("Rooting", "BlockActivationDuringSpringBoots", true, "Shield cannot be raised while spring boots are active, and goes down if you spring while holding it."); BlockActivationInMenus = ((BaseUnityPlugin)this).Config.Bind("Rooting", "BlockActivationInMenus", true, "Shift does nothing while the pause menu, scoreboard, text chat or emote wheel is open, so you cannot burn pips by accident."); BlockItemUseWhileShielded = ((BaseUnityPlugin)this).Config.Bind("Rooting", "BlockItemUseWhileShielded", true, "No using items (or spring boots) while the shield is up."); BlockAimWhileShielded = ((BaseUnityPlugin)this).Config.Bind("Rooting", "BlockAimWhileShielded", true, "No aiming while the shield is up. Swapping weapons is still allowed."); BreakStunIgnoresComebackImmunity = ((BaseUnityPlugin)this).Config.Bind("Rooting", "BreakStunIgnoresComebackImmunity", true, "A hit that breaks your shield stuns you even if the game's comeback bubble is up. Off = vanilla behaviour, where comeback protection refuses the knockout and you get no stun at all."); RequireAllPlayersModded = ((BaseUnityPlugin)this).Config.Bind("Network", "RequireAllPlayersModded", true, "Stand down (vanilla rules, no shield, no percent) unless every other player in the lobby is running this exact version. Players announce themselves over the game's own chat channel; anyone without the mod sees one line of plain text saying who is modded. NOTE: this runs on your machine, so it stops accidents and version drift, not a determined cheater -- only a server-side check could do that."); MismatchPopupDuration = ((BaseUnityPlugin)this).Config.Bind("Network", "MismatchPopupDuration", 12f, "Seconds the big version-mismatch panel stays up before shrinking to a single line at the top of the screen."); HandshakeTimeout = ((BaseUnityPlugin)this).Config.Bind("Network", "HandshakeTimeout", 12f, "Seconds to wait for a player to announce before treating them as unmodded. Raise it on slow connections."); BlockActivationDuringImmunity = ((BaseUnityPlugin)this).Config.Bind("Rooting", "BlockActivationDuringImmunity", true, "Shift does nothing while the game's own comeback bubble (blue recovery protection or gold repeat protection) is up. Nothing can knock you out then, so a shield would only waste pips."); TintVanillaShield = ((BaseUnityPlugin)this).Config.Bind("Bubble", "TintVanillaShield", true, "Recolor the game's own shield particle (hold, dissolve, hit sparks, break) to your skin color for the Shift shield. The magnet item stays team-colored."); ShowHud = ((BaseUnityPlugin)this).Config.Bind("HUD", "ShowHud", true, "Show the percent + bubble readiness overlay."); HudScale = ((BaseUnityPlugin)this).Config.Bind("HUD", "HudScale", 1f, "Overall HUD scale."); HudBottomMargin = ((BaseUnityPlugin)this).Config.Bind("HUD", "HudBottomMargin", 150f, "Pixels from the bottom of the screen. Raised so the percent clears the golf-cart Exit prompt."); HudHorizontalOffset = ((BaseUnityPlugin)this).Config.Bind("HUD", "HudHorizontalOffset", 0f, "Pixels to shift the percent left/right from centre."); BubbleHudSize = ((BaseUnityPlugin)this).Config.Bind("HUD", "BubbleHudSize", 64f, "Bubble readiness icon size in pixels at HudScale 1."); BubbleHudGap = ((BaseUnityPlugin)this).Config.Bind("HUD", "BubbleHudGap", 22f, "Gap between the percent and the icon."); BubbleHudOnLeft = ((BaseUnityPlugin)this).Config.Bind("HUD", "BubbleHudOnLeft", true, "Icon left of the percent (away from the item bar). Off = right of it."); ShowPipDots = ((BaseUnityPlugin)this).Config.Bind("HUD", "ShowPipDots", true, "Show pip dots under the icon. Debug aid; the shield itself should carry this in the final build."); PercentFontName = ((BaseUnityPlugin)this).Config.Bind("HUD", "PercentFontName", "DFGothic-EB", "OS-installed font to use for the percent. Matched loosely (spaces/dashes ignored). Unity can only load fonts installed on the system, so install DF Gothic first. Falls back to the default font."); PercentFontSize = ((BaseUnityPlugin)this).Config.Bind("HUD", "PercentFontSize", 72, "Percent font size in pixels at HudScale 1."); PercentShakeDurationTable = ((BaseUnityPlugin)this).Config.Bind("HUD", "ShakeDurationTable", "0:0.8, 30:2, 60:3, 90:5", "How long the shake takes to settle, as percent:seconds thresholds. Values between two thresholds interpolate, so with the default a hit at 45% settles over 2.5s. The shake always decays to nothing -- the number is still when you are not being hit."); PercentShakeDuration = ((BaseUnityPlugin)this).Config.Bind("HUD", "PercentShakeDuration", 2f, "Fallback settle time if ShakeDurationTable cannot be read."); PercentShakePixels = ((BaseUnityPlugin)this).Config.Bind("HUD", "PercentShakePixels", 5f, "Rumble size in pixels immediately after a hit, decaying to zero. This is a rattle, not a bounce; keep it small."); PercentShakeSpeed = ((BaseUnityPlugin)this).Config.Bind("HUD", "PercentShakeSpeed", 90f, "How fast the rumble moves. Higher is a tighter buzz."); PercentShakePunch = ((BaseUnityPlugin)this).Config.Bind("HUD", "PercentShakePunch", 0.3f, "Momentary size pop on a hit (0.3 = 30% bigger), scaled about the number's centre. This is what gives the impact."); PercentBlurSamples = ((BaseUnityPlugin)this).Config.Bind("HUD", "MotionBlurSamples", 3f, "Ghost copies drawn behind the number while it moves, to fake motion blur. 0 = off."); PercentBlurLength = ((BaseUnityPlugin)this).Config.Bind("HUD", "MotionBlurLength", 2.5f, "How far the ghosts trail behind the movement. Higher smears more."); PercentVerticalOffset = ((BaseUnityPlugin)this).Config.Bind("HUD", "PercentVerticalOffset", 14f, "Pixels to push the percent down so its digits line up with the middle of the bubble icon. Text sits above its own baseline, so a bottom-aligned number reads high next to a circle."); ConfigVersion = ((BaseUnityPlugin)this).Config.Bind("Meta", "ConfigVersion", "", "Internal. When the mod version changes, all settings are reset to the new defaults so retunes actually land."); VerboseLogging = ((BaseUnityPlugin)this).Config.Bind("Debug", "VerboseLogging", false, "Log every activation, absorb, break and percent change. Noisy; turn on when reporting a problem."); CostOverrides.SettingChanged += delegate { ShieldState.InvalidateOverrides(); }; PercentFontName.SettingChanged += delegate { Hud.InvalidateFont(); }; PercentShakeDurationTable.SettingChanged += delegate { Hud.InvalidateShakeTable(); }; } private void ResetConfigIfVersionChanged() { if (ConfigVersion.Value == "0.7.7") { return; } List list = new List(); foreach (KeyValuePair item in ((BaseUnityPlugin)this).Config) { string text = item.Key.Section + "." + item.Key.Key; if (Array.IndexOf(RetunedThisVersion, text) < 0) { continue; } ConfigEntryBase value = item.Value; try { if (!object.Equals(value.BoxedValue, value.DefaultValue)) { value.BoxedValue = value.DefaultValue; list.Add(text); } } catch { } } ConfigVersion.Value = "0.7.7"; ((BaseUnityPlugin)this).Config.Save(); Log.LogInfo((object)((list.Count == 0) ? "Config version now 0.7.7; no retuned entries needed resetting." : ("Config version now 0.7.7; reset to new defaults: " + string.Join(", ", list) + "."))); } private void OnDestroy() { try { ReleaseShield(); } catch (Exception ex) { Log.LogWarning((object)("Unload: " + ex.Message)); } try { ShieldTint.DestroyAll(); } catch (Exception ex2) { Log.LogWarning((object)("Unload: " + ex2.Message)); } try { LaunchVfx.DestroyAll(); } catch (Exception ex3) { Log.LogWarning((object)("Unload: " + ex3.Message)); } try { KillZone.DestroyAll(); } catch (Exception ex4) { Log.LogWarning((object)("Unload: " + ex4.Message)); } try { Hud.Shutdown(); } catch (Exception ex5) { Log.LogWarning((object)("Unload: " + ex5.Message)); } try { CourseManager.MatchStateChanged -= OnMatchStateChanged; } catch { } Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private void OnMatchStateChanged(MatchState from, MatchState to) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 //IL_0009: Unknown result type (might be due to invalid IL or missing references) if ((int)to == 2 && (int)from != 2) { if ((int)from == 0) { ShieldState.FullReset("match start"); ModHandshake.Reset("match start"); Launch.Cancel(); } else { ShieldState.ResetForNewHole(); } } } private void Update() { ModHandshake.Tick(); if (_lingerUntil > double.MinValue && Time.timeAsDouble >= _lingerUntil) { CancelLingeringShield("linger over"); } ShieldState.Tick(); ShieldTint.Tick(); LaunchVfx.Tick(); KillZone.Tick(); Keyboard current = Keyboard.current; if (current == null) { return; } PlayerInfo localPlayerInfo = GameManager.LocalPlayerInfo; if ((Object)(object)localPlayerInfo == (Object)null) { _weActivated = false; return; } bool isPressed = ((ButtonControl)current.leftShiftKey).isPressed; if (_weActivated && BlockActivationDuringImmunity.Value && HasKnockoutImmunity(localPlayerInfo)) { if (VerboseLogging.Value) { Log.LogInfo((object)"Comeback immunity is up; dropping the shield."); } ReleaseShield(); } if (_weActivated && (IsInGolfCart(localPlayerInfo) || (BlockActivationDuringSpringBoots.Value && IsUsingSpringBoots(localPlayerInfo)))) { ReleaseShield(); } if (isPressed) { if (!localPlayerInfo.IsElectromagnetShieldActive) { TryActivate(localPlayerInfo); } else if (_weActivated) { _activationTimestamp.Invoke(localPlayerInfo) = Time.timeAsDouble; } } else if (_weActivated) { ReleaseShield(); } } private void OnGUI() { try { Hud.Draw(); } catch (Exception ex) { if (VerboseLogging.Value) { Log.LogWarning((object)("HUD draw error: " + ex.Message)); } } } internal static bool IsInGolfCart(PlayerInfo player) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) try { GolfCartSeat activeGolfCartSeat = player.ActiveGolfCartSeat; return ((GolfCartSeat)(ref activeGolfCartSeat)).IsValid(); } catch { return false; } } internal static bool ActivationBlockedByState(PlayerInfo player) { return ActivationBlockedByState(player, forHud: false); } internal static bool ActivationBlockedByState(PlayerInfo player, bool forHud) { //IL_008e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null) { return true; } if (!ModHandshake.GameplayEnabled) { return true; } if (!forHud && BlockActivationDuringImmunity.Value && HasKnockoutImmunity(player)) { return true; } if (BlockActivationInMenus.Value && AnyMenuOpen()) { return true; } if (KillZone.IsLingering) { return true; } if (IsInGolfCart(player)) { return true; } PlayerMovement movement = player.Movement; if ((Object)(object)movement != (Object)null) { if (!AllowMidAirActivation.Value && !movement.IsGrounded) { return true; } if (movement.IsKnockedOutOrRecovering || movement.IsRespawningOrDrowning) { return true; } if ((int)movement.DivingState != 0) { return true; } } if (BlockActivationDuringSpringBoots.Value && IsUsingSpringBoots(player)) { return true; } PlayerGolfer asGolfer = player.AsGolfer; if (BlockActivationDuringSwing.Value && (Object)(object)asGolfer != (Object)null && (asGolfer.IsChargingSwing || asGolfer.IsSwinging)) { return true; } return false; } internal static bool AnyMenuOpen() { try { if (PauseMenu.IsPaused) { return true; } } catch { } try { if (Scoreboard.IsVisible) { return true; } } catch { } try { if (TextChatUi.IsOpen) { return true; } } catch { } try { if (RadialMenu.IsVisible) { return true; } } catch { } return false; } internal static bool HasKnockoutImmunity(PlayerInfo player) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) try { return (Object)(object)player != (Object)null && (Object)(object)player.Movement != (Object)null && player.Movement.KnockoutImmunityStatus.hasImmunity; } catch { return false; } } internal static bool IsUsingSpringBoots(PlayerInfo player) { try { if ((Object)(object)player.Inventory != (Object)null && player.Inventory.IsUsingSpringBoots) { return true; } return (Object)(object)player.Movement != (Object)null && player.Movement.IsInSpringBootsJump; } catch { return false; } } private void TryActivate(PlayerInfo player) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) if (!(Time.timeAsDouble - _lastActivationTime < (double)ActivationCooldown.Value) && ShieldState.CanActivate(out var _) && !ActivationBlockedByState(player)) { ItemUseId val = default(ItemUseId); ((ItemUseId)(ref val))..ctor(player.PlayerId.Guid, 0, (ItemType)9, false); _weActivated = true; _lastActivationTime = Time.timeAsDouble; player.LocalPlayerActivateElectromagnetShield(val); if (!player.IsElectromagnetShieldActive) { _weActivated = false; } else if (VerboseLogging.Value) { Log.LogInfo((object)$"Shield up ({ShieldState.Pips} pips)."); } } } private static void ReleaseShield() { if (!_weActivated) { return; } PlayerInfo localPlayerInfo = GameManager.LocalPlayerInfo; if ((Object)(object)localPlayerInfo == (Object)null || !localPlayerInfo.IsElectromagnetShieldActive) { _weActivated = false; return; } _weActivated = false; LastOurShieldReleaseTime = Time.timeAsDouble; ShieldState.LoweredAt = Time.timeAsDouble; ShieldState.OnShieldReleased(); float num = Mathf.Max(0f, ParryLinger.Value); if (num > 0f && ShieldState.GameplayParryEnabled) { _lingerUntil = Time.timeAsDouble + (double)num; if (VerboseLogging.Value) { Log.LogInfo((object)$"Shield key released; body lingers {num:0.00}s."); } } else { CancelLingeringShield("released"); } } private static void CancelLingeringShield(string why) { _lingerUntil = double.MinValue; PlayerInfo localPlayerInfo = GameManager.LocalPlayerInfo; if (!((Object)(object)localPlayerInfo == (Object)null) && localPlayerInfo.IsElectromagnetShieldActive) { localPlayerInfo.LocalPlayerCancelElectromagnetShield(false); LastOurShieldReleaseTime = Time.timeAsDouble; if (VerboseLogging.Value) { Log.LogInfo((object)("Shield down (" + why + ").")); } } } internal static void ForceReleaseForHandshake() { try { if (_weActivated) { ReleaseShield(); } CancelLingeringShield("handshake"); } catch { } } internal static void NotifyShieldDropped() { _weActivated = false; _lingerUntil = double.MinValue; LastOurShieldReleaseTime = Time.timeAsDouble; } } internal static class ShieldState { internal const int CostFullBreak = 1000; internal const int CostUnblockable = -1; internal static int Pips; internal static float Percent; internal static double UseCooldownUntil = double.MinValue; internal static double LoweredAt = double.MinValue; internal static double LastParryAt = double.MinValue; internal static double BreakCooldownUntil = double.MinValue; internal static Vector3 PendingVelocityCorrection; internal static bool HasPendingVelocityCorrection; internal static float PendingHitstunAbsolute = -1f; internal static float PendingHitstunMultiplier = -1f; internal static bool PendingProjectileWasTargeted; internal static float PendingPercentGain; internal static double LastKnockoutChargeTime = double.MinValue; internal static double BreakStunUntil = double.MinValue; internal static bool LastKnockoutWasBreakStun; private static bool _pendingReleasesBreakStun; private static bool _awaitingResult; internal static bool ForcingBreakKnockout; private static int _pipsBeforeHit; private static double _breakCdBeforeHit; private static double _useCdBeforeHit; private static bool _shieldWasUpBeforeHit; internal static bool KillZoneDeathPending; private static double _lastRespawnTime = double.MinValue; private static Dictionary _overrides; internal static float PendingHitDistance; internal static Vector3 PendingHitLocalOrigin; internal static double LaunchHangUntil = double.MinValue; internal static float LaunchHangScale; internal static double LaunchDragUntil = double.MinValue; internal static bool RequestingBreakStun; internal static float BreakStun { get { if (Plugin.BreakStunScalesWithPercent.Value) { return Mathf.Max(0.05f, Mathf.Lerp(Plugin.BreakStunDuration.Value, Plugin.BreakStunDurationAtMax.Value, ScaleT)); } return Plugin.BreakStunDuration.Value; } } internal static float BreakImmunityDuration => Mathf.Max(0f, Mathf.Lerp(Plugin.BreakImmunityAtZeroPercent.Value, Plugin.BreakImmunityAtMaxPercent.Value, ScaleT)); internal static bool InPlayableHole { get { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Invalid comparison between Unknown and I4 try { if (!ModHandshake.GameplayEnabled) { return false; } if (SingletonBehaviour.HasInstance) { return false; } MatchState matchState = CourseManager.MatchState; if (matchState - 2 <= 3) { return true; } return false; } catch { return true; } } } internal static bool InDrivingRange { get { try { return SingletonBehaviour.HasInstance; } catch { return false; } } } internal static bool IsOnBreakCooldown => Time.timeAsDouble < BreakCooldownUntil; internal static bool IsOnUseCooldown => Time.timeAsDouble < UseCooldownUntil; internal static float SecondsUntilReady { get { double timeAsDouble = Time.timeAsDouble; double num = Math.Max(UseCooldownUntil, BreakCooldownUntil); if (Pips <= 0 && !Plugin.RestoreAfterBreakCooldown.Value) { return float.PositiveInfinity; } return (float)Math.Max(0.0, num - timeAsDouble); } } internal static bool GameplayParryEnabled { get { if (ModHandshake.GameplayEnabled) { return Plugin.PerfectParry.Value; } return false; } } internal static float ScaleT => Mathf.Clamp01(Percent / Mathf.Max(1f, Plugin.PercentForMaxScaling.Value)); internal static float KillT => Mathf.Clamp01(Percent / Mathf.Max(1f, Plugin.KillPercent.Value)); internal static float ForceMultiplier => 1f + (Plugin.ForceMultiplierAtKill.Value - 1f) * KnockbackCurve(KillT); internal static float HorizontalMultiplier => 1f + (Plugin.HorizontalMultiplierAtKill.Value - 1f) * KnockbackCurve(KillT); internal static float HitstunMultiplier => Mathf.Lerp(1f, Plugin.HitstunMultiplierAtMax.Value, ScaleT); internal static event Action PercentIncreased; private static void SnapshotForRefund(bool shieldWasUp) { _pipsBeforeHit = Pips; _breakCdBeforeHit = BreakCooldownUntil; _useCdBeforeHit = UseCooldownUntil; _shieldWasUpBeforeHit = shieldWasUp; } private static void RefundRefusedHit() { if (_shieldWasUpBeforeHit && (Pips != _pipsBeforeHit || BreakCooldownUntil != _breakCdBeforeHit)) { int num = _pipsBeforeHit - Pips; Pips = _pipsBeforeHit; BreakCooldownUntil = _breakCdBeforeHit; UseCooldownUntil = _useCdBeforeHit; if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)$"Knockout refused: refunded {num} pip(s). The bubble still popped, but it costs you nothing."); } } } internal static bool ConsumeBreakStunImmunity() { if (!LastKnockoutWasBreakStun) { return false; } LastKnockoutWasBreakStun = false; BreakStunUntil = double.MinValue; return true; } internal static void FullReset(string why) { Pips = Plugin.MaxPips.Value; Percent = 0f; UseCooldownUntil = double.MinValue; BreakCooldownUntil = double.MinValue; BreakStunUntil = double.MinValue; LastKnockoutWasBreakStun = false; KillZoneDeathPending = false; _lastRespawnTime = double.MinValue; KillZone.Disarm(); KillZone.CancelLinger(); ClearPending(); if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)$"Full reset ({why}): pips={Pips}, percent=0."); } } internal static void ResetForNewHole() { Pips = Plugin.MaxPips.Value; Percent *= 1f - Mathf.Clamp01(Plugin.PercentReductionBetweenHoles.Value); UseCooldownUntil = double.MinValue; BreakCooldownUntil = double.MinValue; BreakStunUntil = double.MinValue; LastKnockoutWasBreakStun = false; KillZone.Disarm(); KillZone.CancelLinger(); ClearPending(); if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)$"New hole: pips={Pips}, percent={Percent:0}"); } } internal static void OnRespawn() { double timeAsDouble = Time.timeAsDouble; bool flag = timeAsDouble - _lastRespawnTime < (double)Plugin.RespawnFatigueWindow.Value; _lastRespawnTime = timeAsDouble; BreakStunUntil = double.MinValue; LastKnockoutWasBreakStun = false; KillZone.Disarm(); Launch.Cancel(); if (KillZoneDeathPending) { KillZoneDeathPending = false; if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)$"Respawn after star KO: percent is {Percent:0}."); } return; } if (flag) { if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)$"Respawn within fatigue window: percent kept at {Percent:0}."); } return; } float percent = Percent; Percent = Mathf.Max(0f, Percent - Mathf.Max(0f, Plugin.PercentLostOnRespawn.Value)); if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)$"Respawn: percent {percent:0} -> {Percent:0}."); } } internal static void Tick() { double timeAsDouble = Time.timeAsDouble; if (Pips <= 0 && Plugin.RestoreAfterBreakCooldown.Value && timeAsDouble >= BreakCooldownUntil && BreakCooldownUntil > double.MinValue) { Pips = Plugin.MaxPips.Value; BreakCooldownUntil = double.MinValue; if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)"Break cooldown over: shield restored."); } } } internal static void ClearPending() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) HasPendingVelocityCorrection = false; PendingVelocityCorrection = Vector3.zero; PendingHitstunAbsolute = -1f; PendingHitstunMultiplier = -1f; PendingPercentGain = 0f; PendingProjectileWasTargeted = false; } internal static bool CanActivate(out string reason) { if (Pips <= 0) { reason = "no pips"; return false; } if (IsOnBreakCooldown) { reason = "break cooldown"; return false; } if (IsOnUseCooldown) { reason = "use cooldown"; return false; } reason = null; return true; } internal static void OnShieldReleased() { UseCooldownUntil = Time.timeAsDouble + (double)Plugin.UseCooldown.Value; } internal static void InvalidateOverrides() { _overrides = null; } private static void EnsureOverrides() { //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) if (_overrides != null) { return; } _overrides = new Dictionary(); string text = Plugin.CostOverrides.Value ?? ""; string[] array = text.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); foreach (string text2 in array) { string[] array2 = text2.Split('='); if (array2.Length != 2) { Plugin.Log.LogWarning((object)("Bad cost override '" + text2 + "'")); continue; } if (!Enum.TryParse(array2[0].Trim(), ignoreCase: true, out KnockoutType result)) { Plugin.Log.LogWarning((object)("Unknown knockout type '" + array2[0].Trim() + "'")); continue; } string text3 = array2[1].Trim().ToLowerInvariant(); int result2; switch (text3) { case "full": case "break": result2 = 1000; break; case "unblockable": result2 = -1; break; default: if (!int.TryParse(text3, out result2) || result2 < 0) { Plugin.Log.LogWarning((object)$"Bad cost '{array2[1]}' for {result}"); continue; } break; } _overrides[result] = result2; } if (_overrides.Count > 0) { Plugin.Log.LogInfo((object)("Cost overrides: " + text)); } } internal static int GetCost(KnockoutType type, bool projectileTargeted) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Expected I4, but got Unknown EnsureOverrides(); if (_overrides.TryGetValue(type, out var value)) { return value; } switch (type - 1) { case 2: case 3: case 4: case 14: case 15: return 1; case 0: case 12: case 19: if (!projectileTargeted) { return 1; } return 1000; case 7: case 16: case 22: case 33: return 2; case 5: case 11: case 17: case 18: case 26: return 3; case 23: case 24: case 25: case 27: case 31: case 32: return -1; default: return 1000; } } private static bool IsExplosive(KnockoutType t) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Invalid comparison between Unknown and I4 //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Invalid comparison between Unknown and I4 //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Invalid comparison between Unknown and I4 //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Invalid comparison between Unknown and I4 //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Invalid comparison between Unknown and I4 if ((int)t <= 14) { if (t - 7 <= 1 || (int)t == 12 || (int)t == 14) { goto IL_0028; } } else if ((int)t == 17 || t - 21 <= 2 || (int)t == 34) { goto IL_0028; } return false; IL_0028: return true; } internal static bool IsPerfectParry(int cost) { if (!Plugin.PerfectParry.Value) { return false; } if (Time.timeAsDouble - LoweredAt > (double)Plugin.PerfectParryWindow.Value) { return false; } return cost switch { -1 => Plugin.PerfectParryBeatsUnblockable.Value, 1000 => Plugin.PerfectParryBeatsFullBreak.Value, _ => true, }; } private static void Parry(PlayerInfo player, string what, int cost) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) LastParryAt = Time.timeAsDouble; if (Plugin.PerfectParryRefundsUse.Value) { UseCooldownUntil = double.MinValue; } ShieldTint.ParryFlash(player); if (Plugin.PerfectParrySound.Value) { try { RuntimeManager.PlayOneShot(GameManager.AudioSettings.KnockoutImmunityBlockedKnockoutEvent, ((Component)player).transform.position); } catch (Exception ex) { if (Plugin.VerboseLogging.Value) { Plugin.Log.LogWarning((object)("Parry sound: " + ex.Message)); } } } Plugin.Log.LogInfo((object)$"PERFECT PARRY on {what} ({(Time.timeAsDouble - LoweredAt) * 1000.0:0} ms after release, would have cost {CostLabel(cost)}). {Pips} pips kept."); } private static string CostLabel(int cost) { return cost switch { -1 => "an unblockable", 1000 => "a break", _ => cost + " pips", }; } internal static float GetPercentGain(int cost) { return GetPercentGain(cost, null); } internal static float GetPercentGain(int cost, KnockoutType? type) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) float num = cost switch { -1 => Plugin.PercentPerUnblockableHit.Value, 1000 => Plugin.PercentPerFullBreakHit.Value, _ => Plugin.PercentPerHitBase.Value + Plugin.PercentPerPip.Value * (float)cost, }; if (Plugin.ExplosionPercentFalloff.Value && type.HasValue && IsExplosive(type.Value)) { float num2 = Mathf.Max(0.5f, Plugin.ExplosionFalloffRadius.Value); float num3 = Mathf.Clamp01(PendingHitDistance / num2); float num4 = Mathf.Lerp(1f, Mathf.Clamp01(Plugin.ExplosionPercentAtEdge.Value), num3); if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)$"{type} at {PendingHitDistance:0.0}m: percent x{num4:0.00}."); } num *= num4; } return num; } internal static float KnockbackCurve(float t) { float num = Mathf.Max(1f, Plugin.KnockbackExponent.Value); return Mathf.Pow(Mathf.Clamp01(t), num); } internal unsafe static bool ResolveKnockout(PlayerInfo player, KnockoutType type, Vector3 incomingVelocityChange) { //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_038b: Unknown result type (might be due to invalid IL or missing references) //IL_0429: Unknown result type (might be due to invalid IL or missing references) //IL_03c4: Unknown result type (might be due to invalid IL or missing references) //IL_0496: Unknown result type (might be due to invalid IL or missing references) //IL_049b: Unknown result type (might be due to invalid IL or missing references) //IL_04a0: Unknown result type (might be due to invalid IL or missing references) //IL_0403: Unknown result type (might be due to invalid IL or missing references) //IL_0552: Unknown result type (might be due to invalid IL or missing references) //IL_0554: Unknown result type (might be due to invalid IL or missing references) //IL_0559: Unknown result type (might be due to invalid IL or missing references) //IL_055b: Unknown result type (might be due to invalid IL or missing references) //IL_055d: Unknown result type (might be due to invalid IL or missing references) //IL_055e: Unknown result type (might be due to invalid IL or missing references) //IL_0563: Unknown result type (might be due to invalid IL or missing references) //IL_0592: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0601: Unknown result type (might be due to invalid IL or missing references) //IL_04be: Unknown result type (might be due to invalid IL or missing references) //IL_04c3: Unknown result type (might be due to invalid IL or missing references) //IL_04c8: Unknown result type (might be due to invalid IL or missing references) //IL_04d0: Unknown result type (might be due to invalid IL or missing references) //IL_04d5: Unknown result type (might be due to invalid IL or missing references) //IL_04df: Unknown result type (might be due to invalid IL or missing references) //IL_04e4: Unknown result type (might be due to invalid IL or missing references) //IL_04e9: Unknown result type (might be due to invalid IL or missing references) //IL_04eb: Unknown result type (might be due to invalid IL or missing references) //IL_04f0: Unknown result type (might be due to invalid IL or missing references) //IL_0663: Unknown result type (might be due to invalid IL or missing references) //IL_066a: Unknown result type (might be due to invalid IL or missing references) //IL_0671: Unknown result type (might be due to invalid IL or missing references) //IL_0676: Unknown result type (might be due to invalid IL or missing references) //IL_0687: Unknown result type (might be due to invalid IL or missing references) //IL_0524: Unknown result type (might be due to invalid IL or missing references) //IL_051e: Unknown result type (might be due to invalid IL or missing references) //IL_0529: Unknown result type (might be due to invalid IL or missing references) //IL_053a: Unknown result type (might be due to invalid IL or missing references) //IL_053f: Unknown result type (might be due to invalid IL or missing references) //IL_0543: Unknown result type (might be due to invalid IL or missing references) //IL_054a: Unknown result type (might be due to invalid IL or missing references) //IL_054f: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_031a: Unknown result type (might be due to invalid IL or missing references) //IL_031b: Unknown result type (might be due to invalid IL or missing references) //IL_0320: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_0341: Unknown result type (might be due to invalid IL or missing references) //IL_0263: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Unknown result type (might be due to invalid IL or missing references) ClearPendingHitOnly(); if (!ModHandshake.GameplayEnabled) { return true; } if (RequestingBreakStun) { PendingHitstunAbsolute = BreakStun; PendingVelocityCorrection = -player.Movement.Velocity; HasPendingVelocityCorrection = ((Vector3)(ref PendingVelocityCorrection)).sqrMagnitude > 1E-06f; PendingPercentGain = 0f; _awaitingResult = true; ForcingBreakKnockout = Plugin.BreakStunIgnoresComebackImmunity.Value; BreakTrace.Log($"asking the game for a {PendingHitstunAbsolute:0.00}s stun"); return true; } bool pendingProjectileWasTargeted = PendingProjectileWasTargeted; PendingProjectileWasTargeted = false; int cost = GetCost(type, pendingProjectileWasTargeted); float num = 1f; _awaitingResult = false; ForcingBreakKnockout = false; SnapshotForRefund(player.IsElectromagnetShieldActive && Plugin.WeActivated); if (player.IsElectromagnetShieldActive && !Plugin.WeActivated && !Plugin.ShieldLingering) { return true; } if (IsPerfectParry(cost)) { Parry(player, ((object)(*(KnockoutType*)(&type))/*cast due to .constrained prefix*/).ToString(), cost); PendingVelocityCorrection = -incomingVelocityChange; HasPendingVelocityCorrection = true; return false; } if (player.IsElectromagnetShieldActive && Plugin.ShieldAbsorbsHits.Value) { LastKnockoutChargeTime = Time.timeAsDouble; if (cost == -1) { Break(player, playBreakEffect: true); if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)$"Shield hit by unblockable {type}: broken, hit goes through."); } } else { if (cost != 1000 && cost < Pips) { Pips -= cost; if (Plugin.AbsorbedHitsCancelKnockback.Value) { PendingVelocityCorrection = -incomingVelocityChange; HasPendingVelocityCorrection = true; } if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)$"Shield absorbed {type}: -{cost} pips, {Pips} left."); } return false; } float num2 = ((cost == 1000) ? Plugin.PercentGainOnFullBreak.Value : (1f - (float)Pips / (float)cost)); int pips = Pips; Break(player, playBreakEffect: true); if (!Plugin.PartialBreakLaunches.Value || cost == 1000 || num2 <= 0f) { PendingVelocityCorrection = -incomingVelocityChange; HasPendingVelocityCorrection = true; PendingHitstunAbsolute = BreakStun; BreakTrace.Begin(PendingHitstunAbsolute); BreakTrace.Log($"SHIELD BREAK by {type} ({pips} pips vs cost {cost}): asking the game for a {PendingHitstunAbsolute:0.00}s stun"); PendingPercentGain = GetPercentGain(cost, type) * Mathf.Clamp01(num2); if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)$"SHIELD BREAK by {type} ({pips} pips). Stunned in place {PendingHitstunAbsolute:0.00}s, +{PendingPercentGain:0}%."); } _awaitingResult = true; ForcingBreakKnockout = Plugin.BreakStunIgnoresComebackImmunity.Value; return true; } num = num2; if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)$"Shield broken through by {type}: cost {cost} vs {pips} pips, {num:P0} of the hit lands."); } } } bool flag = false; try { flag = (Object)(object)player.Movement != (Object)null && player.Movement.IsKnockedOut; } catch { } if (flag) { PendingPercentGain = GetPercentGain(cost, type) * num; _pendingReleasesBreakStun = Time.timeAsDouble < BreakStunUntil; if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)$"Hit {type} while down: vanilla knockback, +{PendingPercentGain:0}% pending."); } _awaitingResult = true; return true; } if (!InPlayableHole) { if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)$"Hit {type} outside a hole: vanilla knockback, no percent."); } _awaitingResult = true; return true; } float hitstunMultiplier = HitstunMultiplier; float num3 = ForceMultiplier; bool flag2 = IsExplosive(type); if (flag2 && Plugin.ExplosionPercentFalloff.Value) { float num4 = Mathf.Max(0.5f, Plugin.ExplosionFalloffRadius.Value); float num5 = Mathf.Clamp01(PendingHitDistance / num4); float num6 = Mathf.Lerp(1f, Mathf.Clamp01(Plugin.ExplosionForceAtEdge.Value), num5); num3 = 1f + (num3 - 1f) * num6; } Vector3 v = incomingVelocityChange * (num * num3); if (flag2 && Plugin.ExplosionRadialLaunch.Value) { Vector3 val = ((Component)player).transform.TransformPoint(PendingHitLocalOrigin); Vector3 val2 = ((Component)player).transform.position + Vector3.up * 0.9f - val; if (((Vector3)(ref val2)).sqrMagnitude > 0.01f) { ((Vector3)(ref val2)).Normalize(); float magnitude = ((Vector3)(ref v)).magnitude; Vector3 val3 = Vector3.Slerp((((Vector3)(ref v)).sqrMagnitude > 1E-06f) ? ((Vector3)(ref v)).normalized : val2, val2, Mathf.Clamp01(Plugin.ExplosionRadialWeight.Value)); v = ((Vector3)(ref val3)).normalized * magnitude; } } Vector3 val4 = ShapeLaunch(player, v); PendingVelocityCorrection = val4 - incomingVelocityChange; HasPendingVelocityCorrection = ((Vector3)(ref PendingVelocityCorrection)).sqrMagnitude > 1E-06f; PendingHitstunMultiplier = Mathf.Max(0.05f, num * hitstunMultiplier); PendingPercentGain = GetPercentGain(cost, type) * num; LaunchDragUntil = Time.timeAsDouble + (double)Plugin.LaunchDragDuration.Value; LaunchHangUntil = Time.timeAsDouble + (double)Plugin.LaunchHangDuration.Value; LaunchHangScale = ScaleT; Launch.Begin(); if (Plugin.VerboseLogging.Value) { ManualLogSource log = Plugin.Log; object[] obj2 = new object[9] { type, Percent, flag2 ? $" from {PendingHitDistance:0.0}m" : "", num * num3, ((Vector3)(ref incomingVelocityChange)).magnitude, ((Vector3)(ref val4)).magnitude, null, null, null }; Vector2 val5 = new Vector2(val4.x, val4.z); obj2[6] = ((Vector2)(ref val5)).magnitude; obj2[7] = val4.y; obj2[8] = PendingHitstunMultiplier; log.LogInfo((object)string.Format("Hit {0} at {1:0}%{2}: force x{3:0.00}, |v| {4:0.0} -> {5:0.0} (h {6:0.0}, up {7:0.0}), hitstun x{8:0.00}", obj2)); } _awaitingResult = true; return true; } internal static Vector3 ShapeLaunch(PlayerInfo player, Vector3 v) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: 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_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) float magnitude = ((Vector3)(ref v)).magnitude; if (magnitude < 0.01f || !Plugin.ShapeLaunches.Value) { return v; } float num = Mathf.Lerp(Plugin.MinLaunchAngleAtZero.Value, Plugin.MinLaunchAngleAtMax.Value, ScaleT) * (MathF.PI / 180f); Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(v.x, 0f, v.z); float magnitude2 = ((Vector3)(ref val)).magnitude; float num2 = Mathf.Atan2(v.y, magnitude2); if (num2 < num) { num2 = num; } float num3 = magnitude * Mathf.Cos(num2); float num4 = magnitude * Mathf.Sin(num2); float horizontalMultiplier = HorizontalMultiplier; if (horizontalMultiplier != 1f) { num3 *= horizontalMultiplier; } float num5 = Mathf.Sqrt(num3 * num3 + num4 * num4); float value = Plugin.MaxHorizontalLaunchSpeed.Value; if (value > 0f && num3 > value) { num4 = Mathf.Sqrt(Mathf.Max(0f, num5 * num5 - value * value)); num3 = value; } Vector3 val2; if (magnitude2 > 0.05f) { val2 = val / magnitude2; } else { Vector3 forward = ((Component)player).transform.forward; forward.y = 0f; val2 = ((((Vector3)(ref forward)).sqrMagnitude > 0.01f) ? (-((Vector3)(ref forward)).normalized) : Vector3.forward); } return val2 * num3 + Vector3.up * num4; } internal static void OnKnockoutResolved(bool knockedOut) { //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) if (knockedOut && PendingPercentGain > 0f) { AddPercent(PendingPercentGain); } PendingPercentGain = 0f; if (knockedOut && InPlayableHole && Plugin.KillZoneEnabled.Value && Percent >= Plugin.KillPercent.Value && !KillZone.IsArmed) { KillZone.Arm(); } if (knockedOut && _pendingReleasesBreakStun) { BreakStunUntil = double.MinValue; LastKnockoutWasBreakStun = false; } _pendingReleasesBreakStun = false; if (!knockedOut) { if (_awaitingResult && Plugin.RefundPipsOnRefusedKnockout.Value) { RefundRefusedHit(); } PendingHitstunAbsolute = -1f; PendingHitstunMultiplier = -1f; HasPendingVelocityCorrection = false; PendingVelocityCorrection = Vector3.zero; LaunchDragUntil = double.MinValue; BreakTrace.Log("game REFUSED the knockout: no stun will happen"); if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)"Knockout refused by the game (immunity/team/self/frozen); launch shaping discarded, no stun."); } } _awaitingResult = false; ForcingBreakKnockout = false; } internal static void SetPercent(float value) { float percent = Percent; Percent = Mathf.Clamp(value, 0f, Plugin.MaxPercent.Value); if (Percent > percent) { ShieldState.PercentIncreased?.Invoke(Percent); } Plugin.Log.LogInfo((object)$"Percent set: {percent:0} -> {Percent:0}."); if (Plugin.KillZoneEnabled.Value && Percent >= Plugin.KillPercent.Value && !KillZone.IsArmed) { Plugin.Log.LogInfo((object)"At or above the kill line: the next knockout kills."); } } internal static void AddPercent(float amount) { if (amount <= 0f) { return; } if (!InPlayableHole) { if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)$"Percent gain of {amount:0} ignored: not in a hole."); } return; } float percent = Percent; Percent = Mathf.Min(Plugin.MaxPercent.Value, Percent + amount); if (Percent > percent) { ShieldState.PercentIncreased?.Invoke(Percent); } if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)$"Percent {percent:0} -> {Percent:0}"); } } internal static void ChargeReflection(PlayerInfo player, int cost, string what) { if (!player.IsElectromagnetShieldActive || !Plugin.WeActivated || !Plugin.ShieldAbsorbsHits.Value || cost == -1) { return; } if (IsPerfectParry(cost)) { Parry(player, "reflected " + what, cost); } else if (cost == 1000 || cost >= Pips) { BreakTrace.Begin(BreakStun); BreakTrace.Log($"SHIELD BREAK by reflected {what} ({Pips} pips vs cost {cost})"); Break(player, playBreakEffect: true); StunInPlaceAfterBreak(player); } else { Pips -= cost; if (Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)$"Reflected {what}: -{cost} pips, {Pips} left."); } } } private static void StunInPlaceAfterBreak(PlayerInfo player) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) PlayerMovement movement = player.Movement; if ((Object)(object)movement == (Object)null) { return; } if (movement.IsKnockedOutOrRecovering) { BreakTrace.Log("already knocked out; not requesting a second knockout"); return; } RequestingBreakStun = true; try { bool flag = default(bool); bool flag2 = default(bool); BreakTrace.Log(movement.TryKnockOut(player, (KnockoutType)34, false, Vector3.zero, 0f, Vector3.zero, (ElectromagnetShieldHitBlockType)0, ItemUseId.Invalid, false, false, ref flag, ref flag2) ? "stun knockout accepted by the game" : "stun knockout REFUSED by the game"); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Break stun request failed: " + ex.Message)); } finally { RequestingBreakStun = false; } } internal static void Break(PlayerInfo player, bool playBreakEffect) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) Pips = 0; double timeAsDouble = Time.timeAsDouble; BreakCooldownUntil = timeAsDouble + (double)Plugin.BreakCooldown.Value; UseCooldownUntil = Math.Max(UseCooldownUntil, timeAsDouble + (double)Plugin.UseCooldown.Value); if (player.IsElectromagnetShieldActive) { player.LocalPlayerCancelElectromagnetShield(false); } Plugin.NotifyShieldDropped(); if (playBreakEffect) { try { player.PlayElectromagnetShieldHitForAllClients(default(Vector3), true); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Break effect failed: " + ex.Message)); } } } private static void ClearPendingHitOnly() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) _pendingReleasesBreakStun = false; HasPendingVelocityCorrection = false; PendingVelocityCorrection = Vector3.zero; PendingHitstunAbsolute = -1f; PendingHitstunMultiplier = -1f; PendingPercentGain = 0f; } } internal static class Skin { internal static Color Of(PlayerInfo p) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) try { PlayerCosmeticsSettings playerCosmeticsSettings = GameManager.PlayerCosmeticsSettings; PlayerCosmetics cosmetics = p.Cosmetics; if ((Object)(object)playerCosmeticsSettings != (Object)null && (Object)(object)cosmetics != (Object)null && playerCosmeticsSettings.skinColors != null) { int networkskinColorIndex = cosmetics.NetworkskinColorIndex; if (networkskinColorIndex >= 0 && networkskinColorIndex < playerCosmeticsSettings.skinColors.Length) { return playerCosmeticsSettings.skinColors[networkskinColorIndex].baseColor; } } } catch { } return Color.white; } } internal static class ShieldTint { private class Instanced { public Material Original; public Material Instance; } private static Color? _armed; private static bool _consumed; private static readonly List _systems = new List(); private static readonly List _renderers = new List(); private static readonly List _handlers = new List(); private static readonly HashSet _dumped = new HashSet(); private static readonly Dictionary _instances = new Dictionary(); private static readonly List _sweep = new List(); private static bool _restored = true; private static double _lastSweep; private static double _flashUntil = double.MinValue; private static PlayerInfo _flashOn; internal static bool Enabled => Plugin.TintVanillaShield.Value; internal static bool IsOurs(PlayerInfo p) { if (!Local.Is(p)) { return false; } if (!Plugin.WeActivated) { return Time.timeAsDouble - Plugin.LastOurShieldReleaseTime < 0.5; } return true; } internal static void Arm(PlayerInfo p) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) _armed = null; _consumed = false; if (Enabled && IsOurs(p)) { _armed = Skin.Of(p); } } internal static void Disarm() { _armed = null; } internal static void ParryFlash(PlayerInfo p) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) if (Enabled && Plugin.ParryGlow.Value && !((Object)(object)p == (Object)null)) { SphereCollider electromagnetShieldCollider = p.ElectromagnetShieldCollider; if (!((Object)(object)electromagnetShieldCollider == (Object)null)) { Color val = Skin.Of(p); float num = Mathf.Max(1f, Plugin.ParryGlowBoost.Value); Color c = default(Color); ((Color)(ref c))..ctor(val.r * num, val.g * num, val.b * num, val.a); _flashOn = p; _flashUntil = Time.timeAsDouble + (double)Mathf.Max(0.05f, Plugin.ParryGlowDuration.Value); Apply(((Component)electromagnetShieldCollider).transform, c, "parry flash"); } } } private static void TickParryFlash() { //IL_0058: Unknown result type (might be due to invalid IL or missing references) if (_flashUntil == double.MinValue || Time.timeAsDouble < _flashUntil) { return; } _flashUntil = double.MinValue; PlayerInfo flashOn = _flashOn; _flashOn = null; if (!((Object)(object)flashOn == (Object)null)) { SphereCollider electromagnetShieldCollider = flashOn.ElectromagnetShieldCollider; if ((Object)(object)electromagnetShieldCollider != (Object)null) { Apply(((Component)electromagnetShieldCollider).transform, Skin.Of(flashOn), "parry flash over"); } } } internal static void OnSetTeam(TeamColorVfxHandler h) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) if (_armed.HasValue && !((Object)(object)h == (Object)null)) { _consumed = true; Apply(((Component)h).transform, _armed.Value, "SetTeam"); } } internal static void OnShieldHookDone(PlayerInfo p) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) if (_armed.HasValue && !_consumed && (Object)(object)p.ElectromagnetShieldCollider != (Object)null) { Apply(((Component)p.ElectromagnetShieldCollider).transform, _armed.Value, "hook fallback"); } _armed = null; _consumed = false; } internal static void Apply(Transform root, Color c, string why) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Expected O, but got Unknown //IL_0172: Unknown result type (might be due to invalid IL or missing references) try { _systems.Clear(); ((Component)root).GetComponentsInChildren(true, _systems); foreach (ParticleSystem system in _systems) { TintSystem(system, c); } _handlers.Clear(); ((Component)root).GetComponentsInChildren(true, _handlers); foreach (BubbleVfxMaterialHandler handler in _handlers) { BubbleMaterialTintPatch.Register(handler, c); } _renderers.Clear(); ((Component)root).GetComponentsInChildren(true, _renderers); foreach (ParticleSystemRenderer renderer in _renderers) { if ((Object)(object)((Component)renderer).GetComponentInParent() != (Object)null) { continue; } Material sharedMaterial = ((Renderer)renderer).sharedMaterial; if (!((Object)(object)sharedMaterial == (Object)null)) { if (!_instances.TryGetValue(renderer, out var value) || (Object)(object)value.Instance == (Object)null || (Object)(object)value.Instance.shader != (Object)(object)sharedMaterial.shader) { value = new Instanced { Original = sharedMaterial, Instance = new Material(sharedMaterial) }; _instances[renderer] = value; } else if (sharedMaterial != value.Instance) { value.Original = sharedMaterial; value.Instance.CopyPropertiesFromMaterial(sharedMaterial); } BubbleMaterialTintPatch.TintMaterial(value.Instance, c); ((Renderer)renderer).sharedMaterial = value.Instance; _restored = false; } } if (Plugin.VerboseLogging.Value && _dumped.Add(((Object)root).name)) { Dump(root, why); } } catch (Exception ex) { if (Plugin.VerboseLogging.Value) { Plugin.Log.LogWarning((object)("Shield tint failed: " + ex.Message)); } } } private static void TintSystem(ParticleSystem ps, Color c) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) MainModule main = ps.main; ((MainModule)(ref main)).startColor = Retint(((MainModule)(ref main)).startColor, c); ColorOverLifetimeModule colorOverLifetime = ps.colorOverLifetime; if (((ColorOverLifetimeModule)(ref colorOverLifetime)).enabled) { ((ColorOverLifetimeModule)(ref colorOverLifetime)).color = Retint(((ColorOverLifetimeModule)(ref colorOverLifetime)).color, c); } ColorBySpeedModule colorBySpeed = ps.colorBySpeed; if (((ColorBySpeedModule)(ref colorBySpeed)).enabled) { ((ColorBySpeedModule)(ref colorBySpeed)).color = Retint(((ColorBySpeedModule)(ref colorBySpeed)).color, c); } TrailModule trails = ps.trails; if (((TrailModule)(ref trails)).enabled) { ((TrailModule)(ref trails)).colorOverLifetime = Retint(((TrailModule)(ref trails)).colorOverLifetime, c); ((TrailModule)(ref trails)).colorOverTrail = Retint(((TrailModule)(ref trails)).colorOverTrail, c); } } internal static MinMaxGradient Retint(MinMaxGradient src, Color c) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected I4, but got Unknown //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0096: 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_00ab: Unknown result type (might be due to invalid IL or missing references) ParticleSystemGradientMode mode = ((MinMaxGradient)(ref src)).mode; switch ((int)mode) { case 0: return new MinMaxGradient(Hue(((MinMaxGradient)(ref src)).color, c)); case 2: return new MinMaxGradient(Hue(((MinMaxGradient)(ref src)).colorMin, c), Hue(((MinMaxGradient)(ref src)).colorMax, c)); case 1: return new MinMaxGradient(Hue(((MinMaxGradient)(ref src)).gradient, c)); case 3: return new MinMaxGradient(Hue(((MinMaxGradient)(ref src)).gradientMin, c), Hue(((MinMaxGradient)(ref src)).gradientMax, c)); case 4: { MinMaxGradient result = default(MinMaxGradient); ((MinMaxGradient)(ref result))..ctor(Hue(((MinMaxGradient)(ref src)).gradient, c)); ((MinMaxGradient)(ref result)).mode = (ParticleSystemGradientMode)4; return result; } default: return src; } } private static Color Hue(Color k, Color c) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) float maxColorComponent = ((Color)(ref k)).maxColorComponent; if (maxColorComponent <= 0.0001f) { return k; } return new Color(c.r * maxColorComponent, c.g * maxColorComponent, c.b * maxColorComponent, k.a); } private static Gradient Hue(Gradient g, Color c) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown if (g == null) { return null; } GradientColorKey[] colorKeys = g.colorKeys; GradientColorKey[] array = (GradientColorKey[])(object)new GradientColorKey[colorKeys.Length]; for (int i = 0; i < colorKeys.Length; i++) { array[i] = new GradientColorKey(Hue(colorKeys[i].color, c), colorKeys[i].time); } Gradient val = new Gradient { mode = g.mode }; val.SetKeys(array, g.alphaKeys); return val; } internal static void Tick() { TickParryFlash(); if (_instances.Count == 0) { return; } double timeAsDouble = Time.timeAsDouble; bool flag = !Plugin.WeActivated && timeAsDouble - Plugin.LastOurShieldReleaseTime >= 3.0; if (!_restored && flag) { foreach (KeyValuePair instance in _instances) { ParticleSystemRenderer key = instance.Key; Instanced value = instance.Value; if ((Object)(object)key != (Object)null && (Object)(object)value.Original != (Object)null && ((Renderer)key).sharedMaterial == value.Instance) { ((Renderer)key).sharedMaterial = value.Original; } } _restored = true; } if (timeAsDouble - _lastSweep < 5.0) { return; } _lastSweep = timeAsDouble; _sweep.Clear(); foreach (KeyValuePair instance2 in _instances) { if ((Object)(object)instance2.Key == (Object)null) { _sweep.Add(instance2.Key); } } foreach (ParticleSystemRenderer item in _sweep) { if (_instances.TryGetValue(item, out var value2) && (Object)(object)value2.Instance != (Object)null) { Object.Destroy((Object)(object)value2.Instance); } _instances.Remove(item); } if (_sweep.Count > 0 && Plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)$"Shield tint: released {_sweep.Count} material instance(s) for destroyed renderers."); } BubbleMaterialTintPatch.Sweep(); } internal static void DestroyAll() { foreach (KeyValuePair instance in _instances) { ParticleSystemRenderer key = instance.Key; Instanced value = instance.Value; if ((Object)(object)key != (Object)null && (Object)(object)value.Original != (Object)null && ((Renderer)key).sharedMaterial == value.Instance) { ((Renderer)key).sharedMaterial = value.Original; } if ((Object)(object)value.Instance != (Object)null) { Object.Destroy((Object)(object)value.Instance); } } _instances.Clear(); _dumped.Clear(); _restored = true; _armed = null; BubbleMaterialTintPatch.DestroyAll(); } private static void Dump(Transform root, string why) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: 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_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("Shield VFX '" + ((Object)root).name + "' tinted via " + why + ":"); foreach (ParticleSystem system in _systems) { MainModule main = system.main; ColorOverLifetimeModule colorOverLifetime = system.colorOverLifetime; string name = ((Object)system).name; MinMaxGradient val = ((MainModule)(ref main)).startColor; object arg = ((MinMaxGradient)(ref val)).mode; object arg2; if (!((ColorOverLifetimeModule)(ref colorOverLifetime)).enabled) { arg2 = "off"; } else { val = ((ColorOverLifetimeModule)(ref colorOverLifetime)).color; arg2 = ((object)((MinMaxGradient)(ref val)).mode/*cast due to .constrained prefix*/).ToString(); } string text = $"\n PS '{name}' startColor={arg} col={arg2}"; CustomDataModule customData = system.customData; object obj; if (!((CustomDataModule)(ref customData)).enabled) { obj = "off"; } else { customData = system.customData; obj = ((object)((CustomDataModule)(ref customData)).GetMode((ParticleSystemCustomData)0)/*cast due to .constrained prefix*/).ToString(); } MinMaxCurve startDelay = ((MainModule)(ref main)).startDelay; stringBuilder.Append(text + " custom1=" + (string?)obj + $" delay={((MinMaxCurve)(ref startDelay)).constant:0.00} loop={((MainModule)(ref main)).loop}"); ParticleSystemRenderer component = ((Component)system).GetComponent(); Material val2 = (((Object)(object)component != (Object)null) ? ((Renderer)component).sharedMaterial : null); if (!((Object)(object)val2 != (Object)null)) { continue; } stringBuilder.Append($"\n mat '{((Object)val2).name}' shader '{((Object)val2.shader).name}' handler={(Object)(object)((Component)component).GetComponentInParent() != (Object)null}"); Shader shader = val2.shader; int propertyCount = shader.GetPropertyCount(); for (int i = 0; i < propertyCount; i++) { if ((int)shader.GetPropertyType(i) == 0) { stringBuilder.Append($" {shader.GetPropertyName(i)}={val2.GetColor(shader.GetPropertyName(i))}"); } } } Plugin.Log.LogInfo((object)stringBuilder.ToString()); } } [HarmonyPatch(typeof(PlayerInfo), "OnIsElectromagnetShieldActiveChanged")] internal static class ShieldVfxTintHook { private static void Prefix(PlayerInfo __instance) { ShieldTint.Arm(__instance); if (Plugin.VerboseLogging.Value && Local.Is(__instance) && Plugin.WeActivated) { Plugin.Log.LogInfo((object)$"Shield hook fired {(Time.timeAsDouble - Plugin.LastActivationTime) * 1000.0:0} ms after activation (active={__instance.IsElectromagnetShieldActive})."); } } private static void Postfix(PlayerInfo __instance) { if (Local.Is(__instance)) { ShieldTint.OnShieldHookDone(__instance); } else { ShieldTint.Disarm(); } } } [HarmonyPatch(typeof(PlayerInfo), "PlayElectromagnetShieldHitInternal")] internal static class ShieldHitTintHook { private static void Prefix(PlayerInfo __instance) { ShieldTint.Arm(__instance); } private static void Postfix() { ShieldTint.Disarm(); } } [HarmonyPatch(typeof(TeamColorVfxHandler), "SetTeam")] internal static class TeamColorSetTeamPatch { private static void Postfix(TeamColorVfxHandler __instance) { ShieldTint.OnSetTeam(__instance); } } [HarmonyPatch(typeof(BubbleVfxMaterialHandler), "Update")] internal static class BubbleMaterialTintPatch { private class Tinted { public Material Normal; public Material Stencil; public Color Color; } private static readonly Dictionary _reg = new Dictionary(); private static FieldRef _renderer; private static FieldRef _normal; private static FieldRef _stencil; private static Transform _ourShieldRoot; private static int _ourShieldFrame = -1; private static readonly List _regSweep = new List(); private static bool Prepare() { try { _renderer = AccessTools.FieldRefAccess("particleSystemRenderer"); _normal = AccessTools.FieldRefAccess("normalMaterial"); _stencil = AccessTools.FieldRefAccess("stencilMaterial"); return true; } catch (Exception ex) { Plugin.Log.LogWarning((object)("BubbleVfxMaterialHandler fields not found; shield tint will be overridden by the game. " + ex.Message)); return false; } } internal static void Register(BubbleVfxMaterialHandler h, Color c) { //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Expected O, but got Unknown //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)h == (Object)null || _normal == null) { return; } if (!_reg.TryGetValue(h, out var value)) { value = new Tinted(); _reg[h] = value; } Material val = _normal.Invoke(h); Material val2 = _stencil.Invoke(h); if ((Object)(object)value.Normal == (Object)null && (Object)(object)val != (Object)null) { value.Normal = new Material(val); } if ((Object)(object)value.Stencil == (Object)null && (Object)(object)val2 != (Object)null) { value.Stencil = new Material(val2); } if (value.Color != c || (Object)(object)value.Normal == (Object)null) { value.Color = c; if ((Object)(object)value.Normal != (Object)null && (Object)(object)val != (Object)null) { value.Normal.CopyPropertiesFromMaterial(val); TintMaterial(value.Normal, c); } if ((Object)(object)value.Stencil != (Object)null && (Object)(object)val2 != (Object)null) { value.Stencil.CopyPropertiesFromMaterial(val2); TintMaterial(value.Stencil, c); } } ParticleSystemRenderer val3 = _renderer.Invoke(h); if ((Object)(object)val3 != (Object)null) { Swap(val3, value); } } internal static void TintMaterial(Material m, Color c) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) Shader shader = m.shader; int propertyCount = shader.GetPropertyCount(); for (int i = 0; i < propertyCount; i++) { if ((int)shader.GetPropertyType(i) == 0) { string propertyName = shader.GetPropertyName(i); Color color = m.GetColor(propertyName); float num = Mathf.Max(((Color)(ref color)).maxColorComponent, 1f); m.SetColor(propertyName, new Color(c.r * num, c.g * num, c.b * num, color.a)); } } } private static bool StillOurs(BubbleVfxMaterialHandler h) { if (!Plugin.WeActivated && Time.timeAsDouble - Plugin.LastOurShieldReleaseTime >= 3.0) { return false; } if (_ourShieldFrame != Time.frameCount) { _ourShieldFrame = Time.frameCount; PlayerInfo localPlayerInfo = GameManager.LocalPlayerInfo; SphereCollider val = (((Object)(object)localPlayerInfo != (Object)null) ? localPlayerInfo.ElectromagnetShieldCollider : null); _ourShieldRoot = (((Object)(object)val != (Object)null) ? ((Component)val).transform : null); } if ((Object)(object)_ourShieldRoot != (Object)null) { return ((Component)h).transform.IsChildOf(_ourShieldRoot); } return false; } private static void Swap(ParticleSystemRenderer r, Tinted t) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) LevelBoundsTracker cameraLevelBoundsTracker = GameManager.CameraLevelBoundsTracker; if ((Object)(object)cameraLevelBoundsTracker == (Object)null) { return; } float num = float.NegativeInfinity; SecondaryOutOfBoundsHazard currentSecondaryHazardLocalOnly = cameraLevelBoundsTracker.CurrentSecondaryHazardLocalOnly; if ((Object)(object)currentSecondaryHazardLocalOnly == (Object)null) { if ((int)MainOutOfBoundsHazard.Type == 0) { num = cameraLevelBoundsTracker.CurrentOutOfBoundsHazardWorldHeightLocalOnly; } } else if ((int)currentSecondaryHazardLocalOnly.Type == 0) { num = cameraLevelBoundsTracker.CurrentOutOfBoundsHazardWorldHeightLocalOnly; } Material val = ((((Component)cameraLevelBoundsTracker).transform.position.y > num) ? t.Stencil : t.Normal); if ((Object)(object)val == (Object)null) { val = t.Normal ?? t.Stencil; } if ((Object)(object)val != (Object)null && ((Renderer)r).sharedMaterial != val) { ((Renderer)r).sharedMaterial = val; } } [HarmonyPriority(200)] private static bool Prefix(BubbleVfxMaterialHandler __instance) { try { if (!_reg.TryGetValue(__instance, out var value)) { return true; } if (!StillOurs(__instance)) { Release(__instance, value); return true; } ParticleSystemRenderer val = _renderer.Invoke(__instance); if ((Object)(object)val == (Object)null) { return false; } Swap(val, value); return false; } catch (Exception ex) { Plugin.Log.LogWarning((object)("Bubble tint error, reverting to vanilla for this handler: " + ex.Message)); try { _reg.Remove(__instance); } catch { } return true; } } private static void Release(BubbleVfxMaterialHandler h, Tinted t) { _reg.Remove(h); if (t != null) { if ((Object)(object)t.Normal != (Object)null) { Object.Destroy((Object)(object)t.Normal); } if ((Object)(object)t.Stencil != (Object)null) { Object.Destroy((Object)(object)t.Stencil); } } } internal static void Sweep() { if (_reg.Count == 0) { return; } _regSweep.Clear(); foreach (KeyValuePair item in _reg) { if ((Object)(object)item.Key == (Object)null) { _regSweep.Add(item.Key); } } foreach (BubbleVfxMaterialHandler item2 in _regSweep) { if (_reg.TryGetValue(item2, out var value)) { if ((Object)(object)value.Normal != (Object)null) { Object.Destroy((Object)(object)value.Normal); } if ((Object)(object)value.Stencil != (Object)null) { Object.Destroy((Object)(object)value.Stencil); } } _reg.Remove(item2); } } internal static void DestroyAll() { foreach (KeyValuePair item in _reg) { if ((Object)(object)item.Value.Normal != (Object)null) { Object.Destroy((Object)(object)item.Value.Normal); } if ((Object)(object)item.Value.Stencil != (Object)null) { Object.Destroy((Object)(object)item.Value.Stencil); } } _reg.Clear(); _ourShieldRoot = null; } } }