~ruther/NosSmooth

0e0daae17288897ef778a75485048589d8e1e872 — Rutherther 3 years ago ca065c0
fix(combat): make skill cancellation tokens actions async
M Extensions/NosSmooth.Extensions.Combat/CombatManager.cs => Extensions/NosSmooth.Extensions.Combat/CombatManager.cs +53 -22
@@ 20,7 20,7 @@ namespace NosSmooth.Extensions.Combat;
public class CombatManager : IStatefulEntity
{
    private readonly List<CancellationTokenSource> _tokenSource;
    private readonly Semaphore _semaphore;
    private readonly SemaphoreSlim _semaphore;
    private readonly INostaleClient _client;
    private readonly Game.Game _game;



@@ 31,7 31,7 @@ public class CombatManager : IStatefulEntity
    /// <param name="game">The game.</param>
    public CombatManager(INostaleClient client, Game.Game game)
    {
        _semaphore = new Semaphore(1, 1);
        _semaphore = new SemaphoreSlim(1, 1);
        _tokenSource = new List<CancellationTokenSource>();
        _client = client;
        _game = game;


@@ 136,43 136,74 @@ public class CombatManager : IStatefulEntity
    /// Register the given cancellation token source to be cancelled on skill use/cancel.
    /// </summary>
    /// <param name="tokenSource">The token source to register.</param>
    public void RegisterSkillCancellationToken(CancellationTokenSource tokenSource)
    /// <param name="ct">The cancellation token for cancelling the operation.</param>
    /// <returns>A task.</returns>
    public async Task RegisterSkillCancellationTokenAsync(CancellationTokenSource tokenSource, CancellationToken ct)
    {
        _semaphore.WaitOne();
        _tokenSource.Add(tokenSource);
        _semaphore.Release();
        await _semaphore.WaitAsync(ct);
        try
        {
            _tokenSource.Add(tokenSource);
        }
        finally
        {
            _semaphore.Release();
        }
    }

    /// <summary>
    /// Unregister the given cancellation token registered using <see cref="RegisterSkillCancellationToken"/>.
    /// </summary>
    /// <param name="tokenSource">The token source to unregister.</param>
    public void UnregisterSkillCancellationToken(CancellationTokenSource tokenSource)
    /// <param name="ct">The cancellation token for cancelling the operation.</param>
    /// <returns>A task.</returns>
    public async Task UnregisterSkillCancellationTokenAsync(CancellationTokenSource tokenSource, CancellationToken ct)
    {
        _semaphore.WaitOne();
        _tokenSource.Remove(tokenSource);
        _semaphore.Release();
        if (_cancelling)
        {
            return;
        }

        await _semaphore.WaitAsync(ct);
        try
        {
            _tokenSource.Remove(tokenSource);
        }
        finally
        {
            _semaphore.Release();
        }
    }

    /// <summary>
    /// Cancel all of the skill tokens.
    /// </summary>
    internal void CancelSkillTokens()
    /// <param name="ct">The cancellation token for cancelling the operation.</param>
    /// <returns>A task.</returns>
    internal async Task CancelSkillTokensAsync(CancellationToken ct)
    {
        _semaphore.WaitOne();
        foreach (var tokenSource in _tokenSource)
        await _semaphore.WaitAsync(ct);
        _cancelling = true;
        try
        {
            try
            {
                tokenSource.Cancel();
            }
            catch
            foreach (var tokenSource in _tokenSource)
            {
                // ignored
                try
                {
                    tokenSource.Cancel();
                }
                catch
                {
                    // ignored
                }
            }
        }

        _tokenSource.Clear();
        _semaphore.Release();
            _tokenSource.Clear();
        }
        finally
        {
            _cancelling = false;
            _semaphore.Release();
        }
    }
}
\ No newline at end of file

M Extensions/NosSmooth.Extensions.Combat/Operations/UseSkillOperation.cs => Extensions/NosSmooth.Extensions.Combat/Operations/UseSkillOperation.cs +12 -4
@@ 49,6 49,8 @@ public record UseSkillOperation(Skill Skill, ILivingEntity Target) : ICombatOper
        }

        // TODO: support for area skills, support skills that use x, y coordinates (like dashes or teleports)
        var linkedSource = CancellationTokenSource.CreateLinkedTokenSource(ct);
        await combatState.CombatManager.RegisterSkillCancellationTokenAsync(linkedSource, ct);
        var sendResponse = await combatState.Client.SendPacketAsync
        (
            new UseSkillPacket


@@ 64,13 66,19 @@ public record UseSkillOperation(Skill Skill, ILivingEntity Target) : ICombatOper

        if (!sendResponse.IsSuccess)
        {
            await combatState.CombatManager.UnregisterSkillCancellationTokenAsync(linkedSource, ct);
            return sendResponse;
        }

        var linkedSource = CancellationTokenSource.CreateLinkedTokenSource(ct);
        combatState.CombatManager.RegisterSkillCancellationToken(linkedSource);
        await Task.Delay(Skill.Info.CastTime * 200 * 5, linkedSource.Token);
        combatState.CombatManager.UnregisterSkillCancellationToken(linkedSource);
        try
        {
            await Task.Delay(Skill.Info.CastTime * 200 * 5, linkedSource.Token);
        }
        catch (TaskCanceledException)
        {
            // ignored
        }
        await combatState.CombatManager.UnregisterSkillCancellationTokenAsync(linkedSource, ct);

        return Result.FromSuccess();
    }

M Extensions/NosSmooth.Extensions.Combat/Responders/CancelResponder.cs => Extensions/NosSmooth.Extensions.Combat/Responders/CancelResponder.cs +1 -1
@@ 29,7 29,7 @@ public class CancelResponder : IPacketResponder<CancelPacket>
    /// <inheritdoc />
    public Task<Result> Respond(PacketEventArgs<CancelPacket> packetArgs, CancellationToken ct = default)
    {
        _combatManager.CancelSkillTokens();
        _combatManager.CancelSkillTokensAsync(ct);
        return Task.FromResult(Result.FromSuccess());
    }
}
\ No newline at end of file

M Extensions/NosSmooth.Extensions.Combat/Responders/SuResponder.cs => Extensions/NosSmooth.Extensions.Combat/Responders/SuResponder.cs +1 -1
@@ 29,7 29,7 @@ public class SuResponder : IPacketResponder<SuPacket>
    /// <inheritdoc />
    public Task<Result> Respond(PacketEventArgs<SuPacket> packetArgs, CancellationToken ct = default)
    {
        _combatManager.CancelSkillTokens();
        _combatManager.CancelSkillTokensAsync(ct);
        return Task.FromResult(Result.FromSuccess());
    }
}
\ No newline at end of file

Do not follow this link