Files
TheVVaS-Assets/RPGCore/Runtime/ObjectModules/ActionObjectModule/ActionModule.cs
T
2026-04-25 23:37:10 +02:00

142 lines
5.1 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using RPGCore.Core;
using RPGCore.Core.Objects;
using RPGCore.ObjectModules.ActionObjectModule.Events;
using RPGCore.ObjectModules.EventObjectModule;
using RPGCoreCommon.Helpers;
using UnityEngine;
namespace RPGCore.ObjectModules.ActionObjectModule
{
[Serializable]
public class ActionModule : ObjectModule<UnitObject>
{
private List<BaseActionParallel> _actionParallels = new();
private readonly List<BaseAction> _actionQueue = new();
private BaseAction _actionCurrent;
public List<BaseActionParallel> actionParallels => _actionParallels.ToList();
public List<BaseAction> actionQueue => _actionQueue.ToList();
public BaseAction actionCurrent => _actionCurrent;
private void FixedUpdate()
{
if (_actionCurrent?.state is not ActionState.Running) NextAction();
}
/// <summary>
/// 1. Checks if the action can be executed outside the queue.<br/>
/// 2. If allowed, executes the action and handles potential errors.
/// </summary>
public void Execute(BaseActionParallel action)
{
try
{
var actionExecuteEvent = new ActionExecuteEvent { action = action };
parent.events.InvokeBefore(actionExecuteEvent);
if (actionExecuteEvent.isPrevented) throw new ActionErrorException(action, "Action is prevented");
parent.events.InvokeAfter(actionExecuteEvent);
_actionParallels.Add(action);
action.unit = parent;
action.OnEnd += () => _actionParallels.Remove(action);
action.OnCancel += () => _actionParallels.Remove(action);
action.DoIt();
}
catch (ActionErrorException e)
{
parent.events.Invoke(new ActionErrorEvent
{
unit = parent,
action = e.action,
message = e.Message
});
}
}
public void Stop()
{
_actionParallels
.Where(action => action.CanBeStopped())
.ForEach(action => action.CancelIt())
.ForEach(action => _actionParallels.Remove(action));
}
/// <summary>
/// 1. Adds given action to queue
/// 2. Starts it if queue is empty
/// </summary>
public void AddToQueue(BaseAction action) => AddToQueue(new List<BaseAction> { 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 AddToQueue(List<BaseAction> actions)
{
actions.ForEach(action => action.unit = parent);
actions.ForEach((index, action) =>
{
if (index != 0) action.runAfterAction = actions[index - 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
{
var actionExecuteEvent = new ActionExecuteEvent { action = _actionCurrent };
parent.events.InvokeBefore(actionExecuteEvent);
if (actionExecuteEvent.isPrevented) throw new ActionErrorException(_actionCurrent, "Action is prevented");
parent.events.InvokeAfter(actionExecuteEvent);
_actionCurrent.DoIt();
}
catch (ActionErrorException e)
{
parent.events.Invoke(new ActionErrorEvent
{
unit = parent,
action = e.action,
message = e.Message
});
}
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();
}
}
}