Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
VolcanicArts committed Feb 20, 2024
2 parents 2086f12 + 1aa4f18 commit f68528a
Show file tree
Hide file tree
Showing 12 changed files with 201 additions and 100 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>2024.102.0</FileVersion>
<FileVersion>2024.220.0</FileVersion>
<Title>VRCOSC</Title>
<Authors>VolcanicArts</Authors>
<Company>VolcanicArts</Company>
<Nullable>enable</Nullable>
<AssemblyVersion>2024.102.0</AssemblyVersion>
<AssemblyVersion>2024.220.0</AssemblyVersion>
</PropertyGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\VRCOSC.Game\VRCOSC.Game.csproj" />
Expand Down
2 changes: 2 additions & 0 deletions VRCOSC.Game/App/AppManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
using VRCOSC.Game.OpenVR.Metadata;
using VRCOSC.Game.OSC;
using VRCOSC.Game.OSC.VRChat;
using VRCOSC.Game.Util;

namespace VRCOSC.Game.App;

Expand Down Expand Up @@ -146,6 +147,7 @@ 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);
Scheduler.AddDelayed(CurrentWorldExtractor.UpdateCurrentWorld, 2500, true);
checkForOscjson();
}

Expand Down
4 changes: 3 additions & 1 deletion VRCOSC.Game/Config/VRCOSCConfigManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ protected override void InitialiseDefaults()
SetDefault(VRCOSCSetting.UIScale, 1f);
SetDefault(VRCOSCSetting.StartInTray, false);
SetDefault(VRCOSCSetting.TrayOnClose, false);
SetDefault(VRCOSCSetting.ChatboxWorldBlock, true);
}
}

Expand All @@ -54,5 +55,6 @@ public enum VRCOSCSetting
WindowState,
UIScale,
StartInTray,
TrayOnClose
TrayOnClose,
ChatboxWorldBlock
}
1 change: 1 addition & 0 deletions VRCOSC.Game/Graphics/Settings/GeneralSection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ protected override void GenerateItems()
AddDropdown("Theme", "Select a theme and restart to see the effect", ConfigManager.GetBindable<VRCOSCTheme>(VRCOSCSetting.Theme));
AddFloatSlider("UI Scaling", "Change the UI scale multiplier", uiScaleBindableNumber);
AddTextBox<IntTextBox, int>("ChatBox Update Rate", "The ChatBox update rate (milliseconds)", ConfigManager.GetBindable<int>(VRCOSCSetting.ChatBoxTimeSpan), chatbox_timespan_url);
AddToggle("ChatBox Blacklist", "Blocks the ChatBox from being used when in common club/event worlds", ConfigManager.GetBindable<bool>(VRCOSCSetting.ChatboxWorldBlock), "https://github.com/cyberkitsune/chatbox-club-blacklist/blob/master/npblacklist.json");
AddToggle("Tray on close", "Tells VRCOSC to minimise to the tray when the X is pressed", ConfigManager.GetBindable<bool>(VRCOSCSetting.TrayOnClose));
}
}
3 changes: 2 additions & 1 deletion VRCOSC.Game/Managers/ChatBoxManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using VRCOSC.Game.ChatBox.Serialisation.V1;
using VRCOSC.Game.OSC.VRChat;
using VRCOSC.Game.Serialisation;
using VRCOSC.Game.Util;

namespace VRCOSC.Game.Managers;

Expand Down Expand Up @@ -146,7 +147,7 @@ public Clip CreateClip()

