diff --git a/Assets/Fungus/Flowchart/Editor/CallEditor.cs b/Assets/Fungus/Flowchart/Editor/CallEditor.cs index 0ea0bcae..8c04ec9f 100644 --- a/Assets/Fungus/Flowchart/Editor/CallEditor.cs +++ b/Assets/Fungus/Flowchart/Editor/CallEditor.cs @@ -9,10 +9,12 @@ namespace Fungus public class CallEditor : CommandEditor { protected SerializedProperty targetBlockProp; + protected SerializedProperty stopParentBlockProp; protected virtual void OnEnable() { targetBlockProp = serializedObject.FindProperty("targetBlock"); + stopParentBlockProp = serializedObject.FindProperty("stopParentBlock"); } public override void DrawCommandGUI() @@ -32,6 +34,8 @@ namespace Fungus new GUIContent(""), flowchart); + EditorGUILayout.PropertyField(stopParentBlockProp); + serializedObject.ApplyModifiedProperties(); } } diff --git a/Assets/Fungus/Flowchart/Editor/CommandListAdaptor.cs b/Assets/Fungus/Flowchart/Editor/CommandListAdaptor.cs index 4c07dbc3..dad9a176 100644 --- a/Assets/Fungus/Flowchart/Editor/CommandListAdaptor.cs +++ b/Assets/Fungus/Flowchart/Editor/CommandListAdaptor.cs @@ -362,7 +362,7 @@ namespace Fungus GUI.Label(commandLabelRect, commandName, commandLabelStyle); } - if (command.IsExecuting()) + if (command.isExecuting) { Rect iconRect = new Rect(commandLabelRect); iconRect.x += iconRect.width - commandLabelRect.width - 20; diff --git a/Assets/Fungus/Flowchart/Editor/FlowchartWindow.cs b/Assets/Fungus/Flowchart/Editor/FlowchartWindow.cs index e3dfab7e..1fd8da29 100755 --- a/Assets/Fungus/Flowchart/Editor/FlowchartWindow.cs +++ b/Assets/Fungus/Flowchart/Editor/FlowchartWindow.cs @@ -581,7 +581,7 @@ namespace Fungus } } - bool highlight = command.IsExecuting() || (blockIsSelected && commandIsSelected); + bool highlight = command.isExecuting || (blockIsSelected && commandIsSelected); if (highlightedOnly && !highlight || !highlightedOnly && highlight) diff --git a/Assets/Fungus/Flowchart/Scripts/Block.cs b/Assets/Fungus/Flowchart/Scripts/Block.cs index 0c3d316e..bf25311d 100644 --- a/Assets/Fungus/Flowchart/Scripts/Block.cs +++ b/Assets/Fungus/Flowchart/Scripts/Block.cs @@ -21,6 +21,15 @@ namespace Fungus [AddComponentMenu("")] public class Block : Node { + public enum ExecutionState + { + Idle, + Executing, + } + + [NonSerialized] + public ExecutionState executionState; + [HideInInspector] public int itemId = -1; // Invalid flowchart item id @@ -55,6 +64,12 @@ namespace Fungus protected int executionCount; + /** + * Controls the next command to execute in the block execution coroutine. + */ + [NonSerialized] + public int jumpToCommandIndex = -1; + protected virtual void Awake() { // Give each child command a reference back to its parent block @@ -117,13 +132,7 @@ namespace Fungus public virtual bool IsExecuting() { - Flowchart flowchart = GetFlowchart(); - if (flowchart == null) - { - return false; - } - - return (activeCommand != null); + return (executionState == ExecutionState.Executing); } public virtual int GetExecutionCount() @@ -131,100 +140,101 @@ namespace Fungus return executionCount; } - public virtual void ExecuteCommand(int commandIndex) + public virtual bool Execute() { - if (activeCommand == null) - { - previousActiveCommandIndex = -1; - } - else + if (executionState != ExecutionState.Idle) { - previousActiveCommandIndex = activeCommand.commandIndex; + return false; } - if (commandIndex >= commandList.Count) - { - Stop(); - return; - } + executionCount++; + StartCoroutine(ExecuteBlock()); - if (commandIndex == 0) - { - executionCount++; - } + return true; + } + protected virtual IEnumerator ExecuteBlock() + { Flowchart flowchart = GetFlowchart(); + executionState = ExecutionState.Executing; - // Skip disabled commands, comments and labels - while (commandIndex < commandList.Count && - (!commandList[commandIndex].enabled || - commandList[commandIndex].GetType() == typeof(Comment) || - commandList[commandIndex].GetType() == typeof(Label))) + int i = 0; + while (true) { - commandIndex = commandList[commandIndex].commandIndex + 1; - } + // Executing commands specify the next command to skip to by setting jumpToCommandIndex using Command.Continue() + if (jumpToCommandIndex > -1) + { + i = jumpToCommandIndex; + jumpToCommandIndex = -1; + } - if (commandIndex >= commandList.Count) - { - Stop(); - return; - } + // Skip disabled commands, comments and labels + while (i < commandList.Count && + (!commandList[i].enabled || + commandList[i].GetType() == typeof(Comment) || + commandList[i].GetType() == typeof(Label))) + { + i = commandList[i].commandIndex + 1; + } - Command nextCommand = commandList[commandIndex]; + if (i >= commandList.Count) + { + break; + } - activeCommand = null; - executingIconTimer = 0.5f; + // The previous active command is needed for if / else / else if commands + if (activeCommand == null) + { + previousActiveCommandIndex = -1; + } + else + { + previousActiveCommandIndex = activeCommand.commandIndex; + } + + Command command = commandList[i]; + activeCommand = command; + executingIconTimer = 0.5f; - if (nextCommand == null) - { - Stop(); - } - else - { if (flowchart.gameObject.activeInHierarchy) { // Auto select a command in some situations - if ((flowchart.selectedCommands.Count == 0 && commandIndex == 0) || + if ((flowchart.selectedCommands.Count == 0 && i == 0) || (flowchart.selectedCommands.Count == 1 && flowchart.selectedCommands[0].commandIndex == previousActiveCommandIndex)) { flowchart.ClearSelectedCommands(); - flowchart.AddSelectedCommand(nextCommand); - } - - if (runSlowInEditor && - nextCommand.RunSlowInEditor()) - { - StartCoroutine(ExecuteAfterDelay(nextCommand, flowchart.runSlowDuration)); - } - else - { - activeCommand = nextCommand; - nextCommand.Execute(); + flowchart.AddSelectedCommand(commandList[i]); } } - } - } + command.isExecuting = true; + command.Execute(); - IEnumerator ExecuteAfterDelay(Command nextCommand, float delay) - { - activeCommand = nextCommand; - yield return new WaitForSeconds(delay); - nextCommand.Execute(); - } + // Wait until the executing command sets another command to jump to via Command.Continue() + while (jumpToCommandIndex == -1) + { + yield return null; + } - public virtual void Stop() - { - Flowchart flowchart = GetFlowchart(); - if (flowchart == null) - { - return; + if (runSlowInEditor) + { + yield return new WaitForSeconds(flowchart.runSlowDuration); + } + + command.isExecuting = false; } + executionState = ExecutionState.Idle; activeCommand = null; flowchart.ClearSelectedCommands(); } + public virtual void Stop() + { + // This will cause the execution loop to break on the next iteration + jumpToCommandIndex = int.MaxValue; + } + public virtual List GetConnectedBlocks() { List connectedBlocks = new List(); diff --git a/Assets/Fungus/Flowchart/Scripts/Command.cs b/Assets/Fungus/Flowchart/Scripts/Command.cs index 13515e1a..c53680d4 100644 --- a/Assets/Fungus/Flowchart/Scripts/Command.cs +++ b/Assets/Fungus/Flowchart/Scripts/Command.cs @@ -45,6 +45,12 @@ namespace Fungus [NonSerialized] public int commandIndex; + /** + * Set to true by the parent block while the command is executing. + */ + [NonSerialized] + public bool isExecuting; + /** * Reference to the Block object that this command belongs to. * This reference is only populated at runtime and in the editor when the @@ -64,16 +70,6 @@ namespace Fungus return flowchart; } - public virtual bool IsExecuting() - { - if (parentBlock == null) - { - return false; - } - - return (parentBlock.activeCommand == this); - } - public virtual void Execute() { OnEnter(); @@ -89,7 +85,7 @@ namespace Fungus OnExit(); if (parentBlock != null) { - parentBlock.ExecuteCommand(nextCommandIndex); + parentBlock.jumpToCommandIndex = nextCommandIndex; } } @@ -102,28 +98,30 @@ namespace Fungus } } - public virtual void ExecuteBlock(Block s) + public virtual void ExecuteBlock(Block s, bool stopParentBlock) { OnExit(); if (parentBlock != null) { Flowchart flowchart = parentBlock.GetFlowchart(); + if (flowchart == null) + { + return; + } - // Record the currently selected block because Stop() will clear it. - Block selectedBlock = flowchart.selectedBlock; - - parentBlock.Stop(); - if (flowchart != null) + if (stopParentBlock) { + parentBlock.Stop(); + // If the executing block is currently selected then follow the execution // onto the next block in the inspector. - if (selectedBlock == parentBlock) + if (flowchart.selectedBlock == parentBlock) { flowchart.selectedBlock = s; } - - flowchart.ExecuteBlock(s); } + + flowchart.ExecuteBlock(s); } } diff --git a/Assets/Fungus/Flowchart/Scripts/Commands/Call.cs b/Assets/Fungus/Flowchart/Scripts/Commands/Call.cs index 12f65675..34bc63a3 100644 --- a/Assets/Fungus/Flowchart/Scripts/Commands/Call.cs +++ b/Assets/Fungus/Flowchart/Scripts/Commands/Call.cs @@ -13,14 +13,21 @@ namespace Fungus public class Call : Command { [FormerlySerializedAs("targetSequence")] - [Tooltip("Block to execute")] + [Tooltip("Block to start executing")] public Block targetBlock; + [Tooltip("Stop executing the parent block that contains this command")] + public bool stopParentBlock = true; + public override void OnEnter() { if (targetBlock != null) { - ExecuteBlock(targetBlock); + ExecuteBlock(targetBlock, stopParentBlock); + if (!stopParentBlock) + { + Continue(); + } } else { diff --git a/Assets/Fungus/Flowchart/Scripts/Flowchart.cs b/Assets/Fungus/Flowchart/Scripts/Flowchart.cs index f76aa841..199c2928 100644 --- a/Assets/Fungus/Flowchart/Scripts/Flowchart.cs +++ b/Assets/Fungus/Flowchart/Scripts/Flowchart.cs @@ -242,7 +242,7 @@ namespace Fungus } // Execute the first command in the command list - block.ExecuteCommand(0); + block.Execute(); return true; } diff --git a/Assets/Fungus/Narrative/Deprecated/Choose.cs b/Assets/Fungus/Narrative/Deprecated/Choose.cs index 4c9b5385..53fc7b73 100644 --- a/Assets/Fungus/Narrative/Deprecated/Choose.cs +++ b/Assets/Fungus/Narrative/Deprecated/Choose.cs @@ -100,7 +100,7 @@ namespace Fungus } else { - ExecuteBlock(onSelectBlock); + ExecuteBlock(onSelectBlock, true); } }; @@ -131,7 +131,7 @@ namespace Fungus public override void GetConnectedBlocks (ref List connectedBlocks) { // Show connected blocks from preceding AddOption commands - if (IsExecuting()) + if (isExecuting) { foreach (Option option in options) { @@ -175,7 +175,7 @@ namespace Fungus { options.Clear(); showBasicGUI = false; - ExecuteBlock(option.targetBlock); + ExecuteBlock(option.targetBlock, true); } } diff --git a/Assets/Fungus/Narrative/Scripts/MenuDialog.cs b/Assets/Fungus/Narrative/Scripts/MenuDialog.cs index 8b240d8d..c506ca1c 100644 --- a/Assets/Fungus/Narrative/Scripts/MenuDialog.cs +++ b/Assets/Fungus/Narrative/Scripts/MenuDialog.cs @@ -126,7 +126,7 @@ namespace Fungus gameObject.SetActive(false); - block.ExecuteCommand(0); + block.Execute(); } }); @@ -199,7 +199,7 @@ namespace Fungus if (targetBlock != null) { - targetBlock.ExecuteCommand(0); + targetBlock.Execute(); } } }