diff --git a/Assets/Fungus/Scripts/Commands/Call.cs b/Assets/Fungus/Scripts/Commands/Call.cs index 3eed582f..3dc2cbb0 100644 --- a/Assets/Fungus/Scripts/Commands/Call.cs +++ b/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(); diff --git a/Assets/Fungus/Scripts/Commands/DebugBreak.cs b/Assets/Fungus/Scripts/Commands/DebugBreak.cs new file mode 100644 index 00000000..785bde0e --- /dev/null +++ b/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 +{ + /// + /// Writes a log message to the debug console. + /// + [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); + } + } +} \ No newline at end of file diff --git a/Assets/Fungus/Scripts/Commands/DebugBreak.cs.meta b/Assets/Fungus/Scripts/Commands/DebugBreak.cs.meta new file mode 100644 index 00000000..cc5c158e --- /dev/null +++ b/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: diff --git a/Assets/Fungus/Scripts/Components/Block.cs b/Assets/Fungus/Scripts/Components/Block.cs index ef780a76..2156f2fc 100644 --- a/Assets/Fungus/Scripts/Components/Block.cs +++ b/Assets/Fungus/Scripts/Components/Block.cs @@ -61,6 +61,15 @@ namespace Fungus protected bool executionInfoSet = false; + /// + /// If set, flowchart will not auto select when it is next executed, used by eventhandlers. + /// Only effects the editor. + /// + 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) || diff --git a/Assets/Fungus/Scripts/Components/Command.cs b/Assets/Fungus/Scripts/Components/Command.cs index fcfaf128..fbe519c7 100644 --- a/Assets/Fungus/Scripts/Components/Command.cs +++ b/Assets/Fungus/Scripts/Components/Command.cs @@ -39,7 +39,7 @@ namespace Fungus /// /// Base class for Commands. Commands can be added to Blocks to create an execution sequence. /// - 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(); + } + /// /// Called by unity when script is loaded or its data changed by editor /// diff --git a/Assets/Fungus/Scripts/Components/EventHandler.cs b/Assets/Fungus/Scripts/Components/EventHandler.cs index b563acf1..ddf64bb6 100644 --- a/Assets/Fungus/Scripts/Components/EventHandler.cs +++ b/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 /// @@ -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); diff --git a/Assets/Fungus/Scripts/Components/MenuDialog.cs b/Assets/Fungus/Scripts/Components/MenuDialog.cs index b5329bf3..3c544b6e 100644 --- a/Assets/Fungus/Scripts/Components/MenuDialog.cs +++ b/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 diff --git a/Assets/Fungus/Scripts/Components/Variable.cs b/Assets/Fungus/Scripts/Components/Variable.cs index 45108425..4a3e317a 100644 --- a/Assets/Fungus/Scripts/Components/Variable.cs +++ b/Assets/Fungus/Scripts/Components/Variable.cs @@ -122,6 +122,12 @@ namespace Fungus /// public abstract void OnReset(); + /// + /// Boxed or referenced value of type defined within inherited types. + /// Not recommended for direct use, primarily intended for use in editor code. + /// + public abstract object GetValue(); + #endregion } @@ -178,6 +184,11 @@ namespace Fungus } } + public override object GetValue() + { + return value; + } + protected T startValue; public override void OnReset() diff --git a/Assets/Fungus/Scripts/Editor/BlockEditor.cs b/Assets/Fungus/Scripts/Editor/BlockEditor.cs index 0d59d642..412fe488 100644 --- a/Assets/Fungus/Scripts/Editor/BlockEditor.cs +++ b/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); diff --git a/Assets/Fungus/Scripts/Editor/EditorExtensions.cs b/Assets/Fungus/Scripts/Editor/EditorExtensions.cs index cce6da06..a1968ee5 100644 --- a/Assets/Fungus/Scripts/Editor/EditorExtensions.cs +++ b/Assets/Fungus/Scripts/Editor/EditorExtensions.cs @@ -78,5 +78,15 @@ namespace Fungus.EditorUtils return retval.ToArray(); #endif } + + /// + /// Find and return all Unity.Objects that have the target interface + /// + /// Intended to be an interface but will work for any + /// + public static List FindObjectsOfInterface() + { + return Object.FindObjectsOfType().OfType().ToList(); + } } } \ No newline at end of file diff --git a/Assets/Fungus/Scripts/Editor/FlowchartWindow.cs b/Assets/Fungus/Scripts/Editor/FlowchartWindow.cs index 6eee2d9a..f03fbe3c 100644 --- a/Assets/Fungus/Scripts/Editor/FlowchartWindow.cs +++ b/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 diff --git a/Assets/Fungus/Scripts/Editor/PopupContent/VariableSelectPopupWindowContent.cs b/Assets/Fungus/Scripts/Editor/PopupContent/VariableSelectPopupWindowContent.cs index ee7c3461..697d8db0 100644 --- a/Assets/Fungus/Scripts/Editor/PopupContent/VariableSelectPopupWindowContent.cs +++ b/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); } } } \ No newline at end of file diff --git a/Assets/Fungus/Scripts/Editor/VariableListAdaptor.cs b/Assets/Fungus/Scripts/Editor/VariableListAdaptor.cs index 02f4c5e5..fcc6cd15 100644 --- a/Assets/Fungus/Scripts/Editor/VariableListAdaptor.cs +++ b/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(Func orderFunc) + { + List vars = new List(); + 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() + .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); + } } } diff --git a/Assets/Fungus/Scripts/Interfaces/IBlockCaller.cs b/Assets/Fungus/Scripts/Interfaces/IBlockCaller.cs index 9462f957..54d85240 100644 --- a/Assets/Fungus/Scripts/Interfaces/IBlockCaller.cs +++ b/Assets/Fungus/Scripts/Interfaces/IBlockCaller.cs @@ -3,10 +3,8 @@ /// /// Interface for indicating that the class holds a reference to and may call a block /// - public interface IBlockCaller + public interface IBlockCaller : IStringLocationIdentifier { bool MayCallBlock(Block block); - - string GetLocationIdentifier(); } } \ No newline at end of file diff --git a/Assets/Fungus/Scripts/Interfaces/IStringLocationIdentifier.cs b/Assets/Fungus/Scripts/Interfaces/IStringLocationIdentifier.cs new file mode 100644 index 00000000..288e9f59 --- /dev/null +++ b/Assets/Fungus/Scripts/Interfaces/IStringLocationIdentifier.cs @@ -0,0 +1,11 @@ +namespace Fungus +{ + /// + /// Interface for providing a human readable path to an element, used in editor code to determine where + /// something exists elsewhere in the scene. + /// + public interface IStringLocationIdentifier + { + string GetLocationIdentifier(); + } +} \ No newline at end of file diff --git a/Assets/Fungus/Scripts/Interfaces/IStringLocationIdentifier.cs.meta b/Assets/Fungus/Scripts/Interfaces/IStringLocationIdentifier.cs.meta new file mode 100644 index 00000000..14719875 --- /dev/null +++ b/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: diff --git a/Assets/Fungus/Scripts/Interfaces/IVariableReference.cs b/Assets/Fungus/Scripts/Interfaces/IVariableReference.cs new file mode 100644 index 00000000..d6848f72 --- /dev/null +++ b/Assets/Fungus/Scripts/Interfaces/IVariableReference.cs @@ -0,0 +1,10 @@ +namespace Fungus +{ + /// + /// Interface for indicating that the class holds a reference to a fungus variable, used primarily in editor. + /// + public interface IVariableReference : IStringLocationIdentifier + { + bool HasReference(Variable variable); + } +} \ No newline at end of file diff --git a/Assets/Fungus/Scripts/Interfaces/IVariableReference.cs.meta b/Assets/Fungus/Scripts/Interfaces/IVariableReference.cs.meta new file mode 100644 index 00000000..a163535d --- /dev/null +++ b/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: diff --git a/Assets/Fungus/Scripts/Utils/VariableReference.cs b/Assets/Fungus/Scripts/Utils/VariableReference.cs index 21410da6..e5c12ce8 100644 --- a/Assets/Fungus/Scripts/Utils/VariableReference.cs +++ b/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. /// [System.Serializable] public struct VariableReference