Browse Source

Debug additions (#777)

* Flowchart block selectedness now only modified by Block.Execute at runtime
Blocks can suppress auto-selection in flowchart window due to execution
Events can suppress auto-selection in flowchart window by activation
Variable returns value as object
Flowchart rightclick menu commands for interacting with blocks
Right click menu for variable list for add, rmove and sort
Add IVariableReference
Add DebugBreak command, also useful for attaching IDE breakpoints to

* IBlockCaller now uses IStringLocationIdentifier
master
Steve Halliwell 5 years ago committed by GitHub
parent
commit
9488ba99d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      Assets/Fungus/Scripts/Commands/Call.cs
  2. 42
      Assets/Fungus/Scripts/Commands/DebugBreak.cs
  3. 11
      Assets/Fungus/Scripts/Commands/DebugBreak.cs.meta
  4. 29
      Assets/Fungus/Scripts/Components/Block.cs
  5. 7
      Assets/Fungus/Scripts/Components/Command.cs
  6. 8
      Assets/Fungus/Scripts/Components/EventHandler.cs
  7. 4
      Assets/Fungus/Scripts/Components/MenuDialog.cs
  8. 11
      Assets/Fungus/Scripts/Components/Variable.cs
  9. 4
      Assets/Fungus/Scripts/Editor/BlockEditor.cs
  10. 10
      Assets/Fungus/Scripts/Editor/EditorExtensions.cs
  11. 43
      Assets/Fungus/Scripts/Editor/FlowchartWindow.cs
  12. 28
      Assets/Fungus/Scripts/Editor/PopupContent/VariableSelectPopupWindowContent.cs
  13. 68
      Assets/Fungus/Scripts/Editor/VariableListAdaptor.cs
  14. 4
      Assets/Fungus/Scripts/Interfaces/IBlockCaller.cs
  15. 11
      Assets/Fungus/Scripts/Interfaces/IStringLocationIdentifier.cs
  16. 11
      Assets/Fungus/Scripts/Interfaces/IStringLocationIdentifier.cs.meta
  17. 10
      Assets/Fungus/Scripts/Interfaces/IVariableReference.cs
  18. 11
      Assets/Fungus/Scripts/Interfaces/IVariableReference.cs.meta
  19. 3
      Assets/Fungus/Scripts/Utils/VariableReference.cs

8
Assets/Fungus/Scripts/Commands/Call.cs

@ -77,7 +77,6 @@ namespace Fungus
if (callMode == CallMode.WaitUntilFinished)
{
onComplete = delegate {
flowchart.SelectedBlock = ParentBlock;
Continue();
};
}
@ -96,13 +95,6 @@ namespace Fungus
if (targetFlowchart == null ||
targetFlowchart.Equals(GetFlowchart()))
{
// If the executing block is currently selected then follow the execution
// onto the next block in the inspector.
if (flowchart.SelectedBlock == ParentBlock)
{
flowchart.SelectedBlock = targetBlock;
}
if (callMode == CallMode.StopThenCall)
{
StopParentBlock();

42
Assets/Fungus/Scripts/Commands/DebugBreak.cs

@ -0,0 +1,42 @@
// This code is part of the Fungus library (http://fungusgames.com) maintained by Chris Gregan (http://twitter.com/gofungus).
// It is released for free under the MIT open source license (https://github.com/snozbot/fungus/blob/master/LICENSE)
using UnityEngine;
namespace Fungus
{
/// <summary>
/// Writes a log message to the debug console.
/// </summary>
[CommandInfo("Scripting",
"Debug Break",
"Calls Debug.Break if enabled. Also useful for putting a visual studio breakbpoint within.")]
[AddComponentMenu("")]
public class DebugBreak : Command
{
[SerializeField] new protected BooleanData enabled = new BooleanData(true);
public override void OnEnter()
{
if (enabled.Value)
Debug.Break();
Continue();
}
public override string GetSummary()
{
return enabled.Value ? "enabled" : "disabled";
}
public override bool HasReference(Variable variable)
{
return variable == enabled.booleanRef;
}
public override Color GetButtonColor()
{
return new Color32(235, 191, 217, 255);
}
}
}

11
Assets/Fungus/Scripts/Commands/DebugBreak.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a14b04da97ec217478d0809feef89ec8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

29
Assets/Fungus/Scripts/Components/Block.cs

@ -61,6 +61,15 @@ namespace Fungus
protected bool executionInfoSet = false;
/// <summary>
/// If set, flowchart will not auto select when it is next executed, used by eventhandlers.
/// Only effects the editor.
/// </summary>
public bool SuppressNextAutoSelection { get; set; }
[SerializeField] bool suppressAllAutoSelections = false;
protected virtual void Awake()
{
SetExecutionInfo();
@ -225,13 +234,23 @@ namespace Fungus
executionState = ExecutionState.Executing;
BlockSignals.DoBlockStart(this);
bool suppressSelectionChanges = false;
#if UNITY_EDITOR
// Select the executing block & the first command
flowchart.SelectedBlock = this;
if (commandList.Count > 0)
if (suppressAllAutoSelections || SuppressNextAutoSelection)
{
flowchart.ClearSelectedCommands();
flowchart.AddSelectedCommand(commandList[0]);
SuppressNextAutoSelection = false;
suppressSelectionChanges = true;
}
else
{
flowchart.SelectedBlock = this;
if (commandList.Count > 0)
{
flowchart.ClearSelectedCommands();
flowchart.AddSelectedCommand(commandList[0]);
}
}
#endif
@ -274,7 +293,7 @@ namespace Fungus
var command = commandList[i];
activeCommand = command;
if (flowchart.IsActive())
if (flowchart.IsActive() && !suppressSelectionChanges)
{
// Auto select a command in some situations
if ((flowchart.SelectedCommands.Count == 0 && i == 0) ||

7
Assets/Fungus/Scripts/Components/Command.cs

@ -39,7 +39,7 @@ namespace Fungus
/// <summary>
/// Base class for Commands. Commands can be added to Blocks to create an execution sequence.
/// </summary>
public abstract class Command : MonoBehaviour
public abstract class Command : MonoBehaviour, IVariableReference
{
[FormerlySerializedAs("commandId")]
[HideInInspector]
@ -228,6 +228,11 @@ namespace Fungus
return false;
}
public virtual string GetLocationIdentifier()
{
return ParentBlock.GetFlowchart().GetName() + ":" + ParentBlock.BlockName + "." + this.GetType().Name + ":" + CommandIndex.ToString();
}
/// <summary>
/// Called by unity when script is loaded or its data changed by editor
/// </summary>

8
Assets/Fungus/Scripts/Components/EventHandler.cs

@ -41,6 +41,9 @@ namespace Fungus
[FormerlySerializedAs("parentSequence")]
[SerializeField] protected Block parentBlock;
[Tooltip("If true, the flowchart window will not auto select the Block when the Event Handler fires. Affects Editor only.")]
[SerializeField] protected bool suppressBlockAutoSelect = false;
#region Public members
/// <summary>
@ -71,10 +74,9 @@ namespace Fungus
return false;
}
// Auto-follow the executing block if none is currently selected
if (flowchart.SelectedBlock == null)
if (suppressBlockAutoSelect)
{
flowchart.SelectedBlock = ParentBlock;
ParentBlock.SuppressNextAutoSelection = true;
}
return flowchart.ExecuteBlock(ParentBlock);

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

@ -240,10 +240,6 @@ namespace Fungus
if (block != null)
{
var flowchart = block.GetFlowchart();
#if UNITY_EDITOR
// Select the new target block in the Flowchart window
flowchart.SelectedBlock = block;
#endif
gameObject.SetActive(false);
// Use a coroutine to call the block on the next frame
// Have to use the Flowchart gameobject as the MenuDialog is now inactive

11
Assets/Fungus/Scripts/Components/Variable.cs

@ -122,6 +122,12 @@ namespace Fungus
/// </summary>
public abstract void OnReset();
/// <summary>
/// Boxed or referenced value of type defined within inherited types.
/// Not recommended for direct use, primarily intended for use in editor code.
/// </summary>
public abstract object GetValue();
#endregion
}
@ -178,6 +184,11 @@ namespace Fungus
}
}
public override object GetValue()
{
return value;
}
protected T startValue;
public override void OnReset()

4
Assets/Fungus/Scripts/Editor/BlockEditor.cs

@ -155,6 +155,9 @@ namespace Fungus.EditorUtils
SerializedProperty descriptionProp = serializedObject.FindProperty("description");
EditorGUILayout.PropertyField(descriptionProp);
SerializedProperty suppressProp = serializedObject.FindProperty("suppressAllAutoSelections");
EditorGUILayout.PropertyField(suppressProp);
EditorGUI.indentLevel++;
if (callersFoldout = EditorGUILayout.Foldout(callersFoldout, "Callers"))
@ -166,7 +169,6 @@ namespace Fungus.EditorUtils
}
EditorGUI.indentLevel--;
EditorGUILayout.Space();
DrawEventHandlerGUI(flowchart);

10
Assets/Fungus/Scripts/Editor/EditorExtensions.cs

@ -78,5 +78,15 @@ namespace Fungus.EditorUtils
return retval.ToArray();
#endif
}
/// <summary>
/// Find and return all Unity.Objects that have the target interface
/// </summary>
/// <typeparam name="T">Intended to be an interface but will work for any</typeparam>
/// <returns></returns>
public static List<T> FindObjectsOfInterface<T>()
{
return Object.FindObjectsOfType<Object>().OfType<T>().ToList();
}
}
}

