Compare commits

...

3 Commits

Author SHA1 Message Date
Oliver Booth e71494ef83
refactor!: revert 63e775855a 2024-06-01 18:14:14 +01:00
Oliver Booth 2669b5083d
refactor!: revert to 397ec2bcf9 2024-05-30 19:36:57 +01:00
Oliver Booth c54dc755ce
test: switch to NUnit 2024-05-23 11:57:56 +01:00
58 changed files with 443 additions and 729 deletions

View File

@ -8,17 +8,17 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\VpSharp.Commands\VpSharp.Commands.csproj"/> <ProjectReference Include="..\..\VpSharp.Commands\VpSharp.Commands.csproj" />
<ProjectReference Include="..\..\VpSharp\VpSharp.csproj"/> <ProjectReference Include="..\..\VpSharp\VpSharp.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Update="libvpsdk.so"> <None Update="libvpsdk.so">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
<None Update="VPSDK.dll"> <None Update="VPSDK.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -8,17 +8,17 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\VpSharp.Commands\VpSharp.Commands.csproj" /> <ProjectReference Include="..\..\VpSharp.Commands\VpSharp.Commands.csproj" />
<ProjectReference Include="..\..\VpSharp\VpSharp.csproj" /> <ProjectReference Include="..\..\VpSharp\VpSharp.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Update="VPSDK.dll"> <None Update="VPSDK.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
<None Update="libvpsdk.so"> <None Update="libvpsdk.so">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -13,6 +13,6 @@ public sealed class RequireBotOwnerAttribute : PreExecutionCheckAttribute
throw new ArgumentNullException(nameof(context)); throw new ArgumentNullException(nameof(context));
} }
return Task.FromResult(context.Avatar.UserId == context.Client.CurrentUser?.Id); return Task.FromResult(context.Avatar.User == context.Client.CurrentUser);
} }
} }

View File

@ -52,6 +52,6 @@ public sealed class RequireUserIdAttribute : PreExecutionCheckAttribute
throw new ArgumentNullException(nameof(context)); throw new ArgumentNullException(nameof(context));
} }
return Task.FromResult(UserIds.Contains(context.Avatar.UserId)); return Task.FromResult(UserIds.Any(i => context.Avatar.User.Id == i));
} }
} }

View File

@ -47,14 +47,14 @@ public sealed class RequireUserNameAttribute : PreExecutionCheckAttribute
public IReadOnlyList<string> Names { get; } public IReadOnlyList<string> Names { get; }
/// <inheritdoc /> /// <inheritdoc />
protected internal override async Task<bool> PerformAsync(CommandContext context) protected internal override Task<bool> PerformAsync(CommandContext context)
{ {
if (context is null) if (context is null)
{ {
throw new ArgumentNullException(nameof(context)); throw new ArgumentNullException(nameof(context));
} }
IUser user = await context.Avatar.GetUserAsync().ConfigureAwait(false); VirtualParadiseUser user = context.Avatar.User;
return Names.Contains(user.Name); return Task.FromResult(Names.Contains(user.Name));
} }
} }

View File

@ -9,7 +9,7 @@ namespace VpSharp.Commands;
/// </summary> /// </summary>
public sealed class CommandContext public sealed class CommandContext
{ {
internal CommandContext(VirtualParadiseClient client, IAvatar avatar, string commandName, string alias, internal CommandContext(VirtualParadiseClient client, VirtualParadiseAvatar avatar, string commandName, string alias,
string rawArguments) string rawArguments)
{ {
Client = client; Client = client;
@ -36,8 +36,8 @@ public sealed class CommandContext
/// Gets the avatar who executed the command. /// Gets the avatar who executed the command.
/// </summary> /// </summary>
/// <value>The executing avatar.</value> /// <value>The executing avatar.</value>
public IAvatar Avatar { get; } public VirtualParadiseAvatar Avatar { get; }
/// <summary> /// <summary>
/// Gets the client which raised the event. /// Gets the client which raised the event.
/// </summary> /// </summary>
@ -65,11 +65,10 @@ public sealed class CommandContext
/// regular chat message. /// regular chat message.
/// </param> /// </param>
/// <returns>The message which was sent.</returns> /// <returns>The message which was sent.</returns>
public async Task<IMessage> RespondAsync(string message, bool ephemeral = false) public Task<VirtualParadiseMessage> RespondAsync(string message, bool ephemeral = false)
{ {
return ephemeral return ephemeral
? await Avatar.SendMessageAsync(Client.CurrentAvatar?.Name, message, FontStyle.Regular, Color.Black) ? Avatar.SendMessageAsync(Client.CurrentAvatar?.Name, message, FontStyle.Regular, Color.Black)
.ConfigureAwait(false) : Client.SendMessageAsync(message);
: await Client.SendMessageAsync(message).ConfigureAwait(false);
} }
} }

View File

@ -176,14 +176,14 @@ public sealed class CommandsExtension : VirtualParadiseClientExtension
} }
/// <inheritdoc /> /// <inheritdoc />
protected internal override Task OnMessageReceived(IMessage message) protected internal override Task OnMessageReceived(VirtualParadiseMessage message)
{ {
if (message is null) if (message is null)
{ {
throw new ArgumentNullException(nameof(message)); throw new ArgumentNullException(nameof(message));
} }
if (message is IUserMessage) if (message.Type != MessageType.ChatMessage)
{ {
return base.OnMessageReceived(message); return base.OnMessageReceived(message);
} }

View File

@ -1,8 +1,6 @@
using System.Reactive.Linq; using VpSharp;
using VpSharp;
using VpSharp.Commands; using VpSharp.Commands;
using VpSharp.Entities; using VpSharp.Entities;
using VpSharp.Extensions;
using VpSharp.IntegrationTests.CommandModules; using VpSharp.IntegrationTests.CommandModules;
string? username = Environment.GetEnvironmentVariable("username"); string? username = Environment.GetEnvironmentVariable("username");
@ -30,8 +28,6 @@ var configuration = new VirtualParadiseConfiguration
}; };
using var client = new VirtualParadiseClient(configuration); using var client = new VirtualParadiseClient(configuration);
client.AvatarJoined.Where(a => !a.IsBot).SubscribeAsync(async avatar => await client.SendMessageAsync($"Hello, {avatar.Name}"));
CommandsExtension commands = client.UseCommands(new CommandsExtensionConfiguration {Prefixes = new[] {"!"}}); CommandsExtension commands = client.UseCommands(new CommandsExtensionConfiguration {Prefixes = new[] {"!"}});
commands.RegisterCommands<TestCommands>(); commands.RegisterCommands<TestCommands>();
@ -42,10 +38,10 @@ Console.WriteLine(@"Logging in");
await client.LoginAsync(); await client.LoginAsync();
Console.WriteLine(@"Entering world"); Console.WriteLine(@"Entering world");
World world = await client.EnterAsync("Mutation"); VirtualParadiseWorld world = await client.EnterAsync("Mutation");
Console.WriteLine(@"Entered world!"); Console.WriteLine(@"Entered world!");
IAvatar avatar = client.CurrentAvatar!; VirtualParadiseAvatar avatar = client.CurrentAvatar!;
Console.WriteLine($@"My name is {avatar.Name} and I am at {avatar.Location}"); Console.WriteLine($@"My name is {avatar.Name} and I am at {avatar.Location}");
Console.WriteLine($@"Entered {world.Name} with size {world.Size}"); Console.WriteLine($@"Entered {world.Name} with size {world.Size}");

View File

@ -6,18 +6,17 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.0"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0"/> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0"/>
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1"/> <PackageReference Include="NUnit" Version="3.14.0"/>
<PackageReference Include="MSTest.TestFramework" Version="3.1.1"/> <PackageReference Include="NUnit.Analyzers" Version="3.9.0"/>
<PackageReference Include="coverlet.collector" Version="6.0.0"> <PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -1,34 +1,40 @@
using System.Drawing; using System.Drawing;
using NUnit.Framework;
namespace VpSharp.Tests; namespace VpSharp.Tests;
[TestClass] internal sealed class ColorFTests
public class ColorFTests
{ {
[TestMethod] [Test]
public void Black_ToVpColorF_ShouldGive0ForProperties() public void Black_ToVpColorF_ShouldGive0ForProperties()
{ {
ColorF color = Color.Black; ColorF color = Color.Black;
Assert.AreEqual(color.A, 1.0f, float.Epsilon); Assert.Multiple(() =>
Assert.AreEqual(color.R, 0.0f, float.Epsilon); {
Assert.AreEqual(color.G, 0.0f, float.Epsilon); Assert.That(color.A, Is.EqualTo(1.0f).Within(float.Epsilon));
Assert.AreEqual(color.B, 0.0f, float.Epsilon); Assert.That(color.R, Is.EqualTo(0.0f).Within(float.Epsilon));
Assert.That(color.G, Is.EqualTo(0.0f).Within(float.Epsilon));
Assert.That(color.B, Is.EqualTo(0.0f).Within(float.Epsilon));
});
} }
[TestMethod] [Test]
public void Transparent_ToVpColorF_ShouldGive0ForAlpha() public void Transparent_ToVpColorF_ShouldGive0ForAlpha()
{ {
ColorF color = Color.Transparent; ColorF color = Color.Transparent;
Assert.AreEqual(color.A, 0.0f, float.Epsilon); Assert.That(color.A, Is.EqualTo(0.0f).Within(float.Epsilon));
} }
[TestMethod] [Test]
public void White_ToVpColorF_ShouldGive1ForProperties() public void White_ToVpColorF_ShouldGive1ForProperties()
{ {
ColorF color = Color.White; ColorF color = Color.White;
Assert.AreEqual(color.A, 1.0f, float.Epsilon); Assert.Multiple(() =>
Assert.AreEqual(color.R, 1.0f, float.Epsilon); {
Assert.AreEqual(color.G, 1.0f, float.Epsilon); Assert.That(color.A, Is.EqualTo(1.0f).Within(float.Epsilon));
Assert.AreEqual(color.B, 1.0f, float.Epsilon); Assert.That(color.R, Is.EqualTo(1.0f).Within(float.Epsilon));
Assert.That(color.G, Is.EqualTo(1.0f).Within(float.Epsilon));
Assert.That(color.B, Is.EqualTo(1.0f).Within(float.Epsilon));
});
} }
} }

View File

@ -1,11 +1,11 @@
using System.Diagnostics; using System.Diagnostics;
using NUnit.Framework;
namespace VpSharp.Tests; namespace VpSharp.Tests;
[TestClass] internal sealed class CoordinateTests
public sealed class CoordinateTests
{ {
[TestMethod] [Test]
public void TestAbsolute() public void TestAbsolute()
{ {
TestCoordinates("asdf", 0.0, 0.0, 0.0, 0.0, world: "asdf"); TestCoordinates("asdf", 0.0, 0.0, 0.0, 0.0, world: "asdf");
@ -16,7 +16,7 @@ public sealed class CoordinateTests
TestCoordinates("2355.71S 3429.68E -0.37a 0", -3429.68, -0.37, -2355.71); TestCoordinates("2355.71S 3429.68E -0.37a 0", -3429.68, -0.37, -2355.71);
} }
[TestMethod] [Test]
public void TestRelative() public void TestRelative()
{ {
TestCoordinates("-1.1 +0 -1.2a", 0.0, -1.2, -1.1, 0.0, true); TestCoordinates("-1.1 +0 -1.2a", 0.0, -1.2, -1.1, 0.0, true);
@ -24,6 +24,24 @@ public sealed class CoordinateTests
TestCoordinates("+1 +1 +1a", 1.0, 1.0, 1.0, 0.0, true); TestCoordinates("+1 +1 +1a", 1.0, 1.0, 1.0, 0.0, true);
} }
[Test]
public void ToString_ShouldReturnFormattedString_GivenCoordinates()
{
Coordinates coordinates = Coordinates.Parse("10n 5e 1a 123");
string result = coordinates.ToString();
Assert.That(result, Is.EqualTo("10.00n 5.00e 1.00a 123.00"));
}
[Test]
public void ToString_ShouldReturnFormattedString_GivenArguments()
{
Coordinates coordinates = Coordinates.Parse("10n 5e 1a 123");
string result = coordinates.ToString("0");
Assert.That(result, Is.EqualTo("10n 5e 1a 123"));
}
private static void TestCoordinates( private static void TestCoordinates(
string input, string input,
double x, double x,
@ -41,18 +59,22 @@ public sealed class CoordinateTests
Trace.WriteLine($"Parsed: {coordinates}"); Trace.WriteLine($"Parsed: {coordinates}");
Trace.WriteLine("----"); Trace.WriteLine("----");
Assert.AreEqual(x, coordinates.X); Assert.Multiple(() =>
Assert.AreEqual(y, coordinates.Y); {
Assert.AreEqual(z, coordinates.Z); Assert.That(coordinates.X, Is.EqualTo(x));
Assert.AreEqual(yaw, coordinates.Yaw); Assert.That(coordinates.Y, Is.EqualTo(y));
Assert.AreEqual(isRelative, coordinates.IsRelative); Assert.That(coordinates.Z, Is.EqualTo(z));
Assert.That(coordinates.Yaw, Is.EqualTo(yaw));
Assert.That(coordinates.IsRelative, Is.EqualTo(isRelative));
});
if (string.IsNullOrWhiteSpace(world)) if (string.IsNullOrWhiteSpace(world))
{ {
Assert.IsTrue(string.IsNullOrWhiteSpace(coordinates.World)); Assert.IsTrue(string.IsNullOrWhiteSpace(coordinates.World));
} }
else else
{ {
Assert.AreEqual(world, coordinates.World); Assert.That(coordinates.World, Is.EqualTo(world));
} }
} }
} }

View File

@ -1,29 +1,29 @@
using System.Diagnostics; using System.Diagnostics;
using System.Text; using System.Text;
using NUnit.Framework;
using VpSharp.Internal; using VpSharp.Internal;
namespace VpSharp.Tests; namespace VpSharp.Tests;
[TestClass] internal sealed class MarshallerTests
public class MarshellerTests
{ {
private static readonly Utf8StringToNative ManagedToNativeMarshaller = new(); private static readonly Utf8StringToNative ManagedToNativeMarshaller = new();
private static readonly Utf8StringToManaged NativeToManagedMarshaller = new(); private static readonly Utf8StringToManaged NativeToManagedMarshaller = new();
private static readonly Random Random = new(); private static readonly Random Random = new();
[TestMethod] [Test]
public unsafe void MarshalNativeToManaged_ShouldReturnPointerToUtf8Bytes_GivenString() public unsafe void MarshalNativeToManaged_ShouldReturnPointerToUtf8Bytes_GivenString()
{ {
string value = GenerateRandomString(); string value = GenerateRandomString();
byte* pointer = GetBytePointer(value, out int count); byte* pointer = GetBytePointer(value, out int count);
string expected = Encoding.UTF8.GetString(pointer, count); string expected = Encoding.UTF8.GetString(pointer, count);
var actual = (string)NativeToManagedMarshaller.MarshalNativeToManaged((nint)pointer); var actual = (string)NativeToManagedMarshaller.MarshalNativeToManaged((nint)pointer);
Assert.AreEqual(expected, actual); Assert.That(actual, Is.EqualTo(expected));
CleanUpNativeData(pointer); CleanUpNativeData(pointer);
} }
[TestMethod] [Test]
public unsafe void MarshalManagedToNative_ShouldReturnPointerToUtf8Bytes_GivenString() public unsafe void MarshalManagedToNative_ShouldReturnPointerToUtf8Bytes_GivenString()
{ {
string value = GenerateRandomString(); string value = GenerateRandomString();
@ -31,7 +31,7 @@ public class MarshellerTests
string result = Encoding.UTF8.GetString(pointer, count); string result = Encoding.UTF8.GetString(pointer, count);
Trace.WriteLine($"Test string: {value}"); Trace.WriteLine($"Test string: {value}");
Assert.AreEqual(value, result); Assert.That(result, Is.EqualTo(value));
CleanUpNativeData(pointer); CleanUpNativeData(pointer);
} }

View File

@ -1 +0,0 @@
global using Microsoft.VisualStudio.TestTools.UnitTesting;

View File

@ -26,8 +26,8 @@ public abstract class VirtualParadiseClientExtension
/// <summary> /// <summary>
/// Called when a chat message is received. /// Called when a chat message is received.
/// </summary> /// </summary>
/// <param name="message">The message which was received.</param> /// <param name="args">An object containing event data.</param>
protected internal virtual Task OnMessageReceived(IMessage message) protected internal virtual Task OnMessageReceived(VirtualParadiseMessage message)
{ {
return Task.CompletedTask; return Task.CompletedTask;
} }

View File

@ -1,30 +0,0 @@
using System.Drawing;
namespace VpSharp.Entities;
/// <summary>
/// Represents a chat message that was sent by a user.
/// </summary>
public sealed class ConsoleMessage : Message, IConsoleMessage
{
/// <summary>
/// Initializes a new instance of the <see cref="UserMessage" /> class.
/// </summary>
/// <param name="author">The author of the message.</param>
/// <param name="name">The apparent sender's name of the message.</param>
/// <param name="content">The content of the message.</param>
/// <param name="color">A <see cref="System.Drawing.Color" /> value representing the color of the message.</param>
/// <param name="fontStyle">A <see cref="FontStyle" /> value representing the font style of the message.</param>
public ConsoleMessage(IAvatar author, string name, string content, Color color, FontStyle fontStyle)
: base(author, name, content)
{
Color = color;
Style = fontStyle;
}
/// <inheritdoc />
public Color Color { get; }
/// <inheritdoc />
public FontStyle Style { get; }
}

View File

@ -1,184 +0,0 @@
using System.Drawing;
namespace VpSharp.Entities;
public interface IAvatar
{
/// <summary>
/// Gets the details of the application this avatar is using.
/// </summary>
/// <value>The avatar's application details.</value>
Application Application { get; }
/// <summary>
/// Gets a value indicating whether this avatar is a bot.
/// </summary>
/// <value><see langword="true" /> if this avatar is a bot; otherwise, <see langword="false" />.</value>
bool IsBot { get; }
/// <summary>
/// Gets the location of this avatar.
/// </summary>
/// <value>The location of this avatar.</value>
Location Location { get; }
/// <summary>
/// Gets the name of this avatar.
/// </summary>
/// <value>The name of this avatar.</value>
string Name { get; }
/// <summary>
/// Gets the session ID of this avatar.
/// </summary>
/// <value>The session ID.</value>
int Session { get; }
/// <summary>
/// Gets the type of this avatar.
/// </summary>
/// <value>The type of this avatar.</value>
int Type { get; }
/// <summary>
/// Gets the user ID associated with this avatar.
/// </summary>
/// <value>The user ID.</value>
int UserId { get; }
/// <summary>
/// Clicks this avatar.
/// </summary>
/// <param name="clickPoint">The position at which the avatar should be clicked.</param>
/// <exception cref="InvalidOperationException">
/// <para>The action cannot be performed on the client's current avatar.</para>
/// -or-
/// <para>An attempt was made to click an avatar outside of a world.</para>
/// </exception>
Task ClickAsync(Vector3d? clickPoint = null);
/// <summary>
/// Determines if two <see cref="Avatar" /> instances are equal.
/// </summary>
/// <param name="other">The other instance.</param>
/// <returns>
/// <see langword="true" /> if this instance is equal to <paramref name="other" />; otherwise, <see langword="false" />.
/// </returns>
bool Equals(Avatar? other);
/// <summary>
/// Gets the user associated with this avatar.
/// </summary>
/// <returns>The user.</returns>
Task<IUser> GetUserAsync();
/// <summary>
/// Sends a console message to the avatar with no name.
/// </summary>
/// <param name="message">The message to send.</param>
/// <param name="fontStyle">The font style of the message.</param>
/// <param name="color">The text color of the message.</param>
/// <returns>The message which was sent.</returns>
/// <exception cref="ArgumentNullException"><paramref name="message" /> is <see langword="null" />.</exception>
/// <exception cref="InvalidOperationException">
/// <para>An attempt was made to send a message while not connected to a world.</para>
/// -or-
/// <para>An attempt was made to send a message to an avatar that is not in the world.</para>
/// </exception>
/// <exception cref="ArgumentException">
/// <para><paramref name="message" /> is empty, or consists of only whitespace.</para>
/// -or-
/// <para><paramref name="message" /> is too long to send.</para>
/// </exception>
Task<IConsoleMessage> SendMessageAsync(string message, FontStyle fontStyle, Color color);
/// <summary>
/// Sends a console message to the avatar.
/// </summary>
/// <param name="name">The apparent author of the message.</param>
/// <param name="message">The message to send.</param>
/// <param name="fontStyle">The font style of the message.</param>
/// <param name="color">The text color of the message.</param>
/// <returns>The message which was sent.</returns>
/// <exception cref="ArgumentNullException"><paramref name="message" /> is <see langword="null" />.</exception>
/// <exception cref="InvalidOperationException">
/// <para>An attempt was made to send a message while not connected to a world.</para>
/// -or-
/// <para>An attempt was made to send a message to an avatar that is not in the world.</para>
/// </exception>
/// <exception cref="ArgumentException">
/// <para><paramref name="message" /> is empty, or consists of only whitespace.</para>
/// -or-
/// <para><paramref name="message" /> is too long to send.</para>
/// </exception>
/// <remarks>Passing <see langword="null" /> to <paramref name="name" /> will hide the name from the recipient.</remarks>
Task<IConsoleMessage> SendMessageAsync(string? name, string message, FontStyle fontStyle, Color color);
/// <summary>
/// Sends a URI to this avatar.
/// </summary>
/// <param name="uri">The URI to send.</param>
/// <param name="target">The URL target. See <see cref="UriTarget" /> for more information.</param>
/// <exception cref="InvalidOperationException">The action cannot be performed on the client's current avatar.</exception>
/// <exception cref="ArgumentNullException"><paramref name="uri" /> is <see langword="null" />.</exception>
Task SendUriAsync(Uri uri, UriTarget target = UriTarget.Browser);
/// <summary>
/// Modifies the world settings for this avatar.
/// </summary>
/// <param name="action">The builder which defines parameters to change.</param>
/// <exception cref="ArgumentNullException"><paramref name="action" /> is <see langword="null" />.</exception>
/// <exception cref="UnauthorizedAccessException">The client does not have permission to modify world settings.</exception>
Task SendWorldSettings(Action<WorldSettingsBuilder> action);
/// <summary>
/// Teleports the avatar to another world.
/// </summary>
/// <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>
/// <exception cref="ArgumentNullException"><paramref name="world" /> is <see langword="null" />.</exception>
Task TeleportAsync(World world, Vector3d position);
/// <summary>
/// Teleports the avatar to another world.
/// </summary>
/// <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="rotation">The rotation to which this avatar should be teleported.</param>
/// <exception cref="ArgumentNullException"><paramref name="world" /> is <see langword="null" />.</exception>
Task TeleportAsync(World world, Vector3d position, Rotation rotation);
/// <summary>
/// Teleports the avatar to another world.
/// </summary>
/// <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>
Task TeleportAsync(string world, Vector3d position);
/// <summary>
/// Teleports the avatar to another world.
/// </summary>
/// <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="rotation">The rotation to which this avatar should be teleported.</param>
Task TeleportAsync(string world, Vector3d position, Rotation rotation);
/// <summary>
/// Teleports the avatar to a new position within the current world.
/// </summary>
/// <param name="position">The position to which this avatar should be teleported.</param>
Task TeleportAsync(Vector3d position);
/// <summary>
/// Teleports the avatar to a new position and rotation within the current world.
/// </summary>
/// <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>
Task TeleportAsync(Vector3d position, Rotation rotation);
/// <summary>
/// Teleports this avatar to a new location, which may or may not be a new world.
/// </summary>
/// <param name="location">The location to which this avatar should be teleported.</param>
Task TeleportAsync(Location location);
}

View File

@ -1,21 +0,0 @@
using System.Drawing;
namespace VpSharp.Entities;
/// <summary>
/// Represents a console message.
/// </summary>
public interface IConsoleMessage : IMessage
{
/// <summary>
/// Gets the color of the message.
/// </summary>
/// <value>A <see cref="System.Drawing.Color" /> value representing the color.</value>
Color Color { get; }
/// <summary>
/// Gets the font style of the message.
/// </summary>
/// <value>A <see cref="FontStyle" /> value representing the font style.</value>
FontStyle Style { get; }
}

View File

@ -1,25 +0,0 @@
namespace VpSharp.Entities;
/// <summary>
/// Represents a message.
/// </summary>
public interface IMessage
{
/// <summary>
/// Gets the author of the message.
/// </summary>
/// <value>The avatar which authored the message.</value>
IAvatar Author { get; }
/// <summary>
/// Gets the content of the message.
/// </summary>
/// <value>The content.</value>
string Content { get; }
/// <summary>
/// Gets the apparent sender's name of the message.
/// </summary>
/// <value>The sender's name.</value>
string Name { get; }
}

View File

@ -1,71 +0,0 @@
using VpSharp.Exceptions;
namespace VpSharp.Entities;
public interface IUser
{
/// <summary>
/// Gets the email address of this user.
/// </summary>
/// <value>The email address of this user.</value>
string EmailAddress { get; }
/// <summary>
/// Gets the ID of this user.
/// </summary>
/// <value>The user's ID.</value>
int Id { get; }
/// <summary>
/// Gets the date and time at which this user was last online.
/// </summary>
/// <value>A <see cref="DateTimeOffset" /> representing the date and time this user was last online.</value>
DateTimeOffset LastLogin { get; }
/// <summary>
/// Gets the name of this user.
/// </summary>
/// <value>The user's name.</value>
string Name { get; }
/// <summary>
/// Gets the duration for which this user has been online.
/// </summary>
/// <value>A <see cref="TimeSpan" /> representing the duration for which this user has been online.</value>
TimeSpan OnlineTime { get; }
/// <summary>
/// Gets the date and time at which this user was registered.
/// </summary>
/// <value>A <see cref="DateTimeOffset" /> representing the date and time this user was registered.</value>
DateTimeOffset RegistrationTime { get; }
/// <summary>
/// Determines if two <see cref="User" /> instances are equal.
/// </summary>
/// <param name="other">The other instance.</param>
/// <returns>
/// <see langword="true" /> if this instance is equal to <paramref name="other" />; otherwise, <see langword="false" />.
/// </returns>
bool Equals(User? other);
/// <summary>
/// Invites this user to a specified location.
/// </summary>
/// <param name="location">
/// The invitation location. If <see langword="null" />, the client's current location is used.
/// </param>
Task<InviteResponse> InviteAsync(Location? location = null);
/// <summary>
/// Sends a to join request to the user.
/// </summary>
/// <param name="suppressTeleport">
/// If <see langword="true" />, the client's avatar will not teleport to the requested location automatically.
/// Be careful, there is no way to retrieve
/// </param>
/// <returns>The result of the request.</returns>
/// <exception cref="UserNotFoundException">This user is invalid and cannot be joined.</exception>
/// <exception cref="InvalidOperationException">An unexpected error occurred trying to join the user.</exception>
Task<JoinResult> JoinAsync(bool suppressTeleport = false);
}

View File

@ -1,6 +0,0 @@
namespace VpSharp.Entities;
/// <summary>
/// Represents a chat message that was sent by a user.
/// </summary>
public interface IUserMessage : IMessage;

View File

@ -1,29 +0,0 @@
namespace VpSharp.Entities;
/// <summary>
/// Represents a message.
/// </summary>
public abstract class Message : IMessage
{
/// <summary>
/// Initializes a new instance of the <see cref="Message" /> class.
/// </summary>
/// <param name="author">The author of the message.</param>
/// <param name="name">The apparent sender's name of the message.</param>
/// <param name="content">The content of the message.</param>
protected Message(IAvatar author, string name, string content)
{
Author = author;
Content = content;
Name = name;
}
/// <inheritdoc />
public IAvatar Author { get; }
/// <inheritdoc />
public string Content { get; }
/// <inheritdoc />
public string Name { get; }
}

View File

@ -1,17 +0,0 @@
namespace VpSharp.Entities;
/// <summary>
/// Represents a chat message that was sent by a user.
/// </summary>
public sealed class UserMessage : Message, IUserMessage
{
/// <summary>
/// Initializes a new instance of the <see cref="UserMessage" /> class.
/// </summary>
/// <param name="author">The author of the message.</param>
/// <param name="content">The content of the message.</param>
public UserMessage(IAvatar author, string content)
: base(author, author.Name, content)
{
}
}

View File

@ -10,12 +10,11 @@ namespace VpSharp.Entities;
/// <summary> /// <summary>
/// Represents an avatar within a world. /// Represents an avatar within a world.
/// </summary> /// </summary>
public sealed class Avatar : IEquatable<Avatar>, IAvatar public sealed class VirtualParadiseAvatar : IEquatable<VirtualParadiseAvatar>
{ {
private readonly VirtualParadiseClient _client; private readonly VirtualParadiseClient _client;
private IUser? _user;
internal Avatar(VirtualParadiseClient client, int session) internal VirtualParadiseAvatar(VirtualParadiseClient client, int session)
{ {
_client = client ?? throw new ArgumentNullException(nameof(client)); _client = client ?? throw new ArgumentNullException(nameof(client));
Session = session; Session = session;
@ -33,7 +32,7 @@ public sealed class Avatar : IEquatable<Avatar>, IAvatar
/// <value><see langword="true" /> if this avatar is a bot; otherwise, <see langword="false" />.</value> /// <value><see langword="true" /> if this avatar is a bot; otherwise, <see langword="false" />.</value>
public bool IsBot public bool IsBot
{ {
get => Name is { Length: > 1 } name && name[0] == '[' && name[^1] == ']'; get => Name is {Length: > 1} name && name[0] == '[' && name[^1] == ']';
} }
/// <summary> /// <summary>
@ -61,13 +60,13 @@ public sealed class Avatar : IEquatable<Avatar>, IAvatar
public int Type { get; internal set; } public int Type { get; internal set; }
/// <summary> /// <summary>
/// Gets the user ID associated with this avatar. /// Gets the user associated with this avatar.
/// </summary> /// </summary>
/// <value>The user ID.</value> /// <value>The user.</value>
public int UserId { get; internal set; } public VirtualParadiseUser User { get; internal set; } = null!;
/// <summary> /// <summary>
/// Determines if two <see cref="Avatar" /> instances are equal. /// Determines if two <see cref="VirtualParadiseAvatar" /> instances are equal.
/// </summary> /// </summary>
/// <param name="left">The first instance.</param> /// <param name="left">The first instance.</param>
/// <param name="right">The second instance.</param> /// <param name="right">The second instance.</param>
@ -75,13 +74,13 @@ public sealed class Avatar : IEquatable<Avatar>, IAvatar
/// <see langword="true" /> if <paramref name="left" /> is equal to <paramref name="right" />; otherwise, /// <see langword="true" /> if <paramref name="left" /> is equal to <paramref name="right" />; otherwise,
/// <see langword="false" />. /// <see langword="false" />.
/// </returns> /// </returns>
public static bool operator ==(Avatar? left, Avatar? right) public static bool operator ==(VirtualParadiseAvatar? left, VirtualParadiseAvatar? right)
{ {
return Equals(left, right); return Equals(left, right);
} }
/// <summary> /// <summary>
/// Determines if two <see cref="Avatar" /> instances are not equal. /// Determines if two <see cref="VirtualParadiseAvatar" /> instances are not equal.
/// </summary> /// </summary>
/// <param name="left">The first instance.</param> /// <param name="left">The first instance.</param>
/// <param name="right">The second instance.</param> /// <param name="right">The second instance.</param>
@ -89,7 +88,7 @@ public sealed class Avatar : IEquatable<Avatar>, IAvatar
/// <see langword="true" /> if <paramref name="left" /> is not equal to <paramref name="right" />; otherwise, /// <see langword="true" /> if <paramref name="left" /> is not equal to <paramref name="right" />; otherwise,
/// <see langword="false" />. /// <see langword="false" />.
/// </returns> /// </returns>
public static bool operator !=(Avatar? left, Avatar? right) public static bool operator !=(VirtualParadiseAvatar? left, VirtualParadiseAvatar? right)
{ {
return !Equals(left, right); return !Equals(left, right);
} }
@ -133,13 +132,13 @@ public sealed class Avatar : IEquatable<Avatar>, IAvatar
} }
/// <summary> /// <summary>
/// Determines if two <see cref="Avatar" /> instances are equal. /// Determines if two <see cref="VirtualParadiseAvatar" /> instances are equal.
/// </summary> /// </summary>
/// <param name="other">The other instance.</param> /// <param name="other">The other instance.</param>
/// <returns> /// <returns>
/// <see langword="true" /> if this instance is equal to <paramref name="other" />; otherwise, <see langword="false" />. /// <see langword="true" /> if this instance is equal to <paramref name="other" />; otherwise, <see langword="false" />.
/// </returns> /// </returns>
public bool Equals(Avatar? other) public bool Equals(VirtualParadiseAvatar? other)
{ {
if (ReferenceEquals(null, other)) if (ReferenceEquals(null, other))
{ {
@ -151,33 +150,23 @@ public sealed class Avatar : IEquatable<Avatar>, IAvatar
return true; return true;
} }
return Session == other.Session && UserId.Equals(other.UserId); return Session == other.Session && User.Equals(other.User);
} }
/// <inheritdoc /> /// <inheritdoc />
public override bool Equals(object? obj) public override bool Equals(object? obj)
{ {
return ReferenceEquals(this, obj) || (obj is Avatar other && Equals(other)); return ReferenceEquals(this, obj) || (obj is VirtualParadiseAvatar other && Equals(other));
} }
/// <inheritdoc /> /// <inheritdoc />
public override int GetHashCode() public override int GetHashCode()
{ {
// ReSharper disable NonReadonlyMemberInGetHashCode // ReSharper disable NonReadonlyMemberInGetHashCode
return HashCode.Combine(Session, UserId); return HashCode.Combine(Session, User);
// ReSharper restore NonReadonlyMemberInGetHashCode // ReSharper restore NonReadonlyMemberInGetHashCode
} }
/// <summary>
/// Gets the user associated with this avatar.
/// </summary>
/// <returns>The user.</returns>
public async Task<IUser> GetUserAsync()
{
_user ??= await _client.GetUserAsync(UserId).ConfigureAwait(false);
return _user;
}
/// <summary> /// <summary>
/// Sends a console message to the avatar with no name. /// Sends a console message to the avatar with no name.
/// </summary> /// </summary>
@ -196,8 +185,9 @@ public sealed class Avatar : IEquatable<Avatar>, IAvatar
/// -or- /// -or-
/// <para><paramref name="message" /> is too long to send.</para> /// <para><paramref name="message" /> is too long to send.</para>
/// </exception> /// </exception>
public Task<IConsoleMessage> SendMessageAsync(string message, FontStyle fontStyle, Color color) public Task<VirtualParadiseMessage> SendMessageAsync(string message, FontStyle fontStyle, Color color)
{ {
// ReSharper disable once InconsistentlySynchronizedField
return SendMessageAsync(null, message, fontStyle, color); return SendMessageAsync(null, message, fontStyle, color);
} }
@ -221,7 +211,7 @@ public sealed class Avatar : IEquatable<Avatar>, IAvatar
/// <para><paramref name="message" /> is too long to send.</para> /// <para><paramref name="message" /> is too long to send.</para>
/// </exception> /// </exception>
/// <remarks>Passing <see langword="null" /> to <paramref name="name" /> will hide the name from the recipient.</remarks> /// <remarks>Passing <see langword="null" /> to <paramref name="name" /> will hide the name from the recipient.</remarks>
public Task<IConsoleMessage> SendMessageAsync(string? name, string message, FontStyle fontStyle, Color color) public Task<VirtualParadiseMessage> SendMessageAsync(string? name, string message, FontStyle fontStyle, Color color)
{ {
if (message is null) if (message is null)
{ {
@ -233,7 +223,7 @@ public sealed class Avatar : IEquatable<Avatar>, IAvatar
throw new ArgumentException(ExceptionMessages.ValueCannotBeEmpty, nameof(message)); throw new ArgumentException(ExceptionMessages.ValueCannotBeEmpty, nameof(message));
} }
IAvatar avatar; VirtualParadiseAvatar avatar;
lock (_client.Lock) lock (_client.Lock)
{ {
@ -248,7 +238,6 @@ public sealed class Avatar : IEquatable<Avatar>, IAvatar
color.B color.B
); );
// TODO remove if statement
if (reason != ReasonCode.Success) if (reason != ReasonCode.Success)
{ {
switch (reason) switch (reason)
@ -267,12 +256,13 @@ public sealed class Avatar : IEquatable<Avatar>, IAvatar
avatar = _client.CurrentAvatar!; avatar = _client.CurrentAvatar!;
} }
return Task.FromResult((IConsoleMessage)new ConsoleMessage( return Task.FromResult(new VirtualParadiseMessage(
avatar, MessageType.ConsoleMessage,
avatar.Name, name,
message, message,
color, avatar,
fontStyle fontStyle,
color
)); ));
} }
@ -330,7 +320,7 @@ public sealed class Avatar : IEquatable<Avatar>, IAvatar
/// <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>
/// <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(World world, Vector3d position) public Task TeleportAsync(VirtualParadiseWorld world, Vector3d position)
{ {
if (world is null) if (world is null)
{ {
@ -347,7 +337,7 @@ public sealed class Avatar : IEquatable<Avatar>, IAvatar
/// <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(World world, Vector3d position, Rotation rotation) public Task TeleportAsync(VirtualParadiseWorld world, Vector3d position, Rotation rotation)
{ {
if (world is null) if (world is null)
{ {
@ -442,8 +432,8 @@ public sealed class Avatar : IEquatable<Avatar>, IAvatar
} }
} }
World? updatedWorld = isNewWorld ? await _client.GetWorldAsync(world) : Location.World; VirtualParadiseWorld? updatedWorld = isNewWorld ? await _client.GetWorldAsync(world) : Location.World;
updatedWorld ??= new World(_client, world); updatedWorld ??= new VirtualParadiseWorld(_client, world);
Location = new Location(updatedWorld, position, rotation); Location = new Location(updatedWorld, position, rotation);
// ReSharper restore InconsistentlySynchronizedField // ReSharper restore InconsistentlySynchronizedField
} }
@ -454,7 +444,7 @@ public sealed class Avatar : IEquatable<Avatar>, IAvatar
/// <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(Vector3d position) public Task TeleportAsync(Vector3d position)
{ {
return TeleportAsync(Location with { Position = position }); return TeleportAsync(Location with {Position = position});
} }
/// <summary> /// <summary>
@ -464,7 +454,7 @@ public sealed class Avatar : IEquatable<Avatar>, IAvatar
/// <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, Rotation rotation) public Task TeleportAsync(Vector3d position, Rotation rotation)
{ {
return TeleportAsync(Location with { Position = position, Rotation = rotation }); return TeleportAsync(Location with {Position = position, Rotation = rotation});
} }
/// <summary> /// <summary>
@ -479,6 +469,6 @@ public sealed class Avatar : IEquatable<Avatar>, IAvatar
/// <inheritdoc /> /// <inheritdoc />
public override string ToString() public override string ToString()
{ {
return $"Avatar #{Session}; User #{UserId} ({Name})"; return $"Avatar #{Session}; {User.Name} ({Name})";
} }
} }

View File

@ -0,0 +1,67 @@
using System.Drawing;
namespace VpSharp.Entities;
/// <summary>
/// Represents a message.
/// </summary>
public sealed class VirtualParadiseMessage
{
internal VirtualParadiseMessage(
MessageType type,
string? name,
string content,
VirtualParadiseAvatar author,
FontStyle style,
Color color)
{
Type = type;
Name = string.IsNullOrWhiteSpace(name) ? null : name;
Content = content;
Author = author;
Style = style;
Color = color;
}
/// <summary>
/// Gets the message author.
/// </summary>
/// <value>The message author.</value>
public VirtualParadiseAvatar Author { get; }
/// <summary>
/// Gets the message content.
/// </summary>
/// <value>The message content.</value>
public string Content { get; }
/// <summary>
/// Gets the message name.
/// </summary>
/// <value>The message name. This will always be equal to the name of the <see cref="Author" /> for chat messages.</value>
public string? Name { get; }
/// <summary>
/// Gets the message color.
/// </summary>
/// <value>The message color. This will always be <see cref="System.Drawing.Color.Black" /> for chat messages.</value>
public Color Color { get; }
/// <summary>
/// Gets the message font style.
/// </summary>
/// <value>The message font style. This will always be <see cref="FontStyle.Regular" /> for chat messages.</value>
public FontStyle Style { get; }
/// <summary>
/// Gets the type of this message.
/// </summary>
/// <value>The type of this message.</value>
public MessageType Type { get; }
/// <inheritdoc />
public override string ToString()
{
return $"Message {Author}; Type {Type}; Content {Content}";
}
}

View File

@ -9,15 +9,15 @@ namespace VpSharp.Entities;
/// Represents an object which renders as a 3D model. A "model" object will contain a <c>Model</c>, <c>Description</c> /// Represents an object which renders as a 3D model. A "model" object will contain a <c>Model</c>, <c>Description</c>
/// and <c>Action</c> field. /// and <c>Action</c> field.
/// </summary> /// </summary>
public class ModelObject : VirtualParadiseObject public class VirtualParadiseModelObject : VirtualParadiseObject
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ModelObject" /> class. /// Initializes a new instance of the <see cref="VirtualParadiseModelObject" /> class.
/// </summary> /// </summary>
/// <param name="client">The owning client.</param> /// <param name="client">The owning client.</param>
/// <param name="id">The object ID.</param> /// <param name="id">The object ID.</param>
/// <exception cref="ArgumentNullException"><paramref name="client" /> is <see langword="null" />.</exception> /// <exception cref="ArgumentNullException"><paramref name="client" /> is <see langword="null" />.</exception>
internal ModelObject(VirtualParadiseClient client, int id) internal VirtualParadiseModelObject(VirtualParadiseClient client, int id)
: base(client, id) : base(client, id)
{ {
} }
@ -46,11 +46,11 @@ public class ModelObject : VirtualParadiseObject
/// <param name="action">The builder which defines parameters to change.</param> /// <param name="action">The builder which defines parameters to change.</param>
/// <exception cref="ArgumentNullException"><paramref name="action" /> is <see langword="null" />.</exception> /// <exception cref="ArgumentNullException"><paramref name="action" /> is <see langword="null" />.</exception>
/// <exception cref="InvalidOperationException"> /// <exception cref="InvalidOperationException">
/// <para><see cref="ModelObjectBuilder.ModificationTimestamp" /> was assigned.</para> /// <para><see cref="VirtualParadiseModelObjectBuilder.ModificationTimestamp" /> was assigned.</para>
/// -or- /// -or-
/// <para><see cref="ModelObjectBuilder.Owner" /> was assigned.</para> /// <para><see cref="VirtualParadiseModelObjectBuilder.Owner" /> was assigned.</para>
/// </exception> /// </exception>
public async Task ModifyAsync(Action<ModelObjectBuilder> action) public async Task ModifyAsync(Action<VirtualParadiseModelObjectBuilder> action)
{ {
if (action is null) if (action is null)
{ {
@ -58,7 +58,7 @@ public class ModelObject : VirtualParadiseObject
} }
var taskCompletionSource = new TaskCompletionSource<ReasonCode>(); var taskCompletionSource = new TaskCompletionSource<ReasonCode>();
var builder = new ModelObjectBuilder(Client, this, ObjectBuilderMode.Modify); var builder = new VirtualParadiseModelObjectBuilder(Client, this, ObjectBuilderMode.Modify);
await Task.Run(() => action(builder)).ConfigureAwait(false); await Task.Run(() => action(builder)).ConfigureAwait(false);
lock (Client.Lock) lock (Client.Lock)
@ -90,9 +90,9 @@ public class ModelObject : VirtualParadiseObject
} }
/// <inheritdoc /> /// <inheritdoc />
protected internal override void ExtractFromBuilder(ObjectBuilder builder) protected internal override void ExtractFromBuilder(VirtualParadiseObjectBuilder builder)
{ {
if (builder is not ModelObjectBuilder modelObjectBuilder) if (builder is not VirtualParadiseModelObjectBuilder modelObjectBuilder)
{ {
return; return;
} }
@ -107,7 +107,7 @@ public class ModelObject : VirtualParadiseObject
/// <inheritdoc /> /// <inheritdoc />
protected internal override void ExtractFromOther(VirtualParadiseObject virtualParadiseObject) protected internal override void ExtractFromOther(VirtualParadiseObject virtualParadiseObject)
{ {
if (virtualParadiseObject is not ModelObject model) if (virtualParadiseObject is not VirtualParadiseModelObject model)
{ {
return; return;
} }

View File

@ -8,11 +8,11 @@ namespace VpSharp.Entities;
/// <summary> /// <summary>
/// Provides mutability for <see cref="VirtualParadiseObject" />. /// Provides mutability for <see cref="VirtualParadiseObject" />.
/// </summary> /// </summary>
public sealed class ModelObjectBuilder : ObjectBuilder public sealed class VirtualParadiseModelObjectBuilder : VirtualParadiseObjectBuilder
{ {
internal ModelObjectBuilder( internal VirtualParadiseModelObjectBuilder(
VirtualParadiseClient client, VirtualParadiseClient client,
ModelObject targetObject, VirtualParadiseModelObject targetObject,
ObjectBuilderMode mode ObjectBuilderMode mode
) )
: base(client, targetObject, mode) : base(client, targetObject, mode)
@ -42,7 +42,7 @@ public sealed class ModelObjectBuilder : ObjectBuilder
base.ApplyChanges(); base.ApplyChanges();
nint handle = Client.NativeInstanceHandle; nint handle = Client.NativeInstanceHandle;
var targetObject = (ModelObject)TargetObject; var targetObject = (VirtualParadiseModelObject)TargetObject;
vp_string_set(handle, ObjectModel, Model.ValueOr(targetObject.Model)); vp_string_set(handle, ObjectModel, Model.ValueOr(targetObject.Model));
vp_string_set(handle, ObjectDescription, Description.ValueOr(targetObject.Description)); vp_string_set(handle, ObjectDescription, Description.ValueOr(targetObject.Description));
vp_string_set(handle, ObjectAction, Action.ValueOr(targetObject.Action)); vp_string_set(handle, ObjectAction, Action.ValueOr(targetObject.Action));

View File

@ -51,7 +51,7 @@ public abstract class VirtualParadiseObject : IEquatable<VirtualParadiseObject>
/// Gets the owner of this object. /// Gets the owner of this object.
/// </summary> /// </summary>
/// <value>The owner of this object.</value> /// <value>The owner of this object.</value>
public IUser Owner { get; internal set; } = null!; public VirtualParadiseUser Owner { get; internal set; } = null!;
internal byte[] Data { get; set; } = Array.Empty<byte>(); internal byte[] Data { get; set; } = Array.Empty<byte>();
@ -90,7 +90,7 @@ public abstract class VirtualParadiseObject : IEquatable<VirtualParadiseObject>
/// The target avatar to receive the event. If this value is <see langword="null" />, the bump will be broadcast to /// The target avatar to receive the event. If this value is <see langword="null" />, the bump will be broadcast to
/// all avatars in the world. /// all avatars in the world.
/// </param> /// </param>
public async Task BumpAsync(BumpPhase? phase = null, Avatar? target = null) public async Task BumpAsync(BumpPhase? phase = null, VirtualParadiseAvatar? target = null)
{ {
int session = target?.Session ?? 0; int session = target?.Session ?? 0;
@ -139,7 +139,7 @@ public abstract class VirtualParadiseObject : IEquatable<VirtualParadiseObject>
/// The target avatar which will receive the event, or <see langword="null" /> to broadcast to every avatar. /// The target avatar which will receive the event, or <see langword="null" /> to broadcast to every avatar.
/// </param> /// </param>
/// <exception cref="InvalidOperationException"><paramref name="target" /> is the client's current avatar.</exception> /// <exception cref="InvalidOperationException"><paramref name="target" /> is the client's current avatar.</exception>
public Task ClickAsync(Vector3d? position = null, Avatar? target = null) public Task ClickAsync(Vector3d? position = null, VirtualParadiseAvatar? target = null)
{ {
if (target == Client.CurrentAvatar) if (target == Client.CurrentAvatar)
{ {
@ -236,10 +236,10 @@ public abstract class VirtualParadiseObject : IEquatable<VirtualParadiseObject>
} }
/// <summary> /// <summary>
/// Updates the object by extracting the values provided by a specified <see cref="ObjectBuilder" />. /// Updates the object by extracting the values provided by a specified <see cref="VirtualParadiseObjectBuilder" />.
/// </summary> /// </summary>
/// <param name="builder">The builder whose values to extract.</param> /// <param name="builder">The builder whose values to extract.</param>
protected internal virtual void ExtractFromBuilder(ObjectBuilder builder) protected internal virtual void ExtractFromBuilder(VirtualParadiseObjectBuilder builder)
{ {
if (builder is null) if (builder is null)
{ {

View File

@ -10,9 +10,9 @@ namespace VpSharp.Entities;
/// <summary> /// <summary>
/// Represents the base class for object builders. /// Represents the base class for object builders.
/// </summary> /// </summary>
public abstract class ObjectBuilder public abstract class VirtualParadiseObjectBuilder
{ {
private protected ObjectBuilder( private protected VirtualParadiseObjectBuilder(
VirtualParadiseClient client, VirtualParadiseClient client,
VirtualParadiseObject targetObject, VirtualParadiseObject targetObject,
ObjectBuilderMode mode ObjectBuilderMode mode
@ -43,7 +43,7 @@ public abstract class ObjectBuilder
/// This property may only be set during an object load, and will throw <see cref="InvalidOperationException" /> at /// This property may only be set during an object load, and will throw <see cref="InvalidOperationException" /> at
/// any other point. /// any other point.
/// </remarks> /// </remarks>
public Option<IUser> Owner { get; set; } public Option<VirtualParadiseUser> Owner { get; set; }
/// <summary> /// <summary>
/// Gets or sets the position of the object. /// Gets or sets the position of the object.
@ -90,7 +90,7 @@ public abstract class ObjectBuilder
throw new InvalidOperationException("Owner can only be assigned during an object load."); throw new InvalidOperationException("Owner can only be assigned during an object load.");
} }
IUser oldOwner = TargetObject.Owner; VirtualParadiseUser oldOwner = TargetObject.Owner;
_ = vp_int_set(handle, ObjectUserId, Owner.ValueOr(oldOwner).Id); _ = vp_int_set(handle, ObjectUserId, Owner.ValueOr(oldOwner).Id);
} }

View File

@ -13,15 +13,15 @@ namespace VpSharp.Entities;
/// <summary> /// <summary>
/// Represents a particle emitter object. /// Represents a particle emitter object.
/// </summary> /// </summary>
public sealed class ParticleEmitterObject : VirtualParadiseObject public sealed class VirtualParadiseParticleEmitterObject : VirtualParadiseObject
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ParticleEmitterObject" /> class. /// Initializes a new instance of the <see cref="VirtualParadiseParticleEmitterObject" /> class.
/// </summary> /// </summary>
/// <param name="client">The owning client.</param> /// <param name="client">The owning client.</param>
/// <param name="id">The object ID.</param> /// <param name="id">The object ID.</param>
/// <exception cref="ArgumentNullException"><paramref name="client" /> is <see langword="null" />.</exception> /// <exception cref="ArgumentNullException"><paramref name="client" /> is <see langword="null" />.</exception>
internal ParticleEmitterObject(VirtualParadiseClient client, int id) internal VirtualParadiseParticleEmitterObject(VirtualParadiseClient client, int id)
: base(client, id) : base(client, id)
{ {
} }
@ -217,13 +217,13 @@ public sealed class ParticleEmitterObject : VirtualParadiseObject
/// <inheritdoc /> /// <inheritdoc />
protected internal override void ExtractFromOther(VirtualParadiseObject virtualParadiseObject) protected internal override void ExtractFromOther(VirtualParadiseObject virtualParadiseObject)
{ {
if (virtualParadiseObject is not ParticleEmitterObject emitter) if (virtualParadiseObject is not VirtualParadiseParticleEmitterObject emitter)
{ {
return; return;
} }
const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
PropertyInfo[] properties = typeof(ParticleEmitterObject).GetProperties(bindingFlags); PropertyInfo[] properties = typeof(VirtualParadiseParticleEmitterObject).GetProperties(bindingFlags);
foreach (PropertyInfo property in properties) foreach (PropertyInfo property in properties)
{ {
@ -243,7 +243,7 @@ public sealed class ParticleEmitterObject : VirtualParadiseObject
#pragma warning disable 612 #pragma warning disable 612
const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
PropertyInfo[] properties = typeof(ParticleEmitterObject).GetProperties(bindingFlags); PropertyInfo[] properties = typeof(VirtualParadiseParticleEmitterObject).GetProperties(bindingFlags);
var keymap = new Dictionary<string, PropertyInfo>(); var keymap = new Dictionary<string, PropertyInfo>();
var converterMap = new Dictionary<string, ValueConverter>(); var converterMap = new Dictionary<string, ValueConverter>();

View File

@ -11,13 +11,13 @@ using VpSharp.Internal.ValueConverters;
namespace VpSharp.Entities; namespace VpSharp.Entities;
/// <summary> /// <summary>
/// Provides mutability for a <see cref="ParticleEmitterObject" />. /// Provides mutability for a <see cref="VirtualParadiseParticleEmitterObject" />.
/// </summary> /// </summary>
public sealed class ParticleEmitterObjectBuilder : ObjectBuilder public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadiseObjectBuilder
{ {
internal ParticleEmitterObjectBuilder( internal VirtualParadiseParticleEmitterObjectBuilder(
VirtualParadiseClient client, VirtualParadiseClient client,
ParticleEmitterObject targetObject, VirtualParadiseParticleEmitterObject targetObject,
ObjectBuilderMode mode ObjectBuilderMode mode
) )
: base(client, targetObject, mode) : base(client, targetObject, mode)
@ -220,7 +220,7 @@ public sealed class ParticleEmitterObjectBuilder : ObjectBuilder
/// </summary> /// </summary>
/// <param name="value">The maximum volume, or <see langword="default" /> to leave unchanged.</param> /// <param name="value">The maximum volume, or <see langword="default" /> to leave unchanged.</param>
/// <returns>The current instance.</returns> /// <returns>The current instance.</returns>
public ParticleEmitterObjectBuilder WithAccelerationMax(Option<Vector3d> value) public VirtualParadiseParticleEmitterObjectBuilder WithAccelerationMax(Option<Vector3d> value)
{ {
AccelerationMax = value; AccelerationMax = value;
return this; return this;
@ -231,7 +231,7 @@ public sealed class ParticleEmitterObjectBuilder : ObjectBuilder
/// </summary> /// </summary>
/// <param name="value">The minimum acceleration, or <see langword="default" /> to leave unchanged.</param> /// <param name="value">The minimum acceleration, or <see langword="default" /> to leave unchanged.</param>
/// <returns>The current instance.</returns> /// <returns>The current instance.</returns>
public ParticleEmitterObjectBuilder WithAccelerationMin(Option<Vector3d> value) public VirtualParadiseParticleEmitterObjectBuilder WithAccelerationMin(Option<Vector3d> value)
{ {
AccelerationMin = value; AccelerationMin = value;
return this; return this;
@ -242,7 +242,7 @@ public sealed class ParticleEmitterObjectBuilder : ObjectBuilder
/// </summary> /// </summary>
/// <param name="value">The blend mode, or <see langword="default" /> to leave unchanged.</param> /// <param name="value">The blend mode, or <see langword="default" /> to leave unchanged.</param>
/// <returns>The current instance.</returns> /// <returns>The current instance.</returns>
public ParticleEmitterObjectBuilder WithBlendMode(Option<ParticleBlendMode> value) public VirtualParadiseParticleEmitterObjectBuilder WithBlendMode(Option<ParticleBlendMode> value)
{ {
BlendMode = value; BlendMode = value;
return this; return this;
@ -253,7 +253,7 @@ public sealed class ParticleEmitterObjectBuilder : ObjectBuilder
/// </summary> /// </summary>
/// <param name="value">The maximum color, or <see langword="default" /> to leave unchanged.</param> /// <param name="value">The maximum color, or <see langword="default" /> to leave unchanged.</param>
/// <returns>The current instance.</returns> /// <returns>The current instance.</returns>
public ParticleEmitterObjectBuilder WithColorMax(Option<Color> value) public VirtualParadiseParticleEmitterObjectBuilder WithColorMax(Option<Color> value)
{ {
ColorMax = value; ColorMax = value;
return this; return this;
@ -264,7 +264,7 @@ public sealed class ParticleEmitterObjectBuilder : ObjectBuilder
/// </summary> /// </summary>
/// <param name="value">The minimum color, or <see langword="default" /> to leave unchanged.</param> /// <param name="value">The minimum color, or <see langword="default" /> to leave unchanged.</param>
/// <returns>The current instance.</returns> /// <returns>The current instance.</returns>
public ParticleEmitterObjectBuilder WithColorMin(Option<Color> value) public VirtualParadiseParticleEmitterObjectBuilder WithColorMin(Option<Color> value)
{ {
ColorMin = value; ColorMin = value;
return this; return this;
@ -275,7 +275,7 @@ public sealed class ParticleEmitterObjectBuilder : ObjectBuilder
/// </summary> /// </summary>
/// <param name="value">The emitter lifespan, or <see langword="default" /> to leave unchanged.</param> /// <param name="value">The emitter lifespan, or <see langword="default" /> to leave unchanged.</param>
/// <returns>The current instance.</returns> /// <returns>The current instance.</returns>
public ParticleEmitterObjectBuilder WithEmitterLifespan(Option<TimeSpan> value) public VirtualParadiseParticleEmitterObjectBuilder WithEmitterLifespan(Option<TimeSpan> value)
{ {
EmitterLifespan = value; EmitterLifespan = value;
return this; return this;
@ -289,7 +289,7 @@ public sealed class ParticleEmitterObjectBuilder : ObjectBuilder
/// <see langword="default" /> to leave unchanged. /// <see langword="default" /> to leave unchanged.
/// </param> /// </param>
/// <returns>The current instance.</returns> /// <returns>The current instance.</returns>
public ParticleEmitterObjectBuilder WithInterpolation(Option<bool> value) public VirtualParadiseParticleEmitterObjectBuilder WithInterpolation(Option<bool> value)
{ {
Interpolate = value; Interpolate = value;
return this; return this;
@ -300,7 +300,7 @@ public sealed class ParticleEmitterObjectBuilder : ObjectBuilder
/// </summary> /// </summary>
/// <param name="value">The opacity, or <see langword="default" /> to leave unchanged.</param> /// <param name="value">The opacity, or <see langword="default" /> to leave unchanged.</param>
/// <returns>The current instance.</returns> /// <returns>The current instance.</returns>
public ParticleEmitterObjectBuilder WithOpacity(Option<double> value) public VirtualParadiseParticleEmitterObjectBuilder WithOpacity(Option<double> value)
{ {
Opacity = value; Opacity = value;
return this; return this;
@ -311,7 +311,7 @@ public sealed class ParticleEmitterObjectBuilder : ObjectBuilder
/// </summary> /// </summary>
/// <param name="value">The particle lifespan, or <see langword="default" /> to leave unchanged.</param> /// <param name="value">The particle lifespan, or <see langword="default" /> to leave unchanged.</param>
/// <returns>The current instance.</returns> /// <returns>The current instance.</returns>
public ParticleEmitterObjectBuilder WithParticleLifespan(Option<TimeSpan> value) public VirtualParadiseParticleEmitterObjectBuilder WithParticleLifespan(Option<TimeSpan> value)
{ {
ParticleLifespan = value; ParticleLifespan = value;
return this; return this;
@ -322,7 +322,7 @@ public sealed class ParticleEmitterObjectBuilder : ObjectBuilder
/// </summary> /// </summary>
/// <param name="value">The particle type, or <see langword="default" /> to leave unchanged.</param> /// <param name="value">The particle type, or <see langword="default" /> to leave unchanged.</param>
/// <returns>The current instance.</returns> /// <returns>The current instance.</returns>
public ParticleEmitterObjectBuilder WithParticleType(Option<ParticleType> value) public VirtualParadiseParticleEmitterObjectBuilder WithParticleType(Option<ParticleType> value)
{ {
ParticleType = value; ParticleType = value;
return this; return this;
@ -333,7 +333,7 @@ public sealed class ParticleEmitterObjectBuilder : ObjectBuilder
/// </summary> /// </summary>
/// <param name="value">The release count, or <see langword="default" /> to leave unchanged.</param> /// <param name="value">The release count, or <see langword="default" /> to leave unchanged.</param>
/// <returns>The current instance.</returns> /// <returns>The current instance.</returns>
public ParticleEmitterObjectBuilder WithReleaseCount(Option<int> value) public VirtualParadiseParticleEmitterObjectBuilder WithReleaseCount(Option<int> value)
{ {
ReleaseCount = value; ReleaseCount = value;
return this; return this;
@ -344,7 +344,7 @@ public sealed class ParticleEmitterObjectBuilder : ObjectBuilder
/// </summary> /// </summary>
/// <param name="value">The release time, or <see langword="default" /> to leave unchanged.</param> /// <param name="value">The release time, or <see langword="default" /> to leave unchanged.</param>
/// <returns>The current instance.</returns> /// <returns>The current instance.</returns>
public ParticleEmitterObjectBuilder WithReleaseTime(Option<TimeSpan> value) public VirtualParadiseParticleEmitterObjectBuilder WithReleaseTime(Option<TimeSpan> value)
{ {
ReleaseTime = value; ReleaseTime = value;
return this; return this;
@ -355,7 +355,7 @@ public sealed class ParticleEmitterObjectBuilder : ObjectBuilder
/// </summary> /// </summary>
/// <param name="value">The maximum size, or <see langword="default" /> to leave unchanged.</param> /// <param name="value">The maximum size, or <see langword="default" /> to leave unchanged.</param>
/// <returns>The current instance.</returns> /// <returns>The current instance.</returns>
public ParticleEmitterObjectBuilder WithSizeMax(Option<Vector3d> value) public VirtualParadiseParticleEmitterObjectBuilder WithSizeMax(Option<Vector3d> value)
{ {
SizeMax = value; SizeMax = value;
return this; return this;
@ -366,7 +366,7 @@ public sealed class ParticleEmitterObjectBuilder : ObjectBuilder
/// </summary> /// </summary>
/// <param name="value">The minimum size, or <see langword="default" /> to leave unchanged.</param> /// <param name="value">The minimum size, or <see langword="default" /> to leave unchanged.</param>
/// <returns>The current instance.</returns> /// <returns>The current instance.</returns>
public ParticleEmitterObjectBuilder WithSizeMin(Option<Vector3d> value) public VirtualParadiseParticleEmitterObjectBuilder WithSizeMin(Option<Vector3d> value)
{ {
SizeMin = value; SizeMin = value;
return this; return this;
@ -377,7 +377,7 @@ public sealed class ParticleEmitterObjectBuilder : ObjectBuilder
/// </summary> /// </summary>
/// <param name="value">The maximum speed, or <see langword="default" /> to leave unchanged.</param> /// <param name="value">The maximum speed, or <see langword="default" /> to leave unchanged.</param>
/// <returns>The current instance.</returns> /// <returns>The current instance.</returns>
public ParticleEmitterObjectBuilder WithSpeedMax(Option<Vector3d> value) public VirtualParadiseParticleEmitterObjectBuilder WithSpeedMax(Option<Vector3d> value)
{ {
SpeedMax = value; SpeedMax = value;
return this; return this;
@ -388,7 +388,7 @@ public sealed class ParticleEmitterObjectBuilder : ObjectBuilder
/// </summary> /// </summary>
/// <param name="value">The minimum speed, or <see langword="default" /> to leave unchanged.</param> /// <param name="value">The minimum speed, or <see langword="default" /> to leave unchanged.</param>
/// <returns>The current instance.</returns> /// <returns>The current instance.</returns>
public ParticleEmitterObjectBuilder WithSpeedMin(Option<Vector3d> value) public VirtualParadiseParticleEmitterObjectBuilder WithSpeedMin(Option<Vector3d> value)
{ {
SpeedMin = value; SpeedMin = value;
return this; return this;
@ -399,7 +399,7 @@ public sealed class ParticleEmitterObjectBuilder : ObjectBuilder
/// </summary> /// </summary>
/// <param name="value">The maximum spin, or <see langword="default" /> to leave unchanged.</param> /// <param name="value">The maximum spin, or <see langword="default" /> to leave unchanged.</param>
/// <returns>The current instance.</returns> /// <returns>The current instance.</returns>
public ParticleEmitterObjectBuilder WithSpinMax(Option<Vector3d> value) public VirtualParadiseParticleEmitterObjectBuilder WithSpinMax(Option<Vector3d> value)
{ {
SpinMax = value; SpinMax = value;
return this; return this;
@ -410,7 +410,7 @@ public sealed class ParticleEmitterObjectBuilder : ObjectBuilder
/// </summary> /// </summary>
/// <param name="value">The minimum spin, or <see langword="default" /> to leave unchanged.</param> /// <param name="value">The minimum spin, or <see langword="default" /> to leave unchanged.</param>
/// <returns>The current instance.</returns> /// <returns>The current instance.</returns>
public ParticleEmitterObjectBuilder WithSpinMin(Option<Vector3d> value) public VirtualParadiseParticleEmitterObjectBuilder WithSpinMin(Option<Vector3d> value)
{ {
SpinMin = value; SpinMin = value;
return this; return this;
@ -421,7 +421,7 @@ public sealed class ParticleEmitterObjectBuilder : ObjectBuilder
/// </summary> /// </summary>
/// <param name="value">The maximum start angle, or <see langword="default" /> to leave unchanged.</param> /// <param name="value">The maximum start angle, or <see langword="default" /> to leave unchanged.</param>
/// <returns>The current instance.</returns> /// <returns>The current instance.</returns>
public ParticleEmitterObjectBuilder WithStartAngleMax(Option<Vector3d> value) public VirtualParadiseParticleEmitterObjectBuilder WithStartAngleMax(Option<Vector3d> value)
{ {
StartAngleMax = value; StartAngleMax = value;
return this; return this;
@ -432,7 +432,7 @@ public sealed class ParticleEmitterObjectBuilder : ObjectBuilder
/// </summary> /// </summary>
/// <param name="value">The minimum start angle, or <see langword="default" /> to leave unchanged.</param> /// <param name="value">The minimum start angle, or <see langword="default" /> to leave unchanged.</param>
/// <returns>The current instance.</returns> /// <returns>The current instance.</returns>
public ParticleEmitterObjectBuilder WithStartAngleMin(Option<Vector3d> value) public VirtualParadiseParticleEmitterObjectBuilder WithStartAngleMin(Option<Vector3d> value)
{ {
StartAngleMin = value; StartAngleMin = value;
return this; return this;
@ -443,7 +443,7 @@ public sealed class ParticleEmitterObjectBuilder : ObjectBuilder
/// </summary> /// </summary>
/// <param name="value">The maximum volume, or <see langword="default" /> to leave unchanged.</param> /// <param name="value">The maximum volume, or <see langword="default" /> to leave unchanged.</param>
/// <returns>The current instance.</returns> /// <returns>The current instance.</returns>
public ParticleEmitterObjectBuilder WithVolumeMax(Option<Vector3d> value) public VirtualParadiseParticleEmitterObjectBuilder WithVolumeMax(Option<Vector3d> value)
{ {
VolumeMax = value; VolumeMax = value;
return this; return this;
@ -454,7 +454,7 @@ public sealed class ParticleEmitterObjectBuilder : ObjectBuilder
/// </summary> /// </summary>
/// <param name="value">The minimum volume, or <see langword="default" /> to leave unchanged.</param> /// <param name="value">The minimum volume, or <see langword="default" /> to leave unchanged.</param>
/// <returns>The current instance.</returns> /// <returns>The current instance.</returns>
public ParticleEmitterObjectBuilder WithVolumeMin(Option<Vector3d> value) public VirtualParadiseParticleEmitterObjectBuilder WithVolumeMin(Option<Vector3d> value)
{ {
VolumeMin = value; VolumeMin = value;
return this; return this;
@ -465,7 +465,7 @@ public sealed class ParticleEmitterObjectBuilder : ObjectBuilder
/// </summary> /// </summary>
/// <param name="value">The tag, or <see langword="default" /> to leave unchanged.</param> /// <param name="value">The tag, or <see langword="default" /> to leave unchanged.</param>
/// <returns>The current instance.</returns> /// <returns>The current instance.</returns>
public ParticleEmitterObjectBuilder WithTag(Option<string> value) public VirtualParadiseParticleEmitterObjectBuilder WithTag(Option<string> value)
{ {
Tag = value; Tag = value;
return this; return this;
@ -476,7 +476,7 @@ public sealed class ParticleEmitterObjectBuilder : ObjectBuilder
/// </summary> /// </summary>
/// <param name="value">The texture, or <see langword="default" /> to leave unchanged.</param> /// <param name="value">The texture, or <see langword="default" /> to leave unchanged.</param>
/// <returns>The current instance.</returns> /// <returns>The current instance.</returns>
public ParticleEmitterObjectBuilder WithTexture(Option<string> value) public VirtualParadiseParticleEmitterObjectBuilder WithTexture(Option<string> value)
{ {
Texture = value; Texture = value;
return this; return this;

View File

@ -1,11 +1,11 @@
namespace VpSharp.Entities; namespace VpSharp.Entities;
/// <summary> /// <summary>
/// Represents a path contained by a <see cref="PathObject" />. /// Represents a path contained by a <see cref="VirtualParadisePathObject" />.
/// </summary> /// </summary>
public sealed class Path : ICloneable public sealed class VirtualParadisePath : ICloneable
{ {
internal Path(PathEasing easing, string name, IEnumerable<PathPoint> points, bool isClosed) internal VirtualParadisePath(PathEasing easing, string name, IEnumerable<PathPoint> points, bool isClosed)
{ {
Easing = easing; Easing = easing;
Name = name; Name = name;
@ -40,6 +40,6 @@ public sealed class Path : ICloneable
/// <inheritdoc /> /// <inheritdoc />
public object Clone() public object Clone()
{ {
return new Path(Easing, Name, Points, IsClosed); return new VirtualParadisePath(Easing, Name, Points, IsClosed);
} }
} }

View File

@ -9,15 +9,15 @@ namespace VpSharp.Entities;
/// <summary> /// <summary>
/// Represents a path object. /// Represents a path object.
/// </summary> /// </summary>
public sealed class PathObject : VirtualParadiseObject public sealed class VirtualParadisePathObject : VirtualParadiseObject
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="PathObject" /> class. /// Initializes a new instance of the <see cref="VirtualParadisePathObject" /> class.
/// </summary> /// </summary>
/// <param name="client">The owning client.</param> /// <param name="client">The owning client.</param>
/// <param name="id">The object ID.</param> /// <param name="id">The object ID.</param>
/// <exception cref="ArgumentNullException"><paramref name="client" /> is <see langword="null" />.</exception> /// <exception cref="ArgumentNullException"><paramref name="client" /> is <see langword="null" />.</exception>
internal PathObject(VirtualParadiseClient client, int id) internal VirtualParadisePathObject(VirtualParadiseClient client, int id)
: base(client, id) : base(client, id)
{ {
} }
@ -26,17 +26,17 @@ public sealed class PathObject : VirtualParadiseObject
/// Gets the path in this object. /// Gets the path in this object.
/// </summary> /// </summary>
/// <value>The path in this object.</value> /// <value>The path in this object.</value>
public Path Path { get; set; } = null!; public VirtualParadisePath Path { get; set; } = null!;
/// <inheritdoc /> /// <inheritdoc />
protected internal override void ExtractFromOther(VirtualParadiseObject virtualParadiseObject) protected internal override void ExtractFromOther(VirtualParadiseObject virtualParadiseObject)
{ {
if (virtualParadiseObject is not PathObject path) if (virtualParadiseObject is not VirtualParadisePathObject path)
{ {
return; return;
} }
Path = (Path)path.Path.Clone(); Path = (VirtualParadisePath)path.Path.Clone();
} }
/// <inheritdoc /> /// <inheritdoc />
@ -92,7 +92,7 @@ public sealed class PathObject : VirtualParadiseObject
buffer.Append(current); buffer.Append(current);
} }
Path = new Path((PathEasing)pathType, name, points, closed == 1); Path = new VirtualParadisePath((PathEasing)pathType, name, points, closed == 1);
buffer.Dispose(); buffer.Dispose();
} }

View File

@ -8,11 +8,11 @@ namespace VpSharp.Entities;
/// <summary> /// <summary>
/// Represents a Virtual Paradise user. /// Represents a Virtual Paradise user.
/// </summary> /// </summary>
public sealed class User : IEquatable<User>, IUser public sealed class VirtualParadiseUser : IEquatable<VirtualParadiseUser>
{ {
private readonly VirtualParadiseClient _client; private readonly VirtualParadiseClient _client;
internal User(VirtualParadiseClient client, int id) internal VirtualParadiseUser(VirtualParadiseClient client, int id)
{ {
_client = client; _client = client;
Id = id; Id = id;
@ -55,7 +55,7 @@ public sealed class User : IEquatable<User>, IUser
public DateTimeOffset RegistrationTime { get; internal set; } public DateTimeOffset RegistrationTime { get; internal set; }
/// <summary> /// <summary>
/// Determines if two <see cref="User" /> instances are equal. /// Determines if two <see cref="VirtualParadiseUser" /> instances are equal.
/// </summary> /// </summary>
/// <param name="left">The first instance.</param> /// <param name="left">The first instance.</param>
/// <param name="right">The second instance.</param> /// <param name="right">The second instance.</param>
@ -63,13 +63,13 @@ public sealed class User : IEquatable<User>, IUser
/// <see langword="true" /> if <paramref name="left" /> is equal to <paramref name="right" />; otherwise, /// <see langword="true" /> if <paramref name="left" /> is equal to <paramref name="right" />; otherwise,
/// <see langword="false" />. /// <see langword="false" />.
/// </returns> /// </returns>
public static bool operator ==(User? left, User? right) public static bool operator ==(VirtualParadiseUser? left, VirtualParadiseUser? right)
{ {
return Equals(left, right); return Equals(left, right);
} }
/// <summary> /// <summary>
/// Determines if two <see cref="User" /> instances are not equal. /// Determines if two <see cref="VirtualParadiseUser" /> instances are not equal.
/// </summary> /// </summary>
/// <param name="left">The first instance.</param> /// <param name="left">The first instance.</param>
/// <param name="right">The second instance.</param> /// <param name="right">The second instance.</param>
@ -77,19 +77,19 @@ public sealed class User : IEquatable<User>, IUser
/// <see langword="true" /> if <paramref name="left" /> is not equal to <paramref name="right" />; otherwise, /// <see langword="true" /> if <paramref name="left" /> is not equal to <paramref name="right" />; otherwise,
/// <see langword="false" />. /// <see langword="false" />.
/// </returns> /// </returns>
public static bool operator !=(User? left, User? right) public static bool operator !=(VirtualParadiseUser? left, VirtualParadiseUser? right)
{ {
return !Equals(left, right); return !Equals(left, right);
} }
/// <summary> /// <summary>
/// Determines if two <see cref="User" /> instances are equal. /// Determines if two <see cref="VirtualParadiseUser" /> instances are equal.
/// </summary> /// </summary>
/// <param name="other">The other instance.</param> /// <param name="other">The other instance.</param>
/// <returns> /// <returns>
/// <see langword="true" /> if this instance is equal to <paramref name="other" />; otherwise, <see langword="false" />. /// <see langword="true" /> if this instance is equal to <paramref name="other" />; otherwise, <see langword="false" />.
/// </returns> /// </returns>
public bool Equals(User? other) public bool Equals(VirtualParadiseUser? other)
{ {
if (ReferenceEquals(null, other)) if (ReferenceEquals(null, other))
{ {
@ -107,7 +107,7 @@ public sealed class User : IEquatable<User>, IUser
/// <inheritdoc /> /// <inheritdoc />
public override bool Equals(object? obj) public override bool Equals(object? obj)
{ {
return ReferenceEquals(this, obj) || (obj is User other && Equals(other)); return ReferenceEquals(this, obj) || (obj is VirtualParadiseUser other && Equals(other));
} }
/// <inheritdoc /> /// <inheritdoc />
@ -214,7 +214,7 @@ public sealed class User : IEquatable<User>, IUser
var position = new Vector3d(x, y, z); var position = new Vector3d(x, y, z);
var rotation = Rotation.CreateFromTiltYawRoll(pitch, yaw, 0); var rotation = Rotation.CreateFromTiltYawRoll(pitch, yaw, 0);
World 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

@ -5,16 +5,16 @@ namespace VpSharp.Entities;
/// <summary> /// <summary>
/// Represents a world in the Virtual Paradise universe. /// Represents a world in the Virtual Paradise universe.
/// </summary> /// </summary>
public sealed class World : IEquatable<World> public sealed class VirtualParadiseWorld : IEquatable<VirtualParadiseWorld>
{ {
/// <summary> /// <summary>
/// A world that represents no world in the universe. /// A world that represents no world in the universe.
/// </summary> /// </summary>
public static readonly World Nowhere = new(null!, "") {IsNowhere = true}; public static readonly VirtualParadiseWorld Nowhere = new(null!, "") {IsNowhere = true};
private readonly VirtualParadiseClient _client; private readonly VirtualParadiseClient _client;
internal World(VirtualParadiseClient client, string name) internal VirtualParadiseWorld(VirtualParadiseClient client, string name)
{ {
_client = client; _client = client;
Name = name ?? throw new ArgumentNullException(nameof(name)); Name = name ?? throw new ArgumentNullException(nameof(name));
@ -53,7 +53,7 @@ public sealed class World : IEquatable<World>
internal bool IsNowhere { get; private init; } internal bool IsNowhere { get; private init; }
/// <summary> /// <summary>
/// Determines if two <see cref="World" /> instances are equal. /// Determines if two <see cref="VirtualParadiseWorld" /> instances are equal.
/// </summary> /// </summary>
/// <param name="left">The first instance.</param> /// <param name="left">The first instance.</param>
/// <param name="right">The second instance.</param> /// <param name="right">The second instance.</param>
@ -61,13 +61,13 @@ public sealed class World : IEquatable<World>
/// <see langword="true" /> if <paramref name="left" /> is equal to <paramref name="right" />; otherwise, /// <see langword="true" /> if <paramref name="left" /> is equal to <paramref name="right" />; otherwise,
/// <see langword="false" />. /// <see langword="false" />.
/// </returns> /// </returns>
public static bool operator ==(World? left, World? right) public static bool operator ==(VirtualParadiseWorld? left, VirtualParadiseWorld? right)
{ {
return Equals(left, right); return Equals(left, right);
} }
/// <summary> /// <summary>
/// Determines if two <see cref="World" /> instances are not equal. /// Determines if two <see cref="VirtualParadiseWorld" /> instances are not equal.
/// </summary> /// </summary>
/// <param name="left">The first instance.</param> /// <param name="left">The first instance.</param>
/// <param name="right">The second instance.</param> /// <param name="right">The second instance.</param>
@ -75,19 +75,19 @@ public sealed class World : IEquatable<World>
/// <see langword="true" /> if <paramref name="left" /> is not equal to <paramref name="right" />; otherwise, /// <see langword="true" /> if <paramref name="left" /> is not equal to <paramref name="right" />; otherwise,
/// <see langword="false" />. /// <see langword="false" />.
/// </returns> /// </returns>
public static bool operator !=(World? left, World? right) public static bool operator !=(VirtualParadiseWorld? left, VirtualParadiseWorld? right)
{ {
return !Equals(left, right); return !Equals(left, right);
} }
/// <summary> /// <summary>
/// Determines if two <see cref="World" /> instances are equal. /// Determines if two <see cref="VirtualParadiseWorld" /> instances are equal.
/// </summary> /// </summary>
/// <param name="other">The other instance.</param> /// <param name="other">The other instance.</param>
/// <returns> /// <returns>
/// <see langword="true" /> if this instance is equal to <paramref name="other" />; otherwise, <see langword="false" />. /// <see langword="true" /> if this instance is equal to <paramref name="other" />; otherwise, <see langword="false" />.
/// </returns> /// </returns>
public bool Equals(World? other) public bool Equals(VirtualParadiseWorld? other)
{ {
if (ReferenceEquals(null, other)) if (ReferenceEquals(null, other))
{ {
@ -105,7 +105,7 @@ public sealed class World : IEquatable<World>
/// <inheritdoc /> /// <inheritdoc />
public override bool Equals(object? obj) public override bool Equals(object? obj)
{ {
return ReferenceEquals(this, obj) || (obj is World other && Equals(other)); return ReferenceEquals(this, obj) || (obj is VirtualParadiseWorld other && Equals(other));
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@ -13,7 +13,7 @@ public sealed class AvatarClickedEventArgs : EventArgs
/// <param name="avatar">The avatar responsible for the click.</param> /// <param name="avatar">The avatar responsible for the click.</param>
/// <param name="clickedAvatar">The clicked avatar.</param> /// <param name="clickedAvatar">The clicked avatar.</param>
/// <param name="clickPoint">The click point.</param> /// <param name="clickPoint">The click point.</param>
public AvatarClickedEventArgs(IAvatar avatar, IAvatar clickedAvatar, Vector3d clickPoint) public AvatarClickedEventArgs(VirtualParadiseAvatar avatar, VirtualParadiseAvatar clickedAvatar, Vector3d clickPoint)
{ {
Avatar = avatar; Avatar = avatar;
ClickedAvatar = clickedAvatar; ClickedAvatar = clickedAvatar;
@ -24,13 +24,13 @@ public sealed class AvatarClickedEventArgs : EventArgs
/// Gets the avatar responsible for the click. /// Gets the avatar responsible for the click.
/// </summary> /// </summary>
/// <value>The avatar responsible for the click.</value> /// <value>The avatar responsible for the click.</value>
public IAvatar Avatar { get; } public VirtualParadiseAvatar Avatar { get; }
/// <summary> /// <summary>
/// Gets the clicked avatar. /// Gets the clicked avatar.
/// </summary> /// </summary>
/// <value>The clicked avatar.</value> /// <value>The clicked avatar.</value>
public IAvatar ClickedAvatar { get; } public VirtualParadiseAvatar ClickedAvatar { get; }
/// <summary> /// <summary>
/// Gets the point at which the avatar clicked the object. /// Gets the point at which the avatar clicked the object.

View File

@ -13,7 +13,7 @@ public sealed class AvatarMovedEventArgs : EventArgs
/// <param name="avatar">The avatar whose type was changed.</param> /// <param name="avatar">The avatar whose type was changed.</param>
/// <param name="locationAfter">The avatar's new location.</param> /// <param name="locationAfter">The avatar's new location.</param>
/// <param name="locationBefore">The avatar's old location.</param> /// <param name="locationBefore">The avatar's old location.</param>
public AvatarMovedEventArgs(IAvatar avatar, Location locationAfter, Location? locationBefore) public AvatarMovedEventArgs(VirtualParadiseAvatar avatar, Location locationAfter, Location? locationBefore)
{ {
Avatar = avatar; Avatar = avatar;
LocationAfter = locationAfter; LocationAfter = locationAfter;
@ -24,7 +24,7 @@ public sealed class AvatarMovedEventArgs : EventArgs
/// Gets the avatar whose location was changed. /// Gets the avatar whose location was changed.
/// </summary> /// </summary>
/// <value>The avatar whose location was changed.</value> /// <value>The avatar whose location was changed.</value>
public IAvatar Avatar { get; } public VirtualParadiseAvatar Avatar { get; }
/// <summary> /// <summary>
/// Gets the avatar's location after the change. /// Gets the avatar's location after the change.

View File

@ -13,7 +13,7 @@ public sealed class AvatarTypeChangedEventArgs : EventArgs
/// <param name="avatar">The avatar whose type was changed.</param> /// <param name="avatar">The avatar whose type was changed.</param>
/// <param name="typeAfter">The avatar's new type.</param> /// <param name="typeAfter">The avatar's new type.</param>
/// <param name="typeBefore">The avatar's old type.</param> /// <param name="typeBefore">The avatar's old type.</param>
public AvatarTypeChangedEventArgs(IAvatar avatar, int typeAfter, int? typeBefore) public AvatarTypeChangedEventArgs(VirtualParadiseAvatar avatar, int typeAfter, int? typeBefore)
{ {
Avatar = avatar; Avatar = avatar;
TypeAfter = typeAfter; TypeAfter = typeAfter;
@ -24,7 +24,7 @@ public sealed class AvatarTypeChangedEventArgs : EventArgs
/// Gets the avatar whose type was changed. /// Gets the avatar whose type was changed.
/// </summary> /// </summary>
/// <value>The avatar whose type was changed.</value> /// <value>The avatar whose type was changed.</value>
public IAvatar Avatar { get; } public VirtualParadiseAvatar Avatar { get; }
/// <summary> /// <summary>
/// Gets the avatar's type after the change. /// Gets the avatar's type after the change.

View File

@ -13,7 +13,7 @@ public sealed class ObjectBumpEventArgs : EventArgs
/// <param name="avatar">The avatar.</param> /// <param name="avatar">The avatar.</param>
/// <param name="bumpedObject">The bumped object.</param> /// <param name="bumpedObject">The bumped object.</param>
/// <param name="phase">The bump phase.</param> /// <param name="phase">The bump phase.</param>
public ObjectBumpEventArgs(IAvatar avatar, VirtualParadiseObject bumpedObject, BumpPhase phase) public ObjectBumpEventArgs(VirtualParadiseAvatar avatar, VirtualParadiseObject bumpedObject, BumpPhase phase)
{ {
Avatar = avatar; Avatar = avatar;
BumpedObject = bumpedObject; BumpedObject = bumpedObject;
@ -24,7 +24,7 @@ public sealed class ObjectBumpEventArgs : EventArgs
/// Gets the avatar responsible for the bump. /// Gets the avatar responsible for the bump.
/// </summary> /// </summary>
/// <value>The avatar responsible for the bump.</value> /// <value>The avatar responsible for the bump.</value>
public IAvatar Avatar { get; } public VirtualParadiseAvatar Avatar { get; }
/// <summary> /// <summary>
/// Gets the object to which this event pertains. /// Gets the object to which this event pertains.

View File

@ -14,7 +14,7 @@ public sealed class ObjectChangedEventArgs : EventArgs
/// <param name="objectBefore">The state of the object prior to the change.</param> /// <param name="objectBefore">The state of the object prior to the change.</param>
/// <param name="objectAfter">The object which was changed, containing updated values.</param> /// <param name="objectAfter">The object which was changed, containing updated values.</param>
public ObjectChangedEventArgs( public ObjectChangedEventArgs(
IAvatar avatar, VirtualParadiseAvatar avatar,
VirtualParadiseObject? objectBefore, VirtualParadiseObject? objectBefore,
VirtualParadiseObject objectAfter) VirtualParadiseObject objectAfter)
{ {
@ -27,7 +27,7 @@ public sealed class ObjectChangedEventArgs : EventArgs
/// Gets the avatar which changed the object. /// Gets the avatar which changed the object.
/// </summary> /// </summary>
/// <value>The avatar which changed the object.</value> /// <value>The avatar which changed the object.</value>
public IAvatar Avatar { get; } public VirtualParadiseAvatar Avatar { get; }
/// <summary> /// <summary>
/// Gets the object which was changed. /// Gets the object which was changed.

View File

@ -14,7 +14,7 @@ public sealed class ObjectClickedEventArgs : EventArgs
/// <param name="clickedObject">The clicked object.</param> /// <param name="clickedObject">The clicked object.</param>
/// <param name="clickPoint">The click point.</param> /// <param name="clickPoint">The click point.</param>
public ObjectClickedEventArgs( public ObjectClickedEventArgs(
IAvatar avatar, VirtualParadiseAvatar avatar,
VirtualParadiseObject clickedObject, VirtualParadiseObject clickedObject,
Vector3d clickPoint) Vector3d clickPoint)
{ {
@ -27,7 +27,7 @@ public sealed class ObjectClickedEventArgs : EventArgs
/// Gets the avatar responsible for the click. /// Gets the avatar responsible for the click.
/// </summary> /// </summary>
/// <value>The avatar responsible for the click.</value> /// <value>The avatar responsible for the click.</value>
public IAvatar Avatar { get; } public VirtualParadiseAvatar Avatar { get; }
/// <summary> /// <summary>
/// Gets the clicked object. /// Gets the clicked object.

View File

@ -12,7 +12,7 @@ public sealed class ObjectCreatedEventArgs : EventArgs
/// </summary> /// </summary>
/// <param name="avatar">The avatar responsible for the object being created.</param> /// <param name="avatar">The avatar responsible for the object being created.</param>
/// <param name="createdObject">The created object.</param> /// <param name="createdObject">The created object.</param>
public ObjectCreatedEventArgs(IAvatar avatar, VirtualParadiseObject createdObject) public ObjectCreatedEventArgs(VirtualParadiseAvatar avatar, VirtualParadiseObject createdObject)
{ {
Avatar = avatar; Avatar = avatar;
CreatedObject = createdObject; CreatedObject = createdObject;
@ -22,7 +22,7 @@ public sealed class ObjectCreatedEventArgs : EventArgs
/// Gets the avatar responsible for the object being created. /// Gets the avatar responsible for the object being created.
/// </summary> /// </summary>
/// <value>The avatar responsible for the object being created.</value> /// <value>The avatar responsible for the object being created.</value>
public IAvatar Avatar { get; } public VirtualParadiseAvatar Avatar { get; }
/// <summary> /// <summary>
/// Gets the object which was created. /// Gets the object which was created.

View File

@ -13,7 +13,7 @@ public sealed class ObjectDeletedEventArgs : EventArgs
/// <param name="avatar">The avatar responsible for the object being deleted.</param> /// <param name="avatar">The avatar responsible for the object being deleted.</param>
/// <param name="objectId">The ID of the deleted object.</param> /// <param name="objectId">The ID of the deleted object.</param>
/// <param name="deletedObject">The deleted object.</param> /// <param name="deletedObject">The deleted object.</param>
public ObjectDeletedEventArgs(IAvatar avatar, int objectId, VirtualParadiseObject deletedObject) public ObjectDeletedEventArgs(VirtualParadiseAvatar avatar, int objectId, VirtualParadiseObject deletedObject)
{ {
Avatar = avatar; Avatar = avatar;
ObjectId = objectId; ObjectId = objectId;
@ -24,7 +24,7 @@ public sealed class ObjectDeletedEventArgs : EventArgs
/// Gets the avatar responsible for the object being deleted. /// Gets the avatar responsible for the object being deleted.
/// </summary> /// </summary>
/// <value>The avatar responsible for the object being deleted.</value> /// <value>The avatar responsible for the object being deleted.</value>
public IAvatar Avatar { get; } public VirtualParadiseAvatar Avatar { get; }
/// <summary> /// <summary>
/// Gets the object which was deleted. /// Gets the object which was deleted.

View File

@ -12,7 +12,7 @@ public sealed class TeleportedEventArgs : EventArgs
/// </summary> /// </summary>
/// <param name="avatar">The avatar which initiated the teleport.</param> /// <param name="avatar">The avatar which initiated the teleport.</param>
/// <param name="location">The target location of the teleport.</param> /// <param name="location">The target location of the teleport.</param>
public TeleportedEventArgs(IAvatar avatar, Location location) public TeleportedEventArgs(VirtualParadiseAvatar avatar, Location location)
{ {
Avatar = avatar; Avatar = avatar;
Location = location; Location = location;
@ -22,7 +22,7 @@ public sealed class TeleportedEventArgs : EventArgs
/// Gets the avatar which initiated the teleport. /// Gets the avatar which initiated the teleport.
/// </summary> /// </summary>
/// <value>The avatar which initiated the teleport.</value> /// <value>The avatar which initiated the teleport.</value>
public IAvatar Avatar { get; } public VirtualParadiseAvatar Avatar { get; }
/// <summary> /// <summary>
/// Gets the target location of the teleport. /// Gets the target location of the teleport.

View File

@ -13,7 +13,7 @@ public sealed class UriReceivedEventArgs : EventArgs
/// <param name="uri">The received URI.</param> /// <param name="uri">The received URI.</param>
/// <param name="target">The URI target.</param> /// <param name="target">The URI target.</param>
/// <param name="avatar">The avatar who sent the URI.</param> /// <param name="avatar">The avatar who sent the URI.</param>
public UriReceivedEventArgs(Uri uri, UriTarget target, IAvatar avatar) public UriReceivedEventArgs(Uri uri, UriTarget target, VirtualParadiseAvatar avatar)
{ {
Uri = uri; Uri = uri;
Target = target; Target = target;
@ -24,7 +24,7 @@ public sealed class UriReceivedEventArgs : EventArgs
/// Gets the avatar who sent the URI. /// Gets the avatar who sent the URI.
/// </summary> /// </summary>
/// <value>The avatar who sent the URI.</value> /// <value>The avatar who sent the URI.</value>
public IAvatar Avatar { get; } public VirtualParadiseAvatar Avatar { get; }
/// <summary> /// <summary>
/// Gets the URI target. /// Gets the URI target.

View File

@ -16,7 +16,7 @@ public sealed class InviteRequest : IEquatable<InviteRequest>
VirtualParadiseClient client, VirtualParadiseClient client,
int requestId, int requestId,
string name, string name,
IUser user, VirtualParadiseUser user,
Location location) Location location)
{ {
Name = name; Name = name;
@ -42,7 +42,7 @@ public sealed class InviteRequest : IEquatable<InviteRequest>
/// Gets the user which sent the request. /// Gets the user which sent the request.
/// </summary> /// </summary>
/// <value>The user which sent the request.</value> /// <value>The user which sent the request.</value>
public IUser User { get; } public VirtualParadiseUser User { get; }
/// <summary> /// <summary>
/// Returns a value indicating whether two <see cref="InviteRequest" /> instances are equal. /// Returns a value indicating whether two <see cref="InviteRequest" /> instances are equal.

View File

@ -12,7 +12,7 @@ public sealed class JoinRequest : IEquatable<JoinRequest>
private readonly VirtualParadiseClient _client; private readonly VirtualParadiseClient _client;
private readonly int _requestId; private readonly int _requestId;
internal JoinRequest(VirtualParadiseClient client, int requestId, string name, IUser user) internal JoinRequest(VirtualParadiseClient client, int requestId, string name, VirtualParadiseUser user)
{ {
Name = name; Name = name;
User = user; User = user;
@ -30,7 +30,7 @@ public sealed class JoinRequest : IEquatable<JoinRequest>
/// Gets the user which sent the request. /// Gets the user which sent the request.
/// </summary> /// </summary>
/// <value>The user which sent the request.</value> /// <value>The user which sent the request.</value>
public IUser User { get; } public VirtualParadiseUser User { get; }
/// <summary> /// <summary>
/// Returns a value indicating whether two <see cref="JoinRequest" /> instances are equal. /// Returns a value indicating whether two <see cref="JoinRequest" /> instances are equal.

View File

@ -10,7 +10,7 @@ public readonly struct Location : IEquatable<Location>
/// <summary> /// <summary>
/// A location that represents nowhere in the universe. /// A location that represents nowhere in the universe.
/// </summary> /// </summary>
public static readonly Location Nowhere = new(Entities.World.Nowhere); public static readonly Location Nowhere = new(VirtualParadiseWorld.Nowhere);
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Location" /> struct. /// Initializes a new instance of the <see cref="Location" /> struct.
@ -22,7 +22,7 @@ public readonly struct Location : IEquatable<Location>
/// <paramref name="world" /> parameter. /// <paramref name="world" /> parameter.
/// </param> /// </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(World world, in Coordinates coordinates) public Location(VirtualParadiseWorld world, in Coordinates coordinates)
{ {
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);
@ -36,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(World world, Vector3d position = default, Rotation 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;
@ -67,7 +67,7 @@ public readonly struct Location : IEquatable<Location>
/// Gets the world represented by this location. /// Gets the world represented by this location.
/// </summary> /// </summary>
/// <value>The world.</value> /// <value>The world.</value>
public World World { get; init; } public VirtualParadiseWorld World { get; init; }
/// <summary> /// <summary>
/// Determines if two <see cref="Location" /> instances are equal. /// Determines if two <see cref="Location" /> instances are equal.

View File

@ -0,0 +1,17 @@
namespace VpSharp;
/// <summary>
/// An enumeration of message types.
/// </summary>
public enum MessageType
{
/// <summary>
/// A chat message sent by an avatar.
/// </summary>
ChatMessage,
/// <summary>
/// A console message sent by a bot.
/// </summary>
ConsoleMessage
}

View File

@ -3,7 +3,7 @@
namespace VpSharp; namespace VpSharp;
/// <summary> /// <summary>
/// An enumeration of easings for use with <see cref="Entities.Path" />. /// An enumeration of easings for use with <see cref="VirtualParadisePath" />.
/// </summary> /// </summary>
public enum PathEasing public enum PathEasing
{ {

View File

@ -4,7 +4,7 @@ using VpSharp.Entities;
namespace VpSharp; namespace VpSharp;
/// <summary> /// <summary>
/// Represents a point along a <see cref="Entities.Path" />. /// Represents a point along a <see cref="VirtualParadisePath" />.
/// </summary> /// </summary>
#pragma warning disable CA1815 #pragma warning disable CA1815
public readonly struct PathPoint public readonly struct PathPoint

View File

@ -6,7 +6,7 @@ namespace VpSharp;
/// An enumeration of URI targets. /// An enumeration of URI targets.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// When used with <see cref="Avatar.SendUriAsync" />, <see cref="Overlay" /> indicates that that the URI /// When used with <see cref="VirtualParadiseAvatar.SendUriAsync" />, <see cref="Overlay" /> indicates that that the URI
/// will be displayed as a 2D overlay over the 3D world view. This currently uses CEF (Chromium Embedded Framework). /// will be displayed as a 2D overlay over the 3D world view. This currently uses CEF (Chromium Embedded Framework).
/// </remarks> /// </remarks>
public enum UriTarget public enum UriTarget

View File

@ -10,7 +10,7 @@ namespace VpSharp;
public sealed partial class VirtualParadiseClient public sealed partial class VirtualParadiseClient
{ {
private readonly ConcurrentDictionary<int, Avatar> _avatars = new(); private readonly ConcurrentDictionary<int, VirtualParadiseAvatar> _avatars = new();
/// <summary> /// <summary>
/// Gets the avatar with the specified session. /// Gets the avatar with the specified session.
@ -20,28 +20,28 @@ public sealed partial class VirtualParadiseClient
/// The avatar whose session is equal to <paramref name="session" />, or <see langword="null" /> if no match was /// The avatar whose session is equal to <paramref name="session" />, or <see langword="null" /> if no match was
/// found. /// found.
/// </returns> /// </returns>
public IAvatar? GetAvatar(int session) public VirtualParadiseAvatar? GetAvatar(int session)
{ {
_avatars.TryGetValue(session, out Avatar? avatar); _avatars.TryGetValue(session, out VirtualParadiseAvatar? avatar);
return avatar; return avatar;
} }
private Avatar AddOrUpdateAvatar(Avatar avatar) private VirtualParadiseAvatar AddOrUpdateAvatar(VirtualParadiseAvatar avatar)
{ {
return _avatars.AddOrUpdate(avatar.Session, avatar, (_, existing) => return _avatars.AddOrUpdate(avatar.Session, avatar, (_, existing) =>
{ {
// ReSharper disable once NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract // ReSharper disable once NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract
existing ??= new Avatar(this, avatar.Session); existing ??= new VirtualParadiseAvatar(this, avatar.Session);
existing.Name = avatar.Name; existing.Name = avatar.Name;
existing.Location = avatar.Location; existing.Location = avatar.Location;
existing.Application = avatar.Application; existing.Application = avatar.Application;
existing.Type = avatar.Type; existing.Type = avatar.Type;
existing.UserId = avatar.UserId; existing.User = avatar.User;
return existing; return existing;
}); });
} }
private Avatar ExtractAvatar(nint sender) private VirtualParadiseAvatar ExtractAvatar(nint sender)
{ {
lock (Lock) lock (Lock)
{ {
@ -58,12 +58,11 @@ public sealed partial class VirtualParadiseClient
string applicationVersion = vp_string(sender, StringAttribute.AvatarApplicationVersion); string applicationVersion = vp_string(sender, StringAttribute.AvatarApplicationVersion);
int session = vp_int(sender, IntegerAttribute.AvatarSession); int session = vp_int(sender, IntegerAttribute.AvatarSession);
return new Avatar(this, session) return new VirtualParadiseAvatar(this, session)
{ {
Name = vp_string(sender, StringAttribute.AvatarName), Name = vp_string(sender, StringAttribute.AvatarName),
Location = new Location(CurrentWorld!, position, rotation), Location = new Location(CurrentWorld!, position, rotation),
Application = new Application(applicationName, applicationVersion), Application = new Application(applicationName, applicationVersion)
UserId = vp_int(sender, IntegerAttribute.UserId)
}; };
} }
} }

View File

@ -7,13 +7,13 @@ namespace VpSharp;
public sealed partial class VirtualParadiseClient public sealed partial class VirtualParadiseClient
{ {
private readonly Subject<AvatarClickedEventArgs> _avatarClicked = new(); private readonly Subject<AvatarClickedEventArgs> _avatarClicked = new();
private readonly Subject<IAvatar> _avatarJoined = new(); private readonly Subject<VirtualParadiseAvatar> _avatarJoined = new();
private readonly Subject<IAvatar> _avatarLeft = new(); private readonly Subject<VirtualParadiseAvatar> _avatarLeft = new();
private readonly Subject<AvatarMovedEventArgs> _avatarMoved = new(); private readonly Subject<AvatarMovedEventArgs> _avatarMoved = new();
private readonly Subject<AvatarTypeChangedEventArgs> _avatarTypeChanged = new(); private readonly Subject<AvatarTypeChangedEventArgs> _avatarTypeChanged = new();
private readonly Subject<InviteRequest> _inviteRequestReceived = new(); private readonly Subject<InviteRequest> _inviteRequestReceived = new();
private readonly Subject<JoinRequest> _joinRequestReceived = new(); private readonly Subject<JoinRequest> _joinRequestReceived = new();
private readonly Subject<IMessage> _messageReceived = new(); private readonly Subject<VirtualParadiseMessage> _messageReceived = new();
private readonly Subject<ObjectBumpEventArgs> _objectBump = new(); private readonly Subject<ObjectBumpEventArgs> _objectBump = new();
private readonly Subject<ObjectChangedEventArgs> _objectChanged = new(); private readonly Subject<ObjectChangedEventArgs> _objectChanged = new();
private readonly Subject<ObjectClickedEventArgs> _objectClicked = new(); private readonly Subject<ObjectClickedEventArgs> _objectClicked = new();
@ -35,7 +35,7 @@ public sealed partial class VirtualParadiseClient
/// <summary> /// <summary>
/// Occurs when an avatar has entered the vicinity of the client. /// Occurs when an avatar has entered the vicinity of the client.
/// </summary> /// </summary>
public IObservable<IAvatar> AvatarJoined public IObservable<VirtualParadiseAvatar> AvatarJoined
{ {
get => _avatarJoined; get => _avatarJoined;
} }
@ -43,7 +43,7 @@ public sealed partial class VirtualParadiseClient
/// <summary> /// <summary>
/// Occurs when an avatar has left the vicinity of the client. /// Occurs when an avatar has left the vicinity of the client.
/// </summary> /// </summary>
public IObservable<IAvatar> AvatarLeft public IObservable<VirtualParadiseAvatar> AvatarLeft
{ {
get => _avatarLeft; get => _avatarLeft;
} }
@ -83,7 +83,7 @@ public sealed partial class VirtualParadiseClient
/// <summary> /// <summary>
/// Occurs when a chat message or console message has been received. /// Occurs when a chat message or console message has been received.
/// </summary> /// </summary>
public IObservable<IMessage> MessageReceived public IObservable<VirtualParadiseMessage> MessageReceived
{ {
get => _messageReceived; get => _messageReceived;
} }

View File

@ -52,7 +52,7 @@ public sealed partial class VirtualParadiseClient
private void OnChatNativeEvent(nint sender) private void OnChatNativeEvent(nint sender)
{ {
IMessage message; VirtualParadiseMessage message;
lock (Lock) lock (Lock)
{ {
@ -61,7 +61,6 @@ public sealed partial class VirtualParadiseClient
string content = vp_string(sender, StringAttribute.ChatMessage); string content = vp_string(sender, StringAttribute.ChatMessage);
int type = vp_int(sender, IntegerAttribute.ChatType); int type = vp_int(sender, IntegerAttribute.ChatType);
IAvatar avatar = GetAvatar(session)!;
Color color = Color.Black; Color color = Color.Black;
var style = FontStyle.Regular; var style = FontStyle.Regular;
@ -73,12 +72,10 @@ public sealed partial class VirtualParadiseClient
int b = vp_int(sender, IntegerAttribute.ChatColorBlue); int b = vp_int(sender, IntegerAttribute.ChatColorBlue);
color = Color.FromArgb(r, g, b); color = Color.FromArgb(r, g, b);
style = (FontStyle)vp_int(sender, IntegerAttribute.ChatEffects); style = (FontStyle)vp_int(sender, IntegerAttribute.ChatEffects);
message = new ConsoleMessage(avatar, name, content, color, style);
}
else
{
message = new UserMessage(avatar, content);
} }
VirtualParadiseAvatar avatar = GetAvatar(session)!;
message = new VirtualParadiseMessage((MessageType)type, name, content, avatar, style, color);
} }
_messageReceived.OnNext(message); _messageReceived.OnNext(message);
@ -91,7 +88,8 @@ public sealed partial class VirtualParadiseClient
private void OnAvatarAddNativeEvent(nint sender) private void OnAvatarAddNativeEvent(nint sender)
{ {
Avatar avatar = ExtractAvatar(sender); VirtualParadiseAvatar avatar = ExtractAvatar(sender);
avatar.User = GetUserAsync(vp_int(sender, IntegerAttribute.UserId)).ConfigureAwait(false).GetAwaiter().GetResult();
avatar = AddOrUpdateAvatar(avatar); avatar = AddOrUpdateAvatar(avatar);
_avatarJoined.OnNext(avatar); _avatarJoined.OnNext(avatar);
} }
@ -118,7 +116,7 @@ public sealed partial class VirtualParadiseClient
rotation = Rotation.CreateFromTiltYawRoll(pitch, yaw, 0); rotation = Rotation.CreateFromTiltYawRoll(pitch, yaw, 0);
} }
var avatar = (Avatar)GetAvatar(session)!; VirtualParadiseAvatar avatar = GetAvatar(session)!;
if (type != avatar.Type) if (type != avatar.Type)
{ {
int oldType = avatar.Type; int oldType = avatar.Type;
@ -148,8 +146,8 @@ public sealed partial class VirtualParadiseClient
session = vp_int(sender, IntegerAttribute.AvatarSession); session = vp_int(sender, IntegerAttribute.AvatarSession);
} }
IAvatar avatar = GetAvatar(session)!; VirtualParadiseAvatar avatar = GetAvatar(session)!;
_avatars.TryRemove(session, out Avatar _); _avatars.TryRemove(session, out VirtualParadiseAvatar _);
_avatarLeft.OnNext(avatar); _avatarLeft.OnNext(avatar);
} }
@ -176,7 +174,7 @@ public sealed partial class VirtualParadiseClient
} }
else else
{ {
IAvatar avatar = GetAvatar(session)!; VirtualParadiseAvatar avatar = GetAvatar(session)!;
var args = new ObjectCreatedEventArgs(avatar, virtualParadiseObject); var args = new ObjectCreatedEventArgs(avatar, virtualParadiseObject);
_objectCreated.OnNext(args); _objectCreated.OnNext(args);
} }
@ -193,7 +191,7 @@ public sealed partial class VirtualParadiseClient
session = vp_int(sender, IntegerAttribute.AvatarSession); session = vp_int(sender, IntegerAttribute.AvatarSession);
} }
IAvatar avatar = GetAvatar(session)!; VirtualParadiseAvatar avatar = GetAvatar(session)!;
VirtualParadiseObject? cachedObject = null; VirtualParadiseObject? cachedObject = null;
if (_objects.TryGetValue(objectId, out VirtualParadiseObject? virtualParadiseObject)) if (_objects.TryGetValue(objectId, out VirtualParadiseObject? virtualParadiseObject))
@ -229,7 +227,7 @@ public sealed partial class VirtualParadiseClient
session = vp_int(sender, IntegerAttribute.AvatarSession); session = vp_int(sender, IntegerAttribute.AvatarSession);
} }
IAvatar avatar = GetAvatar(session)!; VirtualParadiseAvatar? avatar = GetAvatar(session);
VirtualParadiseObject? virtualParadiseObject; VirtualParadiseObject? virtualParadiseObject;
try try
@ -243,7 +241,7 @@ public sealed partial class VirtualParadiseClient
_objects.TryRemove(objectId, out VirtualParadiseObject _); _objects.TryRemove(objectId, out VirtualParadiseObject _);
var args = new ObjectDeletedEventArgs(avatar, objectId, virtualParadiseObject!); var args = new ObjectDeletedEventArgs(avatar!, objectId, virtualParadiseObject!);
_objectDeleted.OnNext(args); _objectDeleted.OnNext(args);
} }
@ -264,7 +262,7 @@ public sealed partial class VirtualParadiseClient
clickPoint = new Vector3d(x, y, z); clickPoint = new Vector3d(x, y, z);
} }
IAvatar avatar = GetAvatar(session)!; VirtualParadiseAvatar avatar = GetAvatar(session)!;
try try
{ {
VirtualParadiseObject virtualParadiseObject = await GetObjectAsync(objectId).ConfigureAwait(false); VirtualParadiseObject virtualParadiseObject = await GetObjectAsync(objectId).ConfigureAwait(false);
@ -279,7 +277,7 @@ public sealed partial class VirtualParadiseClient
private async void OnWorldListNativeEvent(nint sender) private async void OnWorldListNativeEvent(nint sender)
{ {
World world; VirtualParadiseWorld world;
string name; string name;
int avatarCount; int avatarCount;
WorldState state; WorldState state;
@ -290,7 +288,7 @@ public sealed partial class VirtualParadiseClient
avatarCount = vp_int(sender, IntegerAttribute.WorldUsers); avatarCount = vp_int(sender, IntegerAttribute.WorldUsers);
state = (WorldState)vp_int(sender, IntegerAttribute.WorldState); state = (WorldState)vp_int(sender, IntegerAttribute.WorldState);
world = new World(this, name) { AvatarCount = avatarCount, State = state }; world = new VirtualParadiseWorld(this, name) { AvatarCount = avatarCount, State = state };
_worlds[name] = world; _worlds[name] = world;
} }
@ -335,7 +333,7 @@ public sealed partial class VirtualParadiseClient
userId = vp_int(sender, IntegerAttribute.FriendUserId); userId = vp_int(sender, IntegerAttribute.FriendUserId);
} }
var user = (User)await GetUserAsync(userId).ConfigureAwait(false); VirtualParadiseUser user = await GetUserAsync(userId).ConfigureAwait(false);
_friends.AddOrUpdate(userId, user, (_, _) => user); _friends.AddOrUpdate(userId, user, (_, _) => user);
} }
@ -364,7 +362,7 @@ public sealed partial class VirtualParadiseClient
private void OnUserAttributesNativeEvent(nint sender) private void OnUserAttributesNativeEvent(nint sender)
{ {
int userId; int userId;
User user; VirtualParadiseUser user;
lock (Lock) lock (Lock)
{ {
@ -376,7 +374,7 @@ public sealed partial class VirtualParadiseClient
int onlineTime = vp_int(sender, IntegerAttribute.UserOnlineTime); int onlineTime = vp_int(sender, IntegerAttribute.UserOnlineTime);
int registered = vp_int(sender, IntegerAttribute.UserRegistrationTime); int registered = vp_int(sender, IntegerAttribute.UserRegistrationTime);
user = new User(this, userId) user = new VirtualParadiseUser(this, userId)
{ {
Name = name, Name = name,
EmailAddress = email, EmailAddress = email,
@ -386,7 +384,7 @@ public sealed partial class VirtualParadiseClient
}; };
} }
if (_usersCompletionSources.TryGetValue(userId, out TaskCompletionSource<User>? taskCompletionSource)) if (_usersCompletionSources.TryGetValue(userId, out TaskCompletionSource<VirtualParadiseUser>? taskCompletionSource))
{ {
taskCompletionSource.SetResult(user); taskCompletionSource.SetResult(user);
} }
@ -426,8 +424,8 @@ public sealed partial class VirtualParadiseClient
clickPoint = new Vector3d(x, y, z); clickPoint = new Vector3d(x, y, z);
} }
IAvatar avatar = GetAvatar(session)!; VirtualParadiseAvatar avatar = GetAvatar(session)!;
IAvatar clickedAvatar = GetAvatar(clickedSession)!; VirtualParadiseAvatar clickedAvatar = GetAvatar(clickedSession)!;
var args = new AvatarClickedEventArgs(avatar, clickedAvatar, clickPoint); var args = new AvatarClickedEventArgs(avatar, clickedAvatar, clickPoint);
_avatarClicked.OnNext(args); _avatarClicked.OnNext(args);
} }
@ -455,13 +453,13 @@ public sealed partial class VirtualParadiseClient
worldName = vp_string(sender, StringAttribute.TeleportWorld); worldName = vp_string(sender, StringAttribute.TeleportWorld);
} }
World world = (string.IsNullOrWhiteSpace(worldName) VirtualParadiseWorld world = (string.IsNullOrWhiteSpace(worldName)
? CurrentWorld ? CurrentWorld
: await GetWorldAsync(worldName).ConfigureAwait(false))!; : await GetWorldAsync(worldName).ConfigureAwait(false))!;
var location = new Location(world, position, rotation); var location = new Location(world, position, rotation);
((Avatar)CurrentAvatar!).Location = location; CurrentAvatar!.Location = location;
IAvatar avatar = GetAvatar(session)!; VirtualParadiseAvatar avatar = GetAvatar(session)!;
var args = new TeleportedEventArgs(avatar, location); var args = new TeleportedEventArgs(avatar, location);
_teleported.OnNext(args); _teleported.OnNext(args);
} }
@ -477,7 +475,7 @@ public sealed partial class VirtualParadiseClient
objectId = vp_int(sender, IntegerAttribute.ObjectId); objectId = vp_int(sender, IntegerAttribute.ObjectId);
} }
IAvatar avatar = GetAvatar(session)!; VirtualParadiseAvatar avatar = GetAvatar(session)!;
try try
{ {
var vpObject = await GetObjectAsync(objectId).ConfigureAwait(false); var vpObject = await GetObjectAsync(objectId).ConfigureAwait(false);
@ -508,7 +506,7 @@ public sealed partial class VirtualParadiseClient
return; return;
} }
IAvatar avatar = GetAvatar(session)!; VirtualParadiseAvatar avatar = GetAvatar(session)!;
var uri = new Uri(url); var uri = new Uri(url);
var args = new UriReceivedEventArgs(uri, target, avatar); var args = new UriReceivedEventArgs(uri, target, avatar);
_uriReceived.OnNext(args); _uriReceived.OnNext(args);
@ -525,7 +523,7 @@ public sealed partial class VirtualParadiseClient
objectId = vp_int(sender, IntegerAttribute.ObjectId); objectId = vp_int(sender, IntegerAttribute.ObjectId);
} }
IAvatar avatar = GetAvatar(session)!; VirtualParadiseAvatar avatar = GetAvatar(session)!;
try try
{ {
var vpObject = await GetObjectAsync(objectId).ConfigureAwait(false); var vpObject = await GetObjectAsync(objectId).ConfigureAwait(false);
@ -551,7 +549,7 @@ public sealed partial class VirtualParadiseClient
name = vp_string(NativeInstanceHandle, StringAttribute.JoinName); name = vp_string(NativeInstanceHandle, StringAttribute.JoinName);
} }
IUser user = await GetUserAsync(userId).ConfigureAwait(false); VirtualParadiseUser user = await GetUserAsync(userId).ConfigureAwait(false);
var joinRequest = new JoinRequest(this, requestId, name, user); var joinRequest = new JoinRequest(this, requestId, name, user);
_joinRequestReceived.OnNext(joinRequest); _joinRequestReceived.OnNext(joinRequest);
} }
@ -584,8 +582,8 @@ public sealed partial class VirtualParadiseClient
worldName = vp_string(sender, StringAttribute.InviteWorld); worldName = vp_string(sender, StringAttribute.InviteWorld);
} }
World world = (await GetWorldAsync(worldName).ConfigureAwait(false))!; VirtualParadiseWorld world = (await GetWorldAsync(worldName).ConfigureAwait(false))!;
IUser user = await GetUserAsync(userId).ConfigureAwait(false); VirtualParadiseUser user = await GetUserAsync(userId).ConfigureAwait(false);
var location = new Location(world, position, rotation); var location = new Location(world, position, rotation);
var request = new InviteRequest(this, requestId, avatarName, user, location); var request = new InviteRequest(this, requestId, avatarName, user, location);

View File

@ -214,9 +214,9 @@ public sealed partial class VirtualParadiseClient
VirtualParadiseObject virtualParadiseObject = type switch VirtualParadiseObject virtualParadiseObject = type switch
{ {
ObjectType.Model => new ModelObject(this, id), ObjectType.Model => new VirtualParadiseModelObject(this, id),
ObjectType.ParticleEmitter => new ParticleEmitterObject(this, id), ObjectType.ParticleEmitter => new VirtualParadiseParticleEmitterObject(this, id),
ObjectType.Path => new PathObject(this, id), ObjectType.Path => new VirtualParadisePathObject(this, id),
_ => throw new NotSupportedException(ExceptionMessages.UnsupportedObjectType) _ => throw new NotSupportedException(ExceptionMessages.UnsupportedObjectType)
}; };

View File

@ -6,8 +6,8 @@ namespace VpSharp;
public sealed partial class VirtualParadiseClient public sealed partial class VirtualParadiseClient
{ {
private readonly ConcurrentDictionary<int, User> _users = new(); private readonly ConcurrentDictionary<int, VirtualParadiseUser> _users = new();
private readonly ConcurrentDictionary<int, TaskCompletionSource<User>> _usersCompletionSources = new(); private readonly ConcurrentDictionary<int, TaskCompletionSource<VirtualParadiseUser>> _usersCompletionSources = new();
/// <summary> /// <summary>
/// Gets a user by their ID. /// Gets a user by their ID.
@ -16,19 +16,19 @@ public sealed partial class VirtualParadiseClient
/// <returns> /// <returns>
/// The user whose ID is equal to <paramref name="userId" />, or <see langword="null" /> if no match was found. /// The user whose ID is equal to <paramref name="userId" />, or <see langword="null" /> if no match was found.
/// </returns> /// </returns>
public async Task<IUser> GetUserAsync(int userId) public async Task<VirtualParadiseUser> GetUserAsync(int userId)
{ {
if (_users.TryGetValue(userId, out User? user)) if (_users.TryGetValue(userId, out VirtualParadiseUser? user))
{ {
return user; return user;
} }
if (_usersCompletionSources.TryGetValue(userId, out TaskCompletionSource<User>? taskCompletionSource)) if (_usersCompletionSources.TryGetValue(userId, out TaskCompletionSource<VirtualParadiseUser>? taskCompletionSource))
{ {
return await taskCompletionSource.Task.ConfigureAwait(false); return await taskCompletionSource.Task.ConfigureAwait(false);
} }
taskCompletionSource = new TaskCompletionSource<User>(); taskCompletionSource = new TaskCompletionSource<VirtualParadiseUser>();
_usersCompletionSources.TryAdd(userId, taskCompletionSource); _usersCompletionSources.TryAdd(userId, taskCompletionSource);
lock (Lock) lock (Lock)
@ -39,16 +39,16 @@ public sealed partial class VirtualParadiseClient
user = await taskCompletionSource.Task.ConfigureAwait(false); user = await taskCompletionSource.Task.ConfigureAwait(false);
user = AddOrUpdateUser(user); user = AddOrUpdateUser(user);
_usersCompletionSources.TryRemove(userId, out TaskCompletionSource<User> _); _usersCompletionSources.TryRemove(userId, out TaskCompletionSource<VirtualParadiseUser> _);
return user; return user;
} }
private User AddOrUpdateUser(User user) private VirtualParadiseUser AddOrUpdateUser(VirtualParadiseUser user)
{ {
return _users.AddOrUpdate(user.Id, user, (_, existing) => return _users.AddOrUpdate(user.Id, user, (_, existing) =>
{ {
// ReSharper disable once NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract // ReSharper disable once NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract
existing ??= new User(this, user.Id); existing ??= new VirtualParadiseUser(this, user.Id);
existing.Name = user.Name; existing.Name = user.Name;
existing.EmailAddress = user.EmailAddress; existing.EmailAddress = user.EmailAddress;
existing.LastLogin = user.LastLogin; existing.LastLogin = user.LastLogin;

View File

@ -8,22 +8,22 @@ namespace VpSharp;
public sealed partial class VirtualParadiseClient public sealed partial class VirtualParadiseClient
{ {
private readonly ConcurrentDictionary<string, string> _worldSettings = new(); private readonly ConcurrentDictionary<string, string> _worldSettings = new();
private readonly ConcurrentDictionary<string, World> _worlds = new(); private readonly ConcurrentDictionary<string, VirtualParadiseWorld> _worlds = new();
private Channel<World>? _worldListChannel = Channel.CreateUnbounded<World>(); private Channel<VirtualParadiseWorld>? _worldListChannel = Channel.CreateUnbounded<VirtualParadiseWorld>();
private TaskCompletionSource _worldSettingsCompletionSource = new(); private TaskCompletionSource _worldSettingsCompletionSource = new();
/// <summary> /// <summary>
/// Gets an enumerable of the worlds returned by the universe server. /// Gets an enumerable of the worlds returned by the universe server.
/// </summary> /// </summary>
/// <returns>An <see cref="IAsyncEnumerable{T}" /> containing <see cref="World" /> values.</returns> /// <returns>An <see cref="IAsyncEnumerable{T}" /> containing <see cref="VirtualParadiseWorld" /> values.</returns>
/// <remarks> /// <remarks>
/// This method will yield results back as they are received from the world server. To access a consumed collection, /// This method will yield results back as they are received from the world server. To access a consumed collection,
/// use <see cref="GetWorldsAsync" />. /// use <see cref="GetWorldsAsync" />.
/// </remarks> /// </remarks>
/// <seealso cref="GetWorldsAsync" /> /// <seealso cref="GetWorldsAsync" />
public IAsyncEnumerable<World> EnumerateWorldsAsync() public IAsyncEnumerable<VirtualParadiseWorld> EnumerateWorldsAsync()
{ {
_worldListChannel = Channel.CreateUnbounded<World>(); _worldListChannel = Channel.CreateUnbounded<VirtualParadiseWorld>();
lock (Lock) lock (Lock)
{ {
_ = vp_world_list(NativeInstanceHandle, 0); _ = vp_world_list(NativeInstanceHandle, 0);
@ -37,20 +37,20 @@ public sealed partial class VirtualParadiseClient
/// </summary> /// </summary>
/// <param name="name">The name of the world.</param> /// <param name="name">The name of the world.</param>
/// <returns> /// <returns>
/// A <see cref="World" /> whose name is equal to <paramref name="name" />, or <see langword="null" /> /// A <see cref="VirtualParadiseWorld" /> whose name is equal to <paramref name="name" />, or <see langword="null" />
/// if no match was found. /// if no match was found.
/// </returns> /// </returns>
/// <exception cref="ArgumentException"> /// <exception cref="ArgumentException">
/// <paramref name="name" /> is <see langword="null" />, empty, or consists of only whitespace. /// <paramref name="name" /> is <see langword="null" />, empty, or consists of only whitespace.
/// </exception> /// </exception>
public async Task<World?> GetWorldAsync(string name) public async Task<VirtualParadiseWorld?> GetWorldAsync(string name)
{ {
if (string.IsNullOrWhiteSpace(name)) if (string.IsNullOrWhiteSpace(name))
{ {
throw new ArgumentException(ExceptionMessages.WorldNameCannotBeEmpty, nameof(name)); throw new ArgumentException(ExceptionMessages.WorldNameCannotBeEmpty, nameof(name));
} }
await foreach (World world in EnumerateWorldsAsync()) await foreach (VirtualParadiseWorld world in EnumerateWorldsAsync())
{ {
if (string.Equals(world.Name, name, StringComparison.Ordinal)) if (string.Equals(world.Name, name, StringComparison.Ordinal))
{ {
@ -64,18 +64,18 @@ public sealed partial class VirtualParadiseClient
/// <summary> /// <summary>
/// Gets a read-only view of the worlds returned by the universe server. /// Gets a read-only view of the worlds returned by the universe server.
/// </summary> /// </summary>
/// <returns>An <see cref="IReadOnlyCollection{T}" /> containing <see cref="World" /> values.</returns> /// <returns>An <see cref="IReadOnlyCollection{T}" /> containing <see cref="VirtualParadiseWorld" /> values.</returns>
/// <remarks> /// <remarks>
/// This method will consume the list in full before returning, and therefore can result in apparent "hang" while the /// This method will consume the list in full before returning, and therefore can result in apparent "hang" while the
/// list is being fetched. For an <see cref="IAsyncEnumerable{T}" /> alternative, use /// list is being fetched. For an <see cref="IAsyncEnumerable{T}" /> alternative, use
/// <see cref="EnumerateWorldsAsync" />. /// <see cref="EnumerateWorldsAsync" />.
/// </remarks> /// </remarks>
/// <seealso cref="EnumerateWorldsAsync" /> /// <seealso cref="EnumerateWorldsAsync" />
public async Task<IReadOnlyCollection<World>> GetWorldsAsync() public async Task<IReadOnlyCollection<VirtualParadiseWorld>> GetWorldsAsync()
{ {
var worlds = new List<World>(); var worlds = new List<VirtualParadiseWorld>();
await foreach (World world in EnumerateWorldsAsync()) await foreach (VirtualParadiseWorld world in EnumerateWorldsAsync())
{ {
worlds.Add(world); worlds.Add(world);
} }

View File

@ -24,7 +24,7 @@ public sealed partial class VirtualParadiseClient : IDisposable
private readonly VirtualParadiseConfiguration _configuration; private readonly VirtualParadiseConfiguration _configuration;
private readonly ConcurrentDictionary<int, User> _friends = new(); private readonly ConcurrentDictionary<int, VirtualParadiseUser> _friends = new();
private readonly Dictionary<int, TaskCompletionSource<ReasonCode>> _inviteCompletionSources = new(); private readonly Dictionary<int, TaskCompletionSource<ReasonCode>> _inviteCompletionSources = new();
private readonly Dictionary<int, TaskCompletionSource<ReasonCode>> _joinCompletionSources = new(); private readonly Dictionary<int, TaskCompletionSource<ReasonCode>> _joinCompletionSources = new();
@ -66,7 +66,7 @@ public sealed partial class VirtualParadiseClient : IDisposable
/// Gets a read-only view of the cached avatars. /// Gets a read-only view of the cached avatars.
/// </summary> /// </summary>
/// <value>The cached avatars.</value> /// <value>The cached avatars.</value>
public IReadOnlyList<IAvatar> Avatars public IReadOnlyList<VirtualParadiseAvatar> Avatars
{ {
get => _avatars.Values.ToArray(); get => _avatars.Values.ToArray();
} }
@ -75,17 +75,17 @@ public sealed partial class VirtualParadiseClient : IDisposable
/// Gets the current avatar associated with this client. /// Gets the current avatar associated with this client.
/// </summary> /// </summary>
/// <value> /// <value>
/// An instance of <see cref="Avatar" />, or <see langword="null" /> if this client is not in a world. /// An instance of <see cref="VirtualParadiseAvatar" />, or <see langword="null" /> if this client is not in a world.
/// </value> /// </value>
public IAvatar? CurrentAvatar { get; internal set; } public VirtualParadiseAvatar? CurrentAvatar { get; internal set; }
/// <summary> /// <summary>
/// Gets the current user to which this client is logged in. /// Gets the current user to which this client is logged in.
/// </summary> /// </summary>
/// <value> /// <value>
/// An instance of <see cref="IUser" />, or <see langword="null" /> if this client is not logged in. /// An instance of <see cref="VirtualParadiseUser" />, or <see langword="null" /> if this client is not logged in.
/// </value> /// </value>
public IUser? CurrentUser { get; internal set; } public VirtualParadiseUser? CurrentUser { get; internal set; }
/// <summary> /// <summary>
/// Gets the world to which this client is currently connected. /// Gets the world to which this client is currently connected.
@ -94,7 +94,7 @@ public sealed partial class VirtualParadiseClient : IDisposable
/// The world to which this client is currently connected, or <see langword="null" /> if this client is not currently /// The world to which this client is currently connected, or <see langword="null" /> if this client is not currently
/// in a world. /// in a world.
/// </value> /// </value>
public World? CurrentWorld public VirtualParadiseWorld? CurrentWorld
{ {
get => CurrentAvatar?.Location.World; get => CurrentAvatar?.Location.World;
} }
@ -109,7 +109,7 @@ public sealed partial class VirtualParadiseClient : IDisposable
/// Gets a read-only view of the cached worlds. /// Gets a read-only view of the cached worlds.
/// </summary> /// </summary>
/// <value>The cached worlds.</value> /// <value>The cached worlds.</value>
public IReadOnlyList<World> Worlds public IReadOnlyList<VirtualParadiseWorld> Worlds
{ {
get => _worlds.Values.ToArray(); get => _worlds.Values.ToArray();
} }
@ -225,7 +225,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<World> 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, Rotation.None).ConfigureAwait(false); await CurrentAvatar!.TeleportAsync(position, Rotation.None).ConfigureAwait(false);
@ -245,7 +245,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<World> EnterAsync(string worldName, Vector3d position, Rotation 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);
@ -264,7 +264,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(World 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, Rotation.None).ConfigureAwait(false); await CurrentAvatar!.TeleportAsync(position, Rotation.None).ConfigureAwait(false);
@ -283,7 +283,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(World world, Vector3d position, Rotation 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);
@ -300,7 +300,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(World world) public async Task EnterAsync(VirtualParadiseWorld world)
{ {
if (world is null) if (world is null)
{ {
@ -314,7 +314,7 @@ public sealed partial class VirtualParadiseClient : IDisposable
/// Enters a specified world. /// Enters a specified world.
/// </summary> /// </summary>
/// <param name="worldName">The world to enter.</param> /// <param name="worldName">The world to enter.</param>
/// <returns>A <see cref="World" /> representing the world.</returns> /// <returns>A <see cref="VirtualParadiseWorld" /> representing the world.</returns>
/// <exception cref="ArgumentNullException"><paramref name="worldName" /> is <see langword="null" />.</exception> /// <exception cref="ArgumentNullException"><paramref name="worldName" /> is <see langword="null" />.</exception>
/// <exception cref="InvalidOperationException"> /// <exception cref="InvalidOperationException">
/// A world enter was attempted before the client was connected to a universe. /// A world enter was attempted before the client was connected to a universe.
@ -323,7 +323,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<World> EnterAsync(string worldName) public async Task<VirtualParadiseWorld> EnterAsync(string worldName)
{ {
if (worldName is null) if (worldName is null)
{ {
@ -389,27 +389,26 @@ public sealed partial class VirtualParadiseClient : IDisposable
await _worldSettingsCompletionSource.Task.ConfigureAwait(false); await _worldSettingsCompletionSource.Task.ConfigureAwait(false);
World? world = await GetWorldAsync(worldName).ConfigureAwait(false); VirtualParadiseWorld? world = await GetWorldAsync(worldName).ConfigureAwait(false);
if (world is null) if (world is null)
{ {
// we entered the world but it wasn't listed. unlisted world. we'll try our best to create details for it // we entered the world but it wasn't listed. unlisted world. we'll try our best to create details for it
world = new World(this, worldName); world = new VirtualParadiseWorld(this, worldName);
} }
if (CurrentAvatar is not null) if (CurrentAvatar is not null)
{ {
// TODO why is this here? we reassign CurrentAvatar right below! CurrentAvatar.Location = new Location(world);
((Avatar)CurrentAvatar).Location = new Location(world);
} }
world.Size = new Size(size, size); world.Size = new Size(size, size);
CurrentAvatar = new Avatar(this, -1) CurrentAvatar = new VirtualParadiseAvatar(this, -1)
{ {
Application = _configuration.Application!, Application = _configuration.Application!,
Name = $"[{_configuration.BotName}]", Name = $"[{_configuration.BotName}]",
Location = new Location(world, Vector3d.Zero, Rotation.None), Location = new Location(world, Vector3d.Zero, Rotation.None),
UserId = CurrentUser!.Id User = CurrentUser!
}; };
if (CurrentWorld is not null) if (CurrentWorld is not null)
@ -565,7 +564,7 @@ public sealed partial class VirtualParadiseClient : IDisposable
/// -or- /// -or-
/// <para><paramref name="message" /> is too long to send.</para> /// <para><paramref name="message" /> is too long to send.</para>
/// </exception> /// </exception>
public Task<IUserMessage> SendMessageAsync(string message) public Task<VirtualParadiseMessage> SendMessageAsync(string message)
{ {
if (message is null) if (message is null)
{ {
@ -593,9 +592,14 @@ public sealed partial class VirtualParadiseClient : IDisposable
} }
} }
return Task.FromResult((IUserMessage)new UserMessage( VirtualParadiseAvatar? avatar = CurrentAvatar;
CurrentAvatar!, return Task.FromResult(new VirtualParadiseMessage(
message MessageType.ChatMessage,
avatar!.Name,
message,
avatar,
FontStyle.Regular,
Color.Black
)); ));
} }
@ -615,7 +619,7 @@ public sealed partial class VirtualParadiseClient : IDisposable
/// -or- /// -or-
/// <para><paramref name="message" /> is too long to send.</para> /// <para><paramref name="message" /> is too long to send.</para>
/// </exception> /// </exception>
public Task<IConsoleMessage> SendMessageAsync(string message, FontStyle fontStyle, Color color) public Task<VirtualParadiseMessage> SendMessageAsync(string message, FontStyle fontStyle, Color color)
{ {
return SendMessageAsync(null, message, fontStyle, color); return SendMessageAsync(null, message, fontStyle, color);
} }
@ -637,7 +641,7 @@ public sealed partial class VirtualParadiseClient : IDisposable
/// -or- /// -or-
/// <para><paramref name="message" /> is too long to send.</para> /// <para><paramref name="message" /> is too long to send.</para>
/// </exception> /// </exception>
public Task<IConsoleMessage> SendMessageAsync(string? name, string message, FontStyle fontStyle, Color color) public Task<VirtualParadiseMessage> SendMessageAsync(string? name, string message, FontStyle fontStyle, Color color)
{ {
if (message is null) if (message is null)
{ {
@ -675,13 +679,14 @@ public sealed partial class VirtualParadiseClient : IDisposable
} }
} }
IAvatar avatar = CurrentAvatar!; VirtualParadiseAvatar avatar = CurrentAvatar!;
return Task.FromResult((IConsoleMessage)new ConsoleMessage( return Task.FromResult(new VirtualParadiseMessage(
avatar, MessageType.ConsoleMessage,
avatar.Name, name,
message, message,
color, avatar,
fontStyle fontStyle,
color
)); ));
} }
@ -733,7 +738,7 @@ public sealed partial class VirtualParadiseClient : IDisposable
pair.Value.TrySetCanceled(); pair.Value.TrySetCanceled();
} }
foreach (KeyValuePair<int, TaskCompletionSource<User>> pair in _usersCompletionSources) foreach (KeyValuePair<int, TaskCompletionSource<VirtualParadiseUser>> pair in _usersCompletionSources)
{ {
pair.Value.TrySetCanceled(); pair.Value.TrySetCanceled();
} }