Skip to content

Commit

Permalink
Merge branch 'dev' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
VolcanicArts committed Oct 7, 2023
2 parents f85d981 + 7a4d266 commit 85276f6
Show file tree
Hide file tree
Showing 22 changed files with 643 additions and 167 deletions.
4 changes: 2 additions & 2 deletions VRCOSC.Desktop/VRCOSC.Desktop.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
<ApplicationIcon>game.ico</ApplicationIcon>
<ApplicationManifest>app.manifest</ApplicationManifest>
<Version>0.0.0</Version>
<FileVersion>2023.928.1</FileVersion>
<FileVersion>2023.1007.0</FileVersion>
<Title>VRCOSC</Title>
<Authors>VolcanicArts</Authors>
<Company>VolcanicArts</Company>
<Nullable>enable</Nullable>
<AssemblyVersion>2023.928.1</AssemblyVersion>
<AssemblyVersion>2023.1007.0</AssemblyVersion>
</PropertyGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\VRCOSC.Game\VRCOSC.Game.csproj" />
Expand Down
27 changes: 20 additions & 7 deletions VRCOSC.Game/App/AppManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public partial class AppManager : Component

private static readonly TimeSpan openvr_check_interval = TimeSpan.FromSeconds(1);
private static readonly TimeSpan vrchat_check_interval = TimeSpan.FromSeconds(5);
private static readonly TimeSpan oscjson_check_interval = TimeSpan.FromSeconds(5);

private readonly Queue<VRChatOscMessage> oscMessageQueue = new();
private ScheduledDelegate? runningModulesDelegate;
Expand Down Expand Up @@ -144,6 +145,8 @@ private void initialiseDelayedTasks()
{
Scheduler.AddDelayed(checkForOpenVR, openvr_check_interval.TotalMilliseconds, true);
Scheduler.AddDelayed(checkForVRChat, vrchat_check_interval.TotalMilliseconds, true);
Scheduler.AddDelayed(checkForOscjson, oscjson_check_interval.TotalMilliseconds, true);
checkForOscjson();
}

#endregion
Expand Down Expand Up @@ -189,10 +192,7 @@ private void processControlParameters(VRChatOscMessage message)

private void scheduleModuleEnabledParameters()
{
runningModulesDelegate = Scheduler.AddDelayed(() =>
{
ModuleManager.Modules.ForEach(module => sendModuleRunningState(module, ModuleManager.IsModuleRunning(module)));
}, TimeSpan.FromSeconds(1).TotalMilliseconds, true);
runningModulesDelegate = Scheduler.AddDelayed(() => ModuleManager.Modules.ForEach(module => sendModuleRunningState(module, ModuleManager.IsModuleRunning(module))), TimeSpan.FromSeconds(1).TotalMilliseconds, true);
}

private void cancelRunningModulesDelegate()
Expand Down Expand Up @@ -314,10 +314,23 @@ private void checkForOpenVR() => Task.Run(() =>

private void checkForVRChat()
{
if (!configManager.Get<bool>(VRCOSCSetting.AutoStartStop) || !VRChat.HasOpenStateChanged()) return;
var newOpenState = VRChat.HasOpenStateChanged();

if (!configManager.Get<bool>(VRCOSCSetting.AutoStartStop) || !newOpenState) return;

if (VRChat.ClientOpen && State.Value == AppManagerState.Stopped) Start();
if (!VRChat.ClientOpen && State.Value == AppManagerState.Started) Stop();
}

private async void checkForOscjson()
{
if (!VRChat.IsClientOpen())
{
OSCClient.Reset();
return;
}

if (VRChat.IsClientOpen && State.Value == AppManagerState.Stopped) Start();
if (!VRChat.IsClientOpen && State.Value == AppManagerState.Started) Stop();
await OSCClient.CheckForVRChatOSCQuery();
}

#endregion
Expand Down
8 changes: 5 additions & 3 deletions VRCOSC.Game/App/VRChat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace VRCOSC.Game.App;

public class VRChat
{
public bool IsClientOpen;
public bool ClientOpen;

public Player Player = null!;
public AvatarConfig? AvatarConfig;
Expand All @@ -37,12 +37,14 @@ public void HandleAvatarChange(VRChatOscMessage message)
}
}

