Decompiled source of DeathHeadHopperFix v0.1.9

plugins\DeathHeadHopperFix.dll

Decompiled 3 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using DeathHeadHopper.DeathHead.Handlers;
using DeathHeadHopperFix.Modules.Battery;
using DeathHeadHopperFix.Modules.Config;
using DeathHeadHopperFix.Modules.Gameplay.Core.Abilities;
using DeathHeadHopperFix.Modules.Gameplay.Core.Audio;
using DeathHeadHopperFix.Modules.Gameplay.Core.Input;
using DeathHeadHopperFix.Modules.Gameplay.Core.Interop;
using DeathHeadHopperFix.Modules.Gameplay.Core.Runtime;
using DeathHeadHopperFix.Modules.Gameplay.Stun;
using DeathHeadHopperFix.Modules.Stamina;
using DeathHeadHopperFix.Modules.Utilities;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 DeathHeadHopperFix
{
	[BepInPlugin("AdrenSnyder.DeathHeadHopperFix", "Death Head Hopper - Fix", "0.1.9")]
	public sealed class Plugin : BaseUnityPlugin
	{
		private const string TargetAssemblyName = "DeathHeadHopper";

		private Harmony? _harmony;

		private bool _patched;

		private Assembly? _targetAssembly;

		private static ManualLogSource? _log;

		private void Awake()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			_log = ((BaseUnityPlugin)this).Logger;
			ConfigManager.Initialize(((BaseUnityPlugin)this).Config);
			WarnUnsafeDebugFlagsInRelease();
			_harmony = new Harmony("AdrenSnyder.DeathHeadHopperFix");
			_harmony.PatchAll(typeof(Plugin).Assembly);
			DHHApiGuardModule.DetectGameApiChanges();
			ApplyEarlyPatches();
			AppDomain.CurrentDomain.AssemblyLoad += OnAssemblyLoad;
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly asm in assemblies)
			{
				TryPatchIfTargetAssembly(asm);
			}
		}

		private void OnDestroy()
		{
			AppDomain.CurrentDomain.AssemblyLoad -= OnAssemblyLoad;
		}

		private void OnAssemblyLoad(object sender, AssemblyLoadEventArgs args)
		{
			TryPatchIfTargetAssembly(args.LoadedAssembly);
		}

		private void ApplyEarlyPatches()
		{
			if (_harmony != null)
			{
				StatsModule.ApplyHooks(_harmony);
				ItemUpgradeModule.Apply(_harmony);
			}
		}

		private void TryPatchIfTargetAssembly(Assembly asm)
		{
			if (_patched || asm == null)
			{
				return;
			}
			string name = asm.GetName().Name;
			if (!string.Equals(name, "DeathHeadHopper", StringComparison.OrdinalIgnoreCase))
			{
				return;
			}
			try
			{
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogInfo((object)"Detected DeathHeadHopper assembly load. Applying patches...");
				}
				Harmony harmony = _harmony;
				if (harmony == null)
				{
					throw new InvalidOperationException("Harmony instance is null.");
				}
				PrefabModule.Apply(harmony, asm, _log);
				AudioModule.Apply(harmony, asm, _log);
				DHHShopModule.Apply(harmony, asm, _log);
				_targetAssembly = asm;
				DHHApiGuardModule.Apply(harmony, asm);
				BatteryJumpPatchModule.Apply(harmony, asm);
				JumpForceModule.Apply(harmony, asm, _log);
				ChargeAbilityTuningModule.Apply(harmony, asm);
				ChargeHoldReleaseModule.Apply(harmony, asm, _log);
				InputModule.Apply(harmony, asm, _log);
				AbilityModule.ApplyAbilitySpotLabelOverlay(harmony, asm);
				AbilityModule.ApplyAbilityManagerHooks(harmony, asm);
				_patched = true;
				ManualLogSource? log2 = _log;
				if (log2 != null)
				{
					log2.LogInfo((object)"Patches applied successfully.");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource? log3 = _log;
				if (log3 != null)
				{
					log3.LogError((object)ex);
				}
			}
		}

		private void WarnUnsafeDebugFlagsInRelease()
		{
			if (!Debug.isDebugBuild && (InternalDebugFlags.DisableBatteryModule || InternalDebugFlags.DisableAbilityPatches || InternalDebugFlags.DisableSpectateChecks))
			{
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogWarning((object)("[DebugSafety] Internal debug bypass flags are enabled in a non-debug build. " + $"DisableBatteryModule={InternalDebugFlags.DisableBatteryModule}, " + $"DisableAbilityPatches={InternalDebugFlags.DisableAbilityPatches}, " + $"DisableSpectateChecks={InternalDebugFlags.DisableSpectateChecks}"));
				}
			}
		}
	}
}
namespace DeathHeadHopperFix.Modules.Utilities
{
	internal static class ItemHelpers
	{
		internal static string? GetItemAssetName(Object? itemAsset)
		{
			if (itemAsset == (Object)null)
			{
				return null;
			}
			Type type = ((object)itemAsset).GetType();
			PropertyInfo property = type.GetProperty("itemAssetName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (property != null && property.PropertyType == typeof(string))
			{
				return ((string)property.GetValue(itemAsset, null)) ?? itemAsset.name;
			}
			FieldInfo field = type.GetField("itemAssetName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null && field.FieldType == typeof(string))
			{
				return ((string)field.GetValue(itemAsset)) ?? itemAsset.name;
			}
			return itemAsset.name;
		}
	}
	internal static class LastChanceInteropBridge
	{
		private const BindingFlags StaticAny = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

		private static Type? s_timerControllerType;

		private static Type? s_spectateHelperType;

		private static Type? s_featureFlagsType;

		private static Type? s_imageAssetLoaderType;

		private static PropertyInfo? s_isActiveProperty;

		private static PropertyInfo? s_directionUiVisibleProperty;

		private static MethodInfo? s_isDirectionEnergySufficientMethod;

		private static MethodInfo? s_getDirectionPenaltyPreviewMethod;

		private static MethodInfo? s_getDirectionEnergyDebugSnapshotMethod;

		private static MethodInfo? s_isPlayerSurrenderedForDataMethod;

		private static MethodInfo? s_allPlayersDisabledMethod;

		private static MethodInfo? s_resetForceStateMethod;

		private static MethodInfo? s_shouldForceLocalDeathHeadSpectateMethod;

		private static MethodInfo? s_ensureSpectatePlayerLocalMethod;

		private static MethodInfo? s_forceDeathHeadSpectateIfPossibleMethod;

		private static MethodInfo? s_debugLogStateMethod;

		private static MethodInfo? s_isManualSwitchInputDownMethod;

		private static FieldInfo? s_lastChanceModeField;

		private static FieldInfo? s_spectateDeadPlayersField;

		private static FieldInfo? s_spectateDeadPlayersModeField;

		private static FieldInfo? s_lastChanceIndicatorsField;

		private static MethodInfo? s_tryLoadSpriteMethod;

		internal static bool IsLastChanceActive()
		{
			return TryGetBoolProperty(ref s_isActiveProperty, "DeathHeadHopperFix.Modules.Gameplay.LastChance.Runtime.LastChanceTimerController", "IsActive");
		}

		internal static bool IsDirectionIndicatorUiVisible()
		{
			return TryGetBoolProperty(ref s_directionUiVisibleProperty, "DeathHeadHopperFix.Modules.Gameplay.LastChance.Runtime.LastChanceTimerController", "IsDirectionIndicatorUiVisible");
		}

		internal static bool IsDirectionIndicatorEnergySufficientPreview()
		{
			ResolveMembers();
			if (s_isDirectionEnergySufficientMethod == null)
			{
				return false;
			}
			return (s_isDirectionEnergySufficientMethod.Invoke(null, null) as bool?).GetValueOrDefault();
		}

		internal static float GetDirectionIndicatorPenaltySecondsPreview()
		{
			ResolveMembers();
			if (s_getDirectionPenaltyPreviewMethod == null)
			{
				return 0f;
			}
			return (s_getDirectionPenaltyPreviewMethod.Invoke(null, null) as float?).GetValueOrDefault();
		}

		internal static void GetDirectionIndicatorEnergyDebugSnapshot(out bool visible, out float timerRemaining, out float penaltyPreview, out bool hasEnoughEnergy)
		{
			visible = false;
			timerRemaining = 0f;
			penaltyPreview = 0f;
			hasEnoughEnergy = false;
			ResolveMembers();
			if (!(s_getDirectionEnergyDebugSnapshotMethod == null))
			{
				object[] array = new object[4] { false, 0f, 0f, false };
				s_getDirectionEnergyDebugSnapshotMethod.Invoke(null, array);
				visible = (array[0] as bool?).GetValueOrDefault();
				timerRemaining = (array[1] as float?).GetValueOrDefault();
				penaltyPreview = (array[2] as float?).GetValueOrDefault();
				hasEnoughEnergy = (array[3] as bool?).GetValueOrDefault();
			}
		}

		internal static bool IsPlayerSurrenderedForData(PlayerAvatar? player)
		{
			ResolveMembers();
			if (s_isPlayerSurrenderedForDataMethod == null)
			{
				return false;
			}
			return (s_isPlayerSurrenderedForDataMethod.Invoke(null, new object[1] { player }) as bool?).GetValueOrDefault();
		}

		internal static bool AllPlayersDisabled()
		{
			ResolveMembers();
			if (s_allPlayersDisabledMethod == null)
			{
				return false;
			}
			return (s_allPlayersDisabledMethod.Invoke(null, null) as bool?).GetValueOrDefault();
		}

		internal static void ResetSpectateForceState()
		{
			ResolveMembers();
			s_resetForceStateMethod?.Invoke(null, null);
		}

		internal static bool ShouldForceLocalDeathHeadSpectate()
		{
			ResolveMembers();
			if (s_shouldForceLocalDeathHeadSpectateMethod == null)
			{
				return false;
			}
			return (s_shouldForceLocalDeathHeadSpectateMethod.Invoke(null, null) as bool?).GetValueOrDefault();
		}

		internal static void EnsureSpectatePlayerLocal(SpectateCamera? spectate)
		{
			ResolveMembers();
			s_ensureSpectatePlayerLocalMethod?.Invoke(null, new object[1] { spectate });
		}

		internal static void ForceDeathHeadSpectateIfPossible()
		{
			ResolveMembers();
			s_forceDeathHeadSpectateIfPossibleMethod?.Invoke(null, null);
		}

		internal static void DebugLogState(SpectateCamera? spectate)
		{
			ResolveMembers();
			s_debugLogStateMethod?.Invoke(null, new object[1] { spectate });
		}

		internal static bool IsManualSwitchInputDown()
		{
			ResolveMembers();
			if (s_isManualSwitchInputDownMethod == null)
			{
				return false;
			}
			return (s_isManualSwitchInputDownMethod.Invoke(null, null) as bool?).GetValueOrDefault();
		}

		internal static bool IsLastChanceModeEnabled()
		{
			ResolveMembers();
			if (s_lastChanceModeField == null)
			{
				return false;
			}
			return (s_lastChanceModeField.GetValue(null) as bool?).GetValueOrDefault();
		}

		internal static bool IsSpectateDeadPlayersEnabled()
		{
			ResolveMembers();
			if (s_spectateDeadPlayersField == null)
			{
				return false;
			}
			return (s_spectateDeadPlayersField.GetValue(null) as bool?).GetValueOrDefault();
		}

		internal static string GetSpectateDeadPlayersMode()
		{
			ResolveMembers();
			if (s_spectateDeadPlayersModeField == null)
			{
				return string.Empty;
			}
			return (s_spectateDeadPlayersModeField.GetValue(null) as string) ?? string.Empty;
		}

		internal static string GetLastChanceIndicatorsMode()
		{
			ResolveMembers();
			if (s_lastChanceIndicatorsField == null)
			{
				return string.Empty;
			}
			return (s_lastChanceIndicatorsField.GetValue(null) as string) ?? string.Empty;
		}

		internal static bool TryGetDirectionSlotSprite(out Sprite? sprite)
		{
			sprite = null;
			ResolveMembers();
			if (s_tryLoadSpriteMethod == null)
			{
				return false;
			}
			object[] array = new object[5]
			{
				"Direction.png",
				null,
				null,
				string.Empty,
				100f
			};
			if (!(s_tryLoadSpriteMethod.Invoke(null, array) as bool?).GetValueOrDefault())
			{
				return false;
			}
			object obj = array[2];
			sprite = (Sprite?)((obj is Sprite) ? obj : null);
			return (Object)(object)sprite != (Object)null;
		}

		private static bool TryGetBoolProperty(ref PropertyInfo? property, string typeName, string propertyName)
		{
			ResolveMembers();
			if (property == null)
			{
				property = ResolveType(typeName)?.GetProperty(propertyName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			}
			return (property?.GetValue(null) as bool?).GetValueOrDefault();
		}

		private static void ResolveMembers()
		{
			if ((object)s_timerControllerType == null)
			{
				s_timerControllerType = ResolveType("DeathHeadHopperFix.Modules.Gameplay.LastChance.Runtime.LastChanceTimerController");
			}
			if ((object)s_spectateHelperType == null)
			{
				s_spectateHelperType = ResolveType("DeathHeadHopperFix.Modules.Gameplay.LastChance.Spectate.LastChanceSpectateHelper");
			}
			if ((object)s_featureFlagsType == null)
			{
				s_featureFlagsType = ResolveType("DHHFLastChanceMode.Modules.Config.FeatureFlags");
			}
			if ((object)s_imageAssetLoaderType == null)
			{
				s_imageAssetLoaderType = ResolveType("DeathHeadHopperFix.Modules.Utilities.ImageAssetLoader");
			}
			if (s_timerControllerType != null)
			{
				if ((object)s_isDirectionEnergySufficientMethod == null)
				{
					s_isDirectionEnergySufficientMethod = s_timerControllerType.GetMethod("IsDirectionIndicatorEnergySufficientPreview", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				}
				if ((object)s_getDirectionPenaltyPreviewMethod == null)
				{
					s_getDirectionPenaltyPreviewMethod = s_timerControllerType.GetMethod("GetDirectionIndicatorPenaltySecondsPreview", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				}
				if ((object)s_getDirectionEnergyDebugSnapshotMethod == null)
				{
					s_getDirectionEnergyDebugSnapshotMethod = s_timerControllerType.GetMethod("GetDirectionIndicatorEnergyDebugSnapshot", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				}
				if ((object)s_isPlayerSurrenderedForDataMethod == null)
				{
					s_isPlayerSurrenderedForDataMethod = s_timerControllerType.GetMethod("IsPlayerSurrenderedForData", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				}
			}
			if (s_spectateHelperType != null)
			{
				if ((object)s_allPlayersDisabledMethod == null)
				{
					s_allPlayersDisabledMethod = s_spectateHelperType.GetMethod("AllPlayersDisabled", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				}
				if ((object)s_resetForceStateMethod == null)
				{
					s_resetForceStateMethod = s_spectateHelperType.GetMethod("ResetForceState", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				}
				if ((object)s_shouldForceLocalDeathHeadSpectateMethod == null)
				{
					s_shouldForceLocalDeathHeadSpectateMethod = s_spectateHelperType.GetMethod("ShouldForceLocalDeathHeadSpectate", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				}
				if ((object)s_ensureSpectatePlayerLocalMethod == null)
				{
					s_ensureSpectatePlayerLocalMethod = s_spectateHelperType.GetMethod("EnsureSpectatePlayerLocal", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				}
				if ((object)s_forceDeathHeadSpectateIfPossibleMethod == null)
				{
					s_forceDeathHeadSpectateIfPossibleMethod = s_spectateHelperType.GetMethod("ForceDeathHeadSpectateIfPossible", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				}
				if ((object)s_debugLogStateMethod == null)
				{
					s_debugLogStateMethod = s_spectateHelperType.GetMethod("DebugLogState", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				}
				if ((object)s_isManualSwitchInputDownMethod == null)
				{
					s_isManualSwitchInputDownMethod = s_spectateHelperType.GetMethod("IsManualSwitchInputDown", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				}
			}
			if (s_featureFlagsType != null)
			{
				if ((object)s_lastChanceModeField == null)
				{
					s_lastChanceModeField = s_featureFlagsType.GetField("LastChangeMode", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				}
				if ((object)s_spectateDeadPlayersField == null)
				{
					s_spectateDeadPlayersField = s_featureFlagsType.GetField("SpectateDeadPlayers", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				}
				if ((object)s_spectateDeadPlayersModeField == null)
				{
					s_spectateDeadPlayersModeField = s_featureFlagsType.GetField("SpectateDeadPlayersMode", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				}
				if ((object)s_lastChanceIndicatorsField == null)
				{
					s_lastChanceIndicatorsField = s_featureFlagsType.GetField("LastChanceIndicators", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				}
			}
			if (s_imageAssetLoaderType != null && (object)s_tryLoadSpriteMethod == null)
			{
				s_tryLoadSpriteMethod = s_imageAssetLoaderType.GetMethod("TryLoadSprite", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			}
		}

		private static Type? ResolveType(string fullName)
		{
			Type type = Type.GetType(fullName, throwOnError: false);
			if (type != null)
			{
				return type;
			}
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				type = assembly.GetType(fullName, throwOnError: false);
				if (type != null)
				{
					return type;
				}
			}
			return null;
		}
	}
	internal static class LogLimiter
	{
		public const int DefaultFrameInterval = 240;

		private static readonly Dictionary<string, int> _lastFrameByKey = new Dictionary<string, int>(StringComparer.Ordinal);

		public static bool ShouldLog(string key, int frameInterval = 240)
		{
			if (string.IsNullOrEmpty(key))
			{
				return true;
			}
			if (frameInterval <= 0)
			{
				return true;
			}
			int frameCount = Time.frameCount;
			if (_lastFrameByKey.TryGetValue(key, out var value) && frameCount - value < frameInterval)
			{
				return false;
			}
			_lastFrameByKey[key] = frameCount;
			return true;
		}

		public static void Reset(string key)
		{
			if (!string.IsNullOrEmpty(key))
			{
				_lastFrameByKey.Remove(key);
			}
		}

		public static void Clear()
		{
			_lastFrameByKey.Clear();
		}
	}
	internal static class NetworkProtocol
	{
		internal const string ModId = "DeathHeadHopperFix";

		internal const int ProtocolVersion = 1;

		internal const string RoomKeyPrefix = "DeathHeadHopperFix.Room.";

		internal static string BuildRoomKey(string localKey)
		{
			return string.IsNullOrWhiteSpace(localKey) ? "DeathHeadHopperFix.Room." : ("DeathHeadHopperFix.Room." + localKey.Trim());
		}
	}
	internal readonly struct NetworkEnvelope
	{
		internal string ModId { get; }

		internal int ProtocolVersion { get; }

		internal string MessageType { get; }

		internal int MessageSeq { get; }

		internal object? Payload { get; }

		internal NetworkEnvelope(string modId, int protocolVersion, string messageType, int messageSeq, object? payload)
		{
			ModId = (string.IsNullOrWhiteSpace(modId) ? string.Empty : modId.Trim());
			ProtocolVersion = protocolVersion;
			MessageType = (string.IsNullOrWhiteSpace(messageType) ? string.Empty : messageType.Trim());
			MessageSeq = messageSeq;
			Payload = payload;
		}

		internal object?[] ToEventPayload()
		{
			return new object[5] { ModId, ProtocolVersion, MessageType, MessageSeq, Payload };
		}

		internal bool IsExpectedSource()
		{
			return ModId == "DeathHeadHopperFix" && ProtocolVersion == 1 && !string.IsNullOrWhiteSpace(MessageType);
		}

		internal static bool TryParse(object? customData, out NetworkEnvelope envelope)
		{
			envelope = default(NetworkEnvelope);
			if (!(customData is object[] array) || array.Length < 5)
			{
				return false;
			}
			if (array[0] is string modId && array[1] is int protocolVersion && array[2] is string messageType)
			{
				object obj = array[3];
				int messageSeq = default(int);
				int num;
				if (obj is int)
				{
					messageSeq = (int)obj;
					num = 1;
				}
				else
				{
					num = 0;
				}
				if (num != 0)
				{
					envelope = new NetworkEnvelope(modId, protocolVersion, messageType, messageSeq, array[4]);
					return true;
				}
			}
			return false;
		}
	}
	internal static class PhotonEventCodes
	{
		internal const byte ConfigSync = 79;
	}
	internal static class PlayerStateExtractionHelper
	{
		internal readonly struct PlayerStateSnapshot
		{
			internal int ActorNumber { get; }

			internal int SteamIdShort { get; }

			internal string Name { get; }

			internal Color Color { get; }

			internal bool IsAlive { get; }

			internal bool IsDead { get; }

			internal bool IsInTruck { get; }

			internal bool IsSurrendered { get; }

			internal int SourceOrder { get; }

			internal PlayerStateSnapshot(int actorNumber, int steamIdShort, string name, Color color, bool isAlive, bool isDead, bool isInTruck, bool isSurrendered, int sourceOrder)
			{
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				ActorNumber = actorNumber;
				SteamIdShort = steamIdShort;
				Name = name;
				Color = color;
				IsAlive = isAlive;
				IsDead = isDead;
				IsInTruck = isInTruck;
				IsSurrendered = isSurrendered;
				SourceOrder = sourceOrder;
			}
		}

		private static readonly FieldInfo? s_playerNameField = AccessTools.Field(typeof(PlayerAvatar), "playerName");

		private static readonly FieldInfo? s_playerDeadSetField = AccessTools.Field(typeof(PlayerAvatar), "deadSet");

		private static readonly FieldInfo? s_playerIsDisabledField = AccessTools.Field(typeof(PlayerAvatar), "isDisabled");

		private static readonly FieldInfo? s_playerRoomVolumeCheckField = AccessTools.Field(typeof(PlayerAvatar), "RoomVolumeCheck");

		private static readonly FieldInfo? s_playerSteamIdShortField = AccessTools.Field(typeof(PlayerAvatar), "steamIDshort");

		private static readonly FieldInfo? s_visualColorField = AccessTools.Field(typeof(PlayerAvatarVisuals), "color");

		private static FieldInfo? s_roomVolumeCheckInTruckField;

		private static FieldInfo? s_deathHeadInTruckField;

		private static FieldInfo? s_deathHeadRoomVolumeCheckField;

		internal static List<PlayerStateSnapshot> GetPlayersStateSnapshot()
		{
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: 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)
			List<PlayerStateSnapshot> list = new List<PlayerStateSnapshot>();
			GameDirector instance = GameDirector.instance;
			if ((Object)(object)instance == (Object)null || instance.PlayerList == null || instance.PlayerList.Count == 0)
			{
				return list;
			}
			for (int i = 0; i < instance.PlayerList.Count; i++)
			{
				PlayerAvatar val = instance.PlayerList[i];
				if (!((Object)(object)val == (Object)null))
				{
					PhotonView photonView = val.photonView;
					int? obj;
					if (photonView == null)
					{
						obj = null;
					}
					else
					{
						Player owner = photonView.Owner;
						obj = ((owner != null) ? new int?(owner.ActorNumber) : null);
					}
					int? num = obj;
					int valueOrDefault = num.GetValueOrDefault();
					int steamIdShort = GetSteamIdShort(val);
					string playerName = GetPlayerName(val);
					Color playerColor = GetPlayerColor(val);
					bool flag = IsDeadSet(val);
					bool flag2 = IsDisabled(val);
					bool flag3 = flag || flag2;
					bool isAlive = !flag3;
					bool isInTruck = IsPlayerInTruck(val, flag2);
					bool isSurrendered = LastChanceInteropBridge.IsPlayerSurrenderedForData(val);
					list.Add(new PlayerStateSnapshot(valueOrDefault, steamIdShort, playerName, playerColor, isAlive, flag3, isInTruck, isSurrendered, i));
				}
			}
			list.Sort(CompareSnapshotOrder);
			return list;
		}

		internal static List<PlayerStateSnapshot> GetPlayersStillInLastChance()
		{
			List<PlayerStateSnapshot> playersStateSnapshot = GetPlayersStateSnapshot();
			List<PlayerStateSnapshot> list = new List<PlayerStateSnapshot>(playersStateSnapshot.Count);
			for (int i = 0; i < playersStateSnapshot.Count; i++)
			{
				PlayerStateSnapshot item = playersStateSnapshot[i];
				if (!item.IsSurrendered)
				{
					list.Add(item);
				}
			}
			return list;
		}

		private static int CompareSnapshotOrder(PlayerStateSnapshot left, PlayerStateSnapshot right)
		{
			if (left.ActorNumber > 0 && right.ActorNumber > 0)
			{
				return left.ActorNumber.CompareTo(right.ActorNumber);
			}
			return left.SourceOrder.CompareTo(right.SourceOrder);
		}

		private static string GetPlayerName(PlayerAvatar player)
		{
			if (s_playerNameField != null && s_playerNameField.GetValue(player) is string text && !string.IsNullOrWhiteSpace(text))
			{
				return text;
			}
			return "unknown";
		}

		private static Color GetPlayerColor(PlayerAvatar player)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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_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_0059: 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_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			PlayerAvatarVisuals playerAvatarVisuals = player.playerAvatarVisuals;
			if ((Object)(object)playerAvatarVisuals == (Object)null)
			{
				return Color.black;
			}
			if (s_visualColorField != null && s_visualColorField.GetValue(playerAvatarVisuals) is Color result)
			{
				return result;
			}
			return Color.black;
		}

		private static bool IsDeadSet(PlayerAvatar player)
		{
			bool flag = default(bool);
			int num;
			if (s_playerDeadSetField != null)
			{
				object value = s_playerDeadSetField.GetValue(player);
				if (value is bool)
				{
					flag = (bool)value;
					num = 1;
				}
				else
				{
					num = 0;
				}
			}
			else
			{
				num = 0;
			}
			return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
		}

		private static bool IsDisabled(PlayerAvatar player)
		{
			bool flag = default(bool);
			int num;
			if (s_playerIsDisabledField != null)
			{
				object value = s_playerIsDisabledField.GetValue(player);
				if (value is bool)
				{
					flag = (bool)value;
					num = 1;
				}
				else
				{
					num = 0;
				}
			}
			else
			{
				num = 0;
			}
			return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
		}

		private static bool IsPlayerInTruck(PlayerAvatar player, bool isDisabled)
		{
			if (!isDisabled)
			{
				object roomVolumeCheck = GetRoomVolumeCheck(player);
				return roomVolumeCheck != null && IsRoomVolumeInTruck(roomVolumeCheck);
			}
			PlayerDeathHead playerDeathHead = player.playerDeathHead;
			if ((Object)(object)playerDeathHead == (Object)null)
			{
				return false;
			}
			object deathHeadRoomVolumeCheck = GetDeathHeadRoomVolumeCheck(playerDeathHead);
			if (deathHeadRoomVolumeCheck != null)
			{
				return IsRoomVolumeInTruck(deathHeadRoomVolumeCheck);
			}
			FieldInfo deathHeadInTruckField = GetDeathHeadInTruckField(((object)playerDeathHead).GetType());
			bool flag = default(bool);
			int num;
			if (deathHeadInTruckField != null)
			{
				object value = deathHeadInTruckField.GetValue(playerDeathHead);
				if (value is bool)
				{
					flag = (bool)value;
					num = 1;
				}
				else
				{
					num = 0;
				}
			}
			else
			{
				num = 0;
			}
			return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
		}

		private static object? GetRoomVolumeCheck(PlayerAvatar player)
		{
			if (s_playerRoomVolumeCheckField == null)
			{
				return null;
			}
			return s_playerRoomVolumeCheckField.GetValue(player);
		}

		private static bool IsRoomVolumeInTruck(object roomVolumeCheck)
		{
			if (roomVolumeCheck == null)
			{
				return false;
			}
			FieldInfo fieldInfo = s_roomVolumeCheckInTruckField;
			if (fieldInfo == null || fieldInfo.DeclaringType != roomVolumeCheck.GetType())
			{
				fieldInfo = (s_roomVolumeCheckInTruckField = AccessTools.Field(roomVolumeCheck.GetType(), "inTruck"));
			}
			bool flag = default(bool);
			int num;
			if (fieldInfo != null)
			{
				object value = fieldInfo.GetValue(roomVolumeCheck);
				if (value is bool)
				{
					flag = (bool)value;
					num = 1;
				}
				else
				{
					num = 0;
				}
			}
			else
			{
				num = 0;
			}
			return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
		}

		private static FieldInfo? GetDeathHeadInTruckField(Type deathHeadType)
		{
			FieldInfo fieldInfo = s_deathHeadInTruckField;
			if (fieldInfo == null || fieldInfo.DeclaringType != deathHeadType)
			{
				fieldInfo = (s_deathHeadInTruckField = AccessTools.Field(deathHeadType, "inTruck"));
			}
			return fieldInfo;
		}

		private static object? GetDeathHeadRoomVolumeCheck(PlayerDeathHead deathHead)
		{
			FieldInfo fieldInfo = s_deathHeadRoomVolumeCheckField;
			if (fieldInfo == null || fieldInfo.DeclaringType != ((object)deathHead).GetType())
			{
				fieldInfo = (s_deathHeadRoomVolumeCheckField = AccessTools.Field(((object)deathHead).GetType(), "roomVolumeCheck"));
			}
			return fieldInfo?.GetValue(deathHead);
		}

		private static int GetSteamIdShort(PlayerAvatar player)
		{
			return (s_playerSteamIdShortField != null && s_playerSteamIdShortField.GetValue(player) is int num) ? num : 0;
		}
	}
	internal static class PlayerTruckDistanceHelper
	{
		[Flags]
		internal enum DistanceQueryFields
		{
			None = 0,
			Height = 1,
			NavMeshDistance = 2,
			RoomPath = 4,
			All = 7
		}

		internal readonly struct PlayerTruckDistance
		{
			internal PlayerAvatar PlayerAvatar { get; }

			internal float NavMeshDistance { get; }

			internal float HeightDelta { get; }

			internal int ShortestRoomPathToTruck { get; }

			internal int TotalMapRooms { get; }

			internal bool HasValidPath { get; }

			internal PlayerTruckDistance(PlayerAvatar playerAvatar, float navMeshDistance, float heightDelta, int shortestRoomPathToTruck, int totalMapRooms, bool hasValidPath)
			{
				PlayerAvatar = playerAvatar;
				NavMeshDistance = navMeshDistance;
				HeightDelta = heightDelta;
				ShortestRoomPathToTruck = shortestRoomPathToTruck;
				TotalMapRooms = totalMapRooms;
				HasValidPath = hasValidPath;
			}
		}

		private sealed class CachedPlayerDistance
		{
			internal float NavMeshDistance = -1f;

			internal float HeightDelta;

			internal int ShortestRoomPathToTruck = -1;

			internal int TotalMapRooms = -1;

			internal bool HasValidPath;

			internal int RoomHash;

			internal float HeightUpdatedAt = float.NegativeInfinity;

			internal int LevelStamp;

			internal Vector3 LastKnownWorldPosition;
		}

		private readonly struct RemotePlayerHint
		{
			internal int RoomHash { get; }

			internal float HeightDelta { get; }

			internal int LevelStamp { get; }

			internal float UpdatedAt { get; }

			internal RemotePlayerHint(int roomHash, float heightDelta, int levelStamp, float updatedAt)
			{
				RoomHash = roomHash;
				HeightDelta = heightDelta;
				LevelStamp = levelStamp;
				UpdatedAt = updatedAt;
			}
		}

		private struct ActivationProfileStats
		{
			internal int Calls;

			internal int PlayersProcessed;

			internal int NavRefreshCount;

			internal int RoomRefreshCount;

			internal int RemoteHintUsedCount;

			internal float TotalMs;

			internal float SetupMs;

			internal float LoopMs;

			internal float MaxCallMs;
		}

		private const float HeightCacheTtlSeconds = 2f;

		private static readonly Type? s_levelGeneratorType = AccessTools.TypeByName("LevelGenerator");

		private static readonly FieldInfo? s_levelGeneratorInstanceField = ((s_levelGeneratorType == null) ? null : AccessTools.Field(s_levelGeneratorType, "Instance"));

		private static readonly FieldInfo? s_levelPathTruckField = ((s_levelGeneratorType == null) ? null : AccessTools.Field(s_levelGeneratorType, "LevelPathTruck"));

		private static readonly FieldInfo? s_levelPathPointsField = ((s_levelGeneratorType == null) ? null : AccessTools.Field(s_levelGeneratorType, "LevelPathPoints"));

		private static readonly Type? s_levelPointType = AccessTools.TypeByName("LevelPoint");

		private static readonly FieldInfo? s_levelPointTruckField = ((s_levelPointType == null) ? null : AccessTools.Field(s_levelPointType, "Truck"));

		private static readonly FieldInfo? s_levelPointRoomField = ((s_levelPointType == null) ? null : AccessTools.Field(s_levelPointType, "Room"));

		private static readonly FieldInfo? s_levelPointConnectedPointsField = ((s_levelPointType == null) ? null : AccessTools.Field(s_levelPointType, "ConnectedPoints"));

		private static readonly Type? s_roomVolumeType = AccessTools.TypeByName("RoomVolume");

		private static readonly FieldInfo? s_roomVolumeTruckField = ((s_roomVolumeType == null) ? null : AccessTools.Field(s_roomVolumeType, "Truck"));

		private static readonly FieldInfo? s_playerLastNavmeshField = AccessTools.Field(typeof(PlayerAvatar), "LastNavmeshPosition");

		private static readonly FieldInfo? s_playerRoomVolumeCheckField = AccessTools.Field(typeof(PlayerAvatar), "RoomVolumeCheck");

		private static readonly Type? s_playerDeathHeadType = AccessTools.TypeByName("PlayerDeathHead");

		private static readonly FieldInfo? s_playerDeathHeadRoomVolumeCheckField = ((s_playerDeathHeadType == null) ? null : AccessTools.Field(s_playerDeathHeadType, "roomVolumeCheck"));

		private static readonly FieldInfo? s_playerDeathHeadPhysGrabObjectField = ((s_playerDeathHeadType == null) ? null : AccessTools.Field(s_playerDeathHeadType, "physGrabObject"));

		private static readonly Type? s_physGrabObjectType = AccessTools.TypeByName("PhysGrabObject");

		private static readonly FieldInfo? s_physGrabObjectCenterPointField = ((s_physGrabObjectType == null) ? null : AccessTools.Field(s_physGrabObjectType, "centerPoint"));

		private static readonly Type? s_roomVolumeCheckType = AccessTools.TypeByName("RoomVolumeCheck");

		private static readonly FieldInfo? s_roomVolumeCheckCurrentRoomsField = ((s_roomVolumeCheckType == null) ? null : AccessTools.Field(s_roomVolumeCheckType, "CurrentRooms"));

		private static readonly Type? s_navMeshType = AccessTools.TypeByName("UnityEngine.AI.NavMesh");

		private static readonly Type? s_navMeshHitType = AccessTools.TypeByName("UnityEngine.AI.NavMeshHit");

		private static readonly Type? s_navMeshPathType = AccessTools.TypeByName("UnityEngine.AI.NavMeshPath");

		private static readonly MethodInfo? s_navMeshSamplePositionMethod = s_navMeshType?.GetMethod("SamplePosition", BindingFlags.Static | BindingFlags.Public, null, (s_navMeshHitType == null) ? null : new Type[4]
		{
			typeof(Vector3),
			s_navMeshHitType.MakeByRefType(),
			typeof(float),
			typeof(int)
		}, null);

		private static readonly PropertyInfo? s_navMeshHitPositionProperty = s_navMeshHitType?.GetProperty("position", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly FieldInfo? s_navMeshHitPositionField = s_navMeshHitType?.GetField("position", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly MethodInfo? s_navMeshCalculatePathMethod = s_navMeshType?.GetMethod("CalculatePath", BindingFlags.Static | BindingFlags.Public, null, new Type[4]
		{
			typeof(Vector3),
			typeof(Vector3),
			typeof(int),
			s_navMeshPathType
		}, null);

		private static readonly PropertyInfo? s_navMeshPathCornersProperty = s_navMeshPathType?.GetProperty("corners");

		private static object? s_cachedGraphLevelGenerator;

		private static int s_cachedGraphPointCount;

		private static Dictionary<object, HashSet<object>>? s_cachedRoomGraph;

		private static readonly Dictionary<int, CachedPlayerDistance> s_playerCache = new Dictionary<int, CachedPlayerDistance>();

		private static readonly Dictionary<int, RemotePlayerHint> s_remoteHints = new Dictionary<int, RemotePlayerHint>();

		private static object? s_cachedLevelGeneratorForPlayers;

		private static Vector3 s_cachedTruckPosition;

		private static bool s_hasCachedTruckPosition;

		private static int s_cachedLevelPointsCount;

		private static bool s_activationProfilingEnabled;

		private static ActivationProfileStats s_activationProfileStats;

		internal static void PrimeDistancesCache()
		{
			GetDistancesFromTruck(DistanceQueryFields.NavMeshDistance | DistanceQueryFields.RoomPath);
		}

		internal static PlayerTruckDistance[] GetDistancesFromTruck()
		{
			return GetDistancesFromTruck(DistanceQueryFields.All);
		}

		internal static PlayerTruckDistance[] GetDistancesFromTruck(DistanceQueryFields fields, ICollection<PlayerAvatar>? players = null, bool forceRefresh = false)
		{
			//IL_00f9: 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_0100: 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_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_04af: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_04bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_046e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0475: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				bool debugLogging = FeatureFlags.DebugLogging;
				float num = (debugLogging ? Time.realtimeSinceStartup : 0f);
				float num2 = num;
				float num3 = num;
				int num4 = 0;
				int num5 = 0;
				int num6 = 0;
				int num7 = 0;
				if (fields == DistanceQueryFields.None || s_levelGeneratorInstanceField == null)
				{
					return Array.Empty<PlayerTruckDistance>();
				}
				object value = s_levelGeneratorInstanceField.GetValue(null);
				if (value == null)
				{
					return Array.Empty<PlayerTruckDistance>();
				}
				List<object> allLevelPoints = GetAllLevelPoints(value);
				if (!TryGetTruckTarget(value, allLevelPoints, out Vector3 truckPosition, out object truckPoint))
				{
					return Array.Empty<PlayerTruckDistance>();
				}
				GameDirector instance = GameDirector.instance;
				if (instance?.PlayerList == null || instance.PlayerList.Count == 0)
				{
					return Array.Empty<PlayerTruckDistance>();
				}
				int num8 = allLevelPoints?.Count ?? 0;
				if (s_cachedLevelGeneratorForPlayers != value || !s_hasCachedTruckPosition || Vector3.SqrMagnitude(s_cachedTruckPosition - truckPosition) > 0.0001f || s_cachedLevelPointsCount != num8)
				{
					s_playerCache.Clear();
					s_remoteHints.Clear();
					s_cachedLevelGeneratorForPlayers = value;
					s_cachedTruckPosition = truckPosition;
					s_cachedLevelPointsCount = num8;
					s_hasCachedTruckPosition = true;
				}
				HashSet<int> hashSet = null;
				if (players != null)
				{
					hashSet = new HashSet<int>();
					foreach (PlayerAvatar player in players)
					{
						if (!((Object)(object)player == (Object)null))
						{
							hashSet.Add(GetPlayerKey(player));
						}
					}
					if (hashSet.Count == 0)
					{
						return Array.Empty<PlayerTruckDistance>();
					}
				}
				bool flag = (fields & DistanceQueryFields.RoomPath) != 0;
				bool flag2 = (fields & DistanceQueryFields.NavMeshDistance) != 0;
				bool flag3 = (fields & DistanceQueryFields.Height) != 0;
				Dictionary<object, HashSet<object>> dictionary = ((flag || flag2) ? GetOrBuildRoomGraph(value, allLevelPoints) : null);
				int totalMapRooms = ((dictionary != null && dictionary.Count > 0) ? dictionary.Count : (-1));
				int num9 = (((Object)(object)RunManager.instance != (Object)null) ? RunManager.instance.levelsCompleted : 0);
				if (debugLogging)
				{
					num2 = Time.realtimeSinceStartup;
					num3 = num2;
				}
				List<PlayerTruckDistance> list = new List<PlayerTruckDistance>(instance.PlayerList.Count);
				foreach (PlayerAvatar player2 in instance.PlayerList)
				{
					if ((Object)(object)player2 == (Object)null)
					{
						continue;
					}
					int playerKey = GetPlayerKey(player2);
					if (hashSet != null && !hashSet.Contains(playerKey))
					{
						continue;
					}
					if (!s_playerCache.TryGetValue(playerKey, out CachedPlayerDistance value2))
					{
						value2 = new CachedPlayerDistance();
						s_playerCache[playerKey] = value2;
					}
					Vector3 val = (value2.LastKnownWorldPosition = GetPlayerWorldPosition(player2));
					PhotonView photonView = player2.photonView;
					int? obj;
					if (photonView == null)
					{
						obj = null;
					}
					else
					{
						Player owner = photonView.Owner;
						obj = ((owner != null) ? new int?(owner.ActorNumber) : null);
					}
					int? num10 = obj;
					int valueOrDefault = num10.GetValueOrDefault();
					s_remoteHints.TryGetValue(valueOrDefault, out var value3);
					bool flag4 = SemiFunc.IsMasterClientOrSingleplayer() && SemiFunc.IsMultiplayer() && valueOrDefault > 0 && PhotonNetwork.LocalPlayer != null && valueOrDefault != PhotonNetwork.LocalPlayer.ActorNumber && value3.LevelStamp == num9;
					List<object> list2 = null;
					int num11 = value2.RoomHash;
					if (flag4)
					{
						num11 = value3.RoomHash;
						num6++;
					}
					else if (flag || flag2)
					{
						list2 = GetPlayerRooms(player2);
						num11 = ComputeRoomsHash(list2);
					}
					bool flag5 = num11 != value2.RoomHash;
					bool flag6 = value2.LevelStamp != num9;
					if (flag3)
					{
						float num12 = Time.unscaledTime - value2.HeightUpdatedAt;
						if (forceRefresh || flag6 || num12 < 0f || num12 > 2f)
						{
							if (flag4 && Time.unscaledTime - value3.UpdatedAt <= 2f)
							{
								value2.HeightDelta = value3.HeightDelta;
								value2.HeightUpdatedAt = value3.UpdatedAt;
							}
							else
							{
								value2.HeightDelta = val.y - truckPosition.y;
								value2.HeightUpdatedAt = Time.unscaledTime;
							}
						}
					}
					if (flag2 && (forceRefresh || flag6 || flag5))
					{
						float navMeshDistance = -1f;
						Vector3 navMeshPosition;
						bool flag7 = TryGetPlayerNavMeshPosition(player2, val, out navMeshPosition) && TryCalculatePathDistance(navMeshPosition, truckPosition, out navMeshDistance);
						value2.NavMeshDistance = (flag7 ? navMeshDistance : (-1f));
						value2.HasValidPath = flag7;
						num4++;
					}
					if (flag && (forceRefresh || flag6 || flag5))
					{
						if (list2 == null)
						{
							list2 = GetPlayerRooms(player2);
						}
						value2.ShortestRoomPathToTruck = ResolveShortestRoomPathToTruck(list2 ?? new List<object>(), truckPoint, dictionary);
						num5++;
					}
					if (flag || flag2)
					{
						value2.TotalMapRooms = totalMapRooms;
					}
					value2.RoomHash = num11;
					value2.LevelStamp = num9;
					list.Add(new PlayerTruckDistance(player2, value2.NavMeshDistance, value2.HeightDelta, value2.ShortestRoomPathToTruck, value2.TotalMapRooms, value2.HasValidPath));
					num7++;
				}
				if (debugLogging && s_activationProfilingEnabled)
				{
					float realtimeSinceStartup = Time.realtimeSinceStartup;
					float num13 = (realtimeSinceStartup - num) * 1000f;
					float num14 = (num2 - num) * 1000f;
					float num15 = (realtimeSinceStartup - num3) * 1000f;
					s_activationProfileStats.Calls++;
					s_activationProfileStats.PlayersProcessed += num7;
					s_activationProfileStats.NavRefreshCount += num4;
					s_activationProfileStats.RoomRefreshCount += num5;
					s_activationProfileStats.RemoteHintUsedCount += num6;
					s_activationProfileStats.TotalMs += num13;
					s_activationProfileStats.SetupMs += num14;
					s_activationProfileStats.LoopMs += num15;
					s_activationProfileStats.MaxCallMs = Mathf.Max(s_activationProfileStats.MaxCallMs, num13);
				}
				return list.ToArray();
			}
			catch (Exception ex)
			{
				LogReflectionHotPathException("GetDistancesFromTruck", ex);
				return Array.Empty<PlayerTruckDistance>();
			}
		}

		internal static void ApplyRemotePlayerHint(int actorNumber, int roomHash, float heightDelta, int levelStamp)
		{
			if (actorNumber > 0)
			{
				s_remoteHints[actorNumber] = new RemotePlayerHint(roomHash, heightDelta, levelStamp, Time.unscaledTime);
			}
		}

		internal static bool TryBuildLocalPlayerTruckHint(out int roomHash, out float heightDelta, out int levelStamp)
		{
			//IL_0196: 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_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			roomHash = 0;
			heightDelta = 0f;
			levelStamp = (((Object)(object)RunManager.instance != (Object)null) ? RunManager.instance.levelsCompleted : 0);
			try
			{
				if (!PhotonNetwork.InRoom || PhotonNetwork.LocalPlayer == null || s_levelGeneratorInstanceField == null)
				{
					return false;
				}
				object value = s_levelGeneratorInstanceField.GetValue(null);
				if (value == null)
				{
					return false;
				}
				List<object> allLevelPoints = GetAllLevelPoints(value);
				if (!TryGetTruckTarget(value, allLevelPoints, out Vector3 truckPosition, out object _))
				{
					return false;
				}
				GameDirector instance = GameDirector.instance;
				if (instance?.PlayerList == null || instance.PlayerList.Count == 0)
				{
					return false;
				}
				int actorNumber = PhotonNetwork.LocalPlayer.ActorNumber;
				PlayerAvatar val = null;
				for (int i = 0; i < instance.PlayerList.Count; i++)
				{
					PlayerAvatar val2 = instance.PlayerList[i];
					if (!((Object)(object)val2 == (Object)null))
					{
						PhotonView photonView = val2.photonView;
						int? obj;
						if (photonView == null)
						{
							obj = null;
						}
						else
						{
							Player owner = photonView.Owner;
							obj = ((owner != null) ? new int?(owner.ActorNumber) : null);
						}
						int? num = obj;
						if (num.GetValueOrDefault() == actorNumber)
						{
							val = val2;
							break;
						}
					}
				}
				if ((Object)(object)val == (Object)null)
				{
					return false;
				}
				List<object> playerRooms = GetPlayerRooms(val);
				roomHash = ComputeRoomsHash(playerRooms);
				Vector3 playerWorldPosition = GetPlayerWorldPosition(val);
				heightDelta = playerWorldPosition.y - truckPosition.y;
				return true;
			}
			catch (Exception ex)
			{
				LogReflectionHotPathException("TryBuildLocalPlayerTruckHint", ex);
				return false;
			}
		}

		private static void LogReflectionHotPathException(string context, Exception ex)
		{
			if (FeatureFlags.DebugLogging)
			{
				string key = "LastChance.Reflection.PlayerTruckDistance." + context;
				if (LogLimiter.ShouldLog(key, 600))
				{
					Debug.LogWarning((object)("[LastChance] Reflection hot-path failed in " + context + ": " + ex.GetType().Name + ": " + ex.Message));
				}
			}
		}

		internal static void BeginActivationProfiling()
		{
			s_activationProfileStats = default(ActivationProfileStats);
			s_activationProfilingEnabled = true;
		}

		internal static string EndActivationProfilingSummary()
		{
			s_activationProfilingEnabled = false;
			return $"calls={s_activationProfileStats.Calls} total={s_activationProfileStats.TotalMs:F1}ms setup={s_activationProfileStats.SetupMs:F1}ms loop={s_activationProfileStats.LoopMs:F1}ms maxCall={s_activationProfileStats.MaxCallMs:F1}ms players={s_activationProfileStats.PlayersProcessed} navRefresh={s_activationProfileStats.NavRefreshCount} roomRefresh={s_activationProfileStats.RoomRefreshCount} remoteHints={s_activationProfileStats.RemoteHintUsedCount}";
		}

		private static int GetPlayerKey(PlayerAvatar player)
		{
			PhotonView photonView = player.photonView;
			int? obj;
			if (photonView == null)
			{
				obj = null;
			}
			else
			{
				Player owner = photonView.Owner;
				obj = ((owner != null) ? new int?(owner.ActorNumber) : null);
			}
			int? num = obj;
			int valueOrDefault = num.GetValueOrDefault();
			if (valueOrDefault != 0)
			{
				return valueOrDefault;
			}
			return ((Object)player).GetInstanceID();
		}

		private static int ComputeRoomsHash(List<object> rooms)
		{
			int num = 17;
			for (int i = 0; i < rooms.Count; i++)
			{
				num = num * 31 + RuntimeHelpers.GetHashCode(rooms[i]);
			}
			return num;
		}

		private static Dictionary<object, HashSet<object>> GetOrBuildRoomGraph(object levelGenerator, List<object>? allLevelPoints)
		{
			int num = allLevelPoints?.Count ?? 0;
			if (s_cachedRoomGraph != null && levelGenerator == s_cachedGraphLevelGenerator && s_cachedGraphPointCount == num)
			{
				return s_cachedRoomGraph;
			}
			Dictionary<object, HashSet<object>> result = BuildRoomGraph(allLevelPoints);
			s_cachedGraphLevelGenerator = levelGenerator;
			s_cachedGraphPointCount = num;
			s_cachedRoomGraph = result;
			return result;
		}

		private static bool TryGetTruckTarget(object levelGenerator, List<object>? allLevelPoints, out Vector3 truckPosition, out object? truckPoint)
		{
			//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)
			truckPosition = Vector3.zero;
			truckPoint = null;
			if (s_levelPathTruckField != null)
			{
				object value = s_levelPathTruckField.GetValue(levelGenerator);
				if (TryGetLevelPointPosition(value, out truckPosition))
				{
					truckPoint = value;
					return true;
				}
			}
			if (allLevelPoints == null)
			{
				return false;
			}
			foreach (object allLevelPoint in allLevelPoints)
			{
				if (allLevelPoint == null || !TryIsTruckPoint(allLevelPoint) || !TryGetLevelPointPosition(allLevelPoint, out truckPosition))
				{
					continue;
				}
				truckPoint = allLevelPoint;
				return true;
			}
			return false;
		}

		private static List<object>? GetAllLevelPoints(object levelGenerator)
		{
			if (s_levelPathPointsField == null)
			{
				return null;
			}
			if (!(s_levelPathPointsField.GetValue(levelGenerator) is IEnumerable enumerable))
			{
				return null;
			}
			List<object> list = new List<object>();
			foreach (object item in enumerable)
			{
				if (item != null)
				{
					list.Add(item);
				}
			}
			return (list.Count > 0) ? list : null;
		}

		private static bool TryIsTruckPoint(object point)
		{
			if (point == null)
			{
				return false;
			}
			bool flag = default(bool);
			int num;
			if (s_levelPointTruckField != null)
			{
				object value = s_levelPointTruckField.GetValue(point);
				if (value is bool)
				{
					flag = (bool)value;
					num = 1;
				}
				else
				{
					num = 0;
				}
			}
			else
			{
				num = 0;
			}
			if (((uint)num & (flag ? 1u : 0u)) != 0)
			{
				return true;
			}
			if (s_levelPointRoomField != null && s_roomVolumeTruckField != null)
			{
				object value2 = s_levelPointRoomField.GetValue(point);
				bool flag2 = default(bool);
				int num2;
				if (value2 != null)
				{
					object value = s_roomVolumeTruckField.GetValue(value2);
					if (value is bool)
					{
						flag2 = (bool)value;
						num2 = 1;
					}
					else
					{
						num2 = 0;
					}
				}
				else
				{
					num2 = 0;
				}
				if (((uint)num2 & (flag2 ? 1u : 0u)) != 0)
				{
					return true;
				}
			}
			return false;
		}

		private static int ResolveShortestRoomPathToTruck(List<object> playerRooms, object? truckPoint, Dictionary<object, HashSet<object>>? roomGraph)
		{
			if (truckPoint == null || roomGraph == null || roomGraph.Count == 0)
			{
				return -1;
			}
			object levelPointRoom = GetLevelPointRoom(truckPoint);
			if (levelPointRoom == null || !roomGraph.ContainsKey(levelPointRoom))
			{
				return -1;
			}
			if (playerRooms.Count == 0)
			{
				return -1;
			}
			HashSet<object> hashSet = new HashSet<object>();
			Queue<(object, int)> queue = new Queue<(object, int)>();
			foreach (object playerRoom in playerRooms)
			{
				if (playerRoom != null && roomGraph.ContainsKey(playerRoom) && hashSet.Add(playerRoom))
				{
					queue.Enqueue((playerRoom, 0));
				}
			}
			while (queue.Count > 0)
			{
				var (obj, num) = queue.Dequeue();
				if (obj == levelPointRoom)
				{
					return num;
				}
				if (!roomGraph.TryGetValue(obj, out HashSet<object> value))
				{
					continue;
				}
				foreach (object item in value)
				{
					if (item != null && hashSet.Add(item))
					{
						queue.Enqueue((item, num + 1));
					}
				}
			}
			return -1;
		}

		private static List<object> GetPlayerRooms(PlayerAvatar player)
		{
			List<object> list = new List<object>();
			if ((Object)(object)player == (Object)null || s_playerRoomVolumeCheckField == null || s_roomVolumeCheckCurrentRoomsField == null)
			{
				return list;
			}
			object obj = null;
			PlayerDeathHead playerDeathHead = player.playerDeathHead;
			if ((Object)(object)playerDeathHead != (Object)null && s_playerDeathHeadRoomVolumeCheckField != null)
			{
				obj = s_playerDeathHeadRoomVolumeCheckField.GetValue(playerDeathHead);
			}
			if (obj == null)
			{
				obj = s_playerRoomVolumeCheckField.GetValue(player);
			}
			if (obj == null)
			{
				return list;
			}
			if (!(s_roomVolumeCheckCurrentRoomsField.GetValue(obj) is IEnumerable enumerable))
			{
				return list;
			}
			foreach (object item in enumerable)
			{
				if (item != null)
				{
					list.Add(item);
				}
			}
			return list;
		}

		private static Dictionary<object, HashSet<object>> BuildRoomGraph(List<object>? allLevelPoints)
		{
			Dictionary<object, HashSet<object>> dictionary = new Dictionary<object, HashSet<object>>();
			if (allLevelPoints == null || s_levelPointRoomField == null)
			{
				return dictionary;
			}
			foreach (object allLevelPoint in allLevelPoints)
			{
				if (allLevelPoint == null)
				{
					continue;
				}
				object levelPointRoom = GetLevelPointRoom(allLevelPoint);
				if (levelPointRoom == null)
				{
					continue;
				}
				if (!dictionary.ContainsKey(levelPointRoom))
				{
					dictionary[levelPointRoom] = new HashSet<object>();
				}
				IEnumerable<object> connectedPoints = GetConnectedPoints(allLevelPoint);
				if (connectedPoints == null)
				{
					continue;
				}
				foreach (object item in connectedPoints)
				{
					if (item == null)
					{
						continue;
					}
					object levelPointRoom2 = GetLevelPointRoom(item);
					if (levelPointRoom2 != null)
					{
						if (!dictionary.ContainsKey(levelPointRoom2))
						{
							dictionary[levelPointRoom2] = new HashSet<object>();
						}
						if (levelPointRoom != levelPointRoom2)
						{
							dictionary[levelPointRoom].Add(levelPointRoom2);
							dictionary[levelPointRoom2].Add(levelPointRoom);
						}
					}
				}
			}
			return dictionary;
		}

		private static object? GetLevelPointRoom(object levelPoint)
		{
			if (levelPoint == null || s_levelPointRoomField == null)
			{
				return null;
			}
			return s_levelPointRoomField.GetValue(levelPoint);
		}

		private static IEnumerable<object>? GetConnectedPoints(object levelPoint)
		{
			if (levelPoint == null || s_levelPointConnectedPointsField == null)
			{
				return null;
			}
			if (s_levelPointConnectedPointsField.GetValue(levelPoint) is IEnumerable enumerable)
			{
				List<object> list = new List<object>();
				foreach (object item in enumerable)
				{
					if (item != null)
					{
						list.Add(item);
					}
				}
				return (list.Count > 0) ? list : null;
			}
			return null;
		}

		private static bool TryGetLevelPointPosition(object? levelPoint, out Vector3 position)
		{
			//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_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_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			position = Vector3.zero;
			if (levelPoint == null)
			{
				return false;
			}
			Component val = (Component)((levelPoint is Component) ? levelPoint : null);
			if (val != null && (Object)(object)val != (Object)null)
			{
				position = val.transform.position;
				return true;
			}
			PropertyInfo property = levelPoint.GetType().GetProperty("transform", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (property != null)
			{
				object? value = property.GetValue(levelPoint);
				Transform val2 = (Transform)((value is Transform) ? value : null);
				if (val2 != null)
				{
					position = val2.position;
					return true;
				}
			}
			return false;
		}

		private static Vector3 GetPlayerWorldPosition(PlayerAvatar player)
		{
			//IL_000d: 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_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_0065: 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_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)
			if ((Object)(object)player == (Object)null)
			{
				return Vector3.zero;
			}
			PlayerDeathHead playerDeathHead = player.playerDeathHead;
			if ((Object)(object)playerDeathHead != (Object)null)
			{
				return ((Component)playerDeathHead).transform.position;
			}
			if ((Object)(object)player.playerTransform != (Object)null)
			{
				return player.playerTransform.position;
			}
			return ((Component)player).transform.position;
		}

		private static bool TryGetPlayerNavMeshPosition(PlayerAvatar player, Vector3 worldPosition, out Vector3 navMeshPosition)
		{
			//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_0020: 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_0036: 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_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: 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_0158: 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_016e: 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_00df: 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_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: 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_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			navMeshPosition = Vector3.zero;
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			if (TrySamplePosition(worldPosition, 8f, out var navMeshPosition2))
			{
				navMeshPosition = navMeshPosition2;
				return true;
			}
			PlayerDeathHead playerDeathHead = player.playerDeathHead;
			if ((Object)(object)playerDeathHead != (Object)null)
			{
				Vector3 val = ((Component)playerDeathHead).transform.position;
				if (s_playerDeathHeadPhysGrabObjectField != null && s_physGrabObjectCenterPointField != null)
				{
					object value = s_playerDeathHeadPhysGrabObjectField.GetValue(playerDeathHead);
					if (value != null && s_physGrabObjectCenterPointField.GetValue(value) is Vector3 val2)
					{
						val = val2;
					}
				}
				if (TrySamplePosition(val, 12f, out navMeshPosition2) || TrySamplePosition(val - Vector3.up * 0.5f, 18f, out navMeshPosition2) || TrySamplePosition(val, 30f, out navMeshPosition2))
				{
					navMeshPosition = navMeshPosition2;
					return true;
				}
				return false;
			}
			if (s_playerLastNavmeshField != null && s_playerLastNavmeshField.GetValue(player) is Vector3 val3 && val3 != Vector3.zero)
			{
				navMeshPosition = val3;
				return true;
			}
			return false;
		}

		private static bool TrySamplePosition(Vector3 worldPosition, float maxDistance, out Vector3 navMeshPosition)
		{
			//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_0066: 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_00d1: Unknown result type (might be due to invalid IL or missing references)
			navMeshPosition = Vector3.zero;
			if (s_navMeshType == null || s_navMeshHitType == null || s_navMeshSamplePositionMethod == null)
			{
				return false;
			}
			object obj = Activator.CreateInstance(s_navMeshHitType);
			if (obj == null)
			{
				return false;
			}
			object[] array = new object[4] { worldPosition, obj, maxDistance, -1 };
			if (!(s_navMeshSamplePositionMethod.Invoke(null, array) is bool flag) || !flag)
			{
				return false;
			}
			if (!TryGetNavMeshHitPosition(array[1], out var position))
			{
				return false;
			}
			navMeshPosition = position;
			return true;
		}

		private static bool TryGetNavMeshHitPosition(object? navHitBoxed, out Vector3 position)
		{
			//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_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_0056: 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_0085: 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_009a: 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)
			position = Vector3.zero;
			if (navHitBoxed == null)
			{
				return false;
			}
			if (s_navMeshHitPositionProperty != null && s_navMeshHitPositionProperty.GetValue(navHitBoxed) is Vector3 val)
			{
				position = val;
				return true;
			}
			if (s_navMeshHitPositionField != null && s_navMeshHitPositionField.GetValue(navHitBoxed) is Vector3 val2)
			{
				position = val2;
				return true;
			}
			return false;
		}

		private static bool TryCalculatePathDistance(Vector3 from, Vector3 to, out float navMeshDistance)
		{
			//IL_0072: 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_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_00e6: 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_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)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: 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)
			navMeshDistance = 0f;
			if (s_navMeshType == null || s_navMeshPathType == null || s_navMeshCalculatePathMethod == null || s_navMeshPathCornersProperty == null)
			{
				return false;
			}
			object obj = Activator.CreateInstance(s_navMeshPathType);
			if (obj == null)
			{
				return false;
			}
			object[] parameters = new object[4] { from, to, -1, obj };
			if (!(s_navMeshCalculatePathMethod.Invoke(null, parameters) is bool flag) || !flag)
			{
				return false;
			}
			if (!(s_navMeshPathCornersProperty.GetValue(obj) is Vector3[] array) || array.Length == 0)
			{
				navMeshDistance = Vector3.Distance(from, to);
				return true;
			}
			Vector3 val = from;
			float num = 0f;
			Vector3[] array2 = array;
			foreach (Vector3 val2 in array2)
			{
				num += Vector3.Distance(val, val2);
				val = val2;
			}
			navMeshDistance = num;
			return true;
		}
	}
	internal static class ReflectionHelper
	{
		internal static object? GetStaticInstanceByName(string typeName)
		{
			Type type = AccessTools.TypeByName(typeName);
			if (type == null)
			{
				return null;
			}
			return GetStaticInstanceValue(type, "instance");
		}

		internal static object? GetStaticInstanceValue(Type type, string name)
		{
			FieldInfo field = type.GetField(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null)
			{
				return field.GetValue(null);
			}
			PropertyInfo property = type.GetProperty(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			if (property != null)
			{
				return property.GetValue(null, null);
			}
			return null;
		}
	}
	internal static class SpectateContextHelper
	{
		private static readonly FieldInfo? s_spectatePlayerField = AccessTools.Field(typeof(SpectateCamera), "player");

		private static readonly FieldInfo? s_playerDeathHeadSpectatedField = AccessTools.Field(typeof(PlayerDeathHead), "spectated");

		internal static bool IsSpectatingLocalPlayerTarget()
		{
			SpectateCamera instance = SpectateCamera.instance;
			PlayerAvatar instance2 = PlayerAvatar.instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance2 == (Object)null || s_spectatePlayerField == null)
			{
				return false;
			}
			object? value = s_spectatePlayerField.GetValue(instance);
			PlayerAvatar val = (PlayerAvatar)((value is PlayerAvatar) ? value : null);
			return (Object)(object)val != (Object)null && val == instance2;
		}

		internal static bool IsSpectatingLocalDeathHead()
		{
			SpectateCamera instance = SpectateCamera.instance;
			if ((Object)(object)instance == (Object)null || !instance.CheckState((State)2))
			{
				return false;
			}
			PlayerDeathHead val = PlayerController.instance?.playerAvatarScript?.playerDeathHead;
			if ((Object)(object)val == (Object)null || s_playerDeathHeadSpectatedField == null)
			{
				return false;
			}
			return (s_playerDeathHeadSpectatedField.GetValue(val) as bool?).GetValueOrDefault();
		}

		internal static bool IsLocalDeathHeadSpectated()
		{
			PlayerDeathHead val = PlayerController.instance?.playerAvatarScript?.playerDeathHead;
			if ((Object)(object)val == (Object)null || s_playerDeathHeadSpectatedField == null)
			{
				return false;
			}
			return (s_playerDeathHeadSpectatedField.GetValue(val) as bool?).GetValueOrDefault();
		}
	}
}
namespace DeathHeadHopperFix.Modules.Stamina
{
	internal sealed class StaminaRechargeModule : MonoBehaviour
	{
		private static readonly Type? s_deathHeadControllerType = AccessTools.TypeByName("DeathHeadHopper.DeathHead.DeathHeadController");

		private object? _controllerInstance;

		private PhotonView? _photonView;

		private bool _isOwner;

		private float _rechargeAccumulator;

		private Rigidbody? _rb;

		private void Awake()
		{
			if (s_deathHeadControllerType == null)
			{
				((Behaviour)this).enabled = false;
				return;
			}
			_controllerInstance = ((Component)this).GetComponent(s_deathHeadControllerType);
			if (_controllerInstance == null)
			{
				((Behaviour)this).enabled = false;
				return;
			}
			_photonView = ((Component)this).GetComponent<PhotonView>();
			_isOwner = (Object)(object)_photonView == (Object)null || _photonView.IsMine;
			_rb = ((Component)this).GetComponent<Rigidbody>();
		}

		private void Update()
		{
			if (!_isOwner)
			{
				return;
			}
			if (!FeatureFlags.RechargeWithStamina)
			{
				_rechargeAccumulator = 0f;
			}
			else
			{
				if (_controllerInstance == null)
				{
					return;
				}
				_rechargeAccumulator += Time.deltaTime;
				if (!(_rechargeAccumulator < FeatureFlags.RechargeTickInterval))
				{
					bool flag = !FeatureFlags.RechargeStaminaOnlyStationary || IsHeadStationary();
					(bool, bool?, float, float) tuple = DHHBatteryHelper.EvaluateJumpAllowance();
					if (flag || !tuple.Item1)
					{
						DHHBatteryHelper.RechargeDhhAbilityEnergy(_controllerInstance, _rechargeAccumulator);
					}
					_rechargeAccumulator = 0f;
				}
			}
		}

		private bool IsHeadStationary()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_rb == (Object)null)
			{
				return true;
			}
			Vector3 velocity = _rb.velocity;
			return ((Vector3)(ref velocity)).sqrMagnitude < FeatureFlags.HeadStationaryVelocitySqrThreshold;
		}
	}
}
namespace DeathHeadHopperFix.Modules.Gameplay.Stun
{
	internal static class ChargeHoldReleaseModule
	{
		private sealed class ChargeHoldState
		{
			public float StartTime;

			public bool IsHolding;

			public float LaunchScale = 1f;
		}

		private readonly struct DiminishingReturnsResult
		{
			public float BaseValue { get; }

			public float IncreasePerLevel { get; }

			public int AppliedLevel { get; }

			public int ThresholdLevel { get; }

			public float DiminishingFactor { get; }

			public int LinearLevels { get; }

			public int ExtraLevels { get; }

			public float LinearContribution { get; }

			public float DiminishingContribution { get; }

			public float DiminishingComponent { get; }

			public float FinalValue { get; }

			public DiminishingReturnsResult(float baseValue, float increasePerLevel, int appliedLevel, int thresholdLevel, float diminishingFactor, int linearLevels, int extraLevels, float linearContribution, float diminishingContribution, float diminishingComponent, float finalValue)
			{
				BaseValue = baseValue;
				IncreasePerLevel = increasePerLevel;
				AppliedLevel = appliedLevel;
				ThresholdLevel = thresholdLevel;
				DiminishingFactor = diminishingFactor;
				LinearLevels = linearLevels;
				ExtraLevels = extraLevels;
				LinearContribution = linearContribution;
				DiminishingContribution = diminishingContribution;
				DiminishingComponent = diminishingComponent;
				FinalValue = finalValue;
			}
		}

		private const string ChargeStrengthLogKey = "Fix:Charge.Strength";

		private const string ChargePermissiveFallbackLogKey = "Fix:Charge.PermissiveFallback";

		private const float RemoteReleaseCommandTag = -777f;

		private const float RemoteCancelCommandTag = -778f;

		private static ManualLogSource? s_log;

		private static FieldInfo? s_chargeHandlerChargeStrengthField;

		private static MethodInfo? s_chargeHandlerAbilityLevelGetter;

		private static FieldInfo? s_chargeHandlerImpactDetectorField;

		private static FieldInfo? s_chargeHandlerControllerField;

		private static FieldInfo? s_chargeHandlerMaxBouncesField;

		private static FieldInfo? s_chargeHandlerWindupTimerField;

		private static FieldInfo? s_chargeHandlerWindupTimeField;

		private static FieldInfo? s_chargeHandlerEnemiesHitField;

		private static MethodInfo? s_chargeHandlerEndChargeMethod;

		private static MethodInfo? s_chargeHandlerCancelChargeMethod;

		private static MethodInfo? s_chargeHandlerStateGetter;

		private static FieldInfo? s_deathHeadControllerAudioHandlerField;

		private static MethodInfo? s_audioHandlerStopWindupMethod;

		private static FieldInfo? s_impactDetectorPhysGrabObjectField;

		private static FieldInfo? s_cachedPhysGrabObjectGrabbedField;

		private static MethodInfo? s_chargeAbilityOnAbilityUpPrefixMethod;

		private static MethodInfo? s_chargeAbilityOnAbilityDownPostfixMethod;

		private static MethodInfo? s_chargeAbilityOnAbilityCancelPostfixMethod;

		private static MethodInfo? s_stunHandlerStunDurationGetter;

		private static FieldInfo? s_stunHandlerChargeHandlerField;

		private static Type? s_dhhStatsManagerType;

		private static MethodInfo? s_dhhStatsGetHeadChargeUpgradeMethod;

		private static readonly Dictionary<int, ChargeHoldState> s_chargeHoldStates = new Dictionary<int, ChargeHoldState>();

		private static float s_lastLocalHoldInputStartTime;

		private static bool s_localHoldUiActive;

		private static bool s_localHoldInputPending;

		internal static void Apply(Harmony harmony, Assembly asm, ManualLogSource? log)
		{
			s_log = log;
			PatchChargeHandlerDamageModeIfPossible(harmony, asm);
			PatchChargeAbilityHoldReleaseIfPossible(harmony, asm);
			PatchStunHandlerHoldScalingIfPossible(harmony, asm);
		}

		private static void PatchChargeHandlerDamageModeIfPossible(Harmony harmony, Assembly asm)
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Expected O, but got Unknown
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Expected O, but got Unknown
			//IL_027c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0289: Expected O, but got Unknown
			//IL_02d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e3: Expected O, but got Unknown
			//IL_031d: Unknown result type (might be due to invalid IL or missing references)
			//IL_032a: Expected O, but got Unknown
			//IL_0364: Unknown result type (might be due to invalid IL or missing references)
			//IL_0371: Expected O, but got Unknown
			//IL_03aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b8: Expected O, but got Unknown
			//IL_03f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ff: Expected O, but got Unknown
			Type type = asm.GetType("DeathHeadHopper.DeathHead.Handlers.ChargeHandler", throwOnError: false);
			if (!(type == null))
			{
				MethodInfo methodInfo = AccessTools.Method(type, "ChargeWindup", new Type[1] { typeof(Vector3) }, (Type[])null);
				MethodInfo method = typeof(ChargeHoldReleaseModule).GetMethod("ChargeHandler_ChargeWindup_Prefix", BindingFlags.Static | BindingFlags.NonPublic);
				if (methodInfo != null && method != null)
				{
					harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				MethodInfo method2 = typeof(ChargeHoldReleaseModule).GetMethod("ChargeHandler_ChargeWindup_Postfix", BindingFlags.Static | BindingFlags.NonPublic);
				if (methodInfo != null && method2 != null)
				{
					harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				MethodInfo methodInfo2 = AccessTools.Method(type, "ResetState", Type.EmptyTypes, (Type[])null);
				MethodInfo methodInfo3 = AccessTools.Method(type, "FixedUpdate", Type.EmptyTypes, (Type[])null);
				MethodInfo methodInfo4 = AccessTools.Method(type, "CancelCharge", Type.EmptyTypes, (Type[])null);
				MethodInfo methodInfo5 = AccessTools.Method(type, "EnemyHit", (Type[])null, (Type[])null);
				MethodInfo methodInfo6 = AccessTools.Method(type, "UpdateWindupDirection", new Type[1] { typeof(Vector3) }, (Type[])null);
				if (s_chargeHandlerChargeStrengthField == null)
				{
					s_chargeHandlerChargeStrengthField = AccessTools.Field(type, "chargeStrength");
				}
				if (s_chargeHandlerAbilityLevelGetter == null)
				{
					s_chargeHandlerAbilityLevelGetter = AccessTools.PropertyGetter(type, "AbilityLevel");
				}
				if (s_chargeHandlerControllerField == null)
				{
					s_chargeHandlerControllerField = AccessTools.Field(type, "controller");
				}
				if ((object)s_chargeHandlerMaxBouncesField == null)
				{
					s_chargeHandlerMaxBouncesField = AccessTools.Field(type, "maxBounces");
				}
				if ((object)s_chargeHandlerWindupTimerField == null)
				{
					s_chargeHandlerWindupTimerField = AccessTools.Field(type, "windupTimer");
				}
				if ((object)s_chargeHandlerWindupTimeField == null)
				{
					s_chargeHandlerWindupTimeField = AccessTools.Field(type, "windupTime");
				}
				if ((object)s_chargeHandlerEnemiesHitField == null)
				{
					s_chargeHandlerEnemiesHitField = AccessTools.Field(type, "enemiesHit");
				}
				if ((object)s_chargeHandlerEndChargeMethod == null)
				{
					s_chargeHandlerEndChargeMethod = AccessTools.Method(type, "EndCharge", Type.EmptyTypes, (Type[])null);
				}
				if ((object)s_chargeHandlerCancelChargeMethod == null)
				{
					s_chargeHandlerCancelChargeMethod = AccessTools.Method(type, "CancelCharge", Type.EmptyTypes, (Type[])null);
				}
				if ((object)s_chargeHandlerStateGetter == null)
				{
					s_chargeHandlerStateGetter = AccessTools.PropertyGetter(type, "State");
				}
				MethodInfo method3 = typeof(ChargeHoldReleaseModule).GetMethod("ChargeHandler_ResetState_Postfix", BindingFlags.Static | BindingFlags.NonPublic);
				if (methodInfo2 != null && method3 != null)
				{
					harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(method3), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				MethodInfo methodInfo7 = AccessTools.Method(type, "EndCharge", Type.EmptyTypes, (Type[])null);
				MethodInfo method4 = typeof(ChargeHoldReleaseModule).GetMethod("ChargeHandler_EndCharge_Postfix", BindingFlags.Static | BindingFlags.NonPublic);
				if (methodInfo7 != null && method4 != null)
				{
					harmony.Patch((MethodBase)methodInfo7, (HarmonyMethod)null, new HarmonyMethod(method4), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				MethodInfo method5 = typeof(ChargeHoldReleaseModule).GetMethod("ChargeHandler_FixedUpdate_Postfix", BindingFlags.Static | BindingFlags.NonPublic);
				if (methodInfo3 != null && method5 != null)
				{
					harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(method5), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				MethodInfo method6 = typeof(ChargeHoldReleaseModule).GetMethod("ChargeHandler_CancelCharge_Postfix", BindingFlags.Static | BindingFlags.NonPublic);
				if (methodInfo4 != null && method6 != null)
				{
					harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, new HarmonyMethod(method6), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				MethodInfo method7 = typeof(ChargeHoldReleaseModule).GetMethod("ChargeHandler_EnemyHit_Prefix", BindingFlags.Static | BindingFlags.NonPublic);
				if (methodInfo5 != null && method7 != null)
				{
					harmony.Patch((MethodBase)methodInfo5, new HarmonyMethod(method7), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				MethodInfo method8 = typeof(ChargeHoldReleaseModule).GetMethod("ChargeHandler_UpdateWindupDirection_Prefix", BindingFlags.Static | BindingFlags.NonPublic);
				if (methodInfo6 != null && method8 != null)
				{
					harmony.Patch((MethodBase)methodInfo6, new HarmonyMethod(method8), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
		}

		private static bool ChargeHandler_ChargeWindup_Prefix(object __instance)
		{
			if (__instance == null)
			{
				return true;
			}
			if (IsChargeHandlerHeadGrabbed(__instance))
			{
				if (FeatureFlags.DebugLogging && LogLimiter.ShouldLog("Fix:Charge.Grabbed", 30))
				{
					Debug.Log((object)"[Fix:Charge] Charge windup blocked because the head is grabbed.");
				}
				return false;
			}
			return true;
		}

		private static void ChargeHandler_ChargeWindup_Postfix(object __instance)
		{
			if (__instance != null && IsChargeState(__instance, "Windup"))
			{
				int unityObjectInstanceId = GetUnityObjectInstanceId(__instance);
				if (unityObjectInstanceId != 0)
				{
					ChargeHoldState orCreateChargeHoldState = GetOrCreateChargeHoldState(unityObjectInstanceId);
					orCreateChargeHoldState.StartTime = Time.time;
					orCreateChargeHoldState.IsHolding = true;
					orCreateChargeHoldState.LaunchScale = 1f;
					s_localHoldUiActive = true;
					AbilityModule.SetChargeSlotActivationProgress(0f);
				}
			}
		}

		private static void ChargeHandler_FixedUpdate_Postfix(object __instance)
		{
			if (__instance == null)
			{
				return;
			}
			int unityObjectInstanceId = GetUnityObjectInstanceId(__instance);
			if (unityObjectInstanceId == 0)
			{
				return;
			}
			if (!IsLocalChargeHandler(__instance))
			{
				if (s_chargeHoldStates.TryGetValue(unityObjectInstanceId, out ChargeHoldState value))
				{
					if (!IsChargeState(__instance, "Windup"))
					{
						s_chargeHoldStates.Remove(unityObjectInstanceId);
					}
					else if (value.IsHolding && s_chargeHandlerWindupTimerField != null && s_chargeHandlerWindupTimeField != null)
					{
						float num2 = ((s_chargeHandlerWindupTimeField.GetValue(__instance) is float num) ? num : 1.8f);
						s_chargeHandlerWindupTimerField.SetValue(__instance, Mathf.Max(0.01f, num2));
					}
				}
				return;
			}
			if (!s_chargeHoldStates.TryGetValue(unityObjectInstanceId, out ChargeHoldState value2))
			{
				if (!IsChargeState(__instance, "Windup") || !s_localHoldInputPending)
				{
					if (!s_localHoldUiActive)
					{
						AbilityModule.SetChargeSlotActivationProgress(0f);
					}
					return;
				}
				value2 = GetOrCreateChargeHoldState(unityObjectInstanceId);
				value2.StartTime = ((s_lastLocalHoldInputStartTime > 0f) ? s_lastLocalHoldInputStartTime : Time.time);
				value2.IsHolding = true;
				value2.LaunchScale = 1f;
				s_localHoldUiActive = true;
				AbilityModule.SetChargeSlotActivationProgress(0f);
			}
			if (!IsChargeState(__instance, "Windup"))
			{
				s_chargeHoldStates.Remove(unityObjectInstanceId);
				s_localHoldUiActive = false;
				AbilityModule.SetChargeSlotActivationProgress(0f);
				if (!s_localHoldUiActive)
				{
					AbilityModule.SetChargeSlotActivationProgress(0f);
				}
				return;
			}
			if (s_localHoldUiActive && value2.IsHolding)
			{
				float num3 = Mathf.Max(0.2f, FeatureFlags.ChargeAbilityHoldSeconds);
				float progress = Mathf.Clamp01((Time.time - value2.StartTime) / num3);
				float minimumChargeReleaseScale = GetMinimumChargeReleaseScale(__instance);
				AbilityModule.SetChargeSlotActivationProgress(progress, minimumChargeReleaseScale);
			}
			else
			{
				if (!value2.IsHolding)
				{
					if (!s_localHoldUiActive)
					{
						AbilityModule.SetChargeSlotActivationProgress(0f);
					}
					if (!IsChargeState(__instance, "Windup"))
					{
						s_chargeHoldStates.Remove(unityObjectInstanceId);
					}
					return;
				}
				if (!IsChargeState(__instance, "Windup"))
				{
					s_chargeHoldStates.Remove(unityObjectInstanceId);
					AbilityModule.SetChargeSlotActivationProgress(0f);
					return;
				}
				float num4 = Mathf.Max(0.2f, FeatureFlags.ChargeAbilityHoldSeconds);
				float progress2 = Mathf.Clamp01((Time.time - value2.StartTime) / num4);
				float minimumChargeReleaseScale2 = GetMinimumChargeReleaseScale(__instance);
				AbilityModule.SetChargeSlotActivationProgress(progress2, minimumChargeReleaseScale2);
			}
			if (value2.IsHolding && s_chargeHandlerWindupTimerField != null && s_chargeHandlerWindupTimeField != null)
			{
				float num6 = ((s_chargeHandlerWindupTimeField.GetValue(__instance) is float num5) ? num5 : 1.8f);
				s_chargeHandlerWindupTimerField.SetValue(__instance, Mathf.Max(0.01f, num6));
			}
		}

		private static void PatchChargeAbilityHoldReleaseIfPossible(Harmony harmony, Assembly asm)
		{
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Expected O, but got Unknown
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Expected O, but got Unknown
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Expected O, but got Unknown
			Type type = asm.GetType("DeathHeadHopper.Abilities.Charge.ChargeAbility", throwOnError: false);
			if (type == null)
			{
				return;
			}
			MethodInfo methodInfo = AccessTools.Method(type, "OnAbilityDown", Type.EmptyTypes, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(type, "OnAbilityUp", Type.EmptyTypes, (Type[])null);
			MethodInfo methodInfo3 = AccessTools.Method(type, "OnAbilityCancel", Type.EmptyTypes, (Type[])null);
			if (methodInfo2 == null)
			{
				return;
			}
			if ((object)s_chargeAbilityOnAbilityUpPrefixMethod == null)
			{
				s_chargeAbilityOnAbilityUpPrefixMethod = typeof(ChargeHoldReleaseModule).GetMethod("ChargeAbility_OnAbilityUp_Prefix", BindingFlags.Static | BindingFlags.NonPublic);
			}
			if (!(s_chargeAbilityOnAbilityUpPrefixMethod == null))
			{
				if ((object)s_chargeAbilityOnAbilityDownPostfixMethod == null)
				{
					s_chargeAbilityOnAbilityDownPostfixMethod = typeof(ChargeHoldReleaseModule).GetMethod("ChargeAbility_OnAbilityDown_Postfix", BindingFlags.Static | BindingFlags.NonPublic);
				}
				if ((object)s_chargeAbilityOnAbilityCancelPostfixMethod == null)
				{
					s_chargeAbilityOnAbilityCancelPostfixMethod = typeof(ChargeHoldReleaseModule).GetMethod("ChargeAbility_OnAbilityCancel_Postfix", BindingFlags.Static | BindingFlags.NonPublic);
				}
				if (methodInfo != null && s_chargeAbilityOnAbilityDownPostfixMethod != null)
				{
					harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(s_chargeAbilityOnAbilityDownPostfixMethod), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(s_chargeAbilityOnAbilityUpPrefixMethod), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				if (methodInfo3 != null && s_chargeAbilityOnAbilityCancelPostfixMethod != null)
				{
					harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(s_chargeAbilityOnAbilityCancelPostfixMethod), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
		}

		private static void PatchStunHandlerHoldScalingIfPossible(Harmony harmony, Assembly asm)
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Expected O, but got Unknown
			Type type = asm.GetType("DeathHeadHopper.DeathHead.Handlers.StunHandler", throwOnError: false);
			if (type == null)
			{
				return;
			}
			if ((object)s_stunHandlerChargeHandlerField == null)
			{
				s_stunHandlerChargeHandlerField = AccessTools.Field(type, "chargeHandler");
			}
			if ((object)s_stunHandlerStunDurationGetter == null)
			{
				s_stunHandlerStunDurationGetter = AccessTools.PropertyGetter(type, "StunDuration");
			}
			if (!(s_stunHandlerStunDurationGetter == null))
			{
				MethodInfo method = typeof(ChargeHoldReleaseModule).GetMethod("StunHandler_StunDuration_Prefix", BindingFlags.Static | BindingFlags.NonPublic);
				if (!(method == null))
				{
					harmony.Patch((MethodBase)s_stunHandlerStunDurationGetter, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
		}

		private static void ChargeHandler_CancelCharge_Postfix(object __instance)
		{
			ClearChargeHoldState(__instance);
		}

		private static bool ChargeHandler_EnemyHit_Prefix(object __instance)
		{
			if (__instance == null)
			{
				return true;
			}
			if (s_chargeHandlerEnemiesHitField == null || s_chargeHandlerEndChargeMethod == null || s_chargeHandlerAbilityLevelGetter == null)
			{
				return true;
			}
			int unityObjectInstanceId = GetUnityObjectInstanceId(__instance);
			if (unityObjectInstanceId == 0 || !s_chargeHoldStates.TryGetValue(unityObjectInstanceId, out ChargeHoldState value))
			{
				return true;
			}
			if (!(s_chargeHandlerEnemiesHitField.GetValue(__instance) is int num) || 1 == 0)
			{
				return true;
			}
			int num2 = num + 1;
			s_chargeHandlerEnemiesHitField.SetValue(__instance, num2);
			int currentLevel = ((s_chargeHandlerAbilityLevelGetter.Invoke(__instance, null) is int num3) ? num3 : 0);
			int num4 = Mathf.FloorToInt(EvaluateStatWithDiminishingReturns(1f, 0.5f, currentLevel, 20, 0.9f).FinalValue);
			int num5 = Mathf.Max(1, Mathf.RoundToInt((float)num4 * Mathf.Clamp01(value.LaunchScale)));
			if (num2 >= num5)
			{
				s_chargeHandlerEndChargeMethod.Invoke(__instance, null);
			}
			return false;
		}

		private static bool StunHandler_StunDuration_Prefix(object __instance, ref float __result)
		{
			if (__instance == null)
			{
				return true;
			}
			if (s_stunHandlerChargeHandlerField == null || s_chargeHandlerAbilityLevelGetter == null)
			{
				return true;
			}
			object value = s_stunHandlerChargeHandlerField.GetValue(__instance);
			if (value == null)
			{
				return true;
			}
			int unityObjectInstanceId = GetUnityObjectInstanceId(value);
			if (unityObjectInstanceId == 0 || !s_chargeHoldStates.TryGetValue(unityObjectInstanceId, out ChargeHoldState value2))
			{
				return true;
			}
			int num2 = ((s_chargeHandlerAbilityLevelGetter.Invoke(value, null) is int num) ? num : 0);
			float num3 = 5f + 1f * (float)num2;
			__result = num3 * Mathf.Clamp01(value2.LaunchScale);
			return false;
		}

		private static bool ChargeAbility_OnAbilityUp_Prefix()
		{
			return TryReleaseHeldCharge();
		}

		private static void ChargeAbility_OnAbilityDown_Postfix()
		{
			s_lastLocalHoldInputStartTime = Time.time;
			s_localHoldInputPending = true;
			AbilityModule.SetChargeSlotActivationProgress(0f);
			object localChargeHandler = GetLocalChargeHandler();
			if (localChargeHandler != null && !IsChargeState(localChargeHandler, "Windup"))
			{
				ClearChargeHoldState(localChargeHandler);
			}
		}

		private static void ChargeAbility_OnAbilityCancel_Postfix()
		{
			s_localHoldInputPending = false;
			s_localHoldUiActive = false;
			AbilityModule.SetChargeSlotActivationProgress(0f);
			object localChargeHandler = GetLocalChargeHandler();
			if (localChargeHandler != null)
			{
				ClearChargeHoldState(localChargeHandler);
			}
		}

		private static bool TryReleaseHeldCharge()
		{
			object localChargeHandler = GetLocalChargeHandler();
			if (localChargeHandler == null)
			{
				s_localHoldInputPending = false;
				s_localHoldUiActive = false;
				AbilityModule.SetChargeSlotActivationProgress(0f);
				return true;
			}
			if (!IsChargeState(localChargeHandler, "Windup"))
			{
				s_localHoldInputPending = false;
				s_localHoldUiActive = false;
				AbilityModule.SetChargeSlotActivationProgress(0f);
				return true;
			}
			int unityObjectInstanceId = GetUnityObjectInstanceId(localChargeHandler);
			if (unityObjectInstanceId == 0)
			{
				s_localHoldInputPending = false;
				s_localHoldUiActive = false;
				AbilityModule.SetChargeSlotActivationProgress(0f);
				return true;
			}
			if (!s_chargeHoldStates.TryGetValue(unityObjectInstanceId, out ChargeHoldState value))
			{
				value = GetOrCreateChargeHoldState(unityObjectInstanceId);
				value.StartTime = ((s_lastLocalHoldInputStartTime > 0f) ? s_lastLocalHoldInputStartTime : Time.time);
				value.IsHolding = true;
				value.LaunchScale = 1f;
			}
			if (!value.IsHolding)
			{
				return true;
			}
			if (SemiFunc.IsMultiplayer() && !SemiFunc.IsMasterClientOrSingleplayer())
			{
				if (!ConfigSyncManager.IsRemoteHostFixCompatible())
				{
					s_localHoldInputPending = false;
					s_localHoldUiActive = false;
					AbilityModule.SetChargeSlotActivationProgress(0f);
					if (FeatureFlags.DebugLogging && LogLimiter.ShouldLog("Fix:Charge.PermissiveFallback", 120))
					{
						Debug.Log((object)"[Fix:DHHCharge][PermissiveGate] Host fix marker missing. Falling back to vanilla release path.");
					}
					return true;
				}
				value.IsHolding = false;
				s_localHoldInputPending = false;
				s_localHoldUiActive = false;
				AbilityModule.SetChargeSlotActivationProgress(0f);
				SendRemoteReleaseCommand(localChargeHandler);
				return false;
			}
			float num = Mathf.Max(0.2f, FeatureFlags.ChargeAbilityHoldSeconds);
			float num2 = Mathf.Clamp01((Time.time - value.StartTime) / num);
			float minimumChargeReleaseScale = GetMinimumChargeReleaseScale(localChargeHandler);
			if (num2 < minimumChargeReleaseScale)
			{
				value.IsHolding = false;
				value.LaunchScale = 0f;
				s_localHoldInputPending = false;
				s_localHoldUiActive = false;
				AbilityModule.SetChargeSlotActivationProgress(0f);
				StopChargeWindupLoop(localChargeHandler);
				s_chargeHandlerCancelChargeMethod?.Invoke(localChargeHandler, null);
				return false;
			}
			value.IsHolding = false;
			value.LaunchScale = num2;
			if (s_chargeHandlerChargeStrengthField != null && s_chargeHandlerChargeStrengthField.GetValue(localChargeHandler) is float num3)
			{
				s_chargeHandlerChargeStrengthField.SetValue(localChargeHandler, num3 * num2);
			}
			if (s_chargeHandlerMaxBouncesField != null && s_chargeHandlerMaxBouncesField.GetValue(localChargeHandler) is float num4)
			{
				s_chargeHandlerMaxBouncesField.SetValue(localChargeHandler, Mathf.Max(0f, num4 * num2));
			}
			if (s_chargeHandlerWindupTimerField != null)
			{
				s_chargeHandlerWindupTimerField.SetValue(localChargeHandler, -1f);
			}
			s_localHoldInputPending = false;
			s_localHoldUiActive = false;
			AbilityModule.SetChargeSlotActivationProgress(0f);
			return true;
		}

		private static bool ChargeHandler_UpdateWindupDirection_Prefix(object __instance, Vector3 chargeDirection)
		{
			//IL_0029: 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)
			if (__instance == null)
			{
				return true;
			}
			if (!SemiFunc.IsMasterClientOrSingleplayer())
			{
				return true;
			}
			if (Mathf.Abs(chargeDirection.x - -778f) < 0.001f)
			{
				s_chargeHandlerCancelChargeMethod?.Invoke(__instance, null);
				return false;
			}
			if (Mathf.Abs(chargeDirection.x - -777f) > 0.001f)
			{
				return true;
			}
			int unityObjectInstanceId = GetUnityObjectInstanceId(__instance);
			if (unityObjectInstanceId == 0 || !s_chargeHoldStates.TryGetValue(unityObjectInstanceId, out ChargeHoldState value))
			{
				return false;
			}
			if (!IsChargeState(__instance, "Windup"))
			{
				return false;
			}
			float num = Mathf.Max(0.2f, FeatureFlags.ChargeAbilityHoldSeconds);
			float num2 = Mathf.Clamp01((Time.time - value.StartTime) / num);
			float minimumChargeReleaseScale = GetMinimumChargeReleaseScale(__instance);
			value.IsHolding = false;
			if (num2 < minimumChargeReleaseScale)
			{
				value.LaunchScale = 0f;
				s_chargeHandlerCancelChargeMethod?.Invoke(__instance, null);
				return false;
			}
			value.LaunchScale = num2;
			if (s_chargeHandlerChargeStrengthField != null && s_chargeHandlerChargeStrengthField.GetValue(__instance) is float num3)
			{
				s_chargeHandlerChargeStrengthField.SetValue(__instance, num3 * num2);
			}
			if (s_chargeHandlerMaxBouncesField != null && s_chargeHandlerMaxBouncesField.GetValue(__instance) is float num4)
			{
				s_chargeHandlerMaxBouncesField.SetValue(__instance, Mathf.Max(0f, num4 * num2));
			}
			if (s_chargeHandlerWindupTimerField != null)
			{
				s_chargeHandlerWindupTimerField.SetValue(__instance, -1f);
			}
			return false;
		}

		private static void SendRemoteReleaseCommand(object chargeHandler)
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			PhotonView val = GetDhhInputManagerHeadPhotonView();
			if ((Object)(object)val == (Object)null || val.ViewID <= 0)
			{
				Component val2 = (Component)((chargeHandler is Component) ? chargeHandler : null);
				if (val2 != null)
				{
					val = val2.GetComponent<PhotonView>();
				}
			}
			if (!((Object)(object)val == (Object)null) && val.ViewID > 0 && PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient)
			{
				val.RPC("UpdateWindupDirection", (RpcTarget)2, new object[1] { (object)new Vector3(-777f, 0f, 0f) });
			}
		}

		private static void SendRemoteCancelCommand(object chargeHandler)
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			PhotonView val = GetDhhInputManagerHeadPhotonView();
			if ((Object)(object)val == (Object)null || val.ViewID <= 0)
			{
				Component val2 = (Component)((chargeHandler is Component) ? chargeHandler : null);
				if (val2 != null)
				{
					val = val2.GetComponent<PhotonView>();
				}
			}
			if (!((Object)(object)val == (Object)null) && val.ViewID > 0 && PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient)
			{
				val.RPC("UpdateWindupDirection", (RpcTarget)2, new object[1] { (object)new Vector3(-778f, 0f, 0f) });
			}
		}

		private static PhotonView? GetDhhInputManagerHeadPhotonView()
		{
			try
			{
				Type type = AccessTools.TypeByName("DeathHeadHopper.Managers.DHHInputManager");
				if (type == null)
				{
					return null;
				}
				object? obj = type.GetProperty("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(null);
				MonoBehaviour val = (MonoBehaviour)((obj is MonoBehaviour) ? obj : null);
				if ((Object)(object)val == (Object)null)
				{
					return null;
				}
				object? obj2 = type.GetField("headPhotonView", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(val);
				return (PhotonView?)((obj2 is PhotonView) ? obj2 : null);
			}
			catch
			{
				return null;
			}
		}

		private static float GetMinimumChargeReleaseScale(object chargeHandler)
		{
			if (chargeHandler == null)
			{
				return 0f;
			}
			float num = 0f;
			if (s_chargeHandlerChargeStrengthField?.GetValue(chargeHandler) is float baseValue)
			{
				num = Mathf.Max(num, RequiredScaleForMinimumOne(baseValue));
			}
			if (s_chargeHandlerMaxBouncesField?.GetValue(chargeHandler) is float baseValue2)
			{
				num = Mathf.Max(num, RequiredScaleForMinimumOne(baseValue2));
			}
			if (TryGetEffectiveChargeAbilityLevel(chargeHandler, out var abilityLevel))
			{
				int num2 = Mathf.FloorToInt(EvaluateStatWithDiminishingReturns(1f, 0.5f, abilityLevel, 20, 0.9f).FinalValue);
				float baseValue3 = 5f + 1f * (float)abilityLevel;
				num = Mathf.Max(num, RequiredScaleForMinimumOne(num2));
				num = Mathf.Max(num, RequiredScaleForMinimumOne(baseValue3));
			}
			if (float.IsNaN(n