internal static AICanvas Deserialize(AIUI host, string data) { var canvasElement = SerializationMaster.Deserialize(data); var canvas = new AICanvas { offset = canvasElement.ValueOrDefault <Vector2>(ElementName.Offset), zoom = canvasElement.ValueOrDefault(ElementName.Zoom, 1f) }; var selectorViews = canvasElement.Elements(ElementName.SelectorView); foreach (var sve in selectorViews) { var sv = ReadSelectorView(sve, host); canvas.views.Add(sv); } var linkViews = canvasElement.Elements(ElementName.AILinkView); foreach (var lve in linkViews) { var lv = ReadAILinkView(lve, host); canvas.views.Add(lv); } return(canvas); }
private static void DeserializeAILinkViews(StageElement[] viewElements, AIUI targetUI, Vector2 referencePos, Vector2 mousePos, List <TopLevelView> newViews) { for (int i = 0; i < viewElements.Length; i++) { var lv = ReadAILinkView(viewElements[i], targetUI); //We only add an AI link if it does not already exist. Having two links to the same AI does not make sense. var existing = targetUI.FindAILink(other => other.aiId == lv.aiId); if (existing != null) { continue; } // first treat the top-left-most selector as the origin point (reference pos) lv.viewArea.position -= referencePos; // secondly add the mouse offset to the position so as to paste it in where the mouse is at lv.viewArea.position += mousePos; targetUI.canvas.views.Add(lv); newViews.Add(lv); targetUI.undoRedo.Do(new AddAILinkOperation(targetUI, lv)); } }
private static SelectorView ReadSelectorView(StageElement sve, AIUI parent) { var sv = new SelectorView { name = sve.ValueOrDefault <string>(ElementName.Name), description = sve.ValueOrDefault <string>(ElementName.Description), viewArea = sve.ValueOrDefault <Rect>(ElementName.ViewArea), parent = parent }; var defQv = sve.Element(ElementName.DefaultQualifier); sv.defaultQualifierView = defQv != null?ReadQualifierView(defQv, sv) : new QualifierView { parent = sv }; var qualifierViews = sve.Elements(ElementName.QualifierView); foreach (var qve in qualifierViews) { var qv = ReadQualifierView(qve, sv); sv.qualifierViews.Add(qv); } return(sv); }
private void DrawAIUI(AIUI aiui) { HeaderHandler headerRects; if (EditorApplication.isPlaying) { headerRects = HeaderHandler.GetHeaderRects(0); } else { headerRects = HeaderHandler.GetHeaderRects(1); if (GUI.Button(headerRects.Next, SharedStyles.deleteTooltip, SharedStyles.BuiltIn.deleteButtonSmall)) { GUI.changed = false; if (DisplayHelper.ConfirmDelete("AI", true)) { AIEditorWindow.activeInstance.DeleteAI(); return; } } } GUI.Label(headerRects.Next, string.Concat(_state.currentAIUI.name, " | APEX AI"), EditorStyling.Skinned.inspectorTitle); }
internal static AIUI Create(string name) { var gui = new AIUI(); gui.InitNew(name); gui.InitAI(); return(gui); }
internal static void ShowCanvasMenu(AIUI ui, Vector2 mousePos) { var menu = new GenericMenu(); var screenPos = EditorGUIUtility.GUIToScreenPoint(mousePos); menu.AddItem(new GUIContent("Add Selector"), false, () => AIEntitySelectorWindow.Get <Selector>(screenPos, (selectorType) => { ui.AddSelector(mousePos, selectorType); })); menu.AddItem(new GUIContent("Add AI Link"), false, () => AISelectorWindow.Get(screenPos, (storedAI) => { ui.AddAILink(mousePos, storedAI.aiId); })); AddSharedItems(menu, ui, true, mousePos); }
private static AILinkView ReadAILinkView(StageElement lve, AIUI parent) { var lv = new AILinkView { name = lve.ValueOrDefault <string>(ElementName.Name), description = lve.ValueOrDefault <string>(ElementName.Description), viewArea = lve.ValueOrDefault <Rect>(ElementName.ViewArea), aiId = lve.AttributeValue <Guid>(AttributeName.Id), parent = parent }; return(lv); }
internal static AIUI Load(AIStorage ai, bool refreshState) { var gui = new AIUI(); gui.name = ai.name; if (!gui.LoadFrom(ai, refreshState)) { return(null); } return(gui); }
internal static void CopyToClipboard(AIUI sourceUI) { if (sourceUI.currentAction != null) { EditorGUIUtility.systemCopyBuffer = GuiSerializer.Serialize(sourceUI.currentAction); } else if (sourceUI.currentQualifier != null) { EditorGUIUtility.systemCopyBuffer = GuiSerializer.Serialize(sourceUI.currentQualifier); } else if (sourceUI.selectedViews.Count > 0) { EditorGUIUtility.systemCopyBuffer = GuiSerializer.Serialize(sourceUI.selectedViews); } }
internal static SelectorView Create(Type selectorType, AIUI parent, Rect viewArea) { if (!selectorType.IsSubclassOf(typeof(Selector))) { throw new ArgumentException("The proposed type is not a Selector.", "selectorType"); } var sv = new SelectorView(viewArea); sv.parent = parent; sv.selector = Activator.CreateInstance(selectorType) as Selector; sv.defaultQualifierView = new QualifierView { qualifier = sv.selector.defaultQualifier, parent = sv }; return(sv); }
internal static void PasteFromClipboard(AIUI targetUi, Vector2 mousePos) { if (string.IsNullOrEmpty(EditorGUIUtility.systemCopyBuffer)) { // nothing in the clipboard Debug.LogWarning("Could not paste from clipboard; clipboard is empty."); return; } try { GuiSerializer.DeserializeSnippet(EditorGUIUtility.systemCopyBuffer, targetUi, mousePos, true); targetUi.isDirty = true; } catch { Debug.LogWarning("Could not paste from clipboard; invalid data detected."); } }
internal static void CutToClipboard(AIUI sourceUI) { if (sourceUI.currentAction != null) { EditorGUIUtility.systemCopyBuffer = GuiSerializer.Serialize(sourceUI.currentAction); sourceUI.RemoveAction(sourceUI.currentAction); } else if (sourceUI.currentQualifier != null) { if (sourceUI.currentQualifier.isDefault) { EditorUtility.DisplayDialog("Invalid Action", "The default qualifier cannot be cut. Use copy instead.", "Ok"); return; } EditorGUIUtility.systemCopyBuffer = GuiSerializer.Serialize(sourceUI.currentQualifier); sourceUI.RemoveQualifier(sourceUI.currentQualifier); } else if (sourceUI.selectedViews.Count > 0) { var selectedViews = sourceUI.selectedViews; var cutCount = selectedViews.Count; for (int i = 0; i < cutCount; i++) { var sv = selectedViews[i] as SelectorView; if (sv != null && object.ReferenceEquals(sourceUI.rootSelector, sv.selector)) { EditorUtility.DisplayDialog("Invalid Action", "The root selector can not be part of a cut operation.", "Ok"); return; } } EditorGUIUtility.systemCopyBuffer = GuiSerializer.Serialize(sourceUI.selectedViews); using (sourceUI.undoRedo.bulkOperation) { for (int i = cutCount - 1; i >= 0; i--) { sourceUI.RemoveView(selectedViews[i]); } } } }
internal static void DeserializeSnippet(string data, AIUI targetUI, Vector2 mousePos, bool regenIds) { var root = SerializationMaster.Deserialize(data); var snippetType = root.AttributeValue <string>(AttributeName.SnippetType); var aiElements = root.Element(ElementName.AIPart).Elements().ToArray(); if (snippetType == ElementName.ViewSnippet) { var uiPart = root.Element(ElementName.UIPart); var referencePos = uiPart.ValueOrDefault(ElementName.ReferencePosition, Vector2.zero); var newViews = new List <TopLevelView>(uiPart.Items().Count()); using (targetUI.undoRedo.bulkOperation) { //Deserialize links first so that connections are not lost var linkElements = uiPart.Elements(ElementName.AILinkView).ToArray(); DeserializeAILinkViews(linkElements, targetUI, referencePos, mousePos, newViews); var selectorElements = uiPart.Elements(ElementName.SelectorView).ToArray(); DeserializeSelectorViews(aiElements, selectorElements, targetUI, referencePos, mousePos, newViews, regenIds); } targetUI.MultiSelectViews(newViews); return; } var viewElement = root.Element(ElementName.UIPart).Elements().First(); if (snippetType == ElementName.QualifierSnippet) { DeserializeQualifier(aiElements[0], viewElement, targetUI); } else if (snippetType == ElementName.ActionSnippet) { DeserializeAction(aiElements[0], viewElement, targetUI); } }
internal static void ShowRuntimeViewMenu(AIUI ui, Vector2 mousePos) { if (!ui.isVisualizing) { return; } var menu = new GenericMenu(); var screenPos = EditorGUIUtility.GUIToScreenPoint(mousePos); if (ui.currentQualifier != null) { var visualizedQualifier = (IQualifierVisualizer)ui.currentQualifier.qualifier; if (visualizedQualifier.isBreakPoint) { menu.AddItem(new GUIContent("Remove Breakpoint"), false, () => visualizedQualifier.isBreakPoint = false); } else { menu.AddItem(new GUIContent("Set Breakpoint"), false, () => visualizedQualifier.isBreakPoint = true); } menu.AddItem(new GUIContent("Set Conditional Breakpoint"), false, () => BreakpointConditionWindow.Open(screenPos, visualizedQualifier)); } else if (ui.currentSelector != null) { var visualizedSelector = (SelectorVisualizer)ui.currentSelector.selector; menu.AddItem(new GUIContent("Clear Breakpoints"), false, () => visualizedSelector.ClearBreakpoints()); } else if (ui.currentAILink == null) { var visualizedAI = (UtilityAIVisualizer)ui.visualizedAI; menu.AddItem(new GUIContent("Clear All Breakpoints"), false, () => visualizedAI.ClearBreakpoints()); } menu.ShowAsContext(); }
internal bool Reconnect(Selector s) { this.selector = s; var defQv = this.defaultQualifierView; defQv.qualifier = s.defaultQualifier; if (defQv.actionView != null) { //If an action view is present bug the action is null, this means inconsistency between config end editor config //While this should not occur, we still handle it just in case. if (defQv.qualifier.action == null) { defQv.actionView = null; } else { defQv.actionView.action = defQv.qualifier.action; } } var qualifiers = s.qualifiers; int qualifierCount = qualifiers.Count; if (!AIUI.VerifyCountMatch(qualifierCount, this.qualifierViews.Count)) { return(false); } for (int j = 0; j < qualifierCount; j++) { var qv = this.qualifierViews[j]; qv.Reconnect(qualifiers[j]); } return(true); }
private static void DeserializeAction(StageElement aiElement, StageElement viewElement, AIUI targetUI) { var parent = targetUI.currentQualifier; if (parent == null) { EditorUtility.DisplayDialog("Invalid Action", "You must select a Qualifier before pasting an Action.", "Ok"); } else if (parent.actionView != null) { if (!EditorUtility.DisplayDialog("Confirm Replace", "The selected Qualifier already has an action, do you wish to replace it?", "Yes", "No")) { return; } } var requiresInit = new List <IInitializeAfterDeserialization>(); var actionView = ReadActionView(viewElement, parent); var action = SerializationMaster.Unstage <IAction>(aiElement, requiresInit); actionView.action = action; //Do the post deserialize initialization here if (requiresInit.Count == 1) { requiresInit[0].Initialize(targetUI.ai); } targetUI.SetAction(actionView, parent); parent.PruneBrokenConnections(); }
private static bool ExecuteCommand(string cmd, int delay) { var ais = selectedAIs.ToArray(); if (ais.Length == 0) { return(false); } bool consumeEvent = false; switch (cmd) { case "Open": { _pendingAction = () => { for (int i = 0; i < ais.Length; i++) { AIEditorWindow.Open(ais[i].aiId); } }; consumeEvent = true; break; } case "Delete": case "SoftDelete": { //reload all windows with deleted ais var aisBefore = StoredAIs.AIs.ToArray(); _pendingAction = () => { StoredAIs.Refresh(); var aisAfter = StoredAIs.AIs.ToArray(); var deletedIds = aisBefore.Except(aisAfter).Select(ai => ai.aiId).ToArray(); AIEditorWindow.Unload(deletedIds); }; break; } case "Duplicate": { //identify all additions and re-ID them. var aisBefore = StoredAIs.AIs.ToArray(); _pendingAction = () => { StoredAIs.Refresh(); var aisAfter = StoredAIs.AIs.ToArray(); var addedAis = aisAfter.Except(aisBefore); foreach (var copiedAI in addedAis) { var ui = AIUI.Load(copiedAI, false); if (ui != null) { ui.ai.RegenerateIds(); copiedAI.aiId = ui.ai.id.ToString(); ui.Save(null); } else { var path = AssetDatabase.GetAssetPath(copiedAI); AssetDatabase.DeleteAsset(path); } } }; break; } } EditorAsync.ExecuteDelayed( () => { _pendingAction(); _pendingAction = null; }, delay); return(consumeEvent); }
private static void DeserializeQualifier(StageElement aiElement, StageElement viewElement, AIUI targetUI) { var parent = targetUI.currentSelector; if (parent == null) { EditorUtility.DisplayDialog("Invalid Action", "You must select a Selector before pasting a Qualifier.", "Ok"); } var requiresInit = new List <IInitializeAfterDeserialization>(); var qualifierView = ReadQualifierView(viewElement, parent); var qualifier = SerializationMaster.Unstage <IQualifier>(aiElement, requiresInit); qualifierView.Reconnect(qualifier); //Do the post deserialize initialization here if (requiresInit.Count == 1) { requiresInit[0].Initialize(targetUI.ai); } qualifierView.PruneBrokenConnections(); if (qualifierView.isDefault) { if (EditorUtility.DisplayDialog("Confirm Replacement", "Do you wish to replace the current Default Qualifier?", "Yes", "No")) { targetUI.ReplaceDefaultQualifier(qualifierView, parent); } } else { targetUI.AddQualifier(qualifierView, parent); } }
private static void DeserializeSelectorViews(StageElement[] aiElements, StageElement[] viewElements, AIUI targetUI, Vector2 referencePos, Vector2 mousePos, List <TopLevelView> newViews, bool regenIds) { var requiresInit = new List <IInitializeAfterDeserialization>(); var selectorViews = new List <SelectorView>(aiElements.Length); for (int i = 0; i < aiElements.Length; i++) { var selectorView = ReadSelectorView(viewElements[i], targetUI); var selector = SerializationMaster.Unstage <Selector>(aiElements[i], requiresInit); targetUI.canvas.views.Add(selectorView); targetUI.ai.AddSelector(selector); selectorView.Reconnect(selector); selectorViews.Add(selectorView); newViews.Add(selectorView); targetUI.undoRedo.Do(new AddSelectorOperation(targetUI, selectorView)); } //Set the root if pasting to a blank canvas if (targetUI.ai.rootSelector == null) { targetUI.ai.rootSelector = selectorViews[0].selector; targetUI.undoRedo.Do(new SetRootOperation(targetUI, null, selectorViews[0].selector)); } //Do the post deserialize initialization here var count = requiresInit.Count; for (int i = 0; i < count; i++) { requiresInit[i].Initialize(targetUI.ai); } //Finally adjust the positioning of pasted elements and prune broken connections, i.e. SelectorAction that no longer points to a selector for (int i = 0; i < aiElements.Length; i++) { var selectorView = selectorViews[i]; selectorView.PruneBrokenConnections(); if (regenIds) { //We also regen the id since this allows for pasting the same copy multiple times selectorView.selector.RegenerateId(); } // first treat the top-left-most selector as the origin point (reference pos) selectorView.viewArea.position -= referencePos; // secondly add the mouse offset to the position so as to paste it in where the mouse is at selectorView.viewArea.position += mousePos; } }
private static void AddSharedItems(GenericMenu menu, AIUI ui, bool allowDelete, Vector2 mousePos) { if (menu.GetItemCount() > 0) { menu.AddSeparator(string.Empty); } if (ui.undoRedo.canUndo) { menu.AddItem(new GUIContent(string.Concat("Undo (", ctrlOrCmd, " + Shift + Z)")), false, () => ui.undoRedo.Undo()); } else { menu.AddDisabledItem(new GUIContent(string.Concat("Undo (", ctrlOrCmd, " + Shift + Z)"))); } if (ui.undoRedo.canRedo) { menu.AddItem(new GUIContent(string.Concat("Redo (", ctrlOrCmd, " + Shift + Y)")), false, () => ui.undoRedo.Redo()); } else { menu.AddDisabledItem(new GUIContent(string.Concat("Redo (", ctrlOrCmd, " + Shift + Y)"))); } menu.AddSeparator(string.Empty); var hasSelection = ui.selectedViews.Count > 0 || ui.currentAction != null || ui.currentQualifier != null || ui.currentSelector != null; if (hasSelection) { menu.AddItem(new GUIContent(string.Concat("Cut (", ctrlOrCmd, " + X)")), false, () => ClipboardService.CutToClipboard(ui)); menu.AddItem(new GUIContent(string.Concat("Copy (", ctrlOrCmd, " + C)")), false, () => ClipboardService.CopyToClipboard(ui)); menu.AddItem(new GUIContent(string.Concat("Duplicate (", ctrlOrCmd, " + D)")), false, () => ClipboardService.Duplicate(ui, mousePos)); } else { menu.AddDisabledItem(new GUIContent(string.Concat("Cut (", ctrlOrCmd, " + X)"))); menu.AddDisabledItem(new GUIContent(string.Concat("Copy (", ctrlOrCmd, " + C)"))); menu.AddDisabledItem(new GUIContent(string.Concat("Duplicate (", ctrlOrCmd, " + D)"))); } if (!string.IsNullOrEmpty(EditorGUIUtility.systemCopyBuffer)) { menu.AddItem(new GUIContent(string.Concat("Paste (", ctrlOrCmd, " + V)")), false, () => ClipboardService.PasteFromClipboard(ui, mousePos)); } else { menu.AddDisabledItem(new GUIContent(string.Concat("Paste (", ctrlOrCmd, " + V)"))); } menu.AddSeparator(string.Empty); menu.AddItem(new GUIContent(string.Concat("Select All (", ctrlOrCmd, " + A)")), false, () => ui.MultiSelectViews(ui.canvas.views)); if (allowDelete) { menu.AddSeparator(string.Empty); if (hasSelection) { menu.AddItem(new GUIContent("Delete (Del)"), false, () => ui.RemoveSelected()); } else { menu.AddDisabledItem(new GUIContent("Delete (Del)")); } } menu.ShowAsContext(); }
internal static void ShowViewMenu(AIUI ui, Vector2 mousePos) { var menu = new GenericMenu(); var screenPos = EditorGUIUtility.GUIToScreenPoint(mousePos); bool allowDelete = true; if (ui.currentAction != null) { var qv = ui.currentQualifier; Action <Type> cb = (t) => { var newInstance = (IAction)Activator.CreateInstance(t); ui.ReplaceAction(qv, newInstance); }; menu.AddItem(new GUIContent("Change Type"), false, () => AIEntitySelectorWindow.Get <IAction>(screenPos, cb)); } else if (ui.currentQualifier != null) { string label = (ui.currentAction == null && ui.currentQualifier.actionView == null) ? "Add Action" : "Replace Action"; menu.AddItem(new GUIContent(label), false, () => AIEntitySelectorWindow.Get <IAction>(screenPos, (actionType) => { ui.SetAction(actionType); })); menu.AddItem(new GUIContent("Add Qualifier (sibling)"), false, () => AIEntitySelectorWindow.Get <IQualifier>(screenPos, (qualifierType) => { ui.AddQualifier(qualifierType); })); var qv = ui.currentQualifier; if (qv.isDefault) { allowDelete = false; } else { Action <Type> cb = (t) => { var newInstance = (IQualifier)Activator.CreateInstance(t); ui.ReplaceQualifier(qv, newInstance); }; menu.AddSeparator(string.Empty); menu.AddItem(new GUIContent("Change Type"), false, () => AIEntitySelectorWindow.Get <IQualifier>(screenPos, cb)); } } else if (ui.currentSelector != null) { var sv = ui.currentSelector; menu.AddItem(new GUIContent("Add Qualifier"), false, () => AIEntitySelectorWindow.Get <IQualifier>(screenPos, (qualifierType) => { ui.AddQualifier(qualifierType); })); menu.AddSeparator(string.Empty); if (sv.isRoot) { allowDelete = false; } else { menu.AddItem(new GUIContent("Set as Root"), false, () => ui.SetRoot(sv.selector)); } Action <Type> cb = (t) => { var newInstance = (Selector)Activator.CreateInstance(t); ui.ReplaceSelector(sv, newInstance); }; menu.AddItem(new GUIContent("Change Type"), false, () => AIEntitySelectorWindow.Get <Selector>(screenPos, cb)); } else if (ui.currentAILink != null) { var alv = ui.currentAILink; Action <AIStorage> cb = (ai) => { ui.ChangeAILink(alv, new Guid(ai.aiId)); }; menu.AddItem(new GUIContent("Change AI"), false, () => AISelectorWindow.Get(screenPos, cb)); } AddSharedItems(menu, ui, allowDelete, mousePos); }
internal static void Duplicate(AIUI sourceUI, Vector2 mousePos) { CopyToClipboard(sourceUI); PasteFromClipboard(sourceUI, mousePos); }