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
{
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("<Continue>"),
flowchart);
EditorGUILayout.PropertyField(stopParentBlockProp);
serializedObject.ApplyModifiedProperties();
}
}

2
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;

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

152
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<Block> GetConnectedBlocks()
{
List<Block> connectedBlocks = new List<Block>();

38
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);
}
}

11
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
{

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

6
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<Block> 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);
}
}

4
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();
}
}
}

Loading…
Cancel
Save