using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using DeathHeadHopper.DeathHead;
using DeathHeadHopper.Managers;
using DeathHeadHopper.UI;
using DeathHeadHopperVRBridge.Modules.Config;
using DeathHeadHopperVRBridge.Modules.Logging;
using DeathHeadHopperVRBridge.Modules.Spectate;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using RepoXR;
using RepoXR.Input;
using RepoXR.Managers;
using RepoXR.Player;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.Rendering;
[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 DeathHeadHopperVRBridge
{
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInPlugin("AdrenSnyder.DeathHeadHopperVRBridge", "Death Head Hopper - VRBridge", "0.1.0")]
public sealed class Plugin : BaseUnityPlugin
{
private Harmony? _harmony;
private void Awake()
{
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0037: Expected O, but got Unknown
ConfigManager.Initialize(((BaseUnityPlugin)this).Config);
if (((Enum)Plugin.Flags).HasFlag((Enum)(object)(Flags)1))
{
_harmony = new Harmony("DeathHeadHopperFix-VR.Spectate");
_harmony.PatchAll();
VrAbilityBarBridge.EnsureAttached(((Component)this).gameObject);
VanillaAbilityInputBridge.EnsureAttached(((Component)this).gameObject);
((BaseUnityPlugin)this).Logger.LogInfo((object)"DeathHeadHopperFix-VR bridge ready (spectate head bridge enabled).");
}
else
{
((BaseUnityPlugin)this).Logger.LogWarning((object)"RepoXR did not initialize VR mode, keeping Bridge disabled.");
}
}
private void OnDestroy()
{
Harmony? harmony = _harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
}
}
}
namespace DeathHeadHopperVRBridge.Modules.Spectate
{
internal static class DHHInputBridge
{
internal enum MovementDirectionSource
{
Controller,
Head
}
internal enum AbilityDirectionSource
{
Controller,
Head
}
private static readonly FieldInfo? TMainCameraField = AccessTools.Field(typeof(DHHInputManager), "_tMainCamera");
internal static readonly ManualLogSource Log = MovementAnalog.Log;
internal const string ModuleTag = "[DeathHeadHopperFix-VR] [SpectateCam]";
private static Transform? _abilityAimProxy;
internal static MovementDirectionSource MovementDirection => ParseMovementDirection();
internal static AbilityDirectionSource AbilityDirection => ParseAbilityDirection();
internal static void UpdateCameraReference(DHHInputManager instance)
{
if ((Object)(object)instance == (Object)null || !SpectateHeadBridge.IsSpectatingHead())
{
return;
}
Transform val = SpectateHeadBridge.GetHmdCameraTransform() ?? SpectateHeadBridge.GetAlignedCameraTransform();
if ((Object)(object)val == (Object)null || TMainCameraField == null)
{
return;
}
object? value = TMainCameraField.GetValue(instance);
Transform val2 = (Transform)((value is Transform) ? value : null);
if (!((Object)(object)val2 == (Object)(object)val))
{
TMainCameraField.SetValue(instance, val);
if (FeatureFlags.DebugHeadAlignment && LogLimiter.Allow("UpdateCameraReference", 1f))
{
Log.LogInfo((object)"[DeathHeadHopperFix-VR] [SpectateCam] UpdateCameraReference swapped camera transform");
}
}
}
internal static bool TryGetAnalogMovement(out Vector2 movement)
{
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
bool flag = MovementAnalog.TryGetAnalog(out movement);
if (FeatureFlags.DebugHeadAlignment && LogLimiter.Allow("AnalogMovementCheck", 0.5f))
{
Log.LogInfo((object)string.Format("{0} TryGetAnalogMovement analogAvailable={1} movement={2:F3}", "[DeathHeadHopperFix-VR] [SpectateCam]", flag, movement));
}
return flag;
}
internal static Vector2 GetLegacyMovement()
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: 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)
return new Vector2(SemiFunc.InputMovementX(), SemiFunc.InputMovementY());
}
internal static Vector3 CalculateMoveDirection(Vector2 input)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: 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_004b: Unknown result type (might be due to invalid IL or missing references)
//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)
//IL_0061: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
Vector3 val = GetMovementForward(input);
if (((Vector3)(ref val)).sqrMagnitude < 0.0001f)
{
val = Vector3.forward;
}
Vector3 val2 = Vector3.Cross(Vector3.up, val);
Vector3 val3 = val * input.y + val2 * input.x;
if (((Vector3)(ref val3)).sqrMagnitude < 0.0001f)
{
return Vector3.zero;
}
if (FeatureFlags.DebugMovementDirection && LogLimiter.Allow("MovementDirectionDebug", 0.5f))
{
Log.LogInfo((object)string.Format("{0} DebugMovement direction={1:F3} forward={2:F3} input={3:F3} source={4}", "[DeathHeadHopperFix-VR] [SpectateCam]", val3, val, input, MovementDirection));
}
if (FeatureFlags.UseAnalogMagnitude)
{
return Vector3.ClampMagnitude(val3, 1f);
}
return ((Vector3)(ref val3)).normalized;
}
internal static void LogMovement(Vector2 selected, Vector2 legacy, bool analogUsed, Vector3 direction, MovementDirectionSource source)
{
//IL_003e: 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_0059: Unknown result type (might be due to invalid IL or missing references)
if (FeatureFlags.DebugMovementDirection && LogLimiter.Allow("MovementInput", 0.5f))
{
Log.LogDebug((object)string.Format("{0} Movement selected={1:F3} legacy={2:F3} analogUsed={3} forward={4:F3} source={5}", "[DeathHeadHopperFix-VR] [SpectateCam]", selected, legacy, analogUsed, direction, source));
}
}
private static void DebugTrace(string key, string message)
{
if (FeatureFlags.DebugHeadAlignment && LogLimiter.Allow(key, 0.5f))
{
Log.LogInfo((object)("[DeathHeadHopperFix-VR] [SpectateCam] " + message));
}
}
private static Vector3 GetMovementForward(Vector2 input)
{
//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)
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: 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_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: 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)
MovementDirectionSource movementDirection = MovementDirection;
if (1 == 0)
{
}
Vector3 val = ((movementDirection != MovementDirectionSource.Head) ? GetControllerForward(input) : SpectateHeadBridge.GetAlignedForward());
if (1 == 0)
{
}
Vector3 result = val;
if (((Vector3)(ref result)).sqrMagnitude < 0.0001f)
{
return SpectateHeadBridge.GetBaseForward();
}
return result;
}
internal static Vector3 GetControllerForward(Vector2 movementInput)
{
//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: 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_00c0: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
//IL_0087: Unknown result type (might be due to invalid IL or missing references)
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
try
{
string handName;
Transform val = TryGetPreferredControllerTransform(GetCameraGripSelection(), out handName);
if ((Object)(object)val != (Object)null)
{
Vector3 planarForward = Vector3.ProjectOnPlane(val.forward, Vector3.up);
LogControllerOrientation(val, handName, movementInput, planarForward);
if (((Vector3)(ref planarForward)).sqrMagnitude > 1E-06f)
{
return ((Vector3)(ref planarForward)).normalized;
}
}
TrackingInput instance = TrackingInput.Instance;
Transform val2 = ((instance != null) ? instance.HeadTransform : null);
if ((Object)(object)val2 != (Object)null)
{
Vector3 val3 = Vector3.ProjectOnPlane(val2.forward, Vector3.up);
if (((Vector3)(ref val3)).sqrMagnitude > 0.0001f)
{
return ((Vector3)(ref val3)).normalized;
}
}
}
catch
{
}
return SpectateHeadBridge.GetBaseForward();
}
internal static Vector3 GetAbilityForward()
{
//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)
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: 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_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
AbilityDirectionSource abilityDirection = AbilityDirection;
if (1 == 0)
{
}
Vector3 val = ((abilityDirection != AbilityDirectionSource.Head) ? GetControllerAimForward() : GetHeadAimForward());
if (1 == 0)
{
}
Vector3 val2 = val;
if (((Vector3)(ref val2)).sqrMagnitude < 0.0001f)
{
return SpectateHeadBridge.GetAlignedForward();
}
return ((Vector3)(ref val2)).normalized;
}
private static Vector3 GetHeadAimForward()
{
//IL_0025: 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_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
Transform val = SpectateHeadBridge.GetHmdCameraTransform() ?? SpectateHeadBridge.GetAlignedCameraTransform();
if ((Object)(object)val != (Object)null)
{
return val.forward;
}
return SpectateHeadBridge.GetAlignedForward();
}
private static Vector3 GetControllerAimForward()
{
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_0063: 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)
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
try
{
string handName;
Transform val = TryGetPreferredControllerTransform(GetAbilityGripSelection(), out handName);
if ((Object)(object)val != (Object)null)
{
return val.forward;
}
TrackingInput instance = TrackingInput.Instance;
Transform val2 = ((instance != null) ? instance.HeadTransform : null);
if ((Object)(object)val2 != (Object)null)
{
return val2.forward;
}
}
catch
{
}
return SpectateHeadBridge.GetAlignedForward();
}
private static GripSelection GetCameraGripSelection()
{
return GripSelectionHelper.Parse(FeatureFlags.CameraGripPreference);
}
private static GripSelection GetAbilityGripSelection()
{
return GripSelectionHelper.Parse(FeatureFlags.AbilityGripPreference);
}
private static Transform? TryGetPreferredControllerTransform(GripSelection preference, out string handName)
{
TrackingInput instance = TrackingInput.Instance;
bool flag = GripSelectionHelper.ShouldUseLeft(preference);
handName = (flag ? "Left" : "Right");
Transform val = ((!flag) ? ((instance != null) ? instance.RightHandTransform : null) : ((instance != null) ? instance.LeftHandTransform : null));
if ((Object)(object)val != (Object)null)
{
return val;
}
VRSession instance2 = VRSession.Instance;
VRPlayer val2 = ((instance2 != null) ? instance2.Player : null);
if ((Object)(object)val2 != (Object)null)
{
Transform secondaryHand = val2.SecondaryHand;
if ((Object)(object)secondaryHand != (Object)null)
{
handName = (flag ? "Left" : "Right");
return secondaryHand;
}
}
handName = "unknown";
return null;
}
private static void LogControllerOrientation(Transform transform, string handName, Vector2 movementInput, Vector3 planarForward)
{
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
//IL_003f: 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_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0077: Unknown result type (might be due to invalid IL or missing references)
//IL_0080: Unknown result type (might be due to invalid IL or missing references)
//IL_0089: Unknown result type (might be due to invalid IL or missing references)
if (FeatureFlags.LogControllerOrientation && !(((Vector2)(ref movementInput)).sqrMagnitude < 0.0001f) && LogLimiter.Allow("ControllerOrientation", 0.5f))
{
Vector3 forward = transform.forward;
Quaternion rotation = transform.rotation;
Vector3 eulerAngles = ((Quaternion)(ref rotation)).eulerAngles;
Log.LogInfo((object)string.Format("{0} Controller orientation {1} forward={2:F3} planar={3:F3} euler={4:F3} input={5:F3}", "[DeathHeadHopperFix-VR] [SpectateCam]", handName, forward, planarForward, eulerAngles, movementInput));
}
}
private static MovementDirectionSource ParseMovementDirection()
{
string movementDirectionSource = FeatureFlags.MovementDirectionSource;
if (Enum.TryParse<MovementDirectionSource>(movementDirectionSource, ignoreCase: true, out var result))
{
return result;
}
return MovementDirectionSource.Controller;
}
private static AbilityDirectionSource ParseAbilityDirection()
{
string abilityDirectionSource = FeatureFlags.AbilityDirectionSource;
if (Enum.TryParse<AbilityDirectionSource>(abilityDirectionSource, ignoreCase: true, out var result))
{
return result;
}
return AbilityDirectionSource.Head;
}
internal static bool TrySwapAimCamera(DHHInputManager instance, out Transform? original)
{
//IL_0027: 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_00a8: Unknown result type (might be due to invalid IL or missing references)
//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
//IL_00be: Unknown result type (might be due to invalid IL or missing references)
//IL_0083: Unknown result type (might be due to invalid IL or missing references)
//IL_008a: Expected O, but got Unknown
original = null;
if (TMainCameraField == null || (Object)(object)instance == (Object)null)
{
return false;
}
Vector3 abilityForward = GetAbilityForward();
if (((Vector3)(ref abilityForward)).sqrMagnitude < 0.0001f)
{
return false;
}
object? value = TMainCameraField.GetValue(instance);
Transform val = (Transform)((value is Transform) ? value : null);
if ((Object)(object)val == (Object)null)
{
return false;
}
if ((Object)(object)_abilityAimProxy == (Object)null)
{
GameObject val2 = new GameObject("DeathHeadHopperVRBridge_AbilityAimProxy");
Object.DontDestroyOnLoad((Object)(object)val2);
_abilityAimProxy = val2.transform;
}
original = val;
_abilityAimProxy.position = val.position;
_abilityAimProxy.rotation = Quaternion.LookRotation(abilityForward, Vector3.up);
TMainCameraField.SetValue(instance, _abilityAimProxy);
return true;
}
internal static void RestoreAimCamera(DHHInputManager instance, Transform original)
{
if (!(TMainCameraField == null) && !((Object)(object)instance == (Object)null) && !((Object)(object)original == (Object)null))
{
TMainCameraField.SetValue(instance, original);
}
}
}
[HarmonyPatch(typeof(DHHInputManager), "Update")]
internal static class DHHInputManagerUpdatePatch
{
private static void Prefix(DHHInputManager __instance)
{
if (FeatureFlags.DebugHeadAlignment && LogLimiter.Allow("DHHUpdatePatch", 1f))
{
DHHInputBridge.Log.LogInfo((object)"[DeathHeadHopperFix-VR] [SpectateCam] DHHInputManager.Update patch running");
}
DHHInputBridge.UpdateCameraReference(__instance);
}
}
[HarmonyPatch(typeof(DHHInputManager), "LateUpdate")]
internal static class DHHInputManagerLateUpdatePatch
{
private static void Prefix(DHHInputManager __instance)
{
DHHInputBridge.UpdateCameraReference(__instance);
bool flag = SpectateHeadBridge.IsSpectatingHead();
if (FeatureFlags.DebugHeadAlignment && LogLimiter.Allow("LateUpdateSpectate", 2f))
{
DHHInputBridge.Log.LogInfo((object)string.Format("{0} LateUpdate running spectatingHead={1}", "[DeathHeadHopperFix-VR] [SpectateCam]", flag));
}
}
}
[HarmonyPatch(typeof(DHHInputManager), "GetMoveDirection")]
internal static class DHHInputManagerGetMoveDirectionPatch
{
private static bool Prefix(ref Vector3 __result)
{
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_0063: Unknown result type (might be due to invalid IL or missing references)
//IL_00af: Unknown result type (might be due to invalid IL or missing references)
//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
//IL_011c: Unknown result type (might be due to invalid IL or missing references)
//IL_011d: Unknown result type (might be due to invalid IL or missing references)
//IL_011f: Unknown result type (might be due to invalid IL or missing references)
//IL_012c: Unknown result type (might be due to invalid IL or missing references)
//IL_012d: Unknown result type (might be due to invalid IL or missing references)
//IL_010a: Unknown result type (might be due to invalid IL or missing references)
if (!SpectateHeadBridge.IsSpectatingHead())
{
if (FeatureFlags.DebugSpectateGuard && LogLimiter.Allow("MovementGuard", 2f))
{
DHHInputBridge.Log.LogInfo((object)"[DeathHeadHopperFix-VR] [SpectateCam] Movement guard skipped (not spectating head)");
}
return true;
}
Vector2 movement;
bool flag = DHHInputBridge.TryGetAnalogMovement(out movement);
Vector2 legacyMovement = DHHInputBridge.GetLegacyMovement();
if (!flag)
{
movement = legacyMovement;
}
Vector3 val = DHHInputBridge.CalculateMoveDirection(movement);
if (FeatureFlags.DebugMovementDirection && LogLimiter.Allow("MovementInputs", 1f))
{
DHHInputBridge.Log.LogInfo((object)string.Format("{0} Movement patch triggered analog={1} input={2:F3} direction={3:F3} source={4}", "[DeathHeadHopperFix-VR] [SpectateCam]", flag, movement, val, DHHInputBridge.MovementDirection));
}
if (!flag && FeatureFlags.DebugMovementDirection && LogLimiter.Allow("MovementFallback", 1f))
{
DHHInputBridge.Log.LogInfo((object)string.Format("{0} Falling back to legacy WASD input {1:F3}", "[DeathHeadHopperFix-VR] [SpectateCam]", legacyMovement));
}
DHHInputBridge.LogMovement(movement, legacyMovement, flag, val, DHHInputBridge.MovementDirection);
__result = val;
return false;
}
}
[HarmonyPatch(typeof(DHHInputManager), "ChargeWindup")]
internal static class DHHInputManagerChargeWindupPatch
{
private static void Prefix(DHHInputManager __instance, ref Transform? __state)
{
if (SpectateHeadBridge.IsSpectatingHead() && DHHInputBridge.TrySwapAimCamera(__instance, out Transform original))
{
__state = original;
}
}
private static void Postfix(DHHInputManager __instance, Transform? __state)
{
if ((Object)(object)__state != (Object)null)
{
DHHInputBridge.RestoreAimCamera(__instance, __state);
}
}
}
[HarmonyPatch(typeof(DHHInputManager), "UpdateChargeWindup")]
internal static class DHHInputManagerUpdateChargeWindupPatch
{
private static void Prefix(DHHInputManager __instance, ref Transform? __state)
{
if (SpectateHeadBridge.IsSpectatingHead() && DHHInputBridge.TrySwapAimCamera(__instance, out Transform original))
{
__state = original;
}
}
private static void Postfix(DHHInputManager __instance, Transform? __state)
{
if ((Object)(object)__state != (Object)null)
{
DHHInputBridge.RestoreAimCamera(__instance, __state);
}
}
}
[HarmonyPatch(typeof(SemiFunc), "InputMovementX")]
internal static class SemiFuncInputMovementXPatch
{
private static bool Prefix(ref float __result)
{
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
if (!SpectateHeadBridge.IsSpectatingHead())
{
return true;
}
if (!MovementAnalog.TryGetAnalog(out var movement))
{
return true;
}
MovementAnalog.LogAnalog(movement, triggered: true);
__result = movement.x;
return false;
}
}
[HarmonyPatch(typeof(SemiFunc), "InputMovementY")]
internal static class SemiFuncInputMovementYPatch
{
private static bool Prefix(ref float __result)
{
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
if (!SpectateHeadBridge.IsSpectatingHead())
{
return true;
}
if (!MovementAnalog.TryGetAnalog(out var movement))
{
return true;
}
__result = movement.y;
return false;
}
}
internal enum GripSelection
{
Auto,
Left,
Right
}
internal static class GripSelectionHelper
{
internal static GripSelection Parse(string raw)
{
if (string.IsNullOrWhiteSpace(raw))
{
return GripSelection.Auto;
}
if (Enum.TryParse<GripSelection>(raw.Trim(), ignoreCase: true, out var result))
{
return result;
}
return GripSelection.Auto;
}
internal static bool ShouldUseLeft(GripSelection selection)
{
if (1 == 0)
{
}
bool result = selection switch
{
GripSelection.Left => true,
GripSelection.Right => false,
_ => !VRSession.IsLeftHanded,
};
if (1 == 0)
{
}
return result;
}
}
internal static class Math
{
internal static int Max(int x, int y)
{
return System.Math.Max(x, y);
}
internal static int Clamp(int value, int min, int max)
{
if (value < min)
{
return min;
}
if (value > max)
{
return max;
}
return value;
}
}
internal static class MovementAnalog
{
private static readonly ManualLogSource LogSource = Logger.CreateLogSource("DeathHeadHopperFix-VR.InputBridge");
internal const string ModuleTag = "[DeathHeadHopperFix-VR] [SpectateCam]";
internal static ManualLogSource Log => LogSource;
internal static bool TryGetAnalog(out Vector2 movement)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_008a: Unknown result type (might be due to invalid IL or missing references)
movement = Vector2.zero;
InputAction val;
try
{
val = Actions.Instance["Movement"];
}
catch
{
val = null;
}
if (val == null)
{
return false;
}
movement = val.ReadValue<Vector2>();
if (((Vector2)(ref movement)).sqrMagnitude > 0.0001f && SpectateHeadBridge.IsSpectatingHead() && FeatureFlags.DebugMovementDirection && LogLimiter.Allow("JoystickSpectateLog", 0.5f))
{
LogSource.LogInfo((object)string.Format("{0} Joystick moved while spectating head movement={1:F3}", "[DeathHeadHopperFix-VR] [SpectateCam]", movement));
}
return ((Vector2)(ref movement)).sqrMagnitude > 0.0001f;
}
internal static void LogAnalog(Vector2 analog, bool triggered)
{
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
if (FeatureFlags.DebugMovementDirection && LogLimiter.Allow("MovementAnalog", 0.5f))
{
LogSource.LogDebug((object)string.Format("{0} Analog movement triggered={1} vector={2:F3}", "[DeathHeadHopperFix-VR] [SpectateCam]", triggered, analog));
}
}
}
internal static class SpectateHeadBridge
{
internal static readonly ManualLogSource Log = Logger.CreateLogSource("DeathHeadHopperFix-VR.HeadBridge");
internal const string ModuleTag = "[DeathHeadHopperFix-VR] [SpectateCam]";
private static readonly FieldInfo? SpectateCameraMainCameraField = AccessTools.Field(typeof(SpectateCamera), "MainCamera");
private static readonly Type? ActionsType = AccessTools.TypeByName("RepoXR.Input.Actions");
private static readonly PropertyInfo? InstanceProperty = ActionsType?.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public);
private static readonly PropertyInfo? IndexerProperty = ActionsType?.GetProperty("Item", new Type[1] { typeof(string) });
private static readonly FieldInfo? PlayerDeathHeadGrabField = AccessTools.Field(typeof(PlayerDeathHead), "physGrabObject");
private static Vector3 _baseForward = Vector3.forward;
private static bool _baseForwardSet;
private static readonly string[] LeftGripBindings = new string[4] { "GripLeft", "leftGrip", "Grab", "MapGrabLeft" };
private static readonly string[] RightGripBindings = new string[4] { "GripRight", "rightGrip", "Grab", "MapGrabRight" };
internal static readonly FieldInfo? DeathHeadSpectatedField = AccessTools.Field(typeof(DeathHeadController), "spectated");
private static bool _spectatedAnchorActive;
internal static bool VrModeActive => VRSession.InVR;
private static object? ActionsInstance => InstanceProperty?.GetValue(null);
internal static void AlignHeadCamera(bool force)
{
//IL_0169: Unknown result type (might be due to invalid IL or missing references)
//IL_0160: Unknown result type (might be due to invalid IL or missing references)
//IL_016e: Unknown result type (might be due to invalid IL or missing references)
//IL_0176: 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_0185: Unknown result type (might be due to invalid IL or missing references)
//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
//IL_0214: Unknown result type (might be due to invalid IL or missing references)
//IL_0216: Unknown result type (might be due to invalid IL or missing references)
//IL_021d: Unknown result type (might be due to invalid IL or missing references)
//IL_0222: Unknown result type (might be due to invalid IL or missing references)
//IL_0227: Unknown result type (might be due to invalid IL or missing references)
//IL_022b: Unknown result type (might be due to invalid IL or missing references)
//IL_0230: Unknown result type (might be due to invalid IL or missing references)
//IL_0235: Unknown result type (might be due to invalid IL or missing references)
//IL_0237: Unknown result type (might be due to invalid IL or missing references)
//IL_0239: Unknown result type (might be due to invalid IL or missing references)
//IL_023e: Unknown result type (might be due to invalid IL or missing references)
//IL_0243: Unknown result type (might be due to invalid IL or missing references)
//IL_0267: Unknown result type (might be due to invalid IL or missing references)
//IL_026c: Unknown result type (might be due to invalid IL or missing references)
//IL_0270: Unknown result type (might be due to invalid IL or missing references)
//IL_0287: Unknown result type (might be due to invalid IL or missing references)
//IL_028c: Unknown result type (might be due to invalid IL or missing references)
//IL_0290: Unknown result type (might be due to invalid IL or missing references)
//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
//IL_02be: Unknown result type (might be due to invalid IL or missing references)
//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
if (!VrModeActive)
{
return;
}
TraceAlignment($"AlignHeadCamera start force={force}");
LogImmediate($"AlignHeadCamera immediate start force={force}");
LogImmediate($"AlignHeadCamera immediate log force={force}");
SpectateCamera instance = SpectateCamera.instance;
PlayerAvatar instance2 = PlayerAvatar.instance;
PlayerDeathHead val = instance2?.playerDeathHead;
Camera spectateMainCamera = GetSpectateMainCamera(instance);
if ((Object)(object)instance == (Object)null || (Object)(object)val == (Object)null || (Object)(object)spectateMainCamera == (Object)null)
{
TraceAlignment("AlignHeadCamera aborted: missing context or camera");
return;
}
bool flag = IsGripPressed();
if (FeatureFlags.DebugHeadAlignment && LogLimiter.Allow("AlignHeadCamera", 0.25f))
{
Log.LogDebug((object)string.Format("{0} AlignHeadCamera force={1} gripPressed={2}", "[DeathHeadHopperFix-VR] [SpectateCam]", force, flag));
}
if (!force && flag)
{
if (FeatureFlags.DebugHeadAlignment && LogLimiter.Allow("HeadAlignmentGuard", 0.5f))
{
Log.LogInfo((object)"[DeathHeadHopperFix-VR] [SpectateCam] alignment skipped because grip is pressed");
}
return;
}
object? obj = PlayerDeathHeadGrabField?.GetValue(val);
Vector3 val2 = ((PhysGrabObject)(((obj is PhysGrabObject) ? obj : null)?)).centerPoint ?? ((Component)val).transform.position;
Vector3 val3 = Vector3.ProjectOnPlane(((Component)val).transform.forward, Vector3.up);
if (((Vector3)(ref val3)).sqrMagnitude < 0.0001f && (Object)(object)instance2 != (Object)null)
{
val3 = Vector3.ProjectOnPlane(((Component)instance2).transform.forward, Vector3.up);
}
if (((Vector3)(ref val3)).sqrMagnitude < 0.0001f)
{
val3 = Vector3.forward;
}
((Vector3)(ref val3)).Normalize();
if (force || !_baseForwardSet)
{
_baseForward = val3;
_baseForwardSet = true;
}
float headCameraDistance = FeatureFlags.HeadCameraDistance;
float headCameraHeightOffset = FeatureFlags.HeadCameraHeightOffset;
Vector3 val4 = val2 + Vector3.up * headCameraHeightOffset - val3 * headCameraDistance;
Quaternion val5 = Quaternion.LookRotation(val3, Vector3.up);
float headCameraLerpSpeed = FeatureFlags.HeadCameraLerpSpeed;
float num = Mathf.Clamp01(headCameraLerpSpeed * Time.deltaTime);
((Component)instance).transform.position = Vector3.Lerp(((Component)instance).transform.position, val4, num);
((Component)instance).transform.rotation = Quaternion.Slerp(((Component)instance).transform.rotation, val5, num);
((Component)spectateMainCamera).transform.position = ((Component)instance).transform.position;
((Component)spectateMainCamera).transform.rotation = ((Component)instance).transform.rotation;
}
internal static bool IsGripPressed()
{
return IsGripPressedForCamera();
}
internal static bool IsGripPressedForCamera()
{
GripSelection selection = GripSelectionHelper.Parse(FeatureFlags.CameraGripPreference);
return IsGripPressed(selection);
}
internal static bool IsGripPressedForAbility()
{
GripSelection selection = GripSelectionHelper.Parse(FeatureFlags.AbilityGripPreference);
return IsGripPressed(selection);
}
private static bool IsGripPressed(GripSelection selection)
{
bool flag = GripSelectionHelper.ShouldUseLeft(selection);
string[] array = (flag ? LeftGripBindings : RightGripBindings);
string[] array2 = array;
foreach (string text in array2)
{
object action = GetAction(text);
if (IsActionPressed(action))
{
if (FeatureFlags.DebugHeadAlignment && LogLimiter.Allow("IsGripPressed", 0.5f))
{
Log.LogDebug((object)string.Format("{0} Grip detected on binding {1} (leftGrip={2}) using {3}", "[DeathHeadHopperFix-VR] [SpectateCam]", text, flag, selection));
}
return true;
}
}
return false;
}
private static Camera? GetSpectateMainCamera(SpectateCamera? spectate)
{
if ((Object)(object)spectate == (Object)null || SpectateCameraMainCameraField == null)
{
return null;
}
object? value = SpectateCameraMainCameraField.GetValue(spectate);
return (Camera?)((value is Camera) ? value : null);
}
internal static Vector3 GetBaseForward()
{
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: 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_0017: Unknown result type (might be due to invalid IL or missing references)
return _baseForwardSet ? _baseForward : GetAlignedForward();
}
internal static bool IsSpectatingHead()
{
if (!VrModeActive)
{
return false;
}
SpectateCamera instance = SpectateCamera.instance;
if ((Object)(object)instance != (Object)null && instance.CheckState((State)2))
{
TraceAlignment("SpectateCamera reports State.Head");
return true;
}
PlayerDeathHead val = PlayerAvatar.instance?.playerDeathHead;
if ((Object)(object)val != (Object)null)
{
DeathHeadController val2 = null;
DeathHeadController val3 = default(DeathHeadController);
if (((Component)val).TryGetComponent<DeathHeadController>(ref val3))
{
val2 = val3;
}
if ((Object)(object)val2 != (Object)null && DeathHeadSpectatedField != null && DeathHeadSpectatedField.GetValue(val2) is bool flag)
{
TraceAlignment($"DeathHeadController.spectated={flag}");
if (flag)
{
return true;
}
}
FieldInfo fieldInfo = AccessTools.Field(typeof(PlayerDeathHead), "overrideSpectated");
bool flag2 = default(bool);
int num;
if (fieldInfo != null)
{
object value = fieldInfo.GetValue(val);
if (value is bool)
{
flag2 = (bool)value;
num = 1;
}
else
{
num = 0;
}
}
else
{
num = 0;
}
if (((uint)num & (flag2 ? 1u : 0u)) != 0)
{
TraceAlignment("PlayerDeathHead.overrideSpectated true");
return true;
}
}
return false;
}
internal static Transform? GetAlignedCameraTransform()
{
SpectateCamera instance = SpectateCamera.instance;
Camera spectateMainCamera = GetSpectateMainCamera(instance);
if ((Object)(object)spectateMainCamera != (Object)null)
{
return ((Component)spectateMainCamera).transform;
}
return (instance != null) ? ((Component)instance).transform : null;
}
internal static Vector3 GetAlignedForward()
{
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: 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_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: 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_005f: Unknown result type (might be due to invalid IL or missing references)
Transform alignedCameraTransform = GetAlignedCameraTransform();
if ((Object)(object)alignedCameraTransform == (Object)null)
{
return Vector3.forward;
}
Vector3 val = Vector3.ProjectOnPlane(alignedCameraTransform.forward, Vector3.up);
if (((Vector3)(ref val)).sqrMagnitude < 0.0001f)
{
val = alignedCameraTransform.forward;
val.y = 0f;
}
return ((Vector3)(ref val)).normalized;
}
private static object? GetAction(string name)
{
object actionsInstance = ActionsInstance;
if (actionsInstance == null || IndexerProperty == null)
{
return null;
}
try
{
return IndexerProperty.GetValue(actionsInstance, new object[1] { name });
}
catch
{
return null;
}
}
private static bool IsActionPressed(object? action)
{
if (action == null)
{
return false;
}
MethodInfo method = action.GetType().GetMethod("IsPressed", Type.EmptyTypes);
if (method == null)
{
return false;
}
try
{
object obj = method.Invoke(action, null);
bool flag = default(bool);
int num;
if (obj is bool)
{
flag = (bool)obj;
num = 1;
}
else
{
num = 0;
}
return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
}
catch
{
return false;
}
}
internal static Transform? GetHmdCameraTransform()
{
if (!VrModeActive || (Object)(object)VRSession.Instance == (Object)null)
{
return null;
}
Camera mainCamera = VRSession.Instance.MainCamera;
return (mainCamera != null) ? ((Component)mainCamera).transform : null;
}
internal static void TraceAlignment(string message)
{
if (FeatureFlags.DebugHeadAlignment && LogLimiter.Allow("AlignTrace", 0.5f))
{
Log.LogInfo((object)("[DeathHeadHopperFix-VR] [SpectateCam] " + message));
}
}
internal static void LogImmediate(string message)
{
if (FeatureFlags.DebugHeadAlignment)
{
Log.LogInfo((object)("[DeathHeadHopperFix-VR] [SpectateCam] " + message));
}
}
private static void LogAnchorCameraState(string message, SpectateCamera? spectate)
{
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: 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)
if (FeatureFlags.DebugHeadAlignment)
{
Camera spectateMainCamera = GetSpectateMainCamera(spectate);
Vector3 val = ((spectateMainCamera != null) ? ((Component)spectateMainCamera).transform.forward : ((spectate != null) ? ((Component)spectate).transform.forward : Vector3.zero));
Vector3 val2 = ((spectateMainCamera != null) ? ((Component)spectateMainCamera).transform.position : ((spectate != null) ? ((Component)spectate).transform.position : Vector3.zero));
Log.LogInfo((object)string.Format("{0} {1} pos={2:F3} forward={3:F3}", "[DeathHeadHopperFix-VR] [SpectateCam]", message, val2, val));
}
}
internal static void OnSpectatedAnchor(bool value)
{
if (value && !_spectatedAnchorActive)
{
_spectatedAnchorActive = true;
TraceAlignment("Spectated anchor activated");
LogImmediate("Spectated anchor activated");
AlignHeadCamera(force: true);
LogAnchorCameraState("Spectated anchor camera", SpectateCamera.instance);
}
else if (!value && _spectatedAnchorActive)
{
_spectatedAnchorActive = false;
TraceAlignment("Spectated anchor cleared");
LogImmediate("Spectated anchor cleared");
}
}
}
[HarmonyPatch(typeof(SpectateCamera), "StateHead")]
internal static class SpectateCameraStateHeadPatch
{
private static void Postfix()
{
SpectateHeadBridge.TraceAlignment("SpectateCamera.StateHead Postfix triggered");
SpectateHeadBridge.LogImmediate("SpectateCamera.StateHead Postfix triggered");
if (FeatureFlags.DebugHeadAlignment && LogLimiter.Allow("StateHead.Enter", 0.5f))
{
SpectateHeadBridge.Log.LogDebug((object)"[DeathHeadHopperFix-VR] [SpectateCam] SpectateCamera.StateHead entered, queuing head alignment");
}
SpectateHeadBridge.AlignHeadCamera(force: false);
}
}
[HarmonyPatch(typeof(SpectateCamera), "UpdateState")]
internal static class SpectateCameraUpdateStatePatch
{
private static State _previousState;
private static void Postfix(State _state)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0009: Invalid comparison between Unknown and I4
_previousState = _state;
if ((int)_state == 2)
{
SpectateHeadBridge.AlignHeadCamera(force: false);
}
}
}
[HarmonyPatch(typeof(PlayerDeathHead), "OverrideSpectatedReset")]
internal static class PlayerDeathHeadResetPatch
{
private static void Postfix()
{
SpectateHeadBridge.TraceAlignment("PlayerDeathHead.OverrideSpectatedReset Postfix triggered");
SpectateHeadBridge.LogImmediate("PlayerDeathHead.OverrideSpectatedReset Postfix triggered");
}
}
[HarmonyPatch(typeof(DeathHeadController), "SetSpectated")]
internal static class DeathHeadControllerSetSpectatedPatch
{
private static void Postfix(DeathHeadController __instance, bool value)
{
SpectateHeadBridge.LogImmediate($"DeathHeadController.SetSpectated value={value}");
SpectateHeadBridge.OnSpectatedAnchor(value);
}
}
[HarmonyPatch(typeof(PlayerDeathHead), "SpectatedSet")]
internal static class PlayerDeathHeadSpectatedSetPatch
{
private static void Postfix(PlayerDeathHead __instance, bool _active)
{
SpectateHeadBridge.LogImmediate($"PlayerDeathHead.SpectatedSet _active={_active}");
if (_active)
{
SpectateHeadBridge.OnSpectatedAnchor(value: true);
}
}
}
[HarmonyPatch]
internal static class HeadCameraTurnGripGuard
{
private static readonly Type? SpectatePatchesType = AccessTools.TypeByName("RepoXR.Patches.SpectatePatches");
private static MethodBase? TargetMethod()
{
if (SpectatePatchesType == null)
{
return null;
}
return AccessTools.Method(SpectatePatchesType, "HeadCameraTurnPatch", (Type[])null, (Type[])null);
}
private static bool Prefix()
{
bool flag = SpectateHeadBridge.IsGripPressedForCamera();
if (FeatureFlags.DebugHeadAlignment && LogLimiter.Allow("HeadCameraTurnGuard", 0.5f))
{
SpectateHeadBridge.Log.LogDebug((object)string.Format("{0} HeadCameraTurnPatch guard gripPressed={1}", "[DeathHeadHopperFix-VR] [SpectateCam]", flag));
}
return flag;
}
}
[HarmonyPatch]
internal static class SpectateMovementGuard
{
[HarmonyPatch]
internal static class SpectateMovementGuardY
{
private static MethodBase? TargetMethod()
{
Type type = AccessTools.TypeByName("RepoXR.Patches.SpectatePatches");
return (type == null) ? null : AccessTools.Method(type, "<InputPatch>g__GetRotationY|5_1", (Type[])null, (Type[])null);
}
private static bool Prefix(ref float __result)
{
return TryGuard(ref __result);
}
}
private static readonly ManualLogSource Log = Logger.CreateLogSource("DeathHeadHopperFix-VR.HeadBridge");
private static MethodBase? TargetMethod()
{
Type type = AccessTools.TypeByName("RepoXR.Patches.SpectatePatches");
return (type == null) ? null : AccessTools.Method(type, "<InputPatch>g__GetRotationX|5_0", (Type[])null, (Type[])null);
}
private static bool Prefix(ref float __result)
{
return TryGuard(ref __result);
}
private static bool TryGuard(ref float result)
{
if (SpectateHeadBridge.IsGripPressedForCamera())
{
return true;
}
if (FeatureFlags.DebugSpectateGuard && LogLimiter.Allow("MovementGuard.Override", 0.25f))
{
Log.LogDebug((object)"[DeathHeadHopperFix-VR] [SpectateCam] Movement guard zeroed rotation because grip is not pressed");
}
result = 0f;
return false;
}
}
internal sealed class VanillaAbilityInputBridge : MonoBehaviour
{
[CompilerGenerated]
private sealed class <ParseActionNames>d__30 : IEnumerable<string>, IEnumerable, IEnumerator<string>, IDisposable, IEnumerator
{
private int <>1__state;
private string <>2__current;
private int <>l__initialThreadId;
private string raw;
public string <>3__raw;
private string[] <>s__1;
private int <>s__2;
private string <part>5__3;
private string <trimmed>5__4;
string? IEnumerator<string>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object? IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <ParseActionNames>d__30(int <>1__state)
{
this.<>1__state = <>1__state;
<>l__initialThreadId = Environment.CurrentManagedThreadId;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>s__1 = null;
<part>5__3 = null;
<trimmed>5__4 = null;
<>1__state = -2;
}
private bool MoveNext()
{
int num = <>1__state;
if (num != 0)
{
if (num != 1)
{
return false;
}
<>1__state = -1;
goto IL_00b6;
}
<>1__state = -1;
if (string.IsNullOrWhiteSpace(raw))
{
return false;
}
<>s__1 = raw.Split(new char[2] { ';', ',' }, StringSplitOptions.RemoveEmptyEntries);
<>s__2 = 0;
goto IL_00d3;
IL_00b6:
<trimmed>5__4 = null;
<part>5__3 = null;
<>s__2++;
goto IL_00d3;
IL_00d3:
if (<>s__2 < <>s__1.Length)
{
<part>5__3 = <>s__1[<>s__2];
<trimmed>5__4 = <part>5__3.Trim();
if (!string.IsNullOrEmpty(<trimmed>5__4))
{
<>2__current = <trimmed>5__4;
<>1__state = 1;
return true;
}
goto IL_00b6;
}
<>s__1 = null;
return false;
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
[DebuggerHidden]
IEnumerator<string> IEnumerable<string>.GetEnumerator()
{
<ParseActionNames>d__30 <ParseActionNames>d__;
if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
{
<>1__state = 0;
<ParseActionNames>d__ = this;
}
else
{
<ParseActionNames>d__ = new <ParseActionNames>d__30(0);
}
<ParseActionNames>d__.raw = <>3__raw;
return <ParseActionNames>d__;
}
[DebuggerHidden]
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable<string>)this).GetEnumerator();
}
}
private const int SlotCount = 3;
private static readonly Type? RepoXRActionsType = AccessTools.TypeByName("RepoXR.Input.Actions");
private static readonly PropertyInfo? RepoXRActionsInstance = RepoXRActionsType?.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public);
private static readonly PropertyInfo? RepoXRActionsIndexer = RepoXRActionsType?.GetProperty("Item", new Type[1] { typeof(string) });
private static readonly Type? InputActionType = AccessTools.TypeByName("UnityEngine.InputSystem.InputAction");
private static readonly MethodInfo? WasPressedMethod = InputActionType?.GetMethod("WasPressedThisFrame", Type.EmptyTypes);
private static readonly MethodInfo? WasReleasedMethod = InputActionType?.GetMethod("WasReleasedThisFrame", Type.EmptyTypes);
private static readonly MethodInfo? IsPressedMethod = InputActionType?.GetMethod("IsPressed", Type.EmptyTypes);
private static readonly PropertyInfo? DhhInstanceProperty = AccessTools.Property(typeof(DHHAbilityManager), "instance");
private static readonly FieldInfo? AbilitySpotsField = AccessTools.Field(typeof(DHHAbilityManager), "abilitySpots");
private static readonly MethodInfo? HandleInputDownMethod = AccessTools.Method(typeof(DHHAbilityManager), "HandleInputDown", new Type[1] { typeof(AbilitySpot) }, (Type[])null);
private static readonly MethodInfo? HandleInputHoldMethod = AccessTools.Method(typeof(DHHAbilityManager), "HandleInputHold", new Type[1] { typeof(AbilitySpot) }, (Type[])null);
private static readonly MethodInfo? HandleInputUpMethod = AccessTools.Method(typeof(DHHAbilityManager), "HandleInputUp", new Type[1] { typeof(AbilitySpot) }, (Type[])null);
private static readonly MethodInfo? HasEquippedAbilityMethod = AccessTools.Method(typeof(DHHAbilityManager), "HasEquippedAbility", (Type[])null, (Type[])null);
private static readonly FieldInfo? BackgroundIconField = AccessTools.Field(typeof(AbilitySpot), "backgroundIcon");
internal static readonly ManualLogSource Log = Logger.CreateLogSource("DeathHeadHopperFix-VR.VanillaAbility");
internal const string ModuleTag = "[DeathHeadHopperFix-VR] [VanillaAbility]";
private static VanillaAbilityInputBridge? _instance;
private AbilitySpot? _slotDownSpot;
private object? _activeAction;
private Quaternion? _savedAvatarRotation;
private const int PrimarySlotIndex = 0;
public static void EnsureAttached(GameObject host)
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Expected O, but got Unknown
if (!((Object)(object)_instance != (Object)null))
{
GameObject val = new GameObject("DeathHeadHopperVRBridge_VanillaAbilityBridge");
Object.DontDestroyOnLoad((Object)(object)val);
val.transform.SetParent(host.transform, false);
_instance = val.AddComponent<VanillaAbilityInputBridge>();
}
}
private void Update()
{
if (!FeatureFlags.EnableVanillaAbilityBridge)
{
ReleaseAbility();
return;
}
if (!SpectateHeadBridge.IsSpectatingHead())
{
ReleaseAbility();
return;
}
if (!TryPreparePrimarySpot(out AbilitySpot[] _, out AbilitySpot primarySpot))
{
ReleaseAbility();
return;
}
bool flag = SpectateHeadBridge.IsGripPressedForAbility();
LogDebug("ListeningInputs", flag ? "Listening for the primary ability slot while DeathHeadHopper is active and the configured ability grip is held." : "Waiting for the configured ability grip before reacting to the primary ability slot.");
HandleActivation(primarySpot, flag);
}
private bool TryPreparePrimarySpot(out AbilitySpot[]? spots, out AbilitySpot? primarySpot)
{
spots = null;
primarySpot = null;
DHHAbilityManager abilityManager = GetAbilityManager();
if ((Object)(object)abilityManager == (Object)null)
{
return false;
}
if (!ManagerHasEquipped(abilityManager))
{
return false;
}
spots = GetAbilitySpots(abilityManager);
if (spots == null || spots.Length == 0)
{
return false;
}
AbilitySpot abilitySpot = GetAbilitySpot(spots, 0);
if ((Object)(object)abilitySpot == (Object)null || (Object)(object)abilitySpot.CurrentAbility == (Object)null)
{
LogDebug("PrimarySlotMissing", "Primary ability slot is empty while DeathHeadHopper is active.");
return false;
}
primarySpot = abilitySpot;
return true;
}
private void HandleActivation(AbilitySpot spot, bool allowStart)
{
string[] array = ParseActionNames(FeatureFlags.AbilityActivateAction).ToArray();
object firstAvailableAction = GetFirstAvailableAction(array);
if (firstAvailableAction == null)
{
ReleaseAbility();
LogDebug("ActivateActionMissing", "Activate action not found (" + string.Join(", ", array) + ")");
return;
}
LogDebug("ActivateActionReady", string.Format("Activate action ready ({0}). Primary slot index={1}", string.Join(", ", array), 0));
if (allowStart && WasActionPressed(firstAvailableAction))
{
LogDebug("ActivateActionTriggered", "Left stick click (L3) triggered activation for the primary slot while DeathHeadHopper is active.");
ReleaseAbility();
AlignAvatarToCamera();
InvokeAbilityMethod(HandleInputDownMethod, spot);
_slotDownSpot = spot;
_activeAction = firstAvailableAction;
LogDebug("AbilityStart", string.Format("Started primary ability slot {0} ({1})", 0, ((object)spot.CurrentAbility)?.GetType().Name ?? "none"));
}
if ((Object)(object)_slotDownSpot != (Object)null && _activeAction != null)
{
if (IsActionPressed(_activeAction))
{
InvokeAbilityMethod(HandleInputHoldMethod, _slotDownSpot);
LogDebug("AbilityHold", string.Format("Holding primary ability slot {0} ({1})", 0, ((object)_slotDownSpot.CurrentAbility)?.GetType().Name ?? "none"));
}
if (WasActionReleased(_activeAction))
{
ReleaseAbility();
}
}
}
private void ReleaseAbility()
{
if ((Object)(object)_slotDownSpot == (Object)null)
{
_activeAction = null;
return;
}
InvokeAbilityMethod(HandleInputUpMethod, _slotDownSpot);
LogDebug("AbilityRelease", $"Released primary ability slot {0}");
_slotDownSpot = null;
_activeAction = null;
RestoreAvatarAlignment();
}
private static AbilitySpot? GetAbilitySpot(AbilitySpot[] spots, int index)
{
if (spots.Length == 0)
{
return null;
}
int num = index;
if (num < 0)
{
num = 0;
}
if (num >= spots.Length)
{
num = spots.Length - 1;
}
return spots[num];
}
private void AlignAvatarToCamera()
{
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: 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_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)
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
if (_savedAvatarRotation.HasValue)
{
return;
}
PlayerAvatar instance = PlayerAvatar.instance;
if (!((Object)(object)instance == (Object)null))
{
_savedAvatarRotation = ((Component)instance).transform.rotation;
Vector3 val = DHHInputBridge.GetAbilityForward();
val = Vector3.ProjectOnPlane(val, Vector3.up);
if (!(((Vector3)(ref val)).sqrMagnitude < 0.0001f))
{
((Component)instance).transform.rotation = Quaternion.LookRotation(val, Vector3.up);
LogDebug("AbilityOrient", $"Aligned avatar forward to {val:F3}");
}
}
}
private void RestoreAvatarAlignment()
{
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
PlayerAvatar instance = PlayerAvatar.instance;
if (!((Object)(object)instance == (Object)null) && _savedAvatarRotation.HasValue)
{
((Component)instance).transform.rotation = _savedAvatarRotation.Value;
_savedAvatarRotation = null;
LogDebug("AbilityOrient", "Restored avatar rotation");
}
}
[IteratorStateMachine(typeof(<ParseActionNames>d__30))]
private static IEnumerable<string> ParseActionNames(string raw)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <ParseActionNames>d__30(-2)
{
<>3__raw = raw
};
}
private static object? GetFirstAvailableAction(IEnumerable<string> names)
{
foreach (string name in names)
{
object action = GetAction(name);
if (action != null)
{
return action;
}
}
return null;
}
private static object? GetAction(string name)
{
object obj = RepoXRActionsInstance?.GetValue(null);
if (obj == null || RepoXRActionsIndexer == null)
{
return null;
}
try
{
return RepoXRActionsIndexer.GetValue(obj, new object[1] { name });
}
catch
{
return null;
}
}
private static bool WasActionPressed(object? action)
{
return InvokeBooleanMethod(WasPressedMethod, action);
}
private static bool WasActionReleased(object? action)
{
return InvokeBooleanMethod(WasReleasedMethod, action);
}
private static bool IsActionPressed(object? action)
{
return InvokeBooleanMethod(IsPressedMethod, action);
}
private static bool InvokeBooleanMethod(MethodInfo? method, object? action)
{
if (method == null || action == null)
{
return false;
}
try
{
object obj = method.Invoke(action, Array.Empty<object>());
bool flag = default(bool);
int num;
if (obj is bool)
{
flag = (bool)obj;
num = 1;
}
else
{
num = 0;
}
return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
}
catch
{
return false;
}
}
private static DHHAbilityManager? GetAbilityManager()
{
object? obj = DhhInstanceProperty?.GetValue(null);
return (DHHAbilityManager?)((obj is DHHAbilityManager) ? obj : null);
}
private static AbilitySpot[]? GetAbilitySpots(DHHAbilityManager? manager)
{
if (AbilitySpotsField == null || (Object)(object)manager == (Object)null)
{
return null;
}
return AbilitySpotsField.GetValue(manager) as AbilitySpot[];
}
private static void InvokeAbilityMethod(MethodInfo? method, AbilitySpot spot)
{
DHHAbilityManager abilityManager = GetAbilityManager();
if (method == null || (Object)(object)abilityManager == (Object)null)
{
return;
}
try
{
method.Invoke(abilityManager, new object[1] { spot });
}
catch
{
}
}
private static bool ManagerHasEquipped(DHHAbilityManager manager)
{
if (HasEquippedAbilityMethod == null)
{
return false;
}
try
{
object obj = HasEquippedAbilityMethod.Invoke(manager, Array.Empty<object>());
bool flag = default(bool);
int num;
if (obj is bool)
{
flag = (bool)obj;
num = 1;
}
else
{
num = 0;
}
return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
}
catch
{
return false;
}
}
private void LogDebug(string key, string message, float interval = 0.5f)
{
if (FeatureFlags.DebugAbility && LogLimiter.Allow(key, interval))
{
Log.LogInfo((object)("[DeathHeadHopperFix-VR] [VanillaAbility] " + message));
}
}
private void OnDestroy()
{
_instance = null;
}
}
internal sealed class VrAbilityBarBridge : MonoBehaviour
{
private const int SlotCount = 3;
private static readonly string[] ConfirmActionNames = new string[3] { "Grab", "Interact", "Push" };
private static readonly Type? RepoXRActionsType = AccessTools.TypeByName("RepoXR.Input.Actions");
private static readonly PropertyInfo? RepoXRActionsInstance = RepoXRActionsType?.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public);
private static readonly PropertyInfo? RepoXRActionsIndexer = RepoXRActionsType?.GetProperty("Item", new Type[1] { typeof(string) });
private static readonly Type? InputActionType = AccessTools.TypeByName("UnityEngine.InputSystem.InputAction");
private static readonly MethodInfo? ReadValueGenericDefinition = InputActionType?.GetMethods().FirstOrDefault((MethodInfo m) => m.Name == "ReadValue" && m.IsGenericMethodDefinition && m.GetParameters().Length == 0);
private static readonly MethodInfo? WasPressedThisFrameMethod = InputActionType?.GetMethod("WasPressedThisFrame", Type.EmptyTypes);
private static readonly MethodInfo? WasReleasedThisFrameMethod = InputActionType?.GetMethod("WasReleasedThisFrame", Type.EmptyTypes);
private static readonly MethodInfo? IsPressedMethod = InputActionType?.GetMethod("IsPressed", Type.EmptyTypes);
private static readonly PropertyInfo? DhhInstanceProperty = AccessTools.Property(typeof(DHHAbilityManager), "instance");
private static readonly FieldInfo? SpectateCameraStateField = AccessTools.Field(typeof(SpectateCamera), "currentState");
private static readonly MethodInfo? HasEquippedAbilityMethod = AccessTools.Method(typeof(DHHAbilityManager), "HasEquippedAbility", (Type[])null, (Type[])null);
private static readonly FieldInfo? AbilitySpotsField = AccessTools.Field(typeof(DHHAbilityManager), "abilitySpots");
private static readonly MethodInfo? HandleInputDownMethod = AccessTools.Method(typeof(DHHAbilityManager), "HandleInputDown", new Type[1] { typeof(AbilitySpot) }, (Type[])null);
private static readonly MethodInfo? HandleInputHoldMethod = AccessTools.Method(typeof(DHHAbilityManager), "HandleInputHold", new Type[1] { typeof(AbilitySpot) }, (Type[])null);
private static readonly MethodInfo? HandleInputUpMethod = AccessTools.Method(typeof(DHHAbilityManager), "HandleInputUp", new Type[1] { typeof(AbilitySpot) }, (Type[])null);
private static VrAbilityBarBridge? _instance;
private readonly GameObject[] _markers = (GameObject[])(object)new GameObject[3];
private readonly Renderer[] _renderers = (Renderer[])(object)new Renderer[3];
private readonly Material[] _materials = (Material[])(object)new Material[3];
private int _selectedSlot = 1;
private int _slotDown = -1;
private bool _visible;
public static void EnsureAttached(GameObject host)
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Expected O, but got Unknown
if (!((Object)(object)_instance != (Object)null))
{
GameObject val = new GameObject("DeathHeadHopperVRBridge_VrAbilityBridge");
Object.DontDestroyOnLoad((Object)(object)val);
val.transform.SetParent(host.transform, false);
_instance = val.AddComponent<VrAbilityBarBridge>();
}
}
private void Awake()
{
for (int i = 0; i < 3; i++)
{
_markers[i] = CreateMarker($"AbilitySlot{i}");
_renderers[i] = _markers[i].GetComponent<Renderer>();
_materials[i] = _renderers[i].material;
_renderers[i].enabled = false;
}
}
private void Update()
{
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: Invalid comparison between Unknown and I4
SpectateCamera instance = SpectateCamera.instance;
DHHAbilityManager abilityManager = GetAbilityManager();
if ((Object)(object)instance == (Object)null || (Object)(object)abilityManager == (Object)null)
{
SetMarkersVisible(visible: false);
ReleaseAbility();
return;
}
if ((int)GetSpectateState().GetValueOrDefault() != 2 || !ManagerHasEquipped(abilityManager))
{
SetMarkersVisible(visible: false);
ReleaseAbility();
return;
}
bool flag = SpectateHeadBridge.IsGripPressedForAbility();
SetMarkersVisible(flag);
if (!flag)
{
ReleaseAbility();
return;
}
UpdateSelection(ReadTurnValue());
if (_visible)
{
UpdateMarkerVisuals();
PositionMarkers(((Component)instance).transform);
}
object firstAvailableAction = GetFirstAvailableAction(ConfirmActionNames);
TryStartAbility(firstAvailableAction);
if (_slotDown != -1)
{
if (firstAvailableAction != null && IsActionPressed(firstAvailableAction))
{
MaintainAbilityHold();
}
if (firstAvailableAction == null || WasActionReleased(firstAvailableAction))
{
ReleaseAbility();
}
}
}
private GameObject CreateMarker(string name)
{
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_007e: Unknown result type (might be due to invalid IL or missing references)
//IL_0089: Unknown result type (might be due to invalid IL or missing references)
//IL_0097: Expected O, but got Unknown
GameObject val = GameObject.CreatePrimitive((PrimitiveType)3);
((Object)val).name = name;
((Object)val).hideFlags = (HideFlags)61;
Collider component = val.GetComponent<Collider>();
if ((Object)(object)component != (Object)null)
{
Object.Destroy((Object)(object)component);
}
Renderer component2 = val.GetComponent<Renderer>();
component2.shadowCastingMode = (ShadowCastingMode)0;
component2.receiveShadows = false;
component2.material = new Material(Shader.Find("Unlit/Color") ?? Shader.Find("Standard"))
{
color = new Color(0.08f, 0.45f, 0.9f, 0.35f),
hideFlags = (HideFlags)61
};
return val;
}
private void PositionMarkers(Transform cameraTransform)
{
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: 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_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: 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_0063: Unknown result type (might be due to invalid IL or missing references)
//IL_0072: Unknown result type (might be due to invalid IL or missing references)
//IL_0077: Unknown result type (might be due to invalid IL or missing references)
//IL_008a: Unknown result type (might be due to invalid IL or missing references)
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
if (_visible)
{
Vector3 val = cameraTransform.position + cameraTransform.forward * FeatureFlags.AbilityCursorDistance + Vector3.up * FeatureFlags.AbilityCursorVerticalOffset;
Quaternion val2 = Quaternion.LookRotation(cameraTransform.forward, Vector3.up);
for (int i = 0; i < 3; i++)
{
Vector3 val3 = val2 * Vector3.right * ((float)(i - 1) * FeatureFlags.AbilityCursorSpacing);
GameObject val4 = _markers[i];
val4.transform.position = val + val3;
val4.transform.rotation = val2;
float num = FeatureFlags.AbilityCursorScale * ((i == _selectedSlot) ? 1.45f : 1f);
val4.transform.localScale = Vector3.one * num;
}
}
}
private void SetMarkersVisible(bool visible)
{
if (_visible != visible)
{
_visible = visible;
for (int i = 0; i < 3; i++)
{
_renderers[i].enabled = visible;
}
}
}
private void UpdateSelection(float turnValue)
{
if (turnValue < 0f - FeatureFlags.AbilitySelectionDeadzone)
{
_selectedSlot = 0;
}
else if (turnValue > FeatureFlags.AbilitySelectionDeadzone)
{
_selectedSlot = 2;
}
else
{
_selectedSlot = 1;
}
}
private void UpdateMarkerVisuals()
{
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
if (_visible)
{
Color val = default(Color);
((Color)(ref val))..ctor(0.08f, 0.45f, 0.9f, 0.35f);
Color val2 = default(Color);
((Color)(ref val2))..ctor(1f, 0.85f, 0.25f, 0.95f);
for (int i = 0; i < 3; i++)
{
_materials[i].color = ((i == _selectedSlot) ? val2 : val);
}
}
}
private void TryStartAbility(object? confirmAction)
{
if (confirmAction != null && WasActionPressed(confirmAction))
{
ReleaseAbility();
AbilitySpot abilitySpot = GetAbilitySpot(_selectedSlot);
if (!((Object)(object)abilitySpot == (Object)null) && !((Object)(object)abilitySpot.CurrentAbility == (Object)null))
{
InvokeAbilityMethod(HandleInputDownMethod, abilitySpot);
_slotDown = _selectedSlot;
}
}
}
private void MaintainAbilityHold()
{
if (_slotDown != -1)
{
AbilitySpot abilitySpot = GetAbilitySpot(_slotDown);
if ((Object)(object)abilitySpot == (Object)null)
{
_slotDown = -1;
}
else
{
InvokeAbilityMethod(HandleInputHoldMethod, abilitySpot);
}
}
}
private void ReleaseAbility()
{
if (_slotDown != -1)
{
AbilitySpot abilitySpot = GetAbilitySpot(_slotDown);
if ((Object)(object)abilitySpot != (Object)null)
{
InvokeAbilityMethod(HandleInputUpMethod, abilitySpot);
}
_slotDown = -1;
}
}
private AbilitySpot? GetAbilitySpot(int index)
{
DHHAbilityManager abilityManager = GetAbilityManager();
if (AbilitySpotsField == null || (Object)(object)abilityManager == (Object)null)
{
return null;
}
if (!(AbilitySpotsField.GetValue(abilityManager) is AbilitySpot[] array) || index < 0 || index >= array.Length)
{
return null;
}
return array[index];
}
private object? GetFirstAvailableAction(string[] names)
{
foreach (string name in names)
{
object action = GetAction(name);
if (action != null)
{
return action;
}
}
return null;
}
private static object? GetAction(string name)
{
object obj = RepoXRActionsInstance?.GetValue(null);
if (obj == null || RepoXRActionsIndexer == null)
{
return null;
}
try
{
return RepoXRActionsIndexer.GetValue(obj, new object[1] { name });
}
catch
{
return null;
}
}
private static bool IsActionPressed(object? action)
{
return InvokeBooleanMethod(IsPressedMethod, action);
}
private static bool WasActionPressed(object? action)
{
return InvokeBooleanMethod(WasPressedThisFrameMethod, action);
}
private static bool WasActionReleased(object? action)
{
return InvokeBooleanMethod(WasReleasedThisFrameMethod, action);
}
private float ReadTurnValue()
{
return ReadFloat(GetAction("Turn"));
}
private static float ReadFloat(object? action)
{
if (action == null || ReadValueGenericDefinition == null)
{
return 0f;
}
try
{
MethodInfo methodInfo = ReadValueGenericDefinition.MakeGenericMethod(typeof(float));
return (methodInfo.Invoke(action, Array.Empty<object>()) is float num) ? num : 0f;
}
catch
{
return 0f;
}
}
private static bool InvokeBooleanMethod(MethodInfo? method, object? action)
{
if (method == null || action == null)
{
return false;
}
try
{
object obj = method.Invoke(action, Array.Empty<object>());
bool flag = default(bool);
int num;
if (obj is bool)
{
flag = (bool)obj;
num = 1;
}
else
{
num = 0;
}
return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
}
catch
{
return false;
}
}
private static void InvokeAbilityMethod(MethodInfo? method, AbilitySpot spot)
{
DHHAbilityManager abilityManager = GetAbilityManager();
if (method == null || (Object)(object)abilityManager == (Object)null)
{
return;
}
try
{
method.Invoke(abilityManager, new object[1] { spot });
}
catch
{
}
}
private static DHHAbilityManager? GetAbilityManager()
{
object? obj = DhhInstanceProperty?.GetValue(null);
return (DHHAbilityManager?)((obj is DHHAbilityManager) ? obj : null);
}
private static State? GetSpectateState()
{
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
//IL_004b: 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)
SpectateCamera instance = SpectateCamera.instance;
if ((Object)(object)instance == (Object)null || SpectateCameraStateField == null)
{
return null;
}
return (SpectateCameraStateField.GetValue(instance) is State value) ? new State?(value) : null;
}
private static bool ManagerHasEquipped(DHHAbilityManager manager)
{
if (HasEquippedAbilityMethod == null)
{
return false;
}
try
{
object obj = HasEquippedAbilityMethod.Invoke(manager, Array.Empty<object>());
bool flag = default(bool);
int num;
if (obj is bool)
{
flag = (bool)obj;
num = 1;
}
else
{
num = 0;
}
return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
}
catch
{
return false;
}
}
private void OnDestroy()
{
GameObject[] markers = _markers;
foreach (GameObject val in markers)
{
if ((Object)(object)val != (Object)null)
{
Object.Destroy((Object)(object)val);
}
}
Material[] materials = _materials;
foreach (Material val2 in materials)
{
if ((Object)(object)val2 != (Object)null)
{
Object.Destroy((Object)(object)val2);
}
}
_instance = null;
}
}
}
namespace DeathHeadHopperVRBridge.Modules.Logging
{
internal static class LogLimiter
{
private static readonly Dictionary<string, float> _next = new Dictionary<string, float>();
internal static bool Allow(string key, float everySeconds)
{
float realtimeSinceStartup = Time.realtimeSinceStartup;
if (_next.TryGetValue(key, out var value) && realtimeSinceStartup < value)
{
return false;
}
_next[key] = realtimeSinceStartup + everySeconds;
return true;
}
}
}
namespace DeathHeadHopperVRBridge.Modules.Config
{
[AttributeUsage(AttributeTargets.Field)]
internal sealed class FeatureConfigEntryAttribute : Attribute
{
public string Section { get; }
public string Description { get; }
public string Key { get; set; } = string.Empty;
public float Min { get; set; } = float.NaN;
public float Max { get; set; } = float.NaN;
public float Step { get; set; } = float.NaN;
public string[] AcceptableValues { get; set; } = Array.Empty<string>();
public bool HasRange => !float.IsNaN(Min) && !float.IsNaN(Max);
public FeatureConfigEntryAttribute(string section, string description)
{
Section = section;
Description = description;
}
}
internal static class ConfigManager
{
private struct RangeF
{
public float Min;
public float Max;
public float Step;
}
private struct RangeI
{
public int Min;
public int Max;
public int Step;
}
private static bool s_initialized;
private static readonly char[] ColorSeparators = new char[2] { ',', ';' };
private static readonly Dictionary<string, RangeF> s_floatRanges = new Dictionary<string, RangeF>(StringComparer.Ordinal);
private static readonly Dictionary<string, RangeI> s_intRanges = new Dictionary<string, RangeI>(StringComparer.Ordinal);
internal static void Initialize(ConfigFile config)
{
if (!s_initialized && config != null)
{
s_initialized = true;
BindConfigEntries(config, typeof(FeatureFlags), "General");
}
}
private static void BindConfigEntries(ConfigFile config, Type targetType, string defaultSection)
{
//IL_0151: Unknown result type (might be due to invalid IL or missing references)
//IL_015b: Expected O, but got Unknown
//IL_021e: Unknown result type (might be due to invalid IL or missing references)
//IL_0228: Expected O, but got Unknown
//IL_0307: Unknown result type (might be due to invalid IL or missing references)
//IL_030c: Unknown result type (might be due to invalid IL or missing references)
//IL_0313: Unknown result type (might be due to invalid IL or missing references)
FieldInfo[] fields = targetType.GetFields(BindingFlags.Static | BindingFlags.Public);
foreach (FieldInfo field in fields)
{
FeatureConfigEntryAttribute customAttribute = field.GetCustomAttribute<FeatureConfigEntryAttribute>();
if (customAttribute == null)
{
continue;
}
string text = (string.IsNullOrWhiteSpace(customAttribute.Section) ? defaultSection : customAttribute.Section);
string text2 = (string.IsNullOrWhiteSpace(customAttribute.Key) ? field.Name : customAttribute.Key);
string text3 = customAttribute.Description ?? string.Empty;
if (field.FieldType == typeof(bool))
{
bool flag = (bool)field.GetValue(null);
ConfigEntry<bool> entry = config.Bind<bool>(text, text2, flag, text3);
ApplyAndWatch(entry, delegate(bool value)
{
field.SetValue(null, value);
});
}
else if (field.FieldType == typeof(int))
{
int num = (int)field.GetValue(null);
ConfigEntry<int> entry2;
if (customAttribute.HasRange)
{
int intRangeStart = GetIntRangeStart(customAttribute);
int intRangeEnd = GetIntRangeEnd(customAttribute);
entry2 = config.Bind<int>(text, text2, num, new ConfigDescription(text3, (AcceptableValueBase)(object)new AcceptableValueRange<int>(intRangeStart, intRangeEnd), Array.Empty<object>()));
RegisterIntRange(text2, intRangeStart, intRangeEnd, DetermineIntStep(customAttribute));
}
else
{
entry2 = config.Bind<int>(text, text2, num, text3);
}
ApplyAndWatch(entry2, delegate(int value)
{
field.SetValue(null, value);
});
}
else if (field.FieldType == typeof(float))
{
float num2 = (float)field.GetValue(null);
ConfigEntry<float> entry3;
if (customAttribute.HasRange)
{
float num3 = System.Math.Min(customAttribute.Min, customAttribute.Max);
float num4 = System.Math.Max(customAttribute.Min, customAttribute.Max);
entry3 = config.Bind<float>(text, text2, num2, new ConfigDescription(text3, (AcceptableValueBase)(object)new AcceptableValueRange<float>(num3, num4), Array.Empty<object>()));
RegisterFloatRange(text2, num3, num4, DetermineFloatStep(customAttribute, num3));
}
else
{
entry3 = config.Bind<float>(text, text2, num2, text3);
}
ApplyAndWatch(entry3, delegate(float value)
{
field.SetValue(null, value);
});
}
else if (field.FieldType == typeof(string))
{
string text4 = (field.GetValue(null) as string) ?? string.Empty;
ConfigEntry<string> entry4 = config.Bind<string>(text, text2, text4, BuildStringDescription(text3, customAttribute.AcceptableValues));
ApplyAndWatch(entry4, delegate(string value)
{
field.SetValue(null, value);
});
}
else if (field.FieldType == typeof(Color))
{
Color input = (Color)field.GetValue(null);
ConfigEntry<string> entry5 = config.Bind<string>(text, text2, ColorToString(input), text3);
ApplyAndWatch(entry5, ColorFromString, delegate(Color value)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
field.SetValue(null, value);
});
}
}
}
private static int GetIntRangeStart(FeatureConfigEntryAttribute attribute)
{
ValidateIntegerRange(attribute);
return (int)System.Math.Min(attribute.Min, attribute.Max);
}
private static int GetIntRangeEnd(FeatureConfigEntryAttribute attribute)
{
ValidateIntegerRange(attribute);
return (int)System.Math.Max(attribute.Min, attribute.Max);
}
private static void ValidateIntegerRange(FeatureConfigEntryAttribute attribute)
{
if (!IsWholeNumber(attribute.Min) || !IsWholeNumber(attribute.Max))
{
throw new InvalidOperationException("FeatureConfigEntryAttribute integer range values must be whole numbers.");
}
}
private static bool IsWholeNumber(float value)
{
double num = System.Math.Truncate(value);
return System.Math.Abs((double)value - num) < 1.401298464324817E-45;
}
private static void ApplyAndWatch<T>(ConfigEntry<T> entry, Action<T> setter)
{
Action<T> setter2 = setter;
ConfigEntry<T> entry2 = entry;
if (entry2 != null && setter2 != null)
{
Update();
entry2.SettingChanged += delegate
{
Update();
};
}
void Update()
{
setter2(SanitizeValue(entry2.Value, ((ConfigEntryBase)entry2).Definition.Key));
}
}
private static void ApplyAndWatch(ConfigEntry<string> entry, Func<string, Color> parser, Action<Color> setter)
{
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
Action<Color> setter2 = setter;
Func<string, Color> parser2 = parser;
ConfigEntry<string> entry2 = entry;
if (entry2 != null && parser2 != null && setter2 != null)
{
setter2(parser2(entry2.Value));
entry2.SettingChanged += delegate
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
setter2(parser2(entry2.Value));
};
}
}
private static string ColorToString(Color input)
{
return string.Join(",", input.r.ToString(CultureInfo.InvariantCulture), input.g.ToString(CultureInfo.InvariantCulture), input.b.ToString(CultureInfo.InvariantCulture), input.a.ToString(CultureInfo.InvariantCulture));
}
private static Color ColorFromString(string input)
{
//IL_000e: 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_007f: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_0088: Unknown result type (might be due to invalid IL or missing references)
if (string.IsNullOrWhiteSpace(input))
{
return Color.black;
}
string[] array = input.Split(ColorSeparators, StringSplitOptions.RemoveEmptyEntries);
if (array.Length == 0)
{
return Color.black;
}
float slot = 0f;
float slot2 = 0f;
float slot3 = 0f;
float slot4 = 1f;
TryParseComponent(array, 0, ref slot);
TryParseComponent(array, 1, ref slot2);
TryParseComponent(array, 2, ref slot3);
TryParseComponent(array, 3, ref slot4);
return new Color(slot, slot2, slot3, slot4);
}
private static void TryParseComponent(string[] segments, int index, ref float slot)
{
if (index < segments.Length)
{
string s = segments[index].Trim();
if (float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
{
slot = result;
}
}
}
private static T SanitizeValue<T>(T value, string key)
{
if (value is float)
{
object obj = value;
float val = (float)((obj is float) ? obj : null);
if (s_floatRanges.TryGetValue(key, out var value2))
{
float num = System.Math.Min(value2.Max, System.Math.Max(value2.Min, val));
if (value2.Step > 0f)
{
num = SnapFloatToStep(num, value2.Min, value2.Step);
num = System.Math.Min(value2.Max, System.Math.Max(value2.Min, num));
}
return (T)(object)num;
}
}
if (value is int)
{
object obj2 = value;
int val2 = (int)((obj2 is int) ? obj2 : null);
if (s_intRanges.TryGetValue(key, out var value3))
{
int num2 = System.Math.Min(value3.Max, System.Math.Max(value3.Min, val2));
if (value3.Step > 0)
{
num2 = SnapIntToStep(num2, value3.Min, value3.Step);
num2 = System.Math.Min(value3.Max, System.Math.Max(value3.Min, num2));
}
return (T)(object)num2;
}
}
return value;
}
private static ConfigDescription BuildStringDescription(string description, string[] acceptableValues)
{
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Expected O, but got Unknown
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Expected O, but got Unknown
if (acceptableValues == null || acceptableValues.Length == 0)
{
return new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>());
}
return new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueList<string>(acceptableValues), Array.Empty<object>());
}
private static int DetermineIntStep(FeatureConfigEntryAttribute attribute)
{
if (!float.IsNaN(attribute.Step) && attribute.Step >= 1f)
{
return System.Math.Max(1, (int)System.Math.Round(attribute.Step));
}
return 1;
}
private static float DetermineFloatStep(FeatureConfigEntryAttribute attribute, float minValue)
{
if (!float.IsNaN(attribute.Step) && attribute.Step > 0f)
{
return attribute.Step;
}
return DetermineDefaultFloatStep(minValue);
}
private static float DetermineDefaultFloatStep(float minValue)
{
float num = System.Math.Abs(minValue);
if (num <= 0f)
{
return 0.1f;
}
double y = System.Math.Floor(System.Math.Log10(num));
return (float)System.Math.Pow(10.0, y);
}
private static void RegisterFloatRange(string key, float min, float max, float step)
{
s_floatRanges[key] = new RangeF
{
Min = min,
Max = max,
Step = step
};
}
private static void RegisterIntRange(string key, int min, int max, int step)
{
s_intRanges[key] = new RangeI
{
Min = min,
Max = max,
Step = step
};
}
private static float SnapFloatToStep(float value, float min, float step)
{
if (step <= 0f)
{
return value;
}
float num = (value - min) / step;
double num2 = System.Math.Round(num, MidpointRounding.AwayFromZero);
return min + (float)num2 * step;
}
private static int SnapIntToStep(int value, int min, int step)
{
if (step <= 0)
{
return value;
}
double value2 = (double)(value - min) / (double)step;
int num = (int)System.Math.Round(value2, MidpointRounding.AwayFromZero);
return min + num * step;
}
}
internal static class FeatureFlags
{
[FeatureConfigEntry("Spectate Movement", "Defines the forward vector used to rotate jump direction; Controller uses the tracked left-hand controller, Head uses the HMD.", AcceptableValues = new string[] { "Controller", "Head" })]
public static string MovementDirectionSource = "Controller";
[FeatureConfigEntry("Spectate Camera", "Distance that the spectator camera stays behind the death head.", Min = 0.05f, Max = 1.5f)]
public static float HeadCameraDistance = 0.45f;
[FeatureConfigEntry("Spectate Camera", "Vertical offset applied to the death head when aligning the camera.", Min = -0.2f, Max = 1.5f)]
public static float HeadCameraHeightOffset = 0.5f;
[FeatureConfigEntry("Spectate Camera", "How fast the spectator camera lerps back to the default position.", Min = 1f, Max = 12f)]
public static float HeadCameraLerpSpeed = 8f;
[FeatureConfigEntry("Spectate VR Ability", "Defines which forward vector is used to aim DeathHeadHopper abilities; Controller uses the tracked hand, Head uses the HMD.", AcceptableValues = new string[] { "Controller", "Head" })]
public static string AbilityDirectionSource = "Controller";
[FeatureConfigEntry("Spectate VR Ability", "Hand used to hold the grip that activates the spectate ability cursor. Valid values: Auto (opposite the selected main hand in RepoXR), Left, Right.", AcceptableValues = new string[] { "Auto", "Left", "Right" })]
public static string AbilityGripPreference = "Auto";
[FeatureConfigEntry("Spectate VR Ability", "Action name (or semicolon-separated fallback names) used to activate the selected slot.")]
public static string AbilityActivateAction = "VR Actions/ResetHeight";
[FeatureConfigEntry("Spectate VR Ability", "Distance in meters at which the VR ability cursor floats in front of the view.", Min = 0.2f, Max = 2f)]
public static float AbilityCursorDistance = 0.6f;
[FeatureConfigEntry("Spectate VR Ability", "Vertical offset applied to the ability cursor relative to the view origin.", Min = -1f, Max = 1f)]
public static float AbilityCursorVerticalOffset = -0.25f;
[FeatureConfigEntry("Spectate VR Ability", "Horizontal spacing between the ability markers.", Min = 0.1f, Max = 1f)]
public static float AbilityCursorSpacing = 0.35f;
[FeatureConfigEntry("Spectate VR Ability", "Base scale applied to the ability markers.", Min = 0.04f, Max = 0.5f)]
public static float AbilityCursorScale = 0.15f;
[FeatureConfigEntry("Spectate VR Ability", "Deadzone applied to the right stick before changing the selected slot.", Min = 0f, Max = 0.7f)]
public static float AbilitySelectionDeadzone = 0.25f;
[FeatureConfigEntry("Spectate VR Ability", "Enable verbose logging for the vanilla ability bridge (rate-limited).")]
public static bool DebugAbility = false;
public static bool EnableVanillaAbilityBridge = true;
public static bool DebugSpectateGuard = false;
public static bool DebugMovementDirection = false;
public static bool LogControllerOrientation = false;
public static bool DebugHeadAlignment = false;
[FeatureConfigEntry("Spectate Movement", "Hand used to hold the grip that controls camera look/movement while spectating. Valid values: Auto (opposite the selected main hand in RepoXR), Left, Right.", AcceptableValues = new string[] { "Auto", "Left", "Right" })]
public static string CameraGripPreference = "Auto";
[FeatureConfigEntry("Spectate Movement", "When true, scale the jump direction by the analog stick magnitude instead of always normalizing to 1.")]
public static bool UseAnalogMagnitude = true;
}
}