diff --git a/BabbleExpressions.cs b/BabbleExpressions.cs index c5cc2f4..c1712d2 100644 --- a/BabbleExpressions.cs +++ b/BabbleExpressions.cs @@ -1,52 +1,86 @@ -namespace VRCFaceTracking.Babble; -public partial class BabbleOSC +using Newtonsoft.Json; +using System.Reflection; +using VRCFaceTracking.Core.Params.Expressions; +using VRCFaceTracking.Babble.Collections; + +namespace VRCFaceTracking.Babble; +public static class BabbleExpressions { - public Dictionary BabbleExpressionMap = new() + private const string BabbleExpressionsPath = "BabbleExpressions.json"; + + public static readonly TwoKeyDictionary BabbleExpressionMap; + static BabbleExpressions() { - { "/cheekPuffLeft", 0f }, - { "/cheekPuffRight", 0f }, - { "/cheekSuckLeft", 0f }, - { "/cheekSuckRight", 0f }, - { "/jawOpen", 0f }, - { "/jawForward", 0f }, - { "/jawLeft", 0f }, - { "/jawRight", 0f }, - { "/noseSneerLeft", 0f }, - { "/noseSnerrRight", 0f }, - { "/mouthFunnel", 0f }, - { "/mouthPucker", 0f }, - { "/mouthLeft", 0f }, - { "/mouthRight", 0f }, - { "/mouthRollUpper", 0f }, - { "/mouthRollLower", 0f }, - { "/mouthShrugUpper", 0f }, - { "/mouthShrugLower", 0f }, - { "/mouthClose", 0f }, - { "/mouthSmileLeft", 0f }, - { "/mouthSmileRight", 0f }, - { "/mouthFrownLeft", 0f }, - { "/mouthFrownRight", 0f }, - { "/mouthDimpleLeft", 0f }, - { "/mouthDimpleRight", 0f }, - { "/mouthUpperUpLeft", 0f }, - { "/mouthUpperUpRight", 0f }, - { "/mouthLowerDownLeft", 0f }, - { "/mouthLowerDownRight", 0f }, - { "/mouthPressLeft", 0f }, - { "/mouthPressRight", 0f }, - { "/mouthStretchLeft", 0f }, - { "/mouthStretchRight", 0f }, - { "/tongueOut", 0f }, - { "/tongueUp", 0f }, - { "/tongueDown", 0f }, - { "/tongueLeft", 0f }, - { "/tongueRight", 0f }, - { "/tongueRoll", 0f }, - { "/tongueBendDown", 0f }, - { "/tongueCurlUp", 0f }, - { "/tongueSquish", 0f }, - { "/tongueFlat", 0f }, - { "/tongueTwistLeft", 0f }, - { "/tognueTwistRight", 0f } + var expressions = Path.Combine( + Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, + BabbleExpressionsPath); + var converter = new TwoKeyDictionaryConverter(); + if (!File.Exists(expressions)) + { + string json = JsonConvert.SerializeObject( + DefaultBabbleExpressionMap, converter); + File.WriteAllText(expressions, json); + } + + BabbleExpressionMap = JsonConvert.DeserializeObject + > + (File.ReadAllText(expressions), converter)!; + } + + private static readonly TwoKeyDictionary DefaultBabbleExpressionMap = new() + { + { UnifiedExpressions.CheekPuffLeft, "/cheekPuffLeft", 0f }, + { UnifiedExpressions.CheekPuffRight, "/cheekPuffRight", 0f }, + { UnifiedExpressions.CheekSuckLeft, "/cheekSuckLeft", 0f }, + { UnifiedExpressions.CheekSuckRight, "/cheekSuckRight", 0f }, + { UnifiedExpressions.JawOpen, "/jawOpen", 0f }, + { UnifiedExpressions.JawForward, "/jawForward", 0f }, + { UnifiedExpressions.JawLeft, "/jawLeft", 0f }, + { UnifiedExpressions.JawRight, "/jawRight", 0f }, + { UnifiedExpressions.NoseSneerLeft, "/noseSneerLeft", 0f }, + { UnifiedExpressions.NoseSneerRight, "/noseSneerRight", 0f }, + { UnifiedExpressions.LipFunnelLowerLeft, "/mouthFunnel", 0f }, + { UnifiedExpressions.LipFunnelLowerRight, "/mouthFunnel", 0f }, + { UnifiedExpressions.LipFunnelUpperLeft, "/mouthFunnel", 0f }, + { UnifiedExpressions.LipFunnelUpperRight, "/mouthFunnel", 0f }, + { UnifiedExpressions.LipPuckerLowerLeft, "/mouthPucker", 0f }, + { UnifiedExpressions.LipPuckerLowerRight, "/mouthPucker", 0f }, + { UnifiedExpressions.LipPuckerUpperLeft, "/mouthPucker", 0f }, + { UnifiedExpressions.LipPuckerUpperRight, "/mouthPucker", 0f }, + { UnifiedExpressions.MouthPressLeft, "/mouthLeft", 0f }, + { UnifiedExpressions.MouthPressRight, "/mouthRight", 0f }, + { UnifiedExpressions.LipSuckUpperLeft, "/mouthRollUpper", 0f }, + { UnifiedExpressions.LipSuckUpperRight, "/mouthRollUpper", 0f }, + { UnifiedExpressions.LipSuckLowerLeft, "/mouthRollLower", 0f }, + { UnifiedExpressions.LipSuckLowerRight, "/mouthRollLower", 0f }, + { UnifiedExpressions.MouthRaiserUpper, "/mouthShrugUpper", 0f }, + { UnifiedExpressions.MouthRaiserLower, "/mouthShrugLower", 0f }, + { UnifiedExpressions.MouthClosed, "/mouthClose", 0f }, + { UnifiedExpressions.MouthCornerPullLeft, "/mouthSmileLeft", 0f }, + { UnifiedExpressions.MouthCornerPullRight, "/mouthSmileRight", 0f }, + { UnifiedExpressions.MouthFrownLeft, "/mouthFrownLeft", 0f }, + { UnifiedExpressions.MouthFrownRight, "/mouthFrownRight", 0f }, + { UnifiedExpressions.MouthDimpleLeft, "/mouthDimpleLeft", 0f }, + { UnifiedExpressions.MouthDimpleRight, "/mouthDimpleRight", 0f }, + { UnifiedExpressions.MouthUpperUpLeft, "/mouthUpperUpLeft", 0f }, + { UnifiedExpressions.MouthUpperUpRight, "/mouthUpperUpRight", 0f }, + { UnifiedExpressions.MouthLowerDownLeft, "/mouthLowerDownLeft", 0f }, + { UnifiedExpressions.MouthLowerDownRight, "/mouthLowerDownRight", 0f }, + { UnifiedExpressions.MouthPressLeft, "/mouthPressLeft", 0f }, + { UnifiedExpressions.MouthPressRight, "/mouthPressRight", 0f }, + { UnifiedExpressions.MouthStretchLeft, "/mouthStretchLeft", 0f }, + { UnifiedExpressions.MouthStretchRight, "/mouthStretchRight", 0f }, + { UnifiedExpressions.TongueOut, "/tongueOut", 0f }, + { UnifiedExpressions.TongueUp, "/tongueUp", 0f }, + { UnifiedExpressions.TongueDown, "/tongueDown", 0f }, + { UnifiedExpressions.TongueLeft, "/tongueLeft", 0f }, + { UnifiedExpressions.TongueRight, "/tongueRight", 0f }, + { UnifiedExpressions.TongueRoll, "/tongueRoll", 0f }, + { UnifiedExpressions.TongueBendDown, "/tongueBendDown", 0f }, + { UnifiedExpressions.TongueCurlUp, "/tongueCurlUp", 0f }, + { UnifiedExpressions.TongueSquish, "/tongueSquish", 0f }, + { UnifiedExpressions.TongueFlat, "/tongueFlat", 0f }, + { UnifiedExpressions.TongueTwistLeft, "/tongueTwistLeft", 0f }, + { UnifiedExpressions.TongueTwistRight, "/tongueTwistRight", 0 } }; } diff --git a/BabbleOSC.cs b/BabbleOSC.cs index 61da8b0..6395fcc 100644 --- a/BabbleOSC.cs +++ b/BabbleOSC.cs @@ -1,11 +1,10 @@ +using Microsoft.Extensions.Logging; using System.Net; using System.Net.Sockets; -using Microsoft.Extensions.Logging; -using Newtonsoft.Json.Linq; -using VRCFaceTracking.Core.OSC; namespace VRCFaceTracking.Babble; -public partial class BabbleOSC + +public class BabbleOSC { private Socket _receiver; private bool _loop = true; @@ -142,9 +141,9 @@ private void ListenLoop() var length = _receiver.Receive(buffer); Msg msg = ParseOSC(buffer, length); - if (msg.success && BabbleExpressionMap.ContainsKey(msg.address)) + if (msg.success && BabbleExpressions.BabbleExpressionMap.ContainsKey2(msg.address)) { - BabbleExpressionMap[msg.address] = msg.value; + BabbleExpressions.BabbleExpressionMap.SetByKey2(msg.address, msg.value); } } else diff --git a/BabbleVRC.cs b/BabbleVRC.cs index cc1433c..ee9c96c 100644 --- a/BabbleVRC.cs +++ b/BabbleVRC.cs @@ -1,4 +1,5 @@ using System.Reflection; +using VRCFaceTracking.Core.Params.Data; using VRCFaceTracking.Core.Params.Expressions; namespace VRCFaceTracking.Babble; @@ -16,7 +17,7 @@ public override (bool eyeSuccess, bool expressionSuccess) Initialize(bool eyeAva Assembly a = Assembly.GetExecutingAssembly(); var hmdStream = a.GetManifestResourceStream ("VRCFaceTracking.Babble.BabbleLogo.png"); - streams.Add(hmdStream); + streams.Add(hmdStream!); ModuleInformation = new ModuleMetadata() { Name = "Project Babble Face Tracking\nInference Model v2.0.0", @@ -29,44 +30,9 @@ public override (bool eyeSuccess, bool expressionSuccess) Initialize(bool eyeAva public override void Teardown() => babbleOSC.Teardown(); public override void Update() { - UnifiedTracking.Data.Shapes[(int)UnifiedExpressions.TongueOut].Weight = babbleOSC.BabbleExpressionMap["/tongueOut"]; - - UnifiedTracking.Data.Shapes[(int)UnifiedExpressions.JawOpen].Weight = babbleOSC.BabbleExpressionMap["/jawOpen"]; - UnifiedTracking.Data.Shapes[(int)UnifiedExpressions.JawLeft].Weight = -babbleOSC.BabbleExpressionMap["/jawLeft"]; - UnifiedTracking.Data.Shapes[(int)UnifiedExpressions.JawRight].Weight = -babbleOSC.BabbleExpressionMap["/jawRight"]; - UnifiedTracking.Data.Shapes[(int)UnifiedExpressions.JawForward].Weight = babbleOSC.BabbleExpressionMap["/jawForward"]; - - UnifiedTracking.Data.Shapes[(int)UnifiedExpressions.NoseSneerLeft].Weight = -babbleOSC.BabbleExpressionMap["/noseSneerLeft"]; - UnifiedTracking.Data.Shapes[(int)UnifiedExpressions.NoseSneerRight].Weight = -babbleOSC.BabbleExpressionMap["/noseSneerRight"]; - - UnifiedTracking.Data.Shapes[(int)UnifiedExpressions.LipPuckerLowerLeft].Weight = babbleOSC.BabbleExpressionMap["/mouthPucker"]; - UnifiedTracking.Data.Shapes[(int)UnifiedExpressions.LipPuckerLowerRight].Weight = babbleOSC.BabbleExpressionMap["/mouthPucker"]; - UnifiedTracking.Data.Shapes[(int)UnifiedExpressions.LipPuckerUpperLeft].Weight = babbleOSC.BabbleExpressionMap["/mouthPucker"]; - UnifiedTracking.Data.Shapes[(int)UnifiedExpressions.LipPuckerUpperRight].Weight = babbleOSC.BabbleExpressionMap["/mouthPucker"]; - - UnifiedTracking.Data.Shapes[(int)UnifiedExpressions.LipFunnelLowerLeft].Weight = babbleOSC.BabbleExpressionMap["/mouthFunnel"]; - UnifiedTracking.Data.Shapes[(int)UnifiedExpressions.LipFunnelLowerRight].Weight = babbleOSC.BabbleExpressionMap["/mouthFunnel"]; - UnifiedTracking.Data.Shapes[(int)UnifiedExpressions.LipFunnelUpperLeft].Weight = babbleOSC.BabbleExpressionMap["/mouthFunnel"]; - UnifiedTracking.Data.Shapes[(int)UnifiedExpressions.LipFunnelUpperRight].Weight = babbleOSC.BabbleExpressionMap["/mouthFunnel"]; - - UnifiedTracking.Data.Shapes[(int)UnifiedExpressions.MouthUpperUpLeft].Weight = -babbleOSC.BabbleExpressionMap["/mouthUpperUpLeft"]; - UnifiedTracking.Data.Shapes[(int)UnifiedExpressions.MouthUpperUpRight].Weight = -babbleOSC.BabbleExpressionMap["/mouthUpperUpRight"]; - UnifiedTracking.Data.Shapes[(int)UnifiedExpressions.MouthLowerDownLeft].Weight = -babbleOSC.BabbleExpressionMap["/mouthLowerDownLeft"]; - UnifiedTracking.Data.Shapes[(int)UnifiedExpressions.MouthLowerDownRight].Weight = -babbleOSC.BabbleExpressionMap["/mouthLowerDownRight"]; - - UnifiedTracking.Data.Shapes[(int)UnifiedExpressions.MouthPressLeft].Weight = -babbleOSC.BabbleExpressionMap["/mouthPressLeft"]; - UnifiedTracking.Data.Shapes[(int)UnifiedExpressions.MouthPressRight].Weight = -babbleOSC.BabbleExpressionMap["/mouthPressRight"]; - - UnifiedTracking.Data.Shapes[(int)UnifiedExpressions.MouthStretchLeft].Weight = -babbleOSC.BabbleExpressionMap["/mouthStretchLeft"]; - UnifiedTracking.Data.Shapes[(int)UnifiedExpressions.MouthStretchRight].Weight = -babbleOSC.BabbleExpressionMap["/mouthStretchRight"]; - UnifiedTracking.Data.Shapes[(int)UnifiedExpressions.MouthDimpleLeft].Weight = -babbleOSC.BabbleExpressionMap["/mouthDimpleLeft"]; - UnifiedTracking.Data.Shapes[(int)UnifiedExpressions.MouthDimpleRight].Weight = -babbleOSC.BabbleExpressionMap["/mouthDimpleRight"]; - - UnifiedTracking.Data.Shapes[(int)UnifiedExpressions.MouthCornerPullLeft].Weight = -babbleOSC.BabbleExpressionMap["/mouthSmileLeft"]; - UnifiedTracking.Data.Shapes[(int)UnifiedExpressions.MouthCornerPullRight].Weight = -babbleOSC.BabbleExpressionMap["/mouthSmileRight"]; - UnifiedTracking.Data.Shapes[(int)UnifiedExpressions.MouthFrownLeft].Weight = -babbleOSC.BabbleExpressionMap["/mouthFrownLeft"]; - UnifiedTracking.Data.Shapes[(int)UnifiedExpressions.MouthFrownRight].Weight = -babbleOSC.BabbleExpressionMap["/mouthFrownRight"]; - UnifiedTracking.Data.Shapes[(int)UnifiedExpressions.CheekPuffLeft].Weight = babbleOSC.BabbleExpressionMap["/cheekPuff"]; - UnifiedTracking.Data.Shapes[(int)UnifiedExpressions.CheekPuffRight].Weight = babbleOSC.BabbleExpressionMap["/cheekPuff"]; + foreach (var unifiedExpression in BabbleExpressions.BabbleExpressionMap) + { + UnifiedTracking.Data.Shapes[(int) unifiedExpression].Weight = BabbleExpressions.BabbleExpressionMap.GetByKey1 (unifiedExpression); + } } } diff --git a/TwoKeyDictionary.cs b/TwoKeyDictionary.cs new file mode 100644 index 0000000..f3d9ef8 --- /dev/null +++ b/TwoKeyDictionary.cs @@ -0,0 +1,273 @@ +using System.Collections; +using System.Text; + +namespace VRCFaceTracking.Babble.Collections; + +// https://stackoverflow.com/questions/32761880/net-dictionary-with-two-keys-and-one-value + +/// +/// A dictionary whose values can be accessed by two keys. Enforces unique outer keys and inner keys +/// +/// +/// This isn't the fastest implementation, but it's best suited to adapt to varying OSC protocol naming schemes +/// +/// +/// +/// +public class TwoKeyDictionary : IEnumerable +{ + private Dictionary m_dic1 = new Dictionary(); + private Dictionary m_dic2 = new Dictionary(); + + /// + /// Adds the specified key and value to the dictionary. + /// This will always add the value if the input parameters are not null. + /// + /// + /// + /// + /// Returns true if the value was added, false if the value was already present in the dictionary. + public bool Add(TKey1 key1, TKey2 key2, TValue value) + { + if (key1 == null || key2 == null || ContainsKey1(key1) || ContainsKey2(key2)) + { + return false; + } + + m_dic1[key1] = key2; + m_dic2[key2] = value; + + return true; + } + + /// + /// Sets the specified key and value in the dictionary, if it already exists. + /// This is functionally identical to the Add() method, but it will not add the value if it doesn't already exist. + /// + /// + /// + /// + /// Returns true if the value was set, false if the value was not found. + public bool SetByAnyKey(TKey1 key1, TKey2 key2, TValue value) + { + if (!(ContainsKey1(key1) || ContainsKey2(key2))) + { + return false; + } + + m_dic1[key1] = key2; + m_dic2[key2] = value; + return true; + } + + /// + /// Sets the specified value in the dictionary given the first key, if it already exists. + /// + /// + /// + /// Returns true if the value was set, false if the value was not found. + public bool SetByKey1(TKey1 key1, TValue value) + { + if (!ContainsKey1(key1)) + { + return false; + } + + m_dic2[m_dic1[key1]] = value; + return true; + } + + /// + /// Sets the specified value in the dictionary given the second key, if it already exists. + /// + /// + /// + /// Returns true if the value was set, false if the value was not found. + public bool SetByKey2(TKey2 key2, TValue value) + { + if (!ContainsKey2(key2)) + { + return false; + } + + m_dic2[key2] = value; + return true; + } + + + /// + /// Gets the value associated with the outer key. + /// + /// + /// The TValue for this Tkey1. + public TValue GetByKey1(TKey1 key1) + { + return m_dic2[m_dic1[key1]]; + } + + /// + /// Gets the value associated with the inner key. + /// + /// + /// The TValue for this Tkey2. + public TValue GetByKey2(TKey2 key2) + { + return m_dic2[key2]; + } + + /// + /// Gets the value associated with the outer key. + /// + /// + /// The TValue for this Tkey1. + public bool TryGetByKey1(TKey1 key1, out TValue value) + { + if (!ContainsKey1(key1)) + { + value = default(TValue); + return false; + } + + if (!ContainsKey2(m_dic1[key1])) + { + value = default(TValue); + return false; + } + + value = m_dic2[m_dic1[key1]]; + return true; + } + + /// + /// Gets the value associated with the inner key. + /// + /// + /// The TValue for this Tkey2. + public bool TryGetByKey2(TKey2 key2, out TValue value) + { + if (!ContainsKey2(key2)) + { + value = default(TValue); + return false; + } + + value = m_dic2[key2]; + return true; + } + + /// + /// Removes the value associated with the outer key. If the outer key is not found, nothing happens. If the outer key is found, the inner key must also exist and is also removed. + /// + /// + public bool RemoveByKey1(TKey1 key1) + { + if (!m_dic1.TryGetValue(key1, out TKey2 tmp_key2)) + { + return false; + } + + m_dic1.Remove(key1); + m_dic2.Remove(tmp_key2); + return true; + } + + /// + /// Removes the value associated with the inner key. If the inner key is not found, nothing happens. If the inner key is found, the outer key must also exist and is also removed. + /// + /// + public bool RemoveByKey2(TKey2 key2) + { + if (!m_dic2.ContainsKey(key2)) + { + return false; + } + + TKey1 tmp_key1 = m_dic1.First((kvp) => kvp.Value.Equals(key2)).Key; + m_dic1.Remove(tmp_key1); + m_dic2.Remove(key2); + return true; + } + + /// + /// Get the length of this two-key dictionary. m_dic1.Count is used, as it is the same as m_dic2.Count. + /// + public int Count + { + get + { + return m_dic1.Count; + } + } + + /// + /// Evaluates whether the two-key dictionary contains the outer key. + /// + /// + /// True if the outer dictionary contains the key. + public bool ContainsKey1(TKey1 key1) + { + return m_dic1.ContainsKey(key1); + } + + /// + /// Evaluates whether the two-key dictionary contains the inner key. + /// + /// + /// True if the inner dictionary contains the key. + public bool ContainsKey2(TKey2 key2) + { + return m_dic2.ContainsKey(key2); + } + + /// + /// Evaluates whether the two-key dictionary contains the given value. + /// + /// + /// True if the two-key dictionary contains the value. + public bool ContainsValue(TValue value) + { + return m_dic2.ContainsValue(value); + } + + public (TKey1, TKey2, TValue) ElementAt(int index) + { + if (index < 0 || index >= Count) + { + throw new IndexOutOfRangeException(); + } + return (m_dic1.ElementAt(index).Key, m_dic1.ElementAt(index).Value, m_dic2[m_dic1.ElementAt(index).Value]); + } + + /// + /// Clears the two-key dictionary. + /// + public void Clear() + { + m_dic1.Clear(); + m_dic2.Clear(); + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + foreach (KeyValuePair kvp in m_dic1) + { + sb.AppendLine($"Key1: {kvp.Key}, Key2: {kvp.Value}, Value: {m_dic2[kvp.Value]}"); + } + return sb.ToString(); + } + + public IEnumerable OuterKeys => m_dic1.Keys; + + public IEnumerable InnerKeys => m_dic2.Keys; + + public IEnumerator GetEnumerator() + { + return m_dic1.Keys.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } +} \ No newline at end of file diff --git a/TwoKeyDictionaryConverter.cs b/TwoKeyDictionaryConverter.cs new file mode 100644 index 0000000..ff77c87 --- /dev/null +++ b/TwoKeyDictionaryConverter.cs @@ -0,0 +1,53 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using VRCFaceTracking.Babble.Collections; + +namespace VRCFaceTracking.Babble; + +public class TwoKeyDictionaryConverter : JsonConverter> +{ + public override void WriteJson(JsonWriter writer, TwoKeyDictionary tkd, JsonSerializer serializer) + { + var entries = new List(); + + for (int i = 0; i < tkd.Count; i++) + { + var elem = tkd.ElementAt(i); + var entry = new JObject( + new JProperty("unifiedExpression", elem.Item1!.ToString()), + new JProperty("oscAddress", elem.Item2), + new JProperty("weight", elem.Item3) + ); + entries.Add(entry); + } + + serializer.Serialize(writer, entries); + } + + public override TwoKeyDictionary ReadJson(JsonReader reader, Type objectType, TwoKeyDictionary existingValue, bool hasExistingValue, JsonSerializer serializer) + { + var entries = serializer.Deserialize>(reader); + + if (entries == null) + { + return null; + } + + var dictionary = new TwoKeyDictionary(); + + foreach (var entry in entries) + { + var item1 = (TKey1) Enum.Parse(typeof(TKey1), entry["unifiedExpression"]!.Value()!); + var item2 = entry["oscAddress"]!.Value(); + var item3 = entry["weight"]!.Value(); + + dictionary.Add(item1!, item2!, item3!); + } + + return dictionary; + } + + public override bool CanRead => true; + + public override bool CanWrite => true; +} diff --git a/VRCFaceTracking.Babble.csproj b/VRCFaceTracking.Babble.csproj index c4d9dd7..5989a1e 100644 --- a/VRCFaceTracking.Babble.csproj +++ b/VRCFaceTracking.Babble.csproj @@ -1,9 +1,10 @@ - + net7.0-windows10.0.19041.0 enable enable + AnyCPU;x64 @@ -13,6 +14,30 @@ + + + + ..\..\..\..\..\Program Files\WindowsApps\96ba052f-0948-44d8-86c4-a0212e4ae047_5.1.1.0_x64__d7rcq4vxghz0r\Microsoft.Extensions.Logging.dll + + + ..\..\..\..\..\Program Files\WindowsApps\96ba052f-0948-44d8-86c4-a0212e4ae047_5.1.1.0_x64__d7rcq4vxghz0r\Microsoft.Extensions.Logging.Abstractions.dll + + + ..\..\..\..\..\Program Files\WindowsApps\96ba052f-0948-44d8-86c4-a0212e4ae047_5.1.1.0_x64__d7rcq4vxghz0r\Microsoft.Extensions.Logging.EventLog.dll + + + ..\..\..\..\..\Program Files\WindowsApps\96ba052f-0948-44d8-86c4-a0212e4ae047_5.1.1.0_x64__d7rcq4vxghz0r\Microsoft.Extensions.Logging.EventSource.dll + + + ..\..\..\..\..\Program Files\WindowsApps\96ba052f-0948-44d8-86c4-a0212e4ae047_5.1.1.0_x64__d7rcq4vxghz0r\Newtonsoft.Json.dll + + + ..\..\..\..\..\Program Files\WindowsApps\96ba052f-0948-44d8-86c4-a0212e4ae047_5.1.1.0_x64__d7rcq4vxghz0r\VRCFaceTracking.dll + + + ..\..\..\..\..\Program Files\WindowsApps\96ba052f-0948-44d8-86c4-a0212e4ae047_5.1.1.0_x64__d7rcq4vxghz0r\VRCFaceTracking.Core.dll + + diff --git a/VRCFaceTracking.Babble.sln b/VRCFaceTracking.Babble.sln index d36ccc2..b1cb04c 100644 --- a/VRCFaceTracking.Babble.sln +++ b/VRCFaceTracking.Babble.sln @@ -19,8 +19,8 @@ Global GlobalSection(ProjectConfigurationPlatforms) = postSolution {E3CF55A7-D138-4519-A4D1-AD390E2FB8B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E3CF55A7-D138-4519-A4D1-AD390E2FB8B3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E3CF55A7-D138-4519-A4D1-AD390E2FB8B3}.Debug|x64.ActiveCfg = Debug|Any CPU - {E3CF55A7-D138-4519-A4D1-AD390E2FB8B3}.Debug|x64.Build.0 = Debug|Any CPU + {E3CF55A7-D138-4519-A4D1-AD390E2FB8B3}.Debug|x64.ActiveCfg = Debug|x64 + {E3CF55A7-D138-4519-A4D1-AD390E2FB8B3}.Debug|x64.Build.0 = Debug|x64 {E3CF55A7-D138-4519-A4D1-AD390E2FB8B3}.Release|Any CPU.ActiveCfg = Release|Any CPU {E3CF55A7-D138-4519-A4D1-AD390E2FB8B3}.Release|Any CPU.Build.0 = Release|Any CPU {E3CF55A7-D138-4519-A4D1-AD390E2FB8B3}.Release|x64.ActiveCfg = Release|Any CPU