Skip to content

Commit

Permalink
Merge pull request #35 from ChanyaVRC/dev/1.4.x
Browse files Browse the repository at this point in the history
Release v1.4.2
  • Loading branch information
ChanyaVRC authored Dec 9, 2022
2 parents 01ce636 + b112c28 commit 77a2b3f
Show file tree
Hide file tree
Showing 12 changed files with 420 additions and 24 deletions.
128 changes: 128 additions & 0 deletions src/VRCOscLib/Tests/vrcosclib.Test/Tracking/OscTrackerTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
using BuildSoft.OscCore;
using BuildSoft.OscCore.UnityObjects;
using BuildSoft.VRChat.Osc.Test;
using NUnit.Framework;

namespace BuildSoft.VRChat.Osc.Tracking.Test;

[TestOf(typeof(OscTracker))]
public class OscTrackerTest
{
private static IEnumerable<int> ValidRangeSource
{
get
{
yield return 0;
yield return OscTracker.SupportedTrackerCount / 2;
yield return OscTracker.SupportedTrackerCount - 1;
}
}

private static IEnumerable<int> InvalidRangeSource
{
get
{
yield return -1;
yield return OscTracker.SupportedTrackerCount;
yield return int.MaxValue;
yield return int.MinValue;
}
}


private OscClient _client = null!;
private OscServer _server = null!;

[SetUp]
public void Setup()
{
OscParameter.Parameters.Clear();
}

[TearDown]
public void TearDown()
{

}

[OneTimeSetUp]
public void OneTimeSetUp()
{
_client = new OscClient("127.0.0.1", OscUtility.ReceivePort);
_server = new OscServer(OscUtility.SendPort);
}

[OneTimeTearDown]
public void OneTimeTearDown()
{
_client.Dispose();
_server.Dispose();
}


[TestCaseSource(nameof(ValidRangeSource))]
public void Ctor_ValidRangeTest(int index)
{
Assert.DoesNotThrow(() => new OscTracker(index));

OscTracker tracker = new(index);
Assert.AreEqual($"/tracking/trackers/{index + 1}/position", tracker.PositionAddress);
Assert.AreEqual($"/tracking/trackers/{index + 1}/rotation", tracker.RotationAddress);
}

[TestCaseSource(nameof(InvalidRangeSource))]
public void Ctor_InvalidRangeTest(int index)
{
var exception = Assert.Throws<ArgumentOutOfRangeException>(() => new OscTracker(index));

Assert.NotNull(exception);
Assert.AreEqual("index", exception!.ParamName);
}


[Test]
public async Task PositionTest()
{
var tracker = new OscTracker(0);
Assert.AreEqual(new Vector3(), tracker.Position);

OscMessageValues value = null!;
void valueReadMethod(OscMessageValues v) => value = v;
_server.TryAddMethod(tracker.PositionAddress, valueReadMethod);

var expected = new Vector3(10.1f, 20.2f, 30.3f);

tracker.Position = expected;
await TestUtility.LoopWhile(() => value == null, TestUtility.LatencyTimeout);

Assert.AreEqual(expected, tracker.Position);
Assert.AreEqual(expected.x, value.ReadFloatElement(0));
Assert.AreEqual(expected.y, value.ReadFloatElement(1));
Assert.AreEqual(expected.z, value.ReadFloatElement(2));

Assert.AreEqual(expected, new OscTracker(0).Position);
}

[Test]
public async Task RotationTest()
{
var tracker = new OscTracker(0);
Assert.AreEqual(new Vector3(), tracker.Rotation);

OscMessageValues value = null!;
void valueReadMethod(OscMessageValues v) => value = v;
_server.TryAddMethod(tracker.RotationAddress, valueReadMethod);

var expected = new Vector3(10.1f, 20.2f, 30.3f);

tracker.Rotation = expected;
await TestUtility.LoopWhile(() => value == null, TestUtility.LatencyTimeout);

Assert.AreEqual(expected, tracker.Rotation);
Assert.AreEqual(expected.x, value.ReadFloatElement(0));
Assert.AreEqual(expected.y, value.ReadFloatElement(1));
Assert.AreEqual(expected.z, value.ReadFloatElement(2));

Assert.AreEqual(expected, new OscTracker(0).Rotation);
}
}
145 changes: 145 additions & 0 deletions src/VRCOscLib/Tests/vrcosclib.Test/Tracking/OscTrackingTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
using BuildSoft.OscCore;
using BuildSoft.OscCore.UnityObjects;
using BuildSoft.VRChat.Osc.Test;
using NUnit.Framework;

namespace BuildSoft.VRChat.Osc.Tracking.Test;

[TestOf(typeof(OscTracking))]
public class OscTrackingTest
{
private OscClient _client = null!;
private OscServer _server = null!;

[SetUp]
public void Setup()
{
OscParameter.Parameters.Clear();
}

[TearDown]
public void TearDown()
{

}

[OneTimeSetUp]
public void OneTimeSetUp()
{
_client = new OscClient("127.0.0.1", OscUtility.ReceivePort);
_server = new OscServer(OscUtility.SendPort);
}

[OneTimeTearDown]
public void OneTimeTearDown()
{
_client.Dispose();
_server.Dispose();
}


[Test]
public void HeadTracker_AddressTest()
{
var headTracker = OscTracking.HeadTracker;

Assert.AreEqual("/tracking/trackers/head/position", headTracker.PositionAddress);
Assert.AreEqual("/tracking/trackers/head/rotation", headTracker.RotationAddress);
}

[Test]
public async Task HeadTracker_PositionSetTest()
{
var headTracker = OscTracking.HeadTracker;

OscMessageValues value = null!;
void valueReadMethod(OscMessageValues v) => value = v;
_server.TryAddMethod(headTracker.PositionAddress, valueReadMethod);

var expected = new Vector3(10.1f, 20.2f, 30.3f);

headTracker.Position = expected;
await TestUtility.LoopWhile(() => value == null, TestUtility.LatencyTimeout);

Assert.AreEqual(expected, headTracker.Position);
Assert.AreEqual(expected.x, value.ReadFloatElement(0));
Assert.AreEqual(expected.y, value.ReadFloatElement(1));
Assert.AreEqual(expected.z, value.ReadFloatElement(2));
}

[Test]
public async Task HeadTracker_RotationSetTest()
{
var headTracker = OscTracking.HeadTracker;

OscMessageValues value = null!;
void valueReadMethod(OscMessageValues v) => value = v;
_server.TryAddMethod(headTracker.RotationAddress, valueReadMethod);

var expected = new Vector3(10.1f, 20.2f, 30.3f);

headTracker.Rotation = expected;
await TestUtility.LoopWhile(() => value == null, TestUtility.LatencyTimeout);

Assert.AreEqual(expected, headTracker.Rotation);
Assert.AreEqual(expected.x, value.ReadFloatElement(0));
Assert.AreEqual(expected.y, value.ReadFloatElement(1));
Assert.AreEqual(expected.z, value.ReadFloatElement(2));
}


[Test]
public async Task HeadTracker_PositionGetTest()
{
var headTracker = OscTracking.HeadTracker;
Assert.AreEqual(new Vector3(), headTracker.Position);

OscMessageValues value = null!;
void valueReadMethod(OscMessageValues v) => value = v;
OscUtility.Server.TryAddMethod(headTracker.PositionAddress, valueReadMethod);

var expected = new Vector3(10.1f, 20.2f, 30.3f);
_client.Send(headTracker.PositionAddress, expected);

await TestUtility.LoopWhile(() => value == null, TestUtility.LatencyTimeout);
Assert.AreEqual(expected, headTracker.Position);

OscUtility.Server.RemoveMethod(headTracker.PositionAddress, valueReadMethod);
}

[Test]
public async Task HeadTracker_RotationGetTest()
{
var headTracker = OscTracking.HeadTracker;
Assert.AreEqual(new Vector3(), headTracker.Position);

OscMessageValues value = null!;
void valueReadMethod(OscMessageValues v) => value = v;
OscUtility.Server.TryAddMethod(headTracker.RotationAddress, valueReadMethod);

var expected = new Vector3(10.1f, 20.2f, 30.3f);
_client.Send(headTracker.RotationAddress, expected);

await TestUtility.LoopWhile(() => value == null, TestUtility.LatencyTimeout);
Assert.AreEqual(expected, headTracker.Rotation);

OscUtility.Server.RemoveMethod(headTracker.RotationAddress, valueReadMethod);
}


[Test]
public void TrackersTest()
{
var trackers = OscTracking.Trackers;

Assert.AreEqual(OscTracker.SupportedTrackerCount, trackers.Length);
Assert.AreEqual("/tracking/trackers/1/position", trackers[0].PositionAddress);
Assert.AreEqual("/tracking/trackers/1/rotation", trackers[0].RotationAddress);

for (int i = 0; i < OscTracker.SupportedTrackerCount; i++)
{
Assert.AreEqual($"/tracking/trackers/{i + 1}/position", trackers[i].PositionAddress);
Assert.AreEqual($"/tracking/trackers/{i + 1}/rotation", trackers[i].RotationAddress);
}
}
}
6 changes: 4 additions & 2 deletions src/VRCOscLib/VRCOscLib/Avatar/Utility/OscAvatarUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@ public static class OscAvatarUtility
"Viseme",
};

