Newer
Older
Hierarchical-Task-Network-Unity-3D / Assets / Scripts / HTN / CompoundTask.cs
using System;
using System.Collections.Generic;
using UnityEngine;

public class CompoundTask : ITask
{
    // ================== Enum Status =========================
    public enum DecomposeStatus
    {
        None,
        Failed,
        Successful
    }

    // ================== Variables =========================

    private DecomposeStatus decomposeStatus = DecomposeStatus.None;

    // ================== Properties =========================
    public string Name { get; private set; }
    public bool IsCompound => true;
    public List<Method> Methods { get; } = new();
    public DecomposeStatus Status => decomposeStatus;

    // ================== DECOMPOSITION =========================
    /// <summary>
    /// Decomposes the CompoundTask into a list of subtasks by checking which Method's preconditions are met.
    /// </summary>
    /// <param name="planner">The HTNPlanner used to evaluate the preconditions of each Method.</param>
    /// <returns>
    /// A list of ITask subtasks from the first valid Method, 
    /// or null if no Method's preconditions are satisfied.
    /// </returns>
    public List<ITask> Decompose(HTNPlanner planner)
    {
        foreach (Method method in Methods)
        {
            if (method.ArePreconditionsMet(planner))
            {
                decomposeStatus = DecomposeStatus.Successful;
                Debug.Log($"Added: {method.SubTasks.Count} tasks");
                return method.SubTasks;
            }
        }

        decomposeStatus = DecomposeStatus.Failed;
        return new List<ITask>();
    }

    // ================== ADDING =========================
    private void AddMethodInternal(Method method) => Methods.Add(method); //Adds a Method to the CompoundTask

    /// <summary>
    /// Adds a Method to the CompoundTask
    /// </summary>
    /// <param name="method">The Method object to add to the CompoundTask's Methods list.</param>
    /// <returns>The current CompoundTask instance (for method chaining).</returns>
    public CompoundTask AddMethod(Method method)
    {
        if (method == null) throw new ArgumentNullException(nameof(method));
        AddMethodInternal(method);
        return this;
    }

    /// <summary>
    /// Adds a List of Methods to the CompoundTask
    /// </summary>
    /// <param name="methods">The Method object List to add to the CompoundTask's Methods list.</param>
    /// <returns>The current CompoundTask instance (for method chaining).</returns>
    public CompoundTask AddMethod(List<Method> methods)
    {
        if (methods == null) throw new ArgumentNullException(nameof(methods));

        foreach (Method method in methods)
        {
            AddMethodInternal(method);
        }
        return this;
    }

    /// <summary>
    /// Finalizes the setup of the CompoundTask by assigning it a name.
    /// This method is intended to be the last call in a method-chaining setup,
    /// and the name is used for debugging, identification, and logging purposes.
    /// </summary>
    /// <param name="name">The name to assign to the CompoundTask.</param>
    /// <returns>The current CompoundTask instance (for method chaining).</returns>
    public CompoundTask Build(string name)
    {
        Name = name;
        return this;
    }
}