public PlayerAssetData(int pId)
        {
            playerId = pId;

            assetData                = new Dictionary <string,Sprite>();
            playerSpawnedCentrals    = new AutoPopulationList <AbilityCentralThreadPool>();
            internalFreeSpaceTracker = new List <int>();
            globalVariables          = new Dictionary <string,Tuple <int,int,int> >();
            //globalVariables = new Dictionary<int, Dictionary<string, VariableInterfaces>>();
        }
    void Start()
    {
        string cData = FileSaver.sFT[FileSaverTypes.PLAYER_GENERATED_DATA].GenericLoadTrigger(new string[] { AbilityPageScript.selectedAbility }, 0);
        string wData = FileSaver.sFT[FileSaverTypes.PLAYER_GENERATED_DATA].GenericLoadTrigger(new string[] { AbilityPageScript.selectedAbility }, 2);

        if (cData != "")
        {
            abilityData = new UIAbilityData(LoadedData.GetSingleton <JSONFileConvertor>().ConvertToData(JsonConvert.DeserializeObject <StandardJSONFileFormat[]>(cData)), JsonConvert.DeserializeObject <float[][]>(wData));
        }
        else
        {
            abilityData = new UIAbilityData();
        }


        abilityWindows = new AutoPopulationList <EditableWindow>();
        lineData       = new AutoPopulationList <LineData>();

        SpawnUIFromData();

        mainClassSelection = LoadedData.GetSingleton <UIDrawer>().CreateScriptedObject(typeof(LinearLayout));

        SpawnerOutput name = LoadedData.GetSingleton <UIDrawer>().CreateScriptedObject(typeof(InputFieldWrapper));

        name.script.transform.position = UIDrawer.UINormalisedPosition(new Vector3(0.5f, 0.9f));

        InputField castedName = LoadedData.GetSingleton <UIDrawer>().GetTypeInElement <InputField>(name);

        string data = FileSaver.sFT[FileSaverTypes.PLAYER_GENERATED_DATA].GenericLoadTrigger(new string[] { AbilityPageScript.selectedAbility }, 1);

        abilityDescription = JsonConvert.DeserializeObject <AbilityInfo>(data);
        castedName.text    = abilityDescription.n;

        castedName.onValueChanged.AddListener((s) => {
            abilityDescription.n = s;
        });

        SpawnerOutput[] buttons = new SpawnerOutput[LoadedData.loadedNodeInstance.Count];


        foreach (KeyValuePair <Type, AbilityTreeNode> entry in LoadedData.loadedNodeInstance)
        {
            SpawnerOutput button = LoadedData.GetSingleton <UIDrawer>().CreateScriptedObject(typeof(ButtonWrapper));

            Button butInst = LoadedData.GetSingleton <UIDrawer>().GetTypeInElement <Button>(button);

            // Need another way to get elements within spawner output...
            LoadedData.GetSingleton <UIDrawer>().GetTypeInElement <Text>(button, "Text").text = entry.Key.Name;

            butInst.onClick.AddListener(() => {
                selectedType = entry.Key;
                windowSpawner.script.gameObject.SetActive(true);
                mMode = MouseMode.CREATE_NODE;
            });

            (mainClassSelection.script as LinearLayout).Add(butInst.transform as RectTransform);
        }

        classSelectionScrollRect = LoadedData.GetSingleton <UIDrawer>().CreateScriptedObject(typeof(ScrollRectWrapper));
        (classSelectionScrollRect.script as ScrollRectWrapper).ChangeScrollRectSize(new Vector2(100, 600));


        LoadedData.GetSingleton <UIDrawer>().GetTypeInElement <UIMule>(classSelectionScrollRect, "Content").GetRectTransform().sizeDelta = (mainClassSelection.script.transform as RectTransform).sizeDelta;
        classSelectionScrollRect.script.transform.position = UIDrawer.UINormalisedPosition(new Vector3(0.1f, 0.6f));

        mainClassSelection.script.transform.SetParent(LoadedData.GetSingleton <UIDrawer>().GetTypeInElement <UIMule>(classSelectionScrollRect, "Content").transform);
        mainClassSelection.script.transform.localPosition = new Vector2(-(mainClassSelection.script.transform as RectTransform).sizeDelta.x / 2, 0);


        windowSpawner = LoadedData.GetSingleton <UIDrawer>().CreateScriptedObject(typeof(Image));
        windowSpawner.script.gameObject.SetActive(false);

        SpawnerOutput optLL = LoadedData.GetSingleton <UIDrawer>().CreateScriptedObject(typeof(LinearLayout));

        SpawnerOutput normConnButt = LoadedData.GetSingleton <UIDrawer>().CreateScriptedObject(typeof(ButtonWrapper));

        LoadedData.GetSingleton <UIDrawer>().GetTypeInElement <Text>(normConnButt, "Text").text    = "Normal Conection";
        LoadedData.GetSingleton <UIDrawer>().GetTypeInElement <Image>(normConnButt, "Image").color = Color.green;

        LoadedData.GetSingleton <UIDrawer>().GetTypeInElement <Button>(normConnButt).onClick.AddListener(() => {
            mMode = MouseMode.EDIT_CONN;
            lMode = LinkMode.NORMAL;
        });

        SpawnerOutput sigConnButt = LoadedData.GetSingleton <UIDrawer>().CreateScriptedObject(typeof(ButtonWrapper));

        LoadedData.GetSingleton <UIDrawer>().GetTypeInElement <Text>(sigConnButt, "Text").text    = "Signal Conection";
        LoadedData.GetSingleton <UIDrawer>().GetTypeInElement <Image>(sigConnButt, "Image").color = Color.red;

        LoadedData.GetSingleton <UIDrawer>().GetTypeInElement <Button>(sigConnButt).onClick.AddListener(() => {
            mMode = MouseMode.EDIT_CONN;
            lMode = LinkMode.SIGNAL;
        });

        SpawnerOutput rmConnButt = LoadedData.GetSingleton <UIDrawer>().CreateScriptedObject(typeof(ButtonWrapper));

        LoadedData.GetSingleton <UIDrawer>().GetTypeInElement <Text>(rmConnButt,"Text").text = "Remove Conection";

        LoadedData.GetSingleton <UIDrawer>().GetTypeInElement <Button>(rmConnButt).onClick.AddListener(() => {
            mMode = MouseMode.REMOVE_CONN;
        });

        LoadedData.GetSingleton <UIDrawer>().GetTypeInElement <LinearLayout>(optLL).Add(normConnButt.script.transform as RectTransform);
        LoadedData.GetSingleton <UIDrawer>().GetTypeInElement <LinearLayout>(optLL).Add(sigConnButt.script.transform as RectTransform);
        LoadedData.GetSingleton <UIDrawer>().GetTypeInElement <LinearLayout>(optLL).Add(rmConnButt.script.transform as RectTransform);

        optLL.script.transform.position = UIDrawer.UINormalisedPosition(new Vector3(0.9f,0.9f));

        SpawnerOutput saveButton = LoadedData.GetSingleton <UIDrawer>().CreateScriptedObject(typeof(ButtonWrapper));

        LoadedData.GetSingleton <UIDrawer>().GetTypeInElement <Button>(saveButton).onClick.AddListener(() => {
            int[] aEle = abilityData.subclasses.ReturnActiveElementIndex();

            AbilityDataSubclass[] cAD = abilityData.RelinkSubclass();

            string[] imgDependencies = AbilityDataSubclass.GetImageDependencies(cAD);

            // Gets all window locations.
            float[][] windowLocations = new float[cAD.Length][];

            for (int i = 0; i < windowLocations.Length; i++)
            {
                windowLocations[i] = new float[2];

                windowLocations[i][0] = abilityWindows.l[aEle[i]].transform.position.x;
                windowLocations[i][1] = abilityWindows.l[aEle[i]].transform.position.y;
            }

            FileSaver.sFT[FileSaverTypes.PLAYER_GENERATED_DATA].GenericSaveTrigger(new string[] { AbilityPageScript.selectedAbility },0,JsonConvert.SerializeObject(LoadedData.GetSingleton <JSONFileConvertor>().ConvertToStandard(cAD)));
            FileSaver.sFT[FileSaverTypes.PLAYER_GENERATED_DATA].GenericSaveTrigger(new string[] { AbilityPageScript.selectedAbility }, 1, JsonConvert.SerializeObject(abilityDescription));
            FileSaver.sFT[FileSaverTypes.PLAYER_GENERATED_DATA].GenericSaveTrigger(new string[] { AbilityPageScript.selectedAbility }, 2, JsonConvert.SerializeObject(windowLocations));
            FileSaver.sFT[FileSaverTypes.PLAYER_GENERATED_DATA].GenericSaveTrigger(new string[] { AbilityPageScript.selectedAbility }, 3, JsonConvert.SerializeObject(imgDependencies));
        });

        LoadedData.GetSingleton <UIDrawer>().GetTypeInElement <Text>(saveButton, "Text").text = "Save JSON";
        saveButton.script.transform.position = UIDrawer.UINormalisedPosition(new Vector3(0.5f, 0.1f));


        // Creates dropdown for input.
        kcDdL = new KeyCodeDropdownList(abilityDescription.kC);
        kcDdL.ReturnDropdownWrapper().transform.position = UIDrawer.UINormalisedPosition(new Vector3(0.75f, 0.9f));

        kcDdL.ReturnDropdownWrapper().dropdown.onValueChanged.AddListener((v) => {
            abilityDescription.kC = KeyCodeDropdownList.inputValues[v];
        });

        // Creates dropdown for startnode.
        //DropdownWrapper sNDW = LoadedData.GetSingleton<UIDrawer>().CreateScriptedObject(typeof(DropdownWrapper)).script as DropdownWrapper;



        ButtonWrapper addOptionsButton = LoadedData.GetSingleton <UIDrawer>().CreateScriptedObject(typeof(ButtonWrapper)).script as ButtonWrapper;

        addOptionsButton.button.onClick.AddListener(() => CreateWindowForAdditionalOptions());

        addOptionsButton.text.text          = "Additional Options";
        addOptionsButton.transform.position = UIDrawer.UINormalisedPosition(new Vector3(0.1f, 0.2f));

        ButtonWrapper exitBlueprintMaker = LoadedData.GetSingleton <UIDrawer>().CreateScriptedObject(typeof(ButtonWrapper)).script as ButtonWrapper;

        exitBlueprintMaker.button.onClick.AddListener(() => SceneTransitionData.LoadScene("AbilityPage"));
        exitBlueprintMaker.text.text          = "Exit";
        exitBlueprintMaker.transform.position = UIDrawer.UINormalisedPosition(new Vector3(0.1f, 0.1f));
    }
    void RetrieveStartNodes()
    {
        int nonPsuedoNodes = dataVar.Length - 2;

        AutoPopulationList <bool> connected = new AutoPopulationList <bool>(nonPsuedoNodes);

        for (int i = 0; i < nonPsuedoNodes; i++)
        {
            int totalCurrLinks = 0;

            for (int j = 0; j < dataVar[i].Length; j++)
            {
                totalCurrLinks += dataVar[i][j].links.Length;

                for (int k = 0; k < dataVar[i][j].links.Length; k++)
                {
                    int[] currLink = dataVar[i][j].links[k];

                    // Marks target as true so it can't be root.
                    connected.ModifyElementAt(currLink[0], true);
                }
            }

            if (totalCurrLinks == 0)
            {
                dataVar[i][dataVar[i].Length - 1].links = new int[][] { new int[] { dataVar.Length - 1, 0, 0 } }
            }
            ;
        }

        List <int[]> rC = new List <int[]>();

        for (int i = 0; i < connected.l.Count; i++)
        {
            if (!connected.l[i])
            {
                rC.Add(new int[] { i, 0, 1 });
            }
        }

        rootSubclasses = rC.ToArray();
    }

    void RunNodeFlow(int nextNode, int targetVar, Tuple <int, int, int>[] pN = null)
    {
        int[] lC = LoadedData.loadedNodeInstance[dataType[nextNode]].ReturnLinkChannels();

        for (int k = 0; k < lC.Length; k++)
        {
            if (pN != null)
            {
                Tuple <int, int, int> precedingNode = pN[lC[k]];

                if (linkGenerator[lC[k]][precedingNode.Item1][precedingNode.Item2] == null)
                {
                    linkGenerator[lC[k]][precedingNode.Item1][precedingNode.Item2] = new HashSet <Tuple <int, int, int> >();
                }

                Tuple <int, int, int> currNode = Tuple.Create(nextNode, targetVar, precedingNode.Item3);

                if (!linkGenerator[lC[k]][precedingNode.Item1][precedingNode.Item2].Contains(currNode))
                {
                    linkGenerator[lC[k]][precedingNode.Item1][precedingNode.Item2].Add(currNode);
                }
            }
        }


        //if(LoadedData.loadedNodeInstance[dataType[nextNode]] is INodeNetworkPoint)
        //progenitor = nextNode;
        //Debug.LogFormat("Curr Node: {0}, {1}", nextNode,dataType[nextNode]);
        for (int i = 0; i < dataVar[nextNode].Length; i++)
        {
            for (int j = 0; j < dataVar[nextNode][i].links.Length; j++)
            {
                int[] currLink = dataVar[nextNode][i].links[j];

                // Adds links to rhs.
                Tuple <int, int, int, int> rhslinkTup = Tuple.Create(currLink[0], currLink[1], currLink[2], j);

                if (!linkData[nextNode].rHS.Contains(rhslinkTup))
                {
                    linkData[nextNode].rHS.Add(rhslinkTup);
                }

                // Adds links to target lhs.
                Tuple <int, int, int, int> lhslinkTup = Tuple.Create(nextNode, i, currLink[2], j);

                if (!linkData[currLink[0]].lHS.Contains(lhslinkTup))
                {
                    linkData[currLink[0]].lHS.Add(lhslinkTup);
                }


                Tuple <int, int, int>         nextNodeRef    = Tuple.Create <int, int, int>(nextNode, i, currLink[2]);
                List <Tuple <int, int, int> > precedingArray = new List <Tuple <int, int, int> >();

                if (pN != null)
                {
                    precedingArray.AddRange(pN);
                }
                else
                {
                    precedingArray.Add(null);
                    precedingArray.Add(null);
                }

                for (int k = 0; k < lC.Length; k++)
                {
                    precedingArray[lC[k]] = nextNodeRef;
                }

                // Iterates to target.
                RunNodeFlow(currLink[0], currLink[1], precedingArray.ToArray());
            }
        }

        //Debug.LogWarningFormat("End of Node: {0}, {1}", nextNode, dataType[nextNode]);
    }

    void GenerateLinks()
    {
        // Generate links after
        generatedLinks = new int[linkGenerator.Length][][][][];

        for (int i = 0; i < linkGenerator.Length; i++)
        {
            generatedLinks[i] = new int[linkGenerator[i].Length][][][];

            for (int j = 0; j < linkGenerator[i].Length; j++)
            {
                generatedLinks[i][j] = new int[linkGenerator[i][j].Length][][];

                for (int k = 0; k < linkGenerator[i][j].Length; k++)
                {
                    List <int[]> convertedLinks = new List <int[]>();
                    //generatedLinks[i][j][k] = new int[linkGenerator[i][j][k].Count];

                    if (linkGenerator[i][j][k] != null)
                    {
                        foreach (var item in linkGenerator[i][j][k])
                        {
                            convertedLinks.Add(new int[] { item.Item1, item.Item2, item.Item3 });
                        }
                    }


                    //Debug.LogFormat("Generating for: {0}, {1}, {2}", i, j, k);
                    generatedLinks[i][j][k] = convertedLinks.ToArray();
                }
            }
        }
    }

    void EditLinks()
    {
        lM = new LinkModifier();

        for (currBuildNode = 0; currBuildNode < dataType.Length; currBuildNode++)
        {
            LoadedData.loadedNodeInstance[dataType[currBuildNode]].ConstructionPhase(this);
        }
        //LoadedData.loadedNodeInstance[dataType[i]].LinkEdit(i, lD, lM, dataVar);

        foreach (var add in lM.add)
        {
            List <int[]> links = new List <int[]>(dataVar[add.Key.Item1][add.Key.Item2].links);

            foreach (var ele in add.Value)
            {
                links.Add(new int[] { ele.Item1, ele.Item2, ele.Item3 });
                Debug.LogFormat("Adding to {0},{1}. Content: {2},{3}", add.Key.Item1, add.Key.Item2, ele.Item1, ele.Item2);
            }

            dataVar[add.Key.Item1][add.Key.Item2].links = links.ToArray();
        }

        foreach (var rm in lM.remove)
        {
            int[] rmArr = rm.Value.ToArray();
            Array.Sort(rmArr);

            List <int[]> links = new List <int[]>(dataVar[rm.Key.Item1][rm.Key.Item2].links);

            for (int i = rmArr.Length - 1; i >= 0; i--)
            {
                Debug.LogFormat("Removing at {0},{1}. Content: {2},{3}", rm.Key.Item1, rm.Key.Item2, links[rmArr[i]][0], links[rmArr[i]][0]);
                links.RemoveAt(rmArr[i]);
            }

            dataVar[rm.Key.Item1][rm.Key.Item2].links = links.ToArray();
        }
    }

    void BeginDepenciesBuild()
    {
        nodeBranchingData    = new int[dataVar.Length];
        autoManagedVariables = new int[dataVar.Length][];
        boolData             = new AbilityBooleanData(dataVar);

        for (int i = 0; i < dataVar.Length; i++)
        {
            List <int> aMVar            = new List <int>();
            List <int> networkVariables = new List <int>();
            //Debug.Log("Printing for Node: " + i);

            for (int j = 0; j < dataVar[i].Length; j++)
            {
                //Debug.Log("Printing for Variable: " + j);
                bool interchangeable = LoadedData.GetVariableType(dataType[i], j, VariableTypes.INTERCHANGEABLE);

                AutoPopulationList <List <int[]> > varLinks = new AutoPopulationList <List <int[]> >(1);

                for (int k = 0; k < dataVar[i][j].links.Length; k++)
                {
                    int[] currLink = dataVar[i][j].links[k];

                    //Debug.LogFormat("{0},{1}", currLink[0], currLink[1]);

                    bool signal = currLink[2] == (int)LinkMode.SIGNAL ? true : false;//LoadedData.GetVariableType(dataType[i], j, VariableTypes.SIGNAL_ONLY);
                    // Marks target as true so it will be blocked.
                    if (!signal)
                    {
                        if (dataVar[i][j].field.t == dataVar[currLink[0]][currLink[1]].field.t || interchangeable)
                        {
                            boolData.varsBlocked[currLink[0]][currLink[1]] = true;
                            //Debug.LogFormat("From Node {0} Variable {1} link {2} name {3}", i, j, k, dataVar[i][j].field.n);
                            //Debug.LogFormat("To Node {0} Variable {1} link {2} signal {3} interchange {4} name {5}", currLink[0], currLink[1], k, signal, interchangeable, dataVar[i][j].field.n);
                            //Debug.Log("This was called true.");
                        }
                    }
                }

                if (LoadedData.GetVariableType(dataType[i],j,VariableTypes.BLOCKED))
                {
                    boolData.varsBlocked[i][j] = true;
                }

                if (LoadedData.GetVariableType(dataType[i],j,VariableTypes.AUTO_MANAGED))
                {
                    aMVar.Add(j);
                }


                if (!LoadedData.GetVariableType(dataType[i],j,VariableTypes.NON_LINK))
                {
                    nodeBranchingData[i] += dataVar[i][j].links.Length;
                }

                if (LoadedData.GetVariableType(dataType[i],j,VariableTypes.GLOBAL_VARIABLE))
                {
                    string gVN = (dataVar[i][j].field as RuntimeParameters <string>).v;
                    if (!AbilitiesManager.GetAssetData(playerId).globalVariables.ContainsKey(gVN))
                    {
                        AbilitiesManager.GetAssetData(playerId).globalVariables.Add(gVN,null);
                    }
                }

                if (LoadedData.GetVariableType(dataType[i],j,VariableTypes.NETWORK))
                {
                    networkVariables.Add(j);
                }
            }

            autoManagedVariables[i] = aMVar.ToArray();

            if (networkVariables.Count > 0)
            {
                nodeNetworkVariables.Add(i,networkVariables.ToArray());
            }
            //aMVar.Add(j);
        }
    }