rj-action-library/Runtime/Actions/ActionSequence.cs

237 lines
5.5 KiB
C#

using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
using System;
using Godot;
namespace Rokojori
{
public class ActionSequenceRunner
{
public ActionSequence sequence;
public List<RJAction> actions;
public List<RJSequenceAction> 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<RJSequenceAction,RJSequenceAction.OnSequenceDoneEventHandler> callbacks =
new Dictionary<RJSequenceAction, RJSequenceAction.OnSequenceDoneEventHandler>();
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
{
/** <summary for="field actions">Actions to execute</summary>*/
[Export]
public RJAction[] actions;
[Export]
public bool triggerDirectChildren = true;
List<ActionSequenceRunner> running = new List<ActionSequenceRunner>();
public override void _OnTrigger()
{
var run = new ActionSequenceRunner();
run.sequence = this;
run.actions = new List<RJAction>( actions );
if ( triggerDirectChildren )
{
Nodes.ForEachDirectChild<RJAction>( this, a => run.actions.Add( a ) );
}
run.sequencables = Lists.FilterType<RJAction,RJSequenceAction>( 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 );
}
}
}