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.4
plugins\DeathHeadHopperFix.dll
Decompiled a month 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.Items; using DeathHeadHopper.Managers; using DeathHeadHopper.UI; 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.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] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace DeathHeadHopperFix { [BepInPlugin("AdrenSnyder.DeathHeadHopperFix", "Death Head Hopper - Fix", "0.2.4")] 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_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown _log = ((BaseUnityPlugin)this).Logger; ConfigManager.Initialize(((BaseUnityPlugin)this).Config); WarnUnsafeDebugFlagsInRelease(); _harmony = new Harmony("AdrenSnyder.DeathHeadHopperFix"); _harmony.PatchAll(typeof(Plugin).Assembly); DHHApiGuardModule.DetectGameApiChanges(); ApplyEarlyPatches(); AppDomain.CurrentDomain.AssemblyLoad += OnAssemblyLoad; Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly asm in assemblies) { TryPatchIfTargetAssembly(asm); } } private void OnDestroy() { AppDomain.CurrentDomain.AssemblyLoad -= OnAssemblyLoad; } private void OnAssemblyLoad(object sender, AssemblyLoadEventArgs args) { TryPatchIfTargetAssembly(args.LoadedAssembly); } private void ApplyEarlyPatches() { if (_harmony != null) { StatsModule.ApplyHooks(_harmony); ItemUpgradeModule.Apply(_harmony); } } private void TryPatchIfTargetAssembly(Assembly asm) { if (_patched || _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, asm); JumpForceModule.Apply(harmony, asm, _log); ChargeAbilityTuningModule.Apply(harmony, asm); ChargeHoldReleaseModule.Apply(harmony, asm, _log); InputModule.Apply(harmony, asm, _log); AbilityModule.ApplyAbilitySpotLabelOverlay(harmony, asm); AbilityModule.ApplyAbilityManagerHooks(harmony, asm); _patched = true; ManualLogSource? log2 = _log; if (log2 != null) { log2.LogInfo((object)"Patches applied successfully."); } } catch (Exception ex) { ManualLogSource? log3 = _log; if (log3 != null) { log3.LogError((object)ex); } } } private void WarnUnsafeDebugFlagsInRelease() { if (!Debug.isDebugBuild && (InternalDebugFlags.DisableBatteryModule || InternalDebugFlags.DisableAbilityPatches || InternalDebugFlags.DisableSpectateChecks)) { ManualLogSource? log = _log; if (log != null) { log.LogWarning((object)("[DebugSafety] Internal debug bypass flags are enabled in a non-debug build. " + $"DisableBatteryModule={InternalDebugFlags.DisableBatteryModule}, " + $"DisableAbilityPatches={InternalDebugFlags.DisableAbilityPatches}, " + $"DisableSpectateChecks={InternalDebugFlags.DisableSpectateChecks}")); } } } } } namespace DeathHeadHopperFix.Modules.Utilities { internal static class LastChanceInteropBridge { private const BindingFlags StaticAny = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; private static Type? s_timerControllerType; private static Type? s_spectateHelperType; private static Type? s_featureFlagsType; private static Type? s_imageAssetLoaderType; private static PropertyInfo? s_isActiveProperty; private static PropertyInfo? s_directionUiVisibleProperty; private static MethodInfo? s_isDirectionEnergySufficientMethod; private static MethodInfo? s_getDirectionPenaltyPreviewMethod; private static MethodInfo? s_getDirectionEnergyDebugSnapshotMethod; private static MethodInfo? s_isPlayerSurrenderedForDataMethod; private static MethodInfo? s_allPlayersDisabledMethod; private static MethodInfo? s_resetForceStateMethod; private static MethodInfo? s_shouldForceLocalDeathHeadSpectateMethod; private static MethodInfo? s_ensureSpectatePlayerLocalMethod; private static MethodInfo? s_forceDeathHeadSpectateIfPossibleMethod; private static MethodInfo? s_debugLogStateMethod; private static MethodInfo? s_isManualSwitchInputDownMethod; private static FieldInfo? s_lastChanceModeField; private static FieldInfo? s_spectateDeadPlayersField; private static FieldInfo? s_spectateDeadPlayersModeField; private static FieldInfo? s_lastChanceIndicatorsField; private static MethodInfo? s_tryLoadSpriteMethod; internal static bool IsLastChanceActive() { return TryGetBoolProperty(ref s_isActiveProperty, "DeathHeadHopperFix.Modules.Gameplay.LastChance.Runtime.LastChanceTimerController", "IsActive"); } internal static bool IsDirectionIndicatorUiVisible() { return TryGetBoolProperty(ref s_directionUiVisibleProperty, "DeathHeadHopperFix.Modules.Gameplay.LastChance.Runtime.LastChanceTimerController", "IsDirectionIndicatorUiVisible"); } internal static bool IsDirectionIndicatorEnergySufficientPreview() { ResolveMembers(); if (s_isDirectionEnergySufficientMethod == null) { return false; } return (s_isDirectionEnergySufficientMethod.Invoke(null, null) as bool?).GetValueOrDefault(); } internal static float GetDirectionIndicatorPenaltySecondsPreview() { ResolveMembers(); if (s_getDirectionPenaltyPreviewMethod == null) { return 0f; } return (s_getDirectionPenaltyPreviewMethod.Invoke(null, null) as float?).GetValueOrDefault(); } internal static void GetDirectionIndicatorEnergyDebugSnapshot(out bool visible, out float timerRemaining, out float penaltyPreview, out bool hasEnoughEnergy) { visible = false; timerRemaining = 0f; penaltyPreview = 0f; hasEnoughEnergy = false; ResolveMembers(); if (!(s_getDirectionEnergyDebugSnapshotMethod == null)) { object[] array = new object[4] { false, 0f, 0f, false }; s_getDirectionEnergyDebugSnapshotMethod.Invoke(null, array); visible = (array[0] as bool?).GetValueOrDefault(); timerRemaining = (array[1] as float?).GetValueOrDefault(); penaltyPreview = (array[2] as float?).GetValueOrDefault(); hasEnoughEnergy = (array[3] as bool?).GetValueOrDefault(); } } internal static bool IsPlayerSurrenderedForData(PlayerAvatar? player) { ResolveMembers(); if (s_isPlayerSurrenderedForDataMethod == null) { return false; } return (s_isPlayerSurrenderedForDataMethod.Invoke(null, new object[1] { player }) as bool?).GetValueOrDefault(); } internal static bool AllPlayersDisabled() { ResolveMembers(); if (s_allPlayersDisabledMethod == null) { return false; } return (s_allPlayersDisabledMethod.Invoke(null, null) as bool?).GetValueOrDefault(); } internal static void ResetSpectateForceState() { ResolveMembers(); s_resetForceStateMethod?.Invoke(null, null); } internal static bool ShouldForceLocalDeathHeadSpectate() { ResolveMembers(); if (s_shouldForceLocalDeathHeadSpectateMethod == null) { return false; } return (s_shouldForceLocalDeathHeadSpectateMethod.Invoke(null, null) as bool?).GetValueOrDefault(); } internal static void EnsureSpectatePlayerLocal(SpectateCamera? spectate) { ResolveMembers(); s_ensureSpectatePlayerLocalMethod?.Invoke(null, new object[1] { spectate }); } internal static void ForceDeathHeadSpectateIfPossible() { ResolveMembers(); s_forceDeathHeadSpectateIfPossibleMethod?.Invoke(null, null); } internal static void DebugLogState(SpectateCamera? spectate) { ResolveMembers(); s_debugLogStateMethod?.Invoke(null, new object[1] { spectate }); } internal static bool IsManualSwitchInputDown() { ResolveMembers(); if (s_isManualSwitchInputDownMethod == null) { return false; } return (s_isManualSwitchInputDownMethod.Invoke(null, null) as bool?).GetValueOrDefault(); } internal static bool IsLastChanceModeEnabled() { ResolveMembers(); if (s_lastChanceModeField == null) { return false; } return (s_lastChanceModeField.GetValue(null) as bool?).GetValueOrDefault(); } internal static bool IsSpectateDeadPlayersEnabled() { ResolveMembers(); if (s_spectateDeadPlayersField == null) { return false; } return (s_spectateDeadPlayersField.GetValue(null) as bool?).GetValueOrDefault(); } internal static string GetSpectateDeadPlayersMode() { ResolveMembers(); if (s_spectateDeadPlayersModeField == null) { return string.Empty; } return (s_spectateDeadPlayersModeField.GetValue(null) as string) ?? string.Empty; } internal static string GetLastChanceIndicatorsMode() { ResolveMembers(); if (s_lastChanceIndicatorsField == null) { return string.Empty; } return (s_lastChanceIndicatorsField.GetValue(null) as string) ?? string.Empty; } internal static bool TryGetDirectionSlotSprite(out Sprite? sprite) { sprite = null; ResolveMembers(); if (s_tryLoadSpriteMethod == null) { return false; } object[] array = new object[5] { "Direction.png", null, null, string.Empty, 100f }; if (!(s_tryLoadSpriteMethod.Invoke(null, array) as bool?).GetValueOrDefault()) { return false; } object obj = array[2]; sprite = (Sprite?)((obj is Sprite) ? obj : null); return (Object)(object)sprite != (Object)null; } private static bool TryGetBoolProperty(ref PropertyInfo? property, string typeName, string propertyName) { ResolveMembers(); if (property == null) { property = ResolveType(typeName)?.GetProperty(propertyName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } return (property?.GetValue(null) as bool?).GetValueOrDefault(); } private static void ResolveMembers() { if ((object)s_timerControllerType == null) { s_timerControllerType = ResolveType("DeathHeadHopperFix.Modules.Gameplay.LastChance.Runtime.LastChanceTimerController"); } if ((object)s_spectateHelperType == null) { s_spectateHelperType = ResolveType("DeathHeadHopperFix.Modules.Gameplay.LastChance.Spectate.LastChanceSpectateHelper"); } if ((object)s_featureFlagsType == null) { s_featureFlagsType = ResolveType("DHHFLastChanceMode.Modules.Config.FeatureFlags"); } if ((object)s_imageAssetLoaderType == null) { s_imageAssetLoaderType = ResolveType("DeathHeadHopperFix.Modules.Utilities.ImageAssetLoader"); } if (s_timerControllerType != null) { if ((object)s_isDirectionEnergySufficientMethod == null) { s_isDirectionEnergySufficientMethod = s_timerControllerType.GetMethod("IsDirectionIndicatorEnergySufficientPreview", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } if ((object)s_getDirectionPenaltyPreviewMethod == null) { s_getDirectionPenaltyPreviewMethod = s_timerControllerType.GetMethod("GetDirectionIndicatorPenaltySecondsPreview", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } if ((object)s_getDirectionEnergyDebugSnapshotMethod == null) { s_getDirectionEnergyDebugSnapshotMethod = s_timerControllerType.GetMethod("GetDirectionIndicatorEnergyDebugSnapshot", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } if ((object)s_isPlayerSurrenderedForDataMethod == null) { s_isPlayerSurrenderedForDataMethod = s_timerControllerType.GetMethod("IsPlayerSurrenderedForData", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } } if (s_spectateHelperType != null) { if ((object)s_allPlayersDisabledMethod == null) { s_allPlayersDisabledMethod = s_spectateHelperType.GetMethod("AllPlayersDisabled", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } if ((object)s_resetForceStateMethod == null) { s_resetForceStateMethod = s_spectateHelperType.GetMethod("ResetForceState", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } if ((object)s_shouldForceLocalDeathHeadSpectateMethod == null) { s_shouldForceLocalDeathHeadSpectateMethod = s_spectateHelperType.GetMethod("ShouldForceLocalDeathHeadSpectate", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } if ((object)s_ensureSpectatePlayerLocalMethod == null) { s_ensureSpectatePlayerLocalMethod = s_spectateHelperType.GetMethod("EnsureSpectatePlayerLocal", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } if ((object)s_forceDeathHeadSpectateIfPossibleMethod == null) { s_forceDeathHeadSpectateIfPossibleMethod = s_spectateHelperType.GetMethod("ForceDeathHeadSpectateIfPossible", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } if ((object)s_debugLogStateMethod == null) { s_debugLogStateMethod = s_spectateHelperType.GetMethod("DebugLogState", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } if ((object)s_isManualSwitchInputDownMethod == null) { s_isManualSwitchInputDownMethod = s_spectateHelperType.GetMethod("IsManualSwitchInputDown", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } } if (s_featureFlagsType != null) { if ((object)s_lastChanceModeField == null) { s_lastChanceModeField = s_featureFlagsType.GetField("LastChangeMode", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } if ((object)s_spectateDeadPlayersField == null) { s_spectateDeadPlayersField = s_featureFlagsType.GetField("SpectateDeadPlayers", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } if ((object)s_spectateDeadPlayersModeField == null) { s_spectateDeadPlayersModeField = s_featureFlagsType.GetField("SpectateDeadPlayersMode", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } if ((object)s_lastChanceIndicatorsField == null) { s_lastChanceIndicatorsField = s_featureFlagsType.GetField("LastChanceIndicators", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } } if (s_imageAssetLoaderType != null && (object)s_tryLoadSpriteMethod == null) { s_tryLoadSpriteMethod = s_imageAssetLoaderType.GetMethod("TryLoadSprite", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } } private static Type? ResolveType(string fullName) { Type type = Type.GetType(fullName, throwOnError: false); if (type != null) { return type; } Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { type = assembly.GetType(fullName, throwOnError: false); if (type != null) { return type; } } return null; } } internal static class LogLimiter { public const int DefaultFrameInterval = 240; private static readonly Dictionary<string, int> _lastFrameByKey = new Dictionary<string, int>(StringComparer.Ordinal); public static bool ShouldLog(string key, int frameInterval = 240) { if (string.IsNullOrEmpty(key)) { return true; } if (frameInterval <= 0) { return true; } int frameCount = Time.frameCount; if (_lastFrameByKey.TryGetValue(key, out var value) && frameCount - value < frameInterval) { return false; } _lastFrameByKey[key] = frameCount; return true; } public static void Reset(string key) { if (!string.IsNullOrEmpty(key)) { _lastFrameByKey.Remove(key); } } public static void Clear() { _lastFrameByKey.Clear(); } } internal static class NetworkProtocol { internal const string ModId = "DeathHeadHopperFix"; internal const int ProtocolVersion = 1; internal const string RoomKeyPrefix = "DeathHeadHopperFix.Room."; internal static string BuildRoomKey(string localKey) { return string.IsNullOrWhiteSpace(localKey) ? "DeathHeadHopperFix.Room." : ("DeathHeadHopperFix.Room." + localKey.Trim()); } } internal readonly struct NetworkEnvelope { internal string ModId { get; } internal int ProtocolVersion { get; } internal string MessageType { get; } internal int MessageSeq { get; } internal object? Payload { get; } internal NetworkEnvelope(string modId, int protocolVersion, string messageType, int messageSeq, object? payload) { ModId = (string.IsNullOrWhiteSpace(modId) ? string.Empty : modId.Trim()); ProtocolVersion = protocolVersion; MessageType = (string.IsNullOrWhiteSpace(messageType) ? string.Empty : messageType.Trim()); MessageSeq = messageSeq; Payload = payload; } internal object?[] ToEventPayload() { return new object[5] { ModId, ProtocolVersion, MessageType, MessageSeq, Payload }; } internal bool IsExpectedSource() { return ModId == "DeathHeadHopperFix" && ProtocolVersion == 1 && !string.IsNullOrWhiteSpace(MessageType); } internal static bool TryParse(object? customData, out NetworkEnvelope envelope) { envelope = default(NetworkEnvelope); if (!(customData is object[] array) || array.Length < 5) { return false; } if (array[0] is string modId && array[1] is int protocolVersion && array[2] is string messageType) { object obj = array[3]; int messageSeq = default(int); int num; if (obj is int) { messageSeq = (int)obj; num = 1; } else { num = 0; } if (num != 0) { envelope = new NetworkEnvelope(modId, protocolVersion, messageType, messageSeq, array[4]); return true; } } return false; } } internal static class PhotonEventCodes { internal const byte ConfigSync = 79; } internal static class PlayerStateExtractionHelper { internal readonly struct PlayerStateSnapshot { internal int ActorNumber { get; } internal int SteamIdShort { get; } internal string Name { get; } internal Color Color { get; } internal bool IsAlive { get; } internal bool IsDead { get; } internal bool IsInTruck { get; } internal bool IsSurrendered { get; } internal int SourceOrder { get; } internal PlayerStateSnapshot(int actorNumber, int steamIdShort, string name, Color color, bool isAlive, bool isDead, bool isInTruck, bool isSurrendered, int sourceOrder) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) ActorNumber = actorNumber; SteamIdShort = steamIdShort; Name = name; Color = color; IsAlive = isAlive; IsDead = isDead; IsInTruck = isInTruck; IsSurrendered = isSurrendered; SourceOrder = sourceOrder; } } private static readonly FieldInfo? s_playerNameField = AccessTools.Field(typeof(PlayerAvatar), "playerName"); private static readonly FieldInfo? s_playerDeadSetField = AccessTools.Field(typeof(PlayerAvatar), "deadSet"); private static readonly FieldInfo? s_playerIsDisabledField = AccessTools.Field(typeof(PlayerAvatar), "isDisabled"); private static readonly FieldInfo? s_playerRoomVolumeCheckField = AccessTools.Field(typeof(PlayerAvatar), "RoomVolumeCheck"); private static readonly FieldInfo? s_playerSteamIdShortField = AccessTools.Field(typeof(PlayerAvatar), "steamIDshort"); private static readonly FieldInfo? s_visualColorField = AccessTools.Field(typeof(PlayerAvatarVisuals), "color"); private static FieldInfo? s_roomVolumeCheckInTruckField; private static FieldInfo? s_deathHeadInTruckField; private static FieldInfo? s_deathHeadRoomVolumeCheckField; internal static List<PlayerStateSnapshot> GetPlayersStateSnapshot() { //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) List<PlayerStateSnapshot> list = new List<PlayerStateSnapshot>(); GameDirector instance = GameDirector.instance; if ((Object)(object)instance == (Object)null || instance.PlayerList == null || instance.PlayerList.Count == 0) { return list; } for (int i = 0; i < instance.PlayerList.Count; i++) { PlayerAvatar val = instance.PlayerList[i]; if (!((Object)(object)val == (Object)null)) { PhotonView photonView = val.photonView; int? obj; if (photonView == null) { obj = null; } else { Player owner = photonView.Owner; obj = ((owner != null) ? new int?(owner.ActorNumber) : null); } int? num = obj; int valueOrDefault = num.GetValueOrDefault(); int steamIdShort = GetSteamIdShort(val); string playerName = GetPlayerName(val); Color playerColor = GetPlayerColor(val); bool flag = IsDeadSet(val); bool flag2 = IsDisabled(val); bool flag3 = flag || flag2; bool isAlive = !flag3; bool isInTruck = IsPlayerInTruck(val, flag2); bool isSurrendered = LastChanceInteropBridge.IsPlayerSurrenderedForData(val); list.Add(new PlayerStateSnapshot(valueOrDefault, steamIdShort, playerName, playerColor, isAlive, flag3, isInTruck, isSurrendered, i)); } } list.Sort(CompareSnapshotOrder); return list; } internal static List<PlayerStateSnapshot> GetPlayersStillInLastChance() { List<PlayerStateSnapshot> playersStateSnapshot = GetPlayersStateSnapshot(); List<PlayerStateSnapshot> list = new List<PlayerStateSnapshot>(playersStateSnapshot.Count); for (int i = 0; i < playersStateSnapshot.Count; i++) { PlayerStateSnapshot item = playersStateSnapshot[i]; if (!item.IsSurrendered) { list.Add(item); } } return list; } private static int CompareSnapshotOrder(PlayerStateSnapshot left, PlayerStateSnapshot right) { if (left.ActorNumber > 0 && right.ActorNumber > 0) { return left.ActorNumber.CompareTo(right.ActorNumber); } return left.SourceOrder.CompareTo(right.SourceOrder); } private static string GetPlayerName(PlayerAvatar player) { if (s_playerNameField != null && s_playerNameField.GetValue(player) is string text && !string.IsNullOrWhiteSpace(text)) { return text; } return "unknown"; } private static Color GetPlayerColor(PlayerAvatar player) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) PlayerAvatarVisuals playerAvatarVisuals = player.playerAvatarVisuals; if ((Object)(object)playerAvatarVisuals == (Object)null) { return Color.black; } if (s_visualColorField != null && s_visualColorField.GetValue(playerAvatarVisuals) is Color result) { return result; } return Color.black; } private static bool IsDeadSet(PlayerAvatar player) { bool flag = default(bool); int num; if (s_playerDeadSetField != null) { object value = s_playerDeadSetField.GetValue(player); if (value is bool) { flag = (bool)value; num = 1; } else { num = 0; } } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } private static bool IsDisabled(PlayerAvatar player) { bool flag = default(bool); int num; if (s_playerIsDisabledField != null) { object value = s_playerIsDisabledField.GetValue(player); if (value is bool) { flag = (bool)value; num = 1; } else { num = 0; } } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } private static bool IsPlayerInTruck(PlayerAvatar player, bool isDisabled) { if (!isDisabled) { object roomVolumeCheck = GetRoomVolumeCheck(player); return roomVolumeCheck != null && IsRoomVolumeInTruck(roomVolumeCheck); } PlayerDeathHead playerDeathHead = player.playerDeathHead; if ((Object)(object)playerDeathHead == (Object)null) { return false; } object deathHeadRoomVolumeCheck = GetDeathHeadRoomVolumeCheck(playerDeathHead); if (deathHeadRoomVolumeCheck != null) { return IsRoomVolumeInTruck(deathHeadRoomVolumeCheck); } FieldInfo deathHeadInTruckField = GetDeathHeadInTruckField(((object)playerDeathHead).GetType()); bool flag = default(bool); int num; if (deathHeadInTruckField != null) { object value = deathHeadInTruckField.GetValue(playerDeathHead); if (value is bool) { flag = (bool)value; num = 1; } else { num = 0; } } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } private static object? GetRoomVolumeCheck(PlayerAvatar player) { if (s_playerRoomVolumeCheckField == null) { return null; } return s_playerRoomVolumeCheckField.GetValue(player); } private static bool IsRoomVolumeInTruck(object roomVolumeCheck) { if (roomVolumeCheck == null) { return false; } FieldInfo fieldInfo = s_roomVolumeCheckInTruckField; if (fieldInfo == null || fieldInfo.DeclaringType != roomVolumeCheck.GetType()) { fieldInfo = (s_roomVolumeCheckInTruckField = AccessTools.Field(roomVolumeCheck.GetType(), "inTruck")); } bool flag = default(bool); int num; if (fieldInfo != null) { object value = fieldInfo.GetValue(roomVolumeCheck); if (value is bool) { flag = (bool)value; num = 1; } else { num = 0; } } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } private static FieldInfo? GetDeathHeadInTruckField(Type deathHeadType) { FieldInfo fieldInfo = s_deathHeadInTruckField; if (fieldInfo == null || fieldInfo.DeclaringType != deathHeadType) { fieldInfo = (s_deathHeadInTruckField = AccessTools.Field(deathHeadType, "inTruck")); } return fieldInfo; } private static object? GetDeathHeadRoomVolumeCheck(PlayerDeathHead deathHead) { FieldInfo fieldInfo = s_deathHeadRoomVolumeCheckField; if (fieldInfo == null || fieldInfo.DeclaringType != ((object)deathHead).GetType()) { fieldInfo = (s_deathHeadRoomVolumeCheckField = AccessTools.Field(((object)deathHead).GetType(), "roomVolumeCheck")); } return fieldInfo?.GetValue(deathHead); } private static int GetSteamIdShort(PlayerAvatar player) { return (s_playerSteamIdShortField != null && s_playerSteamIdShortField.GetValue(player) is int num) ? num : 0; } } internal static class SpectateContextHelper { private static readonly FieldInfo? s_spectatePlayerField = AccessTools.Field(typeof(SpectateCamera), "player"); private static readonly FieldInfo? s_playerDeathHeadSpectatedField = AccessTools.Field(typeof(PlayerDeathHead), "spectated"); internal static bool IsSpectatingLocalPlayerTarget() { SpectateCamera instance = SpectateCamera.instance; PlayerAvatar instance2 = PlayerAvatar.instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance2 == (Object)null || s_spectatePlayerField == null) { return false; } object? value = s_spectatePlayerField.GetValue(instance); PlayerAvatar val = (PlayerAvatar)((value is PlayerAvatar) ? value : null); return (Object)(object)val != (Object)null && val == instance2; } internal static bool IsSpectatingLocalDeathHead() { SpectateCamera instance = SpectateCamera.instance; if ((Object)(object)instance == (Object)null || !instance.CheckState((State)2)) { return false; } PlayerDeathHead val = PlayerController.instance?.playerAvatarScript?.playerDeathHead; if ((Object)(object)val == (Object)null || s_playerDeathHeadSpectatedField == null) { return false; } return (s_playerDeathHeadSpectatedField.GetValue(val) as bool?).GetValueOrDefault(); } internal static bool IsLocalDeathHeadSpectated() { PlayerDeathHead val = PlayerController.instance?.playerAvatarScript?.playerDeathHead; if ((Object)(object)val == (Object)null || s_playerDeathHeadSpectatedField == null) { return false; } return (s_playerDeathHeadSpectatedField.GetValue(val) as bool?).GetValueOrDefault(); } } } namespace DeathHeadHopperFix.Modules.Stamina { internal sealed class StaminaRechargeModule : MonoBehaviour { private static readonly Type? s_deathHeadControllerType = AccessTools.TypeByName("DeathHeadHopper.DeathHead.DeathHeadController"); private object? _controllerInstance; private PhotonView? _photonView; private bool _isOwner; private float _rechargeAccumulator; private Rigidbody? _rb; private void Awake() { if (s_deathHeadControllerType == null) { ((Behaviour)this).enabled = false; return; } _controllerInstance = ((Component)this).GetComponent(s_deathHeadControllerType); if (_controllerInstance == null) { ((Behaviour)this).enabled = false; return; } _photonView = ((Component)this).GetComponent<PhotonView>(); _isOwner = !SemiFunc.IsMultiplayer() || ((Object)(object)_photonView != (Object)null && _photonView.IsMine); _rb = ((Component)this).GetComponent<Rigidbody>(); } private void Update() { if (!_isOwner) { return; } if (!FeatureFlags.RechargeWithStamina) { _rechargeAccumulator = 0f; } else { if (_controllerInstance == null) { return; } _rechargeAccumulator += Time.deltaTime; if (!(_rechargeAccumulator < FeatureFlags.RechargeTickInterval)) { bool flag = !FeatureFlags.RechargeStaminaOnlyStationary || IsHeadStationary(); (bool, bool?, float, float) tuple = DHHBatteryHelper.EvaluateJumpAllowance(); if (flag || !tuple.Item1) { DHHBatteryHelper.RechargeDhhAbilityEnergy(_controllerInstance, _rechargeAccumulator); } _rechargeAccumulator = 0f; } } } private bool IsHeadStationary() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_rb == (Object)null) { return true; } Vector3 velocity = _rb.velocity; return ((Vector3)(ref velocity)).sqrMagnitude < FeatureFlags.HeadStationaryVelocitySqrThreshold; } } } namespace DeathHeadHopperFix.Modules.Gameplay.Stun { internal static class ChargeHoldReleaseModule { private sealed class ChargeHoldState { public float StartTime; public bool IsHolding; public float LaunchScale = 1f; } private readonly struct DiminishingReturnsResult { public float BaseValue { get; } public float IncreasePerLevel { get; } public int AppliedLevel { get; } public int ThresholdLevel { get; } public float DiminishingFactor { get; } public int LinearLevels { get; } public int ExtraLevels { get; } public float LinearContribution { get; } public float DiminishingContribution { get; } public float DiminishingComponent { get; } public float FinalValue { get; } public DiminishingReturnsResult(float baseValue, float increasePerLevel, int appliedLevel, int thresholdLevel, float diminishingFactor, int linearLevels, int extraLevels, float linearContribution, float diminishingContribution, float diminishingComponent, float finalValue) { BaseValue = baseValue; IncreasePerLevel = increasePerLevel; AppliedLevel = appliedLevel; ThresholdLevel = thresholdLevel; DiminishingFactor = diminishingFactor; LinearLevels = linearLevels; ExtraLevels = extraLevels; LinearContribution = linearContribution; DiminishingContribution = diminishingContribution; DiminishingComponent = diminishingComponent; FinalValue = finalValue; } } private const string ChargeStrengthLogKey = "Fix:Charge.Strength"; private const string ChargePermissiveFallbackLogKey = "Fix:Charge.PermissiveFallback"; private const float RemoteReleaseCommandTag = -777f; private const float RemoteCancelCommandTag = -778f; private static ManualLogSource? s_log; private static 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 (!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 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); } 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; } ChargeState state = chargeHandler.State; return string.Equals(((object)(ChargeState)(ref state)).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); } 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 { [CompilerGenerated] private sealed class <Transpiler>d__3 : IEnumerable<CodeInstruction>, IEnumerable, IEnumerator<CodeInstruction>, IDisposable, IEnumerator { private int <>1__state; private CodeInstruction <>2__current; private int <>l__initialThreadId; private IEnumerable<CodeInstruction> instructions; public IEnumerable<CodeInstruction> <>3__instructions; private IEnumerator<CodeInstruction> <>s__1; private CodeInstruction <instruction>5__2; CodeInstruction IEnumerator<CodeInstruction>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <Transpiler>d__3(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || (uint)(num - 1) <= 1u) { try { } finally { <>m__Finally1(); } } <>s__1 = null; <instruction>5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Expected O, but got Unknown try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>s__1 = instructions.GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; break; case 2: <>1__state = -3; <instruction>5__2 = null; break; } if (<>s__1.MoveNext()) { <instruction>5__2 = <>s__1.Current; if (s_targetCall != null && s_replacement != null && CodeInstructionExtensions.Calls(<instruction>5__2, s_targetCall)) { <>2__current = new CodeInstruction(OpCodes.Call, (object)s_replacement); <>1__state = 1; return true; } <>2__current = <instruction>5__2; <>1__state = 2; return true; } <>m__Finally1(); <>s__1 = null; return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<>s__1 != null) { <>s__1.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<CodeInstruction> IEnumerable<CodeInstruction>.GetEnumerator() { <Transpiler>d__3 <Transpiler>d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; <Transpiler>d__ = this; } else { <Transpiler>d__ = new <Transpiler>d__3(0); } <Transpiler>d__.instructions = <>3__instructions; return <Transpiler>d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<CodeInstruction>)this).GetEnumerator(); } } 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); [IteratorStateMachine(typeof(<Transpiler>d__3))] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <Transpiler>d__3(-2) { <>3__instructions = instructions }; } 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.GetValueOrDefault()) { Debug.Log((object)"[Fix:AbilityBar] hidden by policy (native=false, external=false)."); } s_lastShouldShow = false; return; } if (FeatureFlags.DebugLogging && !s_lastShouldShow.GetValueOrDefault()) { 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?).GetValueOrDefault(); } 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), "PlayerSwitch")] internal static class SpectateDeadPlayersModule { private sealed class CameraSnapshot { public string Reason = string.Empty; public bool LastChanceEnabled; public bool LastChanceActive; public bool AllPlayersDisabled; public string CurrentState = string.Empty; public string PlayerName = string.Empty; public string OverrideName = string.Empty; public bool CurrentPlayerDisabled; public bool LocalPlayerDisabled; public bool LocalPlayerDeadSet; public string? MainCameraName; public string? SpectateCameraName; public float? MainNearClip; public float? SpectateNearClip; public float? MainFov; public float? SpectateFov; public Rect? MainRect; public string? MainRectKey; public int MainCullingMask; public string MainClearFlags = string.Empty; public string? MainParentName; public float? FogStartDistance; public float? MainMinusSpectateNearClip; public bool HasMeaningfulDelta(CameraSnapshot other) { return !NullableFloatEquals(MainNearClip, other.MainNearClip) || !NullableFloatEquals(SpectateNearClip, other.SpectateNearClip) || !NullableFloatEquals(MainFov, other.MainFov) || !NullableRectEquals(MainRect, other.MainRect) || MainCullingMask != other.MainCullingMask || !string.Equals(MainClearFlags, other.MainClearFlags, StringComparison.Ordinal) || !string.Equals(MainParentName, other.MainParentName, StringComparison.Ordinal) || !NullableFloatEquals(FogStartDistance, other.FogStartDistance) || !NullableFloatEquals(MainMinusSpectateNearClip, other.MainMinusSpectateNearClip) || !string.Equals(MainCameraName, other.MainCameraName, StringComparison.Ordinal) || !string.Equals(SpectateCameraName, other.SpectateCameraName, StringComparison.Ordinal); } private static bool NullableFloatEquals(float? left, float? right) { if (!left.HasValue && !right.HasValue) { return true; } if (!left.HasValue || !right.HasValue) { return false; } return Mathf.Abs(left.Value - right.Value) < 0.0001f; } private static bool NullableRectEquals(Rect? left, Rect? right) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) if (!left.HasValue && !right.HasValue) { return true; } if (!left.HasValue || !right.HasValue) { return false; } Rect value = left.Value; Rect value2 = right.Value; return Mathf.Abs(((Rect)(ref value)).x - ((Rect)(ref value2)).x) < 0.0001f && Mathf.Abs(((Rect)(ref value)).y - ((Rect)(ref value2)).y) < 0.0001f && Mathf.Abs(((Rect)(ref value)).width - ((Rect)(ref value2)).width) < 0.0001f && Mathf.Abs(((Rect)(ref value)).height - ((Rect)(ref value2)).height) < 0.0001f; } } private sealed class NearClipSnapshot { public string Reason = string.Empty; public bool LastChanceEnabled; public bool LastChanceActive; public bool AllPlayersDisabled; public string CurrentState = string.Empty; public string PlayerName = string.Empty; public string OverrideName = string.Empty; public bool CurrentPlayerDisabled; public bool LocalPlayerDisabled; public bool LocalPlayerDeadSet; public string? MainCameraName; public string? SpectateCameraName; public float? MainNearClip; public float? SpectateNearClip; public float? FogStartDistance; public float? MainMinusSpectateNearClip; public bool HasMeaningfulDelta(NearClipSnapshot other) { return !NullableFloatEquals(MainNearClip, other.MainNearClip) || !NullableFloatEquals(SpectateNearClip, other.SpectateNearClip) || !NullableFloatEquals(FogStartDistance, other.FogStartDistance) || !NullableFloatEquals(MainMinusSpectateNearClip, other.MainMinusSpectateNearClip) || !string.Equals(MainCameraName, other.MainCameraName, StringComparison.Ordinal) || !string.Equals(SpectateCameraName, other.SpectateCameraName, StringComparison.Ordinal); } private static bool NullableFloatEquals(float? left, float? right) { if (!left.HasValue && !right.HasValue) { return true; } if (!left.HasValue || !right.HasValue) { return false; } return Mathf.Abs(left.Value - right.Value) < 0.0001f; } } [CompilerGenerated] private sealed class <LogCameraDelayedFollowUp>d__31 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public SpectateCamera spectate; public CameraSnapshot baseline; private CameraSnapshot <current>5__1; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <LogCameraDelayedFollowUp>d__31(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <current>5__1 = null; <>1__state = -2; } private bool MoveNext() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSecondsRealtime(3f); <>1__state = 1; return true; case 1: <>1__state = -1; if ((Object)(object)spectate == (Object)null || !FeatureFlags.DebugLogging) { return false; } <current>5__1 = CaptureCameraSnapshot(spectate, baseline.Reason); if (!<current>5__1.HasMeaningfulDelta(baseline)) { return false; } if (!LogCameraSnapshot("delayed", <current>5__1)) { return false; } LogCameraDelta(baseline, <current>5__1); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <LogCameraFollowUp>d__30 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public SpectateCamera spectate; public CameraSnapshot baseline; private CameraSnapshot <current>5__1; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <LogCameraFollowUp>d__30(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <current>5__1 = null; <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = null; <>1__state = 1; return true; case 1: <>1__state = -1; if ((Object)(object)spectate == (Object)null || !FeatureFlags.DebugLogging) { return false; } <current>5__1 = CaptureCameraSnapshot(spectate, baseline.Reason); if (!<current>5__1.HasMeaningfulDelta(baseline)) { return false; } LogCameraDelta(baseline, <current>5__1); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <LogNearClipDelayedFollowUp>d__39 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public SpectateCamera spectate; public NearClipSnapshot baseline; private NearClipSnapshot <current>5__1; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <LogNearClipDelayedFollowUp>d__39(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <current>5__1 = null; <>1__state = -2; } private bool MoveNext() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSecondsRealtime(3f); <>1__state = 1; return true; case 1: <>1__state = -1; if ((Object)(object)spectate == (Object)null || !FeatureFlags.DebugLogging) { return false; } <current>5__1 = CaptureNearClipSnapshot(spectate, baseline.Reason); if (!<current>5__1.HasMeaningfulDelta(baseline)) { return false; } if (!LogNearClipSnapshot("delayed", <current>5__1)) { return false; } LogNearClipDelta(baseline, <current>5__1); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <LogNearClipFollowUp>d__38 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public SpectateCamera spectate; public NearClipSnapshot baseline; private NearClipSnapshot <current>5__1; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <LogNearClipFollowUp>d__38(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <current>5__1 = null; <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = null; <>1__state = 1; return true; case 1: <>1__state = -1; if ((Object)(object)spectate == (Object)null || !FeatureFlags.DebugLogging) { return false; } <current>5__1 = CaptureNearClipSnapshot(spectate, baseline.Reason); if (!<current>5__1.HasMeaningfulDelta(baseline)) { return false; } LogNearClipDelta(baseline, <current>5__1); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <RunDhhFovRecovery>d__25 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public SpectateCamera spectate; public string reason; private int <targetFov>5__1; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <RunDhhFovRecovery>d__25(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSecondsRealtime(3f); <>1__state = 1; return true; case 1: <>1__state = -1; if ((Object)(object)spectate == (Object)null || !IsDeadPlayersSpectateEnabledNow() || !ShouldApplyDhhFovRecovery()) { return false; } <targetFov>5__1 = FeatureFlags.DHHSpectateDefaultFov; TryRestoreDhhFov(spectate, <targetFov>5__1, reason); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private const string ModuleId = "DeathHeadHopperFix.Spectate.DeadPlayers"; private static PlayerAvatar? s_stateNormalPatchedPlayer; private static Transform? s_stateNormalOriginalSpectatePoint; private static Transform? s_stateNormalOrbitProxy; private static string? s_lastNearClipSnapshotKey; private static string? s_lastCameraSnapshotKey; private static int s_lastFovRecoveryFrame = -1; [HarmonyPrefix] private static bool PlayerSwitchPrefix(SpectateCamera __instance, bool _next) { if (ShouldBlockJumpDrivenPlayerSwitch(_next)) { return false; } if (ShouldBlockPlayerSwitchForLastChance()) { return false; } if ((Object)(object)__instance == (Object)null) { return true; } List<PlayerAvatar> list = GameDirector.instance?.PlayerList; if (list == null || list.Count == 0) { return true; } if (IsDeadPlayersSpectateEnabledNow()) { TraceCameraActivation(__instance, "PlayerSwitchPrefix"); return HandleDeadPlayersSpectateSwitch(__instance, list, _next); } return HandleVanillaEquivalentPlayerSwitch(__instance, list, _next); } private static bool HandleDeadPlayersSpectateSwitch(SpectateCamera spectate, IList<PlayerAvatar> playerList, bool next) { TraceCameraActivation(spectate, "HandleDeadPlayersSpectateSwitch"); bool flag = true; foreach (PlayerAvatar player in playerList) { if ((Object)(object)player == (Object)null || player.isDisabled) { continue; } flag = false; break; } if (!flag) { return true; } TryPlayerSwitch(spectate, playerList, next, includeDisabled: true); return false; } private static bool HandleVanillaEquivalentPlayerSwitch(SpectateCamera spectate, IList<PlayerAvatar> playerList, bool next) { if (playerList.All((PlayerAvatar p) => (Object)(object)p == (Object)null || p.isDisabled)) { return false; } if (TryPlayerSwitch(spectate, playerList, next, includeDisabled: false)) { return false; } return true; } private static bool ShouldBlockJumpDrivenPlayerSwitch(bool next) { return next && SemiFunc.InputDown((InputKey)1) && !SemiFunc.InputDown((InputKey)23); } [HarmonyPatch(typeof(SpectateCamera), "StateNormal")] [HarmonyPrefix] private static void StateNormalPrefix(SpectateCamera __instance) { //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || !IsDeadPlayersSpectateEnabledNow()) { return; } PlayerAvatar player = __instance.player; if ((Object)(object)player == (Object)null || player == PlayerAvatar.instance || !player.isDisabled || !TryGetDeathHeadAnchor(player, out var anchor)) { return; } Transform spectatePoint = player.spectatePoint; if ((Object)(object)spectatePoint != (Object)null) { Transform val = EnsureStateNormalOrbitProxy(); if ((Object)(object)val == (Object)null) { return; } Vector3 val2 = Vector3.zero; if ((Object)(object)((Component)player).transform != (Object)null) { val2 = spectatePoint.position - ((Component)player).transform.position; } val.position = anchor + val2; val.rotation = spectatePoint.rotation; s_stateNormalPatchedPlayer = player; s_stateNormalOriginalSpectatePoint = spectatePoint; player.spectatePoint = val; } if (FeatureFlags.DebugLogging && LogLimiter.ShouldLog("Spectate.DeadPlayers.Anchor", 120)) { Debug.Log((object)("[SpectateDeadPlayers] Orbit source moved to DeathHead center for " + GetPlayerName(player))); } } [HarmonyPatch(typeof(SpectateCamera), "StateNormal")] [HarmonyPostfix] private static void StateNormalPostfix(SpectateCamera __instance) { if ((Object)(object)s_stateNormalPatchedPlayer == (Object)null) { HandleLastChanceStateNormalPostfix(__instance); MaintainDhhFovState(__instance); return; } if ((Object)(object)s_stateNormalOriginalSpectatePoint != (Object)null) { s_stateNormalPatchedPlayer.spectatePoint = s_stateNormalOriginalSpectatePoint; } s_stateNormalPatchedPlayer = null; s_stateNormalOriginalSpectatePoint = null; HandleLastChanceStateNormalPostfix(__instance); MaintainDhhFovState(__instance); } [HarmonyPatch(typeof(SpectateCamera), "UpdateState")] [HarmonyPrefix] private static bool UpdateStatePrefix(SpectateCamera __instance, State _state) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Invalid comparison between Unknown and I4 if (!LastChanceInteropBridge.IsLastChanceModeEnabled() || (Object)(object)__instance == (Object)null) { return true; } if ((int)_state != 2) { return true; } if (LastChanceInteropBridge.IsLastChanceActive()) { return false; } return !LastChanceInteropBridge.AllPlayersDisabled(); } private static bool IsDeadPlayersSpectateEnabledNow() { if (!LastChanceInteropBridge.IsSpectateDeadPlayersEnabled()) { return false; } string text = LastChanceInteropBridge.GetSpectateDeadPlayersMode().Trim(); if (text.Equals("Disabled", StringComparison.OrdinalIgnoreCase)) { return false; } if (text.Equals("LastChanceOnly", StringComparison.OrdinalIgnoreCase)) { return LastChanceInteropBridge.IsLastChanceModeEnabled() && LastChanceInteropBridge.IsLastChanceActive() && IsLocalPlayerDeadOrDisabled(); } return true; } private static bool TryPlayerSwitch(SpectateCamera spectate, IList<PlayerAvatar> players, bool next, bool includeDisabled) { //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid