step-timeline/Scripts/Commands/StepCmd.cs

140 lines
5.4 KiB
C#

using UnityEngine;
using System;
using System.Collections.Generic;
using TriInspector;
namespace R0bbie.Timeline
{
/// <summary>
/// Abstract class inherited by all StepCmd types
/// </summary>
public abstract class StepCmd : MonoBehaviour
{
[ShowIf("Inspector_ImplementsPausable")]
[SerializeField] protected bool dontRepeatOnPauseResume;
public event Action onCompleteCommand;
protected Step parentStep;
public bool init { get; protected set; }
public bool active { get; protected set; }
public bool completed { get; private set; }
protected abstract void Init();
/// <summary>
/// Base Activate function, called by inheriting command before its own custom activation command
/// </summary>
/// <param name="_parentStep">The step this command is attached to</param>
public virtual void Activate(Step _parentStep)
{
parentStep = _parentStep;
if (!init)
Init();
active = true;
// If this is a pausable command, add it to activePausableCommands list
if (this is IPausable)
{
if (parentStep.attachedStepTimeline)
parentStep.attachedStepTimeline.AddActivePausableCommand(this);
else if (parentStep.attachedController)
parentStep.attachedController.AddActivePausableCommand(this);
}
}
/// <summary>
/// Called by any commands which have a limited number of components on a particular step, to see if max has been reached
/// </summary>
/// <param name="_currentActivatingStep">The Step we want to check for max commands (the one currently being activated)</param>
/// <param name="_maxCommandsOfTypeOnStep">How many the max no. of commands of that type on this step there should be</param>
/// <param name="_activeCommandsOfTypeOnStep">All instances of this command type on the step</param>
/// <returns></returns>
protected virtual bool CheckMaxCommandsOnStep(Step _currentActivatingStep, int _maxCommandsOfTypeOnStep, List<StepCmd> _activeCommandsOfTypeOnStep)
{
// Check if too many commands of this type have already been activated on this step?
if (_currentActivatingStep != null && _currentActivatingStep == parentStep)
{
// If so, return a warning, and return without ever activating this command
if (_activeCommandsOfTypeOnStep.Count >= _maxCommandsOfTypeOnStep)
{
Debug.LogWarning("Tried to activate a command when the maximum of " + _maxCommandsOfTypeOnStep.ToString() + " of this command type per step have already been activated. Make sure there are only " + _maxCommandsOfTypeOnStep.ToString() + " of this type of command type on each Step.");
return false;
}
}
else
{
// First command of this type activated on this step. Clear our list from previous step (if there was one)
_currentActivatingStep = null;
_activeCommandsOfTypeOnStep.Clear();
}
// Otherwise, we're fine, keep a log of the step this command was activated on, then proceed to activate it
_currentActivatingStep = parentStep;
_activeCommandsOfTypeOnStep.Add(this);
return true;
}
/// <summary>
/// Called by the command once whatever it does has been completed, and the command is to deactivate. Performs generic completion stuff, then calls back into the command itself to Cleanup
/// </summary>
protected virtual void Complete()
{
completed = true;
active = false;
Cleanup();
// If this is a pausable command, ensure it's removed from activePausableCommands list
if (this is IPausable)
{
if (parentStep.attachedStepTimeline)
parentStep.attachedStepTimeline.RemoveActivePausableCommand(this);
else if (parentStep.attachedController)
parentStep.attachedController.RemoveActivePausableCommand(this);
}
onCompleteCommand?.Invoke();
}
/// <summary>
/// Called by an external component (such as DeactivateCommandsCmd) to deactivate a command before it's actually completing - i.e. stop whatever it's doing then clean it up
/// </summary>
public void DeactivateEarly()
{
// TODO: Look at actually deactivating whatever the command behaviour is, rather than just setting in inactive and tidying up?
active = false;
Cleanup();
}
/// <summary>
/// Implemented be command to tidy up any specific stuff in that command that needs tidied up when the command has been deactivated
/// </summary>
protected abstract void Cleanup();
#if UNITY_EDITOR
#region Editor Inspector functions
bool Inspector_ImplementsPausable()
{
return (this is IPausable);
}
#endregion
#endif
}
}