public bool IsClientOpen() => Process.GetProcessesByName("vrchat").Any();

public bool HasOpenStateChanged()
{
var clientNewOpenState = Process.GetProcessesByName("vrchat").Any();
if (clientNewOpenState == IsClientOpen) return false;
if (clientNewOpenState == ClientOpen) return false;

IsClientOpen = clientNewOpenState;
ClientOpen = clientNewOpenState;
return true;
}
}
3 changes: 3 additions & 0 deletions VRCOSC.Game/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,10 @@ public static class AssemblyExtensions

public static class StringExtensions
{
public const char ZERO_WIDTH = '\u200B';

public static string Truncate(this string value, int maxChars) => value.Length <= maxChars ? value : value[..maxChars] + "...";
public static string EscapeNewLine(this string s) => s.Replace("/n", $"/{ZERO_WIDTH}n");
public static string TrimEnd(this string s, string trimmer) => string.IsNullOrEmpty(s) || string.IsNullOrEmpty(trimmer) || !s.EndsWith(trimmer, StringComparison.OrdinalIgnoreCase) ? s : s[..^trimmer.Length];
}

Expand Down
13 changes: 13 additions & 0 deletions VRCOSC.Game/Modules/Module.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using osu.Framework.Bindables;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Extensions.IEnumerableExtensions;
Expand Down Expand Up @@ -406,6 +407,18 @@ protected T GetSetting<T>(Enum lookup)

#region Parameters

/// <summary>
/// Lets you pass a parameter name to attempt to find the current value using OSCQuery
/// </summary>
/// <remarks>Returns null if no parameter is found or OSCQuery hasn't initialised</remarks>
protected async Task<object?> FindParameterValue(string parameterName) => await oscClient.FindParameterValue(parameterName);

/// <summary>
/// Lets you pass a parameter name to attempt to find the type using OSCQuery
/// </summary>
/// <remarks>Returns null if no parameter is found or OSCQuery hasn't initialised</remarks>
protected async Task<TypeCode?> FindParameterType(string parameterName) => await oscClient.FindParameterType(parameterName);

/// <summary>
/// Allows for sending a parameter that hasn't been registered. Only use this when absolutely necessary
/// </summary>
Expand Down
98 changes: 94 additions & 4 deletions VRCOSC.Game/OSC/VRChat/VRChatOscClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@

using System;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;
using osu.Framework.Logging;
using VRC.OSCQuery;
using VRCOSC.Game.OSC.Client;
using Zeroconf;

namespace VRCOSC.Game.OSC.VRChat;

Expand All @@ -12,12 +18,12 @@ public class VRChatOscClient : OscClient
public Action<VRChatOscMessage>? OnParameterSent;
public Action<VRChatOscMessage>? OnParameterReceived;

private readonly HttpClient client = new();
public int? QueryPort { get; private set; }

public VRChatOscClient()
{
OnMessageSent += message =>
{
OnParameterSent?.Invoke(new VRChatOscMessage(message));
};
OnMessageSent += message => { OnParameterSent?.Invoke(new VRChatOscMessage(message)); };

OnMessageReceived += message =>
{
Expand All @@ -27,4 +33,88 @@ public VRChatOscClient()
OnParameterReceived?.Invoke(data);
};
}

public async Task CheckForVRChatOSCQuery()
{
if (QueryPort is not null) return;

var hosts = await ZeroconfResolver.ResolveAsync("_oscjson._tcp.local.");
var host = hosts.FirstOrDefault();

if (host is null)
{
Logger.Log("No OscJson host found");
QueryPort = null;
return;
}

if (!host.Services.Any(s => s.Value.ServiceName.Contains("VRChat-Client")))
{
Logger.Log("No VRChat-Client found");
QueryPort = null;
return;
}

var service = host.Services.Single(s => s.Value.ServiceName.Contains("VRChat-Client"));

QueryPort = service.Value.Port;
Logger.Log($"Successfully found OscJson port: {QueryPort}");
}

