using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FistVR;
using HarmonyLib;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ClipSlap")]
[assembly: AssemblyDescription("Allows players to slap away empty clips from firearms")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("BitWizrd")]
[assembly: AssemblyProduct("ClipSlap")]
[assembly: AssemblyCopyright("Copyright © BitWizrd 2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("B1C2D3E4-F5A6-4B5C-8D7E-9F0A1B2C3D4E")]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace BitWizrd.ClipSlapAkimbo;
[BepInPlugin("BitWizrd.ClipSlapAkimbo", "ClipSlapAkimbo", "1.0.0")]
[BepInProcess("h3vr.exe")]
public class ClipSlap : BaseUnityPlugin
{
public class FirearmClipSlapDetector : MonoBehaviour
{
private FVRFireArm firearm;
public void Awake()
{
firearm = ((Component)this).GetComponent<FVRFireArm>();
}
public void OnCollisionEnter(Collision collision)
{
if (!((Object)(object)firearm != (Object)null) || !((FVRInteractiveObject)firearm).IsHeld || IsControllerObject(collision.collider) || collision.transform.IsChildOf(((Component)firearm).transform))
{
return;
}
if (validClipTriggers.TryGetValue(collision.collider, out var _))
{
if (configEnableDebugLogging.Value)
{
Logger.LogInfo((object)("Found registered clip trigger " + ((Object)collision.collider).name + " through direct collision"));
}
CheckForFirearmClipSlap(firearm, collision.collider);
return;
}
foreach (KeyValuePair<Collider, FVRFireArmClip> validClipTrigger in validClipTriggers)
{
if (((Component)validClipTrigger.Key).transform.IsChildOf(collision.transform))
{
if (configEnableDebugLogging.Value)
{
Logger.LogInfo((object)("Found registered clip trigger " + ((Object)validClipTrigger.Key).name + " through physical collision with " + ((Object)collision.collider).name));
}
CheckForFirearmClipSlap(firearm, validClipTrigger.Key);
break;
}
}
}
private bool IsControllerObject(Collider collider)
{
if ((Object)(object)collider == (Object)null)
{
return false;
}
string name = ((Object)collider).name;
if (!name.Contains("Controller") && !name.Equals("Controller (right)") && !name.Equals("Controller (left)") && !name.Contains("Hand"))
{
return name.Contains("Tracker");
}
return true;
}
}
public class InteractiveObjectClipSlapDetector : MonoBehaviour
{
private FVRInteractiveObject interactiveObject;
public void Awake()
{
interactiveObject = ((Component)this).GetComponent<FVRInteractiveObject>();
}
public void OnCollisionEnter(Collision collision)
{
if (!((Object)(object)interactiveObject != (Object)null) || !interactiveObject.IsHeld || IsControllerObject(collision.collider) || collision.transform.IsChildOf(((Component)interactiveObject).transform))
{
return;
}
if (validClipTriggers.TryGetValue(collision.collider, out var _))
{
if (configEnableDebugLogging.Value)
{
Logger.LogInfo((object)("InteractiveObject " + ((Object)interactiveObject).name + " found registered clip trigger " + ((Object)collision.collider).name + " through direct collision"));
}
CheckForInteractiveObjectClipSlap(interactiveObject, collision.collider);
return;
}
foreach (KeyValuePair<Collider, FVRFireArmClip> validClipTrigger in validClipTriggers)
{
if (((Component)validClipTrigger.Key).transform.IsChildOf(collision.transform))
{
if (configEnableDebugLogging.Value)
{
Logger.LogInfo((object)("InteractiveObject " + ((Object)interactiveObject).name + " found registered clip trigger " + ((Object)validClipTrigger.Key).name + " through physical collision with " + ((Object)collision.collider).name));
}
CheckForInteractiveObjectClipSlap(interactiveObject, validClipTrigger.Key);
break;
}
}
}
private bool IsControllerObject(Collider collider)
{
if ((Object)(object)collider == (Object)null)
{
return false;
}
string name = ((Object)collider).name;
if (!name.Contains("Controller") && !name.Equals("Controller (right)") && !name.Equals("Controller (left)") && !name.Contains("Hand"))
{
return name.Contains("Tracker");
}
return true;
}
}
private class HandStates
{
public FVRViveHand LeftHand;
public FVRViveHand RightHand;
public FVRFireArm LeftFirearm;
public FVRFireArm RightFirearm;
}
private class ColliderPair
{
public BoxCollider SolidCollider;
public BoxCollider TriggerCollider;
}
internal static ManualLogSource Logger;
public static ConfigEntry<float> configSlapForce;
public static ConfigEntry<float> configSlapForceFullClip;
public static ConfigEntry<float> configSlapThreshold;
public static ConfigEntry<bool> configEnableDebugLogging;
public static ConfigEntry<bool> configRequireEmptyClip;
private const float CLIP_REATTACHMENT_COOLDOWN = 1f;
public static ConfigEntry<bool> configAutoBoltRelease;
public static ConfigEntry<bool> configAllowFirearmsToSlap;
public static ConfigEntry<bool> configAutoLoadClipsFromQuickbelt;
public static ConfigEntry<bool> configRequireSpawnlockedQuickbelt;
public static ConfigEntry<bool> configAllowLoadingWithOneFirearm;
public static ConfigEntry<bool> configFirearmsCanPushDownClipRounds;
public static ConfigEntry<bool> configClipsCanPressOtherClips;
public static ConfigEntry<bool> configAllowInteractiveObjectsToSlap;
public static ConfigEntry<bool> configInteractiveObjectsCanPushDownClipRounds;
private Harmony harmony;
private static readonly string HarmonyID = "BitWizrd.ClipSlapAkimbo";
private static Dictionary<FVRFireArmClip, float> recentlySlappedClips = new Dictionary<FVRFireArmClip, float>();
private static Dictionary<FVRFireArmClip, float> activeBulletPushOperations = new Dictionary<FVRFireArmClip, float>();
private static float bulletPushOperationDuration = 0.2f;
private static List<FVRFireArmClip> updateClipsToRemove = new List<FVRFireArmClip>();
private static List<int> idsToRemoveFromRegistration = new List<int>();
private static List<Collider> collidersToUnregister = new List<Collider>();
private static List<Collider> invalidCollidersToClean = new List<Collider>();
private static List<Transform> invalidTransformsToClean = new List<Transform>();
private static List<Rigidbody> invalidRigidbodiesToClean = new List<Rigidbody>();
private static List<Collider> collidersToStoreForDualWield = new List<Collider>();
private static StringBuilder stringBuilder = new StringBuilder(32);
private static Dictionary<Transform, FVRFireArmClip> transformToClipCache = new Dictionary<Transform, FVRFireArmClip>();
private static Dictionary<Rigidbody, FVRFireArmClip> rigidbodyToClipCache = new Dictionary<Rigidbody, FVRFireArmClip>();
private static Dictionary<int, FVRFireArmClip> validClipIDs = new Dictionary<int, FVRFireArmClip>();
private static Dictionary<FVRFireArmClip, int> clipToIdCache = new Dictionary<FVRFireArmClip, int>();
private static int nextClipID = 1000;
private static bool isDualWielding = false;
private static Dictionary<Collider, int> originalColliderLayers = new Dictionary<Collider, int>();
private static Dictionary<FVRFireArmClip, List<Collider>> trackedClipColliders = new Dictionary<FVRFireArmClip, List<Collider>>();
private static Dictionary<Collider, FVRFireArmClip> colliderToClipCache = new Dictionary<Collider, FVRFireArmClip>();
private static HashSet<FVRFireArmClip> activeInteractionClips = new HashSet<FVRFireArmClip>();
private static Dictionary<FVRFireArm, HashSet<FVRFireArmClip>> firearmActiveClips = new Dictionary<FVRFireArm, HashSet<FVRFireArmClip>>();
private static bool hasLoggedInitialState = false;
private static Dictionary<Collider, FVRFireArmClip> validClipTriggers = new Dictionary<Collider, FVRFireArmClip>();
public static int GetClipID(FVRFireArmClip clip)
{
if ((Object)(object)clip == (Object)null)
{
return 0;
}
if (clipToIdCache.TryGetValue(clip, out var value))
{
return value;
}
return 0;
}
public static int RegisterClipForSlapping(FVRFireArmClip clip)
{
if ((Object)(object)clip == (Object)null)
{
return 0;
}
if (clipToIdCache.TryGetValue(clip, out var value))
{
return value;
}
int num = nextClipID++;
validClipIDs[num] = clip;
clipToIdCache[clip] = num;
if (configEnableDebugLogging.Value)
{
Logger.LogInfo((object)$"Registered clip {((Object)clip).name} with ID {num} for slapping authorization");
}
return num;
}
public static void UnregisterClipForSlapping(int clipID)
{
if (validClipIDs.TryGetValue(clipID, out var value))
{
if ((Object)(object)value != (Object)null)
{
clipToIdCache.Remove(value);
}
validClipIDs.Remove(clipID);
if (configEnableDebugLogging.Value)
{
Logger.LogInfo((object)string.Format("Unregistered clip {0} with ID {1} from slapping authorization", ((value != null) ? ((Object)value).name : null) ?? "null", clipID));
}
}
}
public static void UnregisterClipForSlapping(FVRFireArmClip clip)
{
if (!((Object)(object)clip == (Object)null) && clipToIdCache.TryGetValue(clip, out var value))
{
validClipIDs.Remove(value);
clipToIdCache.Remove(clip);
if (configEnableDebugLogging.Value)
{
Logger.LogInfo((object)$"Unregistered clip {((Object)clip).name} with ID {value} from slapping authorization");
}
}
}
public static bool IsDualWielding()
{
return isDualWielding;
}
private static void CleanupColliderCache()
{
invalidCollidersToClean.Clear();
invalidTransformsToClean.Clear();
invalidRigidbodiesToClean.Clear();
int num = 0;
int num2 = 0;
foreach (KeyValuePair<Collider, FVRFireArmClip> item in colliderToClipCache)
{
Collider key = item.Key;
FVRFireArmClip value = item.Value;
if ((Object)(object)key == (Object)null || (Object)(object)value == (Object)null || (Object)(object)((Component)value).gameObject == (Object)null)
{
invalidCollidersToClean.Add(key);
}
else
{
num++;
}
}
foreach (KeyValuePair<Transform, FVRFireArmClip> item2 in transformToClipCache)
{
Transform key2 = item2.Key;
FVRFireArmClip value2 = item2.Value;
if ((Object)(object)key2 == (Object)null || (Object)(object)value2 == (Object)null || (Object)(object)((Component)value2).gameObject == (Object)null)
{
invalidTransformsToClean.Add(key2);
}
}
foreach (KeyValuePair<Rigidbody, FVRFireArmClip> item3 in rigidbodyToClipCache)
{
Rigidbody key3 = item3.Key;
FVRFireArmClip value3 = item3.Value;
if ((Object)(object)key3 == (Object)null || (Object)(object)value3 == (Object)null || (Object)(object)((Component)value3).gameObject == (Object)null)
{
invalidRigidbodiesToClean.Add(key3);
}
}
foreach (Collider item4 in invalidCollidersToClean)
{
colliderToClipCache.Remove(item4);
num2++;
}
foreach (Transform item5 in invalidTransformsToClean)
{
transformToClipCache.Remove(item5);
num2++;
}
foreach (Rigidbody item6 in invalidRigidbodiesToClean)
{
rigidbodyToClipCache.Remove(item6);
num2++;
}
if (configEnableDebugLogging.Value && num2 > 0)
{
Logger.LogInfo((object)$"Cleaned up {num2} invalid cache entries, kept {num} valid collider entries");
}
}
public static void RemoveClipFromCache(FVRFireArmClip clip)
{
if ((Object)(object)clip == (Object)null)
{
return;
}
if ((Object)(object)((Component)clip).gameObject == (Object)null)
{
List<Collider> list = new List<Collider>();
foreach (KeyValuePair<Collider, FVRFireArmClip> item in colliderToClipCache)
{
if ((Object)(object)item.Value == (Object)(object)clip)
{
list.Add(item.Key);
}
}
foreach (Collider item2 in list)
{
colliderToClipCache.Remove(item2);
}
if (configEnableDebugLogging.Value && list.Count > 0)
{
Logger.LogInfo((object)$"Removed {list.Count} cache entries for destroyed clip {((Object)clip).name}");
}
}
else if (configEnableDebugLogging.Value)
{
Logger.LogInfo((object)("Skipped cache removal for active clip " + ((Object)clip).name + " - keeping cache entries for future use"));
}
}
private void Awake()
{
//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
//IL_01e7: Expected O, but got Unknown
Logger = ((BaseUnityPlugin)this).Logger;
configSlapForce = ((BaseUnityPlugin)this).Config.Bind<float>("Settings", "Slap Force Multiplier", 1.75f, "Multiplier for the force applied to the clip when slapped (for empty clips)");
configSlapForceFullClip = ((BaseUnityPlugin)this).Config.Bind<float>("Settings", "Full Clip Slap Force", 0.75f, "Multiplier for the force applied to the clip when slapped (for full clips)");
configSlapThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("Settings", "Slap Velocity Threshold", 1.75f, "Minimum velocity required to slap a clip");
configRequireEmptyClip = ((BaseUnityPlugin)this).Config.Bind<bool>("Settings", "Require Empty Clip", false, "If true, clips can only be slapped out when empty. If false, any clip can be slapped out with force based on how full it is.");
configEnableDebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Settings", "Enable Debug Logging", false, "If true, enables debug logging");
configAutoBoltRelease = ((BaseUnityPlugin)this).Config.Bind<bool>("Settings", "Auto Bolt Release", false, "If true, automatically releases the bolt/slide when a clip is slapped out (if the firearm supports it)");
configAllowFirearmsToSlap = ((BaseUnityPlugin)this).Config.Bind<bool>("Settings", "Allow Firearms To Slap", true, "If true, firearms can slap clips out of other guns");
configAutoLoadClipsFromQuickbelt = ((BaseUnityPlugin)this).Config.Bind<bool>("Settings", "Auto Load Clips From Quickbelt", true, "If true, automatically loads compatible clips from quickbelt slots when a handgun is hovering over them");
configRequireSpawnlockedQuickbelt = ((BaseUnityPlugin)this).Config.Bind<bool>("Settings", "Only Load From Spawnlocked Slots", false, "If true, clips will only auto-load from quickbelt slots that are spawnlocked");
configAllowLoadingWithOneFirearm = ((BaseUnityPlugin)this).Config.Bind<bool>("Settings", "Allow Loading When Wielding One Handgun", false, "If true, clips can be auto-loaded when only one hand has a handgun. If false (default), both hands must be holding firearms for auto-loading to work.");
configFirearmsCanPushDownClipRounds = ((BaseUnityPlugin)this).Config.Bind<bool>("Settings", "Firearms Can Push Down Clip Rounds", true, "If true, allows a firearm in one hand to push rounds from a clip in the other hand (as if dual wielding)");
configClipsCanPressOtherClips = ((BaseUnityPlugin)this).Config.Bind<bool>("Settings", "Clips Can Press Other Clips", true, "If true, clips inserted in firearms can press into each other to load rounds when both hands are holding firearms with clips");
configAllowInteractiveObjectsToSlap = ((BaseUnityPlugin)this).Config.Bind<bool>("Settings", "Allow Interactive Objects To Slap", true, "If true, any held FVRInteractiveObject can slap clips out of firearms");
configInteractiveObjectsCanPushDownClipRounds = ((BaseUnityPlugin)this).Config.Bind<bool>("Settings", "Interactive Objects Can Push Down Clip Rounds", true, "If true, allows any held FVRInteractiveObject to push rounds from clips when dual wielding");
harmony = new Harmony(HarmonyID);
harmony.PatchAll();
Logger.LogInfo((object)"ClipSlapAkimbo plugin loaded!");
}
private void Update()
{
updateClipsToRemove.Clear();
CleanupTimedDictionary(recentlySlappedClips, 1f, updateClipsToRemove);
CleanupCooldownDictionary(activeBulletPushOperations, updateClipsToRemove);
}
public static bool WasRecentlySlapped(FVRFireArmClip clip)
{
if ((Object)(object)clip == (Object)null)
{
return false;
}
bool num = recentlySlappedClips.ContainsKey(clip);
if (num && configEnableDebugLogging.Value)
{
Logger.LogInfo((object)$"Clip {((Object)clip).name} was recently slapped, remaining cooldown: {recentlySlappedClips[clip]}s");
}
return num;
}
public static void RegisterBulletPushOperation(FVRFireArmClip clip)
{
if (!((Object)(object)clip == (Object)null))
{
activeBulletPushOperations[clip] = Time.time + bulletPushOperationDuration;
}
}
public static bool IsClipInBulletPushOperation(FVRFireArmClip clip)
{
if ((Object)(object)clip == (Object)null)
{
return false;
}
if (activeBulletPushOperations.ContainsKey(clip))
{
return Time.time < activeBulletPushOperations[clip];
}
return false;
}
public static void CheckForClipSlap(FVRViveHand hand, Collider collider)
{
if ((Object)(object)hand == (Object)null || hand.PhysTracker == null)
{
return;
}
FVRFireArmClip val = null;
if (validClipTriggers.TryGetValue(collider, out var value))
{
val = value;
if (configEnableDebugLogging.Value)
{
Logger.LogInfo((object)$"[Direct Hit] Hand {((Object)hand).name} hit registered clip trigger {((Object)collider).name}");
}
}
else
{
foreach (KeyValuePair<Collider, FVRFireArmClip> validClipTrigger in validClipTriggers)
{
if (((Component)validClipTrigger.Key).transform.IsChildOf(((Component)collider).transform))
{
val = validClipTrigger.Value;
if (configEnableDebugLogging.Value)
{
Logger.LogInfo((object)$"[Child Hit] Hand {((Object)hand).name} hit {((Object)collider).name}, found child clip trigger {((Object)validClipTrigger.Key).name}");
}
break;
}
}
}
if ((Object)(object)val != (Object)null)
{
ProcessClipSlap(hand, val);
}
}
private static void ProcessClipSlap(FVRViveHand hand, FVRFireArmClip clip)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Invalid comparison between Unknown and I4
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
//IL_014e: Unknown result type (might be due to invalid IL or missing references)
if ((int)clip.State != 1 || (Object)(object)clip.FireArm == (Object)null)
{
return;
}
bool flag = false;
int num = 0;
foreach (KeyValuePair<int, FVRFireArmClip> validClipID in validClipIDs)
{
if ((Object)(object)validClipID.Value == (Object)(object)clip)
{
flag = true;
num = validClipID.Key;
break;
}
}
if (!flag)
{
return;
}
if (configEnableDebugLogging.Value)
{
Logger.LogInfo((object)$"CheckForClipSlap: Target clip {((Object)clip).name} has valid ID {num} for slapping");
}
Vector3 velocity = hand.PhysTracker.Velocity;
float num2 = Mathf.Max(((Vector3)(ref velocity)).magnitude, ((Vector3)(ref hand.Input.VelLinearLocal)).magnitude);
if (num2 < configSlapThreshold.Value)
{
return;
}
FVRInteractiveObject currentInteractable = hand.CurrentInteractable;
FVRFireArm val = (FVRFireArm)(object)((currentInteractable is FVRFireArm) ? currentInteractable : null);
if ((Object)(object)val != (Object)null)
{
TrackClipForInteraction(clip, val);
}
FVRInteractiveObject currentInteractable2 = hand.CurrentInteractable;
FVRFireArm val2 = (FVRFireArm)(object)((currentInteractable2 is FVRFireArm) ? currentInteractable2 : null);
if (!ValidateClipSlapConditions(clip, val2))
{
if ((Object)(object)val2 != (Object)null && (Object)(object)clip.FireArm == (Object)(object)val2)
{
LogDebug("Prevented self-slap: Hand is holding the gun that contains this clip");
}
}
else
{
LogDebug($"SUCCESS: Hand slapping clip {((Object)clip).name} with velocity: {num2}");
ProcessSlap(clip, num2, ((Vector3)(ref hand.Input.VelLinearWorld)).normalized);
}
}
public static bool IsClipCompatibleWithFirearm(FVRFireArmClip clip, FVRFireArm firearm)
{
//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)
if ((Object)(object)clip == (Object)null || (Object)(object)firearm == (Object)null)
{
return false;
}
if (firearm.ClipType != clip.ClipType)
{
return false;
}
if ((Object)(object)firearm.Clip != (Object)null)
{
return false;
}
return true;
}
public static bool BothHandsHaveFirearmsWithClips()
{
if ((Object)(object)GM.CurrentMovementManager == (Object)null || GM.CurrentMovementManager.Hands == null || GM.CurrentMovementManager.Hands.Length < 2)
{
return false;
}
FVRViveHand val = GM.CurrentMovementManager.Hands[0];
FVRViveHand val2 = GM.CurrentMovementManager.Hands[1];
if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
{
return false;
}
FVRInteractiveObject currentInteractable = val.CurrentInteractable;
FVRFireArm val3 = (FVRFireArm)(object)((currentInteractable is FVRFireArm) ? currentInteractable : null);
FVRInteractiveObject currentInteractable2 = val2.CurrentInteractable;
FVRFireArm val4 = (FVRFireArm)(object)((currentInteractable2 is FVRFireArm) ? currentInteractable2 : null);
if ((Object)(object)val3 == (Object)null || (Object)(object)val4 == (Object)null)
{
return false;
}
if ((Object)(object)val3.Clip != (Object)null)
{
return (Object)(object)val4.Clip != (Object)null;
}
return false;
}
public static bool BothHandsHaveFirearms()
{
FVRMovementManager currentMovementManager = GM.CurrentMovementManager;
if (currentMovementManager?.Hands == null || currentMovementManager.Hands.Length < 2)
{
UpdateDualWieldState(newState: false);
return false;
}
FVRViveHand val = currentMovementManager.Hands[0];
FVRViveHand val2 = currentMovementManager.Hands[1];
if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
{
UpdateDualWieldState(newState: false);
return false;
}
FVRInteractiveObject currentInteractable = val.CurrentInteractable;
FVRInteractiveObject obj = ((currentInteractable is FVRFireArm) ? currentInteractable : null);
FVRInteractiveObject currentInteractable2 = val2.CurrentInteractable;
FVRFireArm val3 = (FVRFireArm)(object)((currentInteractable2 is FVRFireArm) ? currentInteractable2 : null);
if ((Object)(object)obj != (Object)null)
{
return (Object)(object)val3 != (Object)null;
}
return false;
}
public static bool BothHandsHaveInteractableObjects()
{
FVRMovementManager currentMovementManager = GM.CurrentMovementManager;
if (currentMovementManager?.Hands == null || currentMovementManager.Hands.Length < 2)
{
return false;
}
FVRViveHand val = currentMovementManager.Hands[0];
FVRViveHand val2 = currentMovementManager.Hands[1];
if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
{
return false;
}
FVRInteractiveObject currentInteractable = val.CurrentInteractable;
FVRInteractiveObject currentInteractable2 = val2.CurrentInteractable;
if ((Object)(object)currentInteractable != (Object)null)
{
return (Object)(object)currentInteractable2 != (Object)null;
}
return false;
}
public static bool HandsHaveMixedInteractables()
{
FVRMovementManager currentMovementManager = GM.CurrentMovementManager;
if (currentMovementManager?.Hands == null || currentMovementManager.Hands.Length < 2)
{
return false;
}
FVRViveHand val = currentMovementManager.Hands[0];
FVRViveHand val2 = currentMovementManager.Hands[1];
if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
{
return false;
}
FVRInteractiveObject currentInteractable = val.CurrentInteractable;
FVRFireArm val3 = (FVRFireArm)(object)((currentInteractable is FVRFireArm) ? currentInteractable : null);
FVRInteractiveObject currentInteractable2 = val2.CurrentInteractable;
FVRFireArm val4 = (FVRFireArm)(object)((currentInteractable2 is FVRFireArm) ? currentInteractable2 : null);
FVRInteractiveObject currentInteractable3 = val.CurrentInteractable;
FVRInteractiveObject currentInteractable4 = val2.CurrentInteractable;
bool flag = (Object)(object)val3 != (Object)null;
bool flag2 = (Object)(object)val4 != (Object)null;
bool flag3 = (Object)(object)currentInteractable3 != (Object)null;
bool flag4 = (Object)(object)currentInteractable4 != (Object)null;
if (!(flag && flag4))
{
return flag2 && flag3;
}
return true;
}
public static void CreateTemporaryBulletCollider(FVRFireArmClip clip)
{
//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_0099: Unknown result type (might be due to invalid IL or missing references)
//IL_00a6: 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_00d3: Unknown result type (might be due to invalid IL or missing references)
//IL_00dd: 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_00bb: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)clip == (Object)null || !clip.HasARound())
{
return;
}
GameObject val = FindTopActiveBulletDisplay(clip);
if ((Object)(object)val == (Object)null)
{
return;
}
MeshFilter component = val.GetComponent<MeshFilter>();
MeshRenderer component2 = val.GetComponent<MeshRenderer>();
if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null || (Object)(object)component.mesh == (Object)null)
{
return;
}
ColliderPair colliderPair = FindExistingColliders(val);
BoxCollider val2 = colliderPair.SolidCollider;
BoxCollider val3 = colliderPair.TriggerCollider;
bool flag = false;
bool flag2 = false;
Bounds bounds = component.mesh.bounds;
if ((Object)(object)val2 == (Object)null)
{
val2 = CreateConfiguredBoxCollider(val, bounds, isTrigger: false);
flag = true;
}
else
{
val2.size = ((Bounds)(ref bounds)).size;
val2.center = ((Bounds)(ref bounds)).center;
}
if ((Object)(object)val3 == (Object)null)
{
val3 = CreateConfiguredBoxCollider(val, bounds, isTrigger: true, 1.4f);
flag2 = true;
}
else
{
val3.size = ((Bounds)(ref bounds)).size * 1.4f;
val3.center = ((Bounds)(ref bounds)).center;
}
BulletTriggerDetector bulletTriggerDetector = val.GetComponent<BulletTriggerDetector>();
bool flag3 = false;
if ((Object)(object)bulletTriggerDetector == (Object)null)
{
bulletTriggerDetector = val.AddComponent<BulletTriggerDetector>();
flag3 = true;
}
bulletTriggerDetector.parentClip = clip;
((Behaviour)bulletTriggerDetector).enabled = true;
val.layer = LayerMask.NameToLayer("Default");
FVRFireArmClipFixedUpdatePatch.temporaryBulletColliders[clip] = val2;
FVRFireArmClipFixedUpdatePatch.temporaryBulletTriggers[clip] = val3;
if (!configEnableDebugLogging.Value)
{
return;
}
string text = "";
if (flag || flag2 || flag3)
{
text = "Created";
if (flag)
{
text += " solid-collider";
}
if (flag2)
{
text += " trigger-collider";
}
if (flag3)
{
text += " detector";
}
}
else
{
text = "Reused existing";
}
Logger.LogInfo((object)(text + " bullet colliders for " + ((Object)clip).name));
}
public static void RemoveTemporaryBulletCollider(FVRFireArmClip clip)
{
if ((Object)(object)clip == (Object)null)
{
return;
}
if (configEnableDebugLogging.Value)
{
Logger.LogInfo((object)("Disabling all bullet colliders for " + ((Object)clip).name));
}
int layerID = LayerMask.NameToLayer("NoCol");
int num = SetGameObjectArrayToLayer(clip.DisplayBullets, layerID);
if (clip.DisplayBullets != null)
{
GameObject[] displayBullets = clip.DisplayBullets;
foreach (GameObject val in displayBullets)
{
if ((Object)(object)val != (Object)null)
{
BulletTriggerDetector component = val.GetComponent<BulletTriggerDetector>();
if ((Object)(object)component != (Object)null)
{
((Behaviour)component).enabled = false;
}
}
}
}
LogDebug($"Disabled {num} colliders by setting to NoCol layer");
if (FVRFireArmClipFixedUpdatePatch.temporaryBulletColliders.ContainsKey(clip))
{
FVRFireArmClipFixedUpdatePatch.temporaryBulletColliders.Remove(clip);
}
if (FVRFireArmClipFixedUpdatePatch.temporaryBulletTriggers.ContainsKey(clip))
{
FVRFireArmClipFixedUpdatePatch.temporaryBulletTriggers.Remove(clip);
}
}
public static void HandleBulletTriggerFirearmInteraction(FVRFireArmClip clip, FVRFireArm firearm, Collider firearmCollider)
{
//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_0086: 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_0092: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)clip == (Object)null || (Object)(object)firearm == (Object)null)
{
return;
}
RegisterBulletPushOperation(clip);
if (!configFirearmsCanPushDownClipRounds.Value)
{
return;
}
string key = $"{((Object)firearm).GetInstanceID()}_{((Object)clip).GetInstanceID()}";
if (FVRFireArmClipFixedUpdatePatch.processedClipPairsThisFrame.TryGetValue(key, out var _))
{
return;
}
FVRFireArmClipFixedUpdatePatch.processedClipPairsThisFrame[key] = Time.time;
Vector3 velLinearWorld = ((FVRInteractiveObject)firearm).m_hand.Input.VelLinearWorld;
if (((Vector3)(ref velLinearWorld)).magnitude > 0.1f && Vector3.Angle(velLinearWorld, -((Component)clip).transform.up) < 45f)
{
if (!TryPushRoundFromClipToMag(clip, $"Trigger-based firearm {((Object)firearm).name}"))
{
LogDebug($"Firearm {((Object)firearm).name} could not push from clip {((Object)clip).name}: {GetClipPushFailureReason(clip)}");
}
else
{
LogDebug($"Firearm {((Object)firearm).name} pushed round from clip {((Object)clip).name}");
}
}
}
public static void HandleBulletTriggerInteractiveObjectInteraction(FVRFireArmClip clip, FVRInteractiveObject interactiveObject, Collider objectCollider)
{
//IL_007b: 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_008f: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
//IL_009b: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)clip == (Object)null || (Object)(object)interactiveObject == (Object)null || interactiveObject is FVRFireArm)
{
return;
}
RegisterBulletPushOperation(clip);
if (!configInteractiveObjectsCanPushDownClipRounds.Value)
{
return;
}
string key = $"{((Object)interactiveObject).GetInstanceID()}_{((Object)clip).GetInstanceID()}";
if (FVRFireArmClipFixedUpdatePatch.processedClipPairsThisFrame.TryGetValue(key, out var _))
{
return;
}
FVRFireArmClipFixedUpdatePatch.processedClipPairsThisFrame[key] = Time.time;
Vector3 velLinearWorld = interactiveObject.m_hand.Input.VelLinearWorld;
if (((Vector3)(ref velLinearWorld)).magnitude > 0.1f && Vector3.Angle(velLinearWorld, -((Component)clip).transform.up) < 45f)
{
if (!TryPushRoundFromClipToMag(clip, $"Trigger-based interactive object {((Object)interactiveObject).name}"))
{
LogDebug($"Interactive object {((Object)interactiveObject).name} could not push from clip {((Object)clip).name}: {GetClipPushFailureReason(clip)}");
}
else
{
LogDebug($"Interactive object {((Object)interactiveObject).name} pushed round from clip {((Object)clip).name}");
}
}
}
public static void HandleBulletTriggerClipInteraction(FVRFireArmClip sourceClip, FVRFireArmClip targetClip)
{
if ((Object)(object)sourceClip == (Object)null || (Object)(object)targetClip == (Object)null)
{
return;
}
RegisterBulletPushOperation(sourceClip);
RegisterBulletPushOperation(targetClip);
if (!configClipsCanPressOtherClips.Value)
{
return;
}
bool num = BothHandsHaveFirearmsWithClips();
bool flag = HandsHaveMixedInteractables();
if (!num && !flag)
{
if (configEnableDebugLogging.Value)
{
LogDebug("Clip-to-clip interaction skipped: No valid dual-wield state for clip interaction");
HandStates handStates = GetHandStates();
LogDebug("Left hand: " + (((Object)(object)handStates.LeftFirearm != (Object)null) ? ((Object)handStates.LeftFirearm).name : "no firearm") + ", clip: " + (((Object)(object)handStates.LeftFirearm != (Object)null && (Object)(object)handStates.LeftFirearm.Clip != (Object)null) ? ((Object)handStates.LeftFirearm.Clip).name : "none"));
LogDebug("Right hand: " + (((Object)(object)handStates.RightFirearm != (Object)null) ? ((Object)handStates.RightFirearm).name : "no firearm") + ", clip: " + (((Object)(object)handStates.RightFirearm != (Object)null && (Object)(object)handStates.RightFirearm.Clip != (Object)null) ? ((Object)handStates.RightFirearm.Clip).name : "none"));
}
return;
}
string key = GenerateClipPairKey(sourceClip, targetClip);
if (!FVRFireArmClipFixedUpdatePatch.processedClipPairsThisFrame.TryGetValue(key, out var _))
{
FVRFireArmClipFixedUpdatePatch.processedClipPairsThisFrame[key] = Time.time;
LogDebug("Clip trigger overlap detected: " + ((Object)sourceClip).name + " <-> " + ((Object)targetClip).name);
bool flag2 = false;
bool flag3 = false;
flag2 = TryPushRoundFromClipToMag(sourceClip, "Source clip " + ((Object)sourceClip).name);
if (!flag2)
{
LogDebug("Source clip " + ((Object)sourceClip).name + " could not push: " + GetClipPushFailureReason(sourceClip));
}
flag3 = TryPushRoundFromClipToMag(targetClip, "Target clip " + ((Object)targetClip).name);
if (!flag3)
{
LogDebug("Target clip " + ((Object)targetClip).name + " could not push: " + GetClipPushFailureReason(targetClip));
}
LogDebug($"Trigger overlap result: {((Object)sourceClip).name} pushed={flag2}, {((Object)targetClip).name} pushed={flag3}");
}
}
private static FVRFireArmClip FindClipFromCollider(Collider collider)
{
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Invalid comparison between Unknown and I4
if ((Object)(object)collider == (Object)null)
{
return null;
}
if (colliderToClipCache.TryGetValue(collider, out var value))
{
if (IsCacheEntryValid(value) && (int)value.State == 1 && (Object)(object)value.FireArm != (Object)null)
{
return value;
}
colliderToClipCache.Remove(collider);
}
FVRFireArmClip value2 = null;
Transform transform = ((Component)collider).transform;
if (transformToClipCache.TryGetValue(transform, out value2) && !IsCacheEntryValid(value2))
{
transformToClipCache.Remove(transform);
value2 = null;
}
if ((Object)(object)value2 == (Object)null)
{
value2 = ((Component)collider).GetComponent<FVRFireArmClip>();
if ((Object)(object)value2 != (Object)null)
{
transformToClipCache[transform] = value2;
}
}
if ((Object)(object)value2 == (Object)null)
{
FVRFireArmClipInterface component = ((Component)collider).GetComponent<FVRFireArmClipInterface>();
if ((Object)(object)component != (Object)null && ((Behaviour)component).isActiveAndEnabled)
{
value2 = component.Clip;
}
}
if ((Object)(object)value2 == (Object)null && (Object)(object)collider.attachedRigidbody != (Object)null)
{
Rigidbody attachedRigidbody = collider.attachedRigidbody;
if (rigidbodyToClipCache.TryGetValue(attachedRigidbody, out value2) && !IsCacheEntryValid(value2))
{
rigidbodyToClipCache.Remove(attachedRigidbody);
value2 = null;
}
if ((Object)(object)value2 == (Object)null)
{
value2 = ((Component)attachedRigidbody).GetComponent<FVRFireArmClip>();
if ((Object)(object)value2 != (Object)null)
{
rigidbodyToClipCache[attachedRigidbody] = value2;
}
}
}
if ((Object)(object)value2 != (Object)null)
{
colliderToClipCache[collider] = value2;
}
return value2;
}
private static void ProcessSlap(FVRFireArmClip clip, float velocityMagnitude, Vector3 slapDirection)
{
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
//IL_00db: Unknown result type (might be due to invalid IL or missing references)
//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
//IL_00df: 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)
//IL_0122: Unknown result type (might be due to invalid IL or missing references)
//IL_0127: Unknown result type (might be due to invalid IL or missing references)
FVRFireArm fireArm = clip.FireArm;
float num = 0f;
if (clip.m_capacity > 0)
{
num = (float)clip.m_numRounds / (float)clip.m_capacity;
}
float num2 = Mathf.Lerp(configSlapForce.Value, configSlapForceFullClip.Value, num);
float num3 = velocityMagnitude * num2;
if (configEnableDebugLogging.Value)
{
Logger.LogInfo((object)$"Processing slap for clip {((Object)clip).name}: force={num3}, direction={slapDirection}");
}
RestoreClipCollidersFromDualWield(clip);
if ((Object)(object)fireArm != (Object)null)
{
fireArm.EjectClip();
if (configAutoBoltRelease.Value)
{
TryReleaseBoltOrSlide(fireArm);
}
}
recentlySlappedClips[clip] = 1f;
if ((Object)(object)((FVRPhysicalObject)clip).RootRigidbody != (Object)null)
{
Vector3 velocity = ((FVRPhysicalObject)clip).RootRigidbody.velocity;
Vector3 val = slapDirection * num3;
((FVRPhysicalObject)clip).RootRigidbody.velocity = velocity + val;
Rigidbody rootRigidbody = ((FVRPhysicalObject)clip).RootRigidbody;
rootRigidbody.angularVelocity += new Vector3(Random.Range(-5f, 5f), Random.Range(-5f, 5f), Random.Range(-5f, 5f));
if (configEnableDebugLogging.Value)
{
Logger.LogInfo((object)$"Applied additional slap velocity {((Vector3)(ref val)).magnitude:F2} to clip {((Object)clip).name}");
}
}
}
private static void TryReleaseBoltOrSlide(FVRFireArm fireArm)
{
if ((Object)(object)fireArm == (Object)null)
{
return;
}
ClosedBoltWeapon val = (ClosedBoltWeapon)(object)((fireArm is ClosedBoltWeapon) ? fireArm : null);
if ((Object)(object)val != (Object)null && (Object)(object)val.Bolt != (Object)null && val.HasBoltReleaseButton)
{
if (val.Bolt.IsBoltLocked())
{
val.Bolt.ReleaseBolt();
LogDebug("Released bolt on ClosedBoltWeapon: " + ((Object)fireArm).name);
}
return;
}
Handgun val2 = (Handgun)(object)((fireArm is Handgun) ? fireArm : null);
if ((Object)(object)val2 != (Object)null && val2.HasSlideReleaseControl)
{
if (val2.IsSlideCatchEngaged())
{
val2.DropSlideRelease();
LogDebug("Released slide on Handgun: " + ((Object)fireArm).name);
}
return;
}
OpenBoltReceiver val3 = (OpenBoltReceiver)(object)((fireArm is OpenBoltReceiver) ? fireArm : null);
if ((Object)(object)val3 != (Object)null)
{
if (val3.IsBoltCatchEngaged())
{
LogDebug("Attempting to release bolt on OpenBoltReceiver: " + ((Object)fireArm).name);
TryInvokeMethod(val3, "DisEngageBoltCatch");
}
return;
}
LogDebug("Attempting to use reflection to release bolt on: " + ((object)fireArm).GetType().Name);
Component val4 = null;
Component[] componentsInChildren = ((Component)fireArm).GetComponentsInChildren<Component>();
foreach (Component val5 in componentsInChildren)
{
if (((object)val5).GetType().Name.Contains("Bolt") || ((object)val5).GetType().Name.Contains("Slide"))
{
val4 = val5;
break;
}
}
if ((Object)(object)val4 != (Object)null && !TryInvokeMethod(val4, "ReleaseBolt"))
{
TryInvokeMethod(val4, "DropSlideRelease");
}
}
public static void UpdateDualWieldState(bool newState)
{
if (!hasLoggedInitialState && configEnableDebugLogging.Value)
{
FVRMovementManager currentMovementManager = GM.CurrentMovementManager;
if (currentMovementManager?.Hands != null && currentMovementManager.Hands.Length >= 2)
{
FVRViveHand obj = currentMovementManager.Hands[0];
FVRViveHand val = currentMovementManager.Hands[1];
FVRInteractiveObject obj2 = ((obj != null) ? obj.CurrentInteractable : null);
FVRFireArm val2 = (FVRFireArm)(object)((obj2 is FVRFireArm) ? obj2 : null);
FVRInteractiveObject obj3 = ((val != null) ? val.CurrentInteractable : null);
FVRFireArm val3 = (FVRFireArm)(object)((obj3 is FVRFireArm) ? obj3 : null);
Logger.LogInfo((object)string.Format("Initial dual-wield state: Left={0}, Right={1}, Result={2}", ((val2 != null) ? ((Object)val2).name : null) ?? "null", ((val3 != null) ? ((Object)val3).name : null) ?? "null", newState));
}
hasLoggedInitialState = true;
}
if (isDualWielding == newState)
{
return;
}
if (configEnableDebugLogging.Value)
{
FVRMovementManager currentMovementManager2 = GM.CurrentMovementManager;
if (currentMovementManager2?.Hands != null && currentMovementManager2.Hands.Length >= 2)
{
FVRViveHand obj4 = currentMovementManager2.Hands[0];
FVRViveHand val4 = currentMovementManager2.Hands[1];
FVRInteractiveObject obj5 = ((obj4 != null) ? obj4.CurrentInteractable : null);
FVRFireArm val5 = (FVRFireArm)(object)((obj5 is FVRFireArm) ? obj5 : null);
FVRInteractiveObject obj6 = ((val4 != null) ? val4.CurrentInteractable : null);
FVRFireArm val6 = (FVRFireArm)(object)((obj6 is FVRFireArm) ? obj6 : null);
Logger.LogInfo((object)string.Format("Dual-wield state changed: Left={0}, Right={1}, {2} -> {3}", ((val5 != null) ? ((Object)val5).name : null) ?? "null", ((val6 != null) ? ((Object)val6).name : null) ?? "null", isDualWielding, newState));
}
}
isDualWielding = newState;
if (!newState)
{
if (configEnableDebugLogging.Value)
{
Logger.LogInfo((object)$"Restoring {activeInteractionClips.Count} active clips from dual-wield state");
}
foreach (FVRFireArmClip item in new HashSet<FVRFireArmClip>(activeInteractionClips))
{
if ((Object)(object)item != (Object)null && (Object)(object)((Component)item).gameObject != (Object)null)
{
RestoreClipCollidersFromDualWield(item);
if (configEnableDebugLogging.Value)
{
Logger.LogInfo((object)$"Restored clip {((Object)item).name} to normal state");
}
}
}
activeInteractionClips.Clear();
firearmActiveClips.Clear();
}
else
{
if (configEnableDebugLogging.Value)
{
Logger.LogInfo((object)"Entered dual-wield mode - configuring all clips in held firearms");
}
ConfigureExistingClipsForDualWield();
}
}
private static void ConfigureExistingClipsForDualWield()
{
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
//IL_00a3: Invalid comparison between Unknown and I4
FVRMovementManager currentMovementManager = GM.CurrentMovementManager;
if (currentMovementManager?.Hands == null || currentMovementManager.Hands.Length < 2)
{
return;
}
FVRViveHand val = currentMovementManager.Hands[0];
FVRViveHand val2 = currentMovementManager.Hands[1];
if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
{
return;
}
FVRFireArm[] obj = new FVRFireArm[2]
{
(FVRFireArm)/*isinst with value type is only supported in some contexts*/,
(FVRFireArm)/*isinst with value type is only supported in some contexts*/
};
int num = 0;
FVRFireArm[] array = (FVRFireArm[])(object)obj;
foreach (FVRFireArm val3 in array)
{
if ((Object)(object)val3 != (Object)null && (Object)(object)val3.Clip != (Object)null && (int)val3.Clip.State == 1)
{
FVRFireArmClip clip = val3.Clip;
RemoveTemporaryBulletCollider(clip);
if (clip.HasARound())
{
CreateTemporaryBulletCollider(clip);
}
TrackClipForInteraction(clip, val3);
num++;
if (configEnableDebugLogging.Value)
{
Logger.LogInfo((object)$"Configured existing clip {((Object)clip).name} in firearm {((Object)val3).name} for dual-wield mode (bullets: {clip.m_numRounds})");
}
}
}
if (configEnableDebugLogging.Value && num > 0)
{
Logger.LogInfo((object)$"Configured {num} existing clips for dual-wield mode");
}
}
public static void TrackClipForInteraction(FVRFireArmClip clip, FVRFireArm firearm)
{
if ((Object)(object)clip == (Object)null || (Object)(object)firearm == (Object)null)
{
return;
}
bool flag = activeInteractionClips.Contains(clip);
activeInteractionClips.Add(clip);
if (!firearmActiveClips.ContainsKey(firearm))
{
firearmActiveClips[firearm] = new HashSet<FVRFireArmClip>();
}
firearmActiveClips[firearm].Add(clip);
if (isDualWielding)
{
StoreAndSetClipCollidersForDualWield(clip, flag);
if (configEnableDebugLogging.Value && flag)
{
Logger.LogInfo((object)$"Reconfigured already tracked clip {((Object)clip).name} for dual-wield mode");
}
}
}
public static void UntrackClipFromInteraction(FVRFireArmClip clip, FVRFireArm firearm)
{
if ((Object)(object)clip == (Object)null)
{
return;
}
activeInteractionClips.Remove(clip);
if ((Object)(object)firearm != (Object)null && firearmActiveClips.ContainsKey(firearm))
{
firearmActiveClips[firearm].Remove(clip);
if (firearmActiveClips[firearm].Count == 0)
{
firearmActiveClips.Remove(firearm);
}
}
RestoreClipCollidersFromDualWield(clip);
}
public static void StoreAndSetClipCollidersForDualWield(FVRFireArmClip clip, bool forceReconfigure = false)
{
//IL_024c: Unknown result type (might be due to invalid IL or missing references)
//IL_0258: Unknown result type (might be due to invalid IL or missing references)
//IL_0265: Unknown result type (might be due to invalid IL or missing references)
//IL_030a: Unknown result type (might be due to invalid IL or missing references)
//IL_030f: 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)
//IL_031a: Unknown result type (might be due to invalid IL or missing references)
//IL_0322: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)clip == (Object)null)
{
if (configEnableDebugLogging.Value)
{
Logger.LogInfo((object)"StoreAndSetClipCollidersForDualWield: Clip is null, returning");
}
return;
}
if (trackedClipColliders.ContainsKey(clip) && !forceReconfigure)
{
LogDebug("StoreAndSetClipCollidersForDualWield: Clip " + ((Object)clip).name + " already configured, skipping");
return;
}
if (forceReconfigure && trackedClipColliders.ContainsKey(clip))
{
LogDebug($"StoreAndSetClipCollidersForDualWield: Force reconfiguring clip {((Object)clip).name} (current bullets: {clip.m_numRounds})");
RestoreClipCollidersFromDualWield(clip);
RemoveTemporaryBulletCollider(clip);
if (clip.HasARound())
{
CreateTemporaryBulletCollider(clip);
LogDebug($"Created bullet colliders for current state: {clip.m_numRounds} bullets");
}
else
{
LogDebug("No bullets remaining, no bullet colliders created");
}
}
LogDebug("StoreAndSetClipCollidersForDualWield: Processing clip " + ((Object)clip).name);
List<Collider> list = new List<Collider>();
if ((Object)(object)clip.Interface != (Object)null)
{
Collider component = ((Component)clip.Interface).GetComponent<Collider>();
if ((Object)(object)component != (Object)null)
{
StoreAndSetColliderLayer(component, "NoCol", list);
}
}
Collider[] componentsInChildren = ((Component)clip).GetComponentsInChildren<Collider>(true);
HashSet<Collider> hashSet = new HashSet<Collider>();
Collider[] componentsInChildren2;
if (clip.DisplayBullets != null && clip.DisplayBullets.Length != 0)
{
int numRounds = clip.m_numRounds;
for (int i = 0; i < clip.DisplayBullets.Length && i < numRounds; i++)
{
GameObject val = clip.DisplayBullets[i];
if (!((Object)(object)val != (Object)null) || !val.activeInHierarchy)
{
continue;
}
componentsInChildren2 = val.GetComponentsInChildren<Collider>(true);
foreach (Collider val2 in componentsInChildren2)
{
if ((Object)(object)val2 != (Object)null)
{
hashSet.Add(val2);
LogDebug($"Including bullet collider {((Object)val2).name} from active bullet {i}");
}
}
}
if (clip.DisplayBullets.Length > numRounds)
{
LogDebug($"Ignoring {clip.DisplayBullets.Length - numRounds} inactive bullet displays for clip {((Object)clip).name}");
}
}
Collider val3 = null;
float num = 0f;
componentsInChildren2 = componentsInChildren;
foreach (Collider val4 in componentsInChildren2)
{
if ((Object)(object)val4 != (Object)null && val4.isTrigger)
{
float num2 = 0f;
if (val4 is BoxCollider)
{
BoxCollider val5 = (BoxCollider)(object)((val4 is BoxCollider) ? val4 : null);
num2 = val5.size.x * val5.size.y * val5.size.z;
}
else if (val4 is SphereCollider)
{
SphereCollider val6 = (SphereCollider)(object)((val4 is SphereCollider) ? val4 : null);
num2 = 4.1887903f * Mathf.Pow(val6.radius, 3f);
}
else if (val4 is CapsuleCollider)
{
CapsuleCollider val7 = (CapsuleCollider)(object)((val4 is CapsuleCollider) ? val4 : null);
float num3 = val7.height - 2f * val7.radius;
float num4 = (float)Math.PI * val7.radius * val7.radius * num3;
float num5 = 4.1887903f * Mathf.Pow(val7.radius, 3f);
num2 = num4 + num5;
}
Vector3 lossyScale = ((Component)val4).transform.lossyScale;
num2 *= lossyScale.x * lossyScale.y * lossyScale.z;
if (num2 > num)
{
num = num2;
val3 = val4;
}
}
}
componentsInChildren2 = componentsInChildren;
foreach (Collider val8 in componentsInChildren2)
{
if ((Object)(object)val8 == (Object)null)
{
continue;
}
bool flag = hashSet.Contains(val8);
if (!flag)
{
if (FVRFireArmClipFixedUpdatePatch.temporaryBulletColliders.ContainsKey(clip) && (Object)(object)val8 == (Object)(object)FVRFireArmClipFixedUpdatePatch.temporaryBulletColliders[clip])
{
flag = true;
}
else if (FVRFireArmClipFixedUpdatePatch.temporaryBulletTriggers.ContainsKey(clip) && (Object)(object)val8 == (Object)(object)FVRFireArmClipFixedUpdatePatch.temporaryBulletTriggers[clip])
{
flag = true;
}
}
bool flag2 = false;
if ((Object)(object)clip.Interface != (Object)null && ((Component)val8).transform.IsChildOf(((Component)clip.Interface).transform))
{
flag2 = true;
}
bool flag3 = (Object)(object)val8 == (Object)(object)val3;
if (!flag && !flag2 && !flag3)
{
StoreAndSetColliderLayer(val8, "NoCol", list);
}
}
trackedClipColliders[clip] = list;
}
public static void RestoreClipCollidersFromDualWield(FVRFireArmClip clip)
{
if ((Object)(object)clip == (Object)null)
{
return;
}
RemoveTemporaryBulletCollider(clip);
if (!trackedClipColliders.ContainsKey(clip))
{
return;
}
List<Collider> list = trackedClipColliders[clip];
int num = 0;
foreach (Collider item in list)
{
if ((Object)(object)item != (Object)null && originalColliderLayers.ContainsKey(item))
{
int num2 = originalColliderLayers[item];
((Component)item).gameObject.layer = num2;
num++;
LogDebug($"Restored collider: {((Object)item).name} on {((Object)((Component)item).gameObject).name} to layer {LayerMask.LayerToName(num2)}");
originalColliderLayers.Remove(item);
}
}
trackedClipColliders.Remove(clip);
LogDebug($"Restored {num} colliders for {((Object)clip).name}");
}
public static void RegisterClipTriggers(FVRFireArmClip clip)
{
if ((Object)(object)clip == (Object)null)
{
return;
}
Collider component = ((Component)clip).GetComponent<Collider>();
if ((Object)(object)component != (Object)null && component.isTrigger)
{
validClipTriggers[component] = clip;
if (configEnableDebugLogging.Value)
{
Logger.LogInfo((object)("Registered trigger collider " + ((Object)component).name + " for clip " + ((Object)clip).name));
}
}
else if (configEnableDebugLogging.Value)
{
Logger.LogInfo((object)("WARNING: Could not find trigger collider directly on clip " + ((Object)clip).name));
}
}
public static void UnregisterClipTriggers(FVRFireArmClip clip)
{
if ((Object)(object)clip == (Object)null)
{
return;
}
List<Collider> list = new List<Collider>();
foreach (KeyValuePair<Collider, FVRFireArmClip> validClipTrigger in validClipTriggers)
{
if ((Object)(object)validClipTrigger.Value == (Object)(object)clip)
{
list.Add(validClipTrigger.Key);
}
}
foreach (Collider item in list)
{
validClipTriggers.Remove(item);
if (configEnableDebugLogging.Value)
{
Logger.LogInfo((object)("Unregistered trigger collider " + ((Object)item).name + " for clip " + ((Object)clip).name));
}
}
}
public static void CheckForFirearmClipSlap(FVRFireArm firearm, Collider collider)
{
//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
//IL_00bb: Invalid comparison between Unknown and I4
//IL_016f: Unknown result type (might be due to invalid IL or missing references)
//IL_0174: Unknown result type (might be due to invalid IL or missing references)
//IL_0190: Unknown result type (might be due to invalid IL or missing references)
//IL_0183: Unknown result type (might be due to invalid IL or missing references)
//IL_0195: Unknown result type (might be due to invalid IL or missing references)
//IL_0197: Unknown result type (might be due to invalid IL or missing references)
//IL_019d: Unknown result type (might be due to invalid IL or missing references)
//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
//IL_029a: Unknown result type (might be due to invalid IL or missing references)
//IL_0253: Unknown result type (might be due to invalid IL or missing references)
if (!configAllowFirearmsToSlap.Value)
{
if (configEnableDebugLogging.Value)
{
Logger.LogInfo((object)"CheckForFirearmClipSlap: Firearms not allowed to slap");
}
return;
}
if ((Object)(object)firearm == (Object)null || !((FVRInteractiveObject)firearm).IsHeld)
{
if (configEnableDebugLogging.Value)
{
Logger.LogInfo((object)string.Format("CheckForFirearmClipSlap: Invalid firearm or not held - firearm: {0}, held: {1}", ((firearm != null) ? ((Object)firearm).name : null) ?? "null", firearm != null && ((FVRInteractiveObject)firearm).IsHeld));
}
return;
}
FVRFireArmClip val = FindClipFromCollider(collider);
if ((Object)(object)val == (Object)null || IsClipInBulletPushOperation(val))
{
return;
}
if ((Object)(object)val.FireArm == (Object)(object)firearm)
{
_ = configEnableDebugLogging.Value;
return;
}
if ((int)val.State != 1 || (Object)(object)val.FireArm == (Object)null)
{
if (colliderToClipCache.ContainsKey(collider))
{
colliderToClipCache.Remove(collider);
}
return;
}
bool flag = false;
int num = 0;
foreach (KeyValuePair<int, FVRFireArmClip> validClipID in validClipIDs)
{
if ((Object)(object)validClipID.Value == (Object)(object)val)
{
flag = true;
num = validClipID.Key;
break;
}
}
if (!flag)
{
return;
}
if (configEnableDebugLogging.Value)
{
Logger.LogInfo((object)$"CheckForFirearmClipSlap: Target clip {((Object)val).name} has valid ID {num} for slapping");
}
Vector3 velLinearWorld = ((FVRInteractiveObject)firearm).m_hand.Input.VelLinearWorld;
Vector3 val2 = (((Object)(object)((FVRPhysicalObject)firearm).RootRigidbody != (Object)null) ? ((FVRPhysicalObject)firearm).RootRigidbody.velocity : Vector3.zero);
Vector3 val3 = ((Vector3.Magnitude(velLinearWorld) > Vector3.Magnitude(val2)) ? velLinearWorld : val2);
float magnitude = ((Vector3)(ref val3)).magnitude;
if (configEnableDebugLogging.Value && magnitude > 0.5f)
{
Logger.LogInfo((object)$"CheckForFirearmClipSlap: {((Object)firearm).name} velocity {magnitude}, threshold {configSlapThreshold.Value}");
}
if (magnitude < configSlapThreshold.Value)
{
if (configEnableDebugLogging.Value && magnitude > 0.5f)
{
Logger.LogInfo((object)"CheckForFirearmClipSlap: Velocity below threshold");
}
return;
}
if ((Object)(object)firearm != (Object)null)
{
TrackClipForInteraction(val, firearm);
}
if (!ValidateClipSlapConditions(val, firearm))
{
LogDebug($"CheckForFirearmClipSlap: Clip {((Object)val).name} failed validation (state: {val.State}, firearm match: {(Object)(object)val.FireArm == (Object)(object)firearm})");
return;
}
LogDebug($"SUCCESS: Firearm slapping clip {((Object)val).name} with velocity: {magnitude}");
ProcessSlap(val, magnitude, ((Vector3)(ref val3)).normalized);
}
public static void CheckForFirearmClipSlap(FVRFireArm firearm, Collision collision)
{
CheckForFirearmClipSlap(firearm, collision.collider);
}
public static void CheckForInteractiveObjectClipSlap(FVRInteractiveObject interactiveObject, Collider collider)
{
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
//IL_00aa: Invalid comparison between Unknown and I4
//IL_015e: Unknown result type (might be due to invalid IL or missing references)
//IL_0163: Unknown result type (might be due to invalid IL or missing references)
//IL_0164: Unknown result type (might be due to invalid IL or missing references)
//IL_0169: Unknown result type (might be due to invalid IL or missing references)
//IL_0186: Unknown result type (might be due to invalid IL or missing references)
//IL_018c: Unknown result type (might be due to invalid IL or missing references)
//IL_017f: 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_0199: Unknown result type (might be due to invalid IL or missing references)
//IL_0195: Unknown result type (might be due to invalid IL or missing references)
//IL_019a: Unknown result type (might be due to invalid IL or missing references)
//IL_0288: Unknown result type (might be due to invalid IL or missing references)
//IL_024c: Unknown result type (might be due to invalid IL or missing references)
if (!configAllowInteractiveObjectsToSlap.Value)
{
if (configEnableDebugLogging.Value)
{
Logger.LogInfo((object)"CheckForInteractiveObjectClipSlap: Interactive objects not allowed to slap");
}
}
else if ((Object)(object)interactiveObject == (Object)null || !interactiveObject.IsHeld)
{
if (configEnableDebugLogging.Value)
{
Logger.LogInfo((object)string.Format("CheckForInteractiveObjectClipSlap: Invalid object or not held - object: {0}, held: {1}", ((interactiveObject != null) ? ((Object)interactiveObject).name : null) ?? "null", interactiveObject != null && interactiveObject.IsHeld));
}
}
else
{
if (interactiveObject is FVRFireArm)
{
return;
}
FVRFireArmClip val = FindClipFromCollider(collider);
if ((Object)(object)val == (Object)null || IsClipInBulletPushOperation(val))
{
return;
}
if ((int)val.State != 1 || (Object)(object)val.FireArm == (Object)null)
{
if (colliderToClipCache.ContainsKey(collider))
{
colliderToClipCache.Remove(collider);
}
return;
}
bool flag = false;
int num = 0;
foreach (KeyValuePair<int, FVRFireArmClip> validClipID in validClipIDs)
{
if ((Object)(object)validClipID.Value == (Object)(object)val)
{
flag = true;
num = validClipID.Key;
break;
}
}
if (!flag)
{
return;
}
if (configEnableDebugLogging.Value)
{
Logger.LogInfo((object)$"CheckForInteractiveObjectClipSlap: Target clip {((Object)val).name} has valid ID {num} for slapping");
}
Vector3 velLinearWorld = interactiveObject.m_hand.Input.VelLinearWorld;
Vector3 val2 = Vector3.zero;
Rigidbody component = ((Component)interactiveObject).GetComponent<Rigidbody>();
if ((Object)(object)component != (Object)null)
{
val2 = component.velocity;
}
Vector3 val3 = ((Vector3.Magnitude(velLinearWorld) > Vector3.Magnitude(val2)) ? velLinearWorld : val2);
float magnitude = ((Vector3)(ref val3)).magnitude;
if (configEnableDebugLogging.Value && magnitude > 0.5f)
{
Logger.LogInfo((object)$"CheckForInteractiveObjectClipSlap: {((Object)interactiveObject).name} velocity {magnitude}, threshold {configSlapThreshold.Value}");
}
if (magnitude < configSlapThreshold.Value)
{
if (configEnableDebugLogging.Value && magnitude > 0.5f)
{
Logger.LogInfo((object)"CheckForInteractiveObjectClipSlap: Velocity below threshold");
}
return;
}
if ((Object)(object)val.FireArm != (Object)null)
{
TrackClipForInteraction(val, val.FireArm);
}
if (!ValidateClipSlapConditions(val))
{
LogDebug($"CheckForInteractiveObjectClipSlap: Clip {((Object)val).name} failed validation (state: {val.State})");
return;
}
LogDebug($"SUCCESS: Interactive object {((Object)interactiveObject).name} slapping clip {((Object)val).name} with velocity: {magnitude}");
ProcessSlap(val, magnitude, ((Vector3)(ref val3)).normalized);
}
}
public static void LogDebug(string message)
{
if (configEnableDebugLogging.Value)
{
Logger.LogInfo((object)message);
}
}
private static FVRFireArmClip TryGetClipFromSingleCollider(Collider collider, bool requireLocked = false)
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Invalid comparison between Unknown and I4
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Invalid comparison between Unknown and I4
//IL_0086: Unknown result type (might be due to invalid IL or missing references)
//IL_008c: Invalid comparison between Unknown and I4
if ((Object)(object)collider == (Object)null)
{
return null;
}
FVRFireArmClip component = ((Component)collider).GetComponent<FVRFireArmClip>();
if ((Object)(object)component != (Object)null && (!requireLocked || (int)component.State == 1))
{
return component;
}
if ((Object)(object)collider.attachedRigidbody != (Object)null)
{
component = ((Component)collider.attachedRigidbody).GetComponent<FVRFireArmClip>();
if ((Object)(object)component != (Object)null && (!requireLocked || (int)component.State == 1))
{
return component;
}
}
FVRFireArmClipInterface component2 = ((Component)collider).GetComponent<FVRFireArmClipInterface>();
if ((Object)(object)component2 != (Object)null && ((Behaviour)component2).isActiveAndEnabled)
{
component = component2.Clip;
if ((Object)(object)component != (Object)null && (!requireLocked || (int)component.State == 1))
{
return component;
}
}
return null;
}
private static bool ValidateClipSlapConditions(FVRFireArmClip clip, FVRFireArm excludeFirearm = null)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Invalid comparison between Unknown and I4
if ((Object)(object)clip == (Object)null)
{
return false;
}
if ((int)clip.State != 1)
{
return false;
}
if ((Object)(object)excludeFirearm != (Object)null && (Object)(object)clip.FireArm == (Object)(object)excludeFirearm)
{
return false;
}
if (configRequireEmptyClip.Value && clip.m_numRounds > 0)
{
return false;
}
if (WasRecentlySlapped(clip))
{
return false;
}
return true;
}
private static void StoreAndSetColliderLayer(Collider collider, string newLayerName, List<Collider> trackingList)
{
if (!((Object)(object)collider == (Object)null))
{
if (!originalColliderLayers.ContainsKey(collider))
{
originalColliderLayers[collider] = ((Component)collider).gameObject.layer;
}
trackingList.Add(collider);
((Component)collider).gameObject.layer = LayerMask.NameToLayer(newLayerName);
LogDebug("Stored and set collider to " + newLayerName + ": " + ((Object)collider).name + " on " + ((Object)((Component)collider).gameObject).name + " (was: " + LayerMask.LayerToName(originalColliderLayers[collider]) + ")");
}
}
private static bool TryPushRoundFromClipToMag(FVRFireArmClip clip, string actionSource)
{
if ((Object)(object)clip == (Object)null || !clip.HasARound())
{
return false;
}
if ((Object)(object)clip.FireArm == (Object)null || (Object)(object)clip.FireArm.Magazine == (Object)null)
{
return false;
}
if (clip.FireArm.Magazine.IsFull())
{
return false;
}
clip.LoadOneRoundFromClipToMag();
LogDebug(actionSource + " pushed round from clip " + ((Object)clip).name);
return true;
}
private static string GenerateClipPairKey(FVRFireArmClip clipA, FVRFireArmClip clipB)
{
int instanceID = ((Object)clipA).GetInstanceID();
int instanceID2 = ((Object)clipB).GetInstanceID();
stringBuilder.Length = 0;
if (instanceID < instanceID2)
{
stringBuilder.Append(instanceID).Append('_').Append(instanceID2);
}
else
{
stringBuilder.Append(instanceID2).Append('_').Append(instanceID);
}
return stringBuilder.ToString();
}
private static BoxCollider CreateConfiguredBoxCollider(GameObject target, Bounds bounds, bool isTrigger, float sizeMultiplier = 1f)
{
//IL_0010: 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_0023: Unknown result type (might be due to invalid IL or missing references)
BoxCollider obj = target.AddComponent<BoxCollider>();
((Collider)obj).isTrigger = isTrigger;
obj.size = ((Bounds)(ref bounds)).size * sizeMultiplier;
obj.center = ((Bounds)(ref bounds)).center;
return obj;
}
private static HandStates GetHandStates()
{
HandStates handStates = new HandStates();
if ((Object)(object)GM.CurrentMovementManager != (Object)null && GM.CurrentMovementManager.Hands != null && GM.CurrentMovementManager.Hands.Length >= 2)
{
handStates.LeftHand = GM.CurrentMovementManager.Hands[0];
handStates.RightHand = GM.CurrentMovementManager.Hands[1];
handStates.LeftFirearm = (FVRFireArm)(((Object)(object)handStates.LeftHand != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null);
handStates.RightFirearm = (FVRFireArm)(((Object)(object)handStates.RightHand != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null);
}
return handStates;
}
private static bool TryInvokeMethod(object target, string methodName, object[] parameters = null)
{
if (target == null)
{
return false;
}
try
{
Type type = target.GetType();
MethodInfo method = type.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public);
if ((object)method != null)
{
method.Invoke(target, parameters);
LogDebug("Successfully invoked " + methodName + " on " + type.Name);
return true;
}
}
catch (Exception ex)
{
LogDebug("Error invoking " + methodName + ": " + ex.Message);
}
return false;
}
private static bool IsCacheEntryValid(FVRFireArmClip clip)
{
if ((Object)(object)clip != (Object)null)
{
return (Object)(object)((Component)clip).gameObject != (Object)null;
}
return false;
}
private static string GetClipPushFailureReason(FVRFireArmClip clip)
{
if (!clip.HasARound())
{
return "no rounds";
}
if ((Object)(object)clip.FireArm == (Object)null)
{
return "no firearm";
}
if ((Object)(object)clip.FireArm.Magazine == (Object)null)
{
return "no magazine";
}
if (clip.FireArm.Magazine.IsFull())
{
return "magazine full";
}
return "unknown";
}
private static GameObject FindTopActiveBulletDisplay(FVRFireArmClip clip)
{
if (clip?.DisplayBullets == null || clip.DisplayBullets.Length == 0)
{
return null;
}
for (int num = clip.DisplayBullets.Length - 1; num >= 0; num--)
{
if ((Object)(object)clip.DisplayBullets[num] != (Object)null && clip.DisplayBullets[num].activeInHierarchy)
{
return clip.DisplayBullets[num];
}
}
return null;
}
private static ColliderPair FindExistingColliders(GameObject target)
{
ColliderPair colliderPair = new ColliderPair();
BoxCollider[] components = target.GetComponents<BoxCollider>();
foreach (BoxCollider val in components)
{
if ((Object)(object)val != (Object)null)
{
if (!((Collider)val).isTrigger && (Object)(object)colliderPair.SolidCollider == (Object)null)
{
colliderPair.SolidCollider = val;
}
else if (((Collider)val).isTrigger && (Object)(object)colliderPair.TriggerCollider == (Object)null)
{
colliderPair.TriggerCollider = val;
}
}
}
return colliderPair;
}
private static int SetGameObjectArrayToLayer(GameObject[] gameObjects, int layerID)
{
int num = 0;
if (gameObjects == null)
{
return num;
}
foreach (GameObject val in gameObjects)
{
if (!((Object)(object)val != (Object)null))
{
continue;
}
BoxCollider[] components = val.GetComponents<BoxCollider>();
foreach (BoxCollider val2 in components)
{
if ((Object)(object)val2 != (Object)null && ((Component)val2).gameObject.layer != layerID)
{
((Component)val2).gameObject.layer = layerID;
num++;
}
}
val.layer = layerID;
}
return num;
}
public static bool IsFirearmValidForClipAutoLoading(FVRFireArm firearm)
{
if ((Object)(object)firearm != (Object)null && firearm.UsesClips && (Object)(object)firearm.Clip == (Object)null)
{
return (Object)(object)firearm.ClipMountPos != (Object)null;
}
return false;
}
public static bool IsClipValidForAutoLoading(FVRFireArmClip clip, FVRFireArm firearm)
{
if ((Object)(object)clip == (Object)null)
{
return false;
}
if (!IsClipCompatibleWithFirearm(clip, firearm))
{
return false;
}
if (WasRecentlySlapped(clip))
{
return false;
}
if (configRequireSpawnlockedQuickbelt.Value && !((FVRPhysicalObject)clip).m_isSpawnLock)
{
return false;
}
return true;
}
public static void CopyLoadedRounds(FVRFireArmClip sourceClip, FVRFireArmClip targetClip)
{
//IL_0069: 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)
if (sourceClip?.LoadedRounds == null || targetClip?.LoadedRounds == null)
{
return;
}
int num = Mathf.Min(sourceClip.LoadedRounds.Length, targetClip.LoadedRounds.Length);
for (int i = 0; i < num; i++)
{
if (sourceClip.LoadedRounds[i] != null && (Object)(object)sourceClip.LoadedRounds[i].LR_Mesh != (Object)null)
{
targetClip.LoadedRounds[i].LR_Class = sourceClip.LoadedRounds[i].LR_Class;
targetClip.LoadedRounds[i].LR_Mesh = sourceClip.LoadedRounds[i].LR_Mesh;
targetClip.LoadedRounds[i].LR_Material = sourceClip.LoadedRounds[i].LR_Material;
targetClip.LoadedRounds[i].LR_ObjectWrapper = sourceClip.LoadedRounds[i].LR_ObjectWrapper;
}
}
}
public static FVRFireArmClip CreateSpawnlockedClipDuplicate(FVRFireArmClip originalClip)
{
//IL_0027: 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)
if ((Object)(object)((FVRPhysicalObject)(originalClip?)).ObjectWrapper == (Object)null)
{
return null;
}
FVRFireArmClip component = Object.Instantiate<GameObject>(((AnvilAsset)((FVRPhysicalObject)originalClip).ObjectWrapper).GetGameObject(), ((Component)originalClip).transform.position, ((Component)originalClip).transform.rotation).GetComponent<FVRFireArmClip>();
if ((Object)(object)component != (Object)null)
{
CopyLoadedRounds(originalClip, component);
component.m_numRounds = originalClip.m_numRounds;
component.UpdateBulletDisplay();
LogDebug("Created duplicate of spawnlocked clip for loading");
}
return component;
}
public static bool OtherHandHasFirearm(FVRViveHand hand)
{
object obj;
if (hand == null)
{
obj = null;
}
else
{
FVRViveHand otherHand = hand.OtherHand;
obj = ((otherHand != null) ? otherHand.CurrentInteractable : null);
}
if ((Object)obj != (Object)null)
{
return hand.OtherHand.CurrentInteractable is FVRFireArm;
}
return false;
}
public static bool IsClipValidForBulletTrigger(FVRFireArmClip clip)
{
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Invalid comparison between Unknown and I4
if ((Object)(object)clip != (Object)null)
{
return (int)clip.State == 1;
}
return false;
}
public static FVRFireArm FindFirearmInHierarchy(Collider collider)
{
if (collider == null)
{
return null;
}
return ((Component)collider).GetComponentInParent<FVRFireArm>();
}
public static FVRInteractiveObject FindInteractiveObjectInHierarchy(Collider collider)
{
if (collider == null)
{
return null;
}
return ((Component)collider).GetComponentInParent<FVRInteractiveObject>();
}
public static bool IsFirearmValidForInteraction(FVRFireArm firearm, FVRFireArm excludeFirearm = null)
{
if ((Object)(object)firearm != (Object)null && (Object)(object)firearm != (Object)(object)excludeFirearm)
{
return ((FVRInteractiveObject)firearm).IsHeld;
}
return false;
}
public static bool IsInteractiveObjectValidForInteraction(FVRInteractiveObject interactiveObject)
{
if ((Object)(object)interactiveObject != (Object)null && interactiveObject.IsHeld)
{
return !(interactiveObject is FVRFireArm);
}
return false;
}
public static bool IsLayerMatch(GameObject obj, string expectedLayerName)
{
if ((Object)(object)obj != (Object)null)
{
return obj.layer == LayerMask.NameToLayer(expectedLayerName);
}
return false;
}
public static void CleanupTimedDictionary<T>(Dictionary<T, float> dictionary, float maxAge, List<T> keysToRemove)
{
keysToRemove.Clear();
float time = Time.time;
foreach (KeyValuePair<T, float> item in dictionary)
{
if (time - item.Value > maxAge)
{
keysToRemove.Add(item.Key);
}
}
foreach (T item2 in keysToRemove)
{
dictionary.Remove(item2);
}
}
public static void CleanupCooldownDictionary<T>(Dictionary<T, float> dictionary, List<T> keysToRemove)
{
keysToRemove.Clear();
float deltaTime = Time.deltaTime;
List<T> list = new List<T>();
List<float> list2 = new List<float>();
foreach (KeyValuePair<T, float> item in dictionary)
{
float num = item.Value - deltaTime;
if (num <= 0f)
{
keysToRemove.Add(item.Key);
continue;
}
list.Add(item.Key);
list2.Add(num);
}
for (int i = 0; i < list.Count; i++)
{
dictionary[list[i]] = list2[i];
}
foreach (T item2 in keysToRemove)
{
dictionary.Remove(item2);
}
}
public static void EnsureClipPhysicsIntegrity(FVRFireArmClip clip)
{
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)((clip != null) ? ((FVRPhysicalObject)clip).RootRigidbody : null) == (Object)null))
{
bool flag = false;
if (!((FVRPhysicalObject)clip).RootRigidbody.useGravity)
{
((FVRPhysicalObject)clip).RootRigidbody.useGravity = true;
flag = true;
LogDebug("Fixed disabled gravity on clip " + ((Object)clip).name);
}
if (((FVRPhysicalObject)clip).RootRigidbody.isKinematic && !((FVRPhysicalObject)clip).IsKinematicLocked)
{
((FVRPhysicalObject)clip).RootRigidbody.isKinematic = false;
flag = true;
LogDebug("Fixed kinematic state on clip " + ((Object)clip).name);
}
if ((int)((FVRPhysicalObject)clip).RootRigidbody.constraints != 0)
{
((FVRPhysicalObject)clip).RootRigidbody.constraints = (RigidbodyConstraints)0;
flag = true;
LogDebug("Cleared position constraints on clip " + ((Object)clip).name);
}
if (flag && configEnableDebugLogging.Value)
{
Logger.LogInfo((object)("Fixed physics integrity issues on clip " + ((Object)clip).name));
}
}
}
public static bool ShouldProcessClipForDualWield(FVRFireArmClip clip)
{
if ((Object)(object)clip != (Object)null && (Object)(object)((Component)clip).gameObject != (Object)null)
{
return ((Component)clip).gameObject.activeInHierarchy;
}
return false;
}
public static bool ValidateFirearmClipForSlapping(FVRFireArm firearm)
{
if ((Object)(object)firearm == (Object)null)
{
return false;
}
if ((Object)(object)firearm.Clip == (Object)null)
{
if (configEnableDebugLogging.Value)
{
Logger.LogInfo((object)("Firearm slap validation failed: Firearm " + ((Object)firearm).name + " has no clip loaded"));
}
return false;
}
bool flag = false;
int num = 0;
foreach (KeyValuePair<int, FVRFireArmClip> validClipID in validClipIDs)
{
if ((Object)(object)validClipID.Value == (Object)(object)firearm.Clip)
{
flag = true;
num = validClipID.Key;
break;
}
}
if (configEnableDebugLogging.Value)
{
if (flag)
{
Logger.LogInfo((object)$"Firearm slap validation passed: Firearm {((Object)firearm).name} has registered clip {((Object)firearm.Clip).name} with ID {num}");
}
else
{
Logger.LogInfo((object)("Firearm slap validation failed: Clip " + ((Object)firearm.Clip).name + " is not registered for slapping"));
}
}
return flag;
}
}
[HarmonyPatch(typeof(FVRFireArmClip), "Load")]
public class FVRFireArmClipLoadPatch
{
public static bool Prefix(FVRFireArmClip __instance, FVRFireArm fireArm)
{
if (ClipSlap.WasRecentlySlapped(__instance))
{
if (ClipSlap.configEnableDebugLogging.Value)
{
ClipSlap.Logger.LogInfo((object)("Blocked clip " + ((Object)__instance).name + " reattachment - recently slapped"));
}
return false;
}
return true;
}
public static void Postfix(FVRFireArmClip __instance, FVRFireArm fireArm)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Invalid comparison between Unknown and I4
if ((int)__instance.State == 1 && (Object)(object)__instance.FireArm != (Object)null)
{
int num = ClipSlap.RegisterClipForSlapping(__instance);
ClipSlap.RegisterClipTriggers(__instance);
if (ClipSlap.configEnableDebugLogging.Value)
{
ClipSlap.Logger.LogInfo((object)$"Auto-registered clip {((Object)__instance).name} with ID {num} upon loading into {((Object)fireArm).name}");
}
if (((FVRInteractiveObject)__instance.FireArm).IsHeld)
{
ClipSlap.TrackClipForInteraction(__instance, __instance.FireArm);
}
ClipSlap.CreateTemporaryBulletCollider(__instance);
if (ClipSlap.configEnableDebugLogging.Value)
{
ClipSlap.Logger.LogInfo((object)$"Clip {((Object)__instance).name} loaded into {((Object)__instance.FireArm).name} (dual-wield: {ClipSlap.IsDualWielding()})");
}
}
}
}
[HarmonyPatch(typeof(FVRFireArmClip), "Release")]
public class FVRFireArmClipReleasePatch
{
public static void Prefix(FVRFireArmClip __instance)
{
ClipSlap.UnregisterClipForSlapping(__instance);
ClipSlap.UnregisterClipTriggers(__instance);
if (ClipSlap.configEnableDebugLogging.Value)
{
ClipSlap.Logger.LogInfo((object)("Auto-unregistered clip " + ((Object)__instance).name + " upon release from firearm"));
}
ClipSlap.RemoveTemporaryBulletCollider(__instance);
ClipSlap.RestoreClipCollidersFromDualWield(__instance);
ClipSlap.EnsureClipPhysicsIntegrity(__instance);
ClipSlap.RemoveClipFromCache(__instance);
}
}
[HarmonyPatch(typeof(FVRFireArmClip), "UpdateBulletDisplay")]
public class FVRFireArmClipUpdateBulletDisplayPatch
{
public static void Postfix(FVRFireArmClip __instance)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Invalid comparison between Unknown and I4
if ((int)__instance.State != 1 || (Object)(object)__instance.FireArm == (Object)null)
{
return;
}
if (ClipSlap.configEnableDebugLogging.Value)
{
ClipSlap.Logger.LogInfo((object)$"UpdateBulletDisplay patch triggered for {((Object)__instance).name}, rounds: {__instance.m_numRounds}");
}
ClipSlap.RemoveTemporaryBulletCollider(__instance);
if (__instance.HasARound())
{
ClipSlap.CreateTemporaryBulletCollider(__instance);
if (ClipSlap.configEnableDebugLogging.Value)
{
ClipSlap.Logger.LogInfo((object)("Created new bullet collider on top bullet for " + ((Object)__instance).name));
}
}
else if (ClipSlap.configEnableDebugLogging.Value)
{
ClipSlap.Logger.LogInfo((object)("No bullets left in " + ((Object)__instance).name + ", no collider created"));
}
}
}
public class BulletTriggerDetector : MonoBehaviour
{
public FVRFireArmClip parentClip;
private Dictionary<Collider, float> _cooldowns;
private const float CooldownTime = 0.1f;
private void Awake()
{
_cooldowns = new Dictionary<Collider, float>();
}
public void OnTriggerEnter(Collider other)
{
//IL_023d: Unknown result type (might be due to invalid IL or missing references)
//IL_0243: Invalid comparison between Unknown and I4
//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
//IL_01c2: Invalid comparison between Unknown and I4
if (_cooldowns.ContainsKey(other) && Time.time < _cooldowns[other])
{
return;
}
_cooldowns[other] = Time.time + 0.1f;
if (ClipSlap.configEnableDebugLogging.Value)
{
ManualLogSource logger = ClipSlap.Logger;
string[] obj = new string[6] { "BulletTriggerDetector on ", null, null, null, null, null };
FVRFireArmClip obj2 = parentClip;
obj[1] = ((obj2 != null) ? ((Object)obj2).name : null) ?? "null";
obj[2] = ": OnTriggerEnter with ";
obj[3] = ((Object)other).name;
obj[4] = " on layer ";
obj[5] = LayerMask.LayerToName(((Component)other).gameObject.layer);
logger.LogInfo((object)string.Concat(obj));
}
if (!ClipSlap.IsClipValidForBulletTrigger(parentClip))
{
ClipSlap.LogDebug("BulletTriggerDetector: Skipping - parentClip null or not locked");
return;
}
if (ClipSlap.IsLayerMatch(((Component)other).gameObject, "Default"))
{
FVRFireArm val = ClipSlap.FindFirearmInHierarchy(other);
if (ClipSlap.IsFirearmValidForInteraction(val, parentClip.FireArm))
{
ClipSlap.LogDebug("BulletTriggerDetector: Detected firearm interaction with " + ((Object)val).name);
ClipSlap.HandleBulletTriggerFirearmInteraction(parentClip, val, other);
}
else
{
FVRInteractiveObject val2 = ClipSlap.FindInteractiveObjectInHierarchy(other);
if (ClipSlap.IsInteractiveObjectValidForInteraction(val2))
{
ClipSlap.LogDebug("BulletTriggerDetector: Detected interactive object interaction with " + ((Object)val2).name);
ClipSlap.HandleBulletTriggerInteractiveObjectInteraction(parentClip, val2, other);
}
}
}
BulletTriggerDetector component = ((Component)other).GetComponent<BulletTriggerDetector>();
if (ClipSlap.configEnableDebugLogging.Value)
{
ClipSlap.Logger.LogInfo((object)$"BulletTriggerDetector: Checking for other BulletTriggerDetector on {((Object)other).name} - found: {(Object)(object)component != (Object)null}");
if ((Object)(object)component != (Object)null)
{
ManualLogSource logger2 = ClipSlap.Logger;
FVRFireArmClip obj3 = component.parentClip;
string arg = ((obj3 != null) ? ((Object)obj3).name : null) ?? "null";
FVRFireArmClip obj4 = component.parentClip;
logger2.LogInfo((object)$"BulletTriggerDetector: Other detector parent clip: {arg}, locked: {obj4 != null && (int)obj4.State == 1}");
ClipSlap.Logger.LogInfo((object)$"BulletTriggerDetector: Same clip check - this: {ClipSlap.GetClipID(parentClip)}, other: {ClipSlap.GetClipID(component.parentClip)}");
}
}
if ((Object)(object)component != (Object)null && (Object)(object)component.parentClip != (Object)null && (Object)(object)component.parentClip != (Object)(object)parentClip && (int)component.parentClip.State == 1 && ClipSlap.GetClipID(component.parentClip) != ClipSlap.GetClipID(parentClip))
{
if (ClipSlap.configEnableDebugLogging.Value)
{
ClipSlap.Logger.LogInfo((object)$"BulletTriggerDetector: Initiating clip-to-clip interaction between {((Object)parentClip).name} and {((Object)component.parentClip).name}");
}
ClipSlap.HandleBulletTriggerClipInteraction(parentClip, component.parentClip);
}
else if (ClipSlap.configEnableDebugLogging.Value && (Object)(object)component != (Object)null)
{
ClipSlap.Logger.LogInfo((object)"BulletTriggerDetector: Skipping interaction - same clip or invalid state");
}
}
private void Update()
{
if (_cooldowns.Count <= 0)
{
return;
}
List<Collider> list = new List<Collider>();
foreach (KeyValuePair<Collider, float> cooldown in _cooldowns)
{
if (Time.time > cooldown.Value)
{
list.Add(cooldown.Key);
}
}
foreach (Collider item in list)
{
_cooldowns.Remove(item);
}
}
}
[HarmonyPatch(typeof(FVRViveHand), "TestQuickBeltDistances")]
public class FVRViveHandQuickBeltPatch
{
public static void Postfix(FVRViveHand __instance)
{
//IL_0117: 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_0164: Unknown result type (might be due to invalid IL or missing references)
if (!ClipSlap.configAutoLoadClipsFromQuickbelt.Value || (Object)(object)__instance.CurrentInteractable == (Object)null || !(__instance.CurrentInteractable is FVRFireArm))
{
return;
}
FVRInteractiveObject currentInteractable = __instance.CurrentInteractable;
FVRFireArm val = (FVRFireArm)(object)((currentInteractable is FVRFireArm) ? currentInteractable : null);
if ((Object)(object)val == (Object)null || !val.UsesClips || (Object)(object)val.Clip != (Object)null || (Object)(object)val.ClipMountPos == (Object)null)
{
return;
}
if (!(val is Handgun))
{
if (ClipSlap.configEnableDebugLogging.Value)
{
ClipSlap.Logger.LogInfo((object)("Quickbelt auto-loading blocked: " + ((Object)val).name + " is not a Handgun (type: " + ((object)val).GetType().Name + ")"));
}
return;
}
FVRViveHand otherHand = __instance.OtherHand;
bool flag = (Object)(object)((otherHand != null) ? otherHand.CurrentInteractable : null) != (Object)null && __instance.OtherHand.CurrentInteractable is FVRFireArm;
if ((!ClipSlap.configAllowLoadingWithOneFirearm.Value && !flag) || GM.CurrentPlayerBody?.QBSlots_Internal == null)
{
return;
}
Vector3 position = val.ClipMountPos.position;
FVRQuickBeltSlot val2 = null;
foreach (FVRQuickBeltSlot item in GM.CurrentPlayerBody.QBSlots_Internal)
{
if ((Object)(object)item != (Object)null && ((Component)item).gameObject.activeInHierarchy && (Object)(object)item.CurObject != (Object)null && item.IsPointInsideMe(position))
{
val2 = item;
break;
}
}
if ((Object)(object)val2 == (Object)null)
{
return;
}
FVRPhysicalObject curObject = val2.CurObject;
FVRFireArmClip val3 = (FVRFireArmClip)(object)((curObject is FVRFireArmClip) ? curObject : null);
if ((Object)(object)val3 == (Object)null || !ClipSlap.IsClipCompatibleWithFirearm(val3, val) || ClipSlap.WasRecentlySlapped(val3) || (ClipSlap.configRequireSpawnlockedQuickbelt.Value && !((FVRPhysicalObject)val3).m_isSpawnLock))
{
return;
}
if (ClipSlap.configEnableDebugLogging.Value)
{
ClipSlap.Logger.LogInfo((object)("Auto-loading clip " + ((Object)val3).name + " from hovered quickbelt slot into firearm " + ((Object)val).name));
}
FVRFireArmClip val4;
if (((FVRPhysicalObject)val3).m_isSpawnLock)
{
val4 = ClipSlap.CreateSpawnlockedClipDuplicate(val3);
if ((Object)(object)val4 == (Object)null)
{
return;
}
}
else
{
val4 = val3;
((FVRPhysicalObject)val3).ClearQuickbeltState();
ClipSlap.LogDebug("Using original clip from quickbelt slot");
}
val4.Load(val);
}
}
[HarmonyPatch(typeof(FVRFireArmClip), "FVRFixedUpdate")]
public class FVRFireArmClipFixedUpdatePatch
{
public static Dictionary<FVRFireArmClip, BoxCollider> temporaryBulletColliders = new Dictionary<FVRFireArmClip, BoxCollider>();
public static Dictionary<FVRFireArmClip, BoxCollider> temporaryBulletTriggers = new Dictionary<FVRFireArmClip, BoxCollider>();
public static Dictionary<string, float> processedClipPairsThisFrame = new Dictionary<string, float>();
public static Dictionary<string, float> clipPairCooldowns = new Dictionary<string, float>();
private static float lastFixedUpdateTime = -1f;
public static void Postfix(FVRFireArmClip __instance)
{
//IL_007b: Unknown result type (might be due to invalid IL or missing references)
//IL_0081: Invalid comparison between Unknown and I4
if (processedClipPairsThisFrame.Count > 0)
{
List<string> keysToRemove = new List<string>();
ClipSlap.CleanupTimedDictionary(processedClipPairsThisFrame, 1f, keysToRemove);
}
if (Time.fixedTime != lastFixedUpdateTime)
{
processedClipPairsThisFrame.Clear();
lastFixedUpdateTime = Time.fixedTime;
}
if (clipPairCooldowns.Count > 0)
{
List<string> keysToRemove2 = new List<string>();
ClipSlap.CleanupCooldownDictionary(clipPairCooldowns, keysToRemove2);
}
if ((ClipSlap.configFirearmsCanPushDownClipRounds.Value || ClipSlap.configClipsCanPressOtherClips.Value) && (int)__instance.State == 1)
{
_ = (Object)(object)__instance.FireArm == (Object)null;
}
}
}
[HarmonyPatch(typeof(FVRFireArm), "FVRFixedUpdate")]
public class FVRFireArmDualWieldPatch
{
public static void Postfix(FVRFireArm __instance)
{
ClipSlap.UpdateDualWieldState(ClipSlap.BothHandsHaveFirearms() || ClipSlap.HandsHaveMixedInteractables());
}
}
[HarmonyPatch(typeof(FVRFireArm), "BeginInteraction")]
public class FVRFireArmBeginInteractionDualWieldPatch
{
public static void Postfix(FVRFireArm __instance, FVRViveHand hand)
{
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Invalid comparison between Unknown and I4
if ((Object)(object)__instance.Clip != (Object)null && (int)__instance.Clip.State == 1)
{
ClipSlap.TrackClipForInteraction(__instance.Clip, __instance);
}
ClipSlap.BothHandsHaveFirearms();
}
}
[HarmonyPatch(typeof(FVRFireArm), "EndInteraction")]
public class FVRFireArmEndInteractionDualWieldPatch
{
public static void Postfix(FVRFireArm __instance, FVRViveHand hand)
{
if ((Object)(object)__instance.Clip != (Object)null)
{
ClipSlap.UntrackClipFromInteraction(__instance.Clip, __instance);
}
ClipSlap.BothHandsHaveFirearms();
}
}
[HarmonyPatch(typeof(FVRFireArm), "EndInteractionIntoInventorySlot")]
public class FVRFireArmEndInteractionIntoInventorySlotDualWieldPatch
{
public static void Postfix(FVRFireArm __instance, FVRViveHand hand, FVRQuickBeltSlot slot)
{
if ((Object)(object)__instance.Clip != (Object)null)
{
ClipSlap.UntrackClipFromInteraction(__instance.Clip, __instance);
}
ClipSlap.BothHandsHaveFirearms();
}
}
[HarmonyPatch(typeof(FVRFireArm), "Awake")]
public class FVRFireArmAwakeClipSlapPatch
{
public static void Postfix(FVRFireArm __instance)
{
if (!Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<ClipSlap.FirearmClipSlapDetector>()))
{
((Component)__instance).gameObject.AddComponent<ClipSlap.FirearmClipSlapDetector>();
if (ClipSlap.configEnableDebugLogging.Value)
{
ClipSlap.Logger.LogInfo((object)$"Added FirearmClipSlapDetector to {((Object)__instance).name}");
}
}
}
}
[HarmonyPatch(typeof(FVRInteractiveObject), "Awake")]
public class FVRInteractiveObjectAwakeClipSlapPatch
{
public static void Postfix(FVRInteractiveObject __instance)
{
if (!(__instance is FVRFireArm) && !Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<ClipSlap.InteractiveObjectClipSlapDetector>()))
{
((Component)__instance).gameObject.AddComponent<ClipSlap.InteractiveObjectClipSlapDetector>();
if (ClipSlap.configEnableDebugLogging.Value)
{
ClipSlap.Logger.LogInfo((object)$"Added InteractiveObjectClipSlapDetector to {((Object)__instance).name}");
}
}
}
}
[HarmonyPatch(typeof(FVRInteractiveObject), "BeginInteraction")]
public class FVRInteractiveObjectBeginInteractionDualWieldPatch
{
public static void Postfix(FVRInteractiveObject __instance, FVRViveHand hand)
{
ClipSlap.UpdateDualWieldState(ClipSlap.BothHandsHaveFirearms() || ClipSlap.HandsHaveMixedInteractables());
}
}
[HarmonyPatch(typeof(FVRInteractiveObject), "EndInteraction")]
public class FVRInteractiveObjectEndInteractionDualWieldPatch
{
public static void Postfix(FVRInteractiveObject __instance, FVRViveHand hand)
{
ClipSlap.UpdateDualWieldState(ClipSlap.BothHandsHaveFirearms() || ClipSlap.HandsHaveMixedInteractables());
}
}
[HarmonyPatch(typeof(FVRViveHand), "OnTriggerEnter")]
public class FVRViveHandTriggerEnterPatch
{
public static void Postfix(FVRViveHand __instance, Collider collider)
{
if (!IsControllerObject(collider))
{
ClipSlap.CheckForClipSlap(__instance, collider);
}
}
private static bool IsControllerObject(Collider collider)
{
if ((Object)(object)collider == (Object)null)
{
return false;
}
string name = ((Object)collider).name;
if (!name.Contains("Controller") && !name.Equals("Controller (right)") && !name.Equals("Controller (left)") && !name.Contains("Hand"))
{
return name.Contains("Tracker");
}
return true;
}
}