OliveRave/UnityProject/Assets/CyanEmu/Scripts/CyanEmuPickupHelper.cs

250 lines
7.9 KiB
C#

using UnityEngine;
using VRC.SDKBase;
namespace VRCPrefabs.CyanEmu
{
[AddComponentMenu("")]
public class CyanEmuPickupHelper : MonoBehaviour, ICyanEmuInteractable
{
// If the user releases the mouse button before this time, it will not fire on use up.
private const float INITIAL_PICKUP_DURATION_ = 0.5f;
private const float MAX_PICKUP_DISTANCE_ = 0.25f;
private static Quaternion GRIP_OFFSET_ROTATION_ = Quaternion.Euler(0, 45, 0);
private static Quaternion GUN_OFFSET_ROTATION_ = Quaternion.Euler(0, -45, 0);
private Rigidbody rigidbody_;
private VRC_Pickup pickup_;
private bool isHeld_;
private Vector3 positionOffset_;
private Quaternion rotationOffset_ = Quaternion.identity;
private bool initialGrab_;
private float grabActionStartTime_;
private float dropActionStartTime_;
public static void InitializePickup(VRC_Pickup pickup)
{
CyanEmuPickupHelper previousHelper = pickup.gameObject.GetComponent<CyanEmuPickupHelper>();
if (previousHelper != null)
{
DestroyImmediate(previousHelper);
pickup.LogWarning("Destroying old pickup helper on object: " + VRC.Tools.GetGameObjectPath(pickup.gameObject));
}
CyanEmuPickupHelper helper = pickup.gameObject.AddComponent<CyanEmuPickupHelper>();
helper.SetPickup(pickup);
}
public static void ForceDrop(VRC_Pickup pickup)
{
CyanEmuPickupHelper helper = pickup.GetComponent<CyanEmuPickupHelper>();
helper.Drop();
}
public static VRCPlayerApi GetCurrentPlayer(VRC_Pickup pickup)
{
CyanEmuPickupHelper helper = pickup.GetComponent<CyanEmuPickupHelper>();
if (helper.isHeld_)
{
return Networking.LocalPlayer;
}
return null;
}
public static VRC_Pickup.PickupHand GetPickupHand(VRC_Pickup pickup)
{
CyanEmuPickupHelper helper = pickup.GetComponent<CyanEmuPickupHelper>();
if (helper.isHeld_)
{
return VRC_Pickup.PickupHand.Right;
}
return VRC_Pickup.PickupHand.None;
}
private void SetPickup(VRC_Pickup pickup)
{
pickup_ = pickup;
rigidbody_ = GetComponent<Rigidbody>();
}
public Rigidbody GetRigidbody()
{
return rigidbody_;
}
public float GetProximity()
{
return pickup_.proximity;
}
public bool CanInteract()
{
return pickup_.pickupable;
}
public string GetInteractText()
{
if (!string.IsNullOrEmpty(pickup_.InteractionText))
{
return pickup_.InteractionText;
}
return "Hold to Grab";
}
public void Interact()
{
Pickup();
}
public void UpdatePosition(Transform root, bool force = false)
{
if (rigidbody_.isKinematic || force)
{
transform.position = root.transform.position + root.TransformDirection(positionOffset_);
transform.rotation = root.transform.rotation * rotationOffset_;
}
}
public void UpdateUse()
{
int dropIndex = 0;
if (pickup_.AutoHold == VRC_Pickup.AutoHoldMode.Yes)
{
dropIndex = 1;
if (Input.GetMouseButtonDown(dropIndex))
{
dropActionStartTime_ = Time.time;
}
float grabDuration = Time.time - grabActionStartTime_;
if (grabDuration > INITIAL_PICKUP_DURATION_)
{
if (Input.GetMouseButtonDown(0) || (initialGrab_ && Input.GetMouseButton(0)))
{
this.Log("Pickup Use Down");
gameObject.OnPickupUseDown();
initialGrab_ = false;
}
if (Input.GetMouseButtonUp(0))
{
this.Log("Pickup Use Up");
gameObject.OnPickupUseUp();
}
}
}
if (Input.GetMouseButtonUp(dropIndex))
{
Drop();
}
}
public void Pickup()
{
if (isHeld_)
{
return;
}
isHeld_ = true;
grabActionStartTime_ = Time.time;
initialGrab_ = true;
gameObject.OnPickup();
CyanEmuPlayerController player = CyanEmuPlayerController.instance;
if (player == null)
{
this.LogWarning("Unable to pickup object when there is no player!");
return;
}
this.Log("Picking up object " + name);
Networking.SetOwner(Networking.LocalPlayer, gameObject);
// Calculate offest
Transform pickupHoldPoint = null;
Quaternion offsetRotation = Quaternion.identity;
if (pickup_.orientation == VRC_Pickup.PickupOrientation.Grip && pickup_.ExactGrip != null)
{
pickupHoldPoint = pickup_.ExactGrip;
offsetRotation = GRIP_OFFSET_ROTATION_;
}
else if (pickup_.orientation == VRC_Pickup.PickupOrientation.Gun && pickup_.ExactGun != null)
{
pickupHoldPoint = pickup_.ExactGun;
offsetRotation = GUN_OFFSET_ROTATION_;
}
Transform arm = player.GetArmTransform();
// Grab as if no pickup point
if (pickupHoldPoint == null)
{
rotationOffset_ = Quaternion.Inverse(arm.rotation) * transform.rotation;
positionOffset_ = arm.InverseTransformDirection(transform.position - arm.position);
float mag = positionOffset_.magnitude;
if (mag > MAX_PICKUP_DISTANCE_ && pickup_.orientation == VRC_Pickup.PickupOrientation.Any)
{
positionOffset_ = positionOffset_.normalized * MAX_PICKUP_DISTANCE_;
}
}
else
{
rotationOffset_ = offsetRotation * Quaternion.Inverse(Quaternion.Inverse(transform.rotation) * pickupHoldPoint.rotation);
positionOffset_ = rotationOffset_ * transform.InverseTransformDirection(transform.position - pickupHoldPoint.position);
}
player.PickupObject(this);
}
public void Drop()
{
if (!isHeld_)
{
return;
}
this.Log("Dropping object " + name);
isHeld_ = false;
initialGrab_ = false;
gameObject.OnDrop();
CyanEmuPlayerController player = CyanEmuPlayerController.instance;
if (player == null)
{
return;
}
player.DropObject(this);
// Calculate throw velocity
if (!rigidbody_.isKinematic && pickup_.AutoHold == VRC_Pickup.AutoHoldMode.Yes)
{
float holdDuration = Mathf.Clamp(Time.time - dropActionStartTime_, 0, 3);
if (holdDuration > 0.2f)
{
Transform rightArm = player.GetArmTransform();
Vector3 throwForce = rightArm.forward * (holdDuration * 500 * pickup_.ThrowVelocityBoostScale);
rigidbody_.AddForce(throwForce);
this.Log("Adding throw force: "+ throwForce);
}
}
}
public string PickupText()
{
// TODO
return "";
}
}
}