public void Reset()
{
QueryPort = null;
}

public async Task<object?> FindParameterValue(string parameterName)
{
if (QueryPort is null) return null;

var url = $"http://127.0.0.1:{QueryPort}/avatar/parameters/{parameterName}";

var response = await client.GetAsync(new Uri(url));
var content = await response.Content.ReadAsStringAsync();
var node = JsonConvert.DeserializeObject<OSCQueryNode>(content);

if (node is null)
{
Logger.Log("Could not decode node");
return null;
}

return node.OscType switch
{
"f" => Convert.ToSingle(node.Value[0]),
"i" => Convert.ToInt32(node.Value[0]),
"T" => Convert.ToBoolean(node.Value[0]),
"F" => Convert.ToBoolean(node.Value[0]),
_ => throw new InvalidOperationException("Unknown type")
};
}

public async Task<TypeCode?> FindParameterType(string parameterName)
{
if (QueryPort is null) return null;

var url = $"http://127.0.0.1:{QueryPort}/avatar/parameters/{parameterName}";

var response = await client.GetAsync(new Uri(url));
var content = await response.Content.ReadAsStringAsync();
var node = JsonConvert.DeserializeObject<OSCQueryNode>(content);

if (node is null)
{
Logger.Log("Could not decode node");
return null;
}

return node.OscType switch
{
"f" => TypeCode.Single,
"i" => TypeCode.Int32,
"T" => TypeCode.Boolean,
"F" => TypeCode.Boolean,
_ => throw new InvalidOperationException("Unknown type")
};
}
}
6 changes: 3 additions & 3 deletions VRCOSC.Game/Providers/Media/MediaState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ public enum MediaPlaybackStatus

public class MediaTimelineProperties
{
public TimeSpan Start { get; internal set; }
public TimeSpan End { get; internal set; }
public TimeSpan Position { get; internal set; }
public TimeSpan Start { get; internal set; } = TimeSpan.Zero;
public TimeSpan End { get; internal set; } = TimeSpan.FromSeconds(1);
public TimeSpan Position { get; internal set; } = TimeSpan.Zero;

public float PositionPercentage => Position.Ticks / (float)End.Ticks;
}
8 changes: 5 additions & 3 deletions VRCOSC.Game/VRCOSC.Game.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<Nullable>enable</Nullable>
<LangVersion>11</LangVersion>
<PackageId>VolcanicArts.VRCOSC.SDK</PackageId>
<Version>2023.928.0</Version>
<Version>2023.1007.0</Version>
<Title>VRCOSC SDK</Title>
<Authors>VolcanicArts</Authors>
<Description>SDK for creating custom modules with VRCOSC</Description>
Expand All @@ -19,16 +19,18 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="LibreHardwareMonitorLib" Version="0.9.2" />
<PackageReference Include="Octokit" Version="8.0.0" />
<PackageReference Include="ppy.osu.Framework" Version="2023.904.0" />
<PackageReference Include="Octokit" Version="8.0.1" />
<PackageReference Include="ppy.osu.Framework" Version="2023.1006.0" />
<PackageReference Include="PInvoke.User32" Version="0.7.124" />
<PackageReference Include="PolySharp" Version="1.13.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="VRChat.OSCQuery" Version="0.0.7" />
<PackageReference Include="WebSocket4Net" Version="0.15.2" />
<PackageReference Include="NAudio.Wasapi" Version="22.0.0" />
<PackageReference Include="Vosk" Version="0.3.38" />
<PackageReference Include="VolcanicArts.Libs.OpenVR" Version="1.26.7" />
<PackageReference Include="Zeroconf" Version="3.6.11" />
</ItemGroup>
</Project>
Loading

0 comments on commit 85276f6

Please sign in to comment.