A Core/NosSmooth.Game/Apis/DialogHandler.cs => Core/NosSmooth.Game/Apis/DialogHandler.cs +56 -0
@@ 0,0 1,56 @@
+//
+// DialogHandler.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 NosSmooth.Core.Client;
+using NosSmooth.Game.Data.Dialogs;
+using Remora.Results;
+
+namespace NosSmooth.Game.Apis;
+
+/// <summary>
+/// Handles accepting and denying of dialogs.
+/// </summary>
+public class DialogHandler
+{
+ private readonly INostaleClient _client;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="DialogHandler"/> class.
+ /// </summary>
+ /// <param name="client">The client.</param>
+ public DialogHandler(INostaleClient client)
+ {
+ _client = client;
+ }
+
+ /// <summary>
+ /// Accept the operation the dialog does.
+ /// </summary>
+ /// <param name="dialog">The opened dialog.</param>
+ /// <param name="ct">The cancellation token used for cancelling the operation.</param>
+ /// <returns>A result that may or may not have succeeded.</returns>
+ public Task<Result> AcceptAsync(Dialog dialog, CancellationToken ct = default)
+ => _client.SendPacketAsync(dialog.AcceptCommand, ct);
+
+ /// <summary>
+ /// Try to deny the operation the dialog does.
+ /// </summary>
+ /// <remarks>
+ /// Some dialogs do not allow denying, they are just ignored instead.
+ /// </remarks>
+ /// <param name="dialog">The opened dialog.</param>
+ /// <param name="ct">The cancellation token used for cancelling the operation.</param>
+ /// <returns>A result that may or may not have succeeded.</returns>
+ public Task<Result> DenyAsync(Dialog dialog, CancellationToken ct = default)
+ {
+ if (dialog.DenyCommand is null)
+ {
+ return Task.FromResult(Result.FromSuccess());
+ }
+
+ return _client.SendPacketAsync(dialog.DenyCommand, ct);
+ }
+}<
\ No newline at end of file
M Core/NosSmooth.Game/Data/Dialogs/Dialog.cs => Core/NosSmooth.Game/Data/Dialogs/Dialog.cs +5 -2
@@ 4,6 4,9 @@
// 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 NosSmooth.Packets.Enums;
+using OneOf;
+
namespace NosSmooth.Game.Data.Dialogs;
/// <summary>
@@ 14,7 17,7 @@ namespace NosSmooth.Game.Data.Dialogs;
public record Dialog
(
string AcceptCommand,
-
- // OneOf<Game18NConstString, string> Message,
+ string? DenyCommand,
+ OneOf<string, Game18NConstString> Message,
IReadOnlyList<string> Parameters
);=
\ No newline at end of file
A Core/NosSmooth.Game/Events/Ui/DialogOpenedEvent.cs => Core/NosSmooth.Game/Events/Ui/DialogOpenedEvent.cs +11 -0
@@ 0,0 1,11 @@
+//
+// DialogOpenedEvent.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 NosSmooth.Game.Data.Dialogs;
+
+namespace NosSmooth.Game.Events.Ui;
+
+public record DialogOpenedEvent(Dialog Dialog) : IGameEvent;<
\ No newline at end of file
M Core/NosSmooth.Game/Extensions/ServiceCollectionExtensions.cs => Core/NosSmooth.Game/Extensions/ServiceCollectionExtensions.cs +1 -0
@@ 68,6 68,7 @@ public static class ServiceCollectionExtensions
.AddPacketResponder<EqResponder>();
serviceCollection
+ .AddTransient<DialogHandler>()
.AddTransient<UnsafeMapApi>()
.AddTransient<UnsafeInventoryApi>()
.AddTransient<UnsafeMateApi>()
A Core/NosSmooth.Game/PacketHandlers/Ui/DialogOpenResponder.cs => Core/NosSmooth.Game/PacketHandlers/Ui/DialogOpenResponder.cs +147 -0
@@ 0,0 1,147 @@
+//
+// DialogOpenResponder.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 NosSmooth.Core.Packets;
+using NosSmooth.Game.Data.Dialogs;
+using NosSmooth.Game.Events.Core;
+using NosSmooth.Game.Events.Ui;
+using NosSmooth.Packets.Enums;
+using NosSmooth.Packets.Server.UI;
+using Remora.Results;
+
+namespace NosSmooth.Game.PacketHandlers.Ui;
+
+/// <summary>
+/// A responder to dialog events that calls DialogOpen.
+/// </summary>
+public class DialogOpenResponder : IPacketResponder<QnamlPacket>, IPacketResponder<Qnamli2Packet>,
+ IPacketResponder<QnaPacket>, IPacketResponder<DlgPacket>, IPacketResponder<DlgiPacket>
+{
+ private readonly EventDispatcher _eventDispatcher;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="DialogOpenResponder"/> class.
+ /// </summary>
+ /// <param name="eventDispatcher">The event dispatcher.</param>
+ public DialogOpenResponder(EventDispatcher eventDispatcher)
+ {
+ _eventDispatcher = eventDispatcher;
+
+ }
+
+ /// <inheritdoc />
+ public Task<Result> Respond(PacketEventArgs<QnamlPacket> packetArgs, CancellationToken ct = default)
+ {
+ var packet = packetArgs.Packet;
+ if (packet.Type != QnamlType.Dialog)
+ {
+ return Task.FromResult(Result.FromSuccess());
+ }
+
+ return _eventDispatcher.DispatchEvent
+ (
+ new DialogOpenedEvent
+ (
+ new Dialog
+ (
+ packet.AcceptCommand,
+ null,
+ packet.Message,
+ Array.Empty<string>()
+ )
+ ),
+ ct
+ );
+ }
+
+ /// <inheritdoc />
+ public Task<Result> Respond(PacketEventArgs<Qnamli2Packet> packetArgs, CancellationToken ct = default)
+ {
+ var packet = packetArgs.Packet;
+ if (packet.Type != QnamlType.Dialog)
+ {
+ return Task.FromResult(Result.FromSuccess());
+ }
+
+ return _eventDispatcher.DispatchEvent
+ (
+ new DialogOpenedEvent
+ (
+ new Dialog
+ (
+ packet.AcceptCommand,
+ null,
+ packet.MessageConst,
+ packet.Parameters
+ )
+ ),
+ ct
+ );
+ }
+
+ /// <inheritdoc />
+ public Task<Result> Respond(PacketEventArgs<QnaPacket> packetArgs, CancellationToken ct = default)
+ {
+ var packet = packetArgs.Packet;
+
+ return _eventDispatcher.DispatchEvent
+ (
+ new DialogOpenedEvent
+ (
+ new Dialog
+ (
+ packet.AcceptCommand,
+ null,
+ packet.Message,
+ Array.Empty<string>()
+ )
+ ),
+ ct
+ );
+ }
+
+ /// <inheritdoc />
+ public Task<Result> Respond(PacketEventArgs<DlgPacket> packetArgs, CancellationToken ct = default)
+ {
+ var packet = packetArgs.Packet;
+
+ return _eventDispatcher.DispatchEvent
+ (
+ new DialogOpenedEvent
+ (
+ new Dialog
+ (
+ packet.AcceptCommand,
+ packet.DenyCommand,
+ packet.Message,
+ Array.Empty<string>()
+ )
+ ),
+ ct
+ );
+ }
+
+ /// <inheritdoc />
+ public Task<Result> Respond(PacketEventArgs<DlgiPacket> packetArgs, CancellationToken ct = default)
+ {
+ var packet = packetArgs.Packet;
+
+ return _eventDispatcher.DispatchEvent
+ (
+ new DialogOpenedEvent
+ (
+ new Dialog
+ (
+ packet.AcceptCommand,
+ packet.DenyCommand,
+ packet.MessageConst,
+ packet.Parameters
+ )
+ ),
+ ct
+ );
+ }
+}<
\ No newline at end of file