43
Assets/Fungus/Scripts/Editor/FlowchartWindow.cs

@ -1247,6 +1247,21 @@ namespace Fungus.EditorUtils
menu.AddItem(new GUIContent ("Cut"), false, () => Cut());
menu.AddItem(new GUIContent ("Duplicate"), false, () => Duplicate());
menu.AddItem(new GUIContent ("Delete"), false, () => AddToDeleteList(blockList));
menu.AddSeparator("");
if(Application.isPlaying)
{
menu.AddItem(new GUIContent("StopAll"), false, () => StopAllBlocks());
menu.AddItem(new GUIContent("Stop"), false, () => StopThisBlock(hitBlock));
menu.AddItem(new GUIContent("Execute"), false, () => ExecuteThisBlock(hitBlock, false));
menu.AddItem(new GUIContent("Execute (Stop All First)"), false, () => ExecuteThisBlock(hitBlock, true));
}
else
{
menu.AddDisabledItem(new GUIContent("StopAll"), false);//, () => StopAllBlocks());
menu.AddDisabledItem(new GUIContent("Stop"), false);//, () => StopThisBlock(hitBlock));
menu.AddDisabledItem(new GUIContent("Execute"), false);//, () => ExecuteThisBlock(hitBlock, false));
menu.AddDisabledItem(new GUIContent("Execute (Stop All First)"), false);//, () => ExecuteThisBlock(hitBlock, true));
}
}
else
{
@ -1262,6 +1277,16 @@ namespace Fungus.EditorUtils
{
menu.AddDisabledItem(new GUIContent("Paste"));
}
menu.AddSeparator("");
if (Application.isPlaying)
{
menu.AddItem(new GUIContent("StopAll"), false, () => StopAllBlocks());
}
else
{
menu.AddDisabledItem(new GUIContent("StopAll"), false);//, () => StopAllBlocks());
}
}
var menuRect = new Rect();
@ -1667,6 +1692,24 @@ namespace Fungus.EditorUtils
}
}
internal void StopThisBlock(Block block)
{
block.Stop();
}
internal void StopAllBlocks()
{
flowchart.StopAllBlocks();
}
internal void ExecuteThisBlock(Block block, bool stopRunningBlocks)
{
if (stopRunningBlocks)
StopAllBlocks();
block.StartExecution();
}
public void DeleteBlocks()
{
// Delete any scheduled objects

28
Assets/Fungus/Scripts/Editor/PopupContent/VariableSelectPopupWindowContent.cs

@ -115,7 +115,12 @@ namespace Fungus.EditorUtils
{
}
protected static void AddVariable(object obj)
public static void AddVariable(object obj)
{
AddVariable(obj, string.Empty);
}
public static void AddVariable(object obj, string suggestedName)
{
System.Type t = obj as System.Type;
if (t == null)
@ -123,13 +128,24 @@ namespace Fungus.EditorUtils
return;
}
Undo.RecordObject(curFlowchart, "Add Variable");
Variable newVariable = curFlowchart.gameObject.AddComponent(t) as Variable;
newVariable.Key = curFlowchart.GetUniqueVariableKey("");
curFlowchart.Variables.Add(newVariable);
var flowchart = curFlowchart != null ? curFlowchart : FlowchartWindow.GetFlowchart();
Undo.RecordObject(flowchart, "Add Variable");
Variable newVariable = flowchart.gameObject.AddComponent(t) as Variable;
newVariable.Key = flowchart.GetUniqueVariableKey(suggestedName);
//if suggested exists, then insert, if not just add
var existingVariable = flowchart.GetVariable(suggestedName);
if (existingVariable != null)
{
flowchart.Variables.Insert(flowchart.Variables.IndexOf(existingVariable)+1, newVariable);
}
else
{
flowchart.Variables.Add(newVariable);
}
// Because this is an async call, we need to force prefab instances to record changes
PrefabUtility.RecordPrefabInstancePropertyModifications(curFlowchart);
PrefabUtility.RecordPrefabInstancePropertyModifications(flowchart);
}
}
}

