using System; using UnityEngine; using VRC.SDKBase; namespace VRC.SDK3.ClientSim { [AddComponentMenu("")] public class ClientSimPickupHelper : ClientSimBehaviour, IClientSimPickupable { private Rigidbody _rigidbody; private VRC_Pickup _pickup; private VRCPlayerApi _heldPlayer; private VRC_Pickup.PickupHand _heldHand; private Action _forceDropHandler; public static void InitializePickup(VRC_Pickup pickup) { ClientSimPickupHelper previousHelper = pickup.gameObject.GetComponent(); if (previousHelper != null) { DestroyImmediate(previousHelper); pickup.LogWarning($"Destroying old pickup helper on object: {Tools.GetGameObjectPath(pickup.gameObject)}"); } ClientSimPickupHelper helper = pickup.gameObject.AddComponent(); helper.SetPickup(pickup); } public static void ForceDrop(VRC_Pickup pickup) { ClientSimPickupHelper helper = pickup.GetComponent(); if (helper) { helper._forceDropHandler?.Invoke(helper); } } public static VRCPlayerApi GetCurrentPlayer(VRC_Pickup pickup) { ClientSimPickupHelper helper = pickup.GetComponent(); if (!helper) { return null; } return helper.GetHoldingPlayer(); } public static VRC_Pickup.PickupHand GetPickupHand(VRC_Pickup pickup) { ClientSimPickupHelper helper = pickup.GetComponent(); if (helper) { return helper._heldHand; } return VRC_Pickup.PickupHand.None; } public static void PickupDestroy(VRC_Pickup pickup) { ForceDrop(pickup); } public static void PlayHapticForPickup(VRC_Pickup obj, float duration, float amplitude, float frequency) { VRCPlayerApi player = obj.currentPlayer; VRC_Pickup.PickupHand hand = obj.currentHand; if (Utilities.IsValid(player) && hand != VRC_Pickup.PickupHand.None) { player.PlayHapticEventInHand(obj.currentHand, duration, amplitude, frequency); } } private void SetPickup(VRC_Pickup pickup) { _pickup = pickup; _rigidbody = GetComponent(); } #region IClientSimInteractible public float GetProximity() { return _pickup.proximity; } public bool CanInteract() { return _pickup.pickupable; } public string GetInteractText() { if (!string.IsNullOrEmpty(_pickup.InteractionText)) { return _pickup.InteractionText; } return AutoHold() ? "Equip" : "Hold to Grab"; } public Vector3 GetInteractTextPlacement() { // VRChatBug: Tooltips always ignore the tooltipPlacement transform and instead place the tooltip at the top // of the first collider on the object. return ClientSimTooltip.GetToolTipPosition(gameObject); } public void Interact() { } #endregion #region IClientSimPickupable public void Pickup(VRCPlayerApi player, VRC_Pickup.PickupHand heldHand, Action forceDropHandler) { if (IsHeld()) { return; } _heldPlayer = player; _heldHand = heldHand; _forceDropHandler = forceDropHandler; } public void Drop(VRCPlayerApi player) { if (GetHoldingPlayer() != player) { return; } _heldPlayer = null; _heldHand = VRC_Pickup.PickupHand.None; _forceDropHandler = null; } public bool IsHeld() => Utilities.IsValid(_heldPlayer); public VRCPlayerApi GetHoldingPlayer() => IsHeld() ? _heldPlayer : null; public bool AutoHold() => _pickup.AutoHold is VRC_Pickup.AutoHoldMode.Yes or VRC_Pickup.AutoHoldMode.Sometimes; public GameObject GetGameObject() => gameObject; public Transform GetTransform() => transform; public Rigidbody GetRigidbody() => _rigidbody; public VRC_Pickup GetPickup() => _pickup; public VRC_Pickup.PickupOrientation GetOrientation() => _pickup.orientation; public Transform GetGunLocation() => _pickup.ExactGun; public Transform GetGripLocation() => _pickup.ExactGrip; public float GetThrowVelocityBoostScale() => _pickup.ThrowVelocityBoostScale; public bool AllowManipulation() => _pickup.allowManipulationWhenEquipped; #endregion // TODO display use text after picking up a pickup. public string PickupText() { return _pickup.UseText; } } }