Newer
Older
Dreamsturbia-Project-IADE-Unity3D / Assets / Editor / FSMGraphView.cs
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)
                {
                   // RemoveStateNode((StateNode)element);
                  
                    statesToRemove.Add((StateNode)element);
                }
            }
        }

       

        return change;


    }

    //runs on build
    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);
                    //TransitionEditorWindow.Init(transitionFound);
                    selectedCache = (Edge)selected;
                }
            }
        }
        return transitions.ToArray();
       // TransitionEditorWindow.Init(transitions.ToArray());


    }

    private void AddGridBackground()
    {
        GridBackground gridBackground = new GridBackground();

        gridBackground.StretchToParentSize();

        Insert(0, gridBackground);
       

    }

    private void AddManipulators()
    {
        this.AddManipulator(CreateNodeContextualMenu());
      //  this.AddManipulator(LoadContextualMenu());
        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);

                }

                //ObjectField actionsObjectField in primary.actions.ToArray()
                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;



                //AssetDatabase.CreateAsset(primary.state, string.Empty);




                if (stateNode.state != null)
                {
                    /* string combinedPath = System.IO.Path.GetRelativePath(Application.dataPath,System.IO.Path.Combine(path,"States", stateNode.titleInputField.value));
                     combinedPath = System.IO.Path.Combine("Assets", combinedPath);
                     AssetDatabase.CreateAsset(stateNode.state, combinedPath + ".asset");*/
                    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));
        
    }
   

}