From 7595ea1a45b9dc086b1091c2ba98644313d081ce Mon Sep 17 00:00:00 2001 From: dfgHiatus <51272212+dfgHiatus@users.noreply.github.com> Date: Sun, 18 Jan 2026 13:19:41 -0500 Subject: [PATCH 1/6] Remove unused namespaces --- .../SteamLinkVRCFTModule/OSCHandler.cs | 10 ---------- SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCParser.cs | 10 +--------- .../SteamLinkVRCFTModule/SteamLinkVRCFTModule.cs | 5 +---- 3 files changed, 2 insertions(+), 23 deletions(-) diff --git a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCHandler.cs b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCHandler.cs index f08ff49..db57abc 100644 --- a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCHandler.cs +++ b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCHandler.cs @@ -1,17 +1,7 @@ using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.Linq; using System.Net; using System.Net.Sockets; -using System.Text; -using System.Threading.Tasks; -using VRCFaceTracking; -using VRCFaceTracking.Core.OSC; using VRCFaceTracking.Core.Params.Expressions; -using VRCFaceTracking.OSC; -using System.Buffers.Binary; -using System.Globalization; namespace SteamLinkVRCFTModule { diff --git a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCParser.cs b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCParser.cs index 210ee21..d7ef944 100644 --- a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCParser.cs +++ b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCParser.cs @@ -1,14 +1,6 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Net.Sockets; +using System.Collections; using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; using Microsoft.Extensions.Logging; -using Microsoft.VisualBasic; -using VRCFaceTracking.Core.OSC; namespace SteamLinkVRCFTModule { diff --git a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/SteamLinkVRCFTModule.cs b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/SteamLinkVRCFTModule.cs index ceb9255..a6a5c14 100644 --- a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/SteamLinkVRCFTModule.cs +++ b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/SteamLinkVRCFTModule.cs @@ -1,7 +1,4 @@ -using Microsoft.Extensions.Logging; -using SteamLinkVRCFTModule; -using System.Net.Sockets; -using VRCFaceTracking; +using VRCFaceTracking; using VRCFaceTracking.Core.Params.Expressions; using static VRCFaceTracking.Core.Params.Expressions.UnifiedExpressions; From 71fa864207dc7a0ef741af81ec320c5bae0c7ec1 Mon Sep 17 00:00:00 2001 From: dfgHiatus <51272212+dfgHiatus@users.noreply.github.com> Date: Sun, 18 Jan 2026 13:20:00 -0500 Subject: [PATCH 2/6] Convert to file-scoped namespaces --- .../SteamLinkVRCFTModule/OSCHandler.cs | 523 +++++++++--------- .../SteamLinkVRCFTModule/OSCParser.cs | 325 ++++++----- .../SteamLinkVRCFTModule.cs | 149 +++-- 3 files changed, 497 insertions(+), 500 deletions(-) diff --git a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCHandler.cs b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCHandler.cs index db57abc..45ee25b 100644 --- a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCHandler.cs +++ b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCHandler.cs @@ -3,294 +3,293 @@ using System.Net.Sockets; using VRCFaceTracking.Core.Params.Expressions; -namespace SteamLinkVRCFTModule -{ - using static UnifiedExpressions; +namespace SteamLinkVRCFTModule; - public class OSCHandler - { - public readonly float[] eyeTrackData = new float[3]; - public readonly float[] eyelids = new float[2]; - - public static readonly Dictionary ueData = new(){ - {EyeWideLeft, 0.0f }, - {EyeWideRight, 0.0f }, - {EyeSquintLeft, 0.0f }, - {EyeSquintRight, 0.0f }, - {BrowInnerUpLeft, 0.0f }, - {BrowInnerUpRight, 0.0f }, - {BrowOuterUpLeft, 0.0f }, - {BrowOuterUpRight, 0.0f }, - {BrowPinchLeft, 0.0f }, - {BrowLowererLeft, 0.0f }, - {BrowLowererRight, 0.0f }, - {BrowPinchRight, 0.0f }, - - { JawOpen, 0.0f}, - { JawLeft, 0.0f}, - { JawRight, 0.0f}, - { JawForward, 0.0f}, - { MouthLowerLeft, 0.0f}, - { MouthUpperLeft, 0.0f}, - { MouthLowerRight, 0.0f}, - { MouthUpperRight, 0.0f}, - { MouthRaiserUpper, 0.0f}, - { MouthRaiserLower, 0.0f}, - - {MouthDimpleLeft ,0.0f}, - { MouthDimpleRight,0.0f}, - { MouthClosed,0.0f}, - { MouthCornerPullLeft,0.0f}, - { MouthCornerSlantLeft,0.0f}, - { MouthCornerPullRight,0.0f}, - { MouthCornerSlantRight,0.0f}, - - {MouthFrownLeft ,0.0f}, - { MouthFrownRight,0.0f}, - { MouthLowerDownLeft,0.0f}, - {MouthLowerDownRight ,0.0f}, - { MouthUpperUpLeft,0.0f}, //TODO CHECK - {MouthUpperUpRight ,0.0f}, //TODO CHECK - {MouthTightenerLeft ,0.0f}, - { MouthTightenerRight,0.0f}, - {MouthPressLeft ,0.0f}, - {MouthPressRight ,0.0f}, - {MouthStretchLeft ,0.0f}, - {MouthStretchRight ,0.0f}, - {LipPuckerLowerLeft ,0.0f}, - { LipPuckerUpperLeft,0.0f}, - { LipPuckerLowerRight,0.0f}, - {LipPuckerUpperRight ,0.0f}, - { LipFunnelLowerLeft,0.0f}, - { LipFunnelUpperLeft,0.0f}, - { LipFunnelLowerRight,0.0f}, - { LipFunnelUpperRight,0.0f}, - {LipSuckLowerLeft,0.0f}, - { LipSuckUpperLeft,0.0f}, - {LipSuckLowerRight ,0.0f}, - { LipSuckUpperRight,0.0f}, - {CheekPuffLeft ,0.0f}, - { CheekPuffRight,0.0f}, - {CheekSuckLeft ,0.0f}, - { CheekSuckRight,0.0f}, - { CheekSquintLeft,0.0f}, - {CheekSquintRight ,0.0f}, - { NoseSneerLeft,0.0f}, - {NoseSneerRight ,0.0f}, - - {TongueCurlUp ,0.0f}, - {TongueOut ,0.0f}, - - }; - - - //based on https://docs.google.com/spreadsheets/d/118jo960co3Mgw8eREFVBsaJ7z0GtKNr52IB4Bz99VTA/edit#gid=0 - private static readonly +using static UnifiedExpressions; + +public class OSCHandler +{ + public readonly float[] eyeTrackData = new float[3]; + public readonly float[] eyelids = new float[2]; + + public static readonly Dictionary ueData = new(){ + {EyeWideLeft, 0.0f }, + {EyeWideRight, 0.0f }, + {EyeSquintLeft, 0.0f }, + {EyeSquintRight, 0.0f }, + {BrowInnerUpLeft, 0.0f }, + {BrowInnerUpRight, 0.0f }, + {BrowOuterUpLeft, 0.0f }, + {BrowOuterUpRight, 0.0f }, + {BrowPinchLeft, 0.0f }, + {BrowLowererLeft, 0.0f }, + {BrowLowererRight, 0.0f }, + {BrowPinchRight, 0.0f }, + + { JawOpen, 0.0f}, + { JawLeft, 0.0f}, + { JawRight, 0.0f}, + { JawForward, 0.0f}, + { MouthLowerLeft, 0.0f}, + { MouthUpperLeft, 0.0f}, + { MouthLowerRight, 0.0f}, + { MouthUpperRight, 0.0f}, + { MouthRaiserUpper, 0.0f}, + { MouthRaiserLower, 0.0f}, + + {MouthDimpleLeft ,0.0f}, + { MouthDimpleRight,0.0f}, + { MouthClosed,0.0f}, + { MouthCornerPullLeft,0.0f}, + { MouthCornerSlantLeft,0.0f}, + { MouthCornerPullRight,0.0f}, + { MouthCornerSlantRight,0.0f}, + + {MouthFrownLeft ,0.0f}, + { MouthFrownRight,0.0f}, + { MouthLowerDownLeft,0.0f}, + {MouthLowerDownRight ,0.0f}, + { MouthUpperUpLeft,0.0f}, //TODO CHECK + {MouthUpperUpRight ,0.0f}, //TODO CHECK + {MouthTightenerLeft ,0.0f}, + { MouthTightenerRight,0.0f}, + {MouthPressLeft ,0.0f}, + {MouthPressRight ,0.0f}, + {MouthStretchLeft ,0.0f}, + {MouthStretchRight ,0.0f}, + {LipPuckerLowerLeft ,0.0f}, + { LipPuckerUpperLeft,0.0f}, + { LipPuckerLowerRight,0.0f}, + {LipPuckerUpperRight ,0.0f}, + { LipFunnelLowerLeft,0.0f}, + { LipFunnelUpperLeft,0.0f}, + { LipFunnelLowerRight,0.0f}, + { LipFunnelUpperRight,0.0f}, + {LipSuckLowerLeft,0.0f}, + { LipSuckUpperLeft,0.0f}, + {LipSuckLowerRight ,0.0f}, + { LipSuckUpperRight,0.0f}, + {CheekPuffLeft ,0.0f}, + { CheekPuffRight,0.0f}, + {CheekSuckLeft ,0.0f}, + { CheekSuckRight,0.0f}, + { CheekSquintLeft,0.0f}, + {CheekSquintRight ,0.0f}, + { NoseSneerLeft,0.0f}, + {NoseSneerRight ,0.0f}, + + {TongueCurlUp ,0.0f}, + {TongueOut ,0.0f}, + + }; + + + //based on https://docs.google.com/spreadsheets/d/118jo960co3Mgw8eREFVBsaJ7z0GtKNr52IB4Bz99VTA/edit#gid=0 + private static readonly Dictionary> mapOSCDirectXRFBUnifiedExpressions = new Dictionary> - { - {"/sl/xrfb/facew/UpperLidRaiserL", new List{EyeWideLeft}}, - {"/sl/xrfb/facew/UpperLidRaiserR", new List{EyeWideRight}}, - {"/sl/xrfb/facew/LidTightenerL", new List{EyeSquintLeft}}, - {"/sl/xrfb/facew/LidTightenerR", new List{EyeSquintRight}}, - {"/sl/xrfb/facew/InnerBrowRaiserL", new List{BrowInnerUpLeft}}, - {"/sl/xrfb/facew/InnerBrowRaiserR", new List{BrowInnerUpRight}}, - {"/sl/xrfb/facew/OuterBrowRaiserL", new List{BrowOuterUpLeft}}, - {"/sl/xrfb/facew/OuterBrowRaiserR", new List{BrowOuterUpRight}}, - {"/sl/xrfb/facew/BrowLowererL", new List{BrowPinchLeft, BrowLowererLeft}}, - {"/sl/xrfb/facew/BrowLowererR", new List{BrowPinchRight, BrowLowererRight}}, - - {"/sl/xrfb/facew/JawDrop", new List{JawOpen}}, - {"/sl/xrfb/facew/JawSidewaysLeft", new List{JawLeft}}, - {"/sl/xrfb/facew/JawSidewaysRight", new List{JawRight}}, - {"/sl/xrfb/facew/JawThrust", new List{JawForward}}, - - {"/sl/xrfb/facew/MouthLeft", new List{MouthLowerLeft, MouthUpperLeft}}, - {"/sl/xrfb/facew/MouthRight", new List{MouthLowerRight, MouthUpperRight}}, - - {"/sl/xrfb/facew/ChinRaiserT", new List{MouthRaiserUpper} }, - {"/sl/xrfb/facew/ChinRaiserB", new List{MouthRaiserLower} }, - - {"/sl/xrfb/facew/DimplerL", new List{MouthDimpleLeft} }, - {"/sl/xrfb/facew/DimplerR", new List{MouthDimpleRight} }, - - {"/sl/xrfb/facew/LipsToward", new List{MouthClosed}}, - {"/sl/xrfb/facew/LipCornerPullerL", new List{ MouthCornerPullLeft, MouthCornerSlantLeft} }, - {"/sl/xrfb/facew/LipCornerPullerR", new List{ MouthCornerPullRight, MouthCornerSlantRight} }, - {"/sl/xrfb/facew/LipCornerDepressorL", new List{ MouthFrownLeft} }, - {"/sl/xrfb/facew/LipCornerDepressorR", new List{ MouthFrownRight} }, - {"/sl/xrfb/facew/LowerLipDepressorL", new List{ MouthLowerDownLeft} }, - {"/sl/xrfb/facew/LowerLipDepressorR", new List{ MouthLowerDownRight} }, - {"/sl/xrfb/facew/UpperLipRaiserL", new List{ MouthUpperUpLeft} }, //something odd here - {"/sl/xrfb/facew/UpperLipRaiserR", new List{ MouthUpperUpRight } }, //something odd here - {"/sl/xrfb/facew/LipTightenerL", new List{MouthTightenerLeft} }, - {"/sl/xrfb/facew/LipTightenerR", new List{MouthTightenerRight} }, - {"/sl/xrfb/facew/LipPressorL", new List{MouthPressLeft} }, - {"/sl/xrfb/facew/LipPressorR", new List{MouthPressRight} }, - {"/sl/xrfb/facew/LipStretcherL", new List{MouthStretchLeft} }, - {"/sl/xrfb/facew/LipStretcherR", new List{MouthStretchRight} }, - {"/sl/xrfb/facew/LipPuckerL", new List{ LipPuckerLowerLeft, LipPuckerUpperLeft } }, - {"/sl/xrfb/facew/LipPuckerR", new List{ LipPuckerLowerRight, LipPuckerUpperRight } }, - {"/sl/xrfb/facew/LipFunnelerLB", new List{LipFunnelLowerLeft} }, - {"/sl/xrfb/facew/LipFunnelerLT", new List{LipFunnelUpperLeft} }, - {"/sl/xrfb/facew/LipFunnelerRB", new List{LipFunnelLowerRight} }, - {"/sl/xrfb/facew/LipFunnelerRT", new List{LipFunnelUpperRight} }, - {"/sl/xrfb/facew/LipSuckLB", new List{LipSuckLowerLeft} }, - {"/sl/xrfb/facew/LipSuckLT", new List{LipSuckUpperLeft} }, - {"/sl/xrfb/facew/LipSuckRB", new List{LipSuckLowerRight} }, - {"/sl/xrfb/facew/LipSuckRT", new List{LipSuckUpperRight} }, - - {"/sl/xrfb/facew/CheekPuffL", new List{CheekPuffLeft} }, - {"/sl/xrfb/facew/CheekPuffR", new List{CheekPuffRight} }, - {"/sl/xrfb/facew/CheekSuckL", new List{CheekSuckLeft} }, - {"/sl/xrfb/facew/CheekSuckR", new List{CheekSuckRight} }, - {"/sl/xrfb/facew/CheekRaiserL", new List{CheekSquintLeft} }, - {"/sl/xrfb/facew/CheekRaiserR", new List{CheekSquintRight} }, - - {"/sl/xrfb/facew/NoseWrinklerL", new List{NoseSneerLeft} }, - {"/sl/xrfb/facew/NoseWrinklerR", new List{NoseSneerRight} }, - - //Tongue Tracking Params - //Some params sent but not part of UE or used? need to look into - //{"/sl/xrfb/facew/TongueTipInterdental", new List{} }, - //{"/sl/xrfb/facew/FrontDorsalPalate", new List{} }, - //{"/sl/xrfb/facew/MidDorsalPalate", new List{} }, - //{"/sl/xrfb/facew/BackDorsalVelar", new List{} }, - //{"/sl/xrfb/facew/TongueRetreat", new List{} }, - //{"/sl/xrfb/facew/TongueTipAlveolar", new List{TongueCurlUp} }, - {"/sl/xrfb/facew/TongueOut", new List{TongueOut} }, - }; - - - - private Socket _receiver; - private bool _loop = true; - private readonly Thread _thread; - private readonly ILogger _logger; - private readonly int _resolvedPort; - private const int DEFAULT_PORT = 9015; - private const int TIMEOUT_MS = 10_000; - - public OSCHandler(ILogger iLogger, int? port = null) { - _logger = iLogger; - if (_receiver != null) - { - _logger.LogError("OSCHandler connection already exists."); - return; - } - - _receiver = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); - _resolvedPort = port ?? DEFAULT_PORT; - _receiver.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), _resolvedPort)); - _receiver.ReceiveTimeout = TIMEOUT_MS; - - _loop = true; - _thread = new Thread(new ThreadStart(ListenLoop)); - _thread.Start(); - // 1 second delay to hopefully fix any race conditions on thread initalization - //TODO remove this and actually fix the issue - Thread.Sleep(1000); + {"/sl/xrfb/facew/UpperLidRaiserL", new List{EyeWideLeft}}, + {"/sl/xrfb/facew/UpperLidRaiserR", new List{EyeWideRight}}, + {"/sl/xrfb/facew/LidTightenerL", new List{EyeSquintLeft}}, + {"/sl/xrfb/facew/LidTightenerR", new List{EyeSquintRight}}, + {"/sl/xrfb/facew/InnerBrowRaiserL", new List{BrowInnerUpLeft}}, + {"/sl/xrfb/facew/InnerBrowRaiserR", new List{BrowInnerUpRight}}, + {"/sl/xrfb/facew/OuterBrowRaiserL", new List{BrowOuterUpLeft}}, + {"/sl/xrfb/facew/OuterBrowRaiserR", new List{BrowOuterUpRight}}, + {"/sl/xrfb/facew/BrowLowererL", new List{BrowPinchLeft, BrowLowererLeft}}, + {"/sl/xrfb/facew/BrowLowererR", new List{BrowPinchRight, BrowLowererRight}}, + + {"/sl/xrfb/facew/JawDrop", new List{JawOpen}}, + {"/sl/xrfb/facew/JawSidewaysLeft", new List{JawLeft}}, + {"/sl/xrfb/facew/JawSidewaysRight", new List{JawRight}}, + {"/sl/xrfb/facew/JawThrust", new List{JawForward}}, + + {"/sl/xrfb/facew/MouthLeft", new List{MouthLowerLeft, MouthUpperLeft}}, + {"/sl/xrfb/facew/MouthRight", new List{MouthLowerRight, MouthUpperRight}}, + + {"/sl/xrfb/facew/ChinRaiserT", new List{MouthRaiserUpper} }, + {"/sl/xrfb/facew/ChinRaiserB", new List{MouthRaiserLower} }, + + {"/sl/xrfb/facew/DimplerL", new List{MouthDimpleLeft} }, + {"/sl/xrfb/facew/DimplerR", new List{MouthDimpleRight} }, + + {"/sl/xrfb/facew/LipsToward", new List{MouthClosed}}, + {"/sl/xrfb/facew/LipCornerPullerL", new List{ MouthCornerPullLeft, MouthCornerSlantLeft} }, + {"/sl/xrfb/facew/LipCornerPullerR", new List{ MouthCornerPullRight, MouthCornerSlantRight} }, + {"/sl/xrfb/facew/LipCornerDepressorL", new List{ MouthFrownLeft} }, + {"/sl/xrfb/facew/LipCornerDepressorR", new List{ MouthFrownRight} }, + {"/sl/xrfb/facew/LowerLipDepressorL", new List{ MouthLowerDownLeft} }, + {"/sl/xrfb/facew/LowerLipDepressorR", new List{ MouthLowerDownRight} }, + {"/sl/xrfb/facew/UpperLipRaiserL", new List{ MouthUpperUpLeft} }, //something odd here + {"/sl/xrfb/facew/UpperLipRaiserR", new List{ MouthUpperUpRight } }, //something odd here + {"/sl/xrfb/facew/LipTightenerL", new List{MouthTightenerLeft} }, + {"/sl/xrfb/facew/LipTightenerR", new List{MouthTightenerRight} }, + {"/sl/xrfb/facew/LipPressorL", new List{MouthPressLeft} }, + {"/sl/xrfb/facew/LipPressorR", new List{MouthPressRight} }, + {"/sl/xrfb/facew/LipStretcherL", new List{MouthStretchLeft} }, + {"/sl/xrfb/facew/LipStretcherR", new List{MouthStretchRight} }, + {"/sl/xrfb/facew/LipPuckerL", new List{ LipPuckerLowerLeft, LipPuckerUpperLeft } }, + {"/sl/xrfb/facew/LipPuckerR", new List{ LipPuckerLowerRight, LipPuckerUpperRight } }, + {"/sl/xrfb/facew/LipFunnelerLB", new List{LipFunnelLowerLeft} }, + {"/sl/xrfb/facew/LipFunnelerLT", new List{LipFunnelUpperLeft} }, + {"/sl/xrfb/facew/LipFunnelerRB", new List{LipFunnelLowerRight} }, + {"/sl/xrfb/facew/LipFunnelerRT", new List{LipFunnelUpperRight} }, + {"/sl/xrfb/facew/LipSuckLB", new List{LipSuckLowerLeft} }, + {"/sl/xrfb/facew/LipSuckLT", new List{LipSuckUpperLeft} }, + {"/sl/xrfb/facew/LipSuckRB", new List{LipSuckLowerRight} }, + {"/sl/xrfb/facew/LipSuckRT", new List{LipSuckUpperRight} }, + + {"/sl/xrfb/facew/CheekPuffL", new List{CheekPuffLeft} }, + {"/sl/xrfb/facew/CheekPuffR", new List{CheekPuffRight} }, + {"/sl/xrfb/facew/CheekSuckL", new List{CheekSuckLeft} }, + {"/sl/xrfb/facew/CheekSuckR", new List{CheekSuckRight} }, + {"/sl/xrfb/facew/CheekRaiserL", new List{CheekSquintLeft} }, + {"/sl/xrfb/facew/CheekRaiserR", new List{CheekSquintRight} }, + + {"/sl/xrfb/facew/NoseWrinklerL", new List{NoseSneerLeft} }, + {"/sl/xrfb/facew/NoseWrinklerR", new List{NoseSneerRight} }, + + //Tongue Tracking Params + //Some params sent but not part of UE or used? need to look into + //{"/sl/xrfb/facew/TongueTipInterdental", new List{} }, + //{"/sl/xrfb/facew/FrontDorsalPalate", new List{} }, + //{"/sl/xrfb/facew/MidDorsalPalate", new List{} }, + //{"/sl/xrfb/facew/BackDorsalVelar", new List{} }, + //{"/sl/xrfb/facew/TongueRetreat", new List{} }, + //{"/sl/xrfb/facew/TongueTipAlveolar", new List{TongueCurlUp} }, + {"/sl/xrfb/facew/TongueOut", new List{TongueOut} }, + }; + + + + private Socket _receiver; + private bool _loop = true; + private readonly Thread _thread; + private readonly ILogger _logger; + private readonly int _resolvedPort; + private const int DEFAULT_PORT = 9015; + private const int TIMEOUT_MS = 10_000; + + public OSCHandler(ILogger iLogger, int? port = null) + { + _logger = iLogger; + if (_receiver != null) + { + _logger.LogError("OSCHandler connection already exists."); + return; } - private void ListenLoop() + _receiver = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + _resolvedPort = port ?? DEFAULT_PORT; + _receiver.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), _resolvedPort)); + _receiver.ReceiveTimeout = TIMEOUT_MS; + + _loop = true; + _thread = new Thread(new ThreadStart(ListenLoop)); + _thread.Start(); + // 1 second delay to hopefully fix any race conditions on thread initalization + //TODO remove this and actually fix the issue + Thread.Sleep(1000); + } + + private void ListenLoop() + { + var buffer = new byte[8192]; + while (_loop) { - var buffer = new byte[8192]; - while (_loop) + try { - try + if (_receiver.IsBound) { - if (_receiver.IsBound) - { - var length = _receiver.Receive(buffer); - List msgList = new List(); - if (OSCParser.IsBundle(ref buffer)) + var length = _receiver.Receive(buffer); + List msgList = new List(); + if (OSCParser.IsBundle(ref buffer)) + { + int i = 16; + var elLength = new byte[4]; + while (i < length) { - int i = 16; - var elLength = new byte[4]; - while (i < length) + int messageLength = 0; + if (BitConverter.IsLittleEndian) { - int messageLength = 0; - if (BitConverter.IsLittleEndian) - { - byte[] msgsize = new byte[4]; - msgsize[0] = buffer[i]; msgsize[1] = buffer[i + 1]; msgsize[2] = buffer[i + 2]; msgsize[3] = buffer[i + 3]; - Array.Reverse(msgsize); - messageLength = BitConverter.ToInt32(msgsize, 0); - } - else - { - messageLength = BitConverter.ToInt32(buffer, i); - } - int adjustLength = 4 - messageLength % 4; - byte[] temp = new byte[messageLength]; - Array.Copy(buffer, i + 4, temp, 0, messageLength); - msgList.Add(new OSCM(ref temp, _logger)); - i = i + messageLength + adjustLength; - + byte[] msgsize = new byte[4]; + msgsize[0] = buffer[i]; msgsize[1] = buffer[i + 1]; msgsize[2] = buffer[i + 2]; msgsize[3] = buffer[i + 3]; + Array.Reverse(msgsize); + messageLength = BitConverter.ToInt32(msgsize, 0); } - } - else - { - msgList.Add(new OSCM(ref buffer, _logger)); - } - foreach (OSCM oscMessage in msgList) - { - if (oscMessage == null) continue; - if (oscMessage.Values.Count < 1) continue; - if (oscMessage.Address == "/sl/eyeTrackedGazePoint") + else { - for (int i = 0; i < 3; i++) - { - eyeTrackData[i] = (float)oscMessage.Values[i]; - } - continue; + messageLength = BitConverter.ToInt32(buffer, i); } - if (oscMessage.Address == ("/sl/xrfb/facew/EyesClosedL")) - { - eyelids[0] = (float)oscMessage.Values[0]; - continue; + int adjustLength = 4 - messageLength % 4; + byte[] temp = new byte[messageLength]; + Array.Copy(buffer, i + 4, temp, 0, messageLength); + msgList.Add(new OSCM(ref temp, _logger)); + i = i + messageLength + adjustLength; - } - if (oscMessage.Address == "/sl/xrfb/facew/EyesClosedR") + } + } + else + { + msgList.Add(new OSCM(ref buffer, _logger)); + } + foreach (OSCM oscMessage in msgList) + { + if (oscMessage == null) continue; + if (oscMessage.Values.Count < 1) continue; + if (oscMessage.Address == "/sl/eyeTrackedGazePoint") + { + for (int i = 0; i < 3; i++) { - eyelids[1] = (float)oscMessage.Values[0]; - continue; + eyeTrackData[i] = (float)oscMessage.Values[i]; } + continue; + } + if (oscMessage.Address == ("/sl/xrfb/facew/EyesClosedL")) + { + eyelids[0] = (float)oscMessage.Values[0]; + continue; + + } + if (oscMessage.Address == "/sl/xrfb/facew/EyesClosedR") + { + eyelids[1] = (float)oscMessage.Values[0]; + continue; + } - if (mapOSCDirectXRFBUnifiedExpressions.ContainsKey(oscMessage.Address)) + if (mapOSCDirectXRFBUnifiedExpressions.ContainsKey(oscMessage.Address)) + { + foreach (UnifiedExpressions unifiedExpression in mapOSCDirectXRFBUnifiedExpressions[oscMessage.Address]) { - foreach (UnifiedExpressions unifiedExpression in mapOSCDirectXRFBUnifiedExpressions[oscMessage.Address]) - { - //This may not be strictly safe but should be good enough for our use case - ueData[unifiedExpression] = (float)oscMessage.Values[0]; } - } + //This may not be strictly safe but should be good enough for our use case + ueData[unifiedExpression] = (float)oscMessage.Values[0]; } } } - else - { - _receiver.Close(); - _receiver.Dispose(); - _receiver = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); - _receiver.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), _resolvedPort)); - _receiver.ReceiveTimeout = TIMEOUT_MS; - } } - catch (Exception e) { - _logger.LogInformation("Exception {0}", e.Message); + else + { + _receiver.Close(); + _receiver.Dispose(); + _receiver = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + _receiver.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), _resolvedPort)); + _receiver.ReceiveTimeout = TIMEOUT_MS; } } + catch (Exception e) { + _logger.LogInformation("Exception {0}", e.Message); + } } + } - public void Teardown() - { - _loop = false; - _receiver.Close(); - _receiver.Dispose(); - _thread.Join(); - } - + public void Teardown() + { + _loop = false; + _receiver.Close(); + _receiver.Dispose(); + _thread.Join(); } -} + +} \ No newline at end of file diff --git a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCParser.cs b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCParser.cs index d7ef944..85e65ed 100644 --- a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCParser.cs +++ b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCParser.cs @@ -2,202 +2,201 @@ using System.Text; using Microsoft.Extensions.Logging; -namespace SteamLinkVRCFTModule +namespace SteamLinkVRCFTModule; + +public class OSCM { - public class OSCM - { - public string Address = ""; - public ArrayList Values = new ArrayList(); - //int = 0, float = 1, blob = 2, string = 3, error = -1 - private List valType = new List(); + public string Address = ""; + public ArrayList Values = new ArrayList(); + //int = 0, float = 1, blob = 2, string = 3, error = -1 + private List valType = new List(); - public int getAddress(ref byte[] msg, int index) + public int getAddress(ref byte[] msg, int index) + { + while (index < msg.Length) { - while (index < msg.Length) + if (msg[index] == 0x2c) + { + //Address = Encoding.ASCII.GetString(msg, 0, index - 1); + index++; + return index; + } + //This is sloppy, But need to verify if OSC spec is one null char on address or if it's up to 4? + if (msg[index] == 0x00) { - if (msg[index] == 0x2c) + if(Address == "") { - //Address = Encoding.ASCII.GetString(msg, 0, index - 1); - index++; - return index; + Address = Encoding.ASCII.GetString(msg, 0, index); } - //This is sloppy, But need to verify if OSC spec is one null char on address or if it's up to 4? - if (msg[index] == 0x00) - { - if(Address == "") - { - Address = Encoding.ASCII.GetString(msg, 0, index); - } - } - - index++; } - return -1; + + index++; } + return -1; + } - public int getParams(ref byte[] msg, int index, ILogger log) + public int getParams(ref byte[] msg, int index, ILogger log) + { + int valmax = 0; + //we start at the parameter not the "," in an osc string, and then we need + // an additional to account for offset + int typetagstart = index-1; + while (index < msg.Length) { - int valmax = 0; - //we start at the parameter not the "," in an osc string, and then we need - // an additional to account for offset - int typetagstart = index-1; - while (index < msg.Length) + switch (msg[index]) { - switch (msg[index]) - { - //null i.e. end of params - case 0x00: - return (4 - ((index - typetagstart) % 4 )+ index); - //float - case 0x66: - valType.Add(1); - valmax++; - break; - //int - case 0x69: - valType.Add(0); - valmax++; - break; - //blob - case 0x62: - valType.Add(2); - valmax++; - break; - //string - case 0x72: - valType.Add(3); - valmax++; - break; - default: - valType.Add(-1); - break; - } - index++; + //null i.e. end of params + case 0x00: + return (4 - ((index - typetagstart) % 4 )+ index); + //float + case 0x66: + valType.Add(1); + valmax++; + break; + //int + case 0x69: + valType.Add(0); + valmax++; + break; + //blob + case 0x62: + valType.Add(2); + valmax++; + break; + //string + case 0x72: + valType.Add(3); + valmax++; + break; + default: + valType.Add(-1); + break; } - return -1; + index++; } - public int getValues(ref byte[] message, int i, ILogger log) + return -1; + } + public int getValues(ref byte[] message, int i, ILogger log) + { + int valuecount = 0; + int maxVal = valType.Count(); + while (i < message.Length) { - int valuecount = 0; - int maxVal = valType.Count(); - while (i < message.Length) + byte[] msgsize = new byte[4]; + switch (valType[valuecount]) { - byte[] msgsize = new byte[4]; - switch (valType[valuecount]) - { - case 0: - if (BitConverter.IsLittleEndian) - { - msgsize[0] = message[i]; msgsize[1] = message[i + 1]; msgsize[2] = message[i + 2]; msgsize[3] = message[i + 3]; - Array.Reverse(msgsize); - Values.Add(BitConverter.ToInt32(msgsize, 0)); - } - else - { - Values.Add(BitConverter.ToInt32(message, i)); - } - i = i + 3; - valuecount++; - - break; - case 1: - if (BitConverter.IsLittleEndian) - { - msgsize[0] = message[i]; msgsize[1] = message[i + 1]; msgsize[2] = message[i + 2]; msgsize[3] = message[i + 3]; - Array.Reverse(msgsize); - Values.Add(BitConverter.ToSingle(msgsize, 0)); - } - else - { - Values.Add(BitConverter.ToSingle(message, i)); - } - i = i + 3; - valuecount++; + case 0: + if (BitConverter.IsLittleEndian) + { + msgsize[0] = message[i]; msgsize[1] = message[i + 1]; msgsize[2] = message[i + 2]; msgsize[3] = message[i + 3]; + Array.Reverse(msgsize); + Values.Add(BitConverter.ToInt32(msgsize, 0)); + } + else + { + Values.Add(BitConverter.ToInt32(message, i)); + } + i = i + 3; + valuecount++; - break; - case 2: - //TODO yea not happening (blob implementation) - break; - case 3: - log.LogInformation("string"); - int initialI = i; - while (message[i] != 0x00) - { - i++; - } - Values.Add(Encoding.ASCII.GetString(message, initialI, i)); - valuecount++; - //OSC padding to 32 bit chunks (4 byte) - i = i + ((i - initialI) % 4); - //i++; + break; + case 1: + if (BitConverter.IsLittleEndian) + { + msgsize[0] = message[i]; msgsize[1] = message[i + 1]; msgsize[2] = message[i + 2]; msgsize[3] = message[i + 3]; + Array.Reverse(msgsize); + Values.Add(BitConverter.ToSingle(msgsize, 0)); + } + else + { + Values.Add(BitConverter.ToSingle(message, i)); + } + i = i + 3; + valuecount++; - break; - default: - log.LogInformation("error default XXXXXXXX"); - //TODO error handling - break; + break; + case 2: + //TODO yea not happening (blob implementation) + break; + case 3: + log.LogInformation("string"); + int initialI = i; + while (message[i] != 0x00) + { + i++; + } + Values.Add(Encoding.ASCII.GetString(message, initialI, i)); + valuecount++; + //OSC padding to 32 bit chunks (4 byte) + i = i + ((i - initialI) % 4); + //i++; + break; + default: + log.LogInformation("error default XXXXXXXX"); + //TODO error handling + break; - } - if (valuecount == maxVal) - { - return message.Length; - } - i++; - } - return -1; - } - public OSCM(ref byte[] message, ILogger iLogger) - { - int i = 0; - i = getAddress(ref message, i); - if (i == -1) - { - iLogger.LogInformation("fail at addr"); - return; } - i = getParams(ref message, i, iLogger); - if (i == -1) + if (valuecount == maxVal) { - iLogger.LogInformation("fail at param"); - return; - } - i = getValues(ref message, i, iLogger); - if (i == -1) - { - iLogger.LogInformation("fail at value"); - return; + return message.Length; } + i++; } - + return -1; } - static public class OSCParser + public OSCM(ref byte[] message, ILogger iLogger) { - static readonly byte[] bufASCII = Encoding.ASCII.GetBytes("#bundle"); - public static bool IsBundle(ref byte[] buff) + int i = 0; + i = getAddress(ref message, i); + if (i == -1) { - if(buff == null|| buff.Length<8) - { - return false; - } - byte[] bundletest = new byte[7]; - Array.Copy(buff, bundletest, 7); - return Enumerable.SequenceEqual(bundletest, bufASCII); + iLogger.LogInformation("fail at addr"); + return; } - public static uint swapEndianness(uint x) + i = getParams(ref message, i, iLogger); + if (i == -1) { - return ((x & 0x000000ff) << 24) + // First byte - ((x & 0x0000ff00) << 8) + // Second byte - ((x & 0x00ff0000) >> 8) + // Third byte - ((x & 0xff000000) >> 24); // Fourth byte + iLogger.LogInformation("fail at param"); + return; } - public static int trueMod(int a, int b) + i = getValues(ref message, i, iLogger); + if (i == -1) { - return (Math.Abs(a * b) + a) % b; + iLogger.LogInformation("fail at value"); + return; } - } + } + +static public class OSCParser +{ + static readonly byte[] bufASCII = Encoding.ASCII.GetBytes("#bundle"); + public static bool IsBundle(ref byte[] buff) + { + if(buff == null|| buff.Length<8) + { + return false; + } + byte[] bundletest = new byte[7]; + Array.Copy(buff, bundletest, 7); + return Enumerable.SequenceEqual(bundletest, bufASCII); + } + public static uint swapEndianness(uint x) + { + return ((x & 0x000000ff) << 24) + // First byte + ((x & 0x0000ff00) << 8) + // Second byte + ((x & 0x00ff0000) >> 8) + // Third byte + ((x & 0xff000000) >> 24); // Fourth byte + } + public static int trueMod(int a, int b) + { + return (Math.Abs(a * b) + a) % b; + } + +} \ No newline at end of file diff --git a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/SteamLinkVRCFTModule.cs b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/SteamLinkVRCFTModule.cs index a6a5c14..72fcf0b 100644 --- a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/SteamLinkVRCFTModule.cs +++ b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/SteamLinkVRCFTModule.cs @@ -2,101 +2,100 @@ using VRCFaceTracking.Core.Params.Expressions; using static VRCFaceTracking.Core.Params.Expressions.UnifiedExpressions; -namespace SteamLinkVRCFTModule +namespace SteamLinkVRCFTModule; + +public class SteamLinkVRCFTModule : ExtTrackingModule { - public class SteamLinkVRCFTModule : ExtTrackingModule - { - private OSCHandler OSCHandler; - private const int DEFAULT_PORT = 9015; + private OSCHandler OSCHandler; + private const int DEFAULT_PORT = 9015; - public override (bool SupportsEye, bool SupportsExpression) Supported => (true, true); + public override (bool SupportsEye, bool SupportsExpression) Supported => (true, true); - public override (bool eyeSuccess, bool expressionSuccess) Initialize(bool eyeAvailable, bool expressionAvailable) - { - ModuleInformation.Name = "SteamLink Module"; + public override (bool eyeSuccess, bool expressionSuccess) Initialize(bool eyeAvailable, bool expressionAvailable) + { + ModuleInformation.Name = "SteamLink Module"; - var stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("SteamLinkVRCFTModule.Assets.steamlink.png"); - ModuleInformation.StaticImages = stream != null ? new List { stream } : ModuleInformation.StaticImages; + var stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("SteamLinkVRCFTModule.Assets.steamlink.png"); + ModuleInformation.StaticImages = stream != null ? new List { stream } : ModuleInformation.StaticImages; - //TODO better error handling on fail? isInit for OSC Handler? - OSCHandler = new OSCHandler(Logger, DEFAULT_PORT); + //TODO better error handling on fail? isInit for OSC Handler? + OSCHandler = new OSCHandler(Logger, DEFAULT_PORT); - return (true, true); - } + return (true, true); + } - private static float CalculateEyeOpenness(float fEyeClosedWeight, float fEyeTightener) - { - return 1.0f - Math.Clamp(fEyeClosedWeight + fEyeClosedWeight * fEyeTightener, 0.0f, 1.0f); - } + private static float CalculateEyeOpenness(float fEyeClosedWeight, float fEyeTightener) + { + return 1.0f - Math.Clamp(fEyeClosedWeight + fEyeClosedWeight * fEyeTightener, 0.0f, 1.0f); + } - private void UpdateEyeTracking() + private void UpdateEyeTracking() + { { - { - float fAngleX = MathF.Atan2(OSCHandler.eyeTrackData[0], -OSCHandler.eyeTrackData[2]); - float fAngleY = MathF.Atan2(OSCHandler.eyeTrackData[1], -OSCHandler.eyeTrackData[2]); - - float fNmAngleX = fAngleX / (MathF.PI / 2.0f) * 2.0f; - float fNmAngleY = fAngleY / (MathF.PI / 2.0f) * 2.0f; - - if (float.IsNaN(fNmAngleX)) - { - fNmAngleX = 0.0f; - } - if (float.IsNaN(fNmAngleY)) - { - fNmAngleY = 0.0f; - } + float fAngleX = MathF.Atan2(OSCHandler.eyeTrackData[0], -OSCHandler.eyeTrackData[2]); + float fAngleY = MathF.Atan2(OSCHandler.eyeTrackData[1], -OSCHandler.eyeTrackData[2]); - UnifiedTracking.Data.Eye.Left.Gaze.x = fAngleX; - UnifiedTracking.Data.Eye.Left.Gaze.y = fAngleY; - - UnifiedTracking.Data.Eye.Right.Gaze.x = fAngleX; - UnifiedTracking.Data.Eye.Right.Gaze.y = fAngleY; + float fNmAngleX = fAngleX / (MathF.PI / 2.0f) * 2.0f; + float fNmAngleY = fAngleY / (MathF.PI / 2.0f) * 2.0f; + if (float.IsNaN(fNmAngleX)) + { + fNmAngleX = 0.0f; + } + if (float.IsNaN(fNmAngleY)) + { + fNmAngleY = 0.0f; + } - //Pupil Dilation, This is not supported, but if we don't set it can cause issues - UnifiedTracking.Data.Eye.Left.PupilDiameter_MM = 5f; - UnifiedTracking.Data.Eye.Right.PupilDiameter_MM = 5f; - UnifiedTracking.Data.Eye._maxDilation = 10; - UnifiedTracking.Data.Eye._minDilation = 0; + UnifiedTracking.Data.Eye.Left.Gaze.x = fAngleX; + UnifiedTracking.Data.Eye.Left.Gaze.y = fAngleY; - } + UnifiedTracking.Data.Eye.Right.Gaze.x = fAngleX; + UnifiedTracking.Data.Eye.Right.Gaze.y = fAngleY; - { - float fLeftOpenness = CalculateEyeOpenness(OSCHandler.eyelids[0], OSCHandler.ueData[UnifiedExpressions.EyeSquintLeft]); - float fRightOpenness = CalculateEyeOpenness(OSCHandler.eyelids[1], OSCHandler.ueData[UnifiedExpressions.EyeSquintRight]); - UnifiedTracking.Data.Eye.Left.Openness = fLeftOpenness;// fLeftOpenness; - UnifiedTracking.Data.Eye.Right.Openness = fRightOpenness;//fRightOpenness; - } + //Pupil Dilation, This is not supported, but if we don't set it can cause issues + UnifiedTracking.Data.Eye.Left.PupilDiameter_MM = 5f; + UnifiedTracking.Data.Eye.Right.PupilDiameter_MM = 5f; + UnifiedTracking.Data.Eye._maxDilation = 10; + UnifiedTracking.Data.Eye._minDilation = 0; } - private void UpdateFaceTracking() - { - foreach (KeyValuePair entry in OSCHandler.ueData) - { - UnifiedTracking.Data.Shapes[(int)entry.Key].Weight = entry.Value; - } - //?? fix some weird ft things need to check (Its not needed anymore, this in fact causes upper lip to not move properly, its more notorious when you try to set an "eww" face) - //UnifiedTracking.Data.Shapes[(int)MouthUpperUpLeft].Weight = Math.Max(0, UnifiedTracking.Data.Shapes[(int)MouthUpperUpLeft].Weight - UnifiedTracking.Data.Shapes[(int)NoseSneerLeft].Weight); - //UnifiedTracking.Data.Shapes[(int)MouthUpperUpRight].Weight = Math.Max(0, UnifiedTracking.Data.Shapes[(int)MouthUpperUpRight].Weight - UnifiedTracking.Data.Shapes[(int)NoseSneerRight].Weight); - //UnifiedTracking.Data.Shapes[(int)MouthUpperDeepenLeft].Weight = Math.Max(0, UnifiedTracking.Data.Shapes[(int)MouthUpperUpLeft].Weight - UnifiedTracking.Data.Shapes[(int)NoseSneerLeft].Weight); - //UnifiedTracking.Data.Shapes[(int)MouthUpperDeepenRight].Weight = Math.Max(0, UnifiedTracking.Data.Shapes[(int)MouthUpperUpRight].Weight - UnifiedTracking.Data.Shapes[(int)NoseSneerRight].Weight); - - //lip Suck - UnifiedTracking.Data.Shapes[(int)LipSuckUpperLeft].Weight = Math.Min(1.0f - (float)Math.Pow(UnifiedTracking.Data.Shapes[(int)MouthUpperLeft].Weight, 1f / 6f), UnifiedTracking.Data.Shapes[(int)LipSuckUpperLeft].Weight); - UnifiedTracking.Data.Shapes[(int)LipSuckUpperRight].Weight = Math.Min(1.0f - (float)Math.Pow(UnifiedTracking.Data.Shapes[(int)MouthUpperRight].Weight, 1f / 6f), UnifiedTracking.Data.Shapes[(int)LipSuckUpperRight].Weight); - } - public override void Update() { - Thread.Sleep(10); - UpdateEyeTracking(); - UpdateFaceTracking(); + float fLeftOpenness = CalculateEyeOpenness(OSCHandler.eyelids[0], OSCHandler.ueData[UnifiedExpressions.EyeSquintLeft]); + float fRightOpenness = CalculateEyeOpenness(OSCHandler.eyelids[1], OSCHandler.ueData[UnifiedExpressions.EyeSquintRight]); + + UnifiedTracking.Data.Eye.Left.Openness = fLeftOpenness;// fLeftOpenness; + UnifiedTracking.Data.Eye.Right.Openness = fRightOpenness;//fRightOpenness; } - public override void Teardown() + + } + private void UpdateFaceTracking() + { + foreach (KeyValuePair entry in OSCHandler.ueData) { - OSCHandler.Teardown(); + UnifiedTracking.Data.Shapes[(int)entry.Key].Weight = entry.Value; } + //?? fix some weird ft things need to check (Its not needed anymore, this in fact causes upper lip to not move properly, its more notorious when you try to set an "eww" face) + //UnifiedTracking.Data.Shapes[(int)MouthUpperUpLeft].Weight = Math.Max(0, UnifiedTracking.Data.Shapes[(int)MouthUpperUpLeft].Weight - UnifiedTracking.Data.Shapes[(int)NoseSneerLeft].Weight); + //UnifiedTracking.Data.Shapes[(int)MouthUpperUpRight].Weight = Math.Max(0, UnifiedTracking.Data.Shapes[(int)MouthUpperUpRight].Weight - UnifiedTracking.Data.Shapes[(int)NoseSneerRight].Weight); + //UnifiedTracking.Data.Shapes[(int)MouthUpperDeepenLeft].Weight = Math.Max(0, UnifiedTracking.Data.Shapes[(int)MouthUpperUpLeft].Weight - UnifiedTracking.Data.Shapes[(int)NoseSneerLeft].Weight); + //UnifiedTracking.Data.Shapes[(int)MouthUpperDeepenRight].Weight = Math.Max(0, UnifiedTracking.Data.Shapes[(int)MouthUpperUpRight].Weight - UnifiedTracking.Data.Shapes[(int)NoseSneerRight].Weight); + + //lip Suck + UnifiedTracking.Data.Shapes[(int)LipSuckUpperLeft].Weight = Math.Min(1.0f - (float)Math.Pow(UnifiedTracking.Data.Shapes[(int)MouthUpperLeft].Weight, 1f / 6f), UnifiedTracking.Data.Shapes[(int)LipSuckUpperLeft].Weight); + UnifiedTracking.Data.Shapes[(int)LipSuckUpperRight].Weight = Math.Min(1.0f - (float)Math.Pow(UnifiedTracking.Data.Shapes[(int)MouthUpperRight].Weight, 1f / 6f), UnifiedTracking.Data.Shapes[(int)LipSuckUpperRight].Weight); + } + + public override void Update() + { + Thread.Sleep(10); + UpdateEyeTracking(); + UpdateFaceTracking(); + } + public override void Teardown() + { + OSCHandler.Teardown(); } -} +} \ No newline at end of file From 18e6e9f30a84daaf65a6d5de786536609fe40451 Mon Sep 17 00:00:00 2001 From: dfgHiatus <51272212+dfgHiatus@users.noreply.github.com> Date: Sun, 18 Jan 2026 13:21:04 -0500 Subject: [PATCH 3/6] Update variable names to match naming standards --- .../SteamLinkVRCFTModule/OSCHandler.cs | 44 +++++++++---------- .../SteamLinkVRCFTModule/OSCParser.cs | 42 +++++++++--------- .../SteamLinkVRCFTModule.cs | 20 ++++----- 3 files changed, 53 insertions(+), 53 deletions(-) diff --git a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCHandler.cs b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCHandler.cs index 45ee25b..75ea125 100644 --- a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCHandler.cs +++ b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCHandler.cs @@ -7,12 +7,12 @@ namespace SteamLinkVRCFTModule; using static UnifiedExpressions; -public class OSCHandler +public class OscHandler { - public readonly float[] eyeTrackData = new float[3]; - public readonly float[] eyelids = new float[2]; + public readonly float[] EyeTrackData = new float[3]; + public readonly float[] Eyelids = new float[2]; - public static readonly Dictionary ueData = new(){ + public static readonly Dictionary UeData = new(){ {EyeWideLeft, 0.0f }, {EyeWideRight, 0.0f }, {EyeSquintLeft, 0.0f }, @@ -86,7 +86,7 @@ public class OSCHandler //based on https://docs.google.com/spreadsheets/d/118jo960co3Mgw8eREFVBsaJ7z0GtKNr52IB4Bz99VTA/edit#gid=0 private static readonly - Dictionary> mapOSCDirectXRFBUnifiedExpressions = new Dictionary> + Dictionary> MapOscDirectXrfbUnifiedExpressions = new Dictionary> { {"/sl/xrfb/facew/UpperLidRaiserL", new List{EyeWideLeft}}, {"/sl/xrfb/facew/UpperLidRaiserR", new List{EyeWideRight}}, @@ -167,10 +167,10 @@ private static readonly private readonly Thread _thread; private readonly ILogger _logger; private readonly int _resolvedPort; - private const int DEFAULT_PORT = 9015; - private const int TIMEOUT_MS = 10_000; + private const int DefaultPort = 9015; + private const int TimeoutMs = 10_000; - public OSCHandler(ILogger iLogger, int? port = null) + public OscHandler(ILogger iLogger, int? port = null) { _logger = iLogger; if (_receiver != null) @@ -180,9 +180,9 @@ public OSCHandler(ILogger iLogger, int? port = null) } _receiver = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); - _resolvedPort = port ?? DEFAULT_PORT; + _resolvedPort = port ?? DefaultPort; _receiver.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), _resolvedPort)); - _receiver.ReceiveTimeout = TIMEOUT_MS; + _receiver.ReceiveTimeout = TimeoutMs; _loop = true; _thread = new Thread(new ThreadStart(ListenLoop)); @@ -205,8 +205,8 @@ private void ListenLoop() var length = _receiver.Receive(buffer); - List msgList = new List(); - if (OSCParser.IsBundle(ref buffer)) + List msgList = new List(); + if (OscParser.IsBundle(ref buffer)) { int i = 16; var elLength = new byte[4]; @@ -227,16 +227,16 @@ private void ListenLoop() int adjustLength = 4 - messageLength % 4; byte[] temp = new byte[messageLength]; Array.Copy(buffer, i + 4, temp, 0, messageLength); - msgList.Add(new OSCM(ref temp, _logger)); + msgList.Add(new Oscm(ref temp, _logger)); i = i + messageLength + adjustLength; } } else { - msgList.Add(new OSCM(ref buffer, _logger)); + msgList.Add(new Oscm(ref buffer, _logger)); } - foreach (OSCM oscMessage in msgList) + foreach (Oscm oscMessage in msgList) { if (oscMessage == null) continue; if (oscMessage.Values.Count < 1) continue; @@ -244,28 +244,28 @@ private void ListenLoop() { for (int i = 0; i < 3; i++) { - eyeTrackData[i] = (float)oscMessage.Values[i]; + EyeTrackData[i] = (float)oscMessage.Values[i]; } continue; } if (oscMessage.Address == ("/sl/xrfb/facew/EyesClosedL")) { - eyelids[0] = (float)oscMessage.Values[0]; + Eyelids[0] = (float)oscMessage.Values[0]; continue; } if (oscMessage.Address == "/sl/xrfb/facew/EyesClosedR") { - eyelids[1] = (float)oscMessage.Values[0]; + Eyelids[1] = (float)oscMessage.Values[0]; continue; } - if (mapOSCDirectXRFBUnifiedExpressions.ContainsKey(oscMessage.Address)) + if (MapOscDirectXrfbUnifiedExpressions.ContainsKey(oscMessage.Address)) { - foreach (UnifiedExpressions unifiedExpression in mapOSCDirectXRFBUnifiedExpressions[oscMessage.Address]) + foreach (UnifiedExpressions unifiedExpression in MapOscDirectXrfbUnifiedExpressions[oscMessage.Address]) { //This may not be strictly safe but should be good enough for our use case - ueData[unifiedExpression] = (float)oscMessage.Values[0]; } + UeData[unifiedExpression] = (float)oscMessage.Values[0]; } } } } @@ -275,7 +275,7 @@ private void ListenLoop() _receiver.Dispose(); _receiver = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); _receiver.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), _resolvedPort)); - _receiver.ReceiveTimeout = TIMEOUT_MS; + _receiver.ReceiveTimeout = TimeoutMs; } } catch (Exception e) { diff --git a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCParser.cs b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCParser.cs index 85e65ed..fbba6a1 100644 --- a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCParser.cs +++ b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCParser.cs @@ -4,15 +4,15 @@ namespace SteamLinkVRCFTModule; -public class OSCM +public class Oscm { public string Address = ""; public ArrayList Values = new ArrayList(); //int = 0, float = 1, blob = 2, string = 3, error = -1 - private List valType = new List(); + private List _valType = new List(); - public int getAddress(ref byte[] msg, int index) + public int GetAddress(ref byte[] msg, int index) { while (index < msg.Length) { @@ -36,7 +36,7 @@ public int getAddress(ref byte[] msg, int index) return -1; } - public int getParams(ref byte[] msg, int index, ILogger log) + public int GetParams(ref byte[] msg, int index, ILogger log) { int valmax = 0; //we start at the parameter not the "," in an osc string, and then we need @@ -51,40 +51,40 @@ public int getParams(ref byte[] msg, int index, ILogger log) return (4 - ((index - typetagstart) % 4 )+ index); //float case 0x66: - valType.Add(1); + _valType.Add(1); valmax++; break; //int case 0x69: - valType.Add(0); + _valType.Add(0); valmax++; break; //blob case 0x62: - valType.Add(2); + _valType.Add(2); valmax++; break; //string case 0x72: - valType.Add(3); + _valType.Add(3); valmax++; break; default: - valType.Add(-1); + _valType.Add(-1); break; } index++; } return -1; } - public int getValues(ref byte[] message, int i, ILogger log) + public int GetValues(ref byte[] message, int i, ILogger log) { int valuecount = 0; - int maxVal = valType.Count(); + int maxVal = _valType.Count(); while (i < message.Length) { byte[] msgsize = new byte[4]; - switch (valType[valuecount]) + switch (_valType[valuecount]) { case 0: if (BitConverter.IsLittleEndian) @@ -149,22 +149,22 @@ public int getValues(ref byte[] message, int i, ILogger log) return -1; } - public OSCM(ref byte[] message, ILogger iLogger) + public Oscm(ref byte[] message, ILogger iLogger) { int i = 0; - i = getAddress(ref message, i); + i = GetAddress(ref message, i); if (i == -1) { iLogger.LogInformation("fail at addr"); return; } - i = getParams(ref message, i, iLogger); + i = GetParams(ref message, i, iLogger); if (i == -1) { iLogger.LogInformation("fail at param"); return; } - i = getValues(ref message, i, iLogger); + i = GetValues(ref message, i, iLogger); if (i == -1) { iLogger.LogInformation("fail at value"); @@ -174,9 +174,9 @@ public OSCM(ref byte[] message, ILogger iLogger) } -static public class OSCParser +static public class OscParser { - static readonly byte[] bufASCII = Encoding.ASCII.GetBytes("#bundle"); + static readonly byte[] BufAscii = Encoding.ASCII.GetBytes("#bundle"); public static bool IsBundle(ref byte[] buff) { if(buff == null|| buff.Length<8) @@ -185,16 +185,16 @@ public static bool IsBundle(ref byte[] buff) } byte[] bundletest = new byte[7]; Array.Copy(buff, bundletest, 7); - return Enumerable.SequenceEqual(bundletest, bufASCII); + return Enumerable.SequenceEqual(bundletest, BufAscii); } - public static uint swapEndianness(uint x) + public static uint SwapEndianness(uint x) { return ((x & 0x000000ff) << 24) + // First byte ((x & 0x0000ff00) << 8) + // Second byte ((x & 0x00ff0000) >> 8) + // Third byte ((x & 0xff000000) >> 24); // Fourth byte } - public static int trueMod(int a, int b) + public static int TrueMod(int a, int b) { return (Math.Abs(a * b) + a) % b; } diff --git a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/SteamLinkVRCFTModule.cs b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/SteamLinkVRCFTModule.cs index 72fcf0b..c1b44da 100644 --- a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/SteamLinkVRCFTModule.cs +++ b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/SteamLinkVRCFTModule.cs @@ -4,10 +4,10 @@ namespace SteamLinkVRCFTModule; -public class SteamLinkVRCFTModule : ExtTrackingModule +public class SteamLinkVrcftModule : ExtTrackingModule { - private OSCHandler OSCHandler; - private const int DEFAULT_PORT = 9015; + private OscHandler _oscHandler; + private const int DefaultPort = 9015; public override (bool SupportsEye, bool SupportsExpression) Supported => (true, true); @@ -19,7 +19,7 @@ public override (bool eyeSuccess, bool expressionSuccess) Initialize(bool eyeAva ModuleInformation.StaticImages = stream != null ? new List { stream } : ModuleInformation.StaticImages; //TODO better error handling on fail? isInit for OSC Handler? - OSCHandler = new OSCHandler(Logger, DEFAULT_PORT); + _oscHandler = new OscHandler(Logger, DefaultPort); return (true, true); } @@ -32,8 +32,8 @@ private static float CalculateEyeOpenness(float fEyeClosedWeight, float fEyeTigh private void UpdateEyeTracking() { { - float fAngleX = MathF.Atan2(OSCHandler.eyeTrackData[0], -OSCHandler.eyeTrackData[2]); - float fAngleY = MathF.Atan2(OSCHandler.eyeTrackData[1], -OSCHandler.eyeTrackData[2]); + float fAngleX = MathF.Atan2(_oscHandler.EyeTrackData[0], -_oscHandler.EyeTrackData[2]); + float fAngleY = MathF.Atan2(_oscHandler.EyeTrackData[1], -_oscHandler.EyeTrackData[2]); float fNmAngleX = fAngleX / (MathF.PI / 2.0f) * 2.0f; float fNmAngleY = fAngleY / (MathF.PI / 2.0f) * 2.0f; @@ -63,8 +63,8 @@ private void UpdateEyeTracking() } { - float fLeftOpenness = CalculateEyeOpenness(OSCHandler.eyelids[0], OSCHandler.ueData[UnifiedExpressions.EyeSquintLeft]); - float fRightOpenness = CalculateEyeOpenness(OSCHandler.eyelids[1], OSCHandler.ueData[UnifiedExpressions.EyeSquintRight]); + float fLeftOpenness = CalculateEyeOpenness(_oscHandler.Eyelids[0], OscHandler.UeData[UnifiedExpressions.EyeSquintLeft]); + float fRightOpenness = CalculateEyeOpenness(_oscHandler.Eyelids[1], OscHandler.UeData[UnifiedExpressions.EyeSquintRight]); UnifiedTracking.Data.Eye.Left.Openness = fLeftOpenness;// fLeftOpenness; UnifiedTracking.Data.Eye.Right.Openness = fRightOpenness;//fRightOpenness; @@ -73,7 +73,7 @@ private void UpdateEyeTracking() } private void UpdateFaceTracking() { - foreach (KeyValuePair entry in OSCHandler.ueData) + foreach (KeyValuePair entry in OscHandler.UeData) { UnifiedTracking.Data.Shapes[(int)entry.Key].Weight = entry.Value; } @@ -96,6 +96,6 @@ public override void Update() } public override void Teardown() { - OSCHandler.Teardown(); + _oscHandler.Teardown(); } } \ No newline at end of file From b202742bf8e9a2ed8eb58b4698f05819940e4f88 Mon Sep 17 00:00:00 2001 From: dfgHiatus <51272212+dfgHiatus@users.noreply.github.com> Date: Sun, 18 Jan 2026 13:22:07 -0500 Subject: [PATCH 4/6] Convert simple variable declarations to use `var` --- .../SteamLinkVRCFTModule/OSCHandler.cs | 18 +++++++++--------- .../SteamLinkVRCFTModule/OSCParser.cs | 16 ++++++++-------- .../SteamLinkVRCFTModule.cs | 14 +++++++------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCHandler.cs b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCHandler.cs index 75ea125..8b131ef 100644 --- a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCHandler.cs +++ b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCHandler.cs @@ -205,17 +205,17 @@ private void ListenLoop() var length = _receiver.Receive(buffer); - List msgList = new List(); + var msgList = new List(); if (OscParser.IsBundle(ref buffer)) { - int i = 16; + var i = 16; var elLength = new byte[4]; while (i < length) { - int messageLength = 0; + var messageLength = 0; if (BitConverter.IsLittleEndian) { - byte[] msgsize = new byte[4]; + var msgsize = new byte[4]; msgsize[0] = buffer[i]; msgsize[1] = buffer[i + 1]; msgsize[2] = buffer[i + 2]; msgsize[3] = buffer[i + 3]; Array.Reverse(msgsize); messageLength = BitConverter.ToInt32(msgsize, 0); @@ -224,8 +224,8 @@ private void ListenLoop() { messageLength = BitConverter.ToInt32(buffer, i); } - int adjustLength = 4 - messageLength % 4; - byte[] temp = new byte[messageLength]; + var adjustLength = 4 - messageLength % 4; + var temp = new byte[messageLength]; Array.Copy(buffer, i + 4, temp, 0, messageLength); msgList.Add(new Oscm(ref temp, _logger)); i = i + messageLength + adjustLength; @@ -236,13 +236,13 @@ private void ListenLoop() { msgList.Add(new Oscm(ref buffer, _logger)); } - foreach (Oscm oscMessage in msgList) + foreach (var oscMessage in msgList) { if (oscMessage == null) continue; if (oscMessage.Values.Count < 1) continue; if (oscMessage.Address == "/sl/eyeTrackedGazePoint") { - for (int i = 0; i < 3; i++) + for (var i = 0; i < 3; i++) { EyeTrackData[i] = (float)oscMessage.Values[i]; } @@ -262,7 +262,7 @@ private void ListenLoop() if (MapOscDirectXrfbUnifiedExpressions.ContainsKey(oscMessage.Address)) { - foreach (UnifiedExpressions unifiedExpression in MapOscDirectXrfbUnifiedExpressions[oscMessage.Address]) + foreach (var unifiedExpression in MapOscDirectXrfbUnifiedExpressions[oscMessage.Address]) { //This may not be strictly safe but should be good enough for our use case UeData[unifiedExpression] = (float)oscMessage.Values[0]; } diff --git a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCParser.cs b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCParser.cs index fbba6a1..2219f45 100644 --- a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCParser.cs +++ b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCParser.cs @@ -38,10 +38,10 @@ public int GetAddress(ref byte[] msg, int index) public int GetParams(ref byte[] msg, int index, ILogger log) { - int valmax = 0; + var valmax = 0; //we start at the parameter not the "," in an osc string, and then we need // an additional to account for offset - int typetagstart = index-1; + var typetagstart = index-1; while (index < msg.Length) { switch (msg[index]) @@ -79,11 +79,11 @@ public int GetParams(ref byte[] msg, int index, ILogger log) } public int GetValues(ref byte[] message, int i, ILogger log) { - int valuecount = 0; - int maxVal = _valType.Count(); + var valuecount = 0; + var maxVal = _valType.Count(); while (i < message.Length) { - byte[] msgsize = new byte[4]; + var msgsize = new byte[4]; switch (_valType[valuecount]) { case 0: @@ -121,7 +121,7 @@ public int GetValues(ref byte[] message, int i, ILogger log) break; case 3: log.LogInformation("string"); - int initialI = i; + var initialI = i; while (message[i] != 0x00) { i++; @@ -151,7 +151,7 @@ public int GetValues(ref byte[] message, int i, ILogger log) public Oscm(ref byte[] message, ILogger iLogger) { - int i = 0; + var i = 0; i = GetAddress(ref message, i); if (i == -1) { @@ -183,7 +183,7 @@ public static bool IsBundle(ref byte[] buff) { return false; } - byte[] bundletest = new byte[7]; + var bundletest = new byte[7]; Array.Copy(buff, bundletest, 7); return Enumerable.SequenceEqual(bundletest, BufAscii); } diff --git a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/SteamLinkVRCFTModule.cs b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/SteamLinkVRCFTModule.cs index c1b44da..93253d5 100644 --- a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/SteamLinkVRCFTModule.cs +++ b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/SteamLinkVRCFTModule.cs @@ -32,11 +32,11 @@ private static float CalculateEyeOpenness(float fEyeClosedWeight, float fEyeTigh private void UpdateEyeTracking() { { - float fAngleX = MathF.Atan2(_oscHandler.EyeTrackData[0], -_oscHandler.EyeTrackData[2]); - float fAngleY = MathF.Atan2(_oscHandler.EyeTrackData[1], -_oscHandler.EyeTrackData[2]); + var fAngleX = MathF.Atan2(_oscHandler.EyeTrackData[0], -_oscHandler.EyeTrackData[2]); + var fAngleY = MathF.Atan2(_oscHandler.EyeTrackData[1], -_oscHandler.EyeTrackData[2]); - float fNmAngleX = fAngleX / (MathF.PI / 2.0f) * 2.0f; - float fNmAngleY = fAngleY / (MathF.PI / 2.0f) * 2.0f; + var fNmAngleX = fAngleX / (MathF.PI / 2.0f) * 2.0f; + var fNmAngleY = fAngleY / (MathF.PI / 2.0f) * 2.0f; if (float.IsNaN(fNmAngleX)) { @@ -63,8 +63,8 @@ private void UpdateEyeTracking() } { - float fLeftOpenness = CalculateEyeOpenness(_oscHandler.Eyelids[0], OscHandler.UeData[UnifiedExpressions.EyeSquintLeft]); - float fRightOpenness = CalculateEyeOpenness(_oscHandler.Eyelids[1], OscHandler.UeData[UnifiedExpressions.EyeSquintRight]); + var fLeftOpenness = CalculateEyeOpenness(_oscHandler.Eyelids[0], OscHandler.UeData[UnifiedExpressions.EyeSquintLeft]); + var fRightOpenness = CalculateEyeOpenness(_oscHandler.Eyelids[1], OscHandler.UeData[UnifiedExpressions.EyeSquintRight]); UnifiedTracking.Data.Eye.Left.Openness = fLeftOpenness;// fLeftOpenness; UnifiedTracking.Data.Eye.Right.Openness = fRightOpenness;//fRightOpenness; @@ -73,7 +73,7 @@ private void UpdateEyeTracking() } private void UpdateFaceTracking() { - foreach (KeyValuePair entry in OscHandler.UeData) + foreach (var entry in OscHandler.UeData) { UnifiedTracking.Data.Shapes[(int)entry.Key].Weight = entry.Value; } From 1e0340e9e00475b74192246eaafbcea2189a9130 Mon Sep 17 00:00:00 2001 From: dfgHiatus <51272212+dfgHiatus@users.noreply.github.com> Date: Sun, 18 Jan 2026 13:24:21 -0500 Subject: [PATCH 5/6] Run formatter --- .../SteamLinkVRCFTModule/OSCHandler.cs | 325 +++++++++--------- .../SteamLinkVRCFTModule/OSCParser.cs | 50 ++- .../SteamLinkVRCFTModule.cs | 26 +- 3 files changed, 224 insertions(+), 177 deletions(-) diff --git a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCHandler.cs b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCHandler.cs index 8b131ef..dc15485 100644 --- a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCHandler.cs +++ b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCHandler.cs @@ -12,154 +12,169 @@ public class OscHandler public readonly float[] EyeTrackData = new float[3]; public readonly float[] Eyelids = new float[2]; - public static readonly Dictionary UeData = new(){ - {EyeWideLeft, 0.0f }, - {EyeWideRight, 0.0f }, - {EyeSquintLeft, 0.0f }, - {EyeSquintRight, 0.0f }, - {BrowInnerUpLeft, 0.0f }, - {BrowInnerUpRight, 0.0f }, - {BrowOuterUpLeft, 0.0f }, - {BrowOuterUpRight, 0.0f }, - {BrowPinchLeft, 0.0f }, - {BrowLowererLeft, 0.0f }, - {BrowLowererRight, 0.0f }, - {BrowPinchRight, 0.0f }, - - { JawOpen, 0.0f}, - { JawLeft, 0.0f}, - { JawRight, 0.0f}, - { JawForward, 0.0f}, - { MouthLowerLeft, 0.0f}, - { MouthUpperLeft, 0.0f}, - { MouthLowerRight, 0.0f}, - { MouthUpperRight, 0.0f}, - { MouthRaiserUpper, 0.0f}, - { MouthRaiserLower, 0.0f}, - - {MouthDimpleLeft ,0.0f}, - { MouthDimpleRight,0.0f}, - { MouthClosed,0.0f}, - { MouthCornerPullLeft,0.0f}, - { MouthCornerSlantLeft,0.0f}, - { MouthCornerPullRight,0.0f}, - { MouthCornerSlantRight,0.0f}, - - {MouthFrownLeft ,0.0f}, - { MouthFrownRight,0.0f}, - { MouthLowerDownLeft,0.0f}, - {MouthLowerDownRight ,0.0f}, - { MouthUpperUpLeft,0.0f}, //TODO CHECK - {MouthUpperUpRight ,0.0f}, //TODO CHECK - {MouthTightenerLeft ,0.0f}, - { MouthTightenerRight,0.0f}, - {MouthPressLeft ,0.0f}, - {MouthPressRight ,0.0f}, - {MouthStretchLeft ,0.0f}, - {MouthStretchRight ,0.0f}, - {LipPuckerLowerLeft ,0.0f}, - { LipPuckerUpperLeft,0.0f}, - { LipPuckerLowerRight,0.0f}, - {LipPuckerUpperRight ,0.0f}, - { LipFunnelLowerLeft,0.0f}, - { LipFunnelUpperLeft,0.0f}, - { LipFunnelLowerRight,0.0f}, - { LipFunnelUpperRight,0.0f}, - {LipSuckLowerLeft,0.0f}, - { LipSuckUpperLeft,0.0f}, - {LipSuckLowerRight ,0.0f}, - { LipSuckUpperRight,0.0f}, - {CheekPuffLeft ,0.0f}, - { CheekPuffRight,0.0f}, - {CheekSuckLeft ,0.0f}, - { CheekSuckRight,0.0f}, - { CheekSquintLeft,0.0f}, - {CheekSquintRight ,0.0f}, - { NoseSneerLeft,0.0f}, - {NoseSneerRight ,0.0f}, - - {TongueCurlUp ,0.0f}, - {TongueOut ,0.0f}, - + public static readonly Dictionary UeData = new() + { + { EyeWideLeft, 0.0f }, + { EyeWideRight, 0.0f }, + { EyeSquintLeft, 0.0f }, + { EyeSquintRight, 0.0f }, + { BrowInnerUpLeft, 0.0f }, + { BrowInnerUpRight, 0.0f }, + { BrowOuterUpLeft, 0.0f }, + { BrowOuterUpRight, 0.0f }, + { BrowPinchLeft, 0.0f }, + { BrowLowererLeft, 0.0f }, + { BrowLowererRight, 0.0f }, + { BrowPinchRight, 0.0f }, + + { JawOpen, 0.0f }, + { JawLeft, 0.0f }, + { JawRight, 0.0f }, + { JawForward, 0.0f }, + { MouthLowerLeft, 0.0f }, + { MouthUpperLeft, 0.0f }, + { MouthLowerRight, 0.0f }, + { MouthUpperRight, 0.0f }, + { MouthRaiserUpper, 0.0f }, + { MouthRaiserLower, 0.0f }, + + { MouthDimpleLeft, 0.0f }, + { MouthDimpleRight, 0.0f }, + { MouthClosed, 0.0f }, + { MouthCornerPullLeft, 0.0f }, + { MouthCornerSlantLeft, 0.0f }, + { MouthCornerPullRight, 0.0f }, + { MouthCornerSlantRight, 0.0f }, + + { MouthFrownLeft, 0.0f }, + { MouthFrownRight, 0.0f }, + { MouthLowerDownLeft, 0.0f }, + { MouthLowerDownRight, 0.0f }, + { MouthUpperUpLeft, 0.0f }, //TODO CHECK + { MouthUpperUpRight, 0.0f }, //TODO CHECK + { MouthTightenerLeft, 0.0f }, + { MouthTightenerRight, 0.0f }, + { MouthPressLeft, 0.0f }, + { MouthPressRight, 0.0f }, + { MouthStretchLeft, 0.0f }, + { MouthStretchRight, 0.0f }, + { LipPuckerLowerLeft, 0.0f }, + { LipPuckerUpperLeft, 0.0f }, + { LipPuckerLowerRight, 0.0f }, + { LipPuckerUpperRight, 0.0f }, + { LipFunnelLowerLeft, 0.0f }, + { LipFunnelUpperLeft, 0.0f }, + { LipFunnelLowerRight, 0.0f }, + { LipFunnelUpperRight, 0.0f }, + { LipSuckLowerLeft, 0.0f }, + { LipSuckUpperLeft, 0.0f }, + { LipSuckLowerRight, 0.0f }, + { LipSuckUpperRight, 0.0f }, + { CheekPuffLeft, 0.0f }, + { CheekPuffRight, 0.0f }, + { CheekSuckLeft, 0.0f }, + { CheekSuckRight, 0.0f }, + { CheekSquintLeft, 0.0f }, + { CheekSquintRight, 0.0f }, + { NoseSneerLeft, 0.0f }, + { NoseSneerRight, 0.0f }, + + { TongueCurlUp, 0.0f }, + { TongueOut, 0.0f }, }; //based on https://docs.google.com/spreadsheets/d/118jo960co3Mgw8eREFVBsaJ7z0GtKNr52IB4Bz99VTA/edit#gid=0 - private static readonly - Dictionary> MapOscDirectXrfbUnifiedExpressions = new Dictionary> - { - {"/sl/xrfb/facew/UpperLidRaiserL", new List{EyeWideLeft}}, - {"/sl/xrfb/facew/UpperLidRaiserR", new List{EyeWideRight}}, - {"/sl/xrfb/facew/LidTightenerL", new List{EyeSquintLeft}}, - {"/sl/xrfb/facew/LidTightenerR", new List{EyeSquintRight}}, - {"/sl/xrfb/facew/InnerBrowRaiserL", new List{BrowInnerUpLeft}}, - {"/sl/xrfb/facew/InnerBrowRaiserR", new List{BrowInnerUpRight}}, - {"/sl/xrfb/facew/OuterBrowRaiserL", new List{BrowOuterUpLeft}}, - {"/sl/xrfb/facew/OuterBrowRaiserR", new List{BrowOuterUpRight}}, - {"/sl/xrfb/facew/BrowLowererL", new List{BrowPinchLeft, BrowLowererLeft}}, - {"/sl/xrfb/facew/BrowLowererR", new List{BrowPinchRight, BrowLowererRight}}, - - {"/sl/xrfb/facew/JawDrop", new List{JawOpen}}, - {"/sl/xrfb/facew/JawSidewaysLeft", new List{JawLeft}}, - {"/sl/xrfb/facew/JawSidewaysRight", new List{JawRight}}, - {"/sl/xrfb/facew/JawThrust", new List{JawForward}}, - - {"/sl/xrfb/facew/MouthLeft", new List{MouthLowerLeft, MouthUpperLeft}}, - {"/sl/xrfb/facew/MouthRight", new List{MouthLowerRight, MouthUpperRight}}, - - {"/sl/xrfb/facew/ChinRaiserT", new List{MouthRaiserUpper} }, - {"/sl/xrfb/facew/ChinRaiserB", new List{MouthRaiserLower} }, - - {"/sl/xrfb/facew/DimplerL", new List{MouthDimpleLeft} }, - {"/sl/xrfb/facew/DimplerR", new List{MouthDimpleRight} }, - - {"/sl/xrfb/facew/LipsToward", new List{MouthClosed}}, - {"/sl/xrfb/facew/LipCornerPullerL", new List{ MouthCornerPullLeft, MouthCornerSlantLeft} }, - {"/sl/xrfb/facew/LipCornerPullerR", new List{ MouthCornerPullRight, MouthCornerSlantRight} }, - {"/sl/xrfb/facew/LipCornerDepressorL", new List{ MouthFrownLeft} }, - {"/sl/xrfb/facew/LipCornerDepressorR", new List{ MouthFrownRight} }, - {"/sl/xrfb/facew/LowerLipDepressorL", new List{ MouthLowerDownLeft} }, - {"/sl/xrfb/facew/LowerLipDepressorR", new List{ MouthLowerDownRight} }, - {"/sl/xrfb/facew/UpperLipRaiserL", new List{ MouthUpperUpLeft} }, //something odd here - {"/sl/xrfb/facew/UpperLipRaiserR", new List{ MouthUpperUpRight } }, //something odd here - {"/sl/xrfb/facew/LipTightenerL", new List{MouthTightenerLeft} }, - {"/sl/xrfb/facew/LipTightenerR", new List{MouthTightenerRight} }, - {"/sl/xrfb/facew/LipPressorL", new List{MouthPressLeft} }, - {"/sl/xrfb/facew/LipPressorR", new List{MouthPressRight} }, - {"/sl/xrfb/facew/LipStretcherL", new List{MouthStretchLeft} }, - {"/sl/xrfb/facew/LipStretcherR", new List{MouthStretchRight} }, - {"/sl/xrfb/facew/LipPuckerL", new List{ LipPuckerLowerLeft, LipPuckerUpperLeft } }, - {"/sl/xrfb/facew/LipPuckerR", new List{ LipPuckerLowerRight, LipPuckerUpperRight } }, - {"/sl/xrfb/facew/LipFunnelerLB", new List{LipFunnelLowerLeft} }, - {"/sl/xrfb/facew/LipFunnelerLT", new List{LipFunnelUpperLeft} }, - {"/sl/xrfb/facew/LipFunnelerRB", new List{LipFunnelLowerRight} }, - {"/sl/xrfb/facew/LipFunnelerRT", new List{LipFunnelUpperRight} }, - {"/sl/xrfb/facew/LipSuckLB", new List{LipSuckLowerLeft} }, - {"/sl/xrfb/facew/LipSuckLT", new List{LipSuckUpperLeft} }, - {"/sl/xrfb/facew/LipSuckRB", new List{LipSuckLowerRight} }, - {"/sl/xrfb/facew/LipSuckRT", new List{LipSuckUpperRight} }, - - {"/sl/xrfb/facew/CheekPuffL", new List{CheekPuffLeft} }, - {"/sl/xrfb/facew/CheekPuffR", new List{CheekPuffRight} }, - {"/sl/xrfb/facew/CheekSuckL", new List{CheekSuckLeft} }, - {"/sl/xrfb/facew/CheekSuckR", new List{CheekSuckRight} }, - {"/sl/xrfb/facew/CheekRaiserL", new List{CheekSquintLeft} }, - {"/sl/xrfb/facew/CheekRaiserR", new List{CheekSquintRight} }, - - {"/sl/xrfb/facew/NoseWrinklerL", new List{NoseSneerLeft} }, - {"/sl/xrfb/facew/NoseWrinklerR", new List{NoseSneerRight} }, - - //Tongue Tracking Params - //Some params sent but not part of UE or used? need to look into - //{"/sl/xrfb/facew/TongueTipInterdental", new List{} }, - //{"/sl/xrfb/facew/FrontDorsalPalate", new List{} }, - //{"/sl/xrfb/facew/MidDorsalPalate", new List{} }, - //{"/sl/xrfb/facew/BackDorsalVelar", new List{} }, - //{"/sl/xrfb/facew/TongueRetreat", new List{} }, - //{"/sl/xrfb/facew/TongueTipAlveolar", new List{TongueCurlUp} }, - {"/sl/xrfb/facew/TongueOut", new List{TongueOut} }, - }; - + private static readonly + Dictionary> MapOscDirectXrfbUnifiedExpressions = + new Dictionary> + { + { "/sl/xrfb/facew/UpperLidRaiserL", new List { EyeWideLeft } }, + { "/sl/xrfb/facew/UpperLidRaiserR", new List { EyeWideRight } }, + { "/sl/xrfb/facew/LidTightenerL", new List { EyeSquintLeft } }, + { "/sl/xrfb/facew/LidTightenerR", new List { EyeSquintRight } }, + { "/sl/xrfb/facew/InnerBrowRaiserL", new List { BrowInnerUpLeft } }, + { "/sl/xrfb/facew/InnerBrowRaiserR", new List { BrowInnerUpRight } }, + { "/sl/xrfb/facew/OuterBrowRaiserL", new List { BrowOuterUpLeft } }, + { "/sl/xrfb/facew/OuterBrowRaiserR", new List { BrowOuterUpRight } }, + { "/sl/xrfb/facew/BrowLowererL", new List { BrowPinchLeft, BrowLowererLeft } }, + { "/sl/xrfb/facew/BrowLowererR", new List { BrowPinchRight, BrowLowererRight } }, + + { "/sl/xrfb/facew/JawDrop", new List { JawOpen } }, + { "/sl/xrfb/facew/JawSidewaysLeft", new List { JawLeft } }, + { "/sl/xrfb/facew/JawSidewaysRight", new List { JawRight } }, + { "/sl/xrfb/facew/JawThrust", new List { JawForward } }, + + { "/sl/xrfb/facew/MouthLeft", new List { MouthLowerLeft, MouthUpperLeft } }, + { "/sl/xrfb/facew/MouthRight", new List { MouthLowerRight, MouthUpperRight } }, + + { "/sl/xrfb/facew/ChinRaiserT", new List { MouthRaiserUpper } }, + { "/sl/xrfb/facew/ChinRaiserB", new List { MouthRaiserLower } }, + + { "/sl/xrfb/facew/DimplerL", new List { MouthDimpleLeft } }, + { "/sl/xrfb/facew/DimplerR", new List { MouthDimpleRight } }, + + { "/sl/xrfb/facew/LipsToward", new List { MouthClosed } }, + { + "/sl/xrfb/facew/LipCornerPullerL", + new List { MouthCornerPullLeft, MouthCornerSlantLeft } + }, + { + "/sl/xrfb/facew/LipCornerPullerR", + new List { MouthCornerPullRight, MouthCornerSlantRight } + }, + { "/sl/xrfb/facew/LipCornerDepressorL", new List { MouthFrownLeft } }, + { "/sl/xrfb/facew/LipCornerDepressorR", new List { MouthFrownRight } }, + { "/sl/xrfb/facew/LowerLipDepressorL", new List { MouthLowerDownLeft } }, + { "/sl/xrfb/facew/LowerLipDepressorR", new List { MouthLowerDownRight } }, + { + "/sl/xrfb/facew/UpperLipRaiserL", new List { MouthUpperUpLeft } + }, //something odd here + { + "/sl/xrfb/facew/UpperLipRaiserR", new List { MouthUpperUpRight } + }, //something odd here + { "/sl/xrfb/facew/LipTightenerL", new List { MouthTightenerLeft } }, + { "/sl/xrfb/facew/LipTightenerR", new List { MouthTightenerRight } }, + { "/sl/xrfb/facew/LipPressorL", new List { MouthPressLeft } }, + { "/sl/xrfb/facew/LipPressorR", new List { MouthPressRight } }, + { "/sl/xrfb/facew/LipStretcherL", new List { MouthStretchLeft } }, + { "/sl/xrfb/facew/LipStretcherR", new List { MouthStretchRight } }, + { + "/sl/xrfb/facew/LipPuckerL", new List { LipPuckerLowerLeft, LipPuckerUpperLeft } + }, + { + "/sl/xrfb/facew/LipPuckerR", + new List { LipPuckerLowerRight, LipPuckerUpperRight } + }, + { "/sl/xrfb/facew/LipFunnelerLB", new List { LipFunnelLowerLeft } }, + { "/sl/xrfb/facew/LipFunnelerLT", new List { LipFunnelUpperLeft } }, + { "/sl/xrfb/facew/LipFunnelerRB", new List { LipFunnelLowerRight } }, + { "/sl/xrfb/facew/LipFunnelerRT", new List { LipFunnelUpperRight } }, + { "/sl/xrfb/facew/LipSuckLB", new List { LipSuckLowerLeft } }, + { "/sl/xrfb/facew/LipSuckLT", new List { LipSuckUpperLeft } }, + { "/sl/xrfb/facew/LipSuckRB", new List { LipSuckLowerRight } }, + { "/sl/xrfb/facew/LipSuckRT", new List { LipSuckUpperRight } }, + + { "/sl/xrfb/facew/CheekPuffL", new List { CheekPuffLeft } }, + { "/sl/xrfb/facew/CheekPuffR", new List { CheekPuffRight } }, + { "/sl/xrfb/facew/CheekSuckL", new List { CheekSuckLeft } }, + { "/sl/xrfb/facew/CheekSuckR", new List { CheekSuckRight } }, + { "/sl/xrfb/facew/CheekRaiserL", new List { CheekSquintLeft } }, + { "/sl/xrfb/facew/CheekRaiserR", new List { CheekSquintRight } }, + + { "/sl/xrfb/facew/NoseWrinklerL", new List { NoseSneerLeft } }, + { "/sl/xrfb/facew/NoseWrinklerR", new List { NoseSneerRight } }, + + //Tongue Tracking Params + //Some params sent but not part of UE or used? need to look into + //{"/sl/xrfb/facew/TongueTipInterdental", new List{} }, + //{"/sl/xrfb/facew/FrontDorsalPalate", new List{} }, + //{"/sl/xrfb/facew/MidDorsalPalate", new List{} }, + //{"/sl/xrfb/facew/BackDorsalVelar", new List{} }, + //{"/sl/xrfb/facew/TongueRetreat", new List{} }, + //{"/sl/xrfb/facew/TongueTipAlveolar", new List{TongueCurlUp} }, + { "/sl/xrfb/facew/TongueOut", new List { TongueOut } }, + }; private Socket _receiver; @@ -201,9 +216,6 @@ private void ListenLoop() { if (_receiver.IsBound) { - - - var length = _receiver.Receive(buffer); var msgList = new List(); if (OscParser.IsBundle(ref buffer)) @@ -216,7 +228,10 @@ private void ListenLoop() if (BitConverter.IsLittleEndian) { var msgsize = new byte[4]; - msgsize[0] = buffer[i]; msgsize[1] = buffer[i + 1]; msgsize[2] = buffer[i + 2]; msgsize[3] = buffer[i + 3]; + msgsize[0] = buffer[i]; + msgsize[1] = buffer[i + 1]; + msgsize[2] = buffer[i + 2]; + msgsize[3] = buffer[i + 3]; Array.Reverse(msgsize); messageLength = BitConverter.ToInt32(msgsize, 0); } @@ -224,18 +239,19 @@ private void ListenLoop() { messageLength = BitConverter.ToInt32(buffer, i); } + var adjustLength = 4 - messageLength % 4; var temp = new byte[messageLength]; Array.Copy(buffer, i + 4, temp, 0, messageLength); msgList.Add(new Oscm(ref temp, _logger)); i = i + messageLength + adjustLength; - } } else { msgList.Add(new Oscm(ref buffer, _logger)); } + foreach (var oscMessage in msgList) { if (oscMessage == null) continue; @@ -246,14 +262,16 @@ private void ListenLoop() { EyeTrackData[i] = (float)oscMessage.Values[i]; } + continue; } + if (oscMessage.Address == ("/sl/xrfb/facew/EyesClosedL")) { Eyelids[0] = (float)oscMessage.Values[0]; continue; - } + if (oscMessage.Address == "/sl/xrfb/facew/EyesClosedR") { Eyelids[1] = (float)oscMessage.Values[0]; @@ -265,7 +283,8 @@ private void ListenLoop() foreach (var unifiedExpression in MapOscDirectXrfbUnifiedExpressions[oscMessage.Address]) { //This may not be strictly safe but should be good enough for our use case - UeData[unifiedExpression] = (float)oscMessage.Values[0]; } + UeData[unifiedExpression] = (float)oscMessage.Values[0]; + } } } } @@ -278,7 +297,8 @@ private void ListenLoop() _receiver.ReceiveTimeout = TimeoutMs; } } - catch (Exception e) { + catch (Exception e) + { _logger.LogInformation("Exception {0}", e.Message); } } @@ -291,5 +311,4 @@ public void Teardown() _receiver.Dispose(); _thread.Join(); } - } \ No newline at end of file diff --git a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCParser.cs b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCParser.cs index 2219f45..4de923a 100644 --- a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCParser.cs +++ b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCParser.cs @@ -7,11 +7,12 @@ namespace SteamLinkVRCFTModule; public class Oscm { public string Address = ""; + public ArrayList Values = new ArrayList(); + //int = 0, float = 1, blob = 2, string = 3, error = -1 private List _valType = new List(); - public int GetAddress(ref byte[] msg, int index) { while (index < msg.Length) @@ -22,10 +23,11 @@ public int GetAddress(ref byte[] msg, int index) index++; return index; } + //This is sloppy, But need to verify if OSC spec is one null char on address or if it's up to 4? if (msg[index] == 0x00) { - if(Address == "") + if (Address == "") { Address = Encoding.ASCII.GetString(msg, 0, index); } @@ -33,6 +35,7 @@ public int GetAddress(ref byte[] msg, int index) index++; } + return -1; } @@ -41,14 +44,14 @@ public int GetParams(ref byte[] msg, int index, ILogger log) var valmax = 0; //we start at the parameter not the "," in an osc string, and then we need // an additional to account for offset - var typetagstart = index-1; + var typetagstart = index - 1; while (index < msg.Length) { switch (msg[index]) { //null i.e. end of params case 0x00: - return (4 - ((index - typetagstart) % 4 )+ index); + return (4 - ((index - typetagstart) % 4) + index); //float case 0x66: _valType.Add(1); @@ -73,10 +76,13 @@ public int GetParams(ref byte[] msg, int index, ILogger log) _valType.Add(-1); break; } + index++; } + return -1; } + public int GetValues(ref byte[] message, int i, ILogger log) { var valuecount = 0; @@ -89,7 +95,10 @@ public int GetValues(ref byte[] message, int i, ILogger log) case 0: if (BitConverter.IsLittleEndian) { - msgsize[0] = message[i]; msgsize[1] = message[i + 1]; msgsize[2] = message[i + 2]; msgsize[3] = message[i + 3]; + msgsize[0] = message[i]; + msgsize[1] = message[i + 1]; + msgsize[2] = message[i + 2]; + msgsize[3] = message[i + 3]; Array.Reverse(msgsize); Values.Add(BitConverter.ToInt32(msgsize, 0)); } @@ -97,6 +106,7 @@ public int GetValues(ref byte[] message, int i, ILogger log) { Values.Add(BitConverter.ToInt32(message, i)); } + i = i + 3; valuecount++; @@ -104,7 +114,10 @@ public int GetValues(ref byte[] message, int i, ILogger log) case 1: if (BitConverter.IsLittleEndian) { - msgsize[0] = message[i]; msgsize[1] = message[i + 1]; msgsize[2] = message[i + 2]; msgsize[3] = message[i + 3]; + msgsize[0] = message[i]; + msgsize[1] = message[i + 1]; + msgsize[2] = message[i + 2]; + msgsize[3] = message[i + 3]; Array.Reverse(msgsize); Values.Add(BitConverter.ToSingle(msgsize, 0)); } @@ -112,6 +125,7 @@ public int GetValues(ref byte[] message, int i, ILogger log) { Values.Add(BitConverter.ToSingle(message, i)); } + i = i + 3; valuecount++; @@ -126,6 +140,7 @@ public int GetValues(ref byte[] message, int i, ILogger log) { i++; } + Values.Add(Encoding.ASCII.GetString(message, initialI, i)); valuecount++; //OSC padding to 32 bit chunks (4 byte) @@ -137,15 +152,16 @@ public int GetValues(ref byte[] message, int i, ILogger log) log.LogInformation("error default XXXXXXXX"); //TODO error handling break; - - } + if (valuecount == maxVal) { return message.Length; } + i++; } + return -1; } @@ -158,12 +174,14 @@ public Oscm(ref byte[] message, ILogger iLogger) iLogger.LogInformation("fail at addr"); return; } + i = GetParams(ref message, i, iLogger); if (i == -1) { iLogger.LogInformation("fail at param"); return; } + i = GetValues(ref message, i, iLogger); if (i == -1) { @@ -171,32 +189,34 @@ public Oscm(ref byte[] message, ILogger iLogger) return; } } - } static public class OscParser { static readonly byte[] BufAscii = Encoding.ASCII.GetBytes("#bundle"); + public static bool IsBundle(ref byte[] buff) { - if(buff == null|| buff.Length<8) + if (buff == null || buff.Length < 8) { return false; } + var bundletest = new byte[7]; Array.Copy(buff, bundletest, 7); return Enumerable.SequenceEqual(bundletest, BufAscii); } + public static uint SwapEndianness(uint x) { - return ((x & 0x000000ff) << 24) + // First byte - ((x & 0x0000ff00) << 8) + // Second byte - ((x & 0x00ff0000) >> 8) + // Third byte - ((x & 0xff000000) >> 24); // Fourth byte + return ((x & 0x000000ff) << 24) + // First byte + ((x & 0x0000ff00) << 8) + // Second byte + ((x & 0x00ff0000) >> 8) + // Third byte + ((x & 0xff000000) >> 24); // Fourth byte } + public static int TrueMod(int a, int b) { return (Math.Abs(a * b) + a) % b; } - } \ No newline at end of file diff --git a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/SteamLinkVRCFTModule.cs b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/SteamLinkVRCFTModule.cs index 93253d5..1725182 100644 --- a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/SteamLinkVRCFTModule.cs +++ b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/SteamLinkVRCFTModule.cs @@ -15,7 +15,8 @@ public override (bool eyeSuccess, bool expressionSuccess) Initialize(bool eyeAva { ModuleInformation.Name = "SteamLink Module"; - var stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("SteamLinkVRCFTModule.Assets.steamlink.png"); + var stream = System.Reflection.Assembly.GetExecutingAssembly() + .GetManifestResourceStream("SteamLinkVRCFTModule.Assets.steamlink.png"); ModuleInformation.StaticImages = stream != null ? new List { stream } : ModuleInformation.StaticImages; //TODO better error handling on fail? isInit for OSC Handler? @@ -42,6 +43,7 @@ private void UpdateEyeTracking() { fNmAngleX = 0.0f; } + if (float.IsNaN(fNmAngleY)) { fNmAngleY = 0.0f; @@ -59,18 +61,19 @@ private void UpdateEyeTracking() UnifiedTracking.Data.Eye.Right.PupilDiameter_MM = 5f; UnifiedTracking.Data.Eye._maxDilation = 10; UnifiedTracking.Data.Eye._minDilation = 0; - } { - var fLeftOpenness = CalculateEyeOpenness(_oscHandler.Eyelids[0], OscHandler.UeData[UnifiedExpressions.EyeSquintLeft]); - var fRightOpenness = CalculateEyeOpenness(_oscHandler.Eyelids[1], OscHandler.UeData[UnifiedExpressions.EyeSquintRight]); + var fLeftOpenness = CalculateEyeOpenness(_oscHandler.Eyelids[0], + OscHandler.UeData[UnifiedExpressions.EyeSquintLeft]); + var fRightOpenness = CalculateEyeOpenness(_oscHandler.Eyelids[1], + OscHandler.UeData[UnifiedExpressions.EyeSquintRight]); - UnifiedTracking.Data.Eye.Left.Openness = fLeftOpenness;// fLeftOpenness; - UnifiedTracking.Data.Eye.Right.Openness = fRightOpenness;//fRightOpenness; + UnifiedTracking.Data.Eye.Left.Openness = fLeftOpenness; // fLeftOpenness; + UnifiedTracking.Data.Eye.Right.Openness = fRightOpenness; // fRightOpenness; } - } + private void UpdateFaceTracking() { foreach (var entry in OscHandler.UeData) @@ -84,8 +87,12 @@ private void UpdateFaceTracking() //UnifiedTracking.Data.Shapes[(int)MouthUpperDeepenRight].Weight = Math.Max(0, UnifiedTracking.Data.Shapes[(int)MouthUpperUpRight].Weight - UnifiedTracking.Data.Shapes[(int)NoseSneerRight].Weight); //lip Suck - UnifiedTracking.Data.Shapes[(int)LipSuckUpperLeft].Weight = Math.Min(1.0f - (float)Math.Pow(UnifiedTracking.Data.Shapes[(int)MouthUpperLeft].Weight, 1f / 6f), UnifiedTracking.Data.Shapes[(int)LipSuckUpperLeft].Weight); - UnifiedTracking.Data.Shapes[(int)LipSuckUpperRight].Weight = Math.Min(1.0f - (float)Math.Pow(UnifiedTracking.Data.Shapes[(int)MouthUpperRight].Weight, 1f / 6f), UnifiedTracking.Data.Shapes[(int)LipSuckUpperRight].Weight); + UnifiedTracking.Data.Shapes[(int)LipSuckUpperLeft].Weight = Math.Min( + 1.0f - (float)Math.Pow(UnifiedTracking.Data.Shapes[(int)MouthUpperLeft].Weight, 1f / 6f), + UnifiedTracking.Data.Shapes[(int)LipSuckUpperLeft].Weight); + UnifiedTracking.Data.Shapes[(int)LipSuckUpperRight].Weight = Math.Min( + 1.0f - (float)Math.Pow(UnifiedTracking.Data.Shapes[(int)MouthUpperRight].Weight, 1f / 6f), + UnifiedTracking.Data.Shapes[(int)LipSuckUpperRight].Weight); } public override void Update() @@ -94,6 +101,7 @@ public override void Update() UpdateEyeTracking(); UpdateFaceTracking(); } + public override void Teardown() { _oscHandler.Teardown(); From 4288266eb08dae384eb2e5f5515edf20ca017560 Mon Sep 17 00:00:00 2001 From: dfgHiatus <51272212+dfgHiatus@users.noreply.github.com> Date: Sun, 18 Jan 2026 13:26:05 -0500 Subject: [PATCH 6/6] Remove redundant qualifiers, fix one typo --- .../SteamLinkVRCFTModule/OSCHandler.cs | 6 +++--- .../SteamLinkVRCFTModule/OSCParser.cs | 14 +++++++------- .../SteamLinkVRCFTModule/SteamLinkVRCFTModule.cs | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCHandler.cs b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCHandler.cs index dc15485..01c667d 100644 --- a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCHandler.cs +++ b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCHandler.cs @@ -87,7 +87,7 @@ public class OscHandler //based on https://docs.google.com/spreadsheets/d/118jo960co3Mgw8eREFVBsaJ7z0GtKNr52IB4Bz99VTA/edit#gid=0 private static readonly Dictionary> MapOscDirectXrfbUnifiedExpressions = - new Dictionary> + new() { { "/sl/xrfb/facew/UpperLidRaiserL", new List { EyeWideLeft } }, { "/sl/xrfb/facew/UpperLidRaiserR", new List { EyeWideRight } }, @@ -200,9 +200,9 @@ public OscHandler(ILogger iLogger, int? port = null) _receiver.ReceiveTimeout = TimeoutMs; _loop = true; - _thread = new Thread(new ThreadStart(ListenLoop)); + _thread = new Thread(ListenLoop); _thread.Start(); - // 1 second delay to hopefully fix any race conditions on thread initalization + // 1 second delay to hopefully fix any race conditions on thread initialization //TODO remove this and actually fix the issue Thread.Sleep(1000); } diff --git a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCParser.cs b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCParser.cs index 4de923a..37beb7b 100644 --- a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCParser.cs +++ b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/OSCParser.cs @@ -8,12 +8,12 @@ public class Oscm { public string Address = ""; - public ArrayList Values = new ArrayList(); + public readonly ArrayList Values = new(); //int = 0, float = 1, blob = 2, string = 3, error = -1 - private List _valType = new List(); + private readonly List _valType = new(); - public int GetAddress(ref byte[] msg, int index) + private int GetAddress(ref byte[] msg, int index) { while (index < msg.Length) { @@ -83,7 +83,7 @@ public int GetParams(ref byte[] msg, int index, ILogger log) return -1; } - public int GetValues(ref byte[] message, int i, ILogger log) + private int GetValues(ref byte[] message, int i, ILogger log) { var valuecount = 0; var maxVal = _valType.Count(); @@ -191,9 +191,9 @@ public Oscm(ref byte[] message, ILogger iLogger) } } -static public class OscParser +public static class OscParser { - static readonly byte[] BufAscii = Encoding.ASCII.GetBytes("#bundle"); + private static readonly byte[] BufAscii = "#bundle"u8.ToArray(); public static bool IsBundle(ref byte[] buff) { @@ -204,7 +204,7 @@ public static bool IsBundle(ref byte[] buff) var bundletest = new byte[7]; Array.Copy(buff, bundletest, 7); - return Enumerable.SequenceEqual(bundletest, BufAscii); + return bundletest.SequenceEqual(BufAscii); } public static uint SwapEndianness(uint x) diff --git a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/SteamLinkVRCFTModule.cs b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/SteamLinkVRCFTModule.cs index 1725182..74aea6d 100644 --- a/SteamLinkVRCFTModule/SteamLinkVRCFTModule/SteamLinkVRCFTModule.cs +++ b/SteamLinkVRCFTModule/SteamLinkVRCFTModule/SteamLinkVRCFTModule.cs @@ -65,9 +65,9 @@ private void UpdateEyeTracking() { var fLeftOpenness = CalculateEyeOpenness(_oscHandler.Eyelids[0], - OscHandler.UeData[UnifiedExpressions.EyeSquintLeft]); + OscHandler.UeData[EyeSquintLeft]); var fRightOpenness = CalculateEyeOpenness(_oscHandler.Eyelids[1], - OscHandler.UeData[UnifiedExpressions.EyeSquintRight]); + OscHandler.UeData[EyeSquintRight]); UnifiedTracking.Data.Eye.Left.Openness = fLeftOpenness; // fLeftOpenness; UnifiedTracking.Data.Eye.Right.Openness = fRightOpenness; // fRightOpenness;