mirror of
https://github.com/oliverbooth/VpSharp
synced 2024-11-22 13:48:48 +00:00
[ci skip] Add braces around single-statement bodies
This commit is contained in:
parent
1bf050eca0
commit
693e90bff1
@ -14,8 +14,14 @@ public sealed class Application
|
||||
{
|
||||
Name = name ?? throw new ArgumentNullException(nameof(name));
|
||||
|
||||
if (string.IsNullOrWhiteSpace(version)) Version = null;
|
||||
else Version = version;
|
||||
if (string.IsNullOrWhiteSpace(version))
|
||||
{
|
||||
Version = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
Version = version;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -116,10 +116,25 @@ public readonly struct ColorF : IEquatable<ColorF>
|
||||
/// </exception>
|
||||
public static ColorF FromArgb(float a, float r, float g, float b)
|
||||
{
|
||||
if (a is < 0 or > 1) throw ThrowHelper.ZeroThroughOneException(nameof(a));
|
||||
if (r is < 0 or > 1) throw ThrowHelper.ZeroThroughOneException(nameof(r));
|
||||
if (g is < 0 or > 1) throw ThrowHelper.ZeroThroughOneException(nameof(g));
|
||||
if (b is < 0 or > 1) throw ThrowHelper.ZeroThroughOneException(nameof(b));
|
||||
if (a is < 0 or > 1)
|
||||
{
|
||||
throw ThrowHelper.ZeroThroughOneException(nameof(a));
|
||||
}
|
||||
|
||||
if (r is < 0 or > 1)
|
||||
{
|
||||
throw ThrowHelper.ZeroThroughOneException(nameof(r));
|
||||
}
|
||||
|
||||
if (g is < 0 or > 1)
|
||||
{
|
||||
throw ThrowHelper.ZeroThroughOneException(nameof(g));
|
||||
}
|
||||
|
||||
if (b is < 0 or > 1)
|
||||
{
|
||||
throw ThrowHelper.ZeroThroughOneException(nameof(b));
|
||||
}
|
||||
|
||||
return new ColorF(a, r, g, b);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System.Numerics;
|
||||
using System.Numerics;
|
||||
using VpSharp.Extensions;
|
||||
using VpSharp.Internal;
|
||||
using VpSharp.Internal.NativeAttributes;
|
||||
@ -98,8 +98,16 @@ public sealed class VirtualParadiseAvatar : IEquatable<VirtualParadiseAvatar>
|
||||
/// </returns>
|
||||
public bool Equals(VirtualParadiseAvatar? other)
|
||||
{
|
||||
if (ReferenceEquals(null, other)) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
if (ReferenceEquals(null, other))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(this, other))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return Session == other.Session && User.Equals(other.User);
|
||||
}
|
||||
|
||||
@ -130,7 +138,9 @@ public sealed class VirtualParadiseAvatar : IEquatable<VirtualParadiseAvatar>
|
||||
{
|
||||
// ReSharper disable once InconsistentlySynchronizedField
|
||||
if (this == _client.CurrentAvatar)
|
||||
{
|
||||
return Task.FromException(ThrowHelper.CannotUseSelfException());
|
||||
}
|
||||
|
||||
clickPoint ??= Location.Position;
|
||||
(double x, double y, double z) = clickPoint.Value;
|
||||
@ -143,9 +153,11 @@ public sealed class VirtualParadiseAvatar : IEquatable<VirtualParadiseAvatar>
|
||||
vp_double_set(handle, FloatAttribute.ClickHitY, y);
|
||||
vp_double_set(handle, FloatAttribute.ClickHitZ, z);
|
||||
|
||||
var reason = (ReasonCode) vp_avatar_click(handle, Session);
|
||||
var reason = (ReasonCode)vp_avatar_click(handle, Session);
|
||||
if (reason == ReasonCode.NotInWorld)
|
||||
{
|
||||
return Task.FromException(ThrowHelper.NotInWorldException());
|
||||
}
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
@ -164,7 +176,9 @@ public sealed class VirtualParadiseAvatar : IEquatable<VirtualParadiseAvatar>
|
||||
|
||||
// ReSharper disable once InconsistentlySynchronizedField
|
||||
if (this == _client.CurrentAvatar)
|
||||
{
|
||||
return Task.FromException(ThrowHelper.CannotUseSelfException());
|
||||
}
|
||||
|
||||
lock (_client.Lock)
|
||||
{
|
||||
@ -248,21 +262,25 @@ public sealed class VirtualParadiseAvatar : IEquatable<VirtualParadiseAvatar>
|
||||
vp_double_set(handle, FloatAttribute.MyPitch, pitch);
|
||||
vp_double_set(handle, FloatAttribute.MyYaw, yaw);
|
||||
|
||||
var reason = (ReasonCode) vp_state_change(handle);
|
||||
var reason = (ReasonCode)vp_state_change(handle);
|
||||
if (reason == ReasonCode.NotInWorld)
|
||||
{
|
||||
ThrowHelper.ThrowNotInWorldException();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lock (_client.Lock)
|
||||
{
|
||||
(float x, float y, float z) = (Vector3) position;
|
||||
(float pitch, float yaw, float _) = (Vector3) rotation.ToEulerAngles(false);
|
||||
(float x, float y, float z) = (Vector3)position;
|
||||
(float pitch, float yaw, float _) = (Vector3)rotation.ToEulerAngles(false);
|
||||
|
||||
var reason = (ReasonCode) vp_teleport_avatar(handle, Session, world, x, y, z, yaw, pitch);
|
||||
var reason = (ReasonCode)vp_teleport_avatar(handle, Session, world, x, y, z, yaw, pitch);
|
||||
if (reason == ReasonCode.NotInWorld)
|
||||
{
|
||||
ThrowHelper.ThrowNotInWorldException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,9 @@ public class VirtualParadiseModelObject : VirtualParadiseObject
|
||||
protected internal override void ExtractFromOther(VirtualParadiseObject virtualParadiseObject)
|
||||
{
|
||||
if (virtualParadiseObject is not VirtualParadiseModelObject model)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Action = model.Action;
|
||||
Description = model.Description;
|
||||
|
@ -107,9 +107,20 @@ public sealed class VirtualParadiseModelObjectBuilder : VirtualParadiseObjectBui
|
||||
{
|
||||
IntPtr handle = Client.NativeInstanceHandle;
|
||||
|
||||
if (Action is { } action) vp_string_set(handle, StringAttribute.ObjectAction, action);
|
||||
if (Description is { } description) vp_string_set(handle, StringAttribute.ObjectDescription, description);
|
||||
if (Model is { } model) vp_string_set(handle, StringAttribute.ObjectModel, model);
|
||||
if (Action is { } action)
|
||||
{
|
||||
vp_string_set(handle, StringAttribute.ObjectAction, action);
|
||||
}
|
||||
|
||||
if (Description is { } description)
|
||||
{
|
||||
vp_string_set(handle, StringAttribute.ObjectDescription, description);
|
||||
}
|
||||
|
||||
if (Model is { } model)
|
||||
{
|
||||
vp_string_set(handle, StringAttribute.ObjectModel, model);
|
||||
}
|
||||
|
||||
if (Position is { } position)
|
||||
{
|
||||
@ -147,7 +158,9 @@ public sealed class VirtualParadiseModelObjectBuilder : VirtualParadiseObjectBui
|
||||
if (ModificationTimestamp is { } modificationTimestamp)
|
||||
{
|
||||
if (Mode != ObjectBuilderMode.Load)
|
||||
{
|
||||
throw new InvalidOperationException("Modification timestamp can only be assigned during an object load.");
|
||||
}
|
||||
|
||||
vp_int_set(handle, IntegerAttribute.ObjectTime, (int) modificationTimestamp.ToUnixTimeSeconds());
|
||||
}
|
||||
@ -155,7 +168,9 @@ public sealed class VirtualParadiseModelObjectBuilder : VirtualParadiseObjectBui
|
||||
if (Owner is { } owner)
|
||||
{
|
||||
if (Mode != ObjectBuilderMode.Load)
|
||||
{
|
||||
throw new InvalidOperationException("Owner can only be assigned during an object load.");
|
||||
}
|
||||
|
||||
vp_int_set(handle, IntegerAttribute.ObjectUserId, owner.Id);
|
||||
}
|
||||
|
@ -77,13 +77,21 @@ public abstract class VirtualParadiseObject : IEquatable<VirtualParadiseObject>
|
||||
|
||||
ValueTask SendBegin()
|
||||
{
|
||||
lock (Client.Lock) vp_object_bump_begin(Client.NativeInstanceHandle, Id, session);
|
||||
lock (Client.Lock)
|
||||
{
|
||||
vp_object_bump_begin(Client.NativeInstanceHandle, Id, session);
|
||||
}
|
||||
|
||||
return ValueTask.CompletedTask;
|
||||
}
|
||||
|
||||
ValueTask SendEnd()
|
||||
{
|
||||
lock (Client.Lock) vp_object_bump_end(Client.NativeInstanceHandle, Id, session);
|
||||
lock (Client.Lock)
|
||||
{
|
||||
vp_object_bump_end(Client.NativeInstanceHandle, Id, session);
|
||||
}
|
||||
|
||||
return ValueTask.CompletedTask;
|
||||
}
|
||||
|
||||
@ -115,7 +123,9 @@ public abstract class VirtualParadiseObject : IEquatable<VirtualParadiseObject>
|
||||
public Task ClickAsync(Vector3d? position = null, VirtualParadiseAvatar? target = null)
|
||||
{
|
||||
if (target == Client.CurrentAvatar)
|
||||
{
|
||||
ThrowHelper.ThrowCannotUseSelfException();
|
||||
}
|
||||
|
||||
lock (Client.Lock)
|
||||
{
|
||||
@ -159,17 +169,37 @@ public abstract class VirtualParadiseObject : IEquatable<VirtualParadiseObject>
|
||||
/// <returns><see langword="true" /> if the two objects are equal; otherwise, <see langword="false" />.</returns>
|
||||
public bool Equals(VirtualParadiseObject? other)
|
||||
{
|
||||
if (ReferenceEquals(null, other)) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
if (ReferenceEquals(null, other))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(this, other))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return Location.World.Equals(other.Location.World) && Id == other.Id;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (obj.GetType() != GetType()) return false;
|
||||
if (ReferenceEquals(null, obj))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(this, obj))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj.GetType() != GetType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Equals((VirtualParadiseObject) obj);
|
||||
}
|
||||
|
||||
|
@ -209,7 +209,9 @@ public sealed class VirtualParadiseParticleEmitterObject : VirtualParadiseObject
|
||||
protected internal override void ExtractFromOther(VirtualParadiseObject virtualParadiseObject)
|
||||
{
|
||||
if (virtualParadiseObject is not VirtualParadiseParticleEmitterObject emitter)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
|
||||
PropertyInfo[] properties = typeof(VirtualParadiseParticleEmitterObject).GetProperties(bindingFlags);
|
||||
@ -217,7 +219,9 @@ public sealed class VirtualParadiseParticleEmitterObject : VirtualParadiseObject
|
||||
foreach (PropertyInfo property in properties)
|
||||
{
|
||||
if (property.GetCustomAttribute<SerializationKeyAttribute>() is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
property.SetValue(this, property.GetValue(emitter));
|
||||
}
|
||||
@ -235,7 +239,9 @@ public sealed class VirtualParadiseParticleEmitterObject : VirtualParadiseObject
|
||||
{
|
||||
var serializationKeyAttribute = property.GetCustomAttribute<SerializationKeyAttribute>();
|
||||
if (serializationKeyAttribute is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
keymap.Add(serializationKeyAttribute.Key, property);
|
||||
|
||||
@ -244,7 +250,9 @@ public sealed class VirtualParadiseParticleEmitterObject : VirtualParadiseObject
|
||||
{
|
||||
Type converterType = converterAttribute.ConverterType;
|
||||
if (Activator.CreateInstance(converterType) is ValueConverter converter)
|
||||
{
|
||||
converterMap.Add(serializationKeyAttribute.Key, converter);
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore 612
|
||||
|
@ -26,7 +26,9 @@ public sealed class VirtualParadisePathObject : VirtualParadiseObject
|
||||
protected internal override void ExtractFromOther(VirtualParadiseObject virtualParadiseObject)
|
||||
{
|
||||
if (virtualParadiseObject is not VirtualParadisePathObject path)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Path = (VirtualParadisePath)path.Path.Clone();
|
||||
}
|
||||
@ -55,7 +57,9 @@ public sealed class VirtualParadisePathObject : VirtualParadiseObject
|
||||
buffer.Clear();
|
||||
|
||||
if (version != 1)
|
||||
{
|
||||
throw new NotSupportedException($"Unsupported path version {version}");
|
||||
}
|
||||
|
||||
// path name
|
||||
var name = string.Empty;
|
||||
|
@ -93,8 +93,16 @@ public sealed class VirtualParadiseUser : IEquatable<VirtualParadiseUser>
|
||||
/// </returns>
|
||||
public bool Equals(VirtualParadiseUser? other)
|
||||
{
|
||||
if (ReferenceEquals(null, other)) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
if (ReferenceEquals(null, other))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(this, other))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return Id == other.Id;
|
||||
}
|
||||
|
||||
@ -214,7 +222,9 @@ public sealed class VirtualParadiseUser : IEquatable<VirtualParadiseUser>
|
||||
location = new Location(world, position, rotation);
|
||||
|
||||
if (!suppressTeleport)
|
||||
{
|
||||
await avatar.TeleportAsync(location.Value);
|
||||
}
|
||||
}
|
||||
|
||||
JoinResponse response = reason switch
|
||||
|
@ -89,8 +89,16 @@ public sealed class VirtualParadiseWorld : IEquatable<VirtualParadiseWorld>
|
||||
/// </returns>
|
||||
public bool Equals(VirtualParadiseWorld? other)
|
||||
{
|
||||
if (ReferenceEquals(null, other)) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
if (ReferenceEquals(null, other))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(this, other))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return IsNowhere == other.IsNowhere && Name == other.Name;
|
||||
}
|
||||
|
||||
|
@ -70,11 +70,15 @@ internal static class SpanExtensions
|
||||
{
|
||||
buffer.Append(current);
|
||||
if (index < value.Length - 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (current != ' ')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ReadOnlySpan<byte> span = buffer.AsSpan();
|
||||
var floatValue = span.ToSingle();
|
||||
@ -111,11 +115,15 @@ internal static class SpanExtensions
|
||||
{
|
||||
buffer.Append(current);
|
||||
if (index < value.Length - 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (current != ' ')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ReadOnlySpan<byte> span = buffer.AsSpan();
|
||||
var floatValue = span.ToSingle();
|
||||
@ -155,11 +163,15 @@ internal static class SpanExtensions
|
||||
{
|
||||
buffer.Append(current);
|
||||
if (index < value.Length - 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (current != ' ')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ReadOnlySpan<byte> span = buffer.AsSpan();
|
||||
var floatValue = span.ToDouble();
|
||||
@ -200,11 +212,15 @@ internal static class SpanExtensions
|
||||
{
|
||||
buffer.Append(current);
|
||||
if (index < value.Length - 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (current != ' ')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ReadOnlySpan<byte> span = buffer.AsSpan();
|
||||
var floatValue = span.ToSingle();
|
||||
|
@ -17,13 +17,19 @@ internal sealed class ValueConverterAttribute : Attribute
|
||||
public ValueConverterAttribute(Type converterType, params object?[]? args)
|
||||
{
|
||||
if (converterType is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(converterType));
|
||||
}
|
||||
|
||||
if (converterType.IsAbstract)
|
||||
{
|
||||
throw new ArgumentException("Cannot use abstract converter.");
|
||||
}
|
||||
|
||||
if (!converterType.IsSubclassOf(typeof(ValueConverter)))
|
||||
{
|
||||
throw new ArgumentException($"Converter does not inherit {typeof(ValueConverter)}");
|
||||
}
|
||||
|
||||
ConverterType = converterType;
|
||||
Args = args;
|
||||
|
@ -60,7 +60,11 @@ internal class Connection
|
||||
GCHandle handle = GCHandle.FromIntPtr(ptr);
|
||||
var connection = handle.Target as Connection;
|
||||
string host = Marshal.PtrToStringAnsi(hostPtr);
|
||||
if (connection is not null) return connection.Connect(host, port);
|
||||
if (connection is not null)
|
||||
{
|
||||
return connection.Connect(host, port);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -83,7 +87,10 @@ internal class Connection
|
||||
|
||||
private void HandleTimeout()
|
||||
{
|
||||
if (_timer != null) Notify(NetworkNotification.Timeout, 0);
|
||||
if (_timer != null)
|
||||
{
|
||||
Notify(NetworkNotification.Timeout, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private static void HandleTimeout(object state)
|
||||
@ -96,13 +103,18 @@ internal class Connection
|
||||
lock (_lockObject)
|
||||
{
|
||||
if (_vpConnection != IntPtr.Zero)
|
||||
{
|
||||
Native.vp_net_notify(_vpConnection, (int) notification, rc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int Receive(IntPtr data, uint length)
|
||||
{
|
||||
if (_readyBuffers.Count == 0) return (int) NetworkReturnCode.WouldBlock;
|
||||
if (_readyBuffers.Count == 0)
|
||||
{
|
||||
return (int) NetworkReturnCode.WouldBlock;
|
||||
}
|
||||
|
||||
var spaceLeft = (int) length;
|
||||
IntPtr destination = data;
|
||||
@ -134,7 +146,11 @@ internal class Connection
|
||||
|
||||
private static void ReceiveCallback(IAsyncResult ar)
|
||||
{
|
||||
if (ar.AsyncState is not Connection connection) return;
|
||||
if (ar.AsyncState is not Connection connection)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int bytesRead;
|
||||
|
||||
try
|
||||
@ -176,14 +192,18 @@ internal class Connection
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
connection.Notify(NetworkNotification.Disconnect, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int ReceiveNative(IntPtr ptr, IntPtr data, uint length)
|
||||
{
|
||||
if (GCHandle.FromIntPtr(ptr).Target is Connection connection)
|
||||
{
|
||||
return connection.Receive(data, length);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -205,7 +225,9 @@ internal class Connection
|
||||
public static int SendNative(IntPtr ptr, IntPtr data, uint length)
|
||||
{
|
||||
if (GCHandle.FromIntPtr(ptr).Target is Connection connection)
|
||||
{
|
||||
return connection.Send(data, length);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -213,9 +235,13 @@ internal class Connection
|
||||
public int Timeout(int seconds)
|
||||
{
|
||||
if (seconds < 0)
|
||||
{
|
||||
_timer = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
_timer = new Timer(HandleTimeout, this, seconds * 1000, global::System.Threading.Timeout.Infinite);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -223,7 +249,9 @@ internal class Connection
|
||||
public static int TimeoutNative(IntPtr ptr, int seconds)
|
||||
{
|
||||
if (GCHandle.FromIntPtr(ptr).Target is Connection connection)
|
||||
{
|
||||
return connection.Timeout(seconds);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -11,9 +11,14 @@ internal static class ObjectReferenceCounter
|
||||
int ret;
|
||||
Rwl.EnterWriteLock();
|
||||
if (s_reference < int.MaxValue)
|
||||
{
|
||||
ret = s_reference++;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = s_reference = int.MinValue;
|
||||
}
|
||||
|
||||
Rwl.ExitWriteLock();
|
||||
return ret;
|
||||
}
|
||||
|
@ -13,6 +13,8 @@ internal sealed class UriConverter : ValueConverter<Uri>
|
||||
public override void Serialize(TextWriter writer, Uri value)
|
||||
{
|
||||
if (value is not null)
|
||||
{
|
||||
writer.Write(value.ToString());
|
||||
}
|
||||
}
|
||||
}
|
@ -18,10 +18,14 @@ internal sealed class Vector2Converter : ValueConverter<Vector2>
|
||||
|
||||
var currentChar = (char) readChar;
|
||||
if (currentChar == ' ')
|
||||
{
|
||||
spaceCount++;
|
||||
}
|
||||
|
||||
if (spaceCount < 2 && readChar != -1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result = builder.AsSpan().ToVector2();
|
||||
break;
|
||||
|
@ -18,10 +18,14 @@ internal sealed class Vector3Converter : ValueConverter<Vector3>
|
||||
|
||||
var currentChar = (char) readChar;
|
||||
if (currentChar == ' ')
|
||||
{
|
||||
spaceCount++;
|
||||
}
|
||||
|
||||
if (spaceCount < 3 && readChar != -1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result = builder.AsSpan().ToVector3();
|
||||
break;
|
||||
|
@ -17,10 +17,14 @@ internal sealed class Vector3ToColorConverter : ValueConverter<ColorF>
|
||||
|
||||
var currentChar = (char) readChar;
|
||||
if (currentChar == ' ')
|
||||
{
|
||||
spaceCount++;
|
||||
}
|
||||
|
||||
if (spaceCount < 3 && readChar != -1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
(float x, float y, float z) = builder.AsSpan().ToVector3();
|
||||
result = ColorF.FromArgb(x, y, z);
|
||||
|
@ -17,10 +17,14 @@ internal sealed class Vector3dConverter : ValueConverter<Vector3d>
|
||||
|
||||
var currentChar = (char) readChar;
|
||||
if (currentChar == ' ')
|
||||
{
|
||||
spaceCount++;
|
||||
}
|
||||
|
||||
if (spaceCount < 3 && readChar != -1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result = builder.AsSpan().ToVector3d();
|
||||
break;
|
||||
|
@ -17,10 +17,14 @@ internal sealed class Vector4ToColorConverter : ValueConverter<ColorF>
|
||||
|
||||
var currentChar = (char) readChar;
|
||||
if (currentChar == ' ')
|
||||
{
|
||||
spaceCount++;
|
||||
}
|
||||
|
||||
if (spaceCount < 4 && readChar != -1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
(float x, float y, float z, float w) = builder.AsSpan().ToVector4();
|
||||
result = ColorF.FromArgb(w, x, y, z);
|
||||
|
@ -18,10 +18,14 @@ internal sealed class Vector4ToVector3Converter : ValueConverter<Vector3>
|
||||
|
||||
var currentChar = (char) readChar;
|
||||
if (currentChar == ' ')
|
||||
{
|
||||
spaceCount++;
|
||||
}
|
||||
|
||||
if (spaceCount < 3 && readChar != -1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result = builder.AsSpan().ToVector3();
|
||||
break;
|
||||
|
@ -24,13 +24,19 @@ internal sealed class VectorToNthComponentConverter : ValueConverter<float>
|
||||
int readChar = reader.Read();
|
||||
|
||||
if (readChar == -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
var currentChar = (char) readChar;
|
||||
if (currentChar == ' ')
|
||||
{
|
||||
spaceCount++;
|
||||
}
|
||||
else if (spaceCount == _componentNumber - 1)
|
||||
{
|
||||
builder.Append(currentChar);
|
||||
}
|
||||
}
|
||||
|
||||
result = builder.AsSpan().ToSingle();
|
||||
|
@ -15,13 +15,17 @@ internal static class WorldSettingsConverter
|
||||
{
|
||||
var attribute = property.GetCustomAttribute<SerializationKeyAttribute>();
|
||||
if (attribute is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
object? propertyValue = property.GetValue(settings);
|
||||
Type propertyType = property.PropertyType;
|
||||
|
||||
if (propertyValue is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var result = propertyValue.ToString();
|
||||
|
||||
@ -33,9 +37,13 @@ internal static class WorldSettingsConverter
|
||||
|
||||
ValueConverter? converter;
|
||||
if (converterAttribute.UseArgs)
|
||||
{
|
||||
converter = Activator.CreateInstance(converterType, converterAttribute.Args) as ValueConverter;
|
||||
}
|
||||
else
|
||||
{
|
||||
converter = Activator.CreateInstance(converterType) as ValueConverter;
|
||||
}
|
||||
|
||||
if (converter is not null)
|
||||
{
|
||||
@ -48,11 +56,15 @@ internal static class WorldSettingsConverter
|
||||
else
|
||||
{
|
||||
if (propertyType == typeof(bool) || propertyType == typeof(bool?))
|
||||
{
|
||||
result = (bool)propertyValue ? "1" : "0";
|
||||
}
|
||||
}
|
||||
|
||||
if (result is not null)
|
||||
{
|
||||
dictionary.Add(attribute.Key, result);
|
||||
}
|
||||
}
|
||||
|
||||
return dictionary;
|
||||
@ -67,7 +79,9 @@ internal static class WorldSettingsConverter
|
||||
{
|
||||
var defaultValueAttribute = property.GetCustomAttribute<DefaultValueAttribute>();
|
||||
if (defaultValueAttribute is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
property.SetValue(settings, defaultValueAttribute.Value);
|
||||
}
|
||||
@ -79,7 +93,9 @@ internal static class WorldSettingsConverter
|
||||
StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (property is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
using var reader = new StringReader(value);
|
||||
object propertyValue = value;
|
||||
@ -95,15 +111,25 @@ internal static class WorldSettingsConverter
|
||||
Type propertyType = property.PropertyType;
|
||||
|
||||
if (propertyType == typeof(bool))
|
||||
{
|
||||
propertyValue = value == "1" || (bool.TryParse(value, out bool result) && result);
|
||||
}
|
||||
else if (propertyType == typeof(int))
|
||||
{
|
||||
propertyValue = int.TryParse(value, out int result) ? result : 0;
|
||||
}
|
||||
else if (propertyType == typeof(float))
|
||||
{
|
||||
propertyValue = float.TryParse(value, out float result) ? result : 0.0f;
|
||||
}
|
||||
else if (propertyType == typeof(double))
|
||||
{
|
||||
propertyValue = double.TryParse(value, out double result) ? result : 0.0;
|
||||
}
|
||||
else if (propertyType.IsEnum && int.TryParse(value, out int result))
|
||||
{
|
||||
propertyValue = Convert.ChangeType(result, propertyType);
|
||||
}
|
||||
}
|
||||
|
||||
// ReSharper disable ConditionIsAlwaysTrueOrFalse
|
||||
@ -112,9 +138,13 @@ internal static class WorldSettingsConverter
|
||||
{
|
||||
ValueConverter? converter;
|
||||
if (converterAttribute.UseArgs)
|
||||
{
|
||||
converter = Activator.CreateInstance(converterType, converterAttribute.Args) as ValueConverter;
|
||||
}
|
||||
else
|
||||
{
|
||||
converter = Activator.CreateInstance(converterType) as ValueConverter;
|
||||
}
|
||||
|
||||
converter?.Deserialize(reader, out propertyValue);
|
||||
}
|
||||
|
@ -46,8 +46,16 @@ public sealed class InviteRequest : IEquatable<InviteRequest>
|
||||
/// <inheritdoc />
|
||||
public bool Equals(InviteRequest? other)
|
||||
{
|
||||
if (ReferenceEquals(null, other)) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
if (ReferenceEquals(null, other))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(this, other))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return _requestId == other._requestId && _client.Equals(other._client);
|
||||
}
|
||||
|
||||
@ -59,10 +67,15 @@ public sealed class InviteRequest : IEquatable<InviteRequest>
|
||||
/// </param>
|
||||
public Task AcceptAsync(bool suppressTeleport = false)
|
||||
{
|
||||
lock (_client.Lock) Native.vp_invite_accept(_client.NativeInstanceHandle, _requestId);
|
||||
lock (_client.Lock)
|
||||
{
|
||||
Native.vp_invite_accept(_client.NativeInstanceHandle, _requestId);
|
||||
}
|
||||
|
||||
if (suppressTeleport)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
return _client.CurrentAvatar.TeleportAsync(Location);
|
||||
}
|
||||
@ -72,7 +85,10 @@ public sealed class InviteRequest : IEquatable<InviteRequest>
|
||||
/// </summary>
|
||||
public Task DeclineAsync()
|
||||
{
|
||||
lock (_client.Lock) Native.vp_invite_decline(_client.NativeInstanceHandle, _requestId);
|
||||
lock (_client.Lock)
|
||||
{
|
||||
Native.vp_invite_decline(_client.NativeInstanceHandle, _requestId);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
@ -80,7 +96,11 @@ public sealed class InviteRequest : IEquatable<InviteRequest>
|
||||
/// <inheritdoc />
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (ReferenceEquals(this, obj))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return obj is InviteRequest other && Equals(other);
|
||||
}
|
||||
|
||||
|
@ -45,15 +45,19 @@ public sealed class JoinRequest : IEquatable<JoinRequest>
|
||||
public Task AcceptAsync(Location? location = null)
|
||||
{
|
||||
if (_client.CurrentAvatar is null)
|
||||
{
|
||||
ThrowHelper.ThrowNotInWorldException();
|
||||
|
||||
}
|
||||
|
||||
location ??= _client.CurrentAvatar!.Location;
|
||||
string worldName = location.Value.World.Name;
|
||||
(double x, double y, double z) = location.Value.Position;
|
||||
(double pitch, double yaw, double _) = location.Value.Rotation.ToEulerAngles();
|
||||
|
||||
lock (_client.Lock)
|
||||
{
|
||||
Native.vp_join_accept(_client.NativeInstanceHandle, _requestId, worldName, x, y, z, (float) yaw, (float) pitch);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
@ -63,7 +67,10 @@ public sealed class JoinRequest : IEquatable<JoinRequest>
|
||||
/// </summary>
|
||||
public Task DeclineAsync()
|
||||
{
|
||||
lock (_client.Lock) Native.vp_join_decline(_client.NativeInstanceHandle, _requestId);
|
||||
lock (_client.Lock)
|
||||
{
|
||||
Native.vp_join_decline(_client.NativeInstanceHandle, _requestId);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
@ -72,15 +79,27 @@ public sealed class JoinRequest : IEquatable<JoinRequest>
|
||||
/// <inheritdoc />
|
||||
public bool Equals(JoinRequest? other)
|
||||
{
|
||||
if (ReferenceEquals(null, other)) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
if (ReferenceEquals(null, other))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(this, other))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return _requestId == other._requestId && _client.Equals(other._client);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (ReferenceEquals(this, obj))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return obj is JoinRequest other && Equals(other);
|
||||
}
|
||||
|
||||
|
@ -104,8 +104,15 @@ public abstract class FluentActionComponent
|
||||
var builder = new StringBuilder();
|
||||
builder.Append($"texture {texture}");
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(mask)) builder.Append($" mask={mask}");
|
||||
if (!string.IsNullOrWhiteSpace(tag)) builder.Append($" tag={tag}");
|
||||
if (!string.IsNullOrWhiteSpace(mask))
|
||||
{
|
||||
builder.Append($" mask={mask}");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(tag))
|
||||
{
|
||||
builder.Append($" tag={tag}");
|
||||
}
|
||||
|
||||
return new FluentActionCommand(Action, Command.Texture);
|
||||
}
|
||||
|
@ -67,7 +67,9 @@ public struct Vector3d : IEquatable<Vector3d>, IFormattable
|
||||
public Vector3d(ReadOnlySpan<double> values)
|
||||
{
|
||||
if (values.Length < 3)
|
||||
{
|
||||
throw new IndexOutOfRangeException("The specified span has an insufficient number of elements.");
|
||||
}
|
||||
|
||||
this = Unsafe.ReadUnaligned<Vector3d>(ref Unsafe.As<double, byte>(ref MemoryMarshal.GetReference(values)));
|
||||
}
|
||||
@ -428,13 +430,19 @@ public struct Vector3d : IEquatable<Vector3d>, IFormattable
|
||||
public readonly void CopyTo(double[] array, int index = 0)
|
||||
{
|
||||
if (array is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(array));
|
||||
}
|
||||
|
||||
if (index < 0 || index >= array.Length)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(index), "Specified index was out of the bounds of the array.");
|
||||
}
|
||||
|
||||
if (array.Length - index < 3)
|
||||
{
|
||||
throw new ArgumentException("The number of elements in source vector is greater than the destination array.");
|
||||
}
|
||||
|
||||
array[index] = X;
|
||||
array[index + 1] = Y;
|
||||
|
@ -17,7 +17,9 @@ public sealed partial class VirtualParadiseClient
|
||||
{
|
||||
var reason = (ReasonCode) Native.vp_init();
|
||||
if (reason == ReasonCode.VersionMismatch)
|
||||
{
|
||||
throw new VersionMismatchException();
|
||||
}
|
||||
|
||||
_instanceHandle = GCHandle.Alloc(this);
|
||||
_netConfig.Context = GCHandle.ToIntPtr(_instanceHandle);
|
||||
|
@ -41,7 +41,9 @@ public sealed partial class VirtualParadiseClient
|
||||
private async void OnObjectGetNativeCallback(IntPtr sender, ReasonCode reason, int reference)
|
||||
{
|
||||
if (!_objectCompletionSources.TryGetValue(reference, out TaskCompletionSource<(ReasonCode, VirtualParadiseObject)>? taskCompletionSource))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
VirtualParadiseObject virtualParadiseObject = reason == ReasonCode.Success ? await ExtractObjectAsync(sender) : null;
|
||||
taskCompletionSource.SetResult((reason, virtualParadiseObject));
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Drawing;
|
||||
using System.Numerics;
|
||||
using System.Threading.Channels;
|
||||
@ -167,7 +167,9 @@ public sealed partial class VirtualParadiseClient
|
||||
if (session == 0)
|
||||
{
|
||||
if (_cellChannels.TryGetValue(cell, out Channel<VirtualParadiseObject>? channel))
|
||||
{
|
||||
await channel.Writer.WriteAsync(virtualParadiseObject);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -201,7 +203,9 @@ public sealed partial class VirtualParadiseClient
|
||||
}
|
||||
|
||||
if (virtualParadiseObject is not null)
|
||||
{
|
||||
AddOrUpdateObject(virtualParadiseObject);
|
||||
}
|
||||
|
||||
var args = new ObjectChangedEventArgs(avatar, cachedObject, virtualParadiseObject);
|
||||
RaiseEvent(ObjectChanged, args);
|
||||
@ -277,7 +281,9 @@ public sealed partial class VirtualParadiseClient
|
||||
}
|
||||
|
||||
if (_worldListChannel is not null)
|
||||
{
|
||||
await _worldListChannel.Writer.WriteAsync(world);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnWorldSettingNativeEvent(IntPtr sender)
|
||||
@ -311,7 +317,10 @@ public sealed partial class VirtualParadiseClient
|
||||
private void OnWorldDisconnectNativeEvent(IntPtr sender)
|
||||
{
|
||||
DisconnectReason reason;
|
||||
lock (Lock) reason = (DisconnectReason) vp_int(sender, IntegerAttribute.DisconnectErrorCode);
|
||||
lock (Lock)
|
||||
{
|
||||
reason = (DisconnectReason) vp_int(sender, IntegerAttribute.DisconnectErrorCode);
|
||||
}
|
||||
|
||||
var args = new DisconnectedEventArgs(reason);
|
||||
RaiseEvent(WorldServerDisconnected, args);
|
||||
@ -320,7 +329,10 @@ public sealed partial class VirtualParadiseClient
|
||||
private void OnUniverseDisconnectNativeEvent(IntPtr sender)
|
||||
{
|
||||
DisconnectReason reason;
|
||||
lock (Lock) reason = (DisconnectReason) vp_int(sender, IntegerAttribute.DisconnectErrorCode);
|
||||
lock (Lock)
|
||||
{
|
||||
reason = (DisconnectReason) vp_int(sender, IntegerAttribute.DisconnectErrorCode);
|
||||
}
|
||||
|
||||
var args = new DisconnectedEventArgs(reason);
|
||||
RaiseEvent(UniverseServerDisconnected, args);
|
||||
@ -352,7 +364,9 @@ public sealed partial class VirtualParadiseClient
|
||||
}
|
||||
|
||||
if (_usersCompletionSources.TryGetValue(userId, out TaskCompletionSource<VirtualParadiseUser>? taskCompletionSource))
|
||||
{
|
||||
taskCompletionSource.SetResult(user);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnQueryCellEndNativeEvent(IntPtr sender)
|
||||
@ -368,7 +382,9 @@ public sealed partial class VirtualParadiseClient
|
||||
}
|
||||
|
||||
if (_cellChannels.TryRemove(cell, out Channel<VirtualParadiseObject>? channel))
|
||||
{
|
||||
channel.Writer.TryComplete();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAvatarClickNativeEvent(IntPtr sender)
|
||||
@ -456,7 +472,9 @@ public sealed partial class VirtualParadiseClient
|
||||
}
|
||||
|
||||
if (!Uri.IsWellFormedUriString(url, UriKind.Absolute))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
VirtualParadiseAvatar? avatar = GetAvatar(session);
|
||||
var uri = new Uri(url);
|
||||
|
@ -24,7 +24,9 @@ public sealed partial class VirtualParadiseClient
|
||||
public IAsyncEnumerable<VirtualParadiseObject> EnumerateObjectsAsync(Cell cell, int? revision = null)
|
||||
{
|
||||
if (_cellChannels.TryGetValue(cell, out Channel<VirtualParadiseObject>? channel))
|
||||
{
|
||||
return channel.Reader.ReadAllAsync();
|
||||
}
|
||||
|
||||
channel = Channel.CreateUnbounded<VirtualParadiseObject>();
|
||||
_cellChannels.TryAdd(cell, channel);
|
||||
@ -53,18 +55,25 @@ public sealed partial class VirtualParadiseClient
|
||||
/// <returns>An enumerable of <see cref="VirtualParadiseObject" />.</returns>
|
||||
public async IAsyncEnumerable<VirtualParadiseObject> EnumerateObjectsAsync(Cell center, int radius, int? revision = null)
|
||||
{
|
||||
if (radius < 0) throw new ArgumentException("Range must be greater than or equal to 1.");
|
||||
if (radius < 0)
|
||||
{
|
||||
throw new ArgumentException("Range must be greater than or equal to 1.");
|
||||
}
|
||||
|
||||
var cells = new HashSet<Cell>();
|
||||
|
||||
for (int x = center.X - radius; x < center.X + radius; x++)
|
||||
for (int z = center.Z - radius; z < center.Z + radius; z++)
|
||||
{
|
||||
cells.Add(new Cell(x, z));
|
||||
}
|
||||
|
||||
foreach (Cell cell in cells.OrderBy(c => Vector2.Distance(c, center)))
|
||||
{
|
||||
await foreach (VirtualParadiseObject vpObject in EnumerateObjectsAsync(cell))
|
||||
{
|
||||
yield return vpObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,7 +91,9 @@ public sealed partial class VirtualParadiseClient
|
||||
public async ValueTask<VirtualParadiseObject> GetObjectAsync(int id)
|
||||
{
|
||||
if (_objects.TryGetValue(id, out VirtualParadiseObject? virtualParadiseObject))
|
||||
{
|
||||
return virtualParadiseObject;
|
||||
}
|
||||
|
||||
ReasonCode reason;
|
||||
|
||||
@ -97,7 +108,9 @@ public sealed partial class VirtualParadiseClient
|
||||
vp_int_set(NativeInstanceHandle, IntegerAttribute.ReferenceNumber, id);
|
||||
reason = (ReasonCode) vp_object_get(NativeInstanceHandle, id);
|
||||
if (reason != ReasonCode.Success)
|
||||
{
|
||||
goto PreReturn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,7 +118,9 @@ public sealed partial class VirtualParadiseClient
|
||||
_objectCompletionSources.TryRemove(id, out _);
|
||||
|
||||
if (virtualParadiseObject is not null)
|
||||
{
|
||||
_objects.TryAdd(id, virtualParadiseObject);
|
||||
}
|
||||
|
||||
PreReturn:
|
||||
return reason switch
|
||||
|
@ -19,15 +19,22 @@ public sealed partial class VirtualParadiseClient
|
||||
public async Task<VirtualParadiseUser> GetUserAsync(int userId)
|
||||
{
|
||||
if (_users.TryGetValue(userId, out VirtualParadiseUser? user))
|
||||
{
|
||||
return user;
|
||||
}
|
||||
|
||||
if (_usersCompletionSources.TryGetValue(userId, out TaskCompletionSource<VirtualParadiseUser>? taskCompletionSource))
|
||||
{
|
||||
return await taskCompletionSource.Task;
|
||||
}
|
||||
|
||||
taskCompletionSource = new TaskCompletionSource<VirtualParadiseUser>();
|
||||
_usersCompletionSources.TryAdd(userId, taskCompletionSource);
|
||||
|
||||
lock (Lock) vp_user_attributes_by_id(NativeInstanceHandle, userId);
|
||||
lock (Lock)
|
||||
{
|
||||
vp_user_attributes_by_id(NativeInstanceHandle, userId);
|
||||
}
|
||||
|
||||
user = await taskCompletionSource.Task;
|
||||
user = AddOrUpdateUser(user);
|
||||
|
@ -1,12 +1,6 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Drawing;
|
||||
using System.Numerics;
|
||||
using System.Threading.Channels;
|
||||
using VpSharp.Entities;
|
||||
using VpSharp.Exceptions;
|
||||
using VpSharp.Internal;
|
||||
using VpSharp.Internal.NativeAttributes;
|
||||
using VpSharp.Internal.ValueConverters;
|
||||
|
||||
namespace VpSharp;
|
||||
|
||||
@ -30,12 +24,16 @@ public sealed partial class VirtualParadiseClient
|
||||
public async Task<VirtualParadiseWorld?> GetWorldAsync(string name)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
throw new ArgumentException(ExceptionMessages.WorldNameCannotBeEmpty, nameof(name));
|
||||
}
|
||||
|
||||
await foreach (VirtualParadiseWorld world in EnumerateWorldsAsync())
|
||||
{
|
||||
if (string.Equals(world.Name, name))
|
||||
{
|
||||
return world;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Drawing;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
@ -92,8 +92,15 @@ public sealed partial class VirtualParadiseClient : IDisposable
|
||||
/// </remarks>
|
||||
public async Task ConnectAsync(string? host = null, int port = -1)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(host)) host = DefaultUniverseHost;
|
||||
if (port < 1) port = DefaultUniversePort;
|
||||
if (string.IsNullOrWhiteSpace(host))
|
||||
{
|
||||
host = DefaultUniverseHost;
|
||||
}
|
||||
|
||||
if (port < 1)
|
||||
{
|
||||
port = DefaultUniversePort;
|
||||
}
|
||||
|
||||
ReasonCode reason;
|
||||
|
||||
@ -101,9 +108,11 @@ public sealed partial class VirtualParadiseClient : IDisposable
|
||||
{
|
||||
_connectCompletionSource = new TaskCompletionSource<ReasonCode>();
|
||||
|
||||
reason = (ReasonCode) vp_connect_universe(NativeInstanceHandle, host, port);
|
||||
reason = (ReasonCode)vp_connect_universe(NativeInstanceHandle, host, port);
|
||||
if (reason != ReasonCode.Success)
|
||||
{
|
||||
goto NoSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
reason = await _connectCompletionSource.Task;
|
||||
@ -118,7 +127,7 @@ public sealed partial class VirtualParadiseClient : IDisposable
|
||||
throw new SocketException();
|
||||
|
||||
default:
|
||||
throw new SocketException((int) reason);
|
||||
throw new SocketException((int)reason);
|
||||
}
|
||||
}
|
||||
|
||||
@ -130,7 +139,10 @@ public sealed partial class VirtualParadiseClient : IDisposable
|
||||
/// <exception cref="ArgumentException"><paramref name="remoteEP" /> is not a supported endpoint.</exception>
|
||||
public Task ConnectAsync(EndPoint remoteEP)
|
||||
{
|
||||
if (remoteEP is null) throw new ArgumentNullException(nameof(remoteEP));
|
||||
if (remoteEP is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(remoteEP));
|
||||
}
|
||||
|
||||
string host;
|
||||
int port;
|
||||
@ -273,7 +285,10 @@ public sealed partial class VirtualParadiseClient : IDisposable
|
||||
|
||||
if (CurrentWorld is not null)
|
||||
{
|
||||
lock (Lock) vp_leave(NativeInstanceHandle);
|
||||
lock (Lock)
|
||||
{
|
||||
vp_leave(NativeInstanceHandle);
|
||||
}
|
||||
}
|
||||
|
||||
ReasonCode reason;
|
||||
@ -283,7 +298,7 @@ public sealed partial class VirtualParadiseClient : IDisposable
|
||||
|
||||
lock (Lock)
|
||||
{
|
||||
reason = (ReasonCode) vp_enter(NativeInstanceHandle, worldName);
|
||||
reason = (ReasonCode)vp_enter(NativeInstanceHandle, worldName);
|
||||
if (reason != ReasonCode.Success)
|
||||
{
|
||||
goto NoSuccess;
|
||||
@ -321,7 +336,10 @@ public sealed partial class VirtualParadiseClient : IDisposable
|
||||
}
|
||||
|
||||
int size;
|
||||
lock (Lock) size = vp_int(NativeInstanceHandle, IntegerAttribute.WorldSize);
|
||||
lock (Lock)
|
||||
{
|
||||
size = vp_int(NativeInstanceHandle, IntegerAttribute.WorldSize);
|
||||
}
|
||||
|
||||
await _worldSettingsCompletionSource.Task;
|
||||
|
||||
@ -332,8 +350,15 @@ public sealed partial class VirtualParadiseClient : IDisposable
|
||||
world = new VirtualParadiseWorld(this, worldName);
|
||||
}
|
||||
|
||||
if (CurrentAvatar is not null) CurrentAvatar.Location = new Location(world);
|
||||
lock (Lock) vp_state_change(NativeInstanceHandle);
|
||||
if (CurrentAvatar is not null)
|
||||
{
|
||||
CurrentAvatar.Location = new Location(world);
|
||||
}
|
||||
|
||||
lock (Lock)
|
||||
{
|
||||
vp_state_change(NativeInstanceHandle);
|
||||
}
|
||||
|
||||
world.Size = new Size(size, size);
|
||||
|
||||
@ -356,7 +381,9 @@ public sealed partial class VirtualParadiseClient : IDisposable
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
await foreach (VirtualParadiseObject virtualParadiseObject in EnumerateObjectsAsync(default, radius: size))
|
||||
{
|
||||
AddOrUpdateObject(virtualParadiseObject);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -375,7 +402,11 @@ public sealed partial class VirtualParadiseClient : IDisposable
|
||||
public IAsyncEnumerable<VirtualParadiseWorld> EnumerateWorldsAsync()
|
||||
{
|
||||
_worldListChannel = Channel.CreateUnbounded<VirtualParadiseWorld>();
|
||||
lock (Lock) vp_world_list(NativeInstanceHandle, 0);
|
||||
lock (Lock)
|
||||
{
|
||||
vp_world_list(NativeInstanceHandle, 0);
|
||||
}
|
||||
|
||||
return _worldListChannel.Reader.ReadAllAsync();
|
||||
}
|
||||
|
||||
@ -389,9 +420,11 @@ public sealed partial class VirtualParadiseClient : IDisposable
|
||||
{
|
||||
lock (Lock)
|
||||
{
|
||||
var reason = (ReasonCode) vp_leave(NativeInstanceHandle);
|
||||
var reason = (ReasonCode)vp_leave(NativeInstanceHandle);
|
||||
if (reason == ReasonCode.NotInWorld)
|
||||
{
|
||||
return Task.FromException(ThrowHelper.NotInWorldException());
|
||||
}
|
||||
}
|
||||
|
||||
_avatars.Clear();
|
||||
@ -438,7 +471,9 @@ public sealed partial class VirtualParadiseClient : IDisposable
|
||||
_configuration.BotName = botName;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password) || string.IsNullOrWhiteSpace(botName))
|
||||
{
|
||||
throw new ArgumentException("Cannot login due to incomplete configuration.");
|
||||
}
|
||||
|
||||
_loginCompletionSource = new TaskCompletionSource<ReasonCode>();
|
||||
|
||||
@ -454,9 +489,11 @@ public sealed partial class VirtualParadiseClient : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
reason = (ReasonCode) vp_login(NativeInstanceHandle, username, password, botName);
|
||||
reason = (ReasonCode)vp_login(NativeInstanceHandle, username, password, botName);
|
||||
if (reason != ReasonCode.Success)
|
||||
{
|
||||
goto NoSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
reason = await _loginCompletionSource.Task;
|
||||
|
@ -19,10 +19,15 @@ public sealed class VirtualParadiseConfiguration
|
||||
/// <param name="configuration">The configuration to copy.</param>
|
||||
public VirtualParadiseConfiguration(VirtualParadiseConfiguration configuration)
|
||||
{
|
||||
if (configuration is null) throw new ArgumentNullException(nameof(configuration));
|
||||
if (configuration is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configuration));
|
||||
}
|
||||
|
||||
if (configuration.Application is ({ } name, { } version))
|
||||
{
|
||||
Application = new Application(name, version);
|
||||
}
|
||||
|
||||
AutoQuery = configuration.AutoQuery;
|
||||
BotName = new string(configuration.BotName);
|
||||
|
@ -388,12 +388,16 @@ public sealed class WorldSettingsBuilder
|
||||
foreach ((string key, string? value) in dictionary)
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var reason = (ReasonCode)Native.vp_world_setting_set(_client.NativeInstanceHandle, key, value, session);
|
||||
|
||||
if (reason == ReasonCode.NotAllowed)
|
||||
{
|
||||
throw new UnauthorizedAccessException("Not allowed to modify world settings.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user