using UnityEngine;
using System;
using System.Collections.Generic;
using TriInspector;
namespace R0bbie.Timeline
{
///
/// Abstract class inherited by all StepCmd types
///
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();
///
/// Base Activate function, called by inheriting command before its own custom activation command
///
/// The step this command is attached to
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);
}
}
///
/// Called by any commands which have a limited number of components on a particular step, to see if max has been reached
///
/// The Step we want to check for max commands (the one currently being activated)
/// How many the max no. of commands of that type on this step there should be
/// All instances of this command type on the step
///
protected virtual bool CheckMaxCommandsOnStep(Step _currentActivatingStep, int _maxCommandsOfTypeOnStep, List _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;
}
///
/// 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
///
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();
}
///
/// 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
///
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();
}
///
/// Implemented be command to tidy up any specific stuff in that command that needs tidied up when the command has been deactivated
///
protected abstract void Cleanup();
#if UNITY_EDITOR
#region Editor Inspector functions
bool Inspector_ImplementsPausable()
{
return (this is IPausable);
}
#endregion
#endif
}
}