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 } }