~ruther/NosSmooth

ref: 2043a7d79fee86f80765ba9a785c09ef5aefa62c NosSmooth/Extensions/NosSmooth.Extensions.Combat/Operations/CompoundOperation.cs -rw-r--r-- 3.8 KiB
2043a7d7 — František Boháček docs: add missing documentation 2 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//
//  CompoundOperation.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 System.Diagnostics;
using Remora.Results;

namespace NosSmooth.Extensions.Combat.Operations;

/// <summary>
/// An operation made from multiple operations
/// that should execute right after each other.
/// </summary>
public class CompoundOperation : ICombatOperation
{
    private readonly ICombatOperation[] _operations;
    private readonly OperationQueueType _queueType;
    private Task<Result>? _compoundOperation;

    /// <summary>
    /// Initializes a new instance of the <see cref="CompoundOperation"/> class.
    /// </summary>
    /// <param name="operations">The operations to execute.</param>
    /// <param name="queueType">The queue type.</param>
    public CompoundOperation
        (OperationQueueType queueType = OperationQueueType.TotalControl, params ICombatOperation[] operations)
    {
        if (operations.Length == 0)
        {
            throw new ArgumentNullException(nameof(operations), "The compound operation needs at least one operation.");
        }

        _operations = operations;
        _queueType = queueType;
    }

    /// <inheritdoc />
    public void Dispose()
    {
        foreach (var operation in _operations)
        {
            operation.Dispose();
        }
    }

    /// <inheritdoc />
    public OperationQueueType QueueType { get; }

    /// <inheritdoc />
    public Task<Result> BeginExecution(ICombatState combatState, CancellationToken ct = default)
    {
        if (_compoundOperation is not null)
        {
            return Task.FromResult(Result.FromSuccess());
        }

        _compoundOperation = Task.Run
        (
            () => UseAsync(combatState, ct),
            ct
        );
        return Task.FromResult(Result.FromSuccess());
    }

    /// <inheritdoc />
    public async Task<Result> WaitForFinishedAsync(ICombatState combatState, CancellationToken ct = default)
    {
        if (IsFinished())
        {
            return Result.FromSuccess();
        }

        await BeginExecution(combatState, ct);
        if (_compoundOperation is null)
        {
            throw new UnreachableException();
        }

        return await _compoundOperation;
    }

    /// <inheritdoc />
    public bool IsExecuting()
        => _compoundOperation is not null && !IsFinished();

    /// <inheritdoc />
    public bool IsFinished()
        => _compoundOperation?.IsCompleted ?? false;

    /// <inheritdoc />
    public Result<CanBeUsedResponse> CanBeUsed(ICombatState combatState)
        => _operations[0].CanBeUsed(combatState);

    private async Task<Result> UseAsync(ICombatState combatState, CancellationToken ct)
    {
        foreach (var operation in _operations)
        {
            CanBeUsedResponse canBeUsed = CanBeUsedResponse.MustWait;

            while (canBeUsed != CanBeUsedResponse.CanBeUsed)
            {
                var canBeUsedResult = operation.CanBeUsed(combatState);
                if (!canBeUsedResult.IsDefined(out canBeUsed))
                {
                    return Result.FromError(canBeUsedResult);
                }

                if (canBeUsed == CanBeUsedResponse.WontBeUsable)
                {
                    return new GenericError("Won't be usable.");
                }

                await Task.Delay(10, ct);
            }

            var result = await operation.BeginExecution(combatState, ct);
            if (!result.IsSuccess)
            {
                return result;
            }

            result = await operation.WaitForFinishedAsync(combatState, ct);
            if (!result.IsSuccess)
            {
                return result;
            }
        }

        return Result.FromSuccess();
    }
}
Do not follow this link