From d0ad5e7aec5084b56486f6dec7d8490e5ab42e04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Boh=C3=A1=C4=8Dek?= Date: Thu, 23 Dec 2021 16:11:51 +0100 Subject: [PATCH] feat: implement walk command handler --- .../Walk/WalkCommandHandler.cs | 69 +++++++++++++++++-- 1 file changed, 64 insertions(+), 5 deletions(-) diff --git a/Local/NosSmooth.LocalClient/CommandHandlers/Walk/WalkCommandHandler.cs b/Local/NosSmooth.LocalClient/CommandHandlers/Walk/WalkCommandHandler.cs index ca13c27e4b6fcf20d4386850c128a01498cf50ab..7fd2a6a4abb89401016893ec6e4e12badbccb6f9 100644 --- a/Local/NosSmooth.LocalClient/CommandHandlers/Walk/WalkCommandHandler.cs +++ b/Local/NosSmooth.LocalClient/CommandHandlers/Walk/WalkCommandHandler.cs @@ -4,11 +4,13 @@ // 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.Options; using NosSmooth.Core.Commands; +using NosSmooth.LocalClient.CommandHandlers.Walk.Errors; using NosSmoothCore; using Remora.Results; -namespace NosSmooth.LocalClient.CommandHandlers; +namespace NosSmooth.LocalClient.CommandHandlers.Walk; /// /// Handles . @@ -16,20 +18,77 @@ namespace NosSmooth.LocalClient.CommandHandlers; public class WalkCommandHandler : ICommandHandler { private readonly NosClient _nosClient; + private readonly WalkStatus _walkStatus; + private readonly WalkCommandHandlerOptions _options; /// /// Initializes a new instance of the class. /// /// The local client. - public WalkCommandHandler(NosClient nosClient) + /// The walk status. + /// The options. + public WalkCommandHandler(NosClient nosClient, WalkStatus walkStatus, IOptions options) { + _options = options.Value; _nosClient = nosClient; + _walkStatus = walkStatus; } /// - public Task HandleCommand(WalkCommand command, CancellationToken ct = default) + /// 1) If client called walk, cancel. + /// 2) If another walk command requested, cancel. + /// 3) If at the correct spot, cancel. + /// 4) If not walking for over x ms, cancel. + public async Task HandleCommand(WalkCommand command, CancellationToken ct = default) { - _nosClient.GetCharacter().Walk(command.TargetX, command.TargetY); - return Task.Delay(1000).ContinueWith(_ => Result.FromSuccess()); // TODO: Wait for the move to finish + CancellationTokenSource linked = CancellationTokenSource.CreateLinkedTokenSource(ct); + ct = linked.Token; + await _walkStatus.SetWalking(linked, command.TargetX, command.TargetY, command.CancelOnUserMove); + while (!ct.IsCancellationRequested) + { + try + { + _nosClient.GetCharacter().Walk(command.TargetX, command.TargetY); + } + catch (Exception e) + { + try + { + await _walkStatus.CancelWalkingAsync(ct: ct); + } + catch + { + // ignored, just for cancellation + } + + return e; + } + + try + { + await Task.Delay(_options.CheckDelay, ct); + } + catch + { + // ignored + } + + if (_walkStatus.IsFinished) + { + return Result.FromSuccess(); + } + + if (_walkStatus.Error is not null) + { + return new WalkNotFinishedError(_walkStatus.CurrentX, _walkStatus.CurrentY, (WalkCancelReason)_walkStatus.Error); + } + + if ((DateTimeOffset.Now - _walkStatus.LastWalkTime).TotalMilliseconds > _options.NotWalkingTooLongTrigger) + { + return new WalkNotFinishedError(_walkStatus.CurrentX, _walkStatus.CurrentY, WalkCancelReason.NotWalkingTooLong); + } + } + + return new WalkNotFinishedError(_walkStatus.CurrentX, _walkStatus.CurrentY, WalkCancelReason.Unknown); } } \ No newline at end of file