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.3")]
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 const string ModuleId = "DeathHeadHopperFix.Spectate.DeadPlayers";
private static PlayerAvatar? s_stateNormalPatchedPlayer;
private static Transform? s_stateNormalOriginalSpectatePoint;
private static Transform? s_stateNormalOrbitProxy;
[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())
{
return HandleDeadPlayersSpectateSwitch(__instance, list, _next);
}
return HandleVanillaEquivalentPlayerSwitch(__instance, list, _next);
}
private static bool HandleDeadPlayersSpectateSwitch(SpectateCamera spectate, IList<PlayerAvatar> playerList, bool next)
{
bool flag = true;
foreach (PlayerAvatar player in playerList)
{
if ((Object)(object)player == (Object)null || player.isDisabled)
{
continue;
}
flag = false;
break;
}
if (!flag)
{
return true;
}
bool flag2 = TryPlayerSwitch(spectate, playerList, next, includeDisabled: true);
if (FeatureFlags.DebugLogging && LogLimiter.ShouldLog("Spectate.DeadPlayers.AllDisabledSwitch", 120))
{
Debug.Log((object)$"[SpectateDeadPlayers] Prefix all-disabled path handled={flag2} count={playerList.Count} next={next}");
}
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);
return;
}
if ((Object)(object)s_stateNormalOriginalSpectatePoint != (Object)null)
{
s_stateNormalPatchedPlayer.spectatePoint = s_stateNormalOriginalSpectatePoint;
}
s_stateNormalPatchedPlayer = null;
s_stateNormalOriginalSpectatePoint = null;
HandleLastChanceStateNormalPostfix(__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 IL or missing references)
//IL_017b: Unknown result type (might be due to invalid IL or missing references)
//IL_0180: Unknown result type (might be due to invalid IL or missing references)
//IL_0184: Unknown result type (might be due to invalid IL or missing references)
//IL_0193: Unknown result type (might be due to invalid IL or missing references)
//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
if (players.Count == 0)
{
return false;
}
PlayerAvatar player = spectate.player;
PlayerAvatar val = spectate.playerOverride;
Transform normalTransformPivot = spectate.normalTransformPivot;
Transform normalTransformDistance = spectate.normalTransformDistance;
if ((Object)(object)normalTransformPivot == (Object)null || (Object)(object)normalTransformDistance == (Object)null)
{
return false;
}
int num = spectate.currentPlayerListIndex;
int count = players.Count;
for (int i = 0; i < count; i++)
{
num = (next ? ((num + 1) % count) : ((num - 1 + count) % count));
PlayerAvatar val2 = players[num];
if ((Object)(object)val2 == (Object)null || ((Object)(object)val != (Object)null && (Object)(object)val2 != (Object)(object)val))
{
continue;
}
val = null;
if ((Object)(object)player == (Object)(object)val2 || (Object)(object)val2.spectatePoint == (Object)null || (!includeDisabled && val2.isDisabled))
{
continue;
}
spectate.playerOverride = null;
spectate.currentPlayerListIndex = num;
spectate.player = val2;
normalTransformPivot.position = val2.spectatePoint.position;
float num2 = (spectate.normalAimHorizontal = ((Component)val2).transform.eulerAngles.y);
spectate.normalAimVertical = 0f;
normalTransformPivot.rotation = Quaternion.Euler(0f, num2, 0f);
Quaternion localRotation = normalTransformPivot.localRotation;
float x = ((Quaternion)(ref localRotation)).eulerAngles.x;
localRotation = normalTransformPivot.localRotation;
normalTransformPivot.localRotation = Quaternion.Euler(x, ((Quaternion)(ref localRotation)).eulerAngles.y, 0f);
normalTransformDistance.localPosition = new Vector3(0f, 0f, -2f);
((Component)spectate).transform.position = normalTransformDistance.position;
((Component)spectate).transform.rotation = normalTransformDistance.rotation;
if (SemiFunc.IsMultiplayer())
{
SemiFunc.HUDSpectateSetName(GetPlayerName(val2));
}
SemiFunc.LightManagerSetCullTargetTransform(((Component)val2).transform);
spectate.CameraTeleportImpulse();
spectate.normalMaxDistance = 3f;
PlayerController instance = PlayerController.instance;
if (instance != null)
{
PlayerAvatar playerAvatarScript = instance.playerAvatarScript;
if (playerAvatarScript != null)
{
PlayerLocalCamera localCamera = playerAvatarScript.localCamera;
if (localCamera != null)
{
localCamera.Teleported();
}
}
}
return true;
}
spectate.playerOverride = null;
return false;
}
private static string GetPlayerName(PlayerAvatar? player)
{
if ((Object)(object)player == (Object)null)
{
return "unknown";
}
return player.playerName ?? "unknown";
}
private static bool TryGetDeathHeadAnchor(PlayerAvatar player, out Vector3 anchor)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: 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_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
anchor = default(Vector3);
PlayerDeathHead playerDeathHead = player.playerDeathHead;
if ((Object)(object)playerDeathHead == (Object)null)
{
return false;
}
anchor = ((Component)playerDeathHead).transform.position;
PhysGrabObject physGrabObject = playerDeathHead.physGrabObject;
if ((Object)(object)physGrabObject != (Object)null)
{
anchor = physGrabObject.centerPoint;
}
return true;
}
private static bool IsLocalPlayerDeadOrDisabled()
{
PlayerAvatar instance = PlayerAvatar.instance;
if ((Object)(object)instance == (Object)null)
{
return false;
}
if (instance.isDisabled)
{
return true;
}
if (instance.deadSet)
{
return true;
}
return false;
}
private static Transform? EnsureStateNormalOrbitProxy()
{
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Expected O, but got Unknown
if ((Object)(object)s_stateNormalOrbitProxy != (Object)null)
{
return s_stateNormalOrbitProxy;
}
GameObject val = GameObject.Find("DHHFix.SpectateDeadPlayers.OrbitProxy");
if ((Object)(object)val == (Object)null)
{
val = new GameObject("DHHFix.SpectateDeadPlayers.OrbitProxy");
Object.DontDestroyOnLoad((Object)(object)val);
}
s_stateNormalOrbitProxy = val.transform;
return s_stateNormalOrbitProxy;
}
private static void HandleLastChanceStateNormalPostfix(SpectateCamera __instance)
{
if (!LastChanceInteropBridge.IsLastChanceModeEnabled())
{
return;
}
if (!LastChanceInteropBridge.IsLastChanceActive())
{
LastChanceInteropBridge.ResetSpectateForceState();
return;
}
if (!LastChanceInteropBridge.AllPlayersDisabled())
{
LastChanceInteropBridge.ResetSpectateForceState();
return;
}
if (LastChanceInteropBridge.ShouldForceLocalDeathHeadSpectate())
{
if ((Object)(object)__instance != (Object)null)
{
LastChanceInteropBridge.EnsureSpectatePlayerLocal(__instance);
}
LastChanceInteropBridge.ForceDeathHeadSpectateIfPossible();
}
LastChanceInteropBridge.DebugLogState(__instance);
}
private static bool ShouldBlockPlayerSwitchForLastChance()
{
if (!LastChanceInteropBridge.IsLastChanceModeEnabled())
{
return false;
}
if (LastChanceInteropBridge.IsManualSwitchInputDown())
{
return false;
}
if (!LastChanceInteropBridge.IsLastChanceActive())
{
return false;
}
if (!LastChanceInteropBridge.AllPlayersDisabled())
{
return false;
}
return true;
}
}
}
namespace DeathHeadHopperFix.Modules.Gameplay.Core.Runtime
{
internal static class StatsModule
{
private static bool _statsHooksApplied;
internal static void ApplyHooks(Harmony harmony)
{
if (harmony != null && !_statsHooksApplied)
{
PatchSemiFuncStatGetItemsPurchasedIfPossible(harmony);
PatchStatsManagerGetItemsUpgradesPurchasedIfPossible(harmony);
PatchStatsManagerItemPurchaseIfPossible(harmony);
_statsHooksApplied = true;
}
}
internal static void EnsureStatsManagerKey(string itemName)
{
if (!string.IsNullOrWhiteSpace(itemName))
{
StatsManager instance = StatsManager.instance;
if (!((Object)(object)instance == (Object)null))
{
EnsureKey(instance.itemsPurchased, itemName);
EnsureKey(instance.itemsPurchasedTotal, itemName);
EnsureKey(instance.itemsUpgradesPurchased, itemName);
}
}
}
internal static void EnsureStatsEntriesForItem(Object itemObj)
{
try
{
if (!(itemObj == (Object)null))
{
StatsManager instance = StatsManager.instance;
if (!((Object)(object)instance == (Object)null))
{
EnsureKey(instance.itemsPurchased, itemObj.name);
EnsureKey(instance.itemsPurchasedTotal, itemObj.name);
EnsureKey(instance.itemsUpgradesPurchased, itemObj.name);
}
}
}
catch
{
}
}
private static void PatchSemiFuncStatGetItemsPurchasedIfPossible(Harmony harmony)
{
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_006c: Expected O, but got Unknown
MethodInfo methodInfo = AccessTools.Method(typeof(SemiFunc), "StatGetItemsPurchased", new Type[1] { typeof(string) }, (Type[])null);
if (!(methodInfo == null))
{
MethodInfo method = typeof(StatsModule).GetMethod("SemiFunc_StatGetItemsPurchased_Prefix", BindingFlags.Static | BindingFlags.NonPublic);
if (!(method == null))
{
harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
}
}
private static bool SemiFunc_StatGetItemsPurchased_Prefix(string itemName, ref int __result)
{
try
{
StatsManager instance = StatsManager.instance;
if ((Object)(object)instance == (Object)null)
{
return true;
}
EnsureKey(instance.itemsPurchased, itemName);
__result = instance.itemsPurchased[itemName];
return false;
}
catch
{
}
return true;
}
private static void PatchStatsManagerGetItemsUpgradesPurchasedIfPossible(Harmony harmony)
{
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_006c: Expected O, but got Unknown
MethodInfo methodInfo = AccessTools.Method(typeof(StatsManager), "GetItemsUpgradesPurchased", new Type[1] { typeof(string) }, (Type[])null);
if (!(methodInfo == null))
{
MethodInfo method = typeof(StatsModule).GetMethod("StatsManager_GetItemsUpgradesPurchased_Prefix", BindingFlags.Static | BindingFlags.NonPublic);
if (!(method == null))
{
harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
}
}
private static bool StatsManager_GetItemsUpgradesPurchased_Prefix(string itemName, ref int __result)
{
try
{
StatsManager instance = StatsManager.instance;
if ((Object)(object)instance == (Object)null)
{
return true;
}
EnsureKey(instance.itemsUpgradesPurchased, itemName);
__result = instance.itemsUpgradesPurchased[itemName];
return false;
}
catch
{
}
return true;
}
private static void PatchStatsManagerItemPurchaseIfPossible(Harmony harmony)
{
//IL_006a: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Expected O, but got Unknown
if (harmony == null)
{
return;
}
MethodInfo methodInfo = AccessTools.Method(typeof(StatsManager), "ItemPurchase", new Type[1] { typeof(string) }, (Type[])null);
if (!(methodInfo == null))
{
MethodInfo method = typeof(StatsModule).GetMethod("StatsManager_ItemPurchase_Prefix", BindingFlags.Static | BindingFlags.NonPublic);
if (!(method == null))
{
harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
}
}
private static bool StatsManager_ItemPurchase_Prefix(string itemName)
{
EnsureStatsManagerKey(itemName);
return true;
}
private static void EnsureKey(IDictionary<string, int> dictionary, string key)
{
if (dictionary != null && !string.IsNullOrWhiteSpace(key) && !dictionary.ContainsKey(key))
{
dictionary[key] = 0;
}
}
}
}
namespace DeathHeadHopperFix.Modules.Gameplay.Core.Interop
{
internal static class DHHApiGuardModule
{
private static bool s_guardMissingLocalCameraPosition;
internal static void DetectGameApiChanges()
{
try
{
Type type = AccessTools.TypeByName("PlayerAvatar");
if (type == null)
{
s_guardMissingLocalCameraPosition = true;
return;
}
FieldInfo field = type.GetField("localCameraPosition", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
s_guardMissingLocalCameraPosition = field == null;
}
catch
{
s_guardMissingLocalCameraPosition = true;
}
}
internal static void Apply(Harmony harmony, Assembly asm)
{
//IL_0077: Unknown result type (might be due to invalid IL or missing references)
//IL_0085: Expected O, but got Unknown
//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
//IL_00db: Expected O, but got Unknown
if (!s_guardMissingLocalCameraPosition)
{
return;
}
Type type = asm.GetType("DeathHeadHopper.DeathHead.DeathHeadController", throwOnError: false);
if (type == null)
{
return;
}
MethodInfo methodInfo = AccessTools.Method(type, "CancelReviveInCart", (Type[])null, (Type[])null);
if (methodInfo != null)
{
MethodInfo method = typeof(DHHApiGuardModule).GetMethod("DeathHeadController_CancelReviveInCart_Prefix", BindingFlags.Static | BindingFlags.NonPublic);
if (method != null)
{
harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
}
MethodInfo methodInfo2 = AccessTools.Method(type, "Update", (Type[])null, (Type[])null);
if (methodInfo2 != null)
{
MethodInfo method2 = typeof(DHHApiGuardModule).GetMethod("DeathHeadCon