Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of DeathHeadHopperFix v0.2.6
plugins\DeathHeadHopperFix.dll
Decompiled 3 weeks ago
The result has been truncated due to the large size, download it to view full contents!
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