Browse Source

Improve efficiency of command list execution #96

Changed the Block and Command classes to use a simple execution loop
inside a coroutine.
The Call command now has a ‘Stop Parent Block’ parameter for when you
want to continue executing the current block after a Call command.
master
chrisgregan 10 years ago
parent
commit
5dd745d140
  1. 4
      Assets/Fungus/Flowchart/Editor/CallEditor.cs
  2. 2
      Assets/Fungus/Flowchart/Editor/CommandListAdaptor.cs
  3. 2
      Assets/Fungus/Flowchart/Editor/FlowchartWindow.cs
  4. 152
      Assets/Fungus/Flowchart/Scripts/Block.cs
  5. 38
      Assets/Fungus/Flowchart/Scripts/Command.cs
  6. 11
      Assets/Fungus/Flowchart/Scripts/Commands/Call.cs
  7. 2
      Assets/Fungus/Flowchart/Scripts/Flowchart.cs
  8. 6
      Assets/Fungus/Narrative/Deprecated/Choose.cs
  9. 4
      Assets/Fungus/Narrative/Scripts/MenuDialog.cs

4
Assets/Fungus/Flowchart/Editor/CallEditor.cs

@ -9,10 +9,12 @@ namespace Fungus
public class CallEditor : CommandEditor public class CallEditor : CommandEditor
{ {
protected SerializedProperty targetBlockProp; protected SerializedProperty targetBlockProp;
protected SerializedProperty stopParentBlockProp;
protected virtual void OnEnable() protected virtual void OnEnable()
{ {
targetBlockProp = serializedObject.FindProperty("targetBlock"); targetBlockProp = serializedObject.FindProperty("targetBlock");
stopParentBlockProp = serializedObject.FindProperty("stopParentBlock");
} }
public override void DrawCommandGUI() public override void DrawCommandGUI()
@ -32,6 +34,8 @@ namespace Fungus
new GUIContent("<Continue>"), new GUIContent("<Continue>"),
flowchart); flowchart);
EditorGUILayout.PropertyField(stopParentBlockProp);
serializedObject.ApplyModifiedProperties(); serializedObject.ApplyModifiedProperties();
} }
} }

2
Assets/Fungus/Flowchart/Editor/CommandListAdaptor.cs

