From 53001defff272403865de322c5d8efa078f90926 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Boh=C3=A1=C4=8Dek?= Date: Tue, 21 Dec 2021 22:18:57 +0100 Subject: [PATCH] feat: add game event responders and logic --- .../Events/Handlers/EventDispatcher.cs | 51 +++++++++++++++++++ .../Events/Handlers/IGameResponder.cs | 34 +++++++++++++ Core/NosSmooth.Game/Events/IGameEvent.cs | 14 +++++ .../Extensions/ServiceCollectionExtensions.cs | 32 ++++++++++++ 4 files changed, 131 insertions(+) create mode 100644 Core/NosSmooth.Game/Events/Handlers/EventDispatcher.cs create mode 100644 Core/NosSmooth.Game/Events/Handlers/IGameResponder.cs create mode 100644 Core/NosSmooth.Game/Events/IGameEvent.cs create mode 100644 Core/NosSmooth.Game/Extensions/ServiceCollectionExtensions.cs diff --git a/Core/NosSmooth.Game/Events/Handlers/EventDispatcher.cs b/Core/NosSmooth.Game/Events/Handlers/EventDispatcher.cs new file mode 100644 index 0000000..675fa74 --- /dev/null +++ b/Core/NosSmooth.Game/Events/Handlers/EventDispatcher.cs @@ -0,0 +1,51 @@ +// +// EventDispatcher.cs +// +// Copyright (c) František Boháček. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Extensions.DependencyInjection; +using Remora.Results; + +namespace NosSmooth.Game.Events.Handlers; + +/// +/// Dispatches with . +/// +public class EventDispatcher +{ + private readonly IServiceProvider _provider; + + /// + /// Initializes a new instance of the class. + /// + /// The services provider. + public EventDispatcher(IServiceProvider provider) + { + _provider = provider; + } + + /// + /// Dispatches game responders that are registered in the service collection. + /// + /// The event to dispatch. + /// The cancellation token for cancelling the operation. + /// The type of the event. + /// A result that may or may not have succeeded. + public async Task DispatchEvent(TEvent @event, CancellationToken ct = default) + where TEvent : IGameEvent + { + var results = await Task.WhenAll( + _provider + .GetServices>() + .Select(responder => responder.Respond(@event, ct)) + ); + + return results.Length switch + { + 0 => Result.FromSuccess(), + 1 => results[0], + _ => new AggregateError(results.Cast().ToArray()), + }; + } +} \ No newline at end of file diff --git a/Core/NosSmooth.Game/Events/Handlers/IGameResponder.cs b/Core/NosSmooth.Game/Events/Handlers/IGameResponder.cs new file mode 100644 index 0000000..c5914e6 --- /dev/null +++ b/Core/NosSmooth.Game/Events/Handlers/IGameResponder.cs @@ -0,0 +1,34 @@ +// +// IGameResponder.cs +// +// Copyright (c) František Boháček. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using OneOf.Types; +using Remora.Results; + +namespace NosSmooth.Game.Events.Handlers; + +/// +/// Represents interface for classes that respond to . +/// +public interface IGameResponder +{ +} + +/// +/// Represents interface for classes that respond to game events. +/// Responds to . +/// +/// The event type this responder responds to. +public interface IGameResponder : IGameResponder + where TEvent : IGameEvent +{ + /// + /// Respond to the given packet. + /// + /// The packet to respond to. + /// The cancellation token for cancelling the operation. + /// A result that may or may not have succeeded. + public Task Respond(TEvent packet, CancellationToken ct = default); +} \ No newline at end of file diff --git a/Core/NosSmooth.Game/Events/IGameEvent.cs b/Core/NosSmooth.Game/Events/IGameEvent.cs new file mode 100644 index 0000000..f0694d2 --- /dev/null +++ b/Core/NosSmooth.Game/Events/IGameEvent.cs @@ -0,0 +1,14 @@ +// +// IGameEvent.cs +// +// Copyright (c) František Boháček. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace NosSmooth.Game.Events; + +/// +/// Represents base interface for game events. +/// +public interface IGameEvent +{ +} \ No newline at end of file diff --git a/Core/NosSmooth.Game/Extensions/ServiceCollectionExtensions.cs b/Core/NosSmooth.Game/Extensions/ServiceCollectionExtensions.cs new file mode 100644 index 0000000..ebbce0f --- /dev/null +++ b/Core/NosSmooth.Game/Extensions/ServiceCollectionExtensions.cs @@ -0,0 +1,32 @@ + + /// + /// Adds the given game event responder. + /// + /// The service collection. + /// The type of the event responder. + /// The collection. + public static IServiceCollection AddGameResponder(this IServiceCollection serviceCollection, Type gameResponder) + { + if (!gameResponder.GetInterfaces().Any( + i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IGameResponder<>) + )) + { + throw new ArgumentException( + $"{nameof(gameResponder)} should implement IGameResponder.", + nameof(gameResponder)); + } + + var handlerTypeInterfaces = gameResponder.GetInterfaces(); + var handlerInterfaces = handlerTypeInterfaces.Where + ( + r => r.IsGenericType && r.GetGenericTypeDefinition() == typeof(IGameResponder<>) + ); + + foreach (var handlerInterface in handlerInterfaces) + { + serviceCollection.AddScoped(handlerInterface, gameResponder); + } + + return serviceCollection; + } +} \ No newline at end of file -- 2.48.1