Decompiled source of DeathHeadHopperFix v0.2.6

plugins\DeathHeadHopperFix.dll

Decompiled 3 weeks 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;
using DeathHeadHopper.Abilities;
using DeathHeadHopper.Abilities.Charge;
using DeathHeadHopper.DeathHead;
using DeathHeadHopper.DeathHead.Handlers;
using DeathHeadHopper.Helpers;
using DeathHeadHopper.Items;
using DeathHeadHopper.Managers;
using DeathHeadHopper.UI;
using DeathHeadHopperFix.API.Abilities;
using DeathHeadHopperFix.API.Battery;
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.Bootstrap;
using DeathHeadHopperFix.Modules.Gameplay.Core.Input;
using DeathHeadHopperFix.Modules.Gameplay.Core.Interop;
using DeathHeadHopperFix.Modules.Gameplay.Core.Runtime;
using DeathHeadHopperFix.Modules.Gameplay.Spectate;
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 REPOLib.Modules;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[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]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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]
	[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]
	[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.2.6")]
	public sealed class Plugin : BaseUnityPlugin
	{
		private const string TargetAssemblyName = "DeathHeadHopper";

		private Harmony? _harmony;

		private bool _patched;

		private bool _patchAttempted;

		private Assembly? _targetAssembly;

		private static ManualLogSource? _log;

		private void Awake()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			_log = ((BaseUnityPlugin)this).Logger;
			ConfigManager.Initialize(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger);
			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 || _patchAttempted || asm == null)
			{
				return;
			}
			string name = asm.GetName().Name;
			if (!string.Equals(name, "DeathHeadHopper", StringComparison.OrdinalIgnoreCase))
			{
				return;
			}
			_patchAttempted = true;
			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.");
				}
				DHHStatsBootstrapModule.Apply(harmony, asm, _log);
				PrefabModule.Apply(harmony, asm, _log);
				AudioModule.Apply(harmony, asm, _log);
				DHHShopVanillaPoolModule.Apply(harmony, asm, _log);
				_targetAssembly = asm;
				DHHApiGuardModule.Apply(harmony, asm);
				BatteryJumpPatchModule.Apply(harmony, _log);
				JumpForceModule.Apply(harmony, _log);
				ChargeAbilityTuningModule.Apply(harmony, asm);
				ChargeHoldReleaseModule.Apply(harmony, asm, _log);
				InputModule.Apply(harmony, asm, _log);
				AbilityModule.ApplyAbilitySpotLabelOverlay(harmony);
				AbilityModule.ApplyAbilityManagerHooks(harmony);
				_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 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 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? == true;
		}

		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? == true;
		}
	}
}
namespace DeathHeadHopperFix.Modules.Stamina
{
	internal sealed class StaminaRechargeModule : MonoBehaviour
	{
		private DeathHeadController? _controller;

		private bool _isOwner;

		private float _rechargeAccumulator;

		private Rigidbody? _rb;

		private void Awake()
		{
			_controller = ((Component)this).GetComponent<DeathHeadController>();
			if ((Object)(object)_controller == (Object)null)
			{
				((Behaviour)this).enabled = false;
				return;
			}
			PhotonView component = ((Component)this).GetComponent<PhotonView>();
			_isOwner = !SemiFunc.IsMultiplayer() || ((Object)(object)component != (Object)null && component.IsMine);
			_rb = ((Component)this).GetComponent<Rigidbody>();
		}

		private void Update()
		{
			if (!_isOwner || (Object)(object)_controller == (Object)null)
			{
				return;
			}
			if (!FeatureFlags.RechargeWithStamina)
			{
				_rechargeAccumulator = 0f;
				return;
			}
			_rechargeAccumulator += Time.deltaTime;
			if (!(_rechargeAccumulator < FeatureFlags.RechargeTickInterval))
			{
				if (!FeatureFlags.RechargeStaminaOnlyStationary || IsHeadStationary())
				{
					DHHBatteryHelper.RechargeDhhAbilityEnergy(_controller, _rechargeAccumulator);
				}
				_rechargeAccumulator = 0f;
			}
		}

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

			public bool IsHolding;

			public float LaunchScale = 1f;

			public float ChargingStartTime;

			public float RestingTime;
		}

		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 const float ChargeRestStopSeconds = 0.35f;

		private const float ChargeFailsafeSeconds = 10f;

		private const float ChargeRestVelocitySqrThreshold = 0.01f;

		private const float ChargeRestAngularVelocitySqrThreshold = 0.04f;

