diff --git a/VRCFaceTracking/ArgsHandler.cs b/VRCFaceTracking/ArgsHandler.cs index cecf5a58..767ed239 100644 --- a/VRCFaceTracking/ArgsHandler.cs +++ b/VRCFaceTracking/ArgsHandler.cs @@ -1,47 +1,77 @@ -using System; -using System.Text.RegularExpressions; - -namespace VRCFaceTracking -{ - public static class ArgsHandler - { - public static (int SendPort, string IP, int RecievePort) HandleArgs() - { - (int SendPort, string IP, int RecievePort) = (9000, "127.0.0.1", 9001); - - foreach (var arg in Environment.GetCommandLineArgs()) - { - if (arg.StartsWith("--osc=")) - { - var oscConfig = arg.Remove(0, 6).Split(':'); - if (oscConfig.Length < 3) - { - Console.WriteLine("Invalid OSC config: " + arg +"\nExpected format: --osc=::"); - break; - } - - if (!int.TryParse(oscConfig[0], out SendPort)) - { - Console.WriteLine("Invalid OSC OutPort: " + oscConfig[0]); - break; - } - - if (!new Regex("^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$").IsMatch(oscConfig[1])) - { - Console.WriteLine("Invalid OSC IP: " + oscConfig[1]); - break; - } - IP = oscConfig[1]; - - if (!int.TryParse(oscConfig[2], out RecievePort)) - { - Console.WriteLine("Invalid OSC InPort: " + oscConfig[2]); - break; - } - } - } - - return (SendPort, IP, RecievePort); - } - } +using System; +using System.Text.RegularExpressions; + +namespace VRCFaceTracking +{ + public static class ArgsHandler + { + + public static (int SendPort, string IP, int ReceivePort, string opMode) HandleArgs() + { + Logger.Msg("Loading Defaults"); + (int SendPort, string IP, int ReceivePort, string opMode) = (9000, "127.0.0.1", 9001, "auto"); + + foreach (var arg in Environment.GetCommandLineArgs()) + { + if ((arg.StartsWith("--help")) || (arg.StartsWith("--options"))) + { + Logger.Msg("To set custom OSC port/IP config please use the following"); + Logger.Msg("--osc=::"); + Logger.Msg("To set operating mode please use the following"); + Logger.Msg("--mode=vrc or --mode=cvr"); + } + if (arg.StartsWith("--mode=")) + { + opMode = arg.Remove(0, 7); + } + if (arg.StartsWith("--osc=")) + { + Logger.Msg("Loading OSC config Args"); + var oscConfig = arg.Remove(0, 6).Split(':'); + if (oscConfig.Length < 3) + { + Logger.Error("Invalid OSC config: " + arg +"\nExpected format: --osc=::"); + break; + } + + + int parsedIntSP; + if (int.TryParse(oscConfig[0], out parsedIntSP)) + { + SendPort = parsedIntSP; + Logger.Msg("Loaded custom OSC OutPort value, " + SendPort); + } + else + { + Logger.Error("Malformed OSC OutPort value" + oscConfig[0] + ", please ensure you set a number"); + } + + + if (!new Regex("^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$").IsMatch(oscConfig[1])) + { + Logger.Error("Invalid OSC IP: " + oscConfig[1]); + break; + } + else + { + IP = oscConfig[1]; + } + + int parsedIntRP; + if (int.TryParse(oscConfig[2], out parsedIntRP)) + { + ReceivePort = parsedIntRP; + Logger.Msg("Loaded custom OSC ReceivePort value, " + ReceivePort); + } + else + { + Logger.Error("Malformed OSC ReceivePort value " + oscConfig[2] + ", please ensure you set a number"); + } + + } + } + + return (SendPort, IP, ReceivePort, opMode); + } + } } \ No newline at end of file diff --git a/VRCFaceTracking/CVR.cs b/VRCFaceTracking/CVR.cs new file mode 100644 index 00000000..7acf8171 --- /dev/null +++ b/VRCFaceTracking/CVR.cs @@ -0,0 +1,18 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using Microsoft.Win32; + +namespace VRCFaceTracking +{ + public static class CVR + { + public static readonly string CVRData = Path.Combine(Environment + .GetFolderPath(Environment.SpecialFolder.ApplicationData).Replace("Roaming", "LocalLow"), "Alpha Blend Interactive\\ChilloutVR"); + + public static readonly string CVROSCDirectory = Path.Combine(CVRData, "OSC"); + + public static bool IsCVRRunning() => Process.GetProcesses().Any(x => x.ProcessName == "ChilloutVR"); + } +} \ No newline at end of file diff --git a/VRCFaceTracking/ConfigParser.cs b/VRCFaceTracking/ConfigParser.cs index efc6bf5b..d333d5df 100644 --- a/VRCFaceTracking/ConfigParser.cs +++ b/VRCFaceTracking/ConfigParser.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Drawing.Text; using System.IO; using System.Linq; using System.Text.Json; @@ -8,7 +9,8 @@ namespace VRCFaceTracking { public static class ConfigParser - { + { + private static string _oscDir; public class InputOutputDef { public string address { get; set; } @@ -35,9 +37,23 @@ public class AvatarConfigSpec public static Action OnConfigLoaded = () => { }; public static void ParseNewAvatar(string newId) - { + { + Logger.Msg("-------------------------------------------------"); + Logger.Msg("avatar id = " + newId); + //check what mode we are in + if(Globals.opMode == "vrc") + { + Logger.Msg("Loading Avatar from VRChat"); + _oscDir = VRChat.VRCOSCDirectory; + } + if (Globals.opMode == "cvr") + { + Logger.Msg("Loading Avatar from ChilloutVR"); + _oscDir = CVR.CVROSCDirectory; + } + AvatarConfigSpec avatarConfig = null; - foreach (var userFolder in Directory.GetDirectories(VRChat.VRCOSCDirectory)) + foreach (var userFolder in Directory.GetDirectories(_oscDir)) { if (Directory.Exists(userFolder + "\\Avatars")) foreach (var avatarFile in Directory.GetFiles(userFolder+"\\Avatars")) diff --git a/VRCFaceTracking/MainStandalone.cs b/VRCFaceTracking/MainStandalone.cs index 3d188f2e..6b2aa049 100644 --- a/VRCFaceTracking/MainStandalone.cs +++ b/VRCFaceTracking/MainStandalone.cs @@ -1,133 +1,249 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Resources; -using System.Runtime.InteropServices; -using System.Threading; -using System.Windows; -using VRCFaceTracking.Assets.UI; -using VRCFaceTracking.OSC; - -[assembly: AssemblyTitle("VRCFaceTracking")] -[assembly: AssemblyDescription("Application to enable Face Tracking from within VRChat using OSC")] -[assembly: AssemblyCompany("benaclejames")] -[assembly: AssemblyProduct("VRCFaceTracking")] -[assembly: AssemblyCopyright("Copyright © benaclejames 2022")] -[assembly: ComVisible(false)] -[assembly: AssemblyVersion("3.0.1")] -[assembly: AssemblyFileVersion("3.0.1")] -[assembly: NeutralResourcesLanguage("en")] -[assembly: ThemeInfo( - ResourceDictionaryLocation.None, - ResourceDictionaryLocation.SourceAssembly -)] - -namespace VRCFaceTracking -{ - public static class MainStandalone - { - public static OscMain OscMain; - - private static List ConstructMessages(IEnumerable parameters) => - parameters.Where(p => p.NeedsSend).Select(param => - { - param.NeedsSend = false; - return new OscMessage(param.OutputInfo.address, param.OscType, param.ParamValue); - }).ToList(); - - private static IEnumerable _relevantParams; - private static int _relevantParamsCount = 416; - - private static string _ip = "127.0.0.1"; - private static int _inPort = 9001, _outPort = 9000; - - public static readonly CancellationTokenSource MasterCancellationTokenSource = new CancellationTokenSource(); - - public static void Teardown() - { - // Kill our threads - MasterCancellationTokenSource.Cancel(); - - Utils.TimeEndPeriod(1); - Logger.Msg("VRCFT Standalone Exiting!"); - UnifiedLibManager.TeardownAllAndReset(); - Console.WriteLine("Shutting down"); - MainWindow.TrayIcon.Visible = false; - Application.Current?.Shutdown(); - } - - public static void Initialize() - { - Logger.Msg("VRCFT Initializing!"); - - // Parse Arguments - (_outPort, _ip, _inPort) = ArgsHandler.HandleArgs(); - - // Load dependencies - DependencyManager.Load(); - - // Ensure OSC is enabled - if (VRChat.ForceEnableOsc()) // If osc was previously not enabled - { - Logger.Warning("VRCFT detected OSC was disabled and automatically enabled it."); - // If we were launched after VRChat - if (VRChat.IsVRChatRunning()) - Logger.Error( - "However, VRChat was running while this change was made.\n" + - "If parameters do not update, please restart VRChat or manually enable OSC yourself in your avatar's expressions menu."); - } - - // Initialize Tracking Runtimes - UnifiedLibManager.Initialize(); - - // Initialize Locals - OscMain = new OscMain(); - var bindResults = OscMain.Bind(_ip, _outPort, _inPort); - if (!bindResults.receiverSuccess) - Logger.Error("Socket failed to bind to receiver port, please ensure it's not already in use by another program or specify a different one instead."); - - if (!bindResults.senderSuccess) - Logger.Error("Socket failed to bind to sender port, please ensure it's not already in use by another program or specify a different one instead."); - - _relevantParams = UnifiedTrackingData.AllParameters.SelectMany(p => p.GetBase()).Where(param => param.Relevant); - - ConfigParser.OnConfigLoaded += () => - { - _relevantParams = UnifiedTrackingData.AllParameters.SelectMany(p => p.GetBase()) - .Where(param => param.Relevant); - UnifiedTrackingData.LatestEyeData.ResetThresholds(); - _relevantParamsCount = _relevantParams.Count(); - Logger.Msg("Config file parsed successfully! " + _relevantParamsCount + " parameters loaded"); - }; - - // Begin main OSC update loop - Utils.TimeBeginPeriod(1); - while (!MasterCancellationTokenSource.IsCancellationRequested) - { - Thread.Sleep(10); - - if (_relevantParamsCount <= 0) - continue; - - UnifiedTrackingData.OnUnifiedDataUpdated.Invoke(UnifiedTrackingData.LatestEyeData, - UnifiedTrackingData.LatestLipData); - - var messages = ConstructMessages(_relevantParams); - while (messages.Count > 0) - { - var msgCount = 16; - var msgList = new List(); - while (messages.Count > 0 && msgCount+messages[0].Data.Length+4 < 4096) - { - msgList.Add(messages[0]); - msgCount += messages[0].Data.Length+4; - messages.RemoveAt(0); - } - var bundle = new OscBundle(msgList); - OscMain.Send(bundle.Data); - } - } - } - } +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; +using System.Resources; +using System.Runtime.InteropServices; +using System.Security.Cryptography.X509Certificates; +using System.Threading; +using System.Windows; +using VRCFaceTracking.Assets.UI; +using VRCFaceTracking.OSC; + +[assembly: AssemblyTitle("VRCFaceTracking")] +[assembly: AssemblyDescription("Application to enable Face Tracking from within VRChat using OSC")] +[assembly: AssemblyCompany("benaclejames")] +[assembly: AssemblyProduct("VRCFaceTracking")] +[assembly: AssemblyCopyright("Copyright © benaclejames 2022")] +[assembly: ComVisible(false)] +[assembly: AssemblyVersion("3.0.1")] +[assembly: AssemblyFileVersion("3.0.1")] +[assembly: NeutralResourcesLanguage("en")] +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, + ResourceDictionaryLocation.SourceAssembly +)] + +namespace VRCFaceTracking +{ + + public class Globals + { + private static string _ip, _opMode; + private static int _inPort, _outPort; + public static string ip + { + get + { + return _ip; + } + set + { + _ip = value; + } + } + public static string opMode + { + get + { + return _opMode; + } + set + { + _opMode = value; + } + } + public static int inPort + { + get + { + return _inPort; + } + set + { + _inPort = value; + } + } + public static int outPort + { + get + { + return _outPort; + } + set + { + _outPort = value; + } + } + + } + public static class MainStandalone + { + public static OscMain OscMain; + + private static List ConstructMessages(IEnumerable parameters) => + parameters.Where(p => p.NeedsSend).Select(param => + { + param.NeedsSend = false; + return new OscMessage(param.OutputInfo.address, param.OscType, param.ParamValue); + }).ToList(); + + private static IEnumerable _relevantParams; + private static int _relevantParamsCount = 416; + + private static string _ip, _opMode; + private static int _inPort, _outPort; + + public static readonly CancellationTokenSource MasterCancellationTokenSource = new CancellationTokenSource(); + + public static void Teardown() + { + // Kill our threads + MasterCancellationTokenSource.Cancel(); + + Utils.TimeEndPeriod(1); + Logger.Msg("VRCFT Standalone Exiting!"); + UnifiedLibManager.TeardownAllAndReset(); + Console.WriteLine("Shutting down"); + MainWindow.TrayIcon.Visible = false; + Application.Current?.Shutdown(); + } + + public static void Initialize() + { + Logger.Msg("VRCFT Initializing!"); + + // Parse Arguments + + (_outPort, _ip, _inPort, _opMode) = ArgsHandler.HandleArgs(); + + // if auto opMode is active (default behavior), detect running app and start in correct mode + if (_opMode == "auto") + { + Logger.Msg("Operating mode auto detecting."); + bool _noset1 = false; + bool _noset2 = false; + if (CVR.IsCVRRunning()) + { + Logger.Msg("ChilloutVR running switching opMode to cvr"); + _opMode = "cvr"; + } + else + { + _noset1 |= true; + } + if (VRChat.IsVRChatRunning()) + { + Logger.Msg("VRChat running switching opMode to vrc"); + _opMode = "vrc"; + } + else + { + _noset2 |= true; + } + + if( _noset1&& _noset2) + { + Logger.Error( + "Neither VRChat or ChilloutVR detected as running.\n" + + "opMode falling back to vrc"); + _opMode = "vrc"; + } + } + + + // setup global values + Globals.inPort = _inPort; + Globals.outPort = _outPort; + Globals.ip = _ip; + Globals.opMode = _opMode; + Logger.Msg("InPort = " + Globals.inPort + " , OutPort = " + Globals.outPort + " , target IP = " + Globals.ip); + Logger.Msg("Operating Mode = '" + Globals.opMode + "'"); + + + // Load dependencies + DependencyManager.Load(); + + if (Globals.opMode == "vrc") + { + // Ensure OSC is enabled + if (VRChat.ForceEnableOsc()) // If osc was previously not enabled + { + Logger.Warning("VRCFT detected OSC was disabled and automatically enabled it."); + // If we were launched after VRChat + if (VRChat.IsVRChatRunning()) + Logger.Error( + "However, VRChat was running while this change was made.\n" + + "If parameters do not update, please restart VRChat or manually enable OSC yourself in your avatar's expressions menu."); + } + // Warn about mode if CVR detected running (as mode is currently vrc) + if (CVR.IsCVRRunning()) + { + Logger.Error("Operating mode is currently VRChat but ChilloutVR is currently running. \n " + + "you may want to set opMode to cvr"); + } + } + if (Globals.opMode == "cvr") + { + if (VRChat.IsVRChatRunning()) + { + Logger.Error( + "Operating mode is currently set to ChilloutVR but VRChat is currently running. \n " + + "you may want to set opMode to vrc"); + } + } + + // Initialize Tracking Runtimes + UnifiedLibManager.Initialize(); + + // Initialize Locals + OscMain = new OscMain(); + var bindResults = OscMain.Bind(_ip, _outPort, _inPort); + if (!bindResults.receiverSuccess) + Logger.Error("Socket failed to bind to receiver port " + _inPort + ", please ensure it's not already in use by another program or specify a different one instead."); + + if (!bindResults.senderSuccess) + Logger.Error("Socket failed to bind to sender port "+ _outPort + ", please ensure it's not already in use by another program or specify a different one instead."); + + _relevantParams = UnifiedTrackingData.AllParameters.SelectMany(p => p.GetBase()).Where(param => param.Relevant); + + ConfigParser.OnConfigLoaded += () => + { + _relevantParams = UnifiedTrackingData.AllParameters.SelectMany(p => p.GetBase()) + .Where(param => param.Relevant); + UnifiedTrackingData.LatestEyeData.ResetThresholds(); + _relevantParamsCount = _relevantParams.Count(); + Logger.Msg("Config file parsed successfully! " + _relevantParamsCount + " parameters loaded"); + }; + + // Begin main OSC update loop + Utils.TimeBeginPeriod(1); + while (!MasterCancellationTokenSource.IsCancellationRequested) + { + Thread.Sleep(10); + + if (_relevantParamsCount <= 0) + continue; + + UnifiedTrackingData.OnUnifiedDataUpdated.Invoke(UnifiedTrackingData.LatestEyeData, + UnifiedTrackingData.LatestLipData); + + var messages = ConstructMessages(_relevantParams); + while (messages.Count > 0) + { + var msgCount = 16; + var msgList = new List(); + while (messages.Count > 0 && msgCount+messages[0].Data.Length+4 < 4096) + { + msgList.Add(messages[0]); + msgCount += messages[0].Data.Length+4; + messages.RemoveAt(0); + } + var bundle = new OscBundle(msgList); + OscMain.Send(bundle.Data); + } + } + } + } } \ No newline at end of file diff --git a/VRCFaceTracking/OSC/OSCMain.cs b/VRCFaceTracking/OSC/OSCMain.cs index ea4bbe07..0c139497 100644 --- a/VRCFaceTracking/OSC/OSCMain.cs +++ b/VRCFaceTracking/OSC/OSCMain.cs @@ -63,15 +63,47 @@ private void Recv() try { ReceiverClient.Receive(buffer, buffer.Length, SocketFlags.None); + if (Globals.opMode == "cvr") + { + // restore catch as CVR has more potential OSC types + var newMsg = new OscMessage(buffer); + + if (newMsg.Address == "/avatar/change") + { + try + { + ConfigParser.ParseNewAvatar((string) newMsg.Value); + } + catch { + Logger.Warning("ParseNewAvatar exception thrown"); + } + } + } } catch (SocketException) - { + { + Logger.Warning("OSC message exception thrown"); // Ignore as this is most likely a timeout exception - return; + if (Globals.opMode == "vrc") + { + // keep current behviour for VRC + return; + } + } + if (Globals.opMode == "vrc") + { + var newMsg = new OscMessage(buffer); + if (newMsg.Address == "/avatar/change") + { + try + { + ConfigParser.ParseNewAvatar((string) newMsg.Value); + } + catch { + Logger.Warning("ParseNewAvatar exception thrown"); + } + } } - var newMsg = new OscMessage(buffer); - if (newMsg.Address == "/avatar/change") - ConfigParser.ParseNewAvatar((string) newMsg.Value); } public void Send(byte[] data) => SenderClient.Send(data, data.Length, SocketFlags.None); diff --git a/VRCFaceTracking/VRCFaceTracking.csproj b/VRCFaceTracking/VRCFaceTracking.csproj index 0b820e45..4c53d851 100644 --- a/VRCFaceTracking/VRCFaceTracking.csproj +++ b/VRCFaceTracking/VRCFaceTracking.csproj @@ -1,191 +1,192 @@ - - - - - Debug - AnyCPU - {0767C09E-D536-464B-B0A1-46D5BFA19E98} - WinExe - Properties - VRCFaceTracking - VRCFaceTracking - v4.7.2 - {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 512 - - - x64 - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - true - false - - - pdbonly - true - TRACE - prompt - 4 - true - bin\Release\ - x64 - false - - - Assets/Images/VRCFT.ico - - - - - App.xaml - Code - - - MainWindow.xaml - Code - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ..\packages\Microsoft.Bcl.AsyncInterfaces.7.0.0-preview.1.22076.8\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll - True - - - - - - - ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll - True - - - - - ..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll - True - - - ..\..\..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Numerics.dll - - - ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll - True - - - ..\packages\System.Runtime.CompilerServices.Unsafe.7.0.0-preview.1.22076.8\lib\net462\System.Runtime.CompilerServices.Unsafe.dll - True - - - ..\packages\System.Text.Encodings.Web.7.0.0-preview.1.22076.8\lib\net462\System.Text.Encodings.Web.dll - True - - - ..\packages\System.Text.Json.7.0.0-preview.1.22076.8\lib\net462\System.Text.Json.dll - True - - - ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll - True - - - ..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll - True - - - - - - - - - - - - - - - - - - MSBuild:Compile - Designer - - - - - MSBuild:Compile - Designer - - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}. - - - - - - - %(ReferenceCopyLocalPaths.DestinationSubDirectory)%(ReferenceCopyLocalPaths.Filename)%(ReferenceCopyLocalPaths.Extension) - - - + + + + + Debug + AnyCPU + {0767C09E-D536-464B-B0A1-46D5BFA19E98} + WinExe + Properties + VRCFaceTracking + VRCFaceTracking + v4.7.2 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 512 + + + x64 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + true + false + + + pdbonly + true + TRACE + prompt + 4 + true + bin\Release\ + x64 + false + + + Assets/Images/VRCFT.ico + + + + + App.xaml + Code + + + MainWindow.xaml + Code + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\packages\Microsoft.Bcl.AsyncInterfaces.7.0.0-preview.1.22076.8\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll + True + + + + + + + ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll + True + + + + + ..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll + True + + + ..\..\..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Numerics.dll + + + ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll + True + + + ..\packages\System.Runtime.CompilerServices.Unsafe.7.0.0-preview.1.22076.8\lib\net462\System.Runtime.CompilerServices.Unsafe.dll + True + + + ..\packages\System.Text.Encodings.Web.7.0.0-preview.1.22076.8\lib\net462\System.Text.Encodings.Web.dll + True + + + ..\packages\System.Text.Json.7.0.0-preview.1.22076.8\lib\net462\System.Text.Json.dll + True + + + ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll + True + + + ..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll + True + + + + + + + + + + + + + + + + + + MSBuild:Compile + Designer + + + + + MSBuild:Compile + Designer + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}. + + + + + + + %(ReferenceCopyLocalPaths.DestinationSubDirectory)%(ReferenceCopyLocalPaths.Filename)%(ReferenceCopyLocalPaths.Extension) + + + + --> \ No newline at end of file