// SDK Setup|Utilities|90030
|
|
namespace VRTK
|
|
{
|
|
using UnityEngine;
|
|
#if UNITY_EDITOR
|
|
using UnityEditor;
|
|
using UnityEditor.Callbacks;
|
|
#endif
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.Linq;
|
|
|
|
/// <summary>
|
|
/// The SDK Setup describes a list of SDKs and game objects to use.
|
|
/// </summary>
|
|
public sealed class VRTK_SDKSetup : MonoBehaviour
|
|
{
|
|
public delegate void LoadEventHandler(VRTK_SDKManager sender, VRTK_SDKSetup setup);
|
|
|
|
[Tooltip("Determines whether the SDK object references are automatically set to the objects of the selected SDKs. If this is true populating is done whenever the selected SDKs change.")]
|
|
public bool autoPopulateObjectReferences = true;
|
|
|
|
[Tooltip("A reference to the GameObject that is the user's boundary or play area, most likely provided by the SDK's Camera Rig.")]
|
|
public GameObject actualBoundaries;
|
|
[Tooltip("A reference to the GameObject that contains the VR camera, most likely provided by the SDK's Camera Rig Headset.")]
|
|
public GameObject actualHeadset;
|
|
[Tooltip("A reference to the GameObject that contains the SDK Left Hand Controller.")]
|
|
public GameObject actualLeftController;
|
|
[Tooltip("A reference to the GameObject that contains the SDK Right Hand Controller.")]
|
|
public GameObject actualRightController;
|
|
|
|
[Tooltip("A reference to the GameObject that models for the Left Hand Controller.")]
|
|
public GameObject modelAliasLeftController;
|
|
[Tooltip("A reference to the GameObject that models for the Right Hand Controller.")]
|
|
public GameObject modelAliasRightController;
|
|
|
|
public event LoadEventHandler Loaded;
|
|
public event LoadEventHandler Unloaded;
|
|
|
|
/// <summary>
|
|
/// The info of the SDK to use to deal with all system actions. By setting this to `null` the fallback SDK will be used.
|
|
/// </summary>
|
|
public VRTK_SDKInfo systemSDKInfo
|
|
{
|
|
get
|
|
{
|
|
return cachedSystemSDKInfo;
|
|
}
|
|
set
|
|
{
|
|
value = value ?? VRTK_SDKInfo.Create<SDK_BaseSystem, SDK_FallbackSystem, SDK_FallbackSystem>()[0];
|
|
if (cachedSystemSDKInfo == value)
|
|
{
|
|
return;
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
DestroyImmediate(cachedSystemSDK);
|
|
#else
|
|
Destroy(cachedSystemSDK);
|
|
#endif
|
|
cachedSystemSDK = null;
|
|
|
|
cachedSystemSDKInfo = new VRTK_SDKInfo(value);
|
|
PopulateObjectReferences(false);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The info of the SDK to use to utilize room scale boundaries. By setting this to `null` the fallback SDK will be used.
|
|
/// </summary>
|
|
public VRTK_SDKInfo boundariesSDKInfo
|
|
{
|
|
get
|
|
{
|
|
return cachedBoundariesSDKInfo;
|
|
}
|
|
set
|
|
{
|
|
value = value ?? VRTK_SDKInfo.Create<SDK_BaseBoundaries, SDK_FallbackBoundaries, SDK_FallbackBoundaries>()[0];
|
|
if (cachedBoundariesSDKInfo == value)
|
|
{
|
|
return;
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
DestroyImmediate(cachedBoundariesSDK);
|
|
#else
|
|
Destroy(cachedBoundariesSDK);
|
|
#endif
|
|
cachedBoundariesSDK = null;
|
|
|
|
cachedBoundariesSDKInfo = new VRTK_SDKInfo(value);
|
|
PopulateObjectReferences(false);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The info of the SDK to use to utilize the VR headset. By setting this to `null` the fallback SDK will be used.
|
|
/// </summary>
|
|
public VRTK_SDKInfo headsetSDKInfo
|
|
{
|
|
get
|
|
{
|
|
return cachedHeadsetSDKInfo;
|
|
}
|
|
set
|
|
{
|
|
value = value ?? VRTK_SDKInfo.Create<SDK_BaseHeadset, SDK_FallbackHeadset, SDK_FallbackHeadset>()[0];
|
|
if (cachedHeadsetSDKInfo == value)
|
|
{
|
|
return;
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
DestroyImmediate(cachedHeadsetSDK);
|
|
#else
|
|
Destroy(cachedHeadsetSDK);
|
|
#endif
|
|
cachedHeadsetSDK = null;
|
|
|
|
cachedHeadsetSDKInfo = new VRTK_SDKInfo(value);
|
|
PopulateObjectReferences(false);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The info of the SDK to use to utilize the input devices. By setting this to `null` the fallback SDK will be used.
|
|
/// </summary>
|
|
public VRTK_SDKInfo controllerSDKInfo
|
|
{
|
|
get
|
|
{
|
|
return cachedControllerSDKInfo;
|
|
}
|
|
set
|
|
{
|
|
value = value ?? VRTK_SDKInfo.Create<SDK_BaseController, SDK_FallbackController, SDK_FallbackController>()[0];
|
|
if (cachedControllerSDKInfo == value)
|
|
{
|
|
return;
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
DestroyImmediate(cachedControllerSDK);
|
|
#else
|
|
Destroy(cachedControllerSDK);
|
|
#endif
|
|
cachedControllerSDK = null;
|
|
|
|
cachedControllerSDKInfo = new VRTK_SDKInfo(value);
|
|
PopulateObjectReferences(false);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The selected system SDK.
|
|
/// </summary>
|
|
/// <returns>The currently selected system SDK.</returns>
|
|
public SDK_BaseSystem systemSDK
|
|
{
|
|
get
|
|
{
|
|
if (cachedSystemSDK == null)
|
|
{
|
|
HandleSDKGetter<SDK_BaseSystem>("System", systemSDKInfo, VRTK_SDKManager.InstalledSystemSDKInfos);
|
|
cachedSystemSDK = (SDK_BaseSystem)ScriptableObject.CreateInstance(systemSDKInfo.type);
|
|
}
|
|
|
|
return cachedSystemSDK;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The selected boundaries SDK.
|
|
/// </summary>
|
|
/// <returns>The currently selected boundaries SDK.</returns>
|
|
public SDK_BaseBoundaries boundariesSDK
|
|
{
|
|
get
|
|
{
|
|
if (cachedBoundariesSDK == null)
|
|
{
|
|
HandleSDKGetter<SDK_BaseBoundaries>("Boundaries", boundariesSDKInfo, VRTK_SDKManager.InstalledBoundariesSDKInfos);
|
|
cachedBoundariesSDK = (SDK_BaseBoundaries)ScriptableObject.CreateInstance(boundariesSDKInfo.type);
|
|
}
|
|
|
|
return cachedBoundariesSDK;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The selected headset SDK.
|
|
/// </summary>
|
|
/// <returns>The currently selected headset SDK.</returns>
|
|
public SDK_BaseHeadset headsetSDK
|
|
{
|
|
get
|
|
{
|
|
if (cachedHeadsetSDK == null)
|
|
{
|
|
HandleSDKGetter<SDK_BaseHeadset>("Headset", headsetSDKInfo, VRTK_SDKManager.InstalledHeadsetSDKInfos);
|
|
cachedHeadsetSDK = (SDK_BaseHeadset)ScriptableObject.CreateInstance(headsetSDKInfo.type);
|
|
}
|
|
|
|
return cachedHeadsetSDK;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The selected controller SDK.
|
|
/// </summary>
|
|
/// <returns>The currently selected controller SDK.</returns>
|
|
public SDK_BaseController controllerSDK
|
|
{
|
|
get
|
|
{
|
|
if (cachedControllerSDK == null)
|
|
{
|
|
HandleSDKGetter<SDK_BaseController>("Controller", controllerSDKInfo, VRTK_SDKManager.InstalledControllerSDKInfos);
|
|
cachedControllerSDK = (SDK_BaseController)ScriptableObject.CreateInstance(controllerSDKInfo.type);
|
|
}
|
|
|
|
return cachedControllerSDK;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The VR device names used by the currently selected SDKs.
|
|
/// </summary>
|
|
public string[] usedVRDeviceNames
|
|
{
|
|
get
|
|
{
|
|
VRTK_SDKInfo[] infos = { systemSDKInfo, boundariesSDKInfo, headsetSDKInfo, controllerSDKInfo };
|
|
return infos.Select(info => info.description.vrDeviceName)
|
|
.Distinct()
|
|
.ToArray();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Whether it's possible to use the Setup. See `GetSimplifiedErrorDescriptions` for more info.
|
|
/// </summary>
|
|
public bool isValid
|
|
{
|
|
get
|
|
{
|
|
return GetSimplifiedErrorDescriptions().Length == 0;
|
|
}
|
|
}
|
|
|
|
[SerializeField]
|
|
private VRTK_SDKInfo cachedSystemSDKInfo = VRTK_SDKInfo.Create<SDK_BaseSystem, SDK_FallbackSystem, SDK_FallbackSystem>()[0];
|
|
[SerializeField]
|
|
private VRTK_SDKInfo cachedBoundariesSDKInfo = VRTK_SDKInfo.Create<SDK_BaseBoundaries, SDK_FallbackBoundaries, SDK_FallbackBoundaries>()[0];
|
|
[SerializeField]
|
|
private VRTK_SDKInfo cachedHeadsetSDKInfo = VRTK_SDKInfo.Create<SDK_BaseHeadset, SDK_FallbackHeadset, SDK_FallbackHeadset>()[0];
|
|
[SerializeField]
|
|
private VRTK_SDKInfo cachedControllerSDKInfo = VRTK_SDKInfo.Create<SDK_BaseController, SDK_FallbackController, SDK_FallbackController>()[0];
|
|
|
|
private SDK_BaseSystem cachedSystemSDK;
|
|
private SDK_BaseBoundaries cachedBoundariesSDK;
|
|
private SDK_BaseHeadset cachedHeadsetSDK;
|
|
private SDK_BaseController cachedControllerSDK;
|
|
|
|
/// <summary>
|
|
/// The PopulateObjectReferences method populates the object references by using the currently set SDKs.
|
|
/// </summary>
|
|
/// <param name="force">Whether to ignore `autoPopulateObjectReferences` while deciding to populate.</param>
|
|
public void PopulateObjectReferences(bool force)
|
|
{
|
|
if (!(force || autoPopulateObjectReferences))
|
|
{
|
|
return;
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
if (!EditorApplication.isPlaying && VRTK_SDKManager.ValidInstance())
|
|
{
|
|
VRTK_SDKManager.instance.SetLoadedSDKSetupToPopulateObjectReferences(this);
|
|
}
|
|
#endif
|
|
VRTK_SDK_Bridge.InvalidateCaches();
|
|
|
|
#if UNITY_EDITOR
|
|
Undo.RecordObject(this, "Populate Object References");
|
|
#endif
|
|
|
|
actualBoundaries = null;
|
|
actualHeadset = null;
|
|
actualLeftController = null;
|
|
actualRightController = null;
|
|
modelAliasLeftController = null;
|
|
modelAliasRightController = null;
|
|
|
|
Transform playAreaTransform = boundariesSDK.GetPlayArea();
|
|
Transform headsetTransform = headsetSDK.GetHeadset();
|
|
|
|
actualBoundaries = playAreaTransform == null ? null : playAreaTransform.gameObject;
|
|
actualHeadset = headsetTransform == null ? null : headsetTransform.gameObject;
|
|
actualLeftController = controllerSDK.GetControllerLeftHand(true);
|
|
actualRightController = controllerSDK.GetControllerRightHand(true);
|
|
modelAliasLeftController = controllerSDK.GetControllerModel(SDK_BaseController.ControllerHand.Left);
|
|
modelAliasRightController = controllerSDK.GetControllerModel(SDK_BaseController.ControllerHand.Right);
|
|
}
|
|
|
|
/// <summary>
|
|
/// The GetSimplifiedErrorDescriptions method checks the setup for errors and creates an array of error descriptions.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The returned error descriptions handle the following cases for the current SDK infos:
|
|
/// <list type="bullet">
|
|
/// <item> <description>Its type doesn't exist anymore.</description> </item>
|
|
/// <item> <description>It's a fallback SDK.</description> </item>
|
|
/// <item> <description>It doesn't have its scripting define symbols added.</description> </item>
|
|
/// <item> <description>It's missing its vendor SDK.</description> </item>
|
|
/// </list>
|
|
/// Additionally the current SDK infos are checked whether they use multiple VR Devices.
|
|
/// </remarks>
|
|
/// <returns>An array of all the error descriptions. Returns an empty array if no errors are found.</returns>
|
|
public string[] GetSimplifiedErrorDescriptions()
|
|
{
|
|
List<string> sdkErrorDescriptions = new List<string>();
|
|
|
|
ReadOnlyCollection<VRTK_SDKInfo>[] installedSDKInfosList = {
|
|
VRTK_SDKManager.InstalledSystemSDKInfos,
|
|
VRTK_SDKManager.InstalledBoundariesSDKInfos,
|
|
VRTK_SDKManager.InstalledHeadsetSDKInfos,
|
|
VRTK_SDKManager.InstalledControllerSDKInfos
|
|
};
|
|
VRTK_SDKInfo[] currentSDKInfos = { systemSDKInfo, boundariesSDKInfo, headsetSDKInfo, controllerSDKInfo };
|
|
|
|
for (int index = 0; index < installedSDKInfosList.Length; index++)
|
|
{
|
|
ReadOnlyCollection<VRTK_SDKInfo> installedSDKInfos = installedSDKInfosList[index];
|
|
VRTK_SDKInfo currentSDKInfo = currentSDKInfos[index];
|
|
|
|
Type baseType = VRTK_SharedMethods.GetBaseType(currentSDKInfo.type);
|
|
if (baseType == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (currentSDKInfo.originalTypeNameWhenFallbackIsUsed != null)
|
|
{
|
|
sdkErrorDescriptions.Add(string.Format("The SDK '{0}' doesn't exist anymore.", currentSDKInfo.originalTypeNameWhenFallbackIsUsed));
|
|
}
|
|
else if (currentSDKInfo.description.describesFallbackSDK)
|
|
{
|
|
sdkErrorDescriptions.Add("A fallback SDK is used. Make sure to set a real SDK.");
|
|
}
|
|
else if (!installedSDKInfos.Contains(currentSDKInfo))
|
|
{
|
|
sdkErrorDescriptions.Add(string.Format("The vendor SDK for '{0}' is not installed.", currentSDKInfo.description.prettyName));
|
|
}
|
|
}
|
|
|
|
if (usedVRDeviceNames.Except(new[] { "None" }).Count() > 1)
|
|
{
|
|
sdkErrorDescriptions.Add("The current SDK selection uses multiple VR Devices. It's not possible to use more than one VR Device at the same time.");
|
|
}
|
|
|
|
return sdkErrorDescriptions.Distinct().ToArray();
|
|
}
|
|
|
|
/// <summary>
|
|
/// The OnLoaded method determines when an SDK Setup has been loaded.
|
|
/// </summary>
|
|
/// <param name="sender">The SDK Manager that has loaded the SDK Setup.</param>
|
|
public void OnLoaded(VRTK_SDKManager sender)
|
|
{
|
|
List<SDK_Base> sdkBases = new SDK_Base[] { systemSDK, boundariesSDK, headsetSDK, controllerSDK }.ToList();
|
|
sdkBases.ForEach(sdkBase => sdkBase.OnBeforeSetupLoad(this));
|
|
|
|
gameObject.SetActive(true);
|
|
VRTK_SDK_Bridge.InvalidateCaches();
|
|
SetupHeadset();
|
|
SetupControllers();
|
|
boundariesSDK.InitBoundaries();
|
|
|
|
sdkBases.ForEach(sdkBase => sdkBase.OnAfterSetupLoad(this));
|
|
|
|
LoadEventHandler handler = Loaded;
|
|
if (handler != null)
|
|
{
|
|
handler(sender, this);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The OnUnloaded method determines when an SDK Setup has been unloaded.
|
|
/// </summary>
|
|
/// <param name="sender">The SDK Manager that has unloaded the SDK Setup.</param>
|
|
public void OnUnloaded(VRTK_SDKManager sender)
|
|
{
|
|
List<SDK_Base> sdkBases = new SDK_Base[] { systemSDK, boundariesSDK, headsetSDK, controllerSDK }.ToList();
|
|
sdkBases.ForEach(sdkBase => sdkBase.OnBeforeSetupUnload(this));
|
|
|
|
gameObject.SetActive(false);
|
|
|
|
sdkBases.ForEach(sdkBase => sdkBase.OnAfterSetupUnload(this));
|
|
|
|
LoadEventHandler handler = Unloaded;
|
|
if (handler != null)
|
|
{
|
|
handler(sender, this);
|
|
}
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
#pragma warning disable 618
|
|
if (VRTK_SDKManager.ValidInstance() && !VRTK_SDKManager.instance.persistOnLoad)
|
|
#pragma warning restore 618
|
|
{
|
|
PopulateObjectReferences(false);
|
|
}
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
static VRTK_SDKSetup()
|
|
{
|
|
//call AutoPopulateObjectReferences when the currently active scene changes
|
|
#if UNITY_2018_1_OR_NEWER
|
|
EditorApplication.hierarchyChanged += AutoPopulateObjectReferences;
|
|
#else
|
|
EditorApplication.hierarchyWindowChanged += AutoPopulateObjectReferences;
|
|
#endif
|
|
}
|
|
|
|
[DidReloadScripts(2)]
|
|
private static void AutoPopulateObjectReferences()
|
|
{
|
|
if (EditorApplication.isPlayingOrWillChangePlaymode)
|
|
{
|
|
return;
|
|
}
|
|
|
|
foreach (VRTK_SDKSetup setup in VRTK_SharedMethods.FindEvenInactiveComponents<VRTK_SDKSetup>(true))
|
|
{
|
|
setup.PopulateObjectReferences(false);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/// <summary>
|
|
/// Handles the various SDK getters by logging potential errors.
|
|
/// </summary>
|
|
/// <typeparam name="BaseType">The SDK base type of which to handle the getter for. Must be a subclass of SDK_Base.</typeparam>
|
|
/// <param name="prettyName">The pretty name of the base SDK to use when logging errors.</param>
|
|
/// <param name="info">The SDK info of which the SDK getter was called.</param>
|
|
/// <param name="installedInfos">The installed SDK infos of which the SDK getter was called.</param>
|
|
private static void HandleSDKGetter<BaseType>(string prettyName, VRTK_SDKInfo info, IEnumerable<VRTK_SDKInfo> installedInfos) where BaseType : SDK_Base
|
|
{
|
|
if (VRTK_SharedMethods.IsEditTime())
|
|
{
|
|
return;
|
|
}
|
|
|
|
string sdkErrorDescription = GetSDKErrorDescription<BaseType>(prettyName, info, installedInfos);
|
|
if (!string.IsNullOrEmpty(sdkErrorDescription))
|
|
{
|
|
VRTK_Logger.Error(sdkErrorDescription);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns an error description in case any of these are true for the current SDK info:
|
|
/// <list type="bullet">
|
|
/// <item> <description>Its type doesn't exist anymore.</description> </item>
|
|
/// <item> <description>It's a fallback SDK.</description> </item>
|
|
/// <item> <description>It doesn't have its scripting define symbols added.</description> </item>
|
|
/// <item> <description>It's missing its vendor SDK.</description> </item>
|
|
/// </list>
|
|
/// </summary>
|
|
/// <typeparam name="BaseType">The SDK base type of which to return the error description for. Must be a subclass of SDK_Base.</typeparam>
|
|
/// <param name="prettyName">The pretty name of the base SDK to use when returning error descriptions.</param>
|
|
/// <param name="info">The SDK info of which to return the error description for.</param>
|
|
/// <param name="installedInfos">The installed SDK infos.</param>
|
|
/// <returns>An error description if there is one, else `null`.</returns>
|
|
private static string GetSDKErrorDescription<BaseType>(string prettyName, VRTK_SDKInfo info, IEnumerable<VRTK_SDKInfo> installedInfos) where BaseType : SDK_Base
|
|
{
|
|
Type selectedType = info.type;
|
|
Type baseType = typeof(BaseType);
|
|
Type fallbackType = VRTK_SDKManager.SDKFallbackTypesByBaseType[baseType];
|
|
|
|
if (selectedType == fallbackType)
|
|
{
|
|
return string.Format("The fallback {0} SDK is being used because there is no other {0} SDK set in the SDK Setup.", prettyName);
|
|
}
|
|
|
|
if (!VRTK_SharedMethods.IsTypeAssignableFrom(baseType, selectedType) || VRTK_SharedMethods.IsTypeAssignableFrom(fallbackType, selectedType))
|
|
{
|
|
string description = string.Format("The fallback {0} SDK is being used despite being set to '{1}'.", prettyName, selectedType.Name);
|
|
|
|
if (installedInfos.Select(installedInfo => installedInfo.type).Contains(selectedType))
|
|
{
|
|
return description + " Its needed scripting define symbols are not added. You can click the GameObject with the `VRTK_SDKManager` script attached to it in Edit Mode and choose to automatically let the manager handle the scripting define symbols." + VRTK_Logger.GetCommonMessage(VRTK_Logger.CommonMessageKeys.SCRIPTING_DEFINE_SYMBOLS_NOT_FOUND);
|
|
}
|
|
|
|
return description + " The needed vendor SDK isn't installed.";
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private void SetupHeadset()
|
|
{
|
|
if (actualHeadset != null && !actualHeadset.GetComponent<VRTK_TrackedHeadset>())
|
|
{
|
|
actualHeadset.AddComponent<VRTK_TrackedHeadset>();
|
|
}
|
|
}
|
|
|
|
private void SetupControllers()
|
|
{
|
|
Action<GameObject, GameObject> setParent = (scriptAliasGameObject, actualGameObject) =>
|
|
{
|
|
if (scriptAliasGameObject == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Transform scriptAliasTransform = scriptAliasGameObject.transform;
|
|
Transform actualTransform = actualGameObject.transform;
|
|
|
|
if (scriptAliasTransform.parent != actualTransform)
|
|
{
|
|
Vector3 previousScale = scriptAliasTransform.localScale;
|
|
scriptAliasTransform.SetParent(actualTransform);
|
|
scriptAliasTransform.localScale = previousScale;
|
|
}
|
|
|
|
scriptAliasTransform.localPosition = Vector3.zero;
|
|
scriptAliasTransform.localRotation = Quaternion.identity;
|
|
};
|
|
|
|
if (actualLeftController != null && VRTK_SDKManager.ValidInstance())
|
|
{
|
|
setParent(VRTK_SDKManager.instance.scriptAliasLeftController, actualLeftController);
|
|
|
|
if (actualLeftController.GetComponent<VRTK_TrackedController>() == null)
|
|
{
|
|
actualLeftController.AddComponent<VRTK_TrackedController>();
|
|
}
|
|
}
|
|
|
|
if (actualRightController != null && VRTK_SDKManager.ValidInstance())
|
|
{
|
|
setParent(VRTK_SDKManager.instance.scriptAliasRightController, actualRightController);
|
|
|
|
if (actualRightController.GetComponent<VRTK_TrackedController>() == null)
|
|
{
|
|
actualRightController.AddComponent<VRTK_TrackedController>();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|