		private static ManualLogSource? s_log;

		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_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Expected O, but got Unknown
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Expected O, but got Unknown
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Expected O, but got Unknown
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Expected O, but got Unknown
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a8: Expected O, but got Unknown
			//IL_02e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: Expected O, but got Unknown
			//IL_0328: Unknown result type (might be due to invalid IL or missing references)
			//IL_0336: Expected O, but got Unknown
			//IL_0371: Unknown result type (might be due to invalid IL or missing references)
			//IL_037f: Expected O, but got Unknown
			//IL_0394: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a1: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(typeof(ChargeHandler), "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(typeof(ChargeHandler), "ResetState", Type.EmptyTypes, (Type[])null);
			MethodInfo methodInfo3 = AccessTools.Method(typeof(ChargeHandler), "FixedUpdate", Type.EmptyTypes, (Type[])null);
			MethodInfo methodInfo4 = AccessTools.Method(typeof(ChargeHandler), "CancelCharge", Type.EmptyTypes, (Type[])null);
			MethodInfo methodInfo5 = AccessTools.Method(typeof(ChargeHandler), "EnemyHit", (Type[])null, (Type[])null);
			MethodInfo methodInfo6 = AccessTools.Method(typeof(ChargeHandler), "UpdateWindupDirection", new Type[1] { typeof(Vector3) }, (Type[])null);
			MethodInfo methodInfo7 = AccessTools.Method(typeof(ChargeHandler), "SyncChargeStateRPC", (Type[])null, (Type[])null);
			MethodInfo method3 = typeof(ChargeHoldReleaseModule).GetMethod("ChargeHandler_SyncChargeStateRPC_Prefix", BindingFlags.Static | BindingFlags.NonPublic);
			MethodInfo method4 = typeof(ChargeHoldReleaseModule).GetMethod("ChargeHandler_ResetState_Postfix", BindingFlags.Static | BindingFlags.NonPublic);
			if (methodInfo2 != null && method4 != null)
			{
				harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(method4), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			MethodInfo methodInfo8 = AccessTools.Method(typeof(ChargeHandler), "EndCharge", Type.EmptyTypes, (Type[])null);
			MethodInfo method5 = typeof(ChargeHoldReleaseModule).GetMethod("ChargeHandler_EndCharge_Postfix", BindingFlags.Static | BindingFlags.NonPublic);
			if (methodInfo8 != null && method5 != null)
			{
				harmony.Patch((MethodBase)methodInfo8, (HarmonyMethod)null, new HarmonyMethod(method5), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			MethodInfo method6 = typeof(ChargeHoldReleaseModule).GetMethod("ChargeHandler_FixedUpdate_Postfix", BindingFlags.Static | BindingFlags.NonPublic);
			if (methodInfo3 != null && method6 != null)
			{
				harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(method6), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			MethodInfo method7 = typeof(ChargeHoldReleaseModule).GetMethod("ChargeHandler_CancelCharge_Postfix", BindingFlags.Static | BindingFlags.NonPublic);
			if (methodInfo4 != null && method7 != null)
			{
				harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, new HarmonyMethod(method7), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			MethodInfo method8 = typeof(ChargeHoldReleaseModule).GetMethod("ChargeHandler_EnemyHit_Prefix", BindingFlags.Static | BindingFlags.NonPublic);
			if (methodInfo5 != null && method8 != null)
			{
				harmony.Patch((MethodBase)methodInfo5, new HarmonyMethod(method8), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			MethodInfo method9 = typeof(ChargeHoldReleaseModule).GetMethod("ChargeHandler_UpdateWindupDirection_Prefix", BindingFlags.Static | BindingFlags.NonPublic);
			if (methodInfo6 != null && method9 != null)
			{
				harmony.Patch((MethodBase)methodInfo6, new HarmonyMethod(method9), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			MethodInfo method10 = typeof(ChargeHoldReleaseModule).GetMethod("ChargeHandler_SyncChargeStateRPC_Postfix", BindingFlags.Static | BindingFlags.NonPublic);
			if (methodInfo7 != null)
			{
				if (method3 != null)
				{
					harmony.Patch((MethodBase)methodInfo7, new HarmonyMethod(method3), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				if (method10 != null)
				{
					harmony.Patch((MethodBase)methodInfo7, (HarmonyMethod)null, new HarmonyMethod(method10), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
		}

		private static bool ChargeHandler_ChargeWindup_Prefix(ChargeHandler __instance)
		{
			if ((Object)(object)__instance == (Object)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(ChargeHandler __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && IsChargeState(__instance, "Windup"))
			{
				int unityObjectInstanceId = GetUnityObjectInstanceId((Object)(object)__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(ChargeHandler __instance)
		{
			if ((Object)(object)__instance == (Object)null)
			{
				return;
			}
			int unityObjectInstanceId = GetUnityObjectInstanceId((Object)(object)__instance);
			if (unityObjectInstanceId == 0)
			{
				return;
			}
			if (SemiFunc.IsMasterClientOrSingleplayer() && IsChargeState(__instance, "Charging"))
			{
				if (!TryStopStalledCharge(__instance, unityObjectInstanceId))
				{
					TryStopAtBounceLimit(__instance);
				}
				return;
			}
			if (!IsLocalChargeHandler(__instance))
			{
				if (s_chargeHoldStates.TryGetValue(unityObjectInstanceId, out ChargeHoldState value))
				{
					if (!IsChargeState(__instance, "Windup"))
					{
						s_chargeHoldStates.Remove(unityObjectInstanceId);
					}
					else if (value.IsHolding)
					{
						__instance.windupTimer = Mathf.Max(0.01f, __instance.windupTime);
					}
				}
				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 num = Mathf.Max(0.2f, FeatureFlags.ChargeAbilityHoldSeconds);
				float progress = Mathf.Clamp01((Time.time - value2.StartTime) / num);
				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 num2 = Mathf.Max(0.2f, FeatureFlags.ChargeAbilityHoldSeconds);
				float progress2 = Mathf.Clamp01((Time.time - value2.StartTime) / num2);
				float minimumChargeReleaseScale2 = GetMinimumChargeReleaseScale(__instance);
				AbilityModule.SetChargeSlotActivationProgress(progress2, minimumChargeReleaseScale2);
			}
			if (value2.IsHolding)
			{
				__instance.windupTimer = Mathf.Max(0.01f, __instance.windupTime);
			}
		}

		private static bool TryStopStalledCharge(ChargeHandler chargeHandler, int id)
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			ChargeHoldState orCreateChargeHoldState = GetOrCreateChargeHoldState(id);
			if (orCreateChargeHoldState.ChargingStartTime <= 0f)
			{
				orCreateChargeHoldState.ChargingStartTime = Time.time;
			}
			DeathHeadController controller = chargeHandler.controller;
			Rigidbody rb = chargeHandler.rb;
			int num;
			if (controller != null && controller.collisionHandler?.isColliding == true && (Object)(object)rb != (Object)null)
			{
				Vector3 val = rb.velocity;
				if (((Vector3)(ref val)).sqrMagnitude <= 0.01f)
				{
					val = rb.angularVelocity;
					num = ((((Vector3)(ref val)).sqrMagnitude <= 0.04f) ? 1 : 0);
					goto IL_00a0;
				}
			}
			num = 0;
			goto IL_00a0;
			IL_00a0:
			bool flag = (byte)num != 0;
			orCreateChargeHoldState.RestingTime = (flag ? (orCreateChargeHoldState.RestingTime + Time.fixedDeltaTime) : 0f);
			bool flag2 = orCreateChargeHoldState.RestingTime >= 0.35f;
			bool flag3 = Time.time - orCreateChargeHoldState.ChargingStartTime >= 10f;
			if (!flag2 && !flag3)
			{
				return false;
			}
			chargeHandler.EndCharge();
			if (FeatureFlags.DebugLogging && LogLimiter.ShouldLog("Fix:DHHCharge.StalledStop", 30))
			{
				string text = (flag2 ? "stable-rest" : "failsafe-timeout");
				ManualLogSource? obj = s_log;
				if (obj != null)
				{
					obj.LogDebug((object)("[Fix:DHHCharge] Ended authoritative Charging state (" + text + ")."));
				}
			}
			return true;
		}

		private static void TryStopAtBounceLimit(ChargeHandler chargeHandler)
		{
			int num = Mathf.Max(0, Mathf.CeilToInt(chargeHandler.maxBounces));
			if (num > 0 && chargeHandler.bounceColliders.Count >= num)
			{
				chargeHandler.EndCharge();
			}
		}

		private static void PatchChargeAbilityHoldReleaseIfPossible(Harmony harmony, Assembly asm)
		{
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Expected O, but got Unknown
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Expected O, but got Unknown
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(typeof(ChargeAbility), "OnAbilityDown", Type.EmptyTypes, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(ChargeAbility), "OnAbilityUp", Type.EmptyTypes, (Type[])null);
			MethodInfo methodInfo3 = AccessTools.Method(typeof(ChargeAbility), "OnAbilityCancel", Type.EmptyTypes, (Type[])null);
			if (methodInfo2 == null)
			{
				return;
			}
			MethodInfo method = typeof(ChargeHoldReleaseModule).GetMethod("ChargeAbility_OnAbilityUp_Prefix", BindingFlags.Static | BindingFlags.NonPublic);
			if (!(method == null))
			{
				MethodInfo method2 = typeof(ChargeHoldReleaseModule).GetMethod("ChargeAbility_OnAbilityDown_Postfix", BindingFlags.Static | BindingFlags.NonPublic);
				MethodInfo method3 = typeof(ChargeHoldReleaseModule).GetMethod("ChargeAbility_OnAbilityCancel_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);
				}
				harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				if (methodInfo3 != null && method3 != null)
				{
					harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(method3), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
		}

		private static void PatchStunHandlerHoldScalingIfPossible(Harmony harmony, Assembly asm)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.PropertyGetter(typeof(StunHandler), "StunDuration");
			if (!(methodInfo == null))
			{
				MethodInfo method = typeof(ChargeHoldReleaseModule).GetMethod("StunHandler_StunDuration_Prefix", BindingFlags.Static | BindingFlags.NonPublic);
				if (!(method == null))
				{
					harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
		}

		private static void ChargeHandler_CancelCharge_Postfix(ChargeHandler __instance)
		{
			StopChargeWindupLoop(__instance);
			ClearChargeHoldState(__instance);
			SynchronizeFinalChargeState(__instance);
		}

		private static void ChargeHandler_SyncChargeStateRPC_Prefix(ChargeHandler __instance, ChargeState state)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Invalid comparison between Unknown and I4
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Invalid comparison between Unknown and I4
			if (!((Object)(object)__instance == (Object)null) && (int)state != 1 && (int)state != 2)
			{
				StopChargeWindupLoop(__instance);
				ClearChargeHoldState(__instance);
			}
		}

		private static void ChargeHandler_SyncChargeStateRPC_Postfix(ChargeHandler __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && !IsChargeState(__instance, "Windup") && !IsChargeState(__instance, "Charging"))
			{
				StopChargeWindupLoop(__instance);
				ClearChargeHoldState(__instance);
			}
		}

		private static bool ChargeHandler_EnemyHit_Prefix(ChargeHandler __instance)
		{
			if ((Object)(object)__instance == (Object)null)
			{
				return true;
			}
			int unityObjectInstanceId = GetUnityObjectInstanceId((Object)(object)__instance);
			if (unityObjectInstanceId == 0 || !s_chargeHoldStates.TryGetValue(unityObjectInstanceId, out ChargeHoldState value))
			{
				return true;
			}
			__instance.enemiesHit++;
			int abilityLevel = __instance.AbilityLevel;
			int num = Mathf.FloorToInt(EvaluateStatWithDiminishingReturns(1f, 0.5f, abilityLevel, 20, 0.9f).FinalValue);
			int num2 = Mathf.Max(1, Mathf.RoundToInt((float)num * Mathf.Clamp01(value.LaunchScale)));
			if (__instance.enemiesHit >= num2)
			{
				__instance.EndCharge();
			}
			return false;
		}

		private static bool StunHandler_StunDuration_Prefix(StunHandler __instance, ref float __result)
		{
			if ((Object)(object)__instance == (Object)null)
			{
				return true;
			}
			ChargeHandler chargeHandler = __instance.chargeHandler;
			if ((Object)(object)chargeHandler == (Object)null)
			{
				return true;
			}
			int unityObjectInstanceId = GetUnityObjectInstanceId((Object)(object)chargeHandler);
			if (unityObjectInstanceId == 0 || !s_chargeHoldStates.TryGetValue(unityObjectInstanceId, out ChargeHoldState value))
			{
				return true;
			}
			int abilityLevel = chargeHandler.AbilityLevel;
			float num = 5f + 1f * (float)abilityLevel;
			__result = num * Mathf.Clamp01(value.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);
			ChargeHandler localChargeHandler = GetLocalChargeHandler();
			if ((Object)(object)localChargeHandler != (Object)null && !IsChargeState(localChargeHandler, "Windup"))
			{
				ClearChargeHoldState(localChargeHandler);
			}
		}

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

		private static bool TryReleaseHeldCharge()
		{
			ChargeHandler localChargeHandler = GetLocalChargeHandler();
			if ((Object)(object)localChargeHandler == (Object)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((Object)(object)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())
				{
					value.IsHolding = false;
					value.LaunchScale = 0f;
					s_localHoldInputPending = false;
					s_localHoldUiActive = false;
					AbilityModule.SetChargeSlotActivationProgress(0f);
					StopChargeWindupLoop(localChargeHandler);
					if (FeatureFlags.DebugLogging && LogLimiter.ShouldLog("Fix:Charge.PermissiveFallback", 120))
					{
						Debug.Log((object)"[Fix:DHHCharge][PermissiveGate] Host fix marker missing. Sending authoritative cancel fallback.");
					}
					TrySendVanillaRemoteCancelCommand(localChargeHandler);
					return false;
				}
				value.IsHolding = false;
				s_localHoldInputPending = false;
				s_localHoldUiActive = false;
				AbilityModule.SetChargeSlotActivationProgress(0f);
				if (!TrySendRemoteReleaseCommand(localChargeHandler))
				{
					StopChargeWindupLoop(localChargeHandler);
					TrySendVanillaRemoteCancelCommand(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);
				localChargeHandler.CancelCharge();
				return false;
			}
			value.IsHolding = false;
			value.LaunchScale = num2;
			localChargeHandler.chargeStrength *= num2;
			localChargeHandler.maxBounces = Mathf.Max(0f, localChargeHandler.maxBounces * num2);
			localChargeHandler.windupTimer = -1f;
			s_localHoldInputPending = false;
			s_localHoldUiActive = false;
			AbilityModule.SetChargeSlotActivationProgress(0f);
			return true;
		}

		private static bool ChargeHandler_UpdateWindupDirection_Prefix(ChargeHandler __instance, Vector3 chargeDirection)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance == (Object)null)
			{
				return true;
			}
			if (!SemiFunc.IsMasterClientOrSingleplayer())
			{
				return true;
			}
			if (Mathf.Abs(chargeDirection.x - -778f) < 0.001f)
			{
				__instance.CancelCharge();
				return false;
			}
			if (Mathf.Abs(chargeDirection.x - -777f) > 0.001f)
			{
				return true;
			}
			int unityObjectInstanceId = GetUnityObjectInstanceId((Object)(object)__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;
				__instance.CancelCharge();
				return false;
			}
			value.LaunchScale = num2;
			__instance.chargeStrength *= num2;
			__instance.maxBounces = Mathf.Max(0f, __instance.maxBounces * num2);
			__instance.windupTimer = -1f;
			return false;
		}

		private static bool TrySendRemoteReleaseCommand(ChargeHandler chargeHandler)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			PhotonView chargePhotonView = GetChargePhotonView(chargeHandler);
			if ((Object)(object)chargePhotonView == (Object)null || chargePhotonView.ViewID <= 0)
			{
				return false;
			}
			if (!PhotonNetwork.InRoom || PhotonNetwork.IsMasterClient)
			{
				return false;
			}
			chargePhotonView.RPC("UpdateWindupDirection", (RpcTarget)2, new object[1] { (object)new Vector3(-777f, 0f, 0f) });
			return true;
		}

		private static bool TrySendVanillaRemoteCancelCommand(ChargeHandler chargeHandler)
		{
			PhotonView chargePhotonView = GetChargePhotonView(chargeHandler);
			if ((Object)(object)chargePhotonView == (Object)null || chargePhotonView.ViewID <= 0)
			{
				return false;
			}
			if (!PhotonNetwork.InRoom || PhotonNetwork.IsMasterClient)
			{
				return false;
			}
			chargePhotonView.RPC("CancelCharge", (RpcTarget)2, Array.Empty<object>());
			return true;
		}

		private static PhotonView? GetChargePhotonView(ChargeHandler chargeHandler)
		{
			if (chargeHandler != null)
			{
				PhotonView component = ((Component)chargeHandler).GetComponent<PhotonView>();
				if ((Object)(object)component != (Object)null && component.ViewID > 0)
				{
					return component;
				}
			}
			return GetDhhInputManagerHeadPhotonView();
		}

		private static PhotonView? GetDhhInputManagerHeadPhotonView()
		{
			return ((Object)(object)DHHInputManager.instance != (Object)null) ? DHHInputManager.instance.headPhotonView : null;
		}

		private static float GetMinimumChargeReleaseScale(ChargeHandler chargeHandler)
		{
			if ((Object)(object)chargeHandler == (Object)null)
			{
				return 0f;
			}
			float num = 0f;
			TryGetEffectiveChargeAbilityLevel(chargeHandler, out var abilityLevel);
			float effectiveChargeStrengthForThreshold = GetEffectiveChargeStrengthForThreshold(chargeHandler, abilityLevel);
			if (effectiveChargeStrengthForThreshold > 0f)
			{
				num = Mathf.Max(num, RequiredScaleForMinimumOne(effectiveChargeStrengthForThreshold));
			}
			float effectiveMaxBouncesForThreshold = GetEffectiveMaxBouncesForThreshold(chargeHandler, abilityLevel);
			if (effectiveMaxBouncesForThreshold > 0f)
			{
				num = Mathf.Max(num, RequiredScaleForMinimumOne(effectiveMaxBouncesForThreshold));
			}
			if (abilityLevel > 0)
			{
				float baseValue = 5f + 1f * (float)abilityLevel;
				num = Mathf.Max(num, RequiredScaleForMinimumOne(baseValue));
			}
			if (float.IsNaN(num) || float.IsInfinity(num))
			{
				return 1f;
			}
			return Mathf.Clamp01(num);
		}

		private static float GetEffectiveChargeStrengthForThreshold(ChargeHandler chargeHandler, int abilityLevel)
		{
			if (chargeHandler.chargeStrength > 0f)
			{
				return chargeHandler.chargeStrength;
			}
			if (abilityLevel <= 0)
			{
				return 0f;
			}
			return EvaluateStatWithDiminishingReturns(FeatureFlags.DHHChargeStrengthBaseValue, FeatureFlags.DHHChargeStrengthIncreasePerLevel, abilityLevel, FeatureFlags.DHHChargeStrengthThresholdLevel, FeatureFlags.DHHChargeStrengthDiminishingFactor).FinalValue;
		}

		private static float GetEffectiveMaxBouncesForThreshold(ChargeHandler chargeHandler, int abilityLevel)
		{
			if (chargeHandler.maxBounces > 0f)
			{
				return chargeHandler.maxBounces;
			}
			if (abilityLevel <= 0)
			{
				return 0f;
			}
			float baseValue = ((chargeHandler.baseMaxBounces > 0) ? ((float)chargeHandler.baseMaxBounces) : 3f);
			return Mathf.FloorToInt(EvaluateStatWithDiminishingReturns(baseValue, 0.5f, abilityLevel, 20, 0.9f).FinalValue);
		}

		private static bool TryGetEffectiveChargeAbilityLevel(ChargeHandler chargeHandler, out int abilityLevel)
		{
			abilityLevel = Mathf.Max(0, chargeHandler.AbilityLevel);
			if (abilityLevel > 0)
			{
				return true;
			}
			if (!SemiFunc.IsMasterClientOrSingleplayer() && IsLocalChargeHandler(chargeHandler) && TryGetLocalPlayerChargeUpgrade(out var upgrade))
			{
				abilityLevel = Mathf.Max(0, upgrade);
				return true;
			}
			return abilityLevel >= 0;
		}

		private static bool TryGetLocalPlayerChargeUpgrade(out int upgrade)
		{
			upgrade = 0;
			PlayerAvatar instance = PlayerAvatar.instance;
			string text = (((Object)(object)instance != (Object)null) ? SemiFunc.PlayerGetSteamID(instance) : null);
			if (string.IsNullOrWhiteSpace(text))
			{
				return false;
			}
			try
			{
				upgrade = DHHStatsManager.GetHeadChargeUpgrade(text);
				return true;
			}
			catch
			{
				return false;
			}
		}

		private static float RequiredScaleForMinimumOne(float baseValue)
		{
			if (baseValue <= 0f)
			{
				return float.PositiveInfinity;
			}
			return 1f / baseValue;
		}

		private static bool IsChargeHandlerHeadGrabbed(ChargeHandler chargeHandler)
		{
			PhysGrabObjectImpactDetector impactDetector = chargeHandler.impactDetector;
			if ((Object)(object)impactDetector == (Object)null)
			{
				return false;
			}
			PhysGrabObject physGrabObject = impactDetector.physGrabObject;
			if ((Object)(object)physGrabObject == (Object)null)
			{
				return false;
			}
			return physGrabObject.grabbed;
		}

		private static int GetUnityObjectInstanceId(Object obj)
		{
			return (obj != (Object)null) ? obj.GetInstanceID() : 0;
		}

		private static ChargeHoldState GetOrCreateChargeHoldState(int id)
		{
			if (!s_chargeHoldStates.TryGetValue(id, out ChargeHoldState value))
			{
				value = new ChargeHoldState();
				s_chargeHoldStates[id] = value;
			}
			return value;
		}

		private static bool IsChargeState(ChargeHandler chargeHandler, string stateName)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)chargeHandler == (Object)null)
			{
				return false;
			}
			return string.Equals(((object)chargeHandler.State/*cast due to .constrained prefix*/).ToString(), stateName, StringComparison.Ordinal);
		}

		private static bool IsLocalChargeHandler(ChargeHandler chargeHandler)
		{
			ChargeHandler localChargeHandler = GetLocalChargeHandler();
			if ((Object)(object)localChargeHandler == (Object)null)
			{
				return false;
			}
			return localChargeHandler == chargeHandler;
		}

		private static ChargeHandler? GetLocalChargeHandler()
		{
			PlayerAvatar instance = PlayerAvatar.instance;
			if ((Object)(object)instance?.playerDeathHead == (Object)null)
			{
				return null;
			}
			return ((Component)instance.playerDeathHead).GetComponent<DeathHeadController>()?.chargeHandler;
		}

		private static void ClearChargeHoldState(ChargeHandler? chargeHandler)
		{
			if (!((Object)(object)chargeHandler == (Object)null))
			{
				int unityObjectInstanceId = GetUnityObjectInstanceId((Object)(object)chargeHandler);
				if (unityObjectInstanceId != 0)
				{
					s_chargeHoldStates.Remove(unityObjectInstanceId);
				}
				AbilityModule.SetChargeSlotActivationProgress(0f);
			}
		}

		private static void ChargeHandler_ResetState_Postfix(ChargeHandler __instance)
		{
			StopChargeWindupLoop(__instance);
			ClearChargeHoldState(__instance);
			if (!((Object)(object)__instance == (Object)null))
			{
				int abilityLevel = __instance.AbilityLevel;
				DiminishingReturnsResult stat = EvaluateStatWithDiminishingReturns(FeatureFlags.DHHChargeStrengthBaseValue, FeatureFlags.DHHChargeStrengthIncreasePerLevel, abilityLevel, FeatureFlags.DHHChargeStrengthThresholdLevel, FeatureFlags.DHHChargeStrengthDiminishingFactor);
				__instance.chargeStrength = stat.FinalValue;
				LogChargeStrength(__instance, stat);
			}
		}

		private static void ChargeHandler_EndCharge_Postfix(ChargeHandler __instance)
		{
			StopChargeWindupLoop(__instance);
			ClearChargeHoldState(__instance);
			SynchronizeFinalChargeState(__instance);
		}

		private static void SynchronizeFinalChargeState(ChargeHandler? chargeHandler)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: 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)
			if ((Object)(object)chargeHandler == (Object)null || (int)chargeHandler.State != 0 || (int)chargeHandler.previousState == 0 || !SemiFunc.IsMultiplayer() || !SemiFunc.IsMasterClient())
			{
				return;
			}
			try
			{
				DeathHeadController controller = chargeHandler.controller;
				PhotonView val = ((controller != null) ? ((MonoBehaviourPun)controller).photonView : null);
				if ((Object)(object)val == (Object)null || val.ViewID <= 0)
				{
					return;
				}
				val.RPC("SyncChargeStateRPC", (RpcTarget)1, new object[1] { (object)(ChargeState)0 });
				chargeHandler.previousState = (ChargeState)0;
				if (FeatureFlags.DebugLogging)
				{
					ManualLogSource? obj = s_log;
					if (obj != null)
					{
						obj.LogDebug((object)$"[Fix:DHHChargeAudio] Synchronized final Charge state immediately for view {val.ViewID}.");
					}
				}
			}
			catch (Exception ex)
			{
				if (FeatureFlags.DebugLogging && LogLimiter.ShouldLog("Fix:DHHChargeAudio.FinalStateSync", 30))
				{
					ManualLogSource? obj2 = s_log;
					if (obj2 != null)
					{
						obj2.LogDebug((object)("[Fix:DHHChargeAudio] Immediate final-state sync failed: " + ex.GetType().Name + "; native Update sync remains available."));
					}
				}
			}
		}

		private static void StopChargeWindupLoop(ChargeHandler? chargeHandler)
		{
			if ((Object)(object)chargeHandler == (Object)null)
			{
				return;
			}
			try
			{
				DeathHeadController controller = chargeHandler.controller;
				if ((Object)(object)controller == (Object)null)
				{
					return;
				}
				ChargeEffects componentInChildren = ((Component)controller).GetComponentInChildren<ChargeEffects>(true);
				if ((Object)(object)componentInChildren != (Object)null)
				{
					try
					{
						componentInChildren.StopWindupState();
					}
					catch
					{
					}
					try
					{
						componentInChildren.StopChargeState();
						return;
					}
					catch
					{
						return;
					}
				}
				AudioHandler audioHandler = controller.audioHandler;
				if (!((Object)(object)audioHandler == (Object)null))
				{
					audioHandler.StopWindupSound();
				}
			}
			catch
			{
			}
		}

		private static DiminishingReturnsResult EvaluateStatWithDiminishingReturns(float baseValue, float increasePerLevel, int currentLevel, int thresholdLevel, float diminishingFactor)
		{
			int num = Math.Max(0, currentLevel - 1);
			int num2 = Math.Max(0, thresholdLevel - 1);
			int num3 = Mathf.Min(num, num2);
			int num4 = Mathf.Max(0, num - num2);
			float num5 = (float)num4 * Mathf.Pow(diminishingFactor, (float)num4);
			float num6 = increasePerLevel * (float)num3;
			float num7 = increasePerLevel * num5;
			float finalValue = baseValue + num6 + num7;
			return new DiminishingReturnsResult(baseValue, increasePerLevel, currentLevel, thresholdLevel, diminishingFactor, num3, num4, num6, num7, num5, finalValue);
		}

		private static string GetHandlerLabel(object? handler, string fallback)
		{
			Component val = (Component)((handler is Component) ? handler : null);
			if (val != null)
			{
				return ((Object)val).name ?? ((object)val).GetType().Name;
			}
			return handler?.GetType().Name ?? fallback;
		}

		private static void LogChargeStrength(object chargeHandler, DiminishingReturnsResult stat)
		{
			if (FeatureFlags.DebugLogging && LogLimiter.ShouldLog("Fix:Charge.Strength", 60))
			{
				string handlerLabel = GetHandlerLabel(chargeHandler, "ChargeHandler");
				string text = $"[Fix:Charge] {handlerLabel} Strength={stat.FinalValue:F3} base={stat.BaseValue:F3} inc={stat.IncreasePerLevel:F3} level={stat.AppliedLevel} fullUpgrades={stat.LinearLevels} dimUpgrades={stat.ExtraLevels} linearDelta={stat.LinearContribution:F3} dimDelta={stat.DiminishingContribution:F3} thresh={stat.ThresholdLevel} dimFactor={stat.DiminishingFactor:F3}";
				ManualLogSource? obj = s_log;
				if (obj != null)
				{
					obj.LogInfo((object)text);
				}
				Debug.Log((object)text);
			}
		}

		private static Vector3 CalculateEnemyBounceNormal(Transform? self, Vector3 enemyCenterPoint)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: 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_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)self == (Object)null)
			{
				return Vector3.up;
			}
			Vector3 val = self.TransformPoint(Vector3.up * 0.3f);
			Vector3 val2 = val - enemyCenterPoint;
			Vector3 val3 = Vector3.ProjectOnPlane(val2, Vector3.up);
			return ((Vector3)(ref val3)).normalized;
		}
	}
	[HarmonyPatch(typeof(StunHandler), "HandleStun")]
	internal static class StunHandlerReleasePatch
	{
		private const int ReleaseObjectViewId = -1;

		private static readonly MethodInfo? s_targetCall = AccessTools.Method(typeof(StunHandler), "PhysObjectHurt", new Type[3]
		{
			typeof(PhysGrabObject),
			typeof(BreakImpact),
			typeof(float)
		}, (Type[])null);

		private static readonly MethodInfo? s_replacement = AccessTools.Method(typeof(StunHandlerReleasePatch), "CustomPhysObjectHurt", new Type[4]
		{
			typeof(StunHandler),
			typeof(PhysGrabObject),
			typeof(BreakImpact),
			typeof(float)
		}, (Type[])null);

		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			foreach (CodeInstruction instruction in instructions)
			{
				if (s_targetCall != null && s_replacement != null && CodeInstructionExtensions.Calls(instruction, s_targetCall))
				{
					yield return new CodeInstruction(OpCodes.Call, (object)s_replacement);
				}
				else
				{
					yield return instruction;
				}
			}
		}

		private static void CustomPhysObjectHurt(StunHandler self, PhysGrabObject physGrabObject, BreakImpact impact, float hitForce)
		{
			//IL_0011: 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_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected I4, but got Unknown
			//IL_00b3: 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)
			if ((Object)(object)physGrabObject == (Object)null)
			{
				return;
			}
			switch (impact - 1)
			{
			case 0:
				physGrabObject.lightBreakImpulse = true;
				break;
			case 1:
				physGrabObject.mediumBreakImpulse = true;
				break;
			case 2:
				physGrabObject.heavyBreakImpulse = true;
				break;
			}
			if (!(hitForce >= 5f) || physGrabObject.playerGrabbing.Count <= 0)
			{
				return;
			}
			foreach (PhysGrabber item in physGrabObject.playerGrabbing.ToList())
			{
				if (!((Object)(object)item == (Object)null))
				{
					if (!SemiFunc.IsMultiplayer())
					{
						item.ReleaseObjectRPC(true, 2f, -1, default(PhotonMessageInfo));
						continue;
					}
					item.photonView.RPC("ReleaseObjectRPC", (RpcTarget)0, new object[3] { false, 1f, -1 });
				}
			}
		}
	}
}
namespace DeathHeadHopperFix.Modules.Gameplay.Spectate
{
	public static class AbilityBarVisibilityAnchor
	{
		private static readonly HashSet<string> ActiveDemands = new HashSet<string>();

		public static bool HasExternalDemand()
		{
			lock (ActiveDemands)
			{
				return ActiveDemands.Count > 0;
			}
		}

		public static void SetExternalDemand(string sourceId, bool active)
		{
			if (string.IsNullOrWhiteSpace(sourceId))
			{
				return;
			}
			lock (ActiveDemands)
			{
				if (active)
				{
					ActiveDemands.Add(sourceId);
				}
				else
				{
					ActiveDemands.Remove(sourceId);
				}
			}
		}

		public static void ClearExternalDemands()
		{
			lock (ActiveDemands)
			{
				ActiveDemands.Clear();
			}
		}
	}
	[HarmonyPatch(typeof(SpectateCamera), "LateUpdate")]
	internal static class AbilityBarVisibilityModule
	{
		private static Type? s_dhhAbilityManagerType;

		private static PropertyInfo? s_dhhAbilityManagerInstanceProperty;

		private static MethodInfo? s_hasEquippedAbilityMethod;

		private static Type? s_abilityUiType;

		private static FieldInfo? s_abilityUiInstanceField;

		private static MethodInfo? s_abilityUiShowMethod;

		private static Type? s_abilityEnergyUiType;

		private static FieldInfo? s_abilityEnergyUiInstanceField;

		private static MethodInfo? s_abilityEnergyUiShowMethod;

		private static bool? s_lastShouldShow;

		[HarmonyPostfix]
		private static void LateUpdatePostfix()
		{
			if (InternalDebugFlags.DisableAbilityPatches)
			{
				return;
			}
			if (!ShouldEvaluateInCurrentContext())
			{
				s_lastShouldShow = null;
				return;
			}
			if (!ShouldShowAbilityBar())
			{
				if (FeatureFlags.DebugLogging && s_lastShouldShow == true)
				{
					Debug.Log((object)"[Fix:AbilityBar] hidden by policy (native=false, external=false).");
				}
				s_lastShouldShow = false;
				return;
			}
			if (FeatureFlags.DebugLogging && s_lastShouldShow != true)
			{
				bool flag = HasNativeEquippedAbility();
				bool flag2 = HasExternalAbilityUiDemand();
				Debug.Log((object)$"[Fix:AbilityBar] show by policy (native={flag}, external={flag2}).");
			}
			TryShowAbilityUi();
			TryShowAbilityEnergyUi();
			s_lastShouldShow = true;
		}

		private static bool ShouldShowAbilityBar()
		{
			return HasNativeEquippedAbility() || HasExternalAbilityUiDemand();
		}

		private static bool HasExternalAbilityUiDemand()
		{
			return AbilityBarVisibilityAnchor.HasExternalDemand();
		}

		private static bool ShouldEvaluateInCurrentContext()
		{
			if (!SemiFunc.RunIsLevel() && !SemiFunc.RunIsShop())
			{
				return false;
			}
			if (HasExternalAbilityUiDemand())
			{
				return true;
			}
			return SpectateContextHelper.IsLocalDeathHeadSpectated();
		}

		private static bool HasNativeEquippedAbility()
		{
			ResolveDhhAbilityManagerReflection();
			if (s_dhhAbilityManagerInstanceProperty == null || s_hasEquippedAbilityMethod == null)
			{
				return false;
			}
			object value = s_dhhAbilityManagerInstanceProperty.GetValue(null);
			if (value == null)
			{
				return false;
			}
			return s_hasEquippedAbilityMethod.Invoke(value, null) as bool? == true;
		}

		private static void TryShowAbilityUi()
		{
			ResolveAbilityUiReflection();
			object obj = s_abilityUiInstanceField?.GetValue(null);
			if (obj == null || s_abilityUiShowMethod == null)
			{
				return;
			}
			try
			{
				s_abilityUiShowMethod.Invoke(obj, null);
			}
			catch
			{
			}
		}

		private static void TryShowAbilityEnergyUi()
		{
			ResolveAbilityEnergyUiReflection();
			object obj = s_abilityEnergyUiInstanceField?.GetValue(null);
			if (obj == null || s_abilityEnergyUiShowMethod == null)
			{
				return;
			}
			try
			{
				s_abilityEnergyUiShowMethod.Invoke(obj, null);
			}
			catch
			{
			}
		}

		private static void ResolveDhhAbilityManagerReflection()
		{
			if ((object)s_dhhAbilityManagerType == null)
			{
				s_dhhAbilityManagerType = AccessTools.TypeByName("DeathHeadHopper.Managers.DHHAbilityManager");
			}
			if (!(s_dhhAbilityManagerType == null))
			{
				if ((object)s_dhhAbilityManagerInstanceProperty == null)
				{
					s_dhhAbilityManagerInstanceProperty = s_dhhAbilityManagerType.GetProperty("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				}
				if ((object)s_hasEquippedAbilityMethod == null)
				{
					s_hasEquippedAbilityMethod = s_dhhAbilityManagerType.GetMethod("HasEquippedAbility", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
			}
		}

		private static void ResolveAbilityUiReflection()
		{
			if ((object)s_abilityUiType == null)
			{
				s_abilityUiType = AccessTools.TypeByName("DeathHeadHopper.UI.AbilityUI");
			}
			if (!(s_abilityUiType == null))
			{
				if ((object)s_abilityUiInstanceField == null)
				{
					s_abilityUiInstanceField = s_abilityUiType.GetField("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				}
				if ((object)s_abilityUiShowMethod == null)
				{
					s_abilityUiShowMethod = s_abilityUiType.GetMethod("Show", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
			}
		}

		private static void ResolveAbilityEnergyUiReflection()
		{
			if ((object)s_abilityEnergyUiType == null)
			{
				s_abilityEnergyUiType = AccessTools.TypeByName("DeathHeadHopper.UI.AbilityEnergyUI");
			}
			if (!(s_abilityEnergyUiType == null))
			{
				if ((object)s_abilityEnergyUiInstanceField == null)
				{
					s_abilityEnergyUiInstanceField = s_abilityEnergyUiType.GetField("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				}
				if ((object)s_abilityEnergyUiShowMethod == null)
				{
					s_abilityEnergyUiShowMethod = s_abilityEnergyUiType.GetMethod("Show", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
			}
		}
	}
	internal static class DeathMinimapBridge
	{
		internal static void Reset()
		{
		}

		internal static void Tick()
		{
		}
	}
	[HarmonyPatch(typeof(SpectateCamera), "LateUpdate")]
	internal static class SpectateRawInputDebugPatch
	{
		private static SpectateCamera? s_pendingCamera;

		private static PlayerAvatar? s_pendingPlayer;

		private static bool s_pendingNext;

		private static bool s_pendingPrevious;

		private static int s_pendingFrame = -1;

		[HarmonyPrefix]
		private static void Prefix(SpectateCamera __instance)
		{
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			ClearPendingInput();
			if ((Object)(object)__instance == (Object)null || !DHHFunc.LocalDeathHeadActive())
			{
				return;
			}
			bool flag = SemiFunc.InputDown((InputKey)23);
			bool flag2 = SemiFunc.InputDown((InputKey)24);
			if (flag || flag2)
			{
				s_pendingCamera = __instance;
				s_pendingPlayer = __instance.player;
				s_pendingNext = flag;
				s_pendingPrevious = flag2;
				s_pendingFrame = Time.frameCount;
				if (FeatureFlags.DebugLogging)
				{
					Debug.Log((object)("[Fix:SpectateDebug] Raw spectate input detected " + $"next={flag}, previous={flag2}, state={__instance.currentState}, " + "player=" + Describe(__instance.player)));
				}
			}
		}

		private static string Describe(PlayerAvatar? avatar)
		{
			if ((Object)(object)avatar == (Object)null)
			{
				return "null";
			}
			string text = (((Object)(object)avatar.photonView != (Object)null) ? avatar.photonView.ViewID.ToString() : "local");
			return $"{((Object)avatar).name}(id={((Object)avatar).GetInstanceID()},view={text},disabled={avatar.isDisabled},dead={avatar.deadSet})";
		}

		[HarmonyPostfix]
		private static void Postfix(SpectateCamera __instance)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Invalid comparison between Unknown and I4
			if ((Object)(object)__instance == (Object)null || (Object)(object)s_pendingCamera != (Object)(object)__instance || s_pendingFrame != Time.frameCount)
			{
				return;
			}
			PlayerAvatar val = s_pendingPlayer;
			bool flag = s_pendingNext;
			bool flag2 = s_pendingPrevious;
			ClearPendingInput();
			if ((int)__instance.currentState == 1 && !((Object)(object)MenuManager.instance?.currentMenuPage != (Object)null) && __instance.player == val)
			{
				if (flag)
				{
					__instance.PlayerSwitch(true);
				}
				else if (flag2)
				{
					__instance.PlayerSwitch(false);
				}
				if (FeatureFlags.DebugLogging)
				{
					Debug.Log((object)($"[Fix:SpectateDebug] Deferred PlayerSwitch executed next={flag}, " + $"previous={flag2}, player={Describe(__instance.player)}"));
				}
			}
		}

		private static void ClearPendingInput()
		{
			s_pendingCamera = null;
			s_pendingPlayer = null;
			s_pendingNext = false;
			s_pendingPrevious = false;
			s_pendingFrame = -1;
		}
	}
	[HarmonyPatch(typeof(SpectateCamera), "StateHead")]
	internal static class SpectateHeadInputDebugPatch
	{
		[HarmonyPrefix]
		private static void Prefix(SpectateCamera __instance)
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)__instance == (Object)null) && ShouldLog(__instance))
			{
				bool flag = SemiFunc.InputDown((InputKey)23);
				bool flag2 = SemiFunc.InputDown((InputKey)24);
				if (flag || flag2)
				{
					PlayerAvatar player = __instance.player;
					Debug.Log((object)("[Fix:SpectateDebug] StateHead received spectate input " + $"next={flag}, previous={flag2}, player={Describe(player)}, " + $"state={__instance.currentState}. No vanilla PlayerSwitch call is expected from StateHead."));
				}
			}
		}

		private static bool ShouldLog(SpectateCamera? spectate)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Invalid comparison between Unknown and I4
			return FeatureFlags.DebugLogging && (Object)(object)spectate != (Object)null && (int)spectate.currentState == 2 && DHHFunc.LocalDeathHeadActive();
		}

		private static string Describe(PlayerAvatar? avatar)
		{
			if ((Object)(object)avatar == (Object)null)
			{
				return "null";
			}
			string text = (((Object)(object)avatar.photonView != (Object)null) ? avatar.photonView.ViewID.ToString() : "local");
			return $"{((Object)avatar).name}(id={((Object)avatar).GetInstanceID()},view={text},disabled={avatar.isDisabled},dead={avatar.deadSet})";
		}
	}
	[HarmonyPatch(typeof(SpectateCamera), "PlayerSwitch")]
	internal static class SpectatePlayerSwitchDebugPatch
	{
		[HarmonyPrefix]
		private static void Prefix(SpectateCamera __instance, bool _next, out PlayerAvatar? __state)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			__state = __instance?.player;
			if (!((Object)(object)__instance == (Object)null) && ShouldLog(__instance))
			{
				Debug.Log((object)($"[Fix:SpectateDebug] PlayerSwitch entered next={_next}, " + $"state={__instance.currentState}, player={Describe(__instance.player)}"));
			}
		}

		[HarmonyPostfix]
		private static void Postfix(SpectateCamera __instance, bool _next, PlayerAvatar? __state)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)__instance == (Object)null) && ShouldLog(__instance))
			{
				PlayerAvatar player = __instance.player;
				int num = CountActiveAlternatives(player);
				bool flag = __state != player;
				Debug.Log((object)($"[Fix:SpectateDebug] PlayerSwitch exited next={_next}, " + $"state={__instance.currentState}, player={Describe(player)}, " + $"activeAlternatives={num}, " + "result=" + (flag ? "target changed successfully" : "target unchanged") + ", reason=" + (flag ? "none" : GetUnchangedTargetReason(player, num))));
			}
		}

		private static bool ShouldLog(SpectateCamera? spectate)
		{
			return FeatureFlags.DebugLogging && (Object)(object)spectate != (Object)null && DHHFunc.LocalDeathHeadActive();
		}

		private static string Describe(PlayerAvatar? avatar)
		{
			if ((Object)(object)avatar == (Object)null)
			{
				return "null";
			}
			string text = (((Object)(object)avatar.photonView != (Object)null) ? avatar.photonView.ViewID.ToString() : "local");
			return $"{((Object)avatar).name}(id={((Object)avatar).GetInstanceID()},view={text},disabled={avatar.isDisabled},dead={avatar.deadSet})";
		}

		private static int CountActiveAlternatives(PlayerAvatar? current)
		{
			List<PlayerAvatar> list = GameDirector.instance?.PlayerList;
			if (list == null)
			{
				return 0;
			}
			int num = 0;
			foreach (PlayerAvatar item in list)
			{
				if ((Object)(object)item != (Object)null && item != current && !item.isDisabled)
				{
					num++;
				}
			}
			return num;
		}

		private static string GetUnchangedTargetReason(PlayerAvatar? current, int activeAlternatives)
		{
			if (activeAlternatives == 0)
			{
				return "no active alternative players";
			}
			if ((Object)(object)current != (Object)null && current.isDisabled)
			{
				return "active alternatives exist but current disabled target was retained";
			}
			return "target unchanged despite active alternatives";
		}
	}
}
namespace DeathHeadHopperFix.Modules.Gameplay.Core.Runtime
{
	internal static class StatsModule
	{
		private static bool _statsHooksApplied;

		internal static void ApplyHooks(Harmony harmony)
		{
			if (harmony != null && !_statsHooksApplied)
			{
				PatchSemiFuncStatGetItemsPurchasedIfPossible(harmony);
				PatchStatsManagerGetItemsUpgradesPurchasedIfPossible(harmony);
				PatchStatsManagerItemPurchaseIfPossible(harmony);
				_statsHooksApplied = true;
			}
		}

		internal static void EnsureStatsManagerKey(string itemName)
		{
			if (!string.IsNullOrWhiteSpace(itemName))
			{
				StatsManager instance = StatsManager.instance;
				if (!((Object)(object)instance == (Object)null))
				{
					EnsureKey(instance.itemsPurchased, itemName);
					EnsureKey(instance.itemsPurchasedTotal, itemName);
					EnsureKey(instance.itemsUpgradesPurchased, itemName);
				}
			}
		}

		internal static void EnsureStatsEntriesForItem(Object itemObj)
		{
			try
			{
				if (!(itemObj == (Object)null))
				{
					StatsManager instance = StatsManager.instance;
					if (!((Object)(object)instance == (Object)null))
					{
						EnsureKey(instance.itemsPurchased, itemObj.name);
						EnsureKey(instance.itemsPurchasedTotal, itemObj.name);
						EnsureKey(instance.itemsUpgradesPurchased, itemObj.name);
					}
				}
			}
			catch
			{
			}
		}

		private static void PatchSemiFuncStatGetItemsPurchasedIfPossible(Harmony harmony)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(typeof(SemiFunc), "StatGetItemsPurchased", new Type[1] { typeof(string) }, (Type[])null);
			if (!(methodInfo == null))
			{
				MethodInfo method = typeof(StatsModule).GetMethod("SemiFunc_StatGetItemsPurchased_Prefix", BindingFlags.Static | BindingFlags.NonPublic);
				if (!(method == null))
				{
					harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
		}

		private static bool SemiFunc_StatGetItemsPurchased_Prefix(string itemName, ref int __result)
		{
			try
			{
				StatsManager instance = StatsManager.instance;
				if ((Object)(object)instance == (Object)null)
				{
					return true;
				}
				EnsureKey(instance.itemsPurchased, itemName);
				__result = instance.itemsPurchased[itemName];
				return false;
			}
			catch
			{
			}
			return true;
		}

		private static void PatchStatsManagerGetItemsUpgradesPurchasedIfPossible(Harmony harmony)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(typeof(StatsManager), "GetItemsUpgradesPurchased", new Type[1] { typeof(string) }, (Type[])null);
			if (!(methodInfo == null))
			{
				MethodInfo method = typeof(StatsModule).GetMethod("StatsManager_GetItemsUpgradesPurchased_Prefix", BindingFlags.Static | BindingFlags.NonPublic);
				if (!(method == null))
				{
					harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
		}

		private static bool StatsManager_GetItemsUpgradesPurchased_Prefix(string itemName, ref int __result)
		{
			try
			{
				StatsManager instance = StatsManager.instance;
				if ((Object)(object)instance == (Object)null)
				{
					return true;
				}
				EnsureKey(instance.itemsUpgradesPurchased, itemName);
				__result = instance.itemsUpgradesPurchased[itemName];
				return false;
			}
			catch
			{
			}
			return true;
		}

		private static void PatchStatsManagerItemPurchaseIfPossible(Harmony harmony)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Expected O, but got Unknown
			if (harmony == null)
			{
				return;
			}
			MethodInfo methodInfo = AccessTools.Method(typeof(StatsManager), "ItemPurchase", new Type[1] { typeof(string) }, (Type[])null);
			if (!(methodInfo == null))
			{
				MethodInfo method = typeof(StatsModule).GetMethod("StatsManager_ItemPurchase_Prefix", BindingFlags.Static | BindingFlags.NonPublic);
				if (!(method == null))
				{
					harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
		}

		private static bool StatsManager_ItemPurchase_Prefix(string itemName)
		{
			EnsureStatsManagerKey(itemName);
			return true;
		}

		private static void EnsureKey(IDictionary<string, int> dictionary, string key)
		{
			if (dictionary != null && !string.IsNullOrWhiteSpace(key) && !dictionary.ContainsKey(key))
			{
				dictionary[key] = 0;
			}
		}
	}
}
namespace DeathHeadHopperFix.Modules.Gameplay.Core.Interop
{
	internal static class DHHApiGuardModule
	{
		private static bool s_guardMissingLocalCameraPosition;

		internal static void DetectGameApiChanges()
		{
			try
			{
				Type type = AccessTools.TypeByName("PlayerAvatar");
				if (type == null)
				{
					s_guardMissingLocalCameraPosition = true;
					return;
				}
				FieldInfo field = type.GetField("localCameraPosition", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				s_guardMissingLocalCameraPosition = field == null;
			}
			catch
			{
				s_guardMissingLocalCameraPosition = true;
			}
		}

		internal static void Apply(Harmony harmony, Assembly asm)
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Expected O, but got Unknown
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Expected O, but got Unknown
			if (!s_guardMissingLocalCameraPosition)
			{
				return;
			}
			Type type = asm.GetType("DeathHeadHopper.DeathHead.DeathHeadController", throwOnError: false);
			if (type == null)
			{
				return;
			}
			MethodInfo methodInfo = AccessTools.Method(type, "CancelReviveInCart", (Type[])null, (Type[])null);
			if (methodInfo != null)
			{
				MethodInfo method = typeof(DHHApiGuardModule).GetMethod("DeathHeadController_CancelReviveInCart_Prefix", BindingFlags.Static | BindingFlags.NonPublic);
				if (method != null)
				{
					harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
			MethodInfo methodInfo2 = AccessTools.Method(type, "Update", (Type[])null, (Type[])null);
			if (methodInfo2 != null)
			{
				MethodInfo method2 = typeof(DHHApiGuardModule).GetMethod("DeathHeadController_Update_Finalizer", BindingFlags.Static | BindingFlags.NonPublic);
				if (method2 != null)
				{
					harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(method2), (HarmonyMethod)null);
				}
			}
		}

		private static bool DeathHeadController_CancelReviveInCart_Prefix()
		{
			return !s_guardMissingLocalCameraPosition;
		}

		private static Exception? DeathHeadController_Update_Finalizer(Exception? __exception)
		{
			if (__exception == null)
			{
				return null;
			}
			if (s_guardMissingLocalCameraPosition && __exception is MissingFieldException)
			{
				return null;
			}
			return __exception;
		}
	}
	internal static class DHHPunViewFixModule
	{
		private sealed class DHHPunViewRoomSyncRelay : MonoBehaviourPunCallbacks
		{
			private MonoBehaviour? _sourceInstance;

			internal void Bind(MonoBehaviour sourceInstance)
			{
				_sourceInstance = sourceInstance;
				Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
			}

			public override void OnJoinedRoom()
			{
				OnRoomSyncChanged(_sourceInstance);
			}

			public override void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged)
			{
				if (propertiesThatChanged != null && ((Dictionary<object, object>)(object)propertiesThatChanged).ContainsKey((object)"DHHFix.PunViewId"))
				{
					OnRoomSyncChanged(_sourceInstance);
				}
			}

			public override void OnMasterClientSwitched(Player newMasterClient)
			{
				OnRoomSyncChanged(_sourceInstance);
			}
		}

		private const string DhhPunViewIdRoomKey = "DHHFix.PunViewId";

		private static ManualLogSource? _log;

		private static readonly MethodInfo? VersionCheckMethodInfo = AccessTools.Method("DeathHeadHopper.Managers.DHHPunManager:VersionCheck", (Type[])null, (Type[])null);

		internal static void Apply(Harmony harmony, Assembly asm, ManualLogSource? log)
		{
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Expected O, but got Unknown
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Expected O, but got Unknown
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Expected O, but got Unknown
			_log = log;
			if (harmony == null || asm == null)
			{
				return;
			}
			Type type = asm.GetType("DeathHeadHopper.Managers.DHHPunManager", throwOnError: false);
			if (!(type == null))
			{
				MethodInfo methodInfo = AccessTools.Method(type, "Awake", (Type[])null, (Type[])null);
				MethodInfo methodInfo2 = AccessTools.Method(type, "EnsurePhotonView", (Type[])null, (Type[])null);
				MethodInfo methodInfo3 = AccessTools.Method(type, "VersionCheck", (Type[])null, (Type[])null);
				MethodInfo method = typeof(DHHPunViewFixModule).GetMethod("DHHPunManager_Awake_Postfix", BindingFlags.Static | BindingFlags.NonPublic);
				MethodInfo method2 = typeof(DHHPunViewFixModule).GetMethod("DHHPunManager_EnsurePhotonView_Prefix", BindingFlags.Static | BindingFlags.NonPublic);
				MethodInfo method3 = typeof(DHHPunViewFixModule).GetMethod("DHHPunManager_VersionCheck_Prefix", BindingFlags.Static | BindingFlags.NonPublic);
				if (methodInfo != null && method != null)
				{
					harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				if (methodInfo2 != null && method2 != null)
				{
					harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				if (methodInfo3 != null && method3 != null)
				{
					harmony.Patch((MethodBase)methodInfo3, new HarmonyMethod(method3), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
		}

		private static void DHHPunManager_Awake_Postfix(MonoBehaviour __instance)
		{
			try
			{
				if (!((Object)(object)__instance == (Object)null))
				{
					BindDedicatedPhotonView(__instance);
					EnsureRoomSyncRelay(__instance);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogWarning((object)("DHHPunViewFix Awake postfix failed: " + ex.GetType().Name));
				}
			}
		}

		private static bool DHHPunManager_EnsurePhotonView_Prefix(MonoBehaviour __instance)
		{
			try
			{
				if ((Object)(object)__instance == (Object)null)
				{
					return true;
				}
				BindDedicatedPhotonView(__instance);
				EnsureRoomSyncRelay(__instance);
			}
			catch (Exception ex)
			{
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogWarning((object)("DHHPunViewFix EnsurePhotonView prefix failed: " + ex.GetType().Name));
				}
			}
			return true;
		}

		private static bool DHHPunManager_VersionCheck_Prefix(MonoBehaviour __instance)
		{
			try
			{
				if ((Object)(object)__instance == (Object)null)
				{
					return false;
				}
				BindDedicatedPhotonView(__instance);
				PhotonView component = ((Component)__instance).GetComponent<PhotonView>();
				if ((Object)(object)component == (Object)null || component.ViewID <= 0)
				{
					if (FeatureFlags.DebugLogging && LogLimiter.ShouldLog("Fix:DHHPunView.VersionCheck.NoView", 30))
					{
						ManualLogSource? log = _log;
						if (log != null)
						{
							log.LogWarning((object)"[Fix:DHHPunView] Skipping VersionCheck RPC because PhotonView ID is not valid yet.");
						}
					}
					return false;
				}
			}
			catch (Exception ex)
			{
				ManualLogSource? log2 = _log;
				if (log2 != null)
				{
					log2.LogWarning((object)("DHHPunViewFix VersionCheck prefix failed: " + ex.GetType().Name));
				}
				return false;
			}
			return true;
		}

		private static void BindDedicatedPhotonView(MonoBehaviour sourceInstance)
		{
			Type type = ((object)sourceInstance).GetType();
			PropertyInfo property = type.GetProperty("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			FieldInfo field = type.GetField("photonView", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if ((Object)(object)((Component)sourceInstance).gameObject == (Object)null)
			{
				return;
			}
			if (FeatureFlags.DebugLogging && LogLimiter.ShouldLog("Fix:DHHPunView.Host", 30))
			{
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogInfo((object)("[Fix:DHHPunView] Using dedicated host GO='" + ((Object)((Component)sourceInstance).gameObject).name + "'."));
				}
			}
			Object.DontDestroyOnLoad((Object)(object)((Component)sourceInstance).gameObject);
			PhotonView val = ((Component)sourceInstance).gameObject.GetComponent<PhotonView>();
			if ((Object)(object)val == (Object)null)
			{
				val = ((Component)sourceInstance).gameObject.AddComponent<PhotonView>();
				if (FeatureFlags.DebugLogging && LogLimiter.ShouldLog("Fix:DHHPunView.AddPhotonView", 30))
				{
					ManualLogSource? log2 = _log;
					if (log2 != null)
					{
						log2.LogInfo((object)"[Fix:DHHPunView] Added PhotonView to DHHPunManager GO.");
					}
				}
			}
			EnsureSynchronizedViewId(val);
			property?.SetValue(null, sourceInstance, null);
			field?.SetValue(sourceInstance, val);
			if (FeatureFlags.DebugLogging && LogLimiter.ShouldLog("Fix:DHHPunView.Bound", 15))
			{
				ManualLogSource? log3 = _log;
				if (log3 != null)
				{
					log3.LogInfo((object)$"[Fix:DHHPunView] Bound DHHPunManager to dedicated PhotonView {val.ViewID} on '{((Object)((Component)sourceInstance).gameObject).name}'.");
				}
			}
		}

		private static void EnsureSynchronizedViewId(PhotonView photonView)
		{
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Expected O, but got Unknown
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Expected O, but got Unknown
			if ((Object)(object)photonView == (Object)null || !PhotonNetwork.InRoom || PhotonNetwork.CurrentRoom == null)
			{
				return;
			}
			try
			{
				if (PhotonNetwork.IsMasterClient)
				{
					if (photonView.ViewID <= 0 && !PhotonNetwork.AllocateViewID(photonView))
					{
						return;
					}
					int viewID = photonView.ViewID;
					Hashtable customProperties = ((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties;
					if (customProperties != null && ((Dictionary<object, object>)(object)customProperties).TryGetValue((object)"DHHFix.PunViewId", out object value) && value is int num && num > 0)
					{
						TryAssignViewId(photonView, num, "master-sync-existing");
						return;
					}
					Hashtable val = new Hashtable { [(object)"DHHFix.PunViewId"] = viewID };
					Hashtable val2 = new Hashtable { [(object)"DHHFix.PunViewId"] = null };
					if (!PhotonNetwork.CurrentRoom.SetCustomProperties(val, val2, (WebFlags)null))
					{
						Hashtable customProperties2 = ((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties;
						if (customProperties2 != null && ((Dictionary<object, object>)(object)customProperties2).TryGetValue((object)"DHHFix.PunViewId", out object value2) && value2 is int num2 && num2 > 0)
						{
							TryAssignViewId(photonView, num2, "master-sync-after-cas-fail");
						}
					}
				}
				else
				{
					Hashtable customProperties3 = ((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties;
					if (customProperties3 != null && ((Dictionary<object, object>)(object)customProperties3).TryGetValue((object)"DHHFix.PunViewId", out object value3) && value3 is int num3 && num3 > 0)
					{
						TryAssignViewId(photonView, num3, "client-sync");
					}
				}
			}
			catch (Exception ex)
			{
				if (FeatureFlags.DebugLogging && LogLimiter.ShouldLog("Fix:DHHPunView.Sync.Error", 30))
				{
					ManualLogSource? log = _log;
					if (log != null)
					{
						log.LogWarning((object)("DHHPunViewFix sync failed: " + ex.GetType().Name));
					}
				}
			}
		}

		private static bool TryAssignViewId(PhotonView photonView, int viewId, string reason)
		{
			if ((Object)(object)photonView == (Object)null || viewId <= 0)
			{
				return false;
			}
			if (photonView.ViewID == viewId)
			{
				return true;
			}
			PhotonView val = PhotonView.Find(viewId);
			if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)photonView)
			{
				if (FeatureFlags.DebugLogging && LogLimiter.ShouldLog("Fix:DHHPunView.Sync.Conflict", 15))
				{
					ManualLogSource? log = _log;
					if (log != null)
					{
						log.LogWarning((object)$"[Fix:DHHPunView] Refusing ViewID {viewId} ({reason}) because it is already owned by '{((Object)((Component)val).gameObject).name}'.");
					}
				}
				return false;
			}
			photonView.ViewID = viewId;
			return photonView.ViewID == viewId;
		}

		private static void EnsureRoomSyncRelay(MonoBehaviour sourceInstance)
		{
			if (!((Object)(object)sourceInstance == (Object)null) && !((Object)(object)((Component)sourceInstance).gameObject == (Object)null))
			{
				DHHPunViewRoomSyncRelay dHHPunViewRoomSyncRelay = ((Component)sourceInstance).gameObject.GetComponent<DHHPunViewRoomSyncRelay>();
				if ((Object)(object)dHHPunViewRoomSyncRelay == (Object)null)
				{
					dHHPunViewRoomSyncRelay = ((Component)sourceInstance).gameObject.AddComponent<DHHPunViewRoomSyncRelay>();
				}
				dHHPunViewRoomSyncRelay.Bind(sourceInstance);
			}
		}

		private static void OnRoomSyncChanged(MonoBehaviour? sourceInstance)
		{
			if (!((Object)(object)sourceInstance == (Object)null))
			{
				BindDedicatedPhotonView(sourceInstance);
				TryInvokeVersionCheck(sourceInstance);
			}
		}

		private static void TryInvokeVersionCheck(MonoBehaviour sourceInstance)
		{
			if ((Object)(object)sourceInstance == (Object)null)
			{
				return;
			}
			PhotonView component = ((Component)sourceInstance).GetComponent<PhotonView>();
			if (component == null || component.ViewID <= 0)
			{
				return;
			}
			try
			{
				VersionCheckMethodInfo?.Invoke(sourceInstance, Array.Empty<object>());
			}
			catch (Exception ex)
			{
				if (FeatureFlags.DebugLogging && LogLimiter.ShouldLog("Fix:DHHPunView.VersionCheck.InvokeFail", 30))
				{
					ManualLogSource? log = _log;
					if (log != null)
					{
						log.LogWarning((object)("DHHPunViewFix VersionCheck invoke failed: " + ex.GetType().Name));
					}
				}
			}
		}
	}
	internal static class DHHShopVanillaPoolModule
	{
		private static bool _hooksApplied;

		private static ManualLogSource? _log;

		private static readonly HashSet<string> LoggedWarnings = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		internal static void Apply(Harmony harmony, Assembly asm, ManualLogSource? log)
		{
			_log = log;
			if (harmony == null || _hooksApplied)
			{
				return;
			}
			try
			{
				Patch(harmony, AccessTools.Method(typeof(DHHPunManager), "LoadShopAtticShelves", (Type[])null, (Type[])null));
				Patch(harmony, AccessTools.Method(typeof(DHHPunManager), "LoadShopAtticShelvesRPC", (Type[])null, (Type[])null));
				Patch(harmony, AccessTools.Method(typeof(DHHShopManager), "LoadShopAtticShelves", (Type[])null, (Type[])null));
				Patch(harmony, AccessTools.Method(typeof(DHHShopManager), "LoadItems", (Type[])null, (Type[])null));
				Patch(harmony, AccessTools.Method(typeof(DHHShopManager), "ShopPopulateItemVolumes", new Type[1] { typeof(PunManager) }, (Type[])null));
				PatchItemManagerGetPurchasedItems(harmony);
				PatchLevelGeneratorItemSetup(harmony);
				PatchShopInitialize(harmony);
				PatchShopItemsCollection(harmony);
				PatchUpgradeStandSelection(harmony);
				_hooksApplied = true;
				ManualLogSource? log2 = _log;
				if (log2 != null)
				{
					log2.LogInfo((object)"[Fix:Shop] Original DeathHeadHopper custom shop flow disabled; vanilla shop pool orchestrator enabled.");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource? log3 = _log;
				if (log3 != null)
				{
					log3.LogWarning((object)("[Fix:Shop] Failed to disable original DeathHeadHopper custom shop flow: " + ex.Message));
				}
			}
		}

		private static void Patch(Harmony harmony, MethodInfo? original)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			if (!(original == null))
			{
				HarmonyMethod val = new HarmonyMethod(typeof(DHHShopVanillaPoolModule), "BlockOriginalShopMethod_Prefix", (Type[])null);
				harmony.Patch((MethodBase)original, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}

		private static void PatchShopInitialize(Harmony harmony)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(typeof(ShopManager), "ShopInitialize", (Type[])null, (Type[])null);
			if (!(methodInfo == null))
			{
				HarmonyMethod val = new HarmonyMethod(typeof(DHHShopVanillaPoolModule), "ShopManager_ShopInitialize_Prefix", (Type[])null);
				harmony.Patch((MethodBase)methodInfo, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}

		private static void PatchShopItemsCollection(Harmony harmony)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(typeof(ShopManager), "GetAllItemsFromStatsManager", (Type[])null, (Type[])null);
			if (!(methodInfo == null))
			{
				HarmonyMethod val = new HarmonyMethod(typeof(DHHShopVanillaPoolModule), "ShopManager_GetAllItemsFromStatsManager_Postfix", (Type[])null);
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}

		private static void PatchUpgradeStandSelection(Harmony harmony)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(typeof(UpgradeStand), "GetWeightedUpgradeExcluding", (Type[])null, (Type[])null);
			if (!(methodInfo == null))
			{
				HarmonyMethod val = new HarmonyMethod(typeof(DHHShopVanillaPoolModule), "UpgradeStand_GetWeightedUpgradeExcluding_Prefix", (Type[])null);
				harmony.Patch((MethodBase)methodInfo, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}

		private static void PatchLevelGeneratorItemSetup(Harmony harmony)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(typeof(LevelGenerator), "ItemSetup", (Type[])null, (Type[])null);
			if (!(methodInfo == null))
			{
				HarmonyMethod val = new HarmonyMethod(typeof(DHHShopVanillaPoolModule), "LevelGenerator_ItemSetup_Postfix", (Type[])null);
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}

		private static void PatchItemManagerGetPurchasedItems(Harmony harmony)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(typeof(ItemManager), "GetPurchasedItems", (Type[])null, (Type[])null);
			if (!(methodInfo == null))
			{
				HarmonyMethod val = new HarmonyMethod(typeof(DHHShopVanillaPoolModule), "ItemManager_GetPurchasedItems_Prefix", (Type[])null);
				harmony.Patch((MethodBase)methodInfo, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}

		private static bool BlockOriginalShopMethod_Prefix()
		{
			return false;
		}

		private static bool UpgradeStand_GetWeightedUpgradeExcluding_Prefix(Item excludeItem, Dictionary<string, int> displayedCounts, Dictionary<string, int> selectedDuringReroll, ref Item __result)
		{
			string mode = NormalizePoolMode(FeatureFlags.DHHUpgradesShopPoolMode);
			__result = GetWeightedUpgradeExcludingWithDhhMode(excludeItem, displayedCounts, selectedDuringReroll, mode);
			return false;
		}

		private static void ShopManager_ShopInitialize_Prefix()
		{
			if (SemiFunc.RunIsShop())
			{
				EnsureDhhItemsInVanillaDictionary();
				ValidateDhhPrefabRefsForVanillaSpawn();
			}
		}

		private static void ShopManager_GetAllItemsFromStatsManager_Postfix(ShopManager __instance)
		{
			if ((Object)(object)__instance == (Object)null)
			{
				return;
			}
			int num = __instance.potentialItems?.Count(IsHeadChargerItem) ?? 0;
			int num2 = __instance.potentialItemUpgrades?.Count(IsDhhUpgradeItem) ?? 0;
			List<Item> potentialItems = __instance.potentialItems;
			if (potentialItems != null)
			{
				ApplyPoolMode(potentialItems, IsHeadChargerItem, FeatureFlags.HeadChargerShopPoolMode);
			}
			List<Item> potentialItemUpgrades = __instance.potentialItemUpgrades;
			if (potentialItemUpgrades != null)
			{
				ApplyPoolMode(potentialItemUpgrades, IsDhhUpgradeItem, FeatureFlags.DHHUpgradesShopPoolMode);
			}
			if (ShouldLogShopDebug())
			{
				int num3 = __instance.potentialItems?.Count(IsHeadChargerItem) ?? 0;
				int num4 = __instance.potentialItemUpgrades?.Count(IsDhhUpgradeItem) ?? 0;
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogInfo((object)string.Format("[Fix:Shop] Pool mode context mode={0} headCharger before={1} after={2} mode={3} upgrades before={4} after={5} mode={6}", SemiFunc.IsMultiplayer() ? "MP" : "SP", num, num3, FeatureFlags.HeadChargerShopPoolMode, num2, num4, FeatureFlags.DHHUpgradesShopPoolMode));
				}
			}
		}

		private static void LevelGenerator_ItemSetup_Postfix()
		{
			EnsureDhhItemsInVanillaDictionary();
			ValidateDhhPrefabRefsForVanillaSpawn();
		}

		private static void ItemManager_GetPurchasedItems_Prefix()
		{
			EnsureDhhItemsInVanillaDictionary();
			ValidateDhhPrefabRefsForVanillaSpawn();
		}

		internal static void EnsureDhhItemsInVanillaDictionary()
		{
			StatsManager instance = StatsManager.instance;
			if (instance?.itemDictionary == null)
			{
				return;
			}
			Dictionary<string, Item> shopItems = DHHAssetManager.shopItems;
			if (shopItems == null || shopItems.Count == 0)
			{
				return;
			}
			int num = 0;
			foreach (Item item in from x in shopItems.Values
				where (Object)(object)x != (Object)null
				group x by ((Object)x).GetInstanceID() into x
				select x.First())
			{
				NormalizeDhhShopItemForVanillaLists(item);
				string name = ((Object)item).name;
				if (string.IsNullOrWhiteSpace(name))
				{
					continue;
				}
				if (instance.itemDictionary.TryGetValue(name, out var value))
				{
					if ((Object)(object)value != (Object)(object)item)
					{
						LogWarningOnce("dictionary-conflict:" + name, "[Fix:Shop] StatsManager.itemDictionary already contains key '" + name + "' for a different item. Keeping vanilla entry.");
					}
				}
				else if (!instance.itemDictionary.Values.Any((Item existingItem) => (Object)(object)existingItem == (Object)(object)item))
				{
					instance.itemDictionary.Add(name, item);
					StatsModule.EnsureStatsEntriesForItem((Object)(object)item);
					num++;
				}
			}
			if (ShouldLogShopDebug() && num > 0)
			{
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogInfo((object)$"[Fix:Shop] Added {num} DeathHeadHopper item(s) to the vanilla shop dictionary.");
				}
			}
		}

		internal static void ValidateDhhPrefabRefsForVanillaSpawn()
		{
			Dictionary<string, Item> shopItems = DHHAssetManager.shopItems;
			if (shopItems == null || shopItems.Count == 0)
			{
				return;
			}
			foreach (Item item in from x in shopItems.Values
				where (Object)(object)x != (Object)null
				group x by ((Object)x).GetInstanceID() into x
				select x.First())
			{
				NormalizeDhhShopItemForVanillaLists(item);
				string text = (string.IsNullOrWhiteSpace(((Object)item).name) ? item.itemName : ((Object)item).name);
				if (item.prefab == null)
				{
					LogWarningOnce("prefab-null:" + text, "[Fix:Shop] DHH item '" + text + "' has no PrefabRef and cannot spawn through the vanilla shop.");
					continue;
				}
				if (!((PrefabRef<GameObject>)(object)item.prefab).IsValid())
				{
					LogWarningOnce("prefab-invalid:" + text, "[Fix:Shop] DHH item '" + text + "' has an invalid PrefabRef resource path.");
					continue;
				}
				if (SemiFunc.IsMultiplayer() && string.IsNullOrWhiteSpace(((PrefabRef<GameObject>)(object)item.prefab).ResourcePath))
				{
					LogWarningOnce("prefab-resourcepath:" + text, "[Fix:Shop] DHH item '" + text + "' has an empty multiplayer ResourcePath.");
				}
				if (!SemiFunc.IsMultiplayer() && (Object)(object)RunManager.instance != (Object)null && (Object)(object)((PrefabRef<GameObject>)(object)item.prefab).Prefab == (Object)null)
				{
					LogWarningOnce("prefab-singleplayer:" + text, "[Fix:Shop] DHH item '" + text + "' could not resolve its singleplayer prefab.");
				}
			}
		}

		private static void NormalizeDhhShopItemForVanillaLists(Item item)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)item == (Object)null))
			{
				if (IsHeadChargerItem(item))
				{
					item.itemType = (itemType)13;
					item.itemSecretShopType = (itemSecretShopType)0;
				}
				else if (IsDhhUpgradeItem(item))
				{
					item.itemType = (itemType)3;
					item.itemSecretShopType = (itemSecretShopType)0;
				}
			}
		}

		private static void ApplyPoolMode(List<Item> list, Predicate<Item> matcher, string mode)
		{
			if (list == null || matcher == null)
			{
				return;
			}
			mode = NormalizePoolMode(mode);
			if (string.Equals(mode, "Default", StringComparison.OrdinalIgnoreCase))
			{
				ApplyDefaultPoolMode(list, matcher);
				return;
			}
			List<Item> list2 = list.Where((Item item) => (Object)(object)item != (Object)null && matcher(item)).ToList();
			if (list2.Count == 0)
			{
				return;
			}
			int count = list2.Count;
			foreach (Item item in list2)
			{
				list.Remove(item);
			}
			int num = 0;
			if (string.Equals(mode, "Reduced", StringComparison.OrdinalIgnoreCase))
			{
				foreach (Item item2 in from item in list2
					group item by ((Object)item).GetInstanceID() into @group
					select @group.First())
				{
					list.Add(item2);
					num++;
				}
			}
			if (ShouldLogShopDebug())
			{
				string text = (SemiFunc.IsMultiplayer() ? "MP" : "SP");
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogInfo((object)$"[Fix:Shop] ApplyPoolMode mode={text} matcher={matcher.Method.Name} original={count} removed={count} poolMode={mode} addedCopies={num} final={list.Count((Item item) => (Object)(object)item != (Object)null && matcher(item))}");
				}
			}
			ListExtension.Shuffle<Item>((IList<Item>)list);
		}

		private static void ApplyDefaultPoolMode(List<Item> list, Predicate<Item> matcher)
		{
			List<Item> list2 = list.Where((Item item) => (Object)(object)item != (Object)null && matcher(item)).ToList();
			if (list2.Count == 0)
			{
				return;
			}
			int balancedCopies = GetBalancedPoolCopyCount(list, matcher);
			List<List<Item>> list3 = (from item in list2
				group item by ((Object)item).GetInstanceID() into @group
				select @group.ToList()).ToList();
			int count = list2.Count;
			int num = list3.Sum((List<Item> group) => Math.Min(group.Count, balancedCopies));
			if (num >= count)
			{
				return;
			}
			foreach (Item item in list2)
			{
				list.Remove(item);
			}
			int num2 = 0;
			foreach (List<Item> item2 in list3)
			{
				int num3 = Math.Min(item2.Count, balancedCopies);
				for (int num4 = 0; num4 < num3; num4++)
				{
					list.Add(item2[0]);
					num2++;
				}
			}
			if (ShouldLogShopDebug())
			{
				string text = (SemiFunc.IsMultiplayer() ? "MP" : "SP");
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogInfo((object)$"[Fix:Shop] ApplyDefaultPoolMode mode={text} matcher={matcher.Method.Name} original={count} balancedCopies={balancedCopies} addedCopies={num2} final={list.Count((Item item) => (Object)(object)item != (Object)null && matcher(item))}");
				}
			}
			ListExtension.Shuffle<Item>((IList<Item>)list);
		}

		private static int GetBalancedPoolCopyCount(List<Item> list, Predicate<Item> matcher)
		{
			List<int> list2 = (from item in list
				where (Object)(object)item != (Object)null && !matcher(ite