using System.Diagnostics; using System.Collections; using System.Collections.Generic; using System; using Godot; namespace Rokojori { public class ActionSequenceRunner { public ActionSequence sequence; public List actions; public List sequencables; public int sequencablesIndex = 0; bool cancelled = false; bool cancelledSequence = false; int _runID = -1; RJSequenceAction _runningAction; int _runningActionID = -1; public void Cancel() { if ( cancelled || _runningAction == null ) { return; } cancelled = true; _runningAction.CancelAction( _runningActionID ); } void CancelRun() { if ( cancelledSequence ) { return; } if ( ! cancelled ) { cancelled = true; } cancelledSequence = true; sequence.DispatchCancelled( _runID ); sequence.ClearRun( this ); } public void ProcessNext() { RJLog.Log( "@" + sequence.Name, "Index:", sequencablesIndex ); if ( sequencablesIndex == 0 ) { _runID = sequence.DispatchStart(); if ( sequencables.Count == 0 ) { actions.ForEach( a => Actions.Trigger( a ) ); sequence.DispatchEnd( _runID ); sequence.ClearRun( this ); return; } } if ( sequencablesIndex >= sequencables.Count ) { TriggerAllAfter( sequencables[ sequencables.Count -1 ] ); sequence.DispatchEnd( _runID ); sequence.ClearRun( this ); return; } if ( cancelled ) { CancelRun(); return; } var sequenceAction = sequencables[ sequencablesIndex ]; StartAction( sequenceAction ); } Dictionary callbacks = new Dictionary(); void StartAction( RJSequenceAction action ) { var capturedAction = action; RJSequenceAction.OnSequenceDoneEventHandler callback = ( long id, bool success ) => { //RJLog.Log( "On Done", id, success ); if ( id != _runningActionID ) { // RJLog.Error( "Invalid ID", id, "!=", _runningActionID ); return; } _runningActionID = -1; if ( success ) { sequencablesIndex ++; ProcessNext(); } else { sequence.DispatchCancelled( _runID ); sequence.ClearRun( this ); } var callbackReference = callbacks[ capturedAction ]; capturedAction.OnSequenceDone -= callbackReference; callbacks.Remove( capturedAction ); }; RunNext( action, callback ); /* _runningAction = action; callbacks[ _runningAction ] = callback; _runningAction.OnSequenceDone += callback; TriggerAllBefore( _runningAction ); Actions.Trigger( _runningAction ); _runningActionID = _runningAction.GetLastSequenceActionID(); */ } void RunNext( RJSequenceAction action, RJSequenceAction.OnSequenceDoneEventHandler callback ) { _runningAction = action; callbacks[ _runningAction ] = callback; _runningAction.OnSequenceDone += callback; TriggerAllBefore( _runningAction ); Actions.Trigger( _runningAction ); _runningActionID = _runningAction.GetLastSequenceActionID(); } void TriggerAllBefore( RJSequenceAction action ) { var actionIndex = actions.IndexOf( action ); for ( int i = actionIndex - 1; i >= 0; i -- ) { if ( typeof( RJSequenceAction ).IsAssignableFrom( actions[ i ].GetType() ) ) { return; } RJLog.Log( "Triggering Action", actions[ i ].Name ); Actions.Trigger( actions[ i ] ); } } void TriggerAllAfter( RJSequenceAction action ) { var actionIndex = actions.IndexOf( action ); for ( int i = actionIndex + 1; i < actions.Count; i ++ ) { if ( typeof( RJSequenceAction ).IsAssignableFrom( actions[ i ].GetType() ) ) { return; } RJLog.Log( "Triggering Action", actions[ i ].Name ); Actions.Trigger( actions[ i ] ); } } } [GlobalClass, Icon("res://addons/rokojori_action_library/Icons/RJActionSequence.svg") ] public partial class ActionSequence:RJSequenceAction { /** Actions to execute*/ [Export] public RJAction[] actions; [Export] public bool triggerDirectChildren = true; List running = new List(); public override void _OnTrigger() { var run = new ActionSequenceRunner(); run.sequence = this; run.actions = new List( actions ); if ( triggerDirectChildren ) { Nodes.ForEachDirectChild( this, a => run.actions.Add( a ) ); } run.sequencables = Lists.FilterType( run.actions ); // RJLog.Log( "Running", HierarchyName.Of( this ), run.sequencables.Count ); running.Add( run ); run.ProcessNext(); } public override void CancelAction( int id ) { running.ForEach( r => r.Cancel() ); } public void ClearRun( ActionSequenceRunner run ) { running.Remove( run ); } } }