From b7f8daa32415c2f25bf4ca09e0637d70e3a8451b Mon Sep 17 00:00:00 2001 From: Nicolas Gnyra Date: Sat, 21 Dec 2024 23:37:23 -0500 Subject: [PATCH] Fix render models not loading properly when using FPFC --- .../OpenVR/OpenVRRenderModelLoader.cs | 10 ++-- .../OpenVR/OpenVRRenderModelProvider.cs | 53 ++++++++++++------- .../Zenject/CustomAvatarsInstaller.cs | 2 +- 3 files changed, 42 insertions(+), 23 deletions(-) diff --git a/Source/CustomAvatar/Tracking/OpenVR/OpenVRRenderModelLoader.cs b/Source/CustomAvatar/Tracking/OpenVR/OpenVRRenderModelLoader.cs index cde4a7b7..2a90e520 100644 --- a/Source/CustomAvatar/Tracking/OpenVR/OpenVRRenderModelLoader.cs +++ b/Source/CustomAvatar/Tracking/OpenVR/OpenVRRenderModelLoader.cs @@ -33,9 +33,9 @@ namespace CustomAvatar.Tracking.OpenVR internal class OpenVRRenderModelLoader : IDisposable { private static readonly uint kRenderModelVertexStructSize = (uint)Marshal.SizeOf(typeof(RenderModel_Vertex_t)); - private static readonly string[] kOffsetComponentNames = new[] { "openxr_grip", "grip" }; + private static readonly string[] kOffsetComponentNames = ["openxr_grip", "grip"]; - private readonly Dictionary _renderModelCache = new(); + private readonly Dictionary _renderModelCache = []; private readonly SemaphoreSlim _renderModelSemaphore = new(1); private readonly ILogger _logger; @@ -78,7 +78,11 @@ internal async Task GetRenderModelAsync(string renderModelName) if (!_renderModelCache.TryGetValue(renderModelName, out RenderModel renderModel)) { renderModel = await LoadRenderModelAsync(renderModelName); - _renderModelCache[renderModelName] = renderModel; + + if (renderModel != null) + { + _renderModelCache[renderModelName] = renderModel; + } } return renderModel; diff --git a/Source/CustomAvatar/Tracking/OpenVR/OpenVRRenderModelProvider.cs b/Source/CustomAvatar/Tracking/OpenVR/OpenVRRenderModelProvider.cs index b771dae8..419c384a 100644 --- a/Source/CustomAvatar/Tracking/OpenVR/OpenVRRenderModelProvider.cs +++ b/Source/CustomAvatar/Tracking/OpenVR/OpenVRRenderModelProvider.cs @@ -14,12 +14,12 @@ // You should have received a copy of the GNU Lesser General Public License // along with this program. If not, see . +using System; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using CustomAvatar.Logging; using Valve.VR; -using Zenject; namespace CustomAvatar.Tracking.OpenVR { @@ -27,34 +27,28 @@ namespace CustomAvatar.Tracking.OpenVR using OpenVR = Valve.VR.OpenVR; #pragma warning restore IDE0065 - internal class OpenVRRenderModelProvider : IRenderModelProvider, IInitializable + internal class OpenVRRenderModelProvider : IRenderModelProvider { private static readonly uint kInputOriginInfoStructSize = (uint)Marshal.SizeOf(typeof(InputOriginInfo_t)); private readonly ILogger _logger; private readonly OpenVRRenderModelLoader _openVRRenderModelLoader; - private readonly ulong[] _handles = new ulong[6]; - public OpenVRRenderModelProvider(ILogger logger, OpenVRRenderModelLoader openVRRenderModelLoader) { _logger = logger; _openVRRenderModelLoader = openVRRenderModelLoader; } - public void Initialize() - { - _handles[(int)DeviceUse.Head] = GetDeviceHandle(OpenVR.k_pchPathUserHead); - _handles[(int)DeviceUse.LeftHand] = GetDeviceHandle(OpenVR.k_pchPathUserHandLeft); - _handles[(int)DeviceUse.RightHand] = GetDeviceHandle(OpenVR.k_pchPathUserHandRight); - _handles[(int)DeviceUse.Waist] = GetDeviceHandle(OpenVR.k_pchPathUserWaist); - _handles[(int)DeviceUse.LeftFoot] = GetDeviceHandle(OpenVR.k_pchPathUserFootLeft); - _handles[(int)DeviceUse.RightFoot] = GetDeviceHandle(OpenVR.k_pchPathUserFootRight); - } - public Task GetRenderModelAsync(DeviceUse deviceUse) { InputOriginInfo_t originInfo = GetOriginInfo(deviceUse); + + if (originInfo.devicePath == default) + { + return Task.FromResult(null); + } + string renderModelName = GetStringTrackedDeviceProperty(originInfo.trackedDeviceIndex, ETrackedDeviceProperty.Prop_RenderModelName_String); if (string.IsNullOrEmpty(renderModelName)) @@ -65,15 +59,31 @@ public Task GetRenderModelAsync(DeviceUse deviceUse) return _openVRRenderModelLoader.GetRenderModelAsync(renderModelName); } - private ulong GetDeviceHandle(string devicePath) + private ulong GetDeviceHandle(DeviceUse deviceUse) { + if (OpenVR.Input == null) + { + return default; + } + + string devicePath = deviceUse switch + { + DeviceUse.Head => OpenVR.k_pchPathUserHead, + DeviceUse.LeftHand => OpenVR.k_pchPathUserHandLeft, + DeviceUse.RightHand => OpenVR.k_pchPathUserHandRight, + DeviceUse.Waist => OpenVR.k_pchPathUserWaist, + DeviceUse.LeftFoot => OpenVR.k_pchPathUserFootLeft, + DeviceUse.RightFoot => OpenVR.k_pchPathUserFootRight, + _ => throw new ArgumentException("Invalid device use", nameof(deviceUse)), + }; + ulong handle = 0; EVRInputError error = OpenVR.Input.GetInputSourceHandle(devicePath, ref handle); if (error != EVRInputError.None) { _logger.LogError($"Failed to get input source handle for '{devicePath}': {error}"); - return 0; + return default; } return handle; @@ -81,9 +91,14 @@ private ulong GetDeviceHandle(string devicePath) private InputOriginInfo_t GetOriginInfo(DeviceUse deviceUse) { - ulong handle = _handles[(int)deviceUse]; + if (OpenVR.Input == null) + { + return default; + } + + ulong handle = GetDeviceHandle(deviceUse); - if (handle == 0) + if (handle == default) { return default; } @@ -108,7 +123,7 @@ private static string GetStringTrackedDeviceProperty(uint deviceIndex, ETrackedD { if (OpenVR.System == null) { - throw new System.InvalidOperationException("OpenVR is not running"); + throw new InvalidOperationException("OpenVR is not running"); } ETrackedPropertyError error = ETrackedPropertyError.TrackedProp_Success; diff --git a/Source/CustomAvatar/Zenject/CustomAvatarsInstaller.cs b/Source/CustomAvatar/Zenject/CustomAvatarsInstaller.cs index 6de283e6..687181de 100644 --- a/Source/CustomAvatar/Zenject/CustomAvatarsInstaller.cs +++ b/Source/CustomAvatar/Zenject/CustomAvatarsInstaller.cs @@ -154,7 +154,7 @@ private void BindOpenVR() if (OpenVRHelper.Initialize()) { Container.Bind(typeof(OpenVRRenderModelLoader), typeof(IDisposable)).To().AsSingle(); - Container.Bind(typeof(IRenderModelProvider), typeof(IInitializable)).To().AsSingle(); + Container.Bind(typeof(IRenderModelProvider)).To().AsSingle(); } } }