Skip to content

Commit

Permalink
Merge pull request #36 from ChanyaVRC/dev/1.4.x
Browse files Browse the repository at this point in the history
Release v1.4.3
  • Loading branch information
ChanyaVRC authored Dec 20, 2022
2 parents 77a2b3f + 0b8927a commit 39a0b56
Show file tree
Hide file tree
Showing 38 changed files with 1,152 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
<TargetFramework Condition="!$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Windows)))">net6.0</TargetFramework>
<Nullable>enable</Nullable>
<RootNamespace>BuildSoft.VRChat.Osc.Test</RootNamespace>
<LangVersion>10.0</LangVersion>
<LangVersion>11.0</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<IsPackable>false</IsPackable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.1" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" version="4.3.1" />
<PackageReference Include="coverlet.collector" Version="3.2.0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,10 @@ public void CtorTest()
Assert.IsNull(parameter3.Output);
Assert.AreEqual(input.Address, parameter3.ReadableAddress);
}

[Test]
public void Ctor_BothNullTest()
{
Assert.Throws<ArgumentException>(() => new OscAvatarParameter("param", null, null));
}
}
10 changes: 10 additions & 0 deletions src/VRCOscLib/Tests/vrcosclib.Test/Utility/OscParameterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ public async Task SendAvatarParameterTest()
Assert.AreEqual(10, value.ReadIntElementUnchecked(0));
value = null;

OscParameter.SendAvatarParameter(ParamName, 1234567890123456789);
await LoopWhile(() => value == null, LatencyTimeout);
Assert.AreEqual(1234567890123456789, value.ReadInt64ElementUnchecked(0));
value = null;

OscParameter.SendAvatarParameter(ParamName, true);
await LoopWhile(() => value == null, LatencyTimeout);
Assert.AreEqual(true, value.ReadBooleanElement(0));
Expand Down Expand Up @@ -137,6 +142,11 @@ public async Task SendValueTest()
Assert.AreEqual(10, value.ReadIntElementUnchecked(0));
value = null;

OscParameter.SendValue(Address, 1234567890123456789);
await LoopWhile(() => value == null, LatencyTimeout);
Assert.AreEqual(1234567890123456789, value.ReadInt64ElementUnchecked(0));
value = null;

OscParameter.SendValue(Address, true);
await LoopWhile(() => value == null, LatencyTimeout);
Assert.AreEqual(true, value.ReadBooleanElement(0));
Expand Down
6 changes: 3 additions & 3 deletions src/VRCOscLib/Tests/vrcosclib.Test/vrcosclib.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
<TargetFramework Condition="!$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Windows)))">net6.0</TargetFramework>
<Nullable>enable</Nullable>
<RootNamespace>BuildSoft.VRChat.Osc.Test</RootNamespace>
<LangVersion>10.0</LangVersion>
<LangVersion>11.0</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<IsPackable>false</IsPackable>
<IsPackable>false</IsPackable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
</PropertyGroup>

Expand All @@ -16,7 +16,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.1" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" version="4.3.1" />
<PackageReference Include="coverlet.collector" Version="3.2.0" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
namespace BuildSoft.VRChat.Osc.Avatar;

/// <summary>
/// Represents a delegate for handling changes to an <see cref="OscAvatarParameter"/>.
/// </summary>
/// <param name="parameter">The <see cref="OscAvatarParameter"/> that has changed.</param>
/// <param name="e">The <see cref="ValueChangedEventArgs"/> containing the old and new values.</param>
public delegate void OscAvatarParameterChangedEventHandler(OscAvatarParameter parameter, ValueChangedEventArgs e);
13 changes: 13 additions & 0 deletions src/VRCOscLib/VRCOscLib/Avatar/OscAvatar.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,21 @@
namespace BuildSoft.VRChat.Osc.Avatar;

/// <summary>
/// Represents a VRChat avatar, as identified by its unique ID.
/// </summary>
public struct OscAvatar
{
/// <summary>
/// The unique ID of the avatar.
/// </summary>
public string? Id { get; set; }

/// <summary>
/// Converts the avatar to an <see cref="OscAvatarConfig"/> object.
/// </summary>
/// <returns>
/// An <see cref="OscAvatarConfig"/> object representing the avatar,
/// or null if the avatar does not have a valid ID.
/// </returns>
public OscAvatarConfig? ToConfig() => Id == null ? null : OscAvatarConfig.Create(Id);
}
62 changes: 62 additions & 0 deletions src/VRCOscLib/VRCOscLib/Avatar/OscAvatarConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,57 @@

namespace BuildSoft.VRChat.Osc.Avatar;