68
Assets/Fungus/Scripts/Editor/VariableListAdaptor.cs

@ -1,12 +1,12 @@
// This code is part of the Fungus library (http://fungusgames.com) maintained by Chris Gregan (http://twitter.com/gofungus).
// It is released for free under the MIT open source license (https://github.com/snozbot/fungus/blob/master/LICENSE)
using UnityEngine;
using UnityEditor;
using System;
using UnityEditorInternal;
using System.Collections.Generic;
using System.Linq;
namespace Fungus.EditorUtils
{
@ -47,6 +47,18 @@ namespace Fungus.EditorUtils
return this[index].objectReferenceValue as Variable;
}
public void SetVarAt(int index, Variable v)
{
if (list.list != null)
{
list.list[index] = v;
}
else
{
this[index].objectReferenceValue = v;
}
}
public VariableListAdaptor(SerializedProperty arrayProperty, Flowchart _targetFlowchart)
{
if (arrayProperty == null)
@ -152,6 +164,11 @@ namespace Fungus.EditorUtils
return;
}
if(Event.current.type == EventType.ContextClick && position.Contains(Event.current.mousePosition))
{
DoRightClickMenu(index);
}
for (int i = 0; i < 4; ++i)
{
itemRects[i] = position;
@ -262,6 +279,55 @@ namespace Fungus.EditorUtils
GUI.backgroundColor = Color.white;
}
private void DoRightClickMenu(int index)
{
var v = GetVarAt(index);
GenericMenu commandMenu = new GenericMenu();
commandMenu.AddItem(new GUIContent("Remove"), false, () => {list.index = index; RemoveItem(list); });
commandMenu.AddItem(new GUIContent("Duplicate"), false, () => VariableSelectPopupWindowContent.AddVariable(v.GetType(), v.Key));
commandMenu.AddItem(new GUIContent("Find References"), false, () => FindUsage(GetVarAt(index)));
commandMenu.AddSeparator("");
commandMenu.AddItem(new GUIContent("Sort by Name"), false, () => SortBy(x => x.Key));
commandMenu.AddItem(new GUIContent("Sort by Type"), false, () => SortBy(x => x.GetType().Name));
commandMenu.AddItem(new GUIContent("Sort by Value"), false, () => SortBy(x => x.GetValue()));
commandMenu.ShowAsContext();
}
private void SortBy<TKey>(Func<Variable, TKey> orderFunc)
{
List<Variable> vars = new List<Variable>();
for (int i = 0; i < list.count; i++)
{
vars.Add(GetVarAt(i));
}
vars = vars.OrderBy(orderFunc).ToList();
for (int i = 0; i < list.count; i++)
{
SetVarAt(i, vars[i]);
}
_arrayProperty.serializedObject.ApplyModifiedProperties();
}
private void FindUsage(Variable variable)
{
var varRefs = EditorExtensions.FindObjectsOfInterface<IVariableReference>()
.Where(x => x.HasReference(variable))
.Select(x => x.GetLocationIdentifier()).ToList(); ;
string varRefString = variable.Key + " referenced in;\n";
if (varRefs.Count > 0)
varRefString += string.Join("\n", varRefs);
else
varRefString += "None";
Debug.Log(varRefString);
}
}
}