internal static List<WeakReference<OscAvatarConfig>> _avatarConfigs = new();
private static List<WeakReference<OscAvatarConfig>>? _avatarConfigs;
internal static List<WeakReference<OscAvatarConfig>> AvatarConfigs => _avatarConfigs ??= new();

internal static void RegisterAvaterConfig(OscAvatarConfig avatarConfig)
{
_avatarConfigs.Add(new WeakReference<OscAvatarConfig>(avatarConfig));
AvatarConfigs.Add(new WeakReference<OscAvatarConfig>(avatarConfig));
}

public static IReadOnlyDictionary<string, object?> CommonParameters
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ public interface IReadOnlyOscParameterCollection : IReadOnlyDictionary<string, o
{
event ParamChangedHandler? ValueChanged;

public void AddValueChangedEventByAddress(string address, ParamChangedHandler handler);
void AddValueChangedEventByAddress(string address, ParamChangedHandler handler);
bool RemoveValueChangedEventByAddress(string address, ParamChangedHandler handler);
}
24 changes: 19 additions & 5 deletions src/VRCOscLib/VRCOscLib/Collections/OscParameterCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ public class OscParameterCollection : IDictionary<string, object?>, IReadOnlyOsc
private readonly Dictionary<string, object?> _items = new();

private Dictionary<string, List<ParamChangedHandler>>? _handlersPerAddress;
private Dictionary<string, List<ParamChangedHandler>> HandlersPerAddress => _handlersPerAddress ??= new();

public object? this[string address]
{
Expand Down Expand Up @@ -107,10 +106,16 @@ protected void OnValueChanged(ParameterChangedEventArgs args)

protected void OnValueChangedByAddress(ParameterChangedEventArgs args)
{
if (!HandlersPerAddress.TryGetValue(args.Address, out var list) || list.Count <= 0)
var handlersPerAddress = _handlersPerAddress;
if (handlersPerAddress == null)
{
return;
}
if (!handlersPerAddress.TryGetValue(args.Address, out var list) || list.Count <= 0)
{
return;
}

var handlers = list.ToArray();
for (int i = 0; i < handlers.Length; i++)
{
Expand All @@ -128,8 +133,13 @@ protected void OnValueChangedByAddress(ParameterChangedEventArgs args)
#region Event registration methods
public void AddValueChangedEventByAddress(string address, ParamChangedHandler handler)
{
var dict = HandlersPerAddress;
if (dict.TryGetValue(address, out var list))
var dict = _handlersPerAddress;
if (dict == null)
{
dict = new();
_handlersPerAddress = dict;
}
else if (dict.TryGetValue(address, out var list))
{
list.Add(handler);
return;
Expand All @@ -139,7 +149,11 @@ public void AddValueChangedEventByAddress(string address, ParamChangedHandler ha

public bool RemoveValueChangedEventByAddress(string address, ParamChangedHandler handler)
{
var dict = HandlersPerAddress;
var dict = _handlersPerAddress;
if (dict == null)
{
return false;
}
if (!dict.TryGetValue(address, out var list))
{
return false;
Expand Down
45 changes: 45 additions & 0 deletions src/VRCOscLib/VRCOscLib/Tracking/OscTracker.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using BuildSoft.OscCore.UnityObjects;

namespace BuildSoft.VRChat.Osc.Tracking;
public class OscTracker
{
public static readonly int SupportedTrackerCount = 8;

public string PositionAddress { get; }
public string RotationAddress { get; }

public Vector3 Position
{
get => OscParameter.GetValueAsVector3(PositionAddress) ?? default;
set => OscParameter.SendValue(PositionAddress, value);
}

public Vector3 Rotation
{
get => OscParameter.GetValueAsVector3(RotationAddress) ?? default;
set => OscParameter.SendValue(RotationAddress, value);
}


/// <summary>
/// Create the OSC tracker.
/// </summary>
/// <param name="index">0 base index. (0 &#x2266; <paramref name="index"/> &lt; <see cref="SupportedTrackerCount"/>)</param>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="index"/> is negative or greater than or equal to <see cref="SupportedTrackerCount"/>.
/// (0 &#x2266; <paramref name="index"/> &lt; <see cref="SupportedTrackerCount"/>)
/// </exception>
public OscTracker(int index) : this((index + 1).ToString())
{
if (index < 0 || index >= SupportedTrackerCount)
{
throw new ArgumentOutOfRangeException(nameof(index));
}
}

internal OscTracker(string part)
{
PositionAddress = $"/tracking/trackers/{part}/position";
RotationAddress = $"/tracking/trackers/{part}/rotation";
}
}
Loading

0 comments on commit 77a2b3f

Please sign in to comment.