/// <summary>
/// Represents the configuration of a VRChat avatar, including its unique ID, name, and a list of avatar parameters.
/// </summary>
public class OscAvatarConfig
{
#pragma warning disable IDE0044 // Add readonly modifier
/// <summary>
/// The unique ID of the avatar.
/// </summary>
[JsonProperty("id", Required = Required.Always)]
private string _id = string.Empty;

/// <summary>
/// The name of the avatar.
/// </summary>
[JsonProperty("name", Required = Required.Always)]
private string _name = string.Empty;
#pragma warning restore IDE0044 // Add readonly modifier

/// <summary>
/// The list of avatar parameters.
/// </summary>
[JsonProperty("parameters", Required = Required.Always)]
private readonly List<OscAvatarParameter> _parametersList = new();

/// <summary>
/// Gets the unique ID of the avatar.
/// </summary>
public string Id => _id;
/// <summary>
/// Gets the name of the avatar.
/// </summary>
public string Name => _name;

[JsonIgnore]
private OscAvatarParametorContainer? _parameters;

/// <summary>
/// Gets the list of avatar parameters.
/// </summary>
[JsonIgnore]
public OscAvatarParametorContainer Parameters => _parameters ??= new(_parametersList);

/// <summary>
/// Gets a value indicating whether the avatar parameters have been created.
/// </summary>
internal bool IsCreatedParameters => _parameters != null;

/// <summary>
/// Gets any additional information that was not explicitly defined in the <see cref="OscAvatarConfig"/> class, but was present in the avatar configuration file.
/// </summary>
[field: JsonExtensionData]
public Dictionary<string, object> Extra { get; } = new();

Expand All @@ -35,6 +63,17 @@ private OscAvatarConfig()
OscAvatarUtility.RegisterAvaterConfig(this);
}

/// <summary>
/// Initializes a new instance of the <see cref="OscAvatarConfig"/> class with the specified avatar ID, name, and parameters.
/// </summary>
/// <param name="id">The unique ID of the avatar.</param>
/// <param name="name">The name of the avatar.</param>
/// <param name="parameters">The avatar parameters.</param>
/// <exception cref="ArgumentException">
/// <paramref name="id"/> is empty.
/// or
/// <paramref name="name"/> is empty.
/// </exception>
public OscAvatarConfig(string id, string name, IEnumerable<OscAvatarParameter> parameters)
: this()
{
Expand All @@ -53,12 +92,20 @@ public OscAvatarConfig(string id, string name, IEnumerable<OscAvatarParameter> p
}


/// <summary>
/// Creates an array of all <see cref="OscAvatarConfig"/> instances in the current directory.
/// </summary>
/// <returns>An array of all <see cref="OscAvatarConfig"/> instances in the current directory.</returns>
public static OscAvatarConfig[] CreateAll() =>
OscUtility.EnumerateOscAvatarConfigPathes()
.AsParallel()
.Select(GetAvatarConfig)
.Where(config => config != null).ToArray()!;

/// <summary>
/// Creates an instance of <see cref="OscAvatarConfig"/> from the currently active avatar.
/// </summary>
/// <returns>An instance of <see cref="OscAvatarConfig"/> from the currently active avatar, or <see langword="null"/> if no avatar is active.</returns>
public static OscAvatarConfig? CreateAtCurrent()
{
var path = OscUtility.GetCurrentOscAvatarConfigPath();
Expand All @@ -69,11 +116,21 @@ public static OscAvatarConfig[] CreateAll() =>
return GetAvatarConfig(path);
}

/// <summary>
/// Creates an instance of <see cref="OscAvatarConfig"/> with the specified ID.
/// </summary>
/// <param name="avatarId">The ID of the avatar to create.</param>
/// <returns>An instance of <see cref="OscAvatarConfig"/> with the specified ID, or <see langword="null"/> if no avatar with the specified ID exists.</returns>
public static OscAvatarConfig? Create(string avatarId)
{
return GetAvatarConfig(OscUtility.GetOscAvatarConfigPath(avatarId));
}

/// <summary>
/// Asynchronously waits until the current avatar is received, and creates the avatar config.
/// </summary>
/// <returns>The <see cref="OscAvatarConfig"/> object that was deserialized.</returns>
/// <exception cref="JsonSerializationException">Thrown if deserialization of the avatar configuration file fails.</exception>
public static async ValueTask<OscAvatarConfig> WaitAndCreateAtCurrentAsync()
{
var path = await OscUtility.WaitAndGetCurrentOscAvatarConfigPathAsync();
Expand All @@ -85,6 +142,11 @@ public static async ValueTask<OscAvatarConfig> WaitAndCreateAtCurrentAsync()
return config;
}

/// <summary>
/// Deserializes the avatar configuration file at the specified path.
/// </summary>
/// <param name="path">The path of the avatar configuration file to deserialize.</param>
/// <returns>The <see cref="OscAvatarConfig"/> object that was deserialized, or <see langword="null"/> if deserialization failed.</returns>
private static OscAvatarConfig? GetAvatarConfig(string path)
=> JsonConvert.DeserializeObject<OscAvatarConfig>(File.ReadAllText(path));
}
37 changes: 37 additions & 0 deletions src/VRCOscLib/VRCOscLib/Avatar/OscAvatarParameter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,67 @@

