Added Unity project files
This commit is contained in:
@ -0,0 +1,5 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("VRC.ClientSim.Editor")]
|
||||
[assembly: InternalsVisibleTo("VRC.ClientSim.Editor.Tests")]
|
||||
[assembly: InternalsVisibleTo("VRC.ClientSim.Tests")]
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bfb84e0933b14ae380634bcd70b18a70
|
||||
timeCreated: 1641884637
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7fd647d22852c4f4db99e7161481e563
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 70f6d4c20b8065e408b6b1fe3223d9e7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,19 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 8474ec07ef88d52458e79ca0f5240d96, type: 3}
|
||||
m_Name: Cam_InternalUI
|
||||
m_EditorClassIdentifier:
|
||||
cameraName: Cam_InternalUI
|
||||
renderLayer:
|
||||
serializedVersion: 2
|
||||
m_Bits: 524288
|
||||
useOcclusionCulling: 0
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d6ef66aee2eba604da699a98a28bba17
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,14 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public class ClientSimStackedCamera : ScriptableObject
|
||||
{
|
||||
[SerializeField] private string cameraName = "Generic Stacked Camera";
|
||||
[SerializeField] private LayerMask renderLayer;
|
||||
[SerializeField] private bool useOcclusionCulling = true;
|
||||
public string CameraName => cameraName;
|
||||
public LayerMask RenderLayer => renderLayer;
|
||||
public bool UseOcclusionCulling => useOcclusionCulling;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8474ec07ef88d52458e79ca0f5240d96
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,120 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.XR;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public class ClientSimStackedVRCameraSystem : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
private ClientSimStackedCamera[] cameraStack;
|
||||
|
||||
private bool _isCameraStackingEnabled;
|
||||
private Camera _mainSceneCamera;
|
||||
private bool _isInitialized;
|
||||
private bool _isReady;
|
||||
private List<Camera> _cameras;
|
||||
private ClientSimMenu _clientSimMenu;
|
||||
private IClientSimEventDispatcher _eventDispatcher;
|
||||
|
||||
public IReadOnlyList<Camera> Cameras => _cameras;
|
||||
|
||||
// all layers handled by this system - note that this does not change whether the system is active or not,
|
||||
// meaning it is valid to call this at any time, which `OnCameraSettingsChanged` may need to do
|
||||
public LayerMask RequestedStackLayers => cameraStack.Aggregate(0, (mask, cam) => mask | cam.RenderLayer);
|
||||
|
||||
public void Initialize(Camera playerCamera, ClientSimMenu menu, IClientSimEventDispatcher eventDispatcher)
|
||||
{
|
||||
_mainSceneCamera = playerCamera;
|
||||
_clientSimMenu = menu;
|
||||
_eventDispatcher = eventDispatcher;
|
||||
}
|
||||
|
||||
public void Ready()
|
||||
{
|
||||
_isReady = true;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if(!_isReady) return;
|
||||
if (!_isInitialized) { InitializeStackedSystem(); }
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
if (_mainSceneCamera != null)
|
||||
{
|
||||
if (_isCameraStackingEnabled)
|
||||
DestroyCameraStack();
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeStackedSystem()
|
||||
{
|
||||
_cameras = new List<Camera>();
|
||||
if (_mainSceneCamera != null)
|
||||
{
|
||||
CreateCameraStack();
|
||||
_isInitialized = true;
|
||||
_eventDispatcher.SendEvent(new ClientSimStackedCameraReadyEvent());
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateCameraStack()
|
||||
{
|
||||
for (int i = 0; i < cameraStack.Length; i++)
|
||||
{
|
||||
AddCamera(i);
|
||||
}
|
||||
_isCameraStackingEnabled = true;
|
||||
}
|
||||
|
||||
private void DestroyCameraStack()
|
||||
{
|
||||
for (int i = 0; i < _cameras.Count; i++)
|
||||
{
|
||||
DestroyCamera(i);
|
||||
}
|
||||
_isCameraStackingEnabled = false;
|
||||
}
|
||||
|
||||
private void AddCamera(int index)
|
||||
{
|
||||
var cameraObj = new GameObject();
|
||||
cameraObj.transform.parent = _mainSceneCamera.transform;
|
||||
Camera cam = cameraObj.AddComponent<Camera>();
|
||||
XRDevice.DisableAutoXRCameraTracking(cam, true);
|
||||
|
||||
cam.CopyFrom(_mainSceneCamera); // Start by copying all the settings from the main camera
|
||||
#if VRC_VR_STEAM // We only want this on SteamVR.
|
||||
cameraObj.AddComponent<SteamVRCantedProjectionCullingFix>();
|
||||
#endif
|
||||
_cameras.Add(cam);
|
||||
|
||||
cameraObj.tag = "Untagged";
|
||||
cameraObj.name = $"StackedCamera : {cameraStack[index].CameraName}";
|
||||
cam.clearFlags = CameraClearFlags.Depth;
|
||||
cam.depth = 100 - index;
|
||||
cam.cullingMask = cameraStack[index].RenderLayer;
|
||||
cam.useOcclusionCulling = cameraStack[index].UseOcclusionCulling;
|
||||
|
||||
//Remove this cameras layers from the base camera
|
||||
_mainSceneCamera.cullingMask = _mainSceneCamera.cullingMask ^ cameraStack[index].RenderLayer;
|
||||
|
||||
// Set the ClientSim UI canvas to use this camera
|
||||
_clientSimMenu.SetCanvasCamera(cam);
|
||||
}
|
||||
|
||||
private void DestroyCamera(int index)
|
||||
{
|
||||
Camera cam = _cameras[index];
|
||||
_cameras.RemoveAt(index);
|
||||
|
||||
//Restore Layers from this camera to the main camera
|
||||
_mainSceneCamera.cullingMask = _mainSceneCamera.cullingMask | cameraStack[index].RenderLayer;
|
||||
Destroy(cam.gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1704c94808cb3c6479f3dc63042a956a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,12 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public abstract class ClientSimBehaviour : MonoBehaviour
|
||||
{
|
||||
protected virtual void Awake()
|
||||
{
|
||||
this.PreventComponentFromSaving();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 29747eaef1c584647a4e877c3f8bc61b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,155 @@
|
||||
using System.Collections.Generic;
|
||||
using JetBrains.Annotations;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using VRC.Core;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public static class ClientSimRuntimeLoader
|
||||
{
|
||||
private const string EDITOR_ONLY_TAG = "EditorOnly";
|
||||
|
||||
// Used in tests to prevent the runtime initialized methods from executing.
|
||||
private static bool _isInTestMode = false;
|
||||
private static ClientSimSettings _testSettingsOverride;
|
||||
private static ClientSimEventDispatcher _testEventDispatcherOverride;
|
||||
|
||||
#region ClientSim Initialization
|
||||
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||
private static void OnBeforeSceneLoad()
|
||||
{
|
||||
StartClientSim(GetSettings(), GetEventDispatcher());
|
||||
}
|
||||
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
|
||||
private static void OnAfterSceneLoad()
|
||||
{
|
||||
// Delete all editor only objects before creating ClientSim.
|
||||
DestroyEditorOnly(GetSettings());
|
||||
|
||||
#if VRC_ENABLE_PLAYER_PERSISTENCE
|
||||
if (ClientSimMain.TryGetInstance(out var instance))
|
||||
instance.EnablePlayerObjects();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Test Methods
|
||||
|
||||
[PublicAPI]
|
||||
public static void BeginUnityTesting(
|
||||
ClientSimSettings testSettingsOverride,
|
||||
ClientSimEventDispatcher testEventDispatcherOverride = null)
|
||||
{
|
||||
_isInTestMode = true;
|
||||
_testSettingsOverride = testSettingsOverride;
|
||||
_testEventDispatcherOverride = testEventDispatcherOverride;
|
||||
|
||||
if (_testSettingsOverride == null)
|
||||
{
|
||||
_testSettingsOverride = new ClientSimSettings();
|
||||
}
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
public static void EndUnityTesting()
|
||||
{
|
||||
_isInTestMode = false;
|
||||
_testSettingsOverride = null;
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
public static bool IsInUnityTest()
|
||||
{
|
||||
return _isInTestMode;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private static ClientSimSettings GetSettings()
|
||||
{
|
||||
return IsInUnityTest() ? _testSettingsOverride : ClientSimSettings.Instance;
|
||||
}
|
||||
|
||||
private static ClientSimEventDispatcher GetEventDispatcher()
|
||||
{
|
||||
return IsInUnityTest() ? _testEventDispatcherOverride : null;
|
||||
}
|
||||
|
||||
private static bool IsClientSimEnabled(ClientSimSettings settings)
|
||||
{
|
||||
return
|
||||
settings.enableClientSim &&
|
||||
Application.isPlaying;
|
||||
}
|
||||
|
||||
// Start client sim with the given settings.
|
||||
// Optional event dispatcher can be passed in to listen to startup events. Mainly used in tests.
|
||||
public static void StartClientSim(
|
||||
ClientSimSettings settings,
|
||||
IClientSimEventDispatcher eventDispatcher = null)
|
||||
{
|
||||
if (!IsClientSimEnabled(settings))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete all editor only objects before creating ClientSim.
|
||||
DestroyEditorOnly(settings);
|
||||
|
||||
ClientSimMain.CreateInstance(settings, eventDispatcher);
|
||||
|
||||
// TODO: Below is disabled for now because the rest of the ClientSim initialization code doesn't work if it's called with a delay.
|
||||
// Currently, not loading RemoteConfig will not cause any issues, but it may in the future, so this is left in as a reminder.
|
||||
|
||||
// Create ClientSim Instance later
|
||||
/*void CreateClientSimInstance() => ClientSimMain.CreateInstance(settings, eventDispatcher);
|
||||
|
||||
// If the Remote Config is not initialized, attempt init before starting ClientSim
|
||||
// Start ClientSim after attempt, regardless of success or failure
|
||||
if (!ConfigManager.RemoteConfig.IsInitialized())
|
||||
{
|
||||
API.SetOnlineMode(true);
|
||||
ConfigManager.RemoteConfig.Init(CreateClientSimInstance, CreateClientSimInstance);
|
||||
}
|
||||
// Otherwise, start ClientSim immediately
|
||||
else
|
||||
{
|
||||
CreateClientSimInstance();
|
||||
}*/
|
||||
}
|
||||
|
||||
private static void DestroyEditorOnly(ClientSimSettings settings)
|
||||
{
|
||||
if (!settings.enableClientSim || !settings.deleteEditorOnly)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
List<GameObject> rootObjects = new List<GameObject>();
|
||||
Scene scene = SceneManager.GetActiveScene();
|
||||
scene.GetRootGameObjects(rootObjects);
|
||||
Queue<GameObject> queue = new Queue<GameObject>(rootObjects);
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
GameObject obj = queue.Dequeue();
|
||||
if (obj.CompareTag(EDITOR_ONLY_TAG))
|
||||
{
|
||||
obj.Log($"Deleting editor only object: {Tools.GetGameObjectPath(obj)}");
|
||||
Object.DestroyImmediate(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int child = 0; child < obj.transform.childCount; ++child)
|
||||
{
|
||||
queue.Enqueue(obj.transform.GetChild(child).gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 47cdc21b10bf4c78890cfe48793dbd14
|
||||
timeCreated: 1638822453
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 08f8a2a94e3342269e856642c4028c74
|
||||
timeCreated: 1638922063
|
||||
@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
/// <summary>
|
||||
/// The Event Dispatcher is how ClientSim implements the Observer Pattern.
|
||||
/// Systems can subscribe to specific event types, and other systems can then send the event.
|
||||
/// </summary>
|
||||
public class ClientSimEventDispatcher : IClientSimEventDispatcher, IDisposable
|
||||
{
|
||||
private readonly Dictionary<Type, Delegate> _eventSubscribers;
|
||||
|
||||
public ClientSimEventDispatcher()
|
||||
{
|
||||
_eventSubscribers = new Dictionary<Type, Delegate>();
|
||||
}
|
||||
|
||||
public void Subscribe<T>(Action<T> eventHandler) where T : IClientSimEvent
|
||||
{
|
||||
Type t = typeof(T);
|
||||
if (_eventSubscribers.TryGetValue(t, out Delegate eventDelegate))
|
||||
{
|
||||
_eventSubscribers[t] = Delegate.Combine(eventDelegate, eventHandler);
|
||||
}
|
||||
else
|
||||
{
|
||||
_eventSubscribers.Add(t, eventHandler);
|
||||
}
|
||||
}
|
||||
|
||||
public void Unsubscribe<T>(Action<T> eventHandler) where T : IClientSimEvent
|
||||
{
|
||||
Type t = typeof(T);
|
||||
if (_eventSubscribers.TryGetValue(t, out Delegate eventDelegate))
|
||||
{
|
||||
Delegate remainingDelegate = Delegate.Remove(eventDelegate, eventHandler);
|
||||
|
||||
if (remainingDelegate == null)
|
||||
{
|
||||
_eventSubscribers.Remove(t);
|
||||
}
|
||||
else
|
||||
{
|
||||
_eventSubscribers[t] = remainingDelegate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends the event to subscribed receivers
|
||||
/// </summary>
|
||||
/// <param name="clientSimEvent"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public void SendEvent<T>(T clientSimEvent) where T : IClientSimEvent
|
||||
{
|
||||
// TODO log warning if trying to send events while another is still being processed.
|
||||
|
||||
if (_eventSubscribers.TryGetValue(typeof(T), out Delegate eventDelegate)
|
||||
&& eventDelegate is Action<T> action)
|
||||
{
|
||||
action.Invoke(clientSimEvent);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_eventSubscribers.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 039d8e7360df43b2a1b0b5f387761dce
|
||||
timeCreated: 1638918329
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d1d43bb9f467463cb77ef60d29a6178a
|
||||
timeCreated: 1640236379
|
||||
@ -0,0 +1,10 @@
|
||||
using VRC.SDKBase;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public class ClientSimPlayerDeathStatusChangedEvent : IClientSimEvent
|
||||
{
|
||||
public VRCPlayerApi player;
|
||||
public bool isDead;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5d6d64ca05845d34bb6753f2cc018bfd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,9 @@
|
||||
using VRC.Udon.Common;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public class ClientSimCurrentHandEvent : IClientSimEvent
|
||||
{
|
||||
public HandType currentUsedHand;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 23f6deb432924c9f898f7f83f000045b
|
||||
timeCreated: 1641101850
|
||||
@ -0,0 +1,14 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using VRC.Udon.Common;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public class ClientSimInteractEvent : IClientSimEvent
|
||||
{
|
||||
public HandType handType;
|
||||
public GameObject interactObject;
|
||||
public float interactDistance;
|
||||
public List<IClientSimInteractable> interacts;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4d4f50777a7b4f5ba8f64f4fe7cb04c4
|
||||
timeCreated: 1640814847
|
||||
@ -0,0 +1,11 @@
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public class ClientSimMenuStateChangedEvent : IClientSimEvent
|
||||
{
|
||||
public bool isMenuOpen;
|
||||
}
|
||||
|
||||
public class ClientSimMenuRespawnClickedEvent : IClientSimEvent { }
|
||||
|
||||
public class ClientSimStackedCameraReadyEvent : IClientSimEvent { }
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 334e4be0c4ea3a34d86e69054d5adc66
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,7 @@
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public class ClientSimMouseReleasedEvent : IClientSimEvent
|
||||
{
|
||||
public bool isReleased;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: efb979a4880368e4997d8efe6882a914
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,113 @@
|
||||
using System.Collections.Generic;
|
||||
using VRC.SDKBase;
|
||||
|
||||
#if VRC_ENABLE_PLAYER_PERSISTENCE
|
||||
using VRC.SDK3.ClientSim.Interfaces;
|
||||
using VRC.SDK3.ClientSim.Persistence;
|
||||
#endif
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public class ClientSimOnPlayerJoinedEvent : IClientSimEvent
|
||||
{
|
||||
public VRCPlayerApi player;
|
||||
}
|
||||
|
||||
public class ClientSimOnPlayerLeftEvent : IClientSimEvent
|
||||
{
|
||||
public VRCPlayerApi player;
|
||||
}
|
||||
|
||||
public class ClientSimOnPlayerRespawnEvent : IClientSimEvent
|
||||
{
|
||||
public VRCPlayerApi player;
|
||||
}
|
||||
|
||||
public class ClientSimOnPlayerTeleportedEvent : IClientSimEvent
|
||||
{
|
||||
public VRCPlayerApi player;
|
||||
}
|
||||
|
||||
public class ClientSimOnPlayerMovedEvent : IClientSimEvent
|
||||
{
|
||||
public VRCPlayerApi player;
|
||||
}
|
||||
|
||||
public class ClientSimOnPlayerEnteredStationEvent : IClientSimEvent
|
||||
{
|
||||
public VRCPlayerApi player;
|
||||
public IClientSimStation station;
|
||||
}
|
||||
|
||||
public class ClientSimOnPlayerExitedStationEvent : IClientSimEvent
|
||||
{
|
||||
public VRCPlayerApi player;
|
||||
public IClientSimStation station;
|
||||
}
|
||||
|
||||
public class ClientSimOnPlayerHeightUpdateEvent : IClientSimEvent
|
||||
{
|
||||
public float playerHeight;
|
||||
public bool exceedsManualScalingMaximum;
|
||||
public bool exceedsManualScalingMinimum;
|
||||
}
|
||||
|
||||
public class ClientSimOnTrackingScaleUpdateEvent : IClientSimEvent
|
||||
{
|
||||
public float trackingScale;
|
||||
}
|
||||
|
||||
public class ClientSimOnNewMasterEvent : IClientSimEvent
|
||||
{
|
||||
public VRCPlayerApi oldMasterPlayer;
|
||||
public VRCPlayerApi newMasterPlayer;
|
||||
}
|
||||
|
||||
#if VRC_ENABLE_PLAYER_PERSISTENCE
|
||||
public class ClientSimOnPlayerDataDecodedEvent : IClientSimEvent
|
||||
{
|
||||
public VRCPlayerApi player;
|
||||
}
|
||||
|
||||
public class ClientSimOnPlayerObjectsDecodedEvent : IClientSimEvent
|
||||
{
|
||||
public VRCPlayerApi player;
|
||||
}
|
||||
|
||||
public class ClientSimOnPlayerRestoredEvent : IClientSimEvent
|
||||
{
|
||||
public VRCPlayerApi player;
|
||||
}
|
||||
|
||||
public class ClientSimOnPlayerDataUpdatedEvent : IClientSimEvent
|
||||
{
|
||||
public VRCPlayerApi player;
|
||||
public Dictionary<string, ClientSimPlayerDataPair> playerData;
|
||||
}
|
||||
|
||||
public class ClientSimOnPlayerDataClearedEvent : IClientSimEvent
|
||||
{
|
||||
public VRCPlayerApi player;
|
||||
}
|
||||
|
||||
public class ClientSimOnPlayerObjectUpdatedEvent : IClientSimEvent
|
||||
{
|
||||
public IClientSimNetworkSerializer Data;
|
||||
}
|
||||
|
||||
public class ClientSimOnPlayerObjectUpdateEndedEvent : IClientSimEvent
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
public class ClientSimOnToggleManualScalingEvent : IClientSimEvent
|
||||
{
|
||||
public bool manualScalingAllowed;
|
||||
}
|
||||
|
||||
public class ClientSimOnVRCPlusMassGift : IClientSimEvent
|
||||
{
|
||||
public VRCPlayerApi gifter;
|
||||
public int numGifts;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c994dd199309cb84c843fe843584cdbb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,33 @@
|
||||
using VRC.SDKBase;
|
||||
using VRC.Udon.Common;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public class ClientSimOnPickupEvent : IClientSimEvent
|
||||
{
|
||||
public VRCPlayerApi player;
|
||||
public HandType handType;
|
||||
public IClientSimPickupable pickup;
|
||||
}
|
||||
|
||||
public class ClientSimOnPickupDropEvent : IClientSimEvent
|
||||
{
|
||||
public VRCPlayerApi player;
|
||||
public HandType handType;
|
||||
public IClientSimPickupable pickup;
|
||||
}
|
||||
|
||||
public class ClientSimOnPickupUseDownEvent : IClientSimEvent
|
||||
{
|
||||
public VRCPlayerApi player;
|
||||
public HandType handType;
|
||||
public IClientSimPickupable pickup;
|
||||
}
|
||||
|
||||
public class ClientSimOnPickupUseUpEvent : IClientSimEvent
|
||||
{
|
||||
public VRCPlayerApi player;
|
||||
public HandType handType;
|
||||
public IClientSimPickupable pickup;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: daf6e253eca84774b6643ef83c0594e7
|
||||
timeCreated: 1640732560
|
||||
@ -0,0 +1,9 @@
|
||||
using VRC.SDK3.Platform;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public class ClientSimScreenUpdateEvent : IClientSimEvent
|
||||
{
|
||||
public ScreenUpdateData data;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 228a1330ea1c47babdd3a40d81194d1d
|
||||
timeCreated: 1698364360
|
||||
@ -0,0 +1,10 @@
|
||||
using VRC.Udon.Common;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public class ClientSimRaycastHitResultsEvent : IClientSimEvent
|
||||
{
|
||||
public HandType handType;
|
||||
public ClientSimRaycastResults raycastResults;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 609324b47ca7465991701242bb8a9e0d
|
||||
timeCreated: 1640274005
|
||||
@ -0,0 +1,7 @@
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public class ClientSimReadyEvent : IClientSimEvent
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 09530bd2269622c4385b1db5178aa0a4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 982b72f64cba3cc42a0918c3fec1ce5e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,4 @@
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public interface IClientSimEvent { }
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 91bfef23cc10ff640880e382bf79c390
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,11 @@
|
||||
using System;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public interface IClientSimEventDispatcher
|
||||
{
|
||||
void Subscribe<T>(Action<T> eventHandler) where T : IClientSimEvent;
|
||||
void Unsubscribe<T>(Action<T> eventHandler) where T : IClientSimEvent;
|
||||
void SendEvent<T>(T clientSimEvent) where T : IClientSimEvent;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b6db79d31b2023245b6131565300da0e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c53e2f6d693eb7c4c9abf6e1124479b2
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,293 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using VRC.SDKBase;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
// Sends Events:
|
||||
// - ClientSimPlayerDeathStatusChangedEvent
|
||||
[AddComponentMenu("")]
|
||||
public class ClientSimCombatSystemHelper : ClientSimBehaviour, IVRC_Destructible
|
||||
{
|
||||
private static readonly string _visualDamagePrefabPath =
|
||||
Path.Combine("Assets", "VRChat Examples", "Prefabs", "VRCPlayerVisualDamage.prefab");
|
||||
|
||||
private VRCPlayerApi _player;
|
||||
private IClientSimEventDispatcher _eventDispatcher;
|
||||
private IClientSimProxyObjectProvider _proxyProvider;
|
||||
private ClientSimPlayerController _playerController;
|
||||
|
||||
// Make values public so users can see and modify these values at runtime.
|
||||
public bool respawnOnDeath;
|
||||
public bool resetHealthOnRespawn = true;
|
||||
public float respawnTime = 5f;
|
||||
public float maxPlayerHealth = 100;
|
||||
public float currentHealth = 100;
|
||||
public Transform respawnPoint;
|
||||
private GameObject _visualDamagePrefab;
|
||||
|
||||
private GameObject _visualDamageObj;
|
||||
private VRC_VisualDamage _visualDamage;
|
||||
|
||||
private bool _dead = false;
|
||||
|
||||
private static ClientSimCombatSystemHelper GetCombatHelper(VRCPlayerApi player)
|
||||
{
|
||||
return player.GetClientSimPlayer().GetCombatHelper();
|
||||
}
|
||||
|
||||
public static void CombatSetup(VRCPlayerApi player)
|
||||
{
|
||||
player.GetClientSimPlayer().InitializeCombat();
|
||||
}
|
||||
|
||||
public static void CombatSetMaxHitpoints(VRCPlayerApi player, float maxHealth)
|
||||
{
|
||||
ClientSimCombatSystemHelper combatHelper = GetCombatHelper(player);
|
||||
if (combatHelper == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
combatHelper.maxPlayerHealth = maxHealth;
|
||||
}
|
||||
|
||||
public static float CombatGetCurrentHitpoints(VRCPlayerApi player)
|
||||
{
|
||||
ClientSimCombatSystemHelper combatHelper = GetCombatHelper(player);
|
||||
if (combatHelper == null)
|
||||
{
|
||||
// If a player doesn't have combat setup, their hitpoints are -1.
|
||||
return -1;
|
||||
}
|
||||
return combatHelper.currentHealth;
|
||||
}
|
||||
|
||||
public static void CombatSetRespawn(VRCPlayerApi player, bool respawnOnDeath, float respawnTime, Transform spawnPoint)
|
||||
{
|
||||
ClientSimCombatSystemHelper combatHelper = GetCombatHelper(player);
|
||||
if (combatHelper == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
combatHelper.respawnOnDeath = respawnOnDeath;
|
||||
combatHelper.respawnTime = respawnTime;
|
||||
combatHelper.respawnPoint = spawnPoint;
|
||||
}
|
||||
|
||||
public static void CombatSetDamageGraphic(VRCPlayerApi player, GameObject visualDamage)
|
||||
{
|
||||
ClientSimCombatSystemHelper combatHelper = GetCombatHelper(player);
|
||||
if (combatHelper == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
combatHelper._visualDamagePrefab = visualDamage;
|
||||
}
|
||||
|
||||
public static IVRC_Destructible CombatGetDestructible(VRCPlayerApi player)
|
||||
{
|
||||
return GetCombatHelper(player);
|
||||
}
|
||||
|
||||
public static void CombatSetCurrentHitpoints(VRCPlayerApi player, float health)
|
||||
{
|
||||
ClientSimCombatSystemHelper combatHelper = GetCombatHelper(player);
|
||||
if (combatHelper == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.isLocal)
|
||||
{
|
||||
float delta = health - combatHelper.currentHealth;
|
||||
if (delta <= 0)
|
||||
{
|
||||
combatHelper.ApplyDamage(-delta);
|
||||
}
|
||||
else
|
||||
{
|
||||
combatHelper.ApplyHealing(delta);
|
||||
}
|
||||
}
|
||||
|
||||
combatHelper.currentHealth = health;
|
||||
}
|
||||
|
||||
public void Initialize(
|
||||
VRCPlayerApi player,
|
||||
IClientSimEventDispatcher eventDispatcher,
|
||||
IClientSimProxyObjectProvider proxyProvider,
|
||||
ClientSimPlayerController playerController)
|
||||
{
|
||||
_player = player;
|
||||
|
||||
// Values below will be null for remote players.
|
||||
_eventDispatcher = eventDispatcher;
|
||||
_playerController = playerController;
|
||||
_proxyProvider = proxyProvider;
|
||||
|
||||
// TODO add ragdoll to player avatar
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
currentHealth = GetMaxHealth();
|
||||
CreateVisualDamage();
|
||||
}
|
||||
|
||||
private void CreateVisualDamage()
|
||||
{
|
||||
if (!_player.isLocal)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_visualDamageObj != null)
|
||||
{
|
||||
Destroy(_visualDamageObj);
|
||||
}
|
||||
|
||||
GameObject damage = _visualDamagePrefab;
|
||||
#if UNITY_EDITOR
|
||||
// If damage prefab is null, try loading it from the sample prefabs
|
||||
if (damage == null)
|
||||
{
|
||||
damage = UnityEditor.AssetDatabase.LoadAssetAtPath<GameObject>(_visualDamagePrefabPath);
|
||||
}
|
||||
#endif
|
||||
if (damage != null)
|
||||
{
|
||||
_visualDamageObj = Instantiate(damage, _proxyProvider.CameraProxy().transform);
|
||||
_visualDamageObj.transform.localScale = new Vector3(40, 40, 40);
|
||||
_visualDamageObj.transform.localPosition = new Vector3(0, 0, 0.5f);
|
||||
|
||||
_visualDamage = _visualDamageObj.GetComponent<VRC_VisualDamage>();
|
||||
if (_visualDamage != null)
|
||||
{
|
||||
// VRChatBug: Visual Damage script is blacklisted in SDK3 and will be destroyed after spawning.
|
||||
DestroyImmediate(_visualDamage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float GetMaxHealth()
|
||||
{
|
||||
return maxPlayerHealth;
|
||||
}
|
||||
|
||||
public float GetCurrentHealth()
|
||||
{
|
||||
return currentHealth;
|
||||
}
|
||||
|
||||
private void ApplyVisualDamage()
|
||||
{
|
||||
if (_visualDamage != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_visualDamage.SetDamagePercent(1 - (currentHealth / maxPlayerHealth));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
this.LogWarning($"Error applying damage: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplyDamage(float damage)
|
||||
{
|
||||
if (!_player.isLocal)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentHealth <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
this.Log($"ApplyDamage: {damage} currentHealth: {currentHealth}");
|
||||
|
||||
currentHealth = Mathf.Clamp(currentHealth - damage, 0, maxPlayerHealth);
|
||||
ApplyVisualDamage();
|
||||
|
||||
if (currentHealth <= 0 && !_dead)
|
||||
{
|
||||
_dead = true;
|
||||
this.Log("Player Died");
|
||||
|
||||
_player.EnablePickups(false);
|
||||
_eventDispatcher?.SendEvent(new ClientSimPlayerDeathStatusChangedEvent
|
||||
{
|
||||
player = _player,
|
||||
isDead = true,
|
||||
});
|
||||
|
||||
StartCoroutine(PlayerDied());
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator PlayerDied()
|
||||
{
|
||||
yield return new WaitForSeconds(respawnTime);
|
||||
|
||||
RevivePlayer();
|
||||
}
|
||||
|
||||
private void RevivePlayer()
|
||||
{
|
||||
if (!_player.isLocal)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_dead = false;
|
||||
this.Log("Player Revived");
|
||||
|
||||
_player.EnablePickups(true);
|
||||
|
||||
if (respawnPoint != null && respawnOnDeath)
|
||||
{
|
||||
_playerController.Teleport(respawnPoint, false);
|
||||
}
|
||||
|
||||
if (resetHealthOnRespawn)
|
||||
{
|
||||
ApplyHealing(maxPlayerHealth);
|
||||
}
|
||||
|
||||
_eventDispatcher?.SendEvent(new ClientSimPlayerDeathStatusChangedEvent
|
||||
{
|
||||
player = _player,
|
||||
isDead = false,
|
||||
});
|
||||
}
|
||||
|
||||
public void ApplyHealing(float healing)
|
||||
{
|
||||
if (!_player.isLocal)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
currentHealth = Mathf.Clamp(currentHealth + healing, 0, maxPlayerHealth);
|
||||
ApplyVisualDamage();
|
||||
|
||||
this.Log($"ApplyHealing: {healing} currentHealth: {currentHealth}");
|
||||
}
|
||||
|
||||
public object[] GetState()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public void SetState(object[] state)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e569e5d477213484e9111d560a39cafc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,77 @@
|
||||
using UnityEngine;
|
||||
using VRC.SDK3.Components;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
[AddComponentMenu("")]
|
||||
public class ClientSimObjectPoolHelper : ClientSimBehaviour, IClientSimSyncable
|
||||
{
|
||||
private int _ownerID = 1;
|
||||
private VRCObjectPool _objectPool;
|
||||
|
||||
private IClientSimSyncedObjectManager _syncedObjectManager;
|
||||
|
||||
|
||||
public static void OnSpawn(VRCObjectPool objectPool, int index)
|
||||
{
|
||||
ClientSimObjectPoolHelper poolHelper = objectPool.GetComponent<ClientSimObjectPoolHelper>();
|
||||
if (!poolHelper)
|
||||
{
|
||||
throw new ClientSimException("Object Pool has not been initialized yet before trying to spawn an object.");
|
||||
}
|
||||
poolHelper.OnObjectSpawned(index);
|
||||
}
|
||||
|
||||
public static void OnReturn(VRCObjectPool objectPool, int index)
|
||||
{
|
||||
ClientSimObjectPoolHelper poolHelper = objectPool.GetComponent<ClientSimObjectPoolHelper>();
|
||||
if (!poolHelper)
|
||||
{
|
||||
throw new ClientSimException("Object Pool has not been initialized yet before trying to return an object.");
|
||||
}
|
||||
poolHelper.OnObjectReturned(index);
|
||||
}
|
||||
|
||||
|
||||
public void Initialize(VRCObjectPool objectPool, IClientSimSyncedObjectManager syncedObjectManager)
|
||||
{
|
||||
_objectPool = objectPool;
|
||||
_syncedObjectManager = syncedObjectManager;
|
||||
syncedObjectManager.AddSyncedObject(this);
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
// Catch Helper not initialized.
|
||||
if (_objectPool == null)
|
||||
{
|
||||
this.LogWarning($"Destroying uninitialized Helper. Object: {Tools.GetGameObjectPath(gameObject)}");
|
||||
DestroyImmediate(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
// Nullable needed for uninitialized case.
|
||||
_syncedObjectManager?.RemoveSyncedObject(this);
|
||||
}
|
||||
|
||||
private void OnObjectSpawned(int index) { }
|
||||
|
||||
private void OnObjectReturned(int index) { }
|
||||
|
||||
#region IClientSimSyncable
|
||||
|
||||
public int GetOwner()
|
||||
{
|
||||
return _ownerID;
|
||||
}
|
||||
|
||||
public void SetOwner(int ownerID)
|
||||
{
|
||||
_ownerID = ownerID;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aae00de63d785d5468f307e29acf4ab7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,68 @@
|
||||
using UnityEngine;
|
||||
using VRC.SDK3.Components;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
[AddComponentMenu("")]
|
||||
public class ClientSimObjectSyncHelper : ClientSimPositionSyncedHelperBase
|
||||
{
|
||||
private VRCObjectSync _sync;
|
||||
|
||||
public static void TeleportTo(VRCObjectSync obj, Vector3 position, Quaternion rotation)
|
||||
{
|
||||
obj.GetComponent<ClientSimObjectSyncHelper>().TeleportTo(position, rotation);
|
||||
}
|
||||
|
||||
public static void RespawnObject(VRCObjectSync sync)
|
||||
{
|
||||
sync.GetComponent<ClientSimObjectSyncHelper>().Respawn();
|
||||
}
|
||||
|
||||
public static void SetIsKinematic(VRCObjectSync sync, bool value)
|
||||
{
|
||||
sync.GetComponent<ClientSimObjectSyncHelper>().SetIsKinematic(value);
|
||||
}
|
||||
|
||||
public static void SetUseGravity(VRCObjectSync sync, bool value)
|
||||
{
|
||||
sync.GetComponent<ClientSimObjectSyncHelper>().SetUseGravity(value);
|
||||
}
|
||||
|
||||
public static bool GetIsKinematic(VRCObjectSync sync)
|
||||
{
|
||||
return sync.GetComponent<ClientSimObjectSyncHelper>().GetIsKinematic();
|
||||
}
|
||||
|
||||
public static bool GetUseGravity(VRCObjectSync sync)
|
||||
{
|
||||
return sync.GetComponent<ClientSimObjectSyncHelper>().GetUseGravity();
|
||||
}
|
||||
|
||||
public static void FlagDiscontinuityHook(VRCObjectSync sync)
|
||||
{
|
||||
sync.GetComponent<ClientSimObjectSyncHelper>().FlagDiscontinuity();
|
||||
}
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
SyncPosition = true;
|
||||
}
|
||||
|
||||
public void Initialize(VRCObjectSync sync, IClientSimSyncedObjectManager syncedObjectManager)
|
||||
{
|
||||
base.Initialize(syncedObjectManager);
|
||||
_sync = sync;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
// Catch Helper not initialized.
|
||||
if (_sync == null)
|
||||
{
|
||||
this.LogWarning($"Destroying uninitialized Helper. Object: {Tools.GetGameObjectPath(gameObject)}");
|
||||
DestroyImmediate(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 589d092631b45f945ace85beb794e76c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,172 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3202215373c7804408519f37ae740d55
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,7 @@
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public class IClientSimPlatformHelper
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9b649f5d029e44a281939561cd0adfd9
|
||||
timeCreated: 1698363870
|
||||
@ -0,0 +1,151 @@
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
[AddComponentMenu("")]
|
||||
public abstract class ClientSimPositionSyncedHelperBase :
|
||||
ClientSimBehaviour,
|
||||
IClientSimSyncable,
|
||||
IClientSimPositionSyncable,
|
||||
IClientSimRespawnHandler
|
||||
{
|
||||
private int _ownerID = 1;
|
||||
private Vector3 _originalPosition;
|
||||
private Quaternion _originalRotation;
|
||||
|
||||
private Rigidbody _rigidbody;
|
||||
private bool _useGravity;
|
||||
private bool _isKinematic;
|
||||
|
||||
private IClientSimSyncedObjectManager _syncedObjectManager;
|
||||
|
||||
public bool SyncPosition { get; protected set; }
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
_originalPosition = transform.position;
|
||||
_originalRotation = transform.rotation;
|
||||
_rigidbody = GetComponent<Rigidbody>();
|
||||
|
||||
if (_rigidbody != null)
|
||||
{
|
||||
_isKinematic = _rigidbody.isKinematic;
|
||||
_useGravity = _rigidbody.useGravity;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Initialize(IClientSimSyncedObjectManager syncedObjectManager)
|
||||
{
|
||||
_syncedObjectManager = syncedObjectManager;
|
||||
_syncedObjectManager.AddSyncedObject(this);
|
||||
}
|
||||
|
||||
protected virtual void OnDestroy()
|
||||
{
|
||||
// Nullable needed for uninitialized case.
|
||||
_syncedObjectManager?.RemoveSyncedObject(this);
|
||||
}
|
||||
|
||||
public void TeleportTo(Vector3 position, Quaternion rotation)
|
||||
{
|
||||
this.Log($"Teleporting Object {Tools.GetGameObjectPath(gameObject)} to {position} and rotation {rotation.eulerAngles}");
|
||||
FlagDiscontinuity();
|
||||
transform.SetPositionAndRotation(position, rotation);
|
||||
}
|
||||
|
||||
public void FlagDiscontinuity()
|
||||
{
|
||||
// TODO As of right now, ClientSim doesn't handle any actual sync.
|
||||
}
|
||||
|
||||
#region IClientSimSyncable
|
||||
|
||||
public int GetOwner()
|
||||
{
|
||||
return _ownerID;
|
||||
}
|
||||
|
||||
public void SetOwner(int ownerID)
|
||||
{
|
||||
_ownerID = ownerID;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IClientSimRespawnable
|
||||
|
||||
public void Respawn()
|
||||
{
|
||||
this.Log($"Respawning Object {Tools.GetGameObjectPath(gameObject)}");
|
||||
TeleportTo(_originalPosition, _originalRotation);
|
||||
|
||||
if (_rigidbody != null)
|
||||
{
|
||||
_rigidbody.velocity = Vector3.zero;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IClientSimPositionSyncable
|
||||
|
||||
public void SetIsKinematic(bool value)
|
||||
{
|
||||
_isKinematic = value;
|
||||
if (_rigidbody)
|
||||
{
|
||||
_rigidbody.isKinematic = value;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetUseGravity(bool value)
|
||||
{
|
||||
_useGravity = value;
|
||||
if (_rigidbody)
|
||||
{
|
||||
_rigidbody.useGravity = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool GetIsKinematic()
|
||||
{
|
||||
return _rigidbody && _rigidbody.isKinematic;
|
||||
}
|
||||
|
||||
public bool GetUseGravity()
|
||||
{
|
||||
return _rigidbody && _rigidbody.useGravity;
|
||||
}
|
||||
|
||||
public void UpdatePositionSync()
|
||||
{
|
||||
if (_rigidbody != null)
|
||||
{
|
||||
// TODO if user is not the owner, set useGravity to false, isKinematic to true.
|
||||
// This would better simulate ownership, but also make testing awkward.
|
||||
|
||||
if (_rigidbody.isKinematic != _isKinematic)
|
||||
{
|
||||
_rigidbody.isKinematic = _isKinematic;
|
||||
this.LogWarning($"Rigidbody.isKinematic was set outside of VRCObjectSync.SetKinematic method! {Tools.GetGameObjectPath(gameObject)}");
|
||||
}
|
||||
|
||||
if (_rigidbody.useGravity != _useGravity)
|
||||
{
|
||||
_rigidbody.useGravity = _useGravity;
|
||||
this.LogWarning($"Rigidbody.useGravity was set outside of VRCObjectSync.SetGravity method! {Tools.GetGameObjectPath(gameObject)}");
|
||||
}
|
||||
|
||||
// VRChatBug: Modifying a collider's "is Trigger" property is also restricted when VRCObjectSync is on
|
||||
// the same object, but this check will not be added.
|
||||
}
|
||||
}
|
||||
|
||||
public Transform GetTransform() => transform;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a751849f43f6c724a8ce7ad9766b132c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,181 @@
|
||||
using UnityEngine;
|
||||
using VRC.SDKBase;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
[AddComponentMenu("")]
|
||||
[DisallowMultipleComponent]
|
||||
public class ClientSimSpatialAudioHelper : ONSPAudioSource
|
||||
{
|
||||
private const float EPS = 1e-3f;
|
||||
|
||||
private VRC_SpatialAudioSource _spatialAudioSource;
|
||||
private AudioSource _audioSource;
|
||||
private bool _useAudioSourceCurve;
|
||||
private ONSPAudioSource _onsp;
|
||||
private bool _forceUpdate = true;
|
||||
private bool _updateONSPParams;
|
||||
|
||||
public static void InitializeAudio(VRC_SpatialAudioSource obj)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
// VRC_SpatialAudioSource executes in editor, meaning it will try to initialize even outside of playmode.
|
||||
// This code is to prevent adding the ClientSim helper in these cases.
|
||||
if (!UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode ||
|
||||
UnityEditor.SceneManagement.EditorSceneManager.IsPreviewSceneObject(obj))
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
ClientSimSpatialAudioHelper spatialAudio = obj.GetComponent<ClientSimSpatialAudioHelper>();
|
||||
if (spatialAudio != null)
|
||||
{
|
||||
DestroyImmediate(spatialAudio);
|
||||
}
|
||||
|
||||
spatialAudio = obj.gameObject.AddComponent<ClientSimSpatialAudioHelper>();
|
||||
spatialAudio.PreventComponentFromSaving();
|
||||
spatialAudio.SetSpatializer(obj);
|
||||
}
|
||||
|
||||
private void SetSpatializer(VRC_SpatialAudioSource obj)
|
||||
{
|
||||
_spatialAudioSource = obj;
|
||||
_audioSource = GetComponent<AudioSource>();
|
||||
_onsp = this;
|
||||
_forceUpdate = true;
|
||||
|
||||
UpdateSettings();
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
// Catch Helper not initialized.
|
||||
if (_spatialAudioSource == null)
|
||||
{
|
||||
this.LogWarning($"Destroying uninitialized Helper. Object: {Tools.GetGameObjectPath(gameObject)}");
|
||||
DestroyImmediate(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
// ONSP needs to reapply audio settings everytime the object is enabled.
|
||||
_forceUpdate = true;
|
||||
_updateONSPParams = true;
|
||||
}
|
||||
|
||||
// Late update to help with testing
|
||||
private void LateUpdate()
|
||||
{
|
||||
UpdateSettings();
|
||||
}
|
||||
|
||||
private void UpdateSettings()
|
||||
{
|
||||
if (_spatialAudioSource == null)
|
||||
{
|
||||
_spatialAudioSource = GetComponent<VRC_SpatialAudioSource>();
|
||||
if (_spatialAudioSource == null)
|
||||
{
|
||||
Destroy(this);
|
||||
}
|
||||
SetSpatializer(_spatialAudioSource);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if we need to make changes.
|
||||
if (
|
||||
_onsp.EnableSpatialization != _spatialAudioSource.EnableSpatialization ||
|
||||
_onsp.Gain != _spatialAudioSource.Gain ||
|
||||
_onsp.Near != _spatialAudioSource.Near ||
|
||||
_onsp.Far != _spatialAudioSource.Far ||
|
||||
_useAudioSourceCurve != _spatialAudioSource.UseAudioSourceVolumeCurve
|
||||
) {
|
||||
_forceUpdate = true;
|
||||
_updateONSPParams = true;
|
||||
}
|
||||
|
||||
_onsp.EnableSpatialization = _spatialAudioSource.EnableSpatialization;
|
||||
_onsp.Gain = _spatialAudioSource.Gain;
|
||||
_useAudioSourceCurve = _spatialAudioSource.UseAudioSourceVolumeCurve;
|
||||
_onsp.Near = _spatialAudioSource.Near;
|
||||
_onsp.Far = _spatialAudioSource.Far;
|
||||
_onsp.VolumetricRadius = _spatialAudioSource.VolumetricRadius;
|
||||
|
||||
// In unity 2022 - updating ONSP params every frame can cause a logspam
|
||||
// This is a workaround to only update when needed
|
||||
if (_updateONSPParams)
|
||||
{
|
||||
_onsp.SetParameters(ref _audioSource);
|
||||
_updateONSPParams = false;
|
||||
}
|
||||
|
||||
if (!_onsp.EnableSpatialization)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_forceUpdate)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_forceUpdate = false;
|
||||
|
||||
if (!_spatialAudioSource.UseAudioSourceVolumeCurve)
|
||||
{
|
||||
float near = _onsp.VolumetricRadius + _onsp.Near;
|
||||
float far = _onsp.VolumetricRadius + Mathf.Max(near, _onsp.Far + EPS);
|
||||
|
||||
_audioSource.maxDistance = far;
|
||||
|
||||
CreateRolloffCurve(near, far);
|
||||
CreateSpatialCurve(near, far);
|
||||
}
|
||||
}
|
||||
|
||||
// Create volume rolloff curve where Volumetric + near is volume 1, then 2^-x fall off to far.
|
||||
private void CreateRolloffCurve(float near, float far)
|
||||
{
|
||||
_audioSource.rolloffMode = AudioRolloffMode.Custom;
|
||||
|
||||
AnimationCurve curve = new AnimationCurve();
|
||||
curve.AddKey(new Keyframe(near, 1));
|
||||
int max = 8;
|
||||
for (int loc = 1; loc < max; ++loc)
|
||||
{
|
||||
float time = near + Mathf.Pow(2, loc - max) * (far - near);
|
||||
float value = Mathf.Pow(2.2f, -loc);
|
||||
curve.AddKey(new Keyframe(time, value));
|
||||
}
|
||||
curve.AddKey(new Keyframe(far, 0));
|
||||
|
||||
for (int i = 0; i < curve.length; ++i)
|
||||
{
|
||||
curve.SmoothTangents(i, 0);
|
||||
}
|
||||
|
||||
_audioSource.SetCustomCurve(AudioSourceCurveType.CustomRolloff, curve);
|
||||
}
|
||||
|
||||
// Create spatial blend curve so that it goes from (Setting) to 3d from min to max
|
||||
private void CreateSpatialCurve(float near, float far)
|
||||
{
|
||||
AnimationCurve spatialCurve = new AnimationCurve();
|
||||
spatialCurve.AddKey(0, _audioSource.spatialBlend);
|
||||
spatialCurve.AddKey(_onsp.VolumetricRadius, _audioSource.spatialBlend);
|
||||
|
||||
Keyframe nearFrame = new Keyframe(near + EPS, 1);
|
||||
nearFrame.outTangent = 0;
|
||||
spatialCurve.AddKey(nearFrame);
|
||||
|
||||
Keyframe farFrame = new Keyframe(far, 1);
|
||||
farFrame.inTangent = 0;
|
||||
spatialCurve.AddKey(farFrame);
|
||||
|
||||
_audioSource.SetCustomCurve(AudioSourceCurveType.SpatialBlend, spatialCurve);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c1c30c850f67fff48a0e69a3e8fa4373
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,175 @@
|
||||
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using VRC.SDKBase;
|
||||
using VRC.Udon;
|
||||
using VRC.Udon.Common;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
[AddComponentMenu("")]
|
||||
public class ClientSimStationHelper : ClientSimBehaviour, IClientSimStation
|
||||
{
|
||||
private VRCStation _station;
|
||||
private VRCPlayerApi _usingPlayer;
|
||||
|
||||
public Transform EnterLocation() => _station.stationEnterPlayerLocation;
|
||||
|
||||
public Transform ExitLocation() => _station.stationExitPlayerLocation;
|
||||
|
||||
public bool IsMobile() =>
|
||||
_station.PlayerMobility == VRCStation.Mobility.Mobile &&
|
||||
!_station.seated;
|
||||
|
||||
public bool IsSeated() => _station.seated;
|
||||
|
||||
public bool DisableStationExit() => _station.disableStationExit;
|
||||
|
||||
public bool CanUseStationFromStation() => _station.canUseStationFromStation;
|
||||
|
||||
public bool IsLockedInStation() => !IsMobile();
|
||||
|
||||
public VRCStation GetStation() => _station;
|
||||
|
||||
public GameObject GetStationGameObject() => gameObject;
|
||||
|
||||
public Transform GetStationTransform() => transform;
|
||||
|
||||
public bool IsOccupied() => _usingPlayer != null;
|
||||
|
||||
public VRCPlayerApi GetCurrentSittingPlayer() => _usingPlayer;
|
||||
|
||||
public static void InitializeStations(VRCStation station)
|
||||
{
|
||||
ClientSimStationHelper prevHelper = station.gameObject.GetComponent<ClientSimStationHelper>();
|
||||
if (prevHelper != null)
|
||||
{
|
||||
DestroyImmediate(prevHelper);
|
||||
station.LogWarning($"Destroying old station helper on object: {Tools.GetGameObjectPath(station.gameObject)}");
|
||||
}
|
||||
|
||||
station.gameObject.AddComponent<ClientSimStationHelper>();
|
||||
}
|
||||
|
||||
public static void UseAttachedStation(VRCPlayerApi player)
|
||||
{
|
||||
// UseAttachedStation is a method in the VRCPlayerApi class. This method will take the given player and try to put them in the station component on the GameObject running this Udon program. Since the GameObject is not provided in the parameters, it must be retrieved from the UdonManager by checking the current executing UdonBehaviour.
|
||||
UdonBehaviour currentUdon = UdonManager.Instance.currentlyExecuting;
|
||||
if (currentUdon == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
VRCStation station = currentUdon.GetComponent<VRCStation>();
|
||||
if (station == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UseStation(station, player);
|
||||
}
|
||||
|
||||
public static void UseStation(VRCStation station, VRCPlayerApi player)
|
||||
{
|
||||
if (!player.isLocal)
|
||||
{
|
||||
station.LogWarning($"Trying to force a remote player to enter a station. Force enter a station can only be done for the local player. PlayerId: {player.playerId}, Station: {Tools.GetGameObjectPath(station.gameObject)}");
|
||||
return;
|
||||
}
|
||||
|
||||
ClientSimStationHelper helper = station.GetComponent<ClientSimStationHelper>();
|
||||
ClientSimPlayer clientPlayer = player.GetClientSimPlayer();
|
||||
if (helper != null && clientPlayer != null)
|
||||
{
|
||||
clientPlayer.GetStationHandler().EnterStation(helper);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ExitStation(VRCStation station, VRCPlayerApi player)
|
||||
{
|
||||
if (!player.isLocal)
|
||||
{
|
||||
station.LogWarning($"Trying to force a remote player to exit a station. Force exit a station can only be done for the local player. PlayerId: {player.playerId}, Station: {Tools.GetGameObjectPath(station.gameObject)}");
|
||||
return;
|
||||
}
|
||||
|
||||
ClientSimStationHelper helper = station.GetComponent<ClientSimStationHelper>();
|
||||
ClientSimPlayer clientPlayer = player.GetClientSimPlayer();
|
||||
if (helper != null && clientPlayer != null)
|
||||
{
|
||||
clientPlayer.GetStationHandler().ExitStation(helper);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
_station = GetComponent<VRCStation>();
|
||||
|
||||
CheckForMissingComponents();
|
||||
|
||||
if (_station.stationEnterPlayerLocation == null)
|
||||
{
|
||||
_station.stationEnterPlayerLocation = transform;
|
||||
}
|
||||
if (_station.stationExitPlayerLocation == null)
|
||||
{
|
||||
_station.stationExitPlayerLocation = transform;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (_usingPlayer != null)
|
||||
{
|
||||
ExitStation(_station, _usingPlayer);
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckForMissingComponents()
|
||||
{
|
||||
Collider stationCollider = GetComponent<Collider>();
|
||||
if (stationCollider == null)
|
||||
{
|
||||
gameObject.AddComponent<BoxCollider>().isTrigger = true;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
UdonBehaviour udon = GetComponent<UdonBehaviour>();
|
||||
if (udon == null)
|
||||
{
|
||||
udon = gameObject.AddComponent<UdonBehaviour>();
|
||||
udon.interactText = "Sit";
|
||||
|
||||
// TODO properly load udon chair program asset.
|
||||
string sitProgramPath = Path.Combine("Assets", "VRChat Examples", "Prefabs", "VRCChair", "StationGraph.asset");
|
||||
AbstractUdonProgramSource program = UnityEditor.AssetDatabase.LoadAssetAtPath<AbstractUdonProgramSource>(sitProgramPath);
|
||||
if (program != null)
|
||||
{
|
||||
udon.AssignProgramAndVariables(program.SerializedProgramAsset, new UdonVariableTable());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public void EnterStation(VRCPlayerApi player)
|
||||
{
|
||||
if (_usingPlayer != null || !player.isLocal)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_usingPlayer = player;
|
||||
}
|
||||
|
||||
public void ExitStation(VRCPlayerApi player)
|
||||
{
|
||||
if (_usingPlayer != player)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_usingPlayer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 989fabbff35c3d845b1b0363b1709ea7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,163 @@
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using VRC.SDKBase;
|
||||
using VRC.Udon;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
[AddComponentMenu("")]
|
||||
public class ClientSimUdonHelper :
|
||||
ClientSimPositionSyncedHelperBase,
|
||||
IClientSimInteractable,
|
||||
IClientSimPickupHandler,
|
||||
IClientSimStationHandler,
|
||||
IClientSimSyncableHandler
|
||||
{
|
||||
private IClientSimUdonManager _udonManager;
|
||||
private UdonBehaviour _udonBehaviour;
|
||||
|
||||
private static readonly FieldInfo _isReady =
|
||||
typeof(UdonBehaviour).GetField("_isReady", (BindingFlags.Instance | BindingFlags.NonPublic));
|
||||
|
||||
public void Initialize(
|
||||
UdonBehaviour udonBehaviour,
|
||||
IClientSimUdonManager udonManager,
|
||||
IClientSimSyncedObjectManager syncedObjectManager,
|
||||
bool isReady)
|
||||
{
|
||||
_udonBehaviour = udonBehaviour;
|
||||
#pragma warning disable 618
|
||||
SyncPosition = _udonBehaviour.SynchronizePosition;
|
||||
#pragma warning restore 618
|
||||
|
||||
SetIsReady(isReady);
|
||||
|
||||
_udonManager = udonManager;
|
||||
_udonManager.AddUdonBehaviour(_udonBehaviour);
|
||||
|
||||
// Ensure that SyncPosition is set before calling this.
|
||||
base.Initialize(syncedObjectManager);
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
// Catch Helper not initialized.
|
||||
if (_udonBehaviour == null)
|
||||
{
|
||||
this.LogWarning($"Destroying uninitialized Helper. Object: {Tools.GetGameObjectPath(gameObject)}");
|
||||
DestroyImmediate(this);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
base.OnDestroy();
|
||||
|
||||
// Nullable needed for uninitialized case.
|
||||
_udonManager?.RemoveUdonBehaviour(_udonBehaviour);
|
||||
}
|
||||
|
||||
private void SetIsReady(bool isReady)
|
||||
{
|
||||
_isReady.SetValue(_udonBehaviour, isReady);
|
||||
}
|
||||
|
||||
public void OnReady()
|
||||
{
|
||||
SetIsReady(true);
|
||||
}
|
||||
|
||||
public UdonBehaviour GetUdonBehaviour()
|
||||
{
|
||||
return _udonBehaviour;
|
||||
}
|
||||
|
||||
#region IClientSimSyncableHandler
|
||||
|
||||
public void OnOwnershipTransferred(int ownerID)
|
||||
{
|
||||
_udonBehaviour.RunEvent("_onOwnershipTransferred", ("Player", VRCPlayerApi.GetPlayerById(ownerID)));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IClientSimInteractable
|
||||
|
||||
public float GetProximity()
|
||||
{
|
||||
return _udonBehaviour.proximity;
|
||||
}
|
||||
|
||||
public bool CanInteract()
|
||||
{
|
||||
return _udonBehaviour.IsInteractive;
|
||||
}
|
||||
|
||||
public string GetInteractText()
|
||||
{
|
||||
return _udonBehaviour.interactText;
|
||||
}
|
||||
|
||||
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.
|
||||
|
||||
//check if this object has already been destroyed, we can't just do a null check because that still throws a destroyed object error in unity
|
||||
if (!Utilities.IsValid(this))
|
||||
{
|
||||
return Vector3.zero;
|
||||
}
|
||||
|
||||
|
||||
return ClientSimTooltip.GetToolTipPosition(gameObject);
|
||||
}
|
||||
|
||||
public void Interact()
|
||||
{
|
||||
_udonBehaviour.Interact();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IClientSimPickupable
|
||||
|
||||
public void OnPickup()
|
||||
{
|
||||
_udonBehaviour.OnPickup();
|
||||
}
|
||||
|
||||
public void OnDrop()
|
||||
{
|
||||
_udonBehaviour.OnDrop();
|
||||
}
|
||||
|
||||
public void OnPickupUseDown()
|
||||
{
|
||||
_udonBehaviour.OnPickupUseDown();
|
||||
}
|
||||
|
||||
public void OnPickupUseUp()
|
||||
{
|
||||
_udonBehaviour.OnPickupUseUp();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IClientSimStationHandler
|
||||
|
||||
public void OnStationEnter(VRCStation station)
|
||||
{
|
||||
VRC.SDK3.Components.VRCStation sdk3Station = station as VRC.SDK3.Components.VRCStation;
|
||||
_udonBehaviour.RunEvent(sdk3Station.OnLocalPlayerEnterStation, ("Player", Networking.LocalPlayer));
|
||||
}
|
||||
|
||||
public void OnStationExit(VRCStation station)
|
||||
{
|
||||
VRC.SDK3.Components.VRCStation sdk3Station = station as VRC.SDK3.Components.VRCStation;
|
||||
_udonBehaviour.RunEvent(sdk3Station.OnLocalPlayerExitStation, ("Player", Networking.LocalPlayer));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 47cf12a423d907241aecd58f6c25b67f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 35b459bb3c0a402478e4dc51b61f4e08
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,13 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public interface IClientSimInteractable
|
||||
{
|
||||
float GetProximity();
|
||||
bool CanInteract();
|
||||
string GetInteractText();
|
||||
Vector3 GetInteractTextPlacement();
|
||||
void Interact();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 21636088934f3b046ae75a139062188f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,10 @@
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public interface IClientSimPickupHandler
|
||||
{
|
||||
void OnPickup();
|
||||
void OnDrop();
|
||||
void OnPickupUseDown();
|
||||
void OnPickupUseUp();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e92c80793952b604689f26d846684351
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using VRC.SDKBase;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public interface IClientSimPickupable : IClientSimInteractable
|
||||
{
|
||||
bool IsHeld();
|
||||
VRCPlayerApi GetHoldingPlayer();
|
||||
bool AutoHold();
|
||||
GameObject GetGameObject();
|
||||
Transform GetTransform();
|
||||
Rigidbody GetRigidbody();
|
||||
VRC_Pickup GetPickup();
|
||||
VRC_Pickup.PickupOrientation GetOrientation();
|
||||
Transform GetGunLocation();
|
||||
Transform GetGripLocation();
|
||||
float GetThrowVelocityBoostScale();
|
||||
bool AllowManipulation();
|
||||
void Pickup(VRCPlayerApi player, VRC_Pickup.PickupHand heldHand, Action<IClientSimPickupable> forceDrop);
|
||||
void Drop(VRCPlayerApi player);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 055ff67a9eb2dd64eb2c06f4df3626e5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,9 @@
|
||||
using VRC.SDK3.Platform;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public interface IClientSimPlatformManager
|
||||
{
|
||||
void OnScreenUpdate(ScreenUpdateData data);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0eab22d28a864961b5fdde0d9feae259
|
||||
timeCreated: 1698363855
|
||||
@ -0,0 +1,19 @@
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an object that syncs its position
|
||||
/// </summary>
|
||||
public interface IClientSimPositionSyncable : IClientSimSyncable, IClientSimRespawnHandler
|
||||
{
|
||||
bool SyncPosition { get; }
|
||||
void SetIsKinematic(bool value);
|
||||
void SetUseGravity(bool value);
|
||||
bool GetIsKinematic();
|
||||
bool GetUseGravity();
|
||||
void UpdatePositionSync();
|
||||
Transform GetTransform();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4b6da4177d7e4ca78b196bbf95952162
|
||||
timeCreated: 1640133052
|
||||
@ -0,0 +1,7 @@
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public interface IClientSimRespawnHandler
|
||||
{
|
||||
void Respawn();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c5fb7511272166a46844d934faa1c807
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,25 @@
|
||||
using UnityEngine;
|
||||
using VRC.SDKBase;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public interface IClientSimStation
|
||||
{
|
||||
Transform EnterLocation();
|
||||
Transform ExitLocation();
|
||||
bool IsMobile();
|
||||
bool IsSeated();
|
||||
bool DisableStationExit();
|
||||
bool CanUseStationFromStation();
|
||||
bool IsLockedInStation();
|
||||
VRCStation GetStation();
|
||||
GameObject GetStationGameObject();
|
||||
Transform GetStationTransform();
|
||||
|
||||
void EnterStation(VRCPlayerApi player);
|
||||
void ExitStation(VRCPlayerApi player);
|
||||
|
||||
bool IsOccupied();
|
||||
VRCPlayerApi GetCurrentSittingPlayer();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 74b90df615347ae4ea37ca4ad194ae63
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,10 @@
|
||||
using VRC.SDKBase;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public interface IClientSimStationHandler
|
||||
{
|
||||
void OnStationEnter(VRCStation station);
|
||||
void OnStationExit(VRCStation station);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c3297e7438270ea4cb73974aaad463b9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public interface IClientSimSyncable
|
||||
{
|
||||
int GetOwner();
|
||||
void SetOwner(int ownerID);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 58e4590a77a47fa429b2271e49050c99
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,7 @@
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public interface IClientSimSyncableHandler
|
||||
{
|
||||
void OnOwnershipTransferred(int ownerID);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d9cad5ab39e663849a092d187a23aa10
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dc4f1fbd5cfb45f1994c36e811fd3d54
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,379 @@
|
||||
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
using System.Text.RegularExpressions;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using VRC.SDKBase;
|
||||
#endif
|
||||
|
||||
using VRC.Udon.Common;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
// TODO refactor Input system to queue events from Unity's input system instead of firing events right away.
|
||||
// Unity's input events are processed and sent before ALL monobehaviours. In test environment, this will happen
|
||||
// right after modifying the input device, which will happen at the end of the frame instead. In order to properly
|
||||
// process input events the same in runtime and tests, the events will need to be queued and processed in mono behaviours.
|
||||
// This would also allow for other event types to be included that does not use the Input System (eg vr controls).
|
||||
|
||||
/// <summary>
|
||||
/// An implementation of ClientSimInput that receives input events from Unity's Input System using InputActions.
|
||||
/// Events from the action system are then sent to systems listening to input events.
|
||||
/// </summary>
|
||||
public class ClientSimInputActionBased : ClientSimInputBase
|
||||
{
|
||||
private readonly ClientSimSettings _settings;
|
||||
|
||||
/* Items need to be wrapped in this define to prevent compiler errors on initial import
|
||||
when the Input System has not yet been imported or enabled.*/
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
private readonly InputAction _movementHorizontal;
|
||||
private readonly InputAction _movementVertical;
|
||||
private readonly InputAction _lookHorizontal;
|
||||
private readonly InputAction _lookVertical;
|
||||
|
||||
private readonly InputAction _jumpLeft;
|
||||
private readonly InputAction _jumpRight;
|
||||
private readonly InputAction _useLeft;
|
||||
private readonly InputAction _useRight;
|
||||
private readonly InputAction _grabLeft;
|
||||
private readonly InputAction _grabRight;
|
||||
private readonly InputAction _dropLeft;
|
||||
private readonly InputAction _dropRight;
|
||||
private readonly InputAction _toggleMenuLeft;
|
||||
private readonly InputAction _toggleMenuRight;
|
||||
|
||||
#region NonVR Only
|
||||
|
||||
private readonly InputAction _run;
|
||||
private readonly InputAction _toggleCrouch;
|
||||
private readonly InputAction _toggleProne;
|
||||
private readonly InputAction _releaseMouse;
|
||||
|
||||
private readonly InputAction _pickupRotateUpDown;
|
||||
private readonly InputAction _pickupRotateLeftRight;
|
||||
private readonly InputAction _pickupRotateCwCcw;
|
||||
private readonly InputAction _pickupManipulateForwardBack;
|
||||
|
||||
#endregion
|
||||
|
||||
private InputActionAsset InputActions;
|
||||
|
||||
public ClientSimInputActionBased(InputActionAsset actionAsset, ClientSimSettings settings)
|
||||
{
|
||||
InputActions = actionAsset;
|
||||
|
||||
_settings = settings;
|
||||
|
||||
_lookHorizontal = actionAsset["LookHorizontal"];
|
||||
_lookVertical = actionAsset["LookVertical"];
|
||||
_movementHorizontal = actionAsset["MovementHorizontal"];
|
||||
_movementVertical = actionAsset["MovementVertical"];
|
||||
|
||||
_jumpLeft = actionAsset["JumpLeft"];
|
||||
_jumpRight = actionAsset["JumpRight"];
|
||||
_useLeft = actionAsset["UseLeft"];
|
||||
_useRight = actionAsset["UseRight"];
|
||||
_grabLeft = actionAsset["GrabLeft"];
|
||||
_grabRight = actionAsset["GrabRight"];
|
||||
_dropLeft = actionAsset["DropLeft"];
|
||||
_dropRight = actionAsset["DropRight"];
|
||||
_toggleMenuLeft = actionAsset["ToggleMenuLeft"];
|
||||
_toggleMenuRight = actionAsset["ToggleMenuRight"];
|
||||
|
||||
// Desktop only input options.
|
||||
_run = actionAsset["Run"];
|
||||
_toggleCrouch = actionAsset["ToggleCrouch"];
|
||||
_toggleProne = actionAsset["ToggleProne"];
|
||||
_releaseMouse = actionAsset["ReleaseMouse"];
|
||||
|
||||
_pickupRotateUpDown = actionAsset["PickupRotateUpDown"];
|
||||
_pickupRotateLeftRight = actionAsset["PickupRotateLeftRight"];
|
||||
_pickupRotateCwCcw = actionAsset["PickupRotateCwCcw"];
|
||||
_pickupManipulateForwardBack = actionAsset["PickupManipulateForwardBack"];
|
||||
|
||||
|
||||
_jumpLeft.performed += HandleJumpLeft;
|
||||
_jumpLeft.canceled += HandleJumpLeft;
|
||||
_jumpRight.performed += HandleJumpRight;
|
||||
_jumpRight.canceled += HandleJumpRight;
|
||||
|
||||
_useLeft.performed += HandleUseLeft;
|
||||
_useLeft.canceled += HandleUseLeft;
|
||||
_useRight.performed += HandleUseRight;
|
||||
_useRight.canceled += HandleUseRight;
|
||||
|
||||
_grabLeft.performed += HandleGrabLeft;
|
||||
_grabLeft.canceled += HandleGrabLeft;
|
||||
_grabRight.performed += HandleGrabRight;
|
||||
_grabRight.canceled += HandleGrabRight;
|
||||
|
||||
_dropLeft.performed += HandleDropLeft;
|
||||
_dropLeft.canceled += HandleDropLeft;
|
||||
_dropRight.performed += HandleDropRight;
|
||||
_dropRight.canceled += HandleDropRight;
|
||||
|
||||
_toggleMenuLeft.performed += HandleToggleMenuLeft;
|
||||
_toggleMenuLeft.canceled += HandleToggleMenuLeft;
|
||||
_toggleMenuRight.performed += HandleToggleMenuRight;
|
||||
_toggleMenuRight.canceled += HandleToggleMenuRight;
|
||||
|
||||
_run.performed += HandleRun;
|
||||
_run.canceled += HandleRun;
|
||||
_toggleCrouch.performed += HandleToggleCrouch;
|
||||
_toggleCrouch.canceled += HandleToggleCrouch;
|
||||
_toggleProne.performed += HandleToggleProne;
|
||||
_toggleProne.canceled += HandleToggleProne;
|
||||
_releaseMouse.performed += HandleReleaseMouse;
|
||||
_releaseMouse.canceled += HandleReleaseMouse;
|
||||
|
||||
foreach (InputAction action in actionAsset)
|
||||
{
|
||||
action.performed += SetInputDevice;
|
||||
}
|
||||
}
|
||||
|
||||
private VRCInputMethod _lastInputMethod = VRCInputMethod.Count;
|
||||
|
||||
public VRCInputMethod LastInputMethod
|
||||
{
|
||||
get => _lastInputMethod;
|
||||
set
|
||||
{
|
||||
// Only send events for changes
|
||||
if(_lastInputMethod == value) return;
|
||||
|
||||
_lastInputMethod = value;
|
||||
SendInputMethodChangedEvent(_lastInputMethod);
|
||||
}
|
||||
}
|
||||
|
||||
private const string MOUSE_LOOK_PATTERN = @"Player/Look.*Mouse/delta";
|
||||
bool isTouchActive = false;
|
||||
private void SetInputDevice(InputAction.CallbackContext ctx)
|
||||
{
|
||||
if(Regex.IsMatch(ctx.action.ToString(), MOUSE_LOOK_PATTERN)) return; // This is to avoid changing the tooltip icon when looking with a mouse
|
||||
isTouchActive = (ctx.control.device.description.empty || Touchscreen.current != null && ctx.control.device.GetType().Equals(Touchscreen.current.GetType())); // On screen controls
|
||||
if (!isTouchActive)
|
||||
{
|
||||
if (Keyboard.current != null && ctx.control.device.GetType().Equals(Keyboard.current.GetType()))
|
||||
{
|
||||
#if VRC_MOBILE && UNITY_ANDROID
|
||||
//This prevents the android back button from switching to keyboard and disabling touch UI
|
||||
if (ctx.control.device.description.interfaceName == "Android")
|
||||
return;
|
||||
#endif
|
||||
LastInputMethod = VRCInputMethod.Keyboard;
|
||||
return;
|
||||
}
|
||||
if (Mouse.current != null && ctx.control.device.GetType().Equals(Mouse.current.GetType()))
|
||||
{
|
||||
LastInputMethod = VRCInputMethod.Mouse;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Gamepad.current != null && ctx.control.device.GetType().Equals(Gamepad.current.GetType()))
|
||||
{
|
||||
LastInputMethod = VRCInputMethod.Controller;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LastInputMethod = VRCInputMethod.Touch;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
base.Dispose();
|
||||
|
||||
// Go through and unsubscribe from all input actions
|
||||
_jumpLeft.performed -= HandleJumpLeft;
|
||||
_jumpLeft.canceled -= HandleJumpLeft;
|
||||
_jumpRight.performed -= HandleJumpRight;
|
||||
_jumpRight.canceled -= HandleJumpRight;
|
||||
|
||||
_useLeft.performed -= HandleUseLeft;
|
||||
_useLeft.canceled -= HandleUseLeft;
|
||||
_useRight.performed -= HandleUseRight;
|
||||
_useRight.canceled -= HandleUseRight;
|
||||
|
||||
_grabLeft.performed -= HandleGrabLeft;
|
||||
_grabLeft.canceled -= HandleGrabLeft;
|
||||
_grabRight.performed -= HandleGrabRight;
|
||||
_grabRight.canceled -= HandleGrabRight;
|
||||
|
||||
_dropLeft.performed -= HandleDropLeft;
|
||||
_dropLeft.canceled -= HandleDropLeft;
|
||||
_dropRight.performed -= HandleDropRight;
|
||||
_dropRight.canceled -= HandleDropRight;
|
||||
|
||||
_toggleMenuLeft.performed -= HandleToggleMenuLeft;
|
||||
_toggleMenuLeft.canceled -= HandleToggleMenuLeft;
|
||||
_toggleMenuRight.performed -= HandleToggleMenuRight;
|
||||
_toggleMenuRight.canceled -= HandleToggleMenuRight;
|
||||
|
||||
_run.performed -= HandleRun;
|
||||
_run.canceled -= HandleRun;
|
||||
_toggleCrouch.performed -= HandleToggleCrouch;
|
||||
_toggleCrouch.canceled -= HandleToggleCrouch;
|
||||
_toggleProne.performed -= HandleToggleProne;
|
||||
_toggleProne.canceled -= HandleToggleProne;
|
||||
_releaseMouse.performed -= HandleReleaseMouse;
|
||||
_releaseMouse.canceled -= HandleReleaseMouse;
|
||||
}
|
||||
|
||||
|
||||
private void HandleJumpLeft(InputAction.CallbackContext context)
|
||||
{
|
||||
SendJumpEvent(context.ReadValueAsButton(), HandType.LEFT);
|
||||
}
|
||||
|
||||
private void HandleJumpRight(InputAction.CallbackContext context)
|
||||
{
|
||||
SendJumpEvent(context.ReadValueAsButton(), HandType.RIGHT);
|
||||
}
|
||||
|
||||
private void HandleUseLeft(InputAction.CallbackContext context)
|
||||
{
|
||||
SendUseEvent(context.ReadValueAsButton(), HandType.LEFT);
|
||||
}
|
||||
|
||||
private void HandleUseRight(InputAction.CallbackContext context)
|
||||
{
|
||||
SendUseEvent(context.ReadValueAsButton(), HandType.RIGHT);
|
||||
}
|
||||
|
||||
private void HandleGrabLeft(InputAction.CallbackContext context)
|
||||
{
|
||||
SendGrabEvent(context.ReadValueAsButton(), HandType.LEFT);
|
||||
}
|
||||
|
||||
private void HandleGrabRight(InputAction.CallbackContext context)
|
||||
{
|
||||
SendGrabEvent(context.ReadValueAsButton(), HandType.RIGHT);
|
||||
}
|
||||
|
||||
private void HandleDropLeft(InputAction.CallbackContext context)
|
||||
{
|
||||
SendDropEvent(context.ReadValueAsButton(), HandType.LEFT);
|
||||
}
|
||||
|
||||
private void HandleDropRight(InputAction.CallbackContext context)
|
||||
{
|
||||
SendDropEvent(context.ReadValueAsButton(), HandType.RIGHT);
|
||||
}
|
||||
|
||||
private void HandleToggleMenuLeft(InputAction.CallbackContext context)
|
||||
{
|
||||
SendToggleMenuEvent(context.ReadValueAsButton(), HandType.LEFT);
|
||||
}
|
||||
|
||||
private void HandleToggleMenuRight(InputAction.CallbackContext context)
|
||||
{
|
||||
SendToggleMenuEvent(context.ReadValueAsButton(), HandType.RIGHT);
|
||||
}
|
||||
|
||||
private void HandleRun(InputAction.CallbackContext context)
|
||||
{
|
||||
SendRunEvent(context.ReadValueAsButton());
|
||||
}
|
||||
|
||||
private void HandleToggleCrouch(InputAction.CallbackContext context)
|
||||
{
|
||||
SendToggleCrouchEvent(context.ReadValueAsButton());
|
||||
}
|
||||
|
||||
private void HandleToggleProne(InputAction.CallbackContext context)
|
||||
{
|
||||
SendToggleProneEvent(context.ReadValueAsButton());
|
||||
}
|
||||
|
||||
private void HandleReleaseMouse(InputAction.CallbackContext context)
|
||||
{
|
||||
SendReleaseMouseEvent(context.ReadValueAsButton());
|
||||
}
|
||||
#endif
|
||||
|
||||
public override float GetMovementHorizontal()
|
||||
{
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
return _movementHorizontal.ReadValue<float>();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
public override float GetMovementVertical()
|
||||
{
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
return _movementVertical.ReadValue<float>();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
public override float GetLookHorizontal()
|
||||
{
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
if (_pickupRotateLeftRight.ReadValue<float>() != 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return _lookHorizontal.ReadValue<float>();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
public override float GetLookVertical()
|
||||
{
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
if (_pickupRotateUpDown.ReadValue<float>() != 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return _lookVertical.ReadValue<float>() * (_settings.invertMouseLook ? -1 : 1);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
public override float GetPickupRotateUpDown()
|
||||
{
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
return _pickupRotateUpDown.ReadValue<float>();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
public override float GetPickupRotateLeftRight()
|
||||
{
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
return _pickupRotateLeftRight.ReadValue<float>();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
public override float GetPickupRotateCwCcw()
|
||||
{
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
return _pickupRotateCwCcw.ReadValue<float>();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
public override float GetPickupManipulateDistance()
|
||||
{
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
return _pickupManipulateForwardBack.ReadValue<float>();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 606ef90f0aab477f88f3df2bd3dece3b
|
||||
timeCreated: 1640211870
|
||||
@ -0,0 +1,242 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using VRC.SDKBase;
|
||||
using VRC.Udon.Common;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
/// <summary>
|
||||
/// Base method for handling subscribing to and sending input events.
|
||||
/// Class is abstract to allow for Test versions to mock sending input events.
|
||||
/// </summary>
|
||||
public abstract class ClientSimInputBase : IClientSimInput, IDisposable
|
||||
{
|
||||
private Action<bool, HandType> _jumpEvent;
|
||||
private Action<bool, HandType> _useEvent;
|
||||
private Action<bool, HandType> _grabEvent;
|
||||
private Action<bool, HandType> _dropEvent;
|
||||
private Action<bool, HandType> _toggleMenuEvent;
|
||||
|
||||
private Action<bool> _runEvent;
|
||||
private Action<bool> _toggleCrouchEvent;
|
||||
private Action<bool> _toggleProneEvent;
|
||||
private Action<bool> _releaseMouseEvent;
|
||||
|
||||
private Action<VRCInputMethod> _inputMethodChangedEvent;
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
// Clear all subscriptions
|
||||
_jumpEvent = null;
|
||||
_useEvent = null;
|
||||
_grabEvent = null;
|
||||
_dropEvent = null;
|
||||
_toggleMenuEvent = null;
|
||||
_inputMethodChangedEvent = null;
|
||||
|
||||
_runEvent = null;
|
||||
_toggleCrouchEvent = null;
|
||||
_toggleProneEvent = null;
|
||||
_releaseMouseEvent = null;
|
||||
}
|
||||
|
||||
#region Event Subscriptions
|
||||
|
||||
public void SubscribeJump(Action<bool, HandType> handler)
|
||||
{
|
||||
_jumpEvent += handler;
|
||||
}
|
||||
|
||||
public void UnsubscribeJump(Action<bool, HandType> handler)
|
||||
{
|
||||
_jumpEvent -= handler;
|
||||
}
|
||||
|
||||
|
||||
public void SubscribeUse(Action<bool, HandType> handler)
|
||||
{
|
||||
_useEvent += handler;
|
||||
}
|
||||
|
||||
public void UnsubscribeUse(Action<bool, HandType> handler)
|
||||
{
|
||||
_useEvent -= handler;
|
||||
}
|
||||
|
||||
|
||||
public void SubscribeGrab(Action<bool, HandType> handler)
|
||||
{
|
||||
_grabEvent += handler;
|
||||
}
|
||||
|
||||
public void UnsubscribeGrab(Action<bool, HandType> handler)
|
||||
{
|
||||
_grabEvent -= handler;
|
||||
}
|
||||
|
||||
|
||||
public void SubscribeDrop(Action<bool, HandType> handler)
|
||||
{
|
||||
_dropEvent += handler;
|
||||
}
|
||||
|
||||
public void UnsubscribeDrop(Action<bool, HandType> handler)
|
||||
{
|
||||
_dropEvent -= handler;
|
||||
}
|
||||
|
||||
|
||||
public void SubscribeToggleMenu(Action<bool, HandType> handler)
|
||||
{
|
||||
_toggleMenuEvent += handler;
|
||||
}
|
||||
|
||||
public void UnsubscribeToggleMenu(Action<bool, HandType> handler)
|
||||
{
|
||||
_toggleMenuEvent -= handler;
|
||||
}
|
||||
|
||||
|
||||
public void SubscribeRun(Action<bool> handler)
|
||||
{
|
||||
_runEvent += handler;
|
||||
}
|
||||
|
||||
public void UnsubscribeRun(Action<bool> handler)
|
||||
{
|
||||
_runEvent -= handler;
|
||||
}
|
||||
|
||||
|
||||
public void SubscribeToggleCrouch(Action<bool> handler)
|
||||
{
|
||||
_toggleCrouchEvent += handler;
|
||||
}
|
||||
|
||||
public void UnsubscribeToggleCrouch(Action<bool> handler)
|
||||
{
|
||||
_toggleCrouchEvent -= handler;
|
||||
}
|
||||
|
||||
|
||||
public void SubscribeToggleProne(Action<bool> handler)
|
||||
{
|
||||
_toggleProneEvent += handler;
|
||||
}
|
||||
|
||||
public void UnsubscribeToggleProne(Action<bool> handler)
|
||||
{
|
||||
_toggleProneEvent -= handler;
|
||||
}
|
||||
|
||||
|
||||
public void SubscribeReleaseMouse(Action<bool> handler)
|
||||
{
|
||||
_releaseMouseEvent += handler;
|
||||
}
|
||||
|
||||
public void UnsubscribeReleaseMouse(Action<bool> handler)
|
||||
{
|
||||
_releaseMouseEvent -= handler;
|
||||
}
|
||||
|
||||
public void SubscribeInputChangedEvent(Action<VRCInputMethod> handler)
|
||||
{
|
||||
_inputMethodChangedEvent += handler;
|
||||
}
|
||||
|
||||
public void UnsubscribeInputChangedEvent(Action<VRCInputMethod> handler)
|
||||
{
|
||||
_inputMethodChangedEvent -= handler;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetAxisData
|
||||
|
||||
public Vector2 GetMovementAxes()
|
||||
{
|
||||
float x = GetMovementHorizontal();
|
||||
float y = GetMovementVertical();
|
||||
|
||||
return new Vector2(x, y);
|
||||
}
|
||||
|
||||
public Vector2 GetLookAxes()
|
||||
{
|
||||
float x = GetLookHorizontal();
|
||||
float y = GetLookVertical();
|
||||
|
||||
return new Vector2(x, y);
|
||||
}
|
||||
|
||||
public abstract float GetMovementHorizontal();
|
||||
|
||||
public abstract float GetMovementVertical();
|
||||
|
||||
public abstract float GetLookHorizontal();
|
||||
|
||||
public abstract float GetLookVertical();
|
||||
|
||||
public abstract float GetPickupRotateUpDown();
|
||||
|
||||
public abstract float GetPickupRotateLeftRight();
|
||||
|
||||
public abstract float GetPickupRotateCwCcw();
|
||||
|
||||
public abstract float GetPickupManipulateDistance();
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
public void SendJumpEvent(bool value, HandType handType)
|
||||
{
|
||||
_jumpEvent?.Invoke(value, handType);
|
||||
}
|
||||
|
||||
public void SendUseEvent(bool value, HandType handType)
|
||||
{
|
||||
_useEvent?.Invoke(value, handType);
|
||||
}
|
||||
|
||||
public void SendGrabEvent(bool value, HandType handType)
|
||||
{
|
||||
_grabEvent?.Invoke(value, handType);
|
||||
}
|
||||
|
||||
public void SendDropEvent(bool value, HandType handType)
|
||||
{
|
||||
_dropEvent?.Invoke(value, handType);
|
||||
}
|
||||
|
||||
public void SendToggleMenuEvent(bool value, HandType handType)
|
||||
{
|
||||
_toggleMenuEvent?.Invoke(value, handType);
|
||||
}
|
||||
|
||||
public void SendRunEvent(bool value)
|
||||
{
|
||||
_runEvent?.Invoke(value);
|
||||
}
|
||||
|
||||
public void SendToggleCrouchEvent(bool value)
|
||||
{
|
||||
_toggleCrouchEvent?.Invoke(value);
|
||||
}
|
||||
|
||||
public void SendToggleProneEvent(bool value)
|
||||
{
|
||||
_toggleProneEvent?.Invoke(value);
|
||||
}
|
||||
|
||||
public void SendReleaseMouseEvent(bool value)
|
||||
{
|
||||
_releaseMouseEvent?.Invoke(value);
|
||||
}
|
||||
|
||||
public void SendInputMethodChangedEvent(VRCInputMethod value)
|
||||
{
|
||||
_inputMethodChangedEvent?.Invoke(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9f663f3afb8c43b9bde934ce5e27b320
|
||||
timeCreated: 1640210807
|
||||
@ -0,0 +1,58 @@
|
||||
using UnityEngine;
|
||||
using VRC.SDKBase;
|
||||
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
using UnityEngine.InputSystem;
|
||||
#endif
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
/// <summary>
|
||||
/// Wrapper around ClientSimInputActionBased that supplies the input actions.
|
||||
/// Classes were split to allow for testing without monobehaviours.
|
||||
/// </summary>
|
||||
[AddComponentMenu("")]
|
||||
public class ClientSimInputManager : ClientSimBehaviour
|
||||
{
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
private PlayerInput _playerInput;
|
||||
private ClientSimInputActionBased _input;
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
_playerInput = GetComponent<PlayerInput>();
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
_input?.Dispose();
|
||||
}
|
||||
#endif
|
||||
|
||||
public void Initialize(ClientSimSettings settings)
|
||||
{
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
_input = new ClientSimInputActionBased(_playerInput.actions, settings);
|
||||
#endif
|
||||
}
|
||||
|
||||
public IClientSimInput GetInput()
|
||||
{
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
return _input;
|
||||
#else
|
||||
return null;
|
||||
#endif
|
||||
}
|
||||
|
||||
public VRCInputMethod GetLastUsedInputMethod()
|
||||
{
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
return _input.LastInputMethod;
|
||||
#else
|
||||
return VRCInputMethod.Generic;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b27b7e912c8f06b47b47730996323943
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,938 @@
|
||||
{
|
||||
"name": "ClientSimInputMapping",
|
||||
"maps": [
|
||||
{
|
||||
"name": "Player",
|
||||
"id": "2f50182f-8d0e-45db-86fb-c28a4c2928c3",
|
||||
"actions": [
|
||||
{
|
||||
"name": "LookHorizontal",
|
||||
"type": "Value",
|
||||
"id": "fd5ba6df-78c4-4e25-9fd5-7e3d97cff8c1",
|
||||
"expectedControlType": "Axis",
|
||||
"processors": "",
|
||||
"interactions": ""
|
||||
},
|
||||
{
|
||||
"name": "LookVertical",
|
||||
"type": "Value",
|
||||
"id": "d9675fd8-9661-4368-984d-f6f7683fe821",
|
||||
"expectedControlType": "Axis",
|
||||
"processors": "",
|
||||
"interactions": ""
|
||||
},
|
||||
{
|
||||
"name": "MovementHorizontal",
|
||||
"type": "Value",
|
||||
"id": "c5e34fa0-7b42-436a-aac5-43719b6671e5",
|
||||
"expectedControlType": "Axis",
|
||||
"processors": "",
|
||||
"interactions": ""
|
||||
},
|
||||
{
|
||||
"name": "MovementVertical",
|
||||
"type": "Value",
|
||||
"id": "9e5c4572-7e08-413a-8992-d08e65de6588",
|
||||
"expectedControlType": "Axis",
|
||||
"processors": "",
|
||||
"interactions": ""
|
||||
},
|
||||
{
|
||||
"name": "JumpLeft",
|
||||
"type": "Button",
|
||||
"id": "4bcd4015-fce1-40e8-bac9-17c60193e8a6",
|
||||
"expectedControlType": "Button",
|
||||
"processors": "",
|
||||
"interactions": ""
|
||||
},
|
||||
{
|
||||
"name": "JumpRight",
|
||||
"type": "Button",
|
||||
"id": "e1d78f1c-246d-42ce-8dad-64769265bc40",
|
||||
"expectedControlType": "Button",
|
||||
"processors": "",
|
||||
"interactions": ""
|
||||
},
|
||||
{
|
||||
"name": "UseLeft",
|
||||
"type": "Button",
|
||||
"id": "1c0d0334-cacd-4c50-81e3-c9efb4436ccb",
|
||||
"expectedControlType": "Button",
|
||||
"processors": "",
|
||||
"interactions": ""
|
||||
},
|
||||
{
|
||||
"name": "UseRight",
|
||||
"type": "Button",
|
||||
"id": "5e78bbbe-04e6-44df-bc85-404f92936b98",
|
||||
"expectedControlType": "Button",
|
||||
"processors": "",
|
||||
"interactions": ""
|
||||
},
|
||||
{
|
||||
"name": "GrabLeft",
|
||||
"type": "Button",
|
||||
"id": "a9b3a7e3-2b29-48d1-8be7-c7a2fba1d70d",
|
||||
"expectedControlType": "Button",
|
||||
"processors": "",
|
||||
"interactions": ""
|
||||
},
|
||||
{
|
||||
"name": "GrabRight",
|
||||
"type": "Button",
|
||||
"id": "e77cb057-0a67-47a5-b73b-cf5f750feae1",
|
||||
"expectedControlType": "Button",
|
||||
"processors": "",
|
||||
"interactions": ""
|
||||
},
|
||||
{
|
||||
"name": "DropLeft",
|
||||
"type": "Button",
|
||||
"id": "5e9b0664-5568-442e-bc7b-000386ea8cb7",
|
||||
"expectedControlType": "Button",
|
||||
"processors": "",
|
||||
"interactions": ""
|
||||
},
|
||||
{
|
||||
"name": "DropRight",
|
||||
"type": "Button",
|
||||
"id": "5ae3c089-7d25-41d2-8245-78c24b806ae9",
|
||||
"expectedControlType": "Button",
|
||||
"processors": "",
|
||||
"interactions": ""
|
||||
},
|
||||
{
|
||||
"name": "ToggleMenuLeft",
|
||||
"type": "Button",
|
||||
"id": "1fe9ba51-431d-42df-b3b8-fb55b37a26d9",
|
||||
"expectedControlType": "Button",
|
||||
"processors": "",
|
||||
"interactions": ""
|
||||
},
|
||||
{
|
||||
"name": "ToggleMenuRight",
|
||||
"type": "Button",
|
||||
"id": "8a4af8b2-f882-4ae3-a6ea-f8d10c88a1f6",
|
||||
"expectedControlType": "Button",
|
||||
"processors": "",
|
||||
"interactions": ""
|
||||
},
|
||||
{
|
||||
"name": "Run",
|
||||
"type": "Button",
|
||||
"id": "e47a69fe-eadc-47da-a81f-909b6c277e00",
|
||||
"expectedControlType": "Button",
|
||||
"processors": "",
|
||||
"interactions": ""
|
||||
},
|
||||
{
|
||||
"name": "ToggleCrouch",
|
||||
"type": "Button",
|
||||
"id": "2064b4f9-486f-476d-800b-52f1208aff6c",
|
||||
"expectedControlType": "Button",
|
||||
"processors": "",
|
||||
"interactions": ""
|
||||
},
|
||||
{
|
||||
"name": "ToggleProne",
|
||||
"type": "Button",
|
||||
"id": "28ffcaeb-1d40-48b8-8ed9-593338b8e9be",
|
||||
"expectedControlType": "Button",
|
||||
"processors": "",
|
||||
"interactions": ""
|
||||
},
|
||||
{
|
||||
"name": "ReleaseMouse",
|
||||
"type": "Button",
|
||||
"id": "20ba4d98-6df4-4d39-aab4-5a0b170f1526",
|
||||
"expectedControlType": "Button",
|
||||
"processors": "",
|
||||
"interactions": ""
|
||||
},
|
||||
{
|
||||
"name": "PickupRotateUpDown",
|
||||
"type": "Button",
|
||||
"id": "5f707c29-abb7-489d-9762-4a19e7a44caf",
|
||||
"expectedControlType": "Button",
|
||||
"processors": "",
|
||||
"interactions": ""
|
||||
},
|
||||
{
|
||||
"name": "PickupRotateLeftRight",
|
||||
"type": "Button",
|
||||
"id": "aaf0f321-7c3d-49d6-991f-1c7ee7cf6425",
|
||||
"expectedControlType": "Button",
|
||||
"processors": "",
|
||||
"interactions": ""
|
||||
},
|
||||
{
|
||||
"name": "PickupRotateCwCcw",
|
||||
"type": "Button",
|
||||
"id": "97928f76-bc32-45a3-94fd-211a439b5a9e",
|
||||
"expectedControlType": "Button",
|
||||
"processors": "",
|
||||
"interactions": ""
|
||||
},
|
||||
{
|
||||
"name": "PickupManipulateForwardBack",
|
||||
"type": "Value",
|
||||
"id": "768b624a-5837-4f36-9f89-e4953a7a8951",
|
||||
"expectedControlType": "Axis",
|
||||
"processors": "",
|
||||
"interactions": ""
|
||||
}
|
||||
],
|
||||
"bindings": [
|
||||
{
|
||||
"name": "",
|
||||
"id": "550c6b6a-81c1-4282-b4fd-ac579d21ac6c",
|
||||
"path": "<Keyboard>/space",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "KeyboardMouse",
|
||||
"action": "JumpLeft",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "730090f3-1e28-4ef7-8a82-0ebb910ef667",
|
||||
"path": "<Keyboard>/c",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "KeyboardMouse",
|
||||
"action": "ToggleCrouch",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "b4cfeb73-71f8-45b9-8cdd-8e649dde9d1b",
|
||||
"path": "<Keyboard>/z",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "KeyboardMouse",
|
||||
"action": "ToggleProne",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "e7ed5e53-bd0b-40a1-a286-8b86a4372292",
|
||||
"path": "<Gamepad>/leftStickPress",
|
||||
"interactions": "Hold",
|
||||
"processors": "",
|
||||
"groups": "Gamepad",
|
||||
"action": "ToggleProne",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "9d0b9b99-72c2-46cf-8765-fbcc9b4589ef",
|
||||
"path": "<Keyboard>/tab",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "KeyboardMouse",
|
||||
"action": "ReleaseMouse",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "UpDown",
|
||||
"id": "599162a8-d480-47e8-a889-c48d14357572",
|
||||
"path": "1DAxis",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "",
|
||||
"action": "MovementVertical",
|
||||
"isComposite": true,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "negative",
|
||||
"id": "ef0c2b1a-07ce-45fc-8d51-1bd6fdcbb28f",
|
||||
"path": "<Keyboard>/s",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "KeyboardMouse",
|
||||
"action": "MovementVertical",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": true
|
||||
},
|
||||
{
|
||||
"name": "positive",
|
||||
"id": "554ed0de-b631-49a1-b623-878c3ab03682",
|
||||
"path": "<Keyboard>/w",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "KeyboardMouse",
|
||||
"action": "MovementVertical",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": true
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "094901d9-a4fa-43ef-8c9f-bfed9d7d8920",
|
||||
"path": "<Gamepad>/leftStick/y",
|
||||
"interactions": "",
|
||||
"processors": "AxisDeadzone",
|
||||
"groups": "Gamepad",
|
||||
"action": "MovementVertical",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "LeftRight",
|
||||
"id": "3c1a54d3-a057-4e61-8b9a-5b1f13341d5a",
|
||||
"path": "1DAxis",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "KeyboardMouse",
|
||||
"action": "MovementHorizontal",
|
||||
"isComposite": true,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "negative",
|
||||
"id": "57ae784a-0a44-45cb-b7b8-fcec8b04cad3",
|
||||
"path": "<Keyboard>/a",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "KeyboardMouse",
|
||||
"action": "MovementHorizontal",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": true
|
||||
},
|
||||
{
|
||||
"name": "positive",
|
||||
"id": "a334ecdc-1430-4b6a-afde-3ff6d2154773",
|
||||
"path": "<Keyboard>/d",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "KeyboardMouse",
|
||||
"action": "MovementHorizontal",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": true
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "b1ab7f24-f82a-42df-b586-cced45f62b2e",
|
||||
"path": "<Gamepad>/leftStick/x",
|
||||
"interactions": "",
|
||||
"processors": "AxisDeadzone",
|
||||
"groups": "Gamepad",
|
||||
"action": "MovementHorizontal",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "adab09ec-3821-417c-82b8-314882199eb0",
|
||||
"path": "<XRController>{RightHand}/primary2daxis/y",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "XRController",
|
||||
"action": "LookVertical",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "a7212801-53a8-4fe8-831b-01974f0c2d9f",
|
||||
"path": "<Mouse>/delta/y",
|
||||
"interactions": "",
|
||||
"processors": "Scale(factor=0.1)",
|
||||
"groups": "KeyboardMouse",
|
||||
"action": "LookVertical",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "7d1e21de-8a59-41db-9f28-c95b92b3da8c",
|
||||
"path": "<Gamepad>/rightStick/y",
|
||||
"interactions": "",
|
||||
"processors": "AxisDeadzone,Scale(factor=2)",
|
||||
"groups": "",
|
||||
"action": "LookVertical",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "3481d65f-35c3-48f7-b259-6f8d2cac26c8",
|
||||
"path": "<Mouse>/delta/x",
|
||||
"interactions": "",
|
||||
"processors": "Scale(factor=0.1)",
|
||||
"groups": "KeyboardMouse",
|
||||
"action": "LookHorizontal",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "4aeeecac-4996-47e7-bd05-af550efb62ac",
|
||||
"path": "<XRController>{RightHand}/primary2daxis/x",
|
||||
"interactions": "",
|
||||
"processors": "Scale(factor=4)",
|
||||
"groups": "XRController",
|
||||
"action": "LookHorizontal",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "6533983e-06ef-4adc-abd2-6cd33b462ac8",
|
||||
"path": "<Gamepad>/rightStick/x",
|
||||
"interactions": "",
|
||||
"processors": "AxisDeadzone,Scale(factor=2)",
|
||||
"groups": "Gamepad",
|
||||
"action": "LookHorizontal",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "f5444cd9-f41a-4ebb-aadf-c10211534afa",
|
||||
"path": "<XRController>{RightHand}/grippressed",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "XRController",
|
||||
"action": "GrabRight",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "ba0f411d-3372-4c6d-b9d5-c26e875be59c",
|
||||
"path": "<Mouse>/leftButton",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "KeyboardMouse",
|
||||
"action": "GrabRight",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "ad175ec7-32cb-49e5-a110-f579d3d3413c",
|
||||
"path": "<Mouse>/rightButton",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "KeyboardMouse",
|
||||
"action": "DropRight",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "1d68fa18-5dc4-4d90-9365-9c4db81311e2",
|
||||
"path": "<Gamepad>/buttonNorth",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Gamepad",
|
||||
"action": "DropRight",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "50eac56e-5677-4524-8d0f-a1fbf16f3900",
|
||||
"path": "<Gamepad>/rightShoulder",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Gamepad",
|
||||
"action": "DropRight",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "157bf0cb-a7e7-48d9-88fa-1517693070c5",
|
||||
"path": "<XRController>{RightHand}/triggerpressed",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "XRController",
|
||||
"action": "UseRight",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "3127ec01-bb2b-4e6d-a7ff-130d739c6b31",
|
||||
"path": "<Mouse>/leftButton",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "KeyboardMouse",
|
||||
"action": "UseRight",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "5ff2efde-e215-4a78-b8bc-0bff8e57e630",
|
||||
"path": "<Gamepad>/rightTrigger",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Gamepad",
|
||||
"action": "UseRight",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "66ff8685-5751-48e9-b8e1-52b8eee82e34",
|
||||
"path": "<Gamepad>/buttonEast",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Gamepad",
|
||||
"action": "UseRight",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "9f1da403-960f-41db-b08c-65d7599e899a",
|
||||
"path": "<Keyboard>/leftShift",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "KeyboardMouse",
|
||||
"action": "Run",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "UpDown",
|
||||
"id": "394c9c63-26cd-4401-a397-184c01a7fb06",
|
||||
"path": "1DAxis",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "",
|
||||
"action": "PickupRotateUpDown",
|
||||
"isComposite": true,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "negative",
|
||||
"id": "bf93b7e2-55ce-481e-85c2-0e8b4ae2f3c9",
|
||||
"path": "<Keyboard>/i",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "KeyboardMouse",
|
||||
"action": "PickupRotateUpDown",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": true
|
||||
},
|
||||
{
|
||||
"name": "positive",
|
||||
"id": "9de24fef-2a7c-4bcf-b274-63daff07abfe",
|
||||
"path": "<Keyboard>/k",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "KeyboardMouse",
|
||||
"action": "PickupRotateUpDown",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": true
|
||||
},
|
||||
{
|
||||
"name": "ClockwiseCounterClockwise",
|
||||
"id": "80006719-f2f8-4dc6-9fdf-443d2486f309",
|
||||
"path": "1DAxis",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "",
|
||||
"action": "PickupRotateCwCcw",
|
||||
"isComposite": true,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "negative",
|
||||
"id": "f3d77344-6c16-4b26-9dfb-ff765db9be87",
|
||||
"path": "<Keyboard>/u",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "KeyboardMouse",
|
||||
"action": "PickupRotateCwCcw",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": true
|
||||
},
|
||||
{
|
||||
"name": "positive",
|
||||
"id": "aae8cb97-dffd-4fb5-b4d3-8bc92c76da7c",
|
||||
"path": "<Keyboard>/o",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "KeyboardMouse",
|
||||
"action": "PickupRotateCwCcw",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": true
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "943c5ae4-0943-427d-95d9-cf4e676b20b0",
|
||||
"path": "<Mouse>/scroll/y",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "KeyboardMouse",
|
||||
"action": "PickupManipulateForwardBack",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "012bc491-7c79-43cd-872a-c9d5c56e6e6f",
|
||||
"path": "<XRController>{LeftHand}/primary2daxis/y",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "XRController",
|
||||
"action": "MovementVertical",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "94d2aec0-a0b9-4934-9b0a-8a27e75d118c",
|
||||
"path": "<XRController>{LeftHand}/primary2daxis/x",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "XRController",
|
||||
"action": "MovementHorizontal",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "11375370-60ed-4eff-968c-85131e5900f9",
|
||||
"path": "<XRController>{RightHand}/joystickorpadpressed",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "XRController",
|
||||
"action": "JumpRight",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "0650c167-2c34-4480-8deb-3c9c251c9563",
|
||||
"path": "<Gamepad>/buttonSouth",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Gamepad",
|
||||
"action": "JumpRight",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "9928474d-83f2-4067-a555-bc7dd2bdf3dd",
|
||||
"path": "<XRController>{LeftHand}/triggerpressed",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "XRController",
|
||||
"action": "UseLeft",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "3462f0fd-c25f-4223-88e1-e448815e9f90",
|
||||
"path": "<XRController>{LeftHand}/grippressed",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "XRController",
|
||||
"action": "GrabLeft",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "6be33530-03b7-47d5-baef-a1873dab0483",
|
||||
"path": "<XRController>{LeftHand}/primary",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "XRController",
|
||||
"action": "ToggleMenuLeft",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "a6937a04-1651-4f9b-b532-f1b1f52f91ea",
|
||||
"path": "<Keyboard>/escape",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "KeyboardMouse",
|
||||
"action": "ToggleMenuLeft",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "LeftRight",
|
||||
"id": "dc3ca725-f9f3-4b9d-b73d-ccab2de20c89",
|
||||
"path": "1DAxis",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "KeyboardMouse",
|
||||
"action": "PickupRotateLeftRight",
|
||||
"isComposite": true,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "negative",
|
||||
"id": "edbe58fa-0e59-446c-9765-589870585e9c",
|
||||
"path": "<Keyboard>/l",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "KeyboardMouse",
|
||||
"action": "PickupRotateLeftRight",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": true
|
||||
},
|
||||
{
|
||||
"name": "positive",
|
||||
"id": "6eab6abd-f646-4064-a093-bef75d51704f",
|
||||
"path": "<Keyboard>/j",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "KeyboardMouse",
|
||||
"action": "PickupRotateLeftRight",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": true
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "41374253-d07b-4eb9-b76f-68ff25ad6099",
|
||||
"path": "<XRController>{RightHand}/primary",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "XRController",
|
||||
"action": "ToggleMenuRight",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "98ed6e07-cbe7-4332-9ab3-7d130fc2be70",
|
||||
"path": "<Gamepad>/start",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Gamepad",
|
||||
"action": "ToggleMenuRight",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "813f1ec6-f321-4bd5-b091-a936c2173904",
|
||||
"path": "<Gamepad>/rightTrigger",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Gamepad",
|
||||
"action": "GrabRight",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "d2eb4465-b94a-4012-ab0d-5c9fa72c9cb7",
|
||||
"path": "<Gamepad>/buttonEast",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Gamepad",
|
||||
"action": "GrabRight",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"id": "d39fd262-9f80-4061-bf54-a42d997bb0d6",
|
||||
"path": "<Gamepad>/leftStickPress",
|
||||
"interactions": "Press",
|
||||
"processors": "",
|
||||
"groups": "Gamepad",
|
||||
"action": "ToggleCrouch",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "RightStickWithLeftShoulder",
|
||||
"id": "b2aff2a5-4826-433b-b14b-4c2c8925e56c",
|
||||
"path": "ButtonWithOneModifier",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Gamepad",
|
||||
"action": "PickupRotateUpDown",
|
||||
"isComposite": true,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "modifier",
|
||||
"id": "42575b80-955d-494a-bdff-4e83a6beb850",
|
||||
"path": "<Gamepad>/leftShoulder",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Gamepad",
|
||||
"action": "PickupRotateUpDown",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": true
|
||||
},
|
||||
{
|
||||
"name": "button",
|
||||
"id": "ada6cac4-3fc3-4dc5-a418-2d6c3f218d24",
|
||||
"path": "<Gamepad>/rightStick/y",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Gamepad",
|
||||
"action": "PickupRotateUpDown",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": true
|
||||
},
|
||||
{
|
||||
"name": "RightStickWithLeftShoulder",
|
||||
"id": "a69e5173-82f8-4ed7-8d30-af528c6fa262",
|
||||
"path": "ButtonWithOneModifier",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Gamepad",
|
||||
"action": "PickupRotateLeftRight",
|
||||
"isComposite": true,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "modifier",
|
||||
"id": "52c40760-cb07-427d-95c9-cd8539c939e8",
|
||||
"path": "<Gamepad>/leftShoulder",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Gamepad",
|
||||
"action": "PickupRotateLeftRight",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": true
|
||||
},
|
||||
{
|
||||
"name": "button",
|
||||
"id": "f3ce62de-2286-499f-bfbb-aaad0021a224",
|
||||
"path": "<Gamepad>/rightStick/x",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Gamepad",
|
||||
"action": "PickupRotateLeftRight",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": true
|
||||
},
|
||||
{
|
||||
"name": "LeftStickWithLeftShoulder",
|
||||
"id": "5466362d-116f-4eb8-9825-010812d07ff7",
|
||||
"path": "ButtonWithOneModifier",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Gamepad",
|
||||
"action": "PickupRotateCwCcw",
|
||||
"isComposite": true,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "modifier",
|
||||
"id": "79ec2bba-44b3-4a1a-a18c-e03370ecce44",
|
||||
"path": "<Gamepad>/leftShoulder",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Gamepad",
|
||||
"action": "PickupRotateCwCcw",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": true
|
||||
},
|
||||
{
|
||||
"name": "button",
|
||||
"id": "3c906a95-8491-42be-a414-8d69ecdf037b",
|
||||
"path": "<Gamepad>/leftStick/x",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Gamepad",
|
||||
"action": "PickupRotateCwCcw",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": true
|
||||
},
|
||||
{
|
||||
"name": "LeftStickWithLeftShoulder",
|
||||
"id": "9170df3e-d37e-4c49-8bb3-5a944ff141d5",
|
||||
"path": "ButtonWithOneModifier",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Gamepad",
|
||||
"action": "PickupManipulateForwardBack",
|
||||
"isComposite": true,
|
||||
"isPartOfComposite": false
|
||||
},
|
||||
{
|
||||
"name": "modifier",
|
||||
"id": "07f0af65-6b32-4bf4-ac49-52784277b1fc",
|
||||
"path": "<Gamepad>/leftShoulder",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Gamepad",
|
||||
"action": "PickupManipulateForwardBack",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": true
|
||||
},
|
||||
{
|
||||
"name": "button",
|
||||
"id": "0f1b2753-f8d1-4106-b35b-1551d1c825db",
|
||||
"path": "<Gamepad>/leftStick/y",
|
||||
"interactions": "",
|
||||
"processors": "",
|
||||
"groups": "Gamepad",
|
||||
"action": "PickupManipulateForwardBack",
|
||||
"isComposite": false,
|
||||
"isPartOfComposite": true
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"controlSchemes": [
|
||||
{
|
||||
"name": "KeyboardMouse",
|
||||
"bindingGroup": "KeyboardMouse",
|
||||
"devices": [
|
||||
{
|
||||
"devicePath": "<Keyboard>",
|
||||
"isOptional": false,
|
||||
"isOR": false
|
||||
},
|
||||
{
|
||||
"devicePath": "<Mouse>",
|
||||
"isOptional": false,
|
||||
"isOR": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Gamepad",
|
||||
"bindingGroup": "Gamepad",
|
||||
"devices": [
|
||||
{
|
||||
"devicePath": "<Gamepad>",
|
||||
"isOptional": false,
|
||||
"isOR": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "XRController",
|
||||
"bindingGroup": "XRController",
|
||||
"devices": [
|
||||
{
|
||||
"devicePath": "<XRController>{RightHand}",
|
||||
"isOptional": true,
|
||||
"isOR": false
|
||||
},
|
||||
{
|
||||
"devicePath": "<XRController>{LeftHand}",
|
||||
"isOptional": true,
|
||||
"isOR": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2a08897387d5ffd4795ccec0e8384a6a
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 11500000, guid: 8404be70184654265930450def6a9037, type: 3}
|
||||
generateWrapperCode: 0
|
||||
wrapperCodePath:
|
||||
wrapperClassName: ClientSimInputMapping
|
||||
wrapperCodeNamespace: VRC.SDK3.ClientSim
|
||||
@ -0,0 +1,193 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using VRC.SDKBase;
|
||||
using VRC.Udon;
|
||||
using VRC.Udon.Common;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
/// <summary>
|
||||
/// System responsible for listening to Input Events and sending them to UdonBehaviours.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Listens to Events:
|
||||
/// - ClientSimMenuStateChangedEvent
|
||||
/// Listens to Input Events:
|
||||
/// - Jump
|
||||
/// - Grab
|
||||
/// - Use
|
||||
/// - Drop
|
||||
/// </remarks>
|
||||
public class ClientSimUdonInput : IDisposable
|
||||
{
|
||||
private const float MINIMUM_MOVE_INPUT_EPS = 1e-3f;
|
||||
private const float MINIMUM_LOOK_INPUT_EPS = 1e-5f;
|
||||
|
||||
private readonly IClientSimInput _input;
|
||||
private readonly IClientSimEventDispatcher _eventDispatcher;
|
||||
/// <summary>
|
||||
/// A wrapper for sending events to all UdonBehaviours to create unit tests not dependent on UdonManager.
|
||||
/// </summary>
|
||||
private readonly IClientSimUdonInputEventSender _udonInputEventSender;
|
||||
|
||||
private Vector2 _prevInput;
|
||||
private Vector2 _prevLookInput = Vector2.zero;
|
||||
private Vector2 _prevMoveAxes = Vector2.zero;
|
||||
|
||||
private bool _isMenuOpen;
|
||||
private int _lastMenuUpdateFrame; // TODO update based on processing tick instead of time to allow for better testing.
|
||||
|
||||
// All button based events are queued until process time. This is done to ensure that all udon input events
|
||||
// happen at the same time in the frame and not mixed between when unity's update for the new Input Manager
|
||||
// sends events. Without this, input events would happen before UdonBehaviour.Update, causing strange out of
|
||||
// order issues.
|
||||
private readonly Queue<Action> _queuedEvents = new Queue<Action>();
|
||||
|
||||
public ClientSimUdonInput(
|
||||
IClientSimEventDispatcher eventDispatcher,
|
||||
IClientSimInput input,
|
||||
IClientSimUdonInputEventSender udonInputEventSender)
|
||||
{
|
||||
_input = input;
|
||||
_eventDispatcher = eventDispatcher;
|
||||
_udonInputEventSender = udonInputEventSender;
|
||||
|
||||
_eventDispatcher.Subscribe<ClientSimMenuStateChangedEvent>(SetMenuOpen);
|
||||
|
||||
// Input will be null with incorrect Unity input project settings.
|
||||
_input?.SubscribeJump(JumpInput);
|
||||
_input?.SubscribeUse(UseInput);
|
||||
_input?.SubscribeGrab(GrabInput);
|
||||
_input?.SubscribeDrop(DropInput);
|
||||
_input?.SubscribeInputChangedEvent(SendInputChangedEvent);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_eventDispatcher?.Unsubscribe<ClientSimMenuStateChangedEvent>(SetMenuOpen);
|
||||
|
||||
_input?.UnsubscribeJump(JumpInput);
|
||||
_input?.UnsubscribeUse(UseInput);
|
||||
_input?.UnsubscribeGrab(GrabInput);
|
||||
_input?.UnsubscribeDrop(DropInput);
|
||||
_input?.UnsubscribeInputChangedEvent(SendInputChangedEvent);
|
||||
}
|
||||
|
||||
#region ClientSim Events
|
||||
|
||||
private void SetMenuOpen(ClientSimMenuStateChangedEvent stateChangedEvent)
|
||||
{
|
||||
_lastMenuUpdateFrame = Time.frameCount;
|
||||
_isMenuOpen = stateChangedEvent.isMenuOpen;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ClientSim Input
|
||||
|
||||
private void JumpInput(bool value, HandType hand)
|
||||
{
|
||||
QueueButtonInputEvent(value, hand, UdonManager.UDON_INPUT_JUMP);
|
||||
}
|
||||
|
||||
private void UseInput(bool value, HandType hand)
|
||||
{
|
||||
QueueButtonInputEvent(value, hand, UdonManager.UDON_INPUT_USE);
|
||||
}
|
||||
|
||||
private void GrabInput(bool value, HandType hand)
|
||||
{
|
||||
QueueButtonInputEvent(value, hand, UdonManager.UDON_INPUT_GRAB);
|
||||
}
|
||||
|
||||
private void DropInput(bool value, HandType hand)
|
||||
{
|
||||
QueueButtonInputEvent(value, hand, UdonManager.UDON_INPUT_DROP);
|
||||
}
|
||||
|
||||
private void SendInputChangedEvent(VRCInputMethod inputMethod)
|
||||
{
|
||||
_queuedEvents.Enqueue(() =>
|
||||
{
|
||||
UdonManager.Instance.RunEvent(UdonManager.UDON_EVENT_ONINPUTMETHODCHANGED, ("inputMethod", inputMethod));
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void SendUdonInputBoolEvent(bool value, HandType hand, string eventName)
|
||||
{
|
||||
var args = new UdonInputEventArgs(value, hand);
|
||||
_udonInputEventSender.RunInputAction(eventName, args);
|
||||
}
|
||||
|
||||
private void SendUdonInputFloatEvent(float value, HandType hand, string eventName)
|
||||
{
|
||||
var args = new UdonInputEventArgs(value, hand);
|
||||
_udonInputEventSender.RunInputAction(eventName, args);
|
||||
}
|
||||
|
||||
private void QueueButtonInputEvent(bool value, HandType hand, string eventName)
|
||||
{
|
||||
// Do not queue event if the menu is open.
|
||||
if (IsMenuOpen())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_queuedEvents.Enqueue(() =>
|
||||
{
|
||||
SendUdonInputBoolEvent(value, hand, eventName);
|
||||
});
|
||||
}
|
||||
|
||||
public void ProcessInputEvents()
|
||||
{
|
||||
// If the menu is open or the menu was updated on this frame, skip sending input events.
|
||||
if (IsMenuOpen())
|
||||
{
|
||||
_queuedEvents.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure that all udon input events happen at the same time in the frame and not mixed between when unity's
|
||||
// update for the new Input Manager sends events. Without this, input events would happen before
|
||||
// UdonBehaviour.Update, causing strange out of order issues.
|
||||
while (_queuedEvents.Count > 0)
|
||||
{
|
||||
Action inputEvent = _queuedEvents.Dequeue();
|
||||
inputEvent?.Invoke();
|
||||
}
|
||||
|
||||
Vector2 lookAxes = _input.GetLookAxes();
|
||||
if (Mathf.Abs(lookAxes.x - _prevLookInput.x) > MINIMUM_LOOK_INPUT_EPS)
|
||||
{
|
||||
SendUdonInputFloatEvent(lookAxes.x, HandType.RIGHT, UdonManager.UDON_LOOK_HORIZONTAL);
|
||||
}
|
||||
if (Mathf.Abs(lookAxes.y - _prevLookInput.y) > MINIMUM_LOOK_INPUT_EPS)
|
||||
{
|
||||
SendUdonInputFloatEvent(lookAxes.y, HandType.RIGHT, UdonManager.UDON_LOOK_VERTICAL);
|
||||
}
|
||||
_prevLookInput = lookAxes;
|
||||
|
||||
|
||||
Vector2 moveAxes = _input.GetMovementAxes();
|
||||
if (Mathf.Abs(_prevMoveAxes.x - moveAxes.x) > MINIMUM_MOVE_INPUT_EPS)
|
||||
{
|
||||
SendUdonInputFloatEvent(moveAxes.x, HandType.LEFT, UdonManager.UDON_MOVE_HORIZONTAL);
|
||||
}
|
||||
if (Mathf.Abs(_prevMoveAxes.y - moveAxes.y) > MINIMUM_MOVE_INPUT_EPS)
|
||||
{
|
||||
SendUdonInputFloatEvent(moveAxes.y, HandType.LEFT, UdonManager.UDON_MOVE_VERTICAL);
|
||||
}
|
||||
_prevMoveAxes = moveAxes;
|
||||
}
|
||||
|
||||
private bool IsMenuOpen()
|
||||
{
|
||||
return _isMenuOpen || _lastMenuUpdateFrame == Time.frameCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1e963688a1c048ddac34d738cc8f3072
|
||||
timeCreated: 1638891929
|
||||
@ -0,0 +1,33 @@
|
||||
using UnityEngine;
|
||||
using VRC.Udon;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
/// <summary>
|
||||
/// Wrapper class for UdonInput
|
||||
/// </summary>
|
||||
[AddComponentMenu("")]
|
||||
[DefaultExecutionOrder(1)] // Ensure that input events happen after UdonBehaviour.Update
|
||||
public class ClientSimUdonInputBehaviour : ClientSimBehaviour
|
||||
{
|
||||
private ClientSimUdonInput _udonInput;
|
||||
|
||||
public void Initialize(IClientSimEventDispatcher eventDispatcher, IClientSimInput input)
|
||||
{
|
||||
_udonInput = new ClientSimUdonInput(
|
||||
eventDispatcher,
|
||||
input,
|
||||
new ClientSimUdonManagerInputEventSender(UdonManager.Instance));
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
_udonInput?.Dispose();
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
_udonInput?.ProcessInputEvents();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5fc129f391f3488e947eb13a9208bae4
|
||||
timeCreated: 1640233289
|
||||
@ -0,0 +1,23 @@
|
||||
using VRC.Udon;
|
||||
using VRC.Udon.Common;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
/// <summary>
|
||||
/// Wrapper for UdonManager. Only needed to prevent direct dependency to UdonManger in the UdonInput class.
|
||||
/// </summary>
|
||||
public class ClientSimUdonManagerInputEventSender : IClientSimUdonInputEventSender
|
||||
{
|
||||
private readonly UdonManager _udonManager;
|
||||
|
||||
public ClientSimUdonManagerInputEventSender(UdonManager udonManager)
|
||||
{
|
||||
_udonManager = udonManager;
|
||||
}
|
||||
|
||||
public void RunInputAction(string eventName, UdonInputEventArgs args)
|
||||
{
|
||||
_udonManager.RunInputAction(eventName, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4025ed62957542d2b0609cfa37d16946
|
||||
timeCreated: 1640269473
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 44c15dbef57edea4eb564bd9c5e634b9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using VRC.SDKBase;
|
||||
using VRC.Udon.Common;
|
||||
|
||||
namespace VRC.SDK3.ClientSim
|
||||
{
|
||||
public interface IClientSimInput
|
||||
{
|
||||
float GetMovementHorizontal();
|
||||
float GetMovementVertical();
|
||||
Vector2 GetMovementAxes();
|
||||
float GetLookHorizontal();
|
||||
float GetLookVertical();
|
||||
Vector2 GetLookAxes();
|
||||
|
||||
float GetPickupRotateUpDown();
|
||||
float GetPickupRotateLeftRight();
|
||||
float GetPickupRotateCwCcw();
|
||||
float GetPickupManipulateDistance();
|
||||
|
||||
|
||||
void SubscribeJump(Action<bool, HandType> handler);
|
||||
void UnsubscribeJump(Action<bool, HandType> handler);
|
||||
|
||||
void SubscribeUse(Action<bool, HandType> handler);
|
||||
void UnsubscribeUse(Action<bool, HandType> handler);
|
||||
|
||||
void SubscribeGrab(Action<bool, HandType> handler);
|
||||
void UnsubscribeGrab(Action<bool, HandType> handler);
|
||||
|
||||
void SubscribeDrop(Action<bool, HandType> handler);
|
||||
void UnsubscribeDrop(Action<bool, HandType> handler);
|
||||
|
||||
void SubscribeToggleMenu(Action<bool, HandType> handler);
|
||||
void UnsubscribeToggleMenu(Action<bool, HandType> handler);
|
||||
|
||||
|
||||
void SubscribeRun(Action<bool> handler);
|
||||
void UnsubscribeRun(Action<bool> handler);
|
||||
|
||||
void SubscribeToggleCrouch(Action<bool> handler);
|
||||
void UnsubscribeToggleCrouch(Action<bool> handler);
|
||||
|
||||
void SubscribeToggleProne(Action<bool> handler);
|
||||
void UnsubscribeToggleProne(Action<bool> handler);
|
||||
|
||||
void SubscribeReleaseMouse(Action<bool> handler);
|
||||
void UnsubscribeReleaseMouse(Action<bool> handler);
|
||||
|
||||
public void SubscribeInputChangedEvent(Action<VRCInputMethod> handler);
|
||||
public void UnsubscribeInputChangedEvent(Action<VRCInputMethod> handler);
|
||||
|
||||
public void SendToggleMenuEvent(bool value, HandType hand);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user