145 lines
4.8 KiB
C#
145 lines
4.8 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Sirenix.OdinInspector;
|
|
using Sirenix.Utilities;
|
|
using UnityEngine;
|
|
using VOID.Generic.Objects.Unit.Actions;
|
|
using VOID.Generic.Objects.Unit.Actions.Exceptions;
|
|
using VOID.Generic.Objects.Unit.Events;
|
|
|
|
namespace VOID.Generic.Objects.Unit
|
|
{
|
|
[Serializable]
|
|
public class UnitObjectActionQueue : ObjectComponent<UnitObject>
|
|
{
|
|
#region Initialize
|
|
|
|
protected override void SelfInitialize()
|
|
{
|
|
parent.basicEvents.onFixedUpdate.AddListener(CheckRunningAction);
|
|
}
|
|
|
|
#endregion
|
|
|
|
// Getters
|
|
public List<AbstractAction> actionQueue => _actionQueue;
|
|
public AbstractAction actionCurrent => _actionCurrent;
|
|
|
|
[ShowInInspector, ReadOnly] private readonly List<AbstractAction> _actionQueue = new();
|
|
[ShowInInspector, ReadOnly] private AbstractAction _actionCurrent;
|
|
|
|
/// <summary>
|
|
/// 1. Checks if the action can be executed outside the queue.
|
|
/// 2. If allowed, executes the action and handles potential errors.
|
|
/// </summary>
|
|
public void ExecuteInstantly(AbstractAction action)
|
|
{
|
|
if (!action.CanSkipQueue())
|
|
{
|
|
Debug.LogError($"Action: {action.GetType().Name} cannot be executed via {nameof(ExecuteInstantly)}");
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
action.DoIt();
|
|
}
|
|
catch (UnitActionErrorException e)
|
|
{
|
|
parent.unitEvents.onActionError.Invoke(new ActionErrorEvent
|
|
{
|
|
unit = parent,
|
|
action = e.action,
|
|
cause = e.unitActionErrorType
|
|
});
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 1. Adds given action to queue
|
|
/// 2. Starts it if queue is empty
|
|
/// </summary>
|
|
public void AddAction(AbstractAction action) => AddActionChain(new List<AbstractAction> { action });
|
|
|
|
/// <summary>
|
|
/// 1. Adds given actions to queue
|
|
/// 2. Runs only when previous action is finished successfully
|
|
/// 3. Starts it if queue is empty
|
|
/// </summary>
|
|
public void AddActionChain(List<AbstractAction> actions)
|
|
{
|
|
// Unit is currently not controllable (stunned? doing something unstoppable? magically frozen by dev?)
|
|
if (!parent.unitState.isControllable)
|
|
{
|
|
parent.unitEvents.onActionError.Invoke(new ActionErrorEvent
|
|
{
|
|
unit = parent,
|
|
action = actions.First(),
|
|
cause = UnitActionErrorType.UnitStateIsNotControllable
|
|
});
|
|
return;
|
|
}
|
|
|
|
actions.ForEach((action, actionIndex) =>
|
|
{
|
|
if (actionIndex != 0) action.runAfterAction = actions[actionIndex - 1];
|
|
_actionQueue.Add(action);
|
|
});
|
|
|
|
if (_actionCurrent == null) NextAction();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 1. Clear whole action queue
|
|
/// 2. Cancel current action IF specified by argument
|
|
/// 3. Some actions cant be stopped once fired by normal means, BUT we can force stopping it
|
|
/// </summary>
|
|
public void StopQueue(bool stopCurrent = true, bool stopForced = false)
|
|
{
|
|
_actionQueue.Clear();
|
|
|
|
if (!stopCurrent) return;
|
|
if (!stopForced && _actionCurrent != null && !_actionCurrent.CanBeStopped()) return;
|
|
|
|
_actionCurrent?.CancelIt();
|
|
_actionCurrent = null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 1. Gets next action to do
|
|
/// 2. If there is no more actions - do nothing
|
|
/// 3. Proceed to execute it
|
|
/// </summary>
|
|
private void NextAction()
|
|
{
|
|
_actionCurrent = _actionQueue.FirstOrDefault();
|
|
_actionQueue.Remove(_actionCurrent);
|
|
|
|
if (_actionCurrent == null) return;
|
|
|
|
try
|
|
{
|
|
_actionCurrent.DoIt();
|
|
}
|
|
catch (UnitActionErrorException e)
|
|
{
|
|
parent.unitEvents.onActionError.Invoke(new ActionErrorEvent
|
|
{
|
|
unit = parent,
|
|
action = e.action,
|
|
cause = e.unitActionErrorType
|
|
});
|
|
}
|
|
|
|
if (_actionCurrent.state is ActionState.Ready) Debug.LogWarning($"Action {_actionCurrent.GetType().Name} is still ready after starting. Skipping.");
|
|
if (_actionCurrent.state is not ActionState.Running) NextAction();
|
|
}
|
|
|
|
private void CheckRunningAction()
|
|
{
|
|
if (_actionCurrent?.state is ActionState.Running) return;
|
|
NextAction();
|
|
}
|
|
}
|
|
} |