- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEditor;
- using UnityEditor.Experimental.GraphView;
- using UnityEngine.UIElements;
- using UnityEditor.UIElements;
- using System.IO;
- public class FSMGraphView : GraphView
- {
- private Edge selectedCache;
- public AIGraphWindow instance;
- public string savePath = "Assets/ScriptableObjects/FSM/";
- private Dictionary<Edge,Transition> edgeTransitionTupleList = new Dictionary<Edge, Transition>();
- private List<StateNode> statesToRemove = new List<StateNode>();
- private List<Edge> edgesToRemove = new List<Edge>();
-
- public FSMGraphView()
- {
- AddGridBackground();
- AddManipulators();
- graphViewChanged = OnGraphViewChange;
-
- }
- private GraphViewChange OnGraphViewChange(GraphViewChange change)
- {
- if (change.edgesToCreate != null)
- {
- foreach (Edge edge in change.edgesToCreate)
- {
- Transition newTransition = ScriptableObject.CreateInstance<Transition>();
- StateNode goalStateNode = (StateNode)edge.input.node;
- StateNode sourceStateNode = (StateNode)edge.output.node;
- newTransition.name = sourceStateNode.titleInputField.value+goalStateNode.titleInputField.value + "Transition";
- newTransition.goalState = goalStateNode.state;
- edgeTransitionTupleList.Add(edge, newTransition);
-
- }
- }
- if (change.elementsToRemove != null)
- {
- foreach (GraphElement element in change.elementsToRemove)
- {
- if (element is Edge)
- {
-
- edgesToRemove.Add((Edge)element);
- }
- if (element is StateNode)
- {
-
-
- statesToRemove.Add((StateNode)element);
- }
- }
- }
-
- return change;
- }
-
- private void RegisterTransitions()
- {
- foreach (Port p in ports)
- {
- if (p.direction == Direction.Output)
- {
- if (p.connected && p.node is StateNode)
- {
- List<Transition> transitionsToBeAdded = new List<Transition>();
- StateNode sn = (StateNode)p.node;
- foreach (Edge e in p.connections)
- {
- Transition targetTransition = null;
- if (edgeTransitionTupleList.TryGetValue(e, out targetTransition))
- {
- transitionsToBeAdded.Add(targetTransition);
- }
- }
- sn.state.transitions = transitionsToBeAdded.ToArray();
- }
- }
- }
- }
-
- public void ClearGraph()
- {
- graphElements.ForEach(grapElement => RemoveElement(grapElement));
- edgeTransitionTupleList.Clear();
- statesToRemove.Clear();
- edgesToRemove.Clear();
- }
-
- public void OnGUI()
- {
-
-
- }
- public Transition[] OpenTransitions()
- {
- List<Transition> transitions = new List<Transition>();
- foreach (ISelectable selected in selection)
- {
- if (selected is Edge)
- {
- Transition transitionFound;
- if (edgeTransitionTupleList.TryGetValue((Edge)selected, out transitionFound))
- {
- transitions.Add(transitionFound);
-
- selectedCache = (Edge)selected;
- }
- }
- }
- return transitions.ToArray();
-
- }
- private void AddGridBackground()
- {
- GridBackground gridBackground = new GridBackground();
- gridBackground.StretchToParentSize();
- Insert(0, gridBackground);
-
- }
- private void AddManipulators()
- {
- this.AddManipulator(CreateNodeContextualMenu());
-
- this.AddManipulator(new SelectionDragger());
- this.AddManipulator(new ContentDragger());
- this.AddManipulator(new ContentZoomer());
- }
- private IManipulator CreateNodeContextualMenu()
- {
- ContextualMenuManipulator contextualMenuManipulator = new ContextualMenuManipulator(
- menuEvent => menuEvent.menu.AppendAction("Add State", actionEvent => AddElement(CreateStateNode(actionEvent.eventInfo.localMousePosition)))
- );
- return contextualMenuManipulator;
- }
-
- public void Load(FSMSave loadSource)
- {
- if (loadSource == null) return;
- ClearGraph();
- if (loadSource.states != null)
- {
- foreach (FSMSave.SavedElement s in loadSource.states)
- {
- StateNode st = RecreateStateNode(s.position, s.node);
- AddElement(st);
- }
- }
- foreach (Node nodElement in nodes)
- {
- StateNode st = (StateNode)nodElement;
- st.titleInputField.value = st.state.name;
- if (st.state.transitions != null)
- {
- foreach (Transition transition in st.state.transitions)
- {
- if (transition != null)
- {
- LoadTrasition(loadSource, st, transition);
- }
- }
- }
- }
-
- }
- private void LoadTrasition(FSMSave sv,StateNode sourceState,Transition transition)
- {
- FSMSave.SavedElement st = sv.states.Find((FSMSave.SavedElement savedState) => {
- return savedState.node == transition.goalState;
- });
- foreach (Node n in nodes)
- {
- StateNode targetStateNode = (StateNode)n;
- if (targetStateNode.state == st.node)
- {
- Edge newEdge = sourceState.outputPort.ConnectTo(targetStateNode.inputPort);
- AddElement(newEdge);
- edgeTransitionTupleList.Add(newEdge, transition);
-
- }
- }
- sourceState.RefreshPorts();
- sourceState.RefreshExpandedState();
- }
- public StateNode CreateStateNode(Vector2 pos)
- {
- StateNode st = new StateNode(ScriptableObject.CreateInstance<State>());
- st.Initialize(pos);
- st.Draw();
- return st;
- }
- public StateNode RecreateStateNode(Vector2 pos,State state)
- {
- StateNode st = new StateNode(state);
- st.Initialize(pos);
- st.Draw();
- return st;
- }
- public override List<Port> GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter)
- {
- List<Port> compatiblePorts = new List<Port>();
- ports.ForEach((Port port) => {
- if (port == startPort)
- {
- return;
- }
- if (startPort.node == port.node)
- {
- return;
- }
- if (startPort.direction == port.direction)
- {
- return;
- }
- compatiblePorts.Add(port);
- });
- return compatiblePorts;
- }
- public void Save()
- {
- RegisterTransitions();
- ActualSave(instance.saveFile);
- }
- private void ActualSave(FSMSave sv)
- {
- string path = instance.rootDirectory;
- foreach (Node currentNode in nodes)
- {
- if (currentNode is StateNode)
- {
- StateNode stateNode = (StateNode)currentNode;
- stateNode.state.entryAction = (Action)stateNode.entry.value;
- Action[] actionArray = new Action[stateNode.actions.Count];
- if (stateNode.state != null)
- {
- EditorUtility.SetDirty(stateNode.state);
- }
-
- for (int i = 0; i < actionArray.Length; i++)
- {
- actionArray[i] = (Action)stateNode.actions[i].value;
- }
- stateNode.state.actions = actionArray;
- stateNode.state.exitAction = (Action)stateNode.exit.value;
-
- if (stateNode.state != null)
- {
-
- if (!PathExists(path, "States", stateNode.titleInputField.value + ".asset"))
- {
- string finalPath = LocatePathOrCreateFolder(path, "States", stateNode.titleInputField.value);
- AssetDatabase.CreateAsset(stateNode.state, finalPath);
- if (instance.saveFile.states != null)
- {
- if (!instance.saveFile.states.Exists((FSMSave.SavedElement element) => { return element.node == stateNode.state; }))
- {
- instance.saveFile.states.Add(new FSMSave.SavedElement(stateNode.state, stateNode.GetPosition().position));
- }
- }
- } else
- {
- if (instance.saveFile.states != null)
- {
- if (!instance.saveFile.states.Exists((FSMSave.SavedElement element) => { return element.node == stateNode.state; }))
- {
- instance.saveFile.states.Add(new FSMSave.SavedElement(stateNode.state, stateNode.GetPosition().position));
- }
- else
- {
- int index = instance.saveFile.states.FindIndex((FSMSave.SavedElement element) => { return element.node == stateNode.state; });
- instance.saveFile.states[index] = new FSMSave.SavedElement(stateNode.state, stateNode.GetPosition().position);
- }
- }
- }
- }
- }
- }
- foreach (Edge removalEdgeGoal in edgesToRemove)
- {
- Transition transitionToCleanup = null;
- if (edgeTransitionTupleList.TryGetValue(removalEdgeGoal, out transitionToCleanup))
- {
- foreach (StateNode st in nodes)
- {
- if (st.state.transitions != null)
- {
- RemoveTransitionFromState(st.state, transitionToCleanup);
- }
- RemoveTransition(transitionToCleanup);
- }
- }
- }
- foreach (StateNode stateNodeToRemove in statesToRemove)
- {
- State stateToRemove = stateNodeToRemove.state;
- if (sv.states.Exists((FSMSave.SavedElement stElement) => { return stElement.node == stateToRemove; }))
- {
-
- if (stateToRemove.transitions != null)
- {
- foreach (Transition removalTransition in stateToRemove.transitions)
- {
-
-
- if (removalTransition != null)
- {
-
- RemoveTransition(removalTransition);
- }
- }
- }
- edgesToRemove.Clear();
- AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(stateToRemove));
- sv.states.RemoveAll((FSMSave.SavedElement removePredicate) => {
- return removePredicate.node == stateToRemove;
- });
- }
- }
- statesToRemove.Clear();
- foreach (Edge e in edges)
- {
- Transition transition = null;
- if (edgeTransitionTupleList.TryGetValue(e, out transition))
- {
- if (!PathExists(path, "Transitions", transition.name + ".asset"))
- {
- string finalPath = LocatePathOrCreateFolder(path, "Transitions", transition.name);
- string assetId = Path.Combine(finalPath, "Transitions");
- AssetDatabase.CreateAsset(transition, finalPath);
- EditorUtility.SetDirty(transition);
- } else
- {
- EditorUtility.SetDirty(transition);
- }
- }
- }
- EditorUtility.SetDirty(instance.saveFile);
- AssetDatabase.SaveAssets();
- AssetDatabase.Refresh();
- EditorUtility.FocusProjectWindow();
- }
- private void RemoveTransition(Transition transition)
- {
- Edge edgeToClear = FindEdgeByTransition(transition);
- if (edgeToClear != null)
- {
- edgeTransitionTupleList.Remove(edgeToClear);
- }
- AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(transition));
- }
- private void RemoveTransitionFromState(State state, Transition targetTransition)
- {
- List<Transition> newTransitionList = new List<Transition>(state.transitions);
- if (newTransitionList.Contains(targetTransition))
- {
- newTransitionList.Remove(targetTransition);
- }
- state.transitions = newTransitionList.ToArray();
- }
- private Edge FindEdgeByTransition(Transition transition)
- {
- foreach (KeyValuePair<Edge,Transition> kvp in edgeTransitionTupleList)
- {
- if (kvp.Value == transition)
- {
- return kvp.Key;
- }
- }
- return null;
- }
- private string LocatePathOrCreateFolder(string path,string folder,string fileName)
- {
- string folderRelativePath = Path.GetRelativePath(Application.dataPath, path);
- string transitionFolder = string.Empty;
- if (folder != string.Empty)
- {
- if (!Directory.Exists(Path.Combine(path, folder)))
- {
- AssetDatabase.CreateFolder(Path.Combine("Assets", folderRelativePath), folder);
- transitionFolder = Path.Combine("Assets", folderRelativePath, folder);
- }
- else
- {
- transitionFolder = Path.Combine("Assets", folderRelativePath, folder);
- }
- } else
- {
- transitionFolder = Path.Combine("Assets", folderRelativePath);
- }
- return Path.Combine(transitionFolder, fileName + ".asset");
- }
- private bool PathExists(string path, string folders, string fileName)
- {
- return File.Exists(Path.Combine(path,folders,fileName));
-
- }
-
- }