Files
2026-06-07 16:58:24 +01:00

173 lines
5.1 KiB
C#

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<IClientSimPickupable> _forceDropHandler;
public static void InitializePickup(VRC_Pickup pickup)
{
ClientSimPickupHelper previousHelper = pickup.gameObject.GetComponent<ClientSimPickupHelper>();
if (previousHelper != null)
{
DestroyImmediate(previousHelper);
pickup.LogWarning($"Destroying old pickup helper on object: {Tools.GetGameObjectPath(pickup.gameObject)}");
}
ClientSimPickupHelper helper = pickup.gameObject.AddComponent<ClientSimPickupHelper>();
helper.SetPickup(pickup);
}
public static void ForceDrop(VRC_Pickup pickup)
{
ClientSimPickupHelper helper = pickup.GetComponent<ClientSimPickupHelper>();
if (helper)
{
helper._forceDropHandler?.Invoke(helper);
}
}
public static VRCPlayerApi GetCurrentPlayer(VRC_Pickup pickup)
{
ClientSimPickupHelper helper = pickup.GetComponent<ClientSimPickupHelper>();
if (!helper)
{
return null;
}
return helper.GetHoldingPlayer();
}
public static VRC_Pickup.PickupHand GetPickupHand(VRC_Pickup pickup)
{
ClientSimPickupHelper helper = pickup.GetComponent<ClientSimPickupHelper>();
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<Rigidbody>();
}
#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<IClientSimPickupable> 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;
}
}
}