Added Unity project files
This commit is contained in:
@ -0,0 +1,68 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
/// <summary>
|
||||
/// This class is responsible for saying if an object can be interacted with given the distance.
|
||||
/// </summary>
|
||||
public class ClientSimInteractManager : IClientSimInteractManager
|
||||
{
|
||||
public const float INTERACT_SCALE = 1.25f;
|
||||
|
||||
private readonly IClientSimTrackingProvider _trackingScaleProvider;
|
||||
private readonly IClientSimPlayerPickupData _pickupData;
|
||||
|
||||
public ClientSimInteractManager(
|
||||
IClientSimTrackingProvider trackingScaleProvider,
|
||||
IClientSimPlayerPickupData pickupData)
|
||||
{
|
||||
_trackingScaleProvider = trackingScaleProvider;
|
||||
_pickupData = pickupData;
|
||||
}
|
||||
|
||||
private float CalculateInteractDistanceFormula()
|
||||
{
|
||||
return _trackingScaleProvider.GetTrackingScale() * INTERACT_SCALE;
|
||||
}
|
||||
|
||||
public IClientSimInteractable GetFirstInteractable(GameObject obj, float distance)
|
||||
{
|
||||
foreach (var interactable in obj.GetComponents<IClientSimInteractable>())
|
||||
{
|
||||
if (CanInteract(interactable, distance))
|
||||
{
|
||||
return interactable;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool CanInteract(IClientSimInteractable interactable, float distance)
|
||||
{
|
||||
if (interactable is IClientSimPickupable && !_pickupData.GetPickupsEnabled())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
float proximityCalculation = CalculateInteractDistanceFormula() + interactable.GetProximity();
|
||||
return interactable.CanInteract() && distance <= proximityCalculation;
|
||||
}
|
||||
|
||||
public List<IClientSimInteractable> Interact(GameObject obj, float distance)
|
||||
{
|
||||
List<IClientSimInteractable> interacts = new List<IClientSimInteractable>();
|
||||
foreach (var interactable in obj.GetComponents<IClientSimInteractable>())
|
||||
{
|
||||
if (CanInteract(interactable, distance))
|
||||
{
|
||||
interactable.Interact();
|
||||
interacts.Add(interactable);
|
||||
}
|
||||
}
|
||||
|
||||
return interacts;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 543fc4d5c13242e499030fe4fc23b119
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,66 @@
|
||||
using UnityEngine;
|
||||
using VRC.SDKBase;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
/// <summary>
|
||||
/// Class used to hold information related to the last raycast. This is created in ClientSimRaycaster.
|
||||
/// </summary>
|
||||
public class ClientSimRaycastResults
|
||||
{
|
||||
public readonly Ray ray;
|
||||
public readonly GameObject hitObject;
|
||||
public readonly Vector3 hitPoint;
|
||||
public readonly Vector3 hitNormal;
|
||||
public readonly float distance;
|
||||
public readonly VRC_UiShape uiShape;
|
||||
public readonly IClientSimInteractable interactable;
|
||||
|
||||
public ClientSimRaycastResults(Ray ray, float distance)
|
||||
{
|
||||
this.ray = ray;
|
||||
hitPoint = ray.GetPoint(distance);
|
||||
this.distance = distance;
|
||||
|
||||
hitNormal = Vector3.zero;
|
||||
|
||||
hitObject = null;
|
||||
uiShape = null;
|
||||
interactable = null;
|
||||
}
|
||||
|
||||
public ClientSimRaycastResults(Ray ray, RaycastHit hit)
|
||||
{
|
||||
this.ray = ray;
|
||||
hitObject = hit.collider.gameObject;
|
||||
hitPoint = hit.point;
|
||||
distance = hit.distance;
|
||||
hitNormal = hit.normal;
|
||||
|
||||
uiShape = null;
|
||||
interactable = null;
|
||||
}
|
||||
|
||||
// TODO create results from SphereOverlap
|
||||
|
||||
public ClientSimRaycastResults(Ray ray, RaycastHit hit, VRC_UiShape shape) : this(ray, hit)
|
||||
{
|
||||
uiShape = shape;
|
||||
}
|
||||
|
||||
public ClientSimRaycastResults(Ray ray, RaycastHit hit, IClientSimInteractable interactable) : this(ray, hit)
|
||||
{
|
||||
this.interactable = interactable;
|
||||
}
|
||||
|
||||
public IClientSimPickupable GetPickupable()
|
||||
{
|
||||
if (interactable != null)
|
||||
{
|
||||
return hitObject.GetComponent<IClientSimPickupable>();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0d50a8c6a5f9bbd40bd24e97775aa311
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,124 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using VRC.SDKBase;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
/// <summary>
|
||||
/// Performs the physics raycast to find objects that can be interacted with.
|
||||
/// </summary>
|
||||
public class ClientSimRaycaster
|
||||
{
|
||||
private const int MAX_INTERACT_RESULTS = 100;
|
||||
private const float MAX_INTERACT_DISTANCE = 100;
|
||||
|
||||
private static readonly RaycastHit[] _raycastHitBuffer = new RaycastHit[MAX_INTERACT_RESULTS];
|
||||
private static readonly RaycastHitComparer _raycastHitComparerInstance = new RaycastHitComparer();
|
||||
|
||||
|
||||
private readonly IClientSimRayProvider _rayProvider;
|
||||
private readonly IClientSimInteractiveLayerProvider _interactiveLayerProvider;
|
||||
private readonly IClientSimInteractManager _interactManager;
|
||||
|
||||
// TODO pass in parameter if should perform overlap sphere at ray origin (eg Desktop should not but VR should)
|
||||
public ClientSimRaycaster(
|
||||
IClientSimRayProvider rayProvider,
|
||||
IClientSimInteractiveLayerProvider interactiveLayerProvider,
|
||||
IClientSimInteractManager interactManager)
|
||||
{
|
||||
_rayProvider = rayProvider;
|
||||
_interactiveLayerProvider = interactiveLayerProvider;
|
||||
_interactManager = interactManager;
|
||||
}
|
||||
|
||||
public ClientSimRaycastResults CheckForInteracts()
|
||||
{
|
||||
Ray ray = _rayProvider.GetRay();
|
||||
int layers = _interactiveLayerProvider.GetInteractiveLayers();
|
||||
|
||||
// TODO use Physics.OverlapSphere to check for objects close to the ray origin.
|
||||
// TODO make sure to scale based on tracking scale.
|
||||
|
||||
// Note: This method has a chance of failing to find objects that move but do not have rigidbodies.
|
||||
int hitCount = Physics.RaycastNonAlloc(
|
||||
ray,
|
||||
_raycastHitBuffer,
|
||||
MAX_INTERACT_DISTANCE,
|
||||
layers);
|
||||
|
||||
Array.Sort(_raycastHitBuffer, 0, hitCount, _raycastHitComparerInstance);
|
||||
|
||||
// Go through all colliders in order of distance and stop after find something
|
||||
// interactable, or a physical collider blocking everything else.
|
||||
for (int curHit = 0; curHit < hitCount; ++curHit)
|
||||
{
|
||||
// VRChatBug: This implementation ignores the bug where trigger colliders extend a player's proximity.
|
||||
// https://feedback.vrchat.com/sdk-bug-reports/p/incorrect-proximity-calculation-when-aiming-through-trigger-colliders
|
||||
|
||||
RaycastHit hit = _raycastHitBuffer[curHit];
|
||||
GameObject hitObject = hit.collider.gameObject;
|
||||
|
||||
// UIShapes are higher priority than interacts/pickups.
|
||||
VRC_UiShape shape = hitObject.GetComponent<VRC_UiShape>();
|
||||
if (shape != null)
|
||||
{
|
||||
return new ClientSimRaycastResults(ray, hit, shape);
|
||||
}
|
||||
|
||||
if (ShouldIgnoreObject(hitObject))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
IClientSimInteractable interactable = _interactManager.GetFirstInteractable(hitObject, hit.distance);
|
||||
if (interactable != null)
|
||||
{
|
||||
return new ClientSimRaycastResults(ray, hit, interactable);
|
||||
}
|
||||
|
||||
// Object found but can't interact with it.
|
||||
if (!hit.collider.isTrigger)
|
||||
{
|
||||
return new ClientSimRaycastResults(ray, hit);
|
||||
}
|
||||
}
|
||||
|
||||
return new ClientSimRaycastResults(ray, MAX_INTERACT_DISTANCE);
|
||||
}
|
||||
|
||||
private bool ShouldIgnoreObject(GameObject hitObject)
|
||||
{
|
||||
if (hitObject == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Do not allow raycasting other players. ClientSim has no reason to select players, so ignore their colliders.
|
||||
if (VRCPlayerApi.GetPlayerByGameObject(hitObject) != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Do not allow raycasting occupied stations
|
||||
// VRChatBug: Raycasting to your own station appears to not work properly in Udon.
|
||||
// Remove the last check on if the player is local to remove this.
|
||||
// Since only local players can enter stations in ClientSim, this code will not be needed unless a method is introduced for remote players to enter stations.
|
||||
IClientSimStation stationHandler = hitObject.GetComponent<IClientSimStation>();
|
||||
if (stationHandler != null && stationHandler.IsOccupied() && !stationHandler.GetCurrentSittingPlayer().isLocal)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private class RaycastHitComparer : IComparer<RaycastHit>
|
||||
{
|
||||
public int Compare(RaycastHit x, RaycastHit y)
|
||||
{
|
||||
return x.distance.CompareTo(y.distance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: be2b97a47a355084ebe65aea9bdfe938
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0661304e031a1834ba3105f488a7ad95
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public interface IClientSimInteractManager
|
||||
{
|
||||
IClientSimInteractable GetFirstInteractable(GameObject obj, float distance);
|
||||
bool CanInteract(IClientSimInteractable interactable, float distance);
|
||||
List<IClientSimInteractable> Interact(GameObject obj, float distance);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6f25e895d01da4543afa9b7373d727da
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,17 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows the Raycasting system to act the same for VR and Desktop.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only need to provide a different initial ray and the rest is handled automatically. There are currently two different ray providers:
|
||||
/// ClientSimCameraRayProvider used for Desktop
|
||||
/// ClientSimTransformRayProvider used for VR
|
||||
/// </remarks>
|
||||
public interface IClientSimRayProvider
|
||||
{
|
||||
Ray GetRay();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c6082ae9f1a154b46a2a8cacb70b4333
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4a4c8d53c4ad481aacc92ee19eb9964c
|
||||
timeCreated: 1640813775
|
||||
@ -0,0 +1,23 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public class ClientSimCameraRayProvider : IClientSimRayProvider
|
||||
{
|
||||
private readonly Camera _playerCamera;
|
||||
private readonly IClientSimMousePositionProvider _mousePositionProvider;
|
||||
|
||||
public ClientSimCameraRayProvider(
|
||||
IClientSimPlayerCameraProvider cameraProvider,
|
||||
IClientSimMousePositionProvider mousePositionProvider)
|
||||
{
|
||||
_playerCamera = cameraProvider.GetCamera();
|
||||
_mousePositionProvider = mousePositionProvider;
|
||||
}
|
||||
|
||||
public Ray GetRay()
|
||||
{
|
||||
return _playerCamera.ScreenPointToRay(_mousePositionProvider.GetMousePosition());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 873629f8aa3a283488e04aaa159e089c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,19 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public class ClientSimTransformRayProvider : IClientSimRayProvider
|
||||
{
|
||||
private readonly Transform _rayTransform;
|
||||
|
||||
public ClientSimTransformRayProvider(Transform rayTransform)
|
||||
{
|
||||
_rayTransform = rayTransform;
|
||||
}
|
||||
|
||||
public Ray GetRay()
|
||||
{
|
||||
return new Ray(_rayTransform.position, _rayTransform.forward);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ceb5186e2cc867941866adee1d5b2072
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user