4
Assets/Fungus/Scripts/Interfaces/IBlockCaller.cs

@ -3,10 +3,8 @@
/// <summary>
/// Interface for indicating that the class holds a reference to and may call a block
/// </summary>
public interface IBlockCaller
public interface IBlockCaller : IStringLocationIdentifier
{
bool MayCallBlock(Block block);
string GetLocationIdentifier();
}
}

11
Assets/Fungus/Scripts/Interfaces/IStringLocationIdentifier.cs

@ -0,0 +1,11 @@
namespace Fungus
{
/// <summary>
/// Interface for providing a human readable path to an element, used in editor code to determine where
/// something exists elsewhere in the scene.
/// </summary>
public interface IStringLocationIdentifier
{
string GetLocationIdentifier();
}
}

11
Assets/Fungus/Scripts/Interfaces/IStringLocationIdentifier.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2993a9ad5bc21254d9ec5d09528775c0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

10
Assets/Fungus/Scripts/Interfaces/IVariableReference.cs

@ -0,0 +1,10 @@
namespace Fungus
{
/// <summary>
/// Interface for indicating that the class holds a reference to a fungus variable, used primarily in editor.
/// </summary>
public interface IVariableReference : IStringLocationIdentifier
{
bool HasReference(Variable variable);
}
}

11
Assets/Fungus/Scripts/Interfaces/IVariableReference.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e8efeca0dcf047241abed0f0f00d1afd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

3
Assets/Fungus/Scripts/Utils/VariableReference.cs

@ -5,6 +5,9 @@
/// This is the a way to directly reference a fungus variable in external c# scripts, it will
/// give you an inspector field that gives a drop down of all the variables on the targeted
/// flowchart, in a similar way to what you would expect from selecting a variable on a command.
///
/// Also recommend implementing IVariableReference on any custom classes that use this so your
/// references can show up in searches for usage.
/// </summary>
[System.Serializable]
public struct VariableReference

Loading…
Cancel
Save