1
0
mirror of https://github.com/oliverbooth/VpSharp synced 2024-11-22 23:58:47 +00:00

Replace usages of Quaternion with custom Rotation struct

This commit is contained in:
Oliver Booth 2022-12-08 15:22:47 +00:00
parent b7e43666b5
commit 342820b444
No known key found for this signature in database
GPG Key ID: 32A00B35503AF634
12 changed files with 213 additions and 119 deletions

View File

@ -1,6 +1,5 @@
using System.Drawing; using System.Drawing;
using System.Numerics; using System.Numerics;
using VpSharp.Extensions;
using VpSharp.Internal; using VpSharp.Internal;
using VpSharp.Internal.NativeAttributes; using VpSharp.Internal.NativeAttributes;
using X10D.Numerics; using X10D.Numerics;
@ -314,7 +313,7 @@ public sealed class VirtualParadiseAvatar : IEquatable<VirtualParadiseAvatar>
public Task TeleportAsync(VirtualParadiseWorld world, Vector3d position) public Task TeleportAsync(VirtualParadiseWorld world, Vector3d position)
{ {
ArgumentNullException.ThrowIfNull(world); ArgumentNullException.ThrowIfNull(world);
return TeleportAsync(world.Name, position, Quaternion.Identity); return TeleportAsync(world.Name, position, Rotation.None);
} }
/// <summary> /// <summary>
@ -324,7 +323,7 @@ public sealed class VirtualParadiseAvatar : IEquatable<VirtualParadiseAvatar>
/// <param name="position">The position to which this avatar should be teleported.</param> /// <param name="position">The position to which this avatar should be teleported.</param>
/// <param name="rotation">The rotation to which this avatar should be teleported.</param> /// <param name="rotation">The rotation to which this avatar should be teleported.</param>
/// <exception cref="ArgumentNullException"><paramref name="world" /> is <see langword="null" />.</exception> /// <exception cref="ArgumentNullException"><paramref name="world" /> is <see langword="null" />.</exception>
public Task TeleportAsync(VirtualParadiseWorld world, Vector3d position, Quaternion rotation) public Task TeleportAsync(VirtualParadiseWorld world, Vector3d position, Rotation rotation)
{ {
ArgumentNullException.ThrowIfNull(world); ArgumentNullException.ThrowIfNull(world);
return TeleportAsync(world.Name, position, rotation); return TeleportAsync(world.Name, position, rotation);
@ -337,7 +336,7 @@ public sealed class VirtualParadiseAvatar : IEquatable<VirtualParadiseAvatar>
/// <param name="position">The position to which this avatar should be teleported.</param> /// <param name="position">The position to which this avatar should be teleported.</param>
public Task TeleportAsync(string world, Vector3d position) public Task TeleportAsync(string world, Vector3d position)
{ {
return TeleportAsync(world, position, Quaternion.Identity); return TeleportAsync(world, position, Rotation.None);
} }
/// <summary> /// <summary>
@ -346,7 +345,7 @@ public sealed class VirtualParadiseAvatar : IEquatable<VirtualParadiseAvatar>
/// <param name="world">The name of the world to which this avatar should be teleported.</param> /// <param name="world">The name of the world to which this avatar should be teleported.</param>
/// <param name="position">The position to which this avatar should be teleported.</param> /// <param name="position">The position to which this avatar should be teleported.</param>
/// <param name="rotation">The rotation to which this avatar should be teleported.</param> /// <param name="rotation">The rotation to which this avatar should be teleported.</param>
public async Task TeleportAsync(string world, Vector3d position, Quaternion rotation) public async Task TeleportAsync(string world, Vector3d position, Rotation rotation)
{ {
ArgumentNullException.ThrowIfNull(world); ArgumentNullException.ThrowIfNull(world);
#if NET7_0_OR_GREATER #if NET7_0_OR_GREATER
@ -385,7 +384,7 @@ public sealed class VirtualParadiseAvatar : IEquatable<VirtualParadiseAvatar>
lock (_client.Lock) lock (_client.Lock)
{ {
(double x, double y, double z) = position; (double x, double y, double z) = position;
(double pitch, double yaw, double _) = rotation.ToEulerAngles(); (double pitch, double yaw, double _) = rotation;
_ = vp_double_set(handle, FloatAttribute.MyX, x); _ = vp_double_set(handle, FloatAttribute.MyX, x);
_ = vp_double_set(handle, FloatAttribute.MyY, y); _ = vp_double_set(handle, FloatAttribute.MyY, y);
@ -405,9 +404,9 @@ public sealed class VirtualParadiseAvatar : IEquatable<VirtualParadiseAvatar>
lock (_client.Lock) lock (_client.Lock)
{ {
(float x, float y, float z) = (Vector3)position; (float x, float y, float z) = (Vector3)position;
(float pitch, float yaw, float _) = (Vector3)rotation.ToEulerAngles(); (double pitch, double yaw, double _) = rotation;
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, (float)yaw, (float)pitch);
if (reason == ReasonCode.NotInWorld) if (reason == ReasonCode.NotInWorld)
{ {
ThrowHelper.ThrowNotInWorldException(); ThrowHelper.ThrowNotInWorldException();
@ -433,7 +432,7 @@ public sealed class VirtualParadiseAvatar : IEquatable<VirtualParadiseAvatar>
/// </summary> /// </summary>
/// <param name="position">The position to which this avatar should be teleported.</param> /// <param name="position">The position to which this avatar should be teleported.</param>
/// <param name="rotation">The rotation to which this avatar should be teleported</param> /// <param name="rotation">The rotation to which this avatar should be teleported</param>
public Task TeleportAsync(Vector3d position, Quaternion rotation) public Task TeleportAsync(Vector3d position, Rotation rotation)
{ {
return TeleportAsync(Location with {Position = position, Rotation = rotation}); return TeleportAsync(Location with {Position = position, Rotation = rotation});
} }

View File

@ -241,7 +241,7 @@ public abstract class VirtualParadiseObject : IEquatable<VirtualParadiseObject>
Location location = Location; Location location = Location;
Vector3d position = location.Position; Vector3d position = location.Position;
Quaternion rotation = location.Rotation; Rotation rotation = location.Rotation;
if (builder.Position.HasValue) if (builder.Position.HasValue)
{ {

View File

@ -1,7 +1,4 @@
using System.Numerics; using VpSharp.Internal;
using VpSharp.Extensions;
using VpSharp.Internal;
using X10D.Math;
using static VpSharp.Internal.NativeAttributes.DataAttribute; using static VpSharp.Internal.NativeAttributes.DataAttribute;
using static VpSharp.Internal.NativeAttributes.FloatAttribute; using static VpSharp.Internal.NativeAttributes.FloatAttribute;
using static VpSharp.Internal.NativeAttributes.IntegerAttribute; using static VpSharp.Internal.NativeAttributes.IntegerAttribute;
@ -57,7 +54,7 @@ public abstract class VirtualParadiseObjectBuilder
/// Gets or sets the rotation of the object. /// Gets or sets the rotation of the object.
/// </summary> /// </summary>
/// <value>The rotation of the object, or <see langword="default" /> to leave unchanged.</value> /// <value>The rotation of the object, or <see langword="default" /> to leave unchanged.</value>
public Optional<Quaternion> Rotation { get; set; } public Optional<Rotation> Rotation { get; set; }
internal Optional<IReadOnlyList<byte>> Data { get; set; } internal Optional<IReadOnlyList<byte>> Data { get; set; }
@ -157,27 +154,12 @@ public abstract class VirtualParadiseObjectBuilder
if (!Rotation.HasValue && Mode == ObjectBuilderMode.Create) if (!Rotation.HasValue && Mode == ObjectBuilderMode.Create)
{ {
Rotation = Quaternion.Identity; Rotation = VpSharp.Rotation.None;
} }
if (Rotation.HasValue) if (Rotation.HasValue)
{ {
(double x, double y, double z) = Vector3d.Zero; (double x, double y, double z, double angle) = Rotation.Value;
double angle = double.PositiveInfinity;
if (Rotation.Value != Quaternion.Identity)
{
Rotation.Value.ToAxisAngle(out Vector3d axis, out angle);
(x, y, z) = axis;
angle = angle.RadiansToDegrees();
}
if (double.IsPositiveInfinity(angle))
{
x = x.RadiansToDegrees();
y = y.RadiansToDegrees();
z = z.RadiansToDegrees();
}
_ = vp_double_set(handle, ObjectRotationX, x); _ = vp_double_set(handle, ObjectRotationX, x);
_ = vp_double_set(handle, ObjectRotationY, y); _ = vp_double_set(handle, ObjectRotationY, y);
_ = vp_double_set(handle, ObjectRotationZ, z); _ = vp_double_set(handle, ObjectRotationZ, z);
@ -185,16 +167,10 @@ public abstract class VirtualParadiseObjectBuilder
} }
else else
{ {
TargetObject.Location.Rotation.ToAxisAngle(out Vector3d axis, out double angle); (double x, double y, double z, double angle) = TargetObject.Location.Rotation;
if (Vector3d.IsNan(axis)) _ = vp_double_set(handle, ObjectRotationX, x);
{ _ = vp_double_set(handle, ObjectRotationY, y);
axis = Vector3d.Zero; _ = vp_double_set(handle, ObjectRotationZ, z);
angle = double.PositiveInfinity;
}
_ = vp_double_set(handle, ObjectRotationX, axis.X);
_ = vp_double_set(handle, ObjectRotationY, axis.Y);
_ = vp_double_set(handle, ObjectRotationZ, axis.Z);
_ = vp_double_set(handle, ObjectRotationAngle, angle); _ = vp_double_set(handle, ObjectRotationAngle, angle);
} }
} }

View File

@ -1,6 +1,4 @@
using System.Numerics;
using VpSharp.Exceptions; using VpSharp.Exceptions;
using VpSharp.Extensions;
using VpSharp.Internal; using VpSharp.Internal;
using VpSharp.Internal.NativeAttributes; using VpSharp.Internal.NativeAttributes;
using static VpSharp.Internal.NativeMethods; using static VpSharp.Internal.NativeMethods;
@ -144,7 +142,7 @@ public sealed class VirtualParadiseUser : IEquatable<VirtualParadiseUser>
string world = location.Value.World.Name; string world = location.Value.World.Name;
(double x, double y, double z) = location.Value.Position; (double x, double y, double z) = location.Value.Position;
(double pitch, double yaw, _) = location.Value.Rotation.ToEulerAngles(); (double pitch, double yaw, _) = location.Value.Rotation;
_ = vp_int_set(_client.NativeInstanceHandle, IntegerAttribute.ReferenceNumber, reference); _ = vp_int_set(_client.NativeInstanceHandle, IntegerAttribute.ReferenceNumber, reference);
_ = vp_invite(_client.NativeInstanceHandle, Id, world, x, y, z, (float)yaw, (float)pitch); _ = vp_invite(_client.NativeInstanceHandle, Id, world, x, y, z, (float)yaw, (float)pitch);
@ -215,7 +213,7 @@ public sealed class VirtualParadiseUser : IEquatable<VirtualParadiseUser>
} }
var position = new Vector3d(x, y, z); var position = new Vector3d(x, y, z);
var rotation = Quaternion.CreateFromYawPitchRoll(yaw, pitch, 0); var rotation = Rotation.CreateFromTiltYawRoll(pitch, yaw, 0);
VirtualParadiseWorld world = (await _client.GetWorldAsync(worldName).ConfigureAwait(false))!; VirtualParadiseWorld world = (await _client.GetWorldAsync(worldName).ConfigureAwait(false))!;
location = new Location(world, position, rotation); location = new Location(world, position, rotation);

View File

@ -1,38 +0,0 @@
using System.Numerics;
namespace VpSharp.Extensions;
/// <summary>
/// Extension methods for <see cref="Quaternion" />.
/// </summary>
public static class QuaternionExtensions
{
/// <summary>
/// Converts this quaternion to a <see cref="Vector3d" /> containing an Euler representation of the rotation.
/// </summary>
/// <param name="value">The quaternion to convert.</param>
/// <returns>The Euler representation of <paramref name="value" />.</returns>
/// <see href="https://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/" />
public static Vector3d ToEulerAngles(this Quaternion value)
{
value = Quaternion.Normalize(value);
double x = Math.Atan2(2 * (value.X * value.W - value.Y * value.Z), 1 - 2 * (value.X * value.X + value.Z * value.Z));
double y = Math.Asin(2 * (value.X * value.Z + value.Y * value.W));
double z = Math.Atan2(2 * (value.Z * value.W - value.X * value.Y), 1 - 2 * (value.Y * value.Y + value.Z * value.Z));
return new Vector3d(x, y, z) * (180 / Math.PI);
}
/// <summary>
/// Converts this quaternion to an axis/angle pair.
/// </summary>
/// <param name="value">The quaternion to convert.</param>
/// <param name="axis">The axis value.</param>
/// <param name="angle">The angle value.</param>
#pragma warning disable CA1021
public static void ToAxisAngle(this Quaternion value, out Vector3d axis, out double angle)
#pragma warning restore CA1021
{
angle = 2 * Math.Acos(value.W);
axis = Vector3d.Normalize(new Vector3d(value.X, value.Y, value.Z));
}
}

View File

@ -1,6 +1,5 @@
using VpSharp.Entities; using VpSharp.Entities;
using VpSharp.Exceptions; using VpSharp.Exceptions;
using VpSharp.Extensions;
using VpSharp.Internal; using VpSharp.Internal;
namespace VpSharp; namespace VpSharp;
@ -76,7 +75,7 @@ public sealed class JoinRequest : IEquatable<JoinRequest>
location ??= _client.CurrentAvatar.Location; location ??= _client.CurrentAvatar.Location;
string worldName = location.Value.World.Name; string worldName = location.Value.World.Name;
(double x, double y, double z) = location.Value.Position; (double x, double y, double z) = location.Value.Position;
(double pitch, double yaw, double _) = location.Value.Rotation.ToEulerAngles(); (double pitch, double yaw, double _) = location.Value.Rotation;
lock (_client.Lock) lock (_client.Lock)
{ {

View File

@ -1,7 +1,4 @@
using System.Numerics; using VpSharp.Entities;
using VpSharp.Entities;
using VpSharp.Extensions;
using X10D.Math;
namespace VpSharp; namespace VpSharp;
@ -29,7 +26,7 @@ public readonly struct Location : IEquatable<Location>
{ {
World = world ?? throw new ArgumentNullException(nameof(world)); World = world ?? throw new ArgumentNullException(nameof(world));
Position = new Vector3d(coordinates.X, coordinates.Y, coordinates.Z); Position = new Vector3d(coordinates.X, coordinates.Y, coordinates.Z);
Rotation = Quaternion.CreateFromYawPitchRoll((float)coordinates.Yaw.DegreesToRadians(), 0, 0); Rotation = Rotation.CreateFromTiltYawRoll(0, coordinates.Yaw, 0);
} }
/// <summary> /// <summary>
@ -39,7 +36,7 @@ public readonly struct Location : IEquatable<Location>
/// <param name="position">The position.</param> /// <param name="position">The position.</param>
/// <param name="rotation">The rotation.</param> /// <param name="rotation">The rotation.</param>
/// <exception cref="ArgumentNullException"><paramref name="world" /> is <see langword="null" />.</exception> /// <exception cref="ArgumentNullException"><paramref name="world" /> is <see langword="null" />.</exception>
public Location(VirtualParadiseWorld world, Vector3d position = default, Quaternion rotation = default) public Location(VirtualParadiseWorld world, Vector3d position = default, Rotation rotation = default)
{ {
World = world ?? throw new ArgumentNullException(nameof(world)); World = world ?? throw new ArgumentNullException(nameof(world));
Position = position; Position = position;
@ -64,7 +61,7 @@ public readonly struct Location : IEquatable<Location>
/// Gets the rotation represented by this location. /// Gets the rotation represented by this location.
/// </summary> /// </summary>
/// <value>The rotation.</value> /// <value>The rotation.</value>
public Quaternion Rotation { get; init; } public Rotation Rotation { get; init; }
/// <summary> /// <summary>
/// Gets the world represented by this location. /// Gets the world represented by this location.
@ -131,8 +128,7 @@ public readonly struct Location : IEquatable<Location>
public Coordinates ToCoordinates() public Coordinates ToCoordinates()
{ {
(double x, double y, double z) = Position; (double x, double y, double z) = Position;
(_, double yaw, _) = Rotation.ToEulerAngles(); return new Coordinates(World?.Name, x, y, z, Rotation.Yaw);
return new Coordinates(World?.Name, x, y, z, yaw);
} }
/// <inheritdoc /> /// <inheritdoc />

172
VpSharp/src/Rotation.cs Normal file
View File

@ -0,0 +1,172 @@
using System.Numerics;
using X10D.Math;
using X10D.Numerics;
namespace VpSharp;
/// <summary>
/// Represents a rotation.
/// </summary>
public readonly struct Rotation : IEquatable<Rotation>
{
/// <summary>
/// Represents no rotation.
/// </summary>
public static readonly Rotation None = new(0, 0, 0, double.PositiveInfinity);
/// <summary>
/// Initializes a new instance of the <see cref="Rotation" /> struct.
/// </summary>
/// <param name="tilt">The tilt.</param>
/// <param name="yaw">The yaw.</param>
/// <param name="roll">The roll.</param>
/// <param name="angle">The angle.</param>
public Rotation(double tilt, double yaw, double roll, double angle)
{
Angle = angle;
Roll = roll;
Tilt = tilt;
Yaw = yaw;
}
/// <summary>
/// Gets or initializes the angle component of this rotation.
/// </summary>
/// <value>The angle component.</value>
public double Angle { get; init; }
/// <summary>
/// Gets or initializes the roll component of this rotation.
/// </summary>
/// <value>The roll component.</value>
/// <remarks>This value is the rotation on the Z axis.</remarks>
public double Roll { get; init; }
/// <summary>
/// Gets or initializes the tilt component of this rotation.
/// </summary>
/// <value>The tilt component.</value>
/// <remarks>This value is the rotation on the X axis.</remarks>
public double Tilt { get; init; }
/// <summary>
/// Gets or initializes the yaw component of this rotation.
/// </summary>
/// <value>The yaw component.</value>
/// <remarks>This value is the rotation on the Y axis.</remarks>
public double Yaw { get; init; }
/// <summary>
/// Returns a value indicating whether the two given rotations are equal.
/// </summary>
/// <param name="left">The first rotation to compare.</param>
/// <param name="right">The second rotation to compare.</param>
/// <returns><see langword="true" /> if the two rotations are equal; otherwise, <see langword="false" />.</returns>
public static bool operator ==(Rotation left, Rotation right)
{
return left.Equals(right);
}
/// <summary>
/// Returns a value indicating whether the two given rotations are not equal.
/// </summary>
/// <param name="left">The first rotation to compare.</param>
/// <param name="right">The second rotation to compare.</param>
/// <returns><see langword="true" /> if the two rotations are not equal; otherwise, <see langword="false" />.</returns>
public static bool operator !=(Rotation left, Rotation right)
{
return !left.Equals(right);
}
/// <summary>
/// Creates a <see cref="Rotation" /> from the specified axis and angle, as represented in degrees.
/// </summary>
/// <param name="axis">The axis value.</param>
/// <param name="angle">The angle value.</param>
/// <returns>A new instance of <see cref="Rotation" />.</returns>
public static Rotation CreateFromAxisAngle(Vector3d axis, double angle)
{
return new Rotation(axis.X, axis.Y, axis.Z, angle.DegreesToRadians());
}
/// <summary>
/// Creates a <see cref="Rotation" /> from the specified quaternion.
/// </summary>
/// <param name="quaternion">The quaternion.</param>
/// <returns>A new instance of <see cref="Rotation" />.</returns>
public static Rotation CreateFromQuaternion(Quaternion quaternion)
{
(Vector3d axis, double angle) = quaternion.ToAxisAngle();
return new Rotation(axis.X, axis.Y, axis.Z, angle);
}
/// <summary>
/// Creates a <see cref="Rotation" /> from the specified Euler rotation vector, as represented in degrees.
/// </summary>
/// <param name="vector">The Euler rotation vector.</param>
/// <returns>A new instance of <see cref="Rotation" />.</returns>
public static Rotation CreateFromTiltYawRoll(Vector3d vector)
{
return new Rotation(vector.X, vector.Y, vector.Z, double.PositiveInfinity);
}
/// <summary>
/// Creates a <see cref="Rotation" /> from the specified tilt, yaw, and roll, as represented in degrees.
/// </summary>
/// <param name="tilt">The tilt.</param>
/// <param name="yaw">The yaw.</param>
/// <param name="roll">The roll.</param>
/// <returns>A new instance of <see cref="Rotation" />.</returns>
public static Rotation CreateFromTiltYawRoll(double tilt, double yaw, double roll)
{
return new Rotation(tilt, yaw, roll, double.PositiveInfinity);
}
/// <summary>
/// Deconstructs this rotation.
/// </summary>
/// <param name="tilt">When this method returns, contains the <see cref="Tilt" /> component value.</param>
/// <param name="yaw">When this method returns, contains the <see cref="Yaw" /> component value.</param>
/// <param name="roll">When this method returns, contains the <see cref="Roll" /> component value.</param>
public void Deconstruct(out double tilt, out double yaw, out double roll)
{
Deconstruct(out tilt, out yaw, out roll, out _);
}
/// <summary>
/// Deconstructs this rotation.
/// </summary>
/// <param name="tilt">When this method returns, contains the <see cref="Tilt" /> component value.</param>
/// <param name="yaw">When this method returns, contains the <see cref="Yaw" /> component value.</param>
/// <param name="roll">When this method returns, contains the <see cref="Roll" /> component value.</param>
/// <param name="angle">When this method returns, contains the <see cref="Angle" /> component value.</param>
public void Deconstruct(out double tilt, out double yaw, out double roll, out double angle)
{
tilt = Tilt;
yaw = Yaw;
roll = Roll;
angle = Angle;
}
/// <summary>
/// Returns a value indicating whether this rotation and another rotation are equal.
/// </summary>
/// <param name="other">The rotation to compare with this instance.</param>
/// <returns><see langword="true" /> if the two rotations are equal; otherwise, <see langword="false" />.</returns>
public bool Equals(Rotation other)
{
return Angle.Equals(other.Angle) && Roll.Equals(other.Roll) && Tilt.Equals(other.Tilt) && Yaw.Equals(other.Yaw);
}
/// <inheritdoc />
public override bool Equals(object? obj)
{
return obj is Rotation other && Equals(other);
}
/// <inheritdoc />
public override int GetHashCode()
{
return HashCode.Combine(Angle, Roll, Tilt, Yaw);
}
}

View File

@ -1,5 +1,4 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Numerics;
using VpSharp.Entities; using VpSharp.Entities;
using VpSharp.Internal.NativeAttributes; using VpSharp.Internal.NativeAttributes;
using static VpSharp.Internal.NativeMethods; using static VpSharp.Internal.NativeMethods;
@ -52,7 +51,7 @@ public sealed partial class VirtualParadiseClient
var yaw = (float)vp_double(sender, FloatAttribute.AvatarYaw); var yaw = (float)vp_double(sender, FloatAttribute.AvatarYaw);
var position = new Vector3d(x, y, z); var position = new Vector3d(x, y, z);
var rotation = Quaternion.CreateFromYawPitchRoll(yaw, pitch, 0); var rotation = Rotation.CreateFromTiltYawRoll(pitch, yaw, 0);
string applicationName = vp_string(sender, StringAttribute.AvatarApplicationName); string applicationName = vp_string(sender, StringAttribute.AvatarApplicationName);
string applicationVersion = vp_string(sender, StringAttribute.AvatarApplicationVersion); string applicationVersion = vp_string(sender, StringAttribute.AvatarApplicationVersion);

View File

@ -1,6 +1,5 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Drawing; using System.Drawing;
using System.Numerics;
using System.Threading.Channels; using System.Threading.Channels;
using VpSharp.ClientExtensions; using VpSharp.ClientExtensions;
using VpSharp.Entities; using VpSharp.Entities;
@ -103,7 +102,7 @@ public sealed partial class VirtualParadiseClient
int session; int session;
int type; int type;
Vector3d position; Vector3d position;
Quaternion rotation; Rotation rotation;
lock (Lock) lock (Lock)
{ {
@ -117,7 +116,7 @@ public sealed partial class VirtualParadiseClient
var pitch = (float)vp_double(sender, FloatAttribute.AvatarPitch); var pitch = (float)vp_double(sender, FloatAttribute.AvatarPitch);
var yaw = (float)vp_double(sender, FloatAttribute.AvatarYaw); var yaw = (float)vp_double(sender, FloatAttribute.AvatarYaw);
rotation = Quaternion.CreateFromYawPitchRoll(yaw, pitch, 0); rotation = Rotation.CreateFromTiltYawRoll(pitch, yaw, 0);
} }
VirtualParadiseAvatar? avatar = GetAvatar(session); VirtualParadiseAvatar? avatar = GetAvatar(session);
@ -436,7 +435,7 @@ public sealed partial class VirtualParadiseClient
int session; int session;
string worldName; string worldName;
Vector3d position; Vector3d position;
Quaternion rotation; Rotation rotation;
lock (Lock) lock (Lock)
{ {
@ -449,7 +448,7 @@ public sealed partial class VirtualParadiseClient
float yaw = vp_float(sender, FloatAttribute.TeleportYaw); float yaw = vp_float(sender, FloatAttribute.TeleportYaw);
float pitch = vp_float(sender, FloatAttribute.TeleportPitch); float pitch = vp_float(sender, FloatAttribute.TeleportPitch);
rotation = Quaternion.CreateFromYawPitchRoll(yaw, pitch, 0); rotation = Rotation.CreateFromTiltYawRoll(pitch, yaw, 0);
worldName = vp_string(sender, StringAttribute.TeleportWorld); worldName = vp_string(sender, StringAttribute.TeleportWorld);
} }
@ -546,7 +545,7 @@ public sealed partial class VirtualParadiseClient
private async void OnInviteNativeEvent(nint sender) private async void OnInviteNativeEvent(nint sender)
{ {
Vector3d position; Vector3d position;
Quaternion rotation; Rotation rotation;
int requestId; int requestId;
int userId; int userId;
string worldName; string worldName;
@ -566,7 +565,7 @@ public sealed partial class VirtualParadiseClient
var pitch = (float)vp_double(sender, FloatAttribute.InvitePitch); var pitch = (float)vp_double(sender, FloatAttribute.InvitePitch);
position = new Vector3d(x, y, z); position = new Vector3d(x, y, z);
rotation = Quaternion.CreateFromYawPitchRoll(yaw, pitch, 0); rotation = Rotation.CreateFromTiltYawRoll(pitch, yaw, 0);
worldName = vp_string(sender, StringAttribute.InviteWorld); worldName = vp_string(sender, StringAttribute.InviteWorld);
} }

View File

@ -1,11 +1,9 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Numerics;
using System.Threading.Channels; using System.Threading.Channels;
using VpSharp.Entities; using VpSharp.Entities;
using VpSharp.Exceptions; using VpSharp.Exceptions;
using VpSharp.Internal; using VpSharp.Internal;
using VpSharp.Internal.NativeAttributes; using VpSharp.Internal.NativeAttributes;
using X10D.Math;
using static VpSharp.Internal.NativeMethods; using static VpSharp.Internal.NativeMethods;
namespace VpSharp; namespace VpSharp;
@ -179,7 +177,7 @@ public sealed partial class VirtualParadiseClient
int id; int id;
int time; int time;
int owner; int owner;
Quaternion rotation; Rotation rotation;
Vector3d position; Vector3d position;
lock (Lock) lock (Lock)
@ -200,15 +198,12 @@ public sealed partial class VirtualParadiseClient
if (double.IsPositiveInfinity(angle)) if (double.IsPositiveInfinity(angle))
{ {
rotX = rotX.DegreesToRadians(); rotation = Rotation.CreateFromTiltYawRoll(rotX, rotY, rotZ);
rotY = rotY.DegreesToRadians();
rotZ = rotZ.DegreesToRadians();
rotation = Quaternion.CreateFromYawPitchRoll(rotY, rotX, rotZ);
} }
else else
{ {
var axis = new Vector3(rotX, rotY, rotZ); var axis = new Vector3d(rotX, rotY, rotZ);
rotation = Quaternion.CreateFromAxisAngle(axis, angle); rotation = Rotation.CreateFromAxisAngle(axis, angle);
} }
time = vp_int(sender, IntegerAttribute.ObjectTime); time = vp_int(sender, IntegerAttribute.ObjectTime);

View File

@ -2,7 +2,6 @@ using System.Collections.Concurrent;
using System.Drawing; using System.Drawing;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Numerics;
using System.Security.Authentication; using System.Security.Authentication;
using System.Threading.Channels; using System.Threading.Channels;
using VpSharp.Entities; using VpSharp.Entities;
@ -218,7 +217,7 @@ public sealed partial class VirtualParadiseClient : IDisposable
public async Task<VirtualParadiseWorld> EnterAsync(string worldName, Vector3d position) public async Task<VirtualParadiseWorld> EnterAsync(string worldName, Vector3d position)
{ {
await EnterAsync(worldName).ConfigureAwait(false); await EnterAsync(worldName).ConfigureAwait(false);
await CurrentAvatar!.TeleportAsync(position, Quaternion.Identity).ConfigureAwait(false); await CurrentAvatar!.TeleportAsync(position, Rotation.None).ConfigureAwait(false);
return CurrentWorld!; return CurrentWorld!;
} }
@ -235,7 +234,7 @@ public sealed partial class VirtualParadiseClient : IDisposable
/// <exception cref="Exception">Connection to the universe server was lost, or connecting to the world failed.</exception> /// <exception cref="Exception">Connection to the universe server was lost, or connecting to the world failed.</exception>
/// <exception cref="WorldNotFoundException">The specified world was not found.</exception> /// <exception cref="WorldNotFoundException">The specified world was not found.</exception>
/// <exception cref="TimeoutException">Connection to the world server timed out.</exception> /// <exception cref="TimeoutException">Connection to the world server timed out.</exception>
public async Task<VirtualParadiseWorld> EnterAsync(string worldName, Vector3d position, Quaternion rotation) public async Task<VirtualParadiseWorld> EnterAsync(string worldName, Vector3d position, Rotation rotation)
{ {
await EnterAsync(worldName).ConfigureAwait(false); await EnterAsync(worldName).ConfigureAwait(false);
await CurrentAvatar!.TeleportAsync(position, rotation).ConfigureAwait(false); await CurrentAvatar!.TeleportAsync(position, rotation).ConfigureAwait(false);
@ -257,7 +256,7 @@ public sealed partial class VirtualParadiseClient : IDisposable
public async Task EnterAsync(VirtualParadiseWorld world, Vector3d position) public async Task EnterAsync(VirtualParadiseWorld world, Vector3d position)
{ {
await EnterAsync(world).ConfigureAwait(false); await EnterAsync(world).ConfigureAwait(false);
await CurrentAvatar!.TeleportAsync(position, Quaternion.Identity).ConfigureAwait(false); await CurrentAvatar!.TeleportAsync(position, Rotation.None).ConfigureAwait(false);
} }
/// <summary> /// <summary>
@ -273,7 +272,7 @@ public sealed partial class VirtualParadiseClient : IDisposable
/// <exception cref="Exception">Connection to the universe server was lost, or connecting to the world failed.</exception> /// <exception cref="Exception">Connection to the universe server was lost, or connecting to the world failed.</exception>
/// <exception cref="WorldNotFoundException">The specified world was not found.</exception> /// <exception cref="WorldNotFoundException">The specified world was not found.</exception>
/// <exception cref="TimeoutException">Connection to the world server timed out.</exception> /// <exception cref="TimeoutException">Connection to the world server timed out.</exception>
public async Task EnterAsync(VirtualParadiseWorld world, Vector3d position, Quaternion rotation) public async Task EnterAsync(VirtualParadiseWorld world, Vector3d position, Rotation rotation)
{ {
await EnterAsync(world).ConfigureAwait(false); await EnterAsync(world).ConfigureAwait(false);
await CurrentAvatar!.TeleportAsync(position, rotation).ConfigureAwait(false); await CurrentAvatar!.TeleportAsync(position, rotation).ConfigureAwait(false);
@ -401,7 +400,7 @@ public sealed partial class VirtualParadiseClient : IDisposable
{ {
Application = _configuration.Application!, Application = _configuration.Application!,
Name = $"[{_configuration.BotName}]", Name = $"[{_configuration.BotName}]",
Location = new Location(world, Vector3d.Zero, Quaternion.Identity), Location = new Location(world, Vector3d.Zero, Rotation.None),
User = CurrentUser! User = CurrentUser!
}; };