@ -362,7 +362,7 @@ namespace Fungus
GUI.Label(commandLabelRect, commandName, commandLabelStyle); GUI.Label(commandLabelRect, commandName, commandLabelStyle);
} }
if (command.IsExecuting()) if (command.isExecuting)
{ {
Rect iconRect = new Rect(commandLabelRect); Rect iconRect = new Rect(commandLabelRect);
iconRect.x += iconRect.width - commandLabelRect.width - 20; iconRect.x += iconRect.width - commandLabelRect.width - 20;

2
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 || if (highlightedOnly && !highlight ||
!highlightedOnly && highlight) !highlightedOnly && highlight)

152
Assets/Fungus/Flowchart/Scripts/Block.cs

@ -21,6 +21,15 @@ namespace Fungus
[AddComponentMenu("")] [AddComponentMenu("")]
public class Block : Node public class Block : Node
{ {
public enum ExecutionState
{
Idle,
Executing,
}
[NonSerialized]
public ExecutionState executionState;
[HideInInspector] [HideInInspector]
public int itemId = -1; // Invalid flowchart item id public int itemId = -1; // Invalid flowchart item id
@ -55,6 +64,12 @@ namespace Fungus
protected int executionCount; protected int executionCount;
/**
* Controls the next command to execute in the block execution coroutine.
*/
[NonSerialized]
public int jumpToCommandIndex = -1;
protected virtual void Awake() protected virtual void Awake()
{ {
// Give each child command a reference back to its parent block // Give each child command a reference back to its parent block
@ -117,13 +132,7 @@ namespace Fungus
public virtual bool IsExecuting() public virtual bool IsExecuting()
{ {
Flowchart flowchart = GetFlowchart(); return (executionState == ExecutionState.Executing);
if (flowchart == null)
{
return false;
}
return (activeCommand != null);
} }
public virtual int GetExecutionCount() public virtual int GetExecutionCount()
@ -131,100 +140,101 @@ namespace Fungus
return executionCount; return executionCount;
} }
public virtual void ExecuteCommand(int commandIndex) public virtual bool Execute()
{ {
if (activeCommand == null) if (executionState != ExecutionState.Idle)
{
previousActiveCommandIndex = -1;
}
else
{ {
previousActiveCommandIndex = activeCommand.commandIndex; return false;
} }
if (commandIndex >= commandList.Count) executionCount++;
{ StartCoroutine(ExecuteBlock());
Stop();
return;
}
if (commandIndex == 0) return true;
{ }
executionCount++;
}
protected virtual IEnumerator ExecuteBlock()
{
Flowchart flowchart = GetFlowchart(); Flowchart flowchart = GetFlowchart();
executionState = ExecutionState.Executing;
// Skip disabled commands, comments and labels int i = 0;
while (commandIndex < commandList.Count && while (true)
(!commandList[commandIndex].enabled ||
commandList[commandIndex].GetType() == typeof(Comment) ||
commandList[commandIndex].GetType() == typeof(Label)))
{ {
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) // Skip disabled commands, comments and labels
{ while (i < commandList.Count &&
Stop(); (!commandList[i].enabled ||
return; 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; // The previous active command is needed for if / else / else if commands
executingIconTimer = 0.5f; 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) if (flowchart.gameObject.activeInHierarchy)
{ {
// Auto select a command in some situations // 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.selectedCommands.Count == 1 && flowchart.selectedCommands[0].commandIndex == previousActiveCommandIndex))
{ {
flowchart.ClearSelectedCommands(); flowchart.ClearSelectedCommands();
flowchart.AddSelectedCommand(nextCommand); flowchart.AddSelectedCommand(commandList[i]);
}
if (runSlowInEditor &&
nextCommand.RunSlowInEditor())
{
StartCoroutine(ExecuteAfterDelay(nextCommand, flowchart.runSlowDuration));
}
else
{
activeCommand = nextCommand;
nextCommand.Execute();
} }
} }
}
} command.isExecuting = true;
command.Execute();
IEnumerator ExecuteAfterDelay(Command nextCommand, float delay) // Wait until the executing command sets another command to jump to via Command.Continue()
{ while (jumpToCommandIndex == -1)
activeCommand = nextCommand; {
yield return new WaitForSeconds(delay); yield return null;
nextCommand.Execute(); }
}
public virtual void Stop() if (runSlowInEditor)
{ {
Flowchart flowchart = GetFlowchart(); yield return new WaitForSeconds(flowchart.runSlowDuration);
if (flowchart == null) }
{
return; command.isExecuting = false;
} }
executionState = ExecutionState.Idle;
activeCommand = null; activeCommand = null;
flowchart.ClearSelectedCommands(); flowchart.ClearSelectedCommands();
} }
public virtual void Stop()
{
// This will cause the execution loop to break on the next iteration
jumpToCommandIndex = int.MaxValue;
}
public virtual List<Block> GetConnectedBlocks() public virtual List<Block> GetConnectedBlocks()
{ {
List<Block> connectedBlocks = new List<Block>(); List<Block> connectedBlocks = new List<Block>();

38
Assets/Fungus/Flowchart/Scripts/Command.cs

@ -45,6 +45,12 @@ namespace Fungus
[NonSerialized] [NonSerialized]
public int commandIndex; 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. * Reference to the Block object that this command belongs to.
* This reference is only populated at runtime and in the editor when the * This reference is only populated at runtime and in the editor when the
@ -64,16 +70,6 @@ namespace Fungus
return flowchart; return flowchart;
} }
public virtual bool IsExecuting()
{
if (parentBlock == null)
{
return false;
}
return (parentBlock.activeCommand == this);
}
public virtual void Execute() public virtual void Execute()
{ {
OnEnter(); OnEnter();
@ -89,7 +85,7 @@ namespace Fungus
OnExit(); OnExit();
if (parentBlock != null) 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(); OnExit();
if (parentBlock != null) if (parentBlock != null)
{ {
Flowchart flowchart = parentBlock.GetFlowchart(); Flowchart flowchart = parentBlock.GetFlowchart();
if (flowchart == null)
{
return;
}
// Record the currently selected block because Stop() will clear it. if (stopParentBlock)
Block selectedBlock = flowchart.selectedBlock;
parentBlock.Stop();
if (flowchart != null)
{ {
parentBlock.Stop();
// If the executing block is currently selected then follow the execution // If the executing block is currently selected then follow the execution
// onto the next block in the inspector. // onto the next block in the inspector.
if (selectedBlock == parentBlock) if (flowchart.selectedBlock == parentBlock)
{ {
flowchart.selectedBlock = s; flowchart.selectedBlock = s;
} }
flowchart.ExecuteBlock(s);
} }
flowchart.ExecuteBlock(s);
} }
} }

11
Assets/Fungus/Flowchart/Scripts/Commands/Call.cs

@ -13,14 +13,21 @@ namespace Fungus
public class Call : Command public class Call : Command
{ {
[FormerlySerializedAs("targetSequence")] [FormerlySerializedAs("targetSequence")]
[Tooltip("Block to execute")] [Tooltip("Block to start executing")]
public Block targetBlock; public Block targetBlock;
[Tooltip("Stop executing the parent block that contains this command")]
public bool stopParentBlock = true;
public override void OnEnter() public override void OnEnter()
{ {
if (targetBlock != null) if (targetBlock != null)
{ {
ExecuteBlock(targetBlock); ExecuteBlock(targetBlock, stopParentBlock);
if (!stopParentBlock)
{
Continue();
}
} }
else else
{ {

2
Assets/Fungus/Flowchart/Scripts/Flowchart.cs

@ -242,7 +242,7 @@ namespace Fungus
} }
// Execute the first command in the command list // Execute the first command in the command list
block.ExecuteCommand(0); block.Execute();
return true; return true;
} }

6
Assets/Fungus/Narrative/Deprecated/Choose.cs

@ -100,7 +100,7 @@ namespace Fungus
} }
else else
{ {
ExecuteBlock(onSelectBlock); ExecuteBlock(onSelectBlock, true);
} }
}; };
@ -131,7 +131,7 @@ namespace Fungus
public override void GetConnectedBlocks (ref List<Block> connectedBlocks) public override void GetConnectedBlocks (ref List<Block> connectedBlocks)
{ {
// Show connected blocks from preceding AddOption commands // Show connected blocks from preceding AddOption commands
if (IsExecuting()) if (isExecuting)
{ {
foreach (Option option in options) foreach (Option option in options)
{ {
@ -175,7 +175,7 @@ namespace Fungus
{ {
options.Clear(); options.Clear();
showBasicGUI = false; showBasicGUI = false;
ExecuteBlock(option.targetBlock); ExecuteBlock(option.targetBlock, true);
} }
} }

4
Assets/Fungus/Narrative/Scripts/MenuDialog.cs

@ -126,7 +126,7 @@ namespace Fungus
gameObject.SetActive(false); gameObject.SetActive(false);
block.ExecuteCommand(0); block.Execute();
} }
}); });
@ -199,7 +199,7 @@ namespace Fungus
if (targetBlock != null) if (targetBlock != null)
{ {
targetBlock.ExecuteCommand(0); targetBlock.Execute();
} }
} }
} }

Loading…
Cancel
Save