public void Update()
{
if (sendAllowed)
if (sendAllowed && !CurrentWorldExtractor.IsCurrentWorldBlacklisted)
{
appManager.ModuleManager.ChatBoxUpdate();

Expand Down
51 changes: 29 additions & 22 deletions VRCOSC.Game/Modules/Module.cs
Original file line number Diff line number Diff line change
Expand Up @@ -446,37 +446,44 @@ protected void SendParameter<T>(Enum lookup, T value) where T : struct

internal virtual void OnParameterReceived(VRChatOscMessage message)
{
var receivedParameter = new ReceivedParameter(message.ParameterName, message.ParameterValue);

try
{
OnAnyParameterReceived(receivedParameter);
}
catch (Exception e)
{
PushException(e);
}
var receivedParameter = new ReceivedParameter(message.ParameterName, message.ParameterValue);

var parameterName = Parameters.Values.FirstOrDefault(moduleParameter => parameterNameRegex[moduleParameter.ParameterName].IsMatch(receivedParameter.Name))?.ParameterName;
if (parameterName is null) return;
try
{
OnAnyParameterReceived(receivedParameter);
}
catch (Exception e)
{
PushException(e);
}

if (!parameterNameEnum.TryGetValue(parameterName, out var lookup)) return;
var parameterName = Parameters.Values.FirstOrDefault(moduleParameter => parameterNameRegex[moduleParameter.ParameterName].IsMatch(receivedParameter.Name))?.ParameterName;
if (string.IsNullOrEmpty(parameterName)) return;

var parameterData = Parameters[lookup];
if (!parameterNameEnum.TryGetValue(parameterName, out var lookup)) return;

if (!parameterData.Mode.HasFlagFast(ParameterMode.Read)) return;
var parameterData = Parameters[lookup];

if (!receivedParameter.IsValueType(parameterData.ExpectedType))
{
Log($"Cannot accept input parameter. `{lookup}` expects type `{parameterData.ExpectedType}` but received type `{receivedParameter.Value.GetType()}`");
return;
}
if (!parameterData.Mode.HasFlagFast(ParameterMode.Read)) return;

var registeredParameter = new RegisteredParameter(receivedParameter, lookup, parameterData);
if (!receivedParameter.IsValueType(parameterData.ExpectedType))
{
Log($"Cannot accept input parameter. `{lookup}` expects type `{parameterData.ExpectedType}` but received type `{receivedParameter.Value.GetType()}`");
return;
}

try
{
ModuleParameterReceived(registeredParameter);
var registeredParameter = new RegisteredParameter(receivedParameter, lookup, parameterData);

try
{
ModuleParameterReceived(registeredParameter);
}
catch (Exception e)
{
PushException(e);
}
}
catch (Exception e)
{
Expand Down
18 changes: 17 additions & 1 deletion VRCOSC.Game/OSC/VRChat/VRChatOscMessage.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) VolcanicArts. Licensed under the GPL-3.0 License.
// See the LICENSE file in the repository root for full license text.

using System;
using VRCOSC.Game.OSC.Client;

namespace VRCOSC.Game.OSC.VRChat;
Expand All @@ -11,7 +12,22 @@ public class VRChatOscMessage : OscMessage
public bool IsAvatarParameter => Address.StartsWith(VRChatOscConstants.ADDRESS_AVATAR_PARAMETERS_PREFIX);

private string? parameterName;
public string ParameterName => parameterName ??= Address[(VRChatOscConstants.ADDRESS_AVATAR_PARAMETERS_PREFIX.Length + 1)..];

public string ParameterName
{
get
{
try
{
return parameterName ??= Address[(VRChatOscConstants.ADDRESS_AVATAR_PARAMETERS_PREFIX.Length + 1)..];
}
// This should never be possible if ParameterName is only called after IsAvatarParameter, but sometimes there's a corrupt address?
catch (Exception)
{
return string.Empty;
}
}
}

public object ParameterValue => Values[0];

Expand Down
115 changes: 115 additions & 0 deletions VRCOSC.Game/Util/CurrentWorldExtractor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// Copyright (c) VolcanicArts. Licensed under the GPL-3.0 License.
// See the LICENSE file in the repository root for full license text.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Newtonsoft.Json;
using osu.Framework.Logging;

namespace VRCOSC.Game.Util;

public static class CurrentWorldExtractor
{
private const string blacklist_url = "https://github.com/cyberkitsune/chatbox-club-blacklist/raw/master/npblacklist.json";
private static readonly string logfile_location = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData).Replace("Roaming", "LocalLow"), "VRChat", "VRChat");
private const string logfile_pattern = "output_log_*";
private static readonly Regex world_regex = new("Fetching world information for (wrld_.*)");

private static Blacklist? blacklist;
private static IEnumerable<string>? ids;

public static bool IsCurrentWorldBlacklisted { get; private set; }
public static string? CurrentWorldId { get; private set; }

public static async void UpdateCurrentWorld()
{
await requestBlacklist();

if (blacklist is null || ids is null)
{
IsCurrentWorldBlacklisted = false;
return;
}

var newCurrentWorldId = await getCurrentWorldId();
if (newCurrentWorldId == CurrentWorldId) return;

CurrentWorldId = newCurrentWorldId;
Logger.Log($"World change detected: {CurrentWorldId}");

if (CurrentWorldId is null)
{
IsCurrentWorldBlacklisted = false;
return;
}

IsCurrentWorldBlacklisted = ids.Contains(CurrentWorldId);
Logger.Log($"Is world blacklisted?: {IsCurrentWorldBlacklisted}");
}

private static async Task requestBlacklist()
{
try
{
if (blacklist is not null) return;

using var client = new HttpClient();

var response = await client.GetAsync(blacklist_url);
response.EnsureSuccessStatusCode();

var content = await response.Content.ReadAsStringAsync();
blacklist = JsonConvert.DeserializeObject<Blacklist>(content);
if (blacklist is null) return;

ids = blacklist.Worlds.Select(world => world.ID);
}
catch (Exception)
{
blacklist = null;
ids = null;
}
}

private static async Task<string?> getCurrentWorldId()
{
try
{
var logFile = Directory.GetFiles(logfile_location, logfile_pattern).MaxBy(d => new FileInfo(d).CreationTime);
if (logFile is null) return null;

using var fileStream = new FileStream(logFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
using var textReader = new StreamReader(fileStream);
var content = await textReader.ReadToEndAsync();

var latestWorld = world_regex.Matches(content).LastOrDefault()?.Groups.Values.LastOrDefault();
if (latestWorld is null) return null;

var latestWorldId = latestWorld.Captures.FirstOrDefault();
if (latestWorldId is null) return null;

return latestWorldId.Value;
}
catch (Exception)
{
return null;
}
}
}

public class Blacklist
{
[JsonProperty("worlds")]
public List<BlacklistedWorld> Worlds = new();
}

public class BlacklistedWorld
{
[JsonProperty("id")]
public string ID = null!;
}
2 changes: 1 addition & 1 deletion 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.1007.0</Version>
<Version>2024.220.0</Version>
<Title>VRCOSC SDK</Title>
<Authors>VolcanicArts</Authors>
<Description>SDK for creating custom modules with VRCOSC</Description>
Expand Down
17 changes: 2 additions & 15 deletions VRCOSC.Modules/Maths/MathsModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ namespace VRCOSC.Modules.Maths;
[ModuleAuthor("VolcanicArts")]
public class MathsModule : AvatarModule
{
private readonly Dictionary<string, ReceivedParameter> parameterValues = new();
private readonly Dictionary<string, MathsEquationInstance> instances = new();
private readonly List<PrimitiveElement> elements = new();

Expand All @@ -37,7 +36,6 @@ protected override void CreateAttributes()

protected override void OnModuleStart()
{
parameterValues.Clear();
instances.Clear();
elements.Clear();

Expand All @@ -50,11 +48,9 @@ protected override void OnModuleStart()

protected override async void OnAnyParameterReceived(ReceivedParameter parameter)
{
parameterValues[parameter.Name] = parameter;

if (!instances.TryGetValue(parameter.Name, out var instance)) return;

var expression = new Expression(instance.Equation.Value, parameterValues.Values.Select(createArgumentForParameterValue).Concat(elements).ToArray());
var expression = new Expression(instance.Equation.Value, elements.ToArray());
expression.disableImpliedMultiplicationMode();

foreach (var missingArgument in expression.getMissingUserDefinedArguments())
Expand Down Expand Up @@ -89,15 +85,6 @@ protected override async void OnAnyParameterReceived(ReceivedParameter parameter
SendParameter(instance.OutputParameter.Value, finalValue);
}

private static PrimitiveElement createArgumentForParameterValue(ReceivedParameter parameter)
{
if (parameter.IsValueType<bool>()) return new Argument(parameter.Name, parameter.ValueAs<bool>() ? 1 : 0);
if (parameter.IsValueType<int>()) return new Argument(parameter.Name, parameter.ValueAs<int>());
if (parameter.IsValueType<float>()) return new Argument(parameter.Name, parameter.ValueAs<float>());

throw new InvalidOperationException("Unknown parameter type");
}

private object convertToOutputType(double value, TypeCode valueType)
{
try
Expand All @@ -112,7 +99,7 @@ private object convertToOutputType(double value, TypeCode valueType)
}
catch (Exception e)
{
Log($"Warning. Value {value}. " + e.Message);
Log($"Output error for value '{value}': '{e.Message}'");

return valueType switch
{
Expand Down
Loading

0 comments on commit f68528a

Please sign in to comment.