namespace BuildSoft.VRChat.Osc.Avatar;

/// <summary>
/// The model of an avatar parameter.
/// </summary>
[JsonObject]
public record class OscAvatarParameter
{
#pragma warning disable IDE0044 // Add readonly modifier
/// <summary>
/// Gets the name of the parameter.
/// </summary>
[JsonProperty("name", Required = Required.Always)]
private string _name = string.Empty;

/// <summary>
/// Gets the input interface for the parameter.
/// </summary>
[JsonProperty("input", Required = Required.DisallowNull)]
private OscAvatarParameterInterface? _input;

/// <summary>
/// Gets the output interface for the parameter.
/// </summary>
[JsonProperty("output", Required = Required.DisallowNull)]
private OscAvatarParameterInterface? _output;
#pragma warning restore IDE0044 // Add readonly modifier

/// <summary>
/// Gets the name of the parameter.
/// </summary>
public string Name => _name;

/// <summary>
/// Gets the input interface for the parameter.
/// </summary>
public OscAvatarParameterInterface? Input => _input;

/// <summary>
/// Gets the output interface for the parameter.
/// </summary>
public OscAvatarParameterInterface? Output => _output;

/// <summary>
/// Gets the readable address for the parameter.
/// </summary>
public string ReadableAddress => (Output ?? Input)!.Address;

/// <summary>
/// Initializes a new instance of the <see cref="OscAvatarParameter"/> class.
/// </summary>
[JsonConstructor]
private OscAvatarParameter()
{

}

/// <summary>
/// Initializes a new instance of the <see cref="OscAvatarParameter"/> class.
/// </summary>
/// <param name="name">The name of the parameter.</param>
/// <param name="input">The input interface for the parameter.</param>
/// <param name="output">The output interface for the parameter.</param>
public OscAvatarParameter(string name, OscAvatarParameterInterface? input = null, OscAvatarParameterInterface? output = null)
{
if (input == null && output == null)
Expand Down
36 changes: 36 additions & 0 deletions src/VRCOscLib/VRCOscLib/Avatar/OscAvatarParameterInterface.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,39 @@

namespace BuildSoft.VRChat.Osc.Avatar;

/// <summary>
/// This class provides an interface for Open Sound Control (OSC) messages to avatar parameter.
/// </summary>
[JsonObject]
public class OscAvatarParameterInterface
{
#pragma warning disable IDE0044 // Add readonly modifier
/// <summary>
/// Gets the address of the parameter interface.
/// </summary>
[JsonProperty("address", Required = Required.Always)]
private string _address = string.Empty;

/// <summary>
/// Gets the blob string for the address of the parameter interface.
/// </summary>
private BlobString _addressBlob = default;

/// <summary>
/// Gets the OSC type of the parameter interface.
/// </summary>
[JsonProperty("type", Required = Required.Always, ItemConverterType = typeof(StringEnumConverter))]
private OscType _type = 0;
#pragma warning restore IDE0044 // Add readonly modifier

/// <summary>
/// Gets the address of the parameter interface.
/// </summary>
public string Address => _address;

/// <summary>
/// Gets the blob string for the address of the parameter interface.
/// </summary>
public BlobString AddressBlob
{
get
Expand All @@ -28,16 +49,31 @@ public BlobString AddressBlob
}
}

/// <summary>
/// Gets the OSC type of the parameter interface.
/// </summary>
public OscType OscType => _type;

/// <summary>
/// Gets the OSC type of the parameter interface as a string.
/// </summary>
public string Type => _type.ToString();


/// <summary>
/// Initializes a new instance of the <see cref="OscAvatarParameterInterface"/> class.
/// </summary>
[JsonConstructor]
private OscAvatarParameterInterface()
{

}

/// <summary>
/// Initializes a new instance of the <see cref="OscAvatarParameterInterface"/> class.
/// </summary>
/// <param name="address">The address of the parameter interface.</param>
/// <param name="type">The OSC type of the parameter interface.</param>
public OscAvatarParameterInterface(string address, OscType type)
{
_address = address;
Expand Down
Loading

0 comments on commit 39a0b56

Please sign in to comment.