Compare commits

...

3 Commits

Author SHA1 Message Date
Oliver Booth ff298a8af5
refactor!: extract interface for Message
This commit also amends the previous commit, where files relevant for User were missed
2024-03-17 13:28:42 +00:00
Oliver Booth 3841ad13aa
refactor!: extract interface for User 2024-03-17 13:25:32 +00:00
Oliver Booth a169346f53
refactor!: extract interface for Avatar 2024-03-17 12:56:28 +00:00
35 changed files with 474 additions and 178 deletions

View File

@ -54,7 +54,7 @@ public sealed class RequireUserNameAttribute : PreExecutionCheckAttribute
throw new ArgumentNullException(nameof(context)); throw new ArgumentNullException(nameof(context));
} }
User user = await context.Avatar.GetUserAsync().ConfigureAwait(false); IUser user = await context.Avatar.GetUserAsync().ConfigureAwait(false);
return Names.Contains(user.Name); return 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, Avatar avatar, string commandName, string alias, internal CommandContext(VirtualParadiseClient client, IAvatar avatar, string commandName, string alias,
string rawArguments) string rawArguments)
{ {
Client = client; Client = client;
@ -36,7 +36,7 @@ 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 Avatar Avatar { get; } public IAvatar Avatar { get; }
/// <summary> /// <summary>
/// Gets the client which raised the event. /// Gets the client which raised the event.
@ -65,10 +65,11 @@ 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 Task<Message> RespondAsync(string message, bool ephemeral = false) public async Task<IMessage> RespondAsync(string message, bool ephemeral = false)
{ {
return ephemeral return ephemeral
? Avatar.SendMessageAsync(Client.CurrentAvatar?.Name, message, FontStyle.Regular, Color.Black) ? await Avatar.SendMessageAsync(Client.CurrentAvatar?.Name, message, FontStyle.Regular, Color.Black)
: Client.SendMessageAsync(message); .ConfigureAwait(false)
: await Client.SendMessageAsync(message).ConfigureAwait(false);
} }
} }

View File

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

View File

@ -45,7 +45,7 @@ Console.WriteLine(@"Entering world");
World world = await client.EnterAsync("Mutation"); World world = await client.EnterAsync("Mutation");
Console.WriteLine(@"Entered world!"); Console.WriteLine(@"Entered world!");
Avatar avatar = client.CurrentAvatar!; IAvatar 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

@ -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="args">An object containing event data.</param> /// <param name="message">The message which was received.</param>
protected internal virtual Task OnMessageReceived(Message message) protected internal virtual Task OnMessageReceived(IMessage message)
{ {
return Task.CompletedTask; return Task.CompletedTask;
} }

View File

@ -10,10 +10,10 @@ 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> public sealed class Avatar : IEquatable<Avatar>, IAvatar
{ {
private readonly VirtualParadiseClient _client; private readonly VirtualParadiseClient _client;
private User? _user; private IUser? _user;
internal Avatar(VirtualParadiseClient client, int session) internal Avatar(VirtualParadiseClient client, int session)
{ {
@ -172,7 +172,7 @@ public sealed class Avatar : IEquatable<Avatar>
/// Gets the user associated with this avatar. /// Gets the user associated with this avatar.
/// </summary> /// </summary>
/// <returns>The user.</returns> /// <returns>The user.</returns>
public async Task<User> GetUserAsync() public async Task<IUser> GetUserAsync()
{ {
_user ??= await _client.GetUserAsync(UserId).ConfigureAwait(false); _user ??= await _client.GetUserAsync(UserId).ConfigureAwait(false);
return _user; return _user;
@ -196,7 +196,7 @@ public sealed class Avatar : IEquatable<Avatar>
/// -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<Message> SendMessageAsync(string message, FontStyle fontStyle, Color color) public Task<IConsoleMessage> SendMessageAsync(string message, FontStyle fontStyle, Color color)
{ {
return SendMessageAsync(null, message, fontStyle, color); return SendMessageAsync(null, message, fontStyle, color);
} }
@ -221,7 +221,7 @@ public sealed class Avatar : IEquatable<Avatar>
/// <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<Message> SendMessageAsync(string? name, string message, FontStyle fontStyle, Color color) public Task<IConsoleMessage> SendMessageAsync(string? name, string message, FontStyle fontStyle, Color color)
{ {
if (message is null) if (message is null)
{ {
@ -233,7 +233,7 @@ public sealed class Avatar : IEquatable<Avatar>
throw new ArgumentException(ExceptionMessages.ValueCannotBeEmpty, nameof(message)); throw new ArgumentException(ExceptionMessages.ValueCannotBeEmpty, nameof(message));
} }
Avatar avatar; IAvatar avatar;
lock (_client.Lock) lock (_client.Lock)
{ {
@ -267,13 +267,12 @@ public sealed class Avatar : IEquatable<Avatar>
avatar = _client.CurrentAvatar!; avatar = _client.CurrentAvatar!;
} }
return Task.FromResult(new Message( return Task.FromResult((IConsoleMessage)new ConsoleMessage(
MessageType.ConsoleMessage,
name,
message,
avatar, avatar,
fontStyle, avatar.Name,
color message,
color,
fontStyle
)); ));
} }

View File

@ -0,0 +1,30 @@
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

@ -0,0 +1,184 @@
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

@ -0,0 +1,21 @@
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

@ -0,0 +1,25 @@
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

@ -0,0 +1,71 @@
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

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

View File

@ -1,67 +1,29 @@
using System.Drawing; namespace VpSharp.Entities;
namespace VpSharp.Entities;
/// <summary> /// <summary>
/// Represents a message. /// Represents a message.
/// </summary> /// </summary>
public sealed class Message public abstract class Message : IMessage
{ {
internal Message( /// <summary>
MessageType type, /// Initializes a new instance of the <see cref="Message" /> class.
string? name, /// </summary>
string content, /// <param name="author">The author of the message.</param>
Avatar author, /// <param name="name">The apparent sender's name of the message.</param>
FontStyle style, /// <param name="content">The content of the message.</param>
Color color) protected Message(IAvatar author, string name, string content)
{ {
Type = type;
Name = string.IsNullOrWhiteSpace(name) ? null : name;
Content = content;
Author = author; Author = author;
Style = style; Content = content;
Color = color; Name = name;
} }
/// <summary>
/// Gets the message author.
/// </summary>
/// <value>The message author.</value>
public Avatar 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 /> /// <inheritdoc />
public override string ToString() public IAvatar Author { get; }
{
return $"Message {Author}; Type {Type}; Content {Content}"; /// <inheritdoc />
} public string Content { get; }
/// <inheritdoc />
public string Name { get; }
} }

View File

@ -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<User> Owner { get; set; } public Option<IUser> 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.");
} }
User oldOwner = TargetObject.Owner; IUser oldOwner = TargetObject.Owner;
_ = vp_int_set(handle, ObjectUserId, Owner.ValueOr(oldOwner).Id); _ = vp_int_set(handle, ObjectUserId, Owner.ValueOr(oldOwner).Id);
} }

View File

@ -8,7 +8,7 @@ namespace VpSharp.Entities;
/// <summary> /// <summary>
/// Represents a Virtual Paradise user. /// Represents a Virtual Paradise user.
/// </summary> /// </summary>
public sealed class User : IEquatable<User> public sealed class User : IEquatable<User>, IUser
{ {
private readonly VirtualParadiseClient _client; private readonly VirtualParadiseClient _client;

View File

@ -0,0 +1,17 @@
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

@ -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 User Owner { get; internal set; } = null!; public IUser Owner { get; internal set; } = null!;
internal byte[] Data { get; set; } = Array.Empty<byte>(); internal byte[] Data { get; set; } = Array.Empty<byte>();

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(Avatar avatar, Avatar clickedAvatar, Vector3d clickPoint) public AvatarClickedEventArgs(IAvatar avatar, IAvatar 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 Avatar Avatar { get; } public IAvatar 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 Avatar ClickedAvatar { get; } public IAvatar 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(Avatar avatar, Location locationAfter, Location? locationBefore) public AvatarMovedEventArgs(IAvatar 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 Avatar Avatar { get; } public IAvatar 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(Avatar avatar, int typeAfter, int? typeBefore) public AvatarTypeChangedEventArgs(IAvatar 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 Avatar Avatar { get; } public IAvatar 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(Avatar avatar, VirtualParadiseObject bumpedObject, BumpPhase phase) public ObjectBumpEventArgs(IAvatar 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 Avatar Avatar { get; } public IAvatar 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(
Avatar avatar, IAvatar 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 Avatar Avatar { get; } public IAvatar 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(
Avatar avatar, IAvatar 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 Avatar Avatar { get; } public IAvatar 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(Avatar avatar, VirtualParadiseObject createdObject) public ObjectCreatedEventArgs(IAvatar 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 Avatar Avatar { get; } public IAvatar 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(Avatar avatar, int objectId, VirtualParadiseObject deletedObject) public ObjectDeletedEventArgs(IAvatar 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 Avatar Avatar { get; } public IAvatar 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(Avatar avatar, Location location) public TeleportedEventArgs(IAvatar 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 Avatar Avatar { get; } public IAvatar 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, Avatar avatar) public UriReceivedEventArgs(Uri uri, UriTarget target, IAvatar 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 Avatar Avatar { get; } public IAvatar 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,
User user, IUser 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 User User { get; } public IUser 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, User user) internal JoinRequest(VirtualParadiseClient client, int requestId, string name, IUser 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 User User { get; } public IUser 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

@ -1,17 +0,0 @@
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

@ -20,7 +20,7 @@ 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 Avatar? GetAvatar(int session) public IAvatar? GetAvatar(int session)
{ {
_avatars.TryGetValue(session, out Avatar? avatar); _avatars.TryGetValue(session, out Avatar? avatar);
return avatar; return avatar;

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<Avatar> _avatarJoined = new(); private readonly Subject<IAvatar> _avatarJoined = new();
private readonly Subject<Avatar> _avatarLeft = new(); private readonly Subject<IAvatar> _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<Message> _messageReceived = new(); private readonly Subject<IMessage> _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<Avatar> AvatarJoined public IObservable<IAvatar> 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<Avatar> AvatarLeft public IObservable<IAvatar> 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<Message> MessageReceived public IObservable<IMessage> 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)
{ {
Message message; IMessage message;
lock (Lock) lock (Lock)
{ {
@ -61,6 +61,7 @@ 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;
@ -72,10 +73,12 @@ 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);
} }
Avatar avatar = GetAvatar(session)!;
message = new Message((MessageType)type, name, content, avatar, style, color);
} }
_messageReceived.OnNext(message); _messageReceived.OnNext(message);
@ -115,7 +118,7 @@ public sealed partial class VirtualParadiseClient
rotation = Rotation.CreateFromTiltYawRoll(pitch, yaw, 0); rotation = Rotation.CreateFromTiltYawRoll(pitch, yaw, 0);
} }
Avatar avatar = GetAvatar(session)!; var avatar = (Avatar)GetAvatar(session)!;
if (type != avatar.Type) if (type != avatar.Type)
{ {
int oldType = avatar.Type; int oldType = avatar.Type;
@ -145,7 +148,7 @@ public sealed partial class VirtualParadiseClient
session = vp_int(sender, IntegerAttribute.AvatarSession); session = vp_int(sender, IntegerAttribute.AvatarSession);
} }
Avatar avatar = GetAvatar(session)!; IAvatar avatar = GetAvatar(session)!;
_avatars.TryRemove(session, out Avatar _); _avatars.TryRemove(session, out Avatar _);
_avatarLeft.OnNext(avatar); _avatarLeft.OnNext(avatar);
} }
@ -173,7 +176,7 @@ public sealed partial class VirtualParadiseClient
} }
else else
{ {
Avatar avatar = GetAvatar(session)!; IAvatar avatar = GetAvatar(session)!;
var args = new ObjectCreatedEventArgs(avatar, virtualParadiseObject); var args = new ObjectCreatedEventArgs(avatar, virtualParadiseObject);
_objectCreated.OnNext(args); _objectCreated.OnNext(args);
} }
@ -190,7 +193,7 @@ public sealed partial class VirtualParadiseClient
session = vp_int(sender, IntegerAttribute.AvatarSession); session = vp_int(sender, IntegerAttribute.AvatarSession);
} }
Avatar avatar = GetAvatar(session)!; IAvatar avatar = GetAvatar(session)!;
VirtualParadiseObject? cachedObject = null; VirtualParadiseObject? cachedObject = null;
if (_objects.TryGetValue(objectId, out VirtualParadiseObject? virtualParadiseObject)) if (_objects.TryGetValue(objectId, out VirtualParadiseObject? virtualParadiseObject))
@ -226,7 +229,7 @@ public sealed partial class VirtualParadiseClient
session = vp_int(sender, IntegerAttribute.AvatarSession); session = vp_int(sender, IntegerAttribute.AvatarSession);
} }
Avatar? avatar = GetAvatar(session); IAvatar avatar = GetAvatar(session)!;
VirtualParadiseObject? virtualParadiseObject; VirtualParadiseObject? virtualParadiseObject;
try try
@ -240,7 +243,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);
} }
@ -261,7 +264,7 @@ public sealed partial class VirtualParadiseClient
clickPoint = new Vector3d(x, y, z); clickPoint = new Vector3d(x, y, z);
} }
Avatar avatar = GetAvatar(session)!; IAvatar avatar = GetAvatar(session)!;
try try
{ {
VirtualParadiseObject virtualParadiseObject = await GetObjectAsync(objectId).ConfigureAwait(false); VirtualParadiseObject virtualParadiseObject = await GetObjectAsync(objectId).ConfigureAwait(false);
@ -332,7 +335,7 @@ public sealed partial class VirtualParadiseClient
userId = vp_int(sender, IntegerAttribute.FriendUserId); userId = vp_int(sender, IntegerAttribute.FriendUserId);
} }
User user = await GetUserAsync(userId).ConfigureAwait(false); var user = (User)await GetUserAsync(userId).ConfigureAwait(false);
_friends.AddOrUpdate(userId, user, (_, _) => user); _friends.AddOrUpdate(userId, user, (_, _) => user);
} }
@ -423,8 +426,8 @@ public sealed partial class VirtualParadiseClient
clickPoint = new Vector3d(x, y, z); clickPoint = new Vector3d(x, y, z);
} }
Avatar avatar = GetAvatar(session)!; IAvatar avatar = GetAvatar(session)!;
Avatar clickedAvatar = GetAvatar(clickedSession)!; IAvatar clickedAvatar = GetAvatar(clickedSession)!;
var args = new AvatarClickedEventArgs(avatar, clickedAvatar, clickPoint); var args = new AvatarClickedEventArgs(avatar, clickedAvatar, clickPoint);
_avatarClicked.OnNext(args); _avatarClicked.OnNext(args);
} }
@ -457,8 +460,8 @@ public sealed partial class VirtualParadiseClient
: await GetWorldAsync(worldName).ConfigureAwait(false))!; : await GetWorldAsync(worldName).ConfigureAwait(false))!;
var location = new Location(world, position, rotation); var location = new Location(world, position, rotation);
CurrentAvatar!.Location = location; ((Avatar)CurrentAvatar!).Location = location;
Avatar avatar = GetAvatar(session)!; IAvatar avatar = GetAvatar(session)!;
var args = new TeleportedEventArgs(avatar, location); var args = new TeleportedEventArgs(avatar, location);
_teleported.OnNext(args); _teleported.OnNext(args);
} }
@ -474,7 +477,7 @@ public sealed partial class VirtualParadiseClient
objectId = vp_int(sender, IntegerAttribute.ObjectId); objectId = vp_int(sender, IntegerAttribute.ObjectId);
} }
Avatar avatar = GetAvatar(session)!; IAvatar avatar = GetAvatar(session)!;
try try
{ {
var vpObject = await GetObjectAsync(objectId).ConfigureAwait(false); var vpObject = await GetObjectAsync(objectId).ConfigureAwait(false);
@ -505,7 +508,7 @@ public sealed partial class VirtualParadiseClient
return; return;
} }
Avatar avatar = GetAvatar(session)!; IAvatar 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);
@ -522,7 +525,7 @@ public sealed partial class VirtualParadiseClient
objectId = vp_int(sender, IntegerAttribute.ObjectId); objectId = vp_int(sender, IntegerAttribute.ObjectId);
} }
Avatar avatar = GetAvatar(session)!; IAvatar avatar = GetAvatar(session)!;
try try
{ {
var vpObject = await GetObjectAsync(objectId).ConfigureAwait(false); var vpObject = await GetObjectAsync(objectId).ConfigureAwait(false);
@ -548,7 +551,7 @@ public sealed partial class VirtualParadiseClient
name = vp_string(NativeInstanceHandle, StringAttribute.JoinName); name = vp_string(NativeInstanceHandle, StringAttribute.JoinName);
} }
User user = await GetUserAsync(userId).ConfigureAwait(false); IUser 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);
} }
@ -582,7 +585,7 @@ public sealed partial class VirtualParadiseClient
} }
World world = (await GetWorldAsync(worldName).ConfigureAwait(false))!; World world = (await GetWorldAsync(worldName).ConfigureAwait(false))!;
User user = await GetUserAsync(userId).ConfigureAwait(false); IUser 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

@ -16,7 +16,7 @@ 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<User> GetUserAsync(int userId) public async Task<IUser> GetUserAsync(int userId)
{ {
if (_users.TryGetValue(userId, out User? user)) if (_users.TryGetValue(userId, out User? user))
{ {

View File

@ -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<Avatar> Avatars public IReadOnlyList<IAvatar> Avatars
{ {
get => _avatars.Values.ToArray(); get => _avatars.Values.ToArray();
} }
@ -77,15 +77,15 @@ public sealed partial class VirtualParadiseClient : IDisposable
/// <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="Avatar" />, or <see langword="null" /> if this client is not in a world.
/// </value> /// </value>
public Avatar? CurrentAvatar { get; internal set; } public IAvatar? 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="User" />, or <see langword="null" /> if this client is not logged in. /// An instance of <see cref="IUser" />, or <see langword="null" /> if this client is not logged in.
/// </value> /// </value>
public User? CurrentUser { get; internal set; } public IUser? 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.
@ -399,7 +399,7 @@ public sealed partial class VirtualParadiseClient : IDisposable
if (CurrentAvatar is not null) if (CurrentAvatar is not null)
{ {
// TODO why is this here? we reassign CurrentAvatar right below! // 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);
@ -565,7 +565,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<Message> SendMessageAsync(string message) public Task<IUserMessage> SendMessageAsync(string message)
{ {
if (message is null) if (message is null)
{ {
@ -593,14 +593,9 @@ public sealed partial class VirtualParadiseClient : IDisposable
} }
} }
Avatar? avatar = CurrentAvatar; return Task.FromResult((IUserMessage)new UserMessage(
return Task.FromResult(new Message( CurrentAvatar!,
MessageType.ChatMessage, message
avatar!.Name,
message,
avatar,
FontStyle.Regular,
Color.Black
)); ));
} }
@ -620,7 +615,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<Message> SendMessageAsync(string message, FontStyle fontStyle, Color color) public Task<IConsoleMessage> SendMessageAsync(string message, FontStyle fontStyle, Color color)
{ {
return SendMessageAsync(null, message, fontStyle, color); return SendMessageAsync(null, message, fontStyle, color);
} }
@ -642,7 +637,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<Message> SendMessageAsync(string? name, string message, FontStyle fontStyle, Color color) public Task<IConsoleMessage> SendMessageAsync(string? name, string message, FontStyle fontStyle, Color color)
{ {
if (message is null) if (message is null)
{ {
@ -680,14 +675,13 @@ public sealed partial class VirtualParadiseClient : IDisposable
} }
} }
Avatar avatar = CurrentAvatar!; IAvatar avatar = CurrentAvatar!;
return Task.FromResult(new Message( return Task.FromResult((IConsoleMessage)new ConsoleMessage(
MessageType.ConsoleMessage,
name,
message,
avatar, avatar,
fontStyle, avatar.Name,
color message,
color,
fontStyle
)); ));
} }