From e0666d54e4a396e2488daa5c28a670189a986c6a Mon Sep 17 00:00:00 2001 From: Oliver Booth Date: Sun, 27 Nov 2022 20:42:55 +0000 Subject: [PATCH] Add support for client extensions This is currently preliminary, and the only event mapped so far is chat messaging --- .../VirtualParadiseClientExtension.cs | 33 +++++++++ .../src/VirtualParadiseClient.Extensions.cs | 68 +++++++++++++++++++ .../src/VirtualParadiseClient.NativeEvents.cs | 6 ++ 3 files changed, 107 insertions(+) create mode 100644 VpSharp/src/ClientExtensions/VirtualParadiseClientExtension.cs create mode 100644 VpSharp/src/VirtualParadiseClient.Extensions.cs diff --git a/VpSharp/src/ClientExtensions/VirtualParadiseClientExtension.cs b/VpSharp/src/ClientExtensions/VirtualParadiseClientExtension.cs new file mode 100644 index 0000000..20c4d76 --- /dev/null +++ b/VpSharp/src/ClientExtensions/VirtualParadiseClientExtension.cs @@ -0,0 +1,33 @@ +using VpSharp.EventData; + +namespace VpSharp.ClientExtensions; + +/// +/// Represents the base class for extensions to the . +/// +public abstract class VirtualParadiseClientExtension +{ + /// + /// Initializes a new instance of the class. + /// + /// The owning client. + protected VirtualParadiseClientExtension(VirtualParadiseClient client) + { + Client = client; + } + + /// + /// Gets the client to which this extension is registered. + /// + /// The owning client. + public VirtualParadiseClient Client { get; } + + /// + /// Called when a chat message is received. + /// + /// An object containing event data. + protected internal virtual Task OnMessageReceived(MessageReceivedEventArgs args) + { + return Task.CompletedTask; + } +} diff --git a/VpSharp/src/VirtualParadiseClient.Extensions.cs b/VpSharp/src/VirtualParadiseClient.Extensions.cs new file mode 100644 index 0000000..d3d9401 --- /dev/null +++ b/VpSharp/src/VirtualParadiseClient.Extensions.cs @@ -0,0 +1,68 @@ +using System.Globalization; +using System.Reflection; +using VpSharp.ClientExtensions; + +namespace VpSharp; + +public sealed partial class VirtualParadiseClient +{ + private readonly List _extensions = new(); + + /// + /// Adds an extension to this client. + /// + /// The arguments to pass to the extension constructor. + /// The type of the extension to add. + /// A new instance of the specified extension. + /// + /// is abstract. + /// + public T AddExtension(params object?[]? arguments) where T : VirtualParadiseClientExtension + { + return (AddExtension(typeof(T), arguments) as T)!; + } + + /// + /// Adds an extension to this client. + /// + /// The type of the extension to add. + /// The arguments to pass to the extension constructor. + /// A new instance of the specified extension. + /// is . + /// + /// does not inherit from . + /// -or- + /// is abstract. + /// + public VirtualParadiseClientExtension AddExtension(Type type, params object?[]? arguments) + { + ArgumentNullException.ThrowIfNull(type); + + if (!type.IsSubclassOf(typeof(VirtualParadiseClientExtension))) + { + throw new ArgumentException($"Type must inherit from {typeof(VirtualParadiseClientExtension)}"); + } + + if (type.IsAbstract) + { + throw new ArgumentException("Extension type cannot be abstract"); + } + + object?[] argumentsActual = {this}; + if (arguments is not null) + { + argumentsActual = argumentsActual.Concat(arguments).ToArray(); + } + + const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; + object? instance = Activator.CreateInstance(type, bindingFlags, null, argumentsActual, CultureInfo.InvariantCulture); + if (instance is not VirtualParadiseClientExtension extension) + { + var innerException = new Exception($"Could not instantiate {type}"); + throw new TypeInitializationException(type.FullName, innerException); + } + + _extensions.Add(extension); + return extension; + } +} diff --git a/VpSharp/src/VirtualParadiseClient.NativeEvents.cs b/VpSharp/src/VirtualParadiseClient.NativeEvents.cs index c3b001b..3f5b068 100644 --- a/VpSharp/src/VirtualParadiseClient.NativeEvents.cs +++ b/VpSharp/src/VirtualParadiseClient.NativeEvents.cs @@ -2,6 +2,7 @@ using System.Collections.Concurrent; using System.Drawing; using System.Numerics; using System.Threading.Channels; +using VpSharp.ClientExtensions; using VpSharp.Entities; using VpSharp.EventData; using VpSharp.Internal; @@ -79,6 +80,11 @@ public sealed partial class VirtualParadiseClient var args = new MessageReceivedEventArgs(message); RaiseEvent(MessageReceived, args); + + foreach (VirtualParadiseClientExtension extension in _extensions) + { + extension.OnMessageReceived(args); + } } private async void OnAvatarAddNativeEvent(IntPtr sender)