1
0
mirror of https://github.com/oliverbooth/VpSharp synced 2024-11-10 03:15:42 +00:00

[ci skip] Add braces around single-statement bodies

This commit is contained in:
Oliver Booth 2022-11-27 17:51:18 +00:00
parent 1bf050eca0
commit 693e90bff1
No known key found for this signature in database
GPG Key ID: 32A00B35503AF634
36 changed files with 445 additions and 70 deletions

View File

@ -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>

View File

@ -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);
}

View File

@ -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();
}
}
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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;
}

View File

@ -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();

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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());
}
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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();

View File

@ -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);
}

View File

@ -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);
}

View File

@ -45,7 +45,9 @@ 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;
@ -53,7 +55,9 @@ public sealed class JoinRequest : IEquatable<JoinRequest>
(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);
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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);

View File

@ -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));

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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.");
}
}
}
}