Decompiled source of BubbleBoi v0.2.2

BubbleBoi.dll

Decompiled 3 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mirror;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("BubbleBoi")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("BubbleBoi")]
[assembly: AssemblyTitle("BubbleBoi")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 BubbleBoi
{
	[BepInPlugin("sbg.bubbleboi", "BubbleBoi", "0.2.2")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string ModGuid = "sbg.bubbleboi";

		public const string ModName = "BubbleBoi";

		public const string ModVersion = "0.2.2";

		internal static ManualLogSource Log;

		internal static Plugin Instance;

		internal ConfigEntry<bool> verboseLoggingConfig;

		internal ConfigEntry<float> expiryWarningSecondsConfig;

		internal ConfigEntry<bool> expiryWarningEnabledConfig;

		private void Awake()
		{
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			verboseLoggingConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "VerboseLogging", false, "Emit per-frame water-walk decision logs. Off by default — flip on when reporting issues so the log shows why synthetic ground was/wasn't injected.");
			expiryWarningEnabledConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "ExpiryWarningEnabled", true, "Tint the local player's electromagnet shield orange→red in the final seconds before it expires.");
			expiryWarningSecondsConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "ExpiryWarningSeconds", 3.5f, "Window before shield expiry over which the warning hue ramps in. The first half is orange-tinted, the last half ramps to red.");
			WaterSurfaceProxy.EnsureCreated();
			new Harmony("sbg.bubbleboi").PatchAll();
			Log.LogInfo((object)"BubbleBoi v0.2.2 loaded.");
		}
	}
	internal static class WaterSurfaceProxy
	{
		private static BoxCollider collider;

		internal static Collider Collider
		{
			get
			{
				EnsureCreated();
				return (Collider)(object)collider;
			}
		}

		internal static void EnsureCreated()
		{
			//IL_0013: 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_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)collider != (Object)null))
			{
				GameObject val = new GameObject("BubbleBoiWaterSurfaceProxy")
				{
					hideFlags = (HideFlags)61
				};
				Object.DontDestroyOnLoad((Object)val);
				collider = val.AddComponent<BoxCollider>();
				((Collider)collider).enabled = false;
				((Collider)collider).isTrigger = false;
				collider.size = new Vector3(1f, 0.1f, 1f);
			}
		}
	}
	internal sealed class ShieldExpiryTinter : MonoBehaviour
	{
		private static readonly Color OrangeWarning = new Color(1f, 0.55f, 0.1f, 1f);

		private static readonly int[] ColorPropertyIds = new int[4]
		{
			Shader.PropertyToID("_TintColor"),
			Shader.PropertyToID("_Color"),
			Shader.PropertyToID("_BaseColor"),
			Shader.PropertyToID("_EmissionColor")
		};

		private static ShieldExpiryTinter instance;

		private static MaterialPropertyBlock block;

		private PlayerInfo target;

		private double activationTimestamp;

		private Renderer[] cachedRenderers;

		private readonly Dictionary<ParticleSystem, MinMaxGradient> originalStartColors = new Dictionary<ParticleSystem, MinMaxGradient>();

		private bool tintApplied;

		public static void OnLocalShieldActivated(PlayerInfo player)
		{
			EnsureInstance();
			instance.target = player;
			instance.activationTimestamp = Time.timeAsDouble;
			instance.cachedRenderers = null;
			instance.originalStartColors.Clear();
			instance.tintApplied = false;
		}

		private static void EnsureInstance()
		{
			//IL_0013: 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_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			if (!((Object)(object)instance != (Object)null))
			{
				GameObject val = new GameObject("BubbleBoiShieldExpiryTinter")
				{
					hideFlags = (HideFlags)61
				};
				Object.DontDestroyOnLoad((Object)val);
				instance = val.AddComponent<ShieldExpiryTinter>();
				block = new MaterialPropertyBlock();
			}
		}

		private void Update()
		{
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: 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_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: 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_00fe: 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)
			if ((Object)(object)target == (Object)null)
			{
				return;
			}
			if (!target.IsElectromagnetShieldActive)
			{
				if (tintApplied)
				{
					ResetTint();
				}
				target = null;
				cachedRenderers = null;
				return;
			}
			Plugin plugin = Plugin.Instance;
			if ((Object)(object)plugin == (Object)null || !plugin.expiryWarningEnabledConfig.Value)
			{
				if (tintApplied)
				{
					ResetTint();
				}
				return;
			}
			float num = (((Object)(object)GameManager.ItemSettings != (Object)null) ? GameManager.ItemSettings.ElectromagnetShieldDuration : 5f) - (float)(Time.timeAsDouble - activationTimestamp);
			float value = plugin.expiryWarningSecondsConfig.Value;
			if (num > value || num <= 0f)
			{
				if (tintApplied)
				{
					ResetTint();
				}
			}
			else
			{
				float num2 = 1f - num / value;
				Color tint = ((num2 < 0.5f) ? Color.Lerp(Color.white, OrangeWarning, num2 * 2f) : Color.Lerp(OrangeWarning, Color.red, (num2 - 0.5f) * 2f));
				EnsureRenderers();
				ApplyTint(tint);
				tintApplied = true;
			}
		}

		private void EnsureRenderers()
		{
			if ((cachedRenderers == null || cachedRenderers.Length == 0) && !((Object)(object)target == (Object)null) && !((Object)(object)target.ElectromagnetShieldCollider == (Object)null))
			{
				cachedRenderers = ((Component)target.ElectromagnetShieldCollider).GetComponentsInChildren<Renderer>(true);
			}
		}

		private void ApplyTint(Color tint)
		{
			//IL_009e: 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_0068: 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_006d: 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_0058: Unknown result type (might be due to invalid IL or missing references)
			if (cachedRenderers == null)
			{
				return;
			}
			Renderer[] array = cachedRenderers;
			ParticleSystem val2 = default(ParticleSystem);
			foreach (Renderer val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				if (val is ParticleSystemRenderer && ((Component)val).TryGetComponent<ParticleSystem>(ref val2))
				{
					if (!originalStartColors.ContainsKey(val2))
					{
						Dictionary<ParticleSystem, MinMaxGradient> dictionary = originalStartColors;
						ParticleSystem key = val2;
						MainModule main = val2.main;
						dictionary[key] = ((MainModule)(ref main)).startColor;
					}
					MainModule main2 = val2.main;
					((MainModule)(ref main2)).startColor = new MinMaxGradient(tint);
				}
				else
				{
					val.GetPropertyBlock(block);
					int[] colorPropertyIds = ColorPropertyIds;
					foreach (int num in colorPropertyIds)
					{
						block.SetColor(num, tint);
					}
					val.SetPropertyBlock(block);
				}
			}
		}

		private void ResetTint()
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: 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)
			if (cachedRenderers != null)
			{
				Renderer[] array = cachedRenderers;
				foreach (Renderer val in array)
				{
					if (!((Object)(object)val == (Object)null) && !(val is ParticleSystemRenderer))
					{
						val.SetPropertyBlock((MaterialPropertyBlock)null);
					}
				}
			}
			foreach (KeyValuePair<ParticleSystem, MinMaxGradient> originalStartColor in originalStartColors)
			{
				if (!((Object)(object)originalStartColor.Key == (Object)null))
				{
					MainModule main = originalStartColor.Key.main;
					((MainModule)(ref main)).startColor = originalStartColor.Value;
				}
			}
			originalStartColors.Clear();
			tintApplied = false;
		}
	}
	[HarmonyPatch]
	internal static class WaterWalkPatches
	{
		private const float DecisionLogIntervalSeconds = 1f;

		private static readonly FieldInfo UprightColliderField = AccessTools.Field(typeof(PlayerMovement), "uprightCollider");

		private static readonly FieldInfo GroundDataField = AccessTools.Field(typeof(PlayerMovement), "<GroundData>k__BackingField");

		private static readonly MethodInfo NoClipEnabledGetter = AccessTools.PropertyGetter(typeof(PlayerMovement), "NoClipEnabled");

		private static readonly Dictionary<int, double> LastDecisionLogTimes = new Dictionary<int, double>();

		private static readonly Dictionary<int, bool> LastInjectedGroundState = new Dictionary<int, bool>();

		[HarmonyPatch(typeof(PlayerMovement), "PerformGroundCheck")]
		[HarmonyPostfix]
		private static void PerformGroundCheckPostfix(PlayerMovement __instance, ref bool __result)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: 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_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: 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)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: 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_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: 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_0122: 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_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: 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_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: 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_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			if (!TryGetWaterSurfacePoint(__instance, out var waterPoint, out var reason))
			{
				if (__result)
				{
					TrackInjectedGroundState(__instance, isInjected: false);
				}
				else
				{
					MaybeLogDecision(__instance, "synthetic ground skipped: " + reason);
				}
				TrackInjectedGroundState(__instance, isInjected: false);
				return;
			}
			if (__result)
			{
				Vector3 point = __instance.GroundData.point;
				if (point.y >= waterPoint.y - 0.05f)
				{
					MaybeLogDecision(__instance, $"keeping vanilla ground at y={point.y:F3} (water y={waterPoint.y:F3})");
					TrackInjectedGroundState(__instance, isInjected: false);
					return;
				}
				MaybeLogDecision(__instance, $"vanilla ground submerged y={point.y:F3} < water y={waterPoint.y:F3} — overriding with synthetic surface");
			}
			object? obj = UprightColliderField?.GetValue(__instance);
			CapsuleCollider val = (CapsuleCollider)((obj is CapsuleCollider) ? obj : null);
			if ((Object)(object)val == (Object)null)
			{
				MaybeLogDecision(__instance, "synthetic ground skipped: uprightCollider missing");
				TrackInjectedGroundState(__instance, isInjected: false);
				return;
			}
			Vector3 val2 = ((Component)val).transform.TransformPoint(val.center);
			float num = val.center.y + 0.35f;
			if (val2.y - waterPoint.y > num)
			{
				MaybeLogDecision(__instance, $"synthetic ground skipped: water surface too far below ray origin ({val2.y - waterPoint.y:F3}m > {num:F3}m)");
				TrackInjectedGroundState(__instance, isInjected: false);
				return;
			}
			__instance.NetworkgroundTerrainType = (GroundTerrainType)0;
			__instance.NetworkgroundTerrainDominantGlobalLayer = (TerrainLayer)0;
			GroundDataField?.SetValue(__instance, (object)new PlayerGroundData
			{
				point = waterPoint,
				contactPoint = waterPoint,
				normal = Vector3.up,
				collider = WaterSurfaceProxy.Collider,
				hasRigidbody = false,
				rigidbody = null
			});
			bool flag = __result;
			__result = true;
			object[] obj2 = new object[4]
			{
				waterPoint.y,
				__instance.Position.y,
				flag,
				null
			};
			PlayerInfo playerInfo = __instance.PlayerInfo;
			BoundsState? obj3;
			if (playerInfo == null)
			{
				obj3 = null;
			}
			else
			{
				LevelBoundsTracker levelBoundsTracker = playerInfo.LevelBoundsTracker;
				obj3 = ((levelBoundsTracker != null) ? new BoundsState?(levelBoundsTracker.AuthoritativeBoundsState) : null);
			}
			obj2[3] = obj3;
			MaybeLogDecision(__instance, string.Format("synthetic ground injected at waterY={0:F3}, playerY={1:F3}, replacedVanillaGround={2}, bounds={3}", obj2));
			TrackInjectedGroundState(__instance, isInjected: true);
		}

		[HarmonyPatch(typeof(PlayerMovement), "FixedUpdate")]
		[HarmonyPostfix]
		private static void FixedUpdatePostfix(PlayerMovement __instance)
		{
			//IL_004e: 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_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)
			//IL_0063: 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_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: 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_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			if (!TryGetWaterSurfacePoint(__instance, out var waterPoint, out var _))
			{
				return;
			}
			PlayerInfo playerInfo = __instance.PlayerInfo;
			if ((Object)(object)((playerInfo != null) ? playerInfo.LevelBoundsTracker : null) == (Object)null)
			{
				return;
			}
			PlayerInfo playerInfo2 = __instance.PlayerInfo;
			Rigidbody val = ((playerInfo2 != null) ? playerInfo2.Rigidbody : null);
			if ((Object)(object)val == (Object)null || val.isKinematic)
			{
				return;
			}
			Vector3 position = val.position;
			if (!(position.y >= waterPoint.y))
			{
				float num = waterPoint.y - position.y;
				position.y = waterPoint.y;
				val.position = position;
				Vector3 linearVelocity = val.linearVelocity;
				if (linearVelocity.y < 0f)
				{
					linearVelocity.y = 0f;
					val.linearVelocity = linearVelocity;
				}
				MaybeLogDecision(__instance, $"surface correction applied: raised by {num:F3}m to waterY={waterPoint.y:F3}", force: true);
			}
		}

		[HarmonyPatch(typeof(PlayerMovement), "OnServerBoundsStateChanged")]
		[HarmonyPrefix]
		private static bool OnServerBoundsStateChangedPrefix(PlayerMovement __instance, BoundsState currentState)
		{
			//IL_0000: 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_003d: 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_004b: Unknown result type (might be due to invalid IL or missing references)
			if (!BoundsStateExtensions.IsInOutOfBoundsHazard(currentState))
			{
				return true;
			}
			if (!ShouldWaterWalk(__instance))
			{
				MaybeLogDecision(__instance, $"server hazard passthrough: currentState={currentState}, reason=water-walk conditions not met");
				return true;
			}
			PlayerInfo playerInfo = __instance.PlayerInfo;
			if (IsWaterHazard((playerInfo != null) ? playerInfo.LevelBoundsTracker : null, currentState))
			{
				MaybeLogDecision(__instance, $"server water elimination suppressed: currentState={currentState}");
				return false;
			}
			MaybeLogDecision(__instance, $"server hazard passthrough: currentState={currentState}, reason=hazard is not water");
			return true;
		}

		private static bool TryGetWaterSurfacePoint(PlayerMovement movement, out Vector3 waterPoint, out string reason)
		{
			//IL_0001: 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_0075: 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)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			waterPoint = default(Vector3);
			reason = string.Empty;
			if (!ShouldWaterWalkLocally(movement))
			{
				reason = "local water-walk conditions not met";
				return false;
			}
			PlayerInfo playerInfo = movement.PlayerInfo;
			LevelBoundsTracker val = ((playerInfo != null) ? playerInfo.LevelBoundsTracker : null);
			if ((Object)(object)val == (Object)null)
			{
				reason = "level bounds tracker missing";
				return false;
			}
			if (!IsWaterHazard(val, val.AuthoritativeBoundsState) && !val.IsInOrOverOutOfBoundsHazard())
			{
				reason = $"not over a water hazard (bounds={val.AuthoritativeBoundsState})";
				return false;
			}
			waterPoint = movement.Position;
			waterPoint.y = val.CurrentOutOfBoundsHazardWorldHeightLocalOnly;
			return true;
		}

		private static bool ShouldWaterWalk(PlayerMovement movement)
		{
			//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)
			if ((Object)(object)movement == (Object)null)
			{
				return false;
			}
			if ((Object)(object)movement.PlayerInfo == (Object)null || !movement.PlayerInfo.IsElectromagnetShieldActive)
			{
				return false;
			}
			GolfCartSeat activeGolfCartSeat = movement.PlayerInfo.ActiveGolfCartSeat;
			if (((GolfCartSeat)(ref activeGolfCartSeat)).IsValid())
			{
				return false;
			}
			if ((bool)(NoClipEnabledGetter?.Invoke(null, null) ?? ((object)false)))
			{
				return false;
			}
			return true;
		}

		private static bool ShouldWaterWalkLocally(PlayerMovement movement)
		{
			if ((Object)(object)movement != (Object)null && ((NetworkBehaviour)movement).isLocalPlayer)
			{
				return ShouldWaterWalk(movement);
			}
			return false;
		}

		private static void TrackInjectedGroundState(PlayerMovement movement, bool isInjected)
		{
			if (!((Object)(object)movement == (Object)null))
			{
				int instanceID = ((Object)movement).GetInstanceID();
				if (!LastInjectedGroundState.TryGetValue(instanceID, out var value) || value != isInjected)
				{
					LastInjectedGroundState[instanceID] = isInjected;
					MaybeLogDecision(movement, isInjected ? "synthetic ground state changed: active" : "synthetic ground state changed: inactive", force: true);
				}
			}
		}

		private static void MaybeLogDecision(PlayerMovement movement, string message, bool force = false)
		{
			//IL_010e: 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_0144: 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_019d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)movement == (Object)null || Plugin.Log == null || (Object)(object)Plugin.Instance == (Object)null || !Plugin.Instance.verboseLoggingConfig.Value)
			{
				return;
			}
			int instanceID = ((Object)movement).GetInstanceID();
			double timeAsDouble = Time.timeAsDouble;
			if (force || !LastDecisionLogTimes.TryGetValue(instanceID, out var value) || !(timeAsDouble - value < 1.0))
			{
				LastDecisionLogTimes[instanceID] = timeAsDouble;
				PlayerInfo playerInfo = movement.PlayerInfo;
				LevelBoundsTracker val = ((playerInfo != null) ? playerInfo.LevelBoundsTracker : null);
				ManualLogSource log = Plugin.Log;
				string[] obj = new string[12]
				{
					"[BubbleBoi] player=",
					((playerInfo != null) ? ((Object)playerInfo).name : null) ?? ((Object)movement).name,
					" ",
					$"local={((NetworkBehaviour)movement).isLocalPlayer} shield={playerInfo != null && playerInfo.IsElectromagnetShieldActive} ",
					$"grounded={movement.IsGrounded} visible={movement.IsVisible} ",
					null,
					null,
					null,
					null,
					null,
					null,
					null
				};
				int num;
				if (playerInfo == null)
				{
					num = 0;
				}
				else
				{
					GolfCartSeat activeGolfCartSeat = playerInfo.ActiveGolfCartSeat;
					num = (((GolfCartSeat)(ref activeGolfCartSeat)).IsValid() ? 1 : 0);
				}
				obj[5] = $"inCart={(byte)num != 0} ";
				obj[6] = "bounds=";
				object obj2;
				if (!((Object)(object)val != (Object)null))
				{
					obj2 = "null";
				}
				else
				{
					BoundsState authoritativeBoundsState = val.AuthoritativeBoundsState;
					obj2 = ((object)(BoundsState)(ref authoritativeBoundsState)).ToString();
				}
				obj[7] = (string)obj2;
				obj[8] = " waterY=";
				obj[9] = (((Object)(object)val != (Object)null) ? val.CurrentOutOfBoundsHazardWorldHeightLocalOnly.ToString("F3") : "n/a");
				obj[10] = " ";
				obj[11] = $"posY={movement.Position.y:F3} :: {message}";
				log.LogInfo((object)string.Concat(obj));
			}
		}

		[HarmonyPatch(typeof(PlayerInfo), "LocalPlayerActivateElectromagnetShield")]
		[HarmonyPostfix]
		private static void LocalPlayerActivateElectromagnetShieldPostfix(PlayerInfo __instance)
		{
			ShieldExpiryTinter.OnLocalShieldActivated(__instance);
		}

		private static bool IsWaterHazard(LevelBoundsTracker tracker, BoundsState boundsState)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Invalid comparison between Unknown and I4
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Invalid comparison between Unknown and I4
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Invalid comparison between Unknown and I4
			if ((Object)(object)tracker == (Object)null)
			{
				return false;
			}
			if (BoundsStateExtensions.HasState(boundsState, (BoundsState)1))
			{
				return (int)MainOutOfBoundsHazard.Type == 0;
			}
			if ((Object)(object)tracker.CurrentSecondaryHazardLocalOnly != (Object)null)
			{
				return (int)tracker.CurrentSecondaryHazardLocalOnly.Type == 0;
			}
			return (int)MainOutOfBoundsHazard.Type == 0;
		}
	}
}