private void deleteRDNode(RDNode node) { // function to effectively remove stock RD nodes node.tech.hideIfNoParts = true; clearParentsFromNode(node); clearChildrenFromNode(node); // move node outside the visible area in case it contains parts already researched (purchased parts doesn't seem to be reliably initialized upon entering space center) moveNode(node, 500, 0); // clear all part assignments on both the node and part side node.tech.partsAssigned.Clear(); foreach (AvailablePart tempPart in PartLoader.LoadedPartsList) { if (tempPart.TechRequired == node.tech.techID) { tempPart.TechRequired = "unassigned"; } } }
//draws arrows manually (not required atm) private void recreateArrows(RDNode rdNode) { if (rdNode.state != RDNode.State.HIDDEN) { for (int i = 0; i < rdNode.parents.Count(); ++i) { //Recreate Parent hopefully recreates incoming array? nope, doesnt, also not with calling UpdateGraphics and/or Setup not... //just changing the line does not update the graphics either. RDNode.Parent parentStruct = rdNode.parents[i]; if (parentStruct.line != null) { Vector.DestroyLine(ref parentStruct.line); } if (parentStruct.arrowHead != null) { GameObject.Destroy(parentStruct.arrowHead); } }//endfor foreach parentnode RDGridArea gridArea = GameObject.FindObjectOfType <RDGridArea>(); //typeof(RDNode).GetMethod("InitializeArrows", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(treeNode, new object[] { }); if (rdNode.state == RDNode.State.RESEARCHED || rdNode.state == RDNode.State.RESEARCHABLE) { typeof(RDNode).GetMethod("DrawArrow", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(rdNode, new object[] { gridArea.LineMaterial }); } else { typeof(RDNode).GetMethod("DrawArrow", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(rdNode, new object[] { gridArea.LineMaterialGray }); } } }
private void visitNode(RDNode rdNode, ref List <RDNode> sortedList, ref HashSet <RDNode> unmarkedNodes, ref HashSet <RDNode> markedNodes, ref HashSet <RDNode> tempMarkedNodes) { //Debug.Log("TOPOSORT visiting " + rdNode.gameObject.name); if (tempMarkedNodes.Contains(rdNode)) { throw new Exception("ATC: Circular dependency in Tech-Node Graph! RDNode " + rdNode.gameObject.name + " is in a circular dependency with one of its direct or indirect parents"); } if (!markedNodes.Contains(rdNode)) //this node has not been visited yet { tempMarkedNodes.Add(rdNode); //DFS-search recursive for all children foreach (RDNode child in rdNode.children) { visitNode(child, ref sortedList, ref unmarkedNodes, ref markedNodes, ref tempMarkedNodes); } //Debug.Log("TOPOSORT marking node " + rdNode.gameObject.name); markedNodes.Add(rdNode); tempMarkedNodes.Remove(rdNode); unmarkedNodes.Remove(rdNode); sortedList.Insert(0, rdNode);//prepend to list } }
private void processNewNodes(ConfigNode tree) { Debug.Log("processing all NEW_NODE items"); //RDController rdControl = GameObject.FindObjectOfType<RDController>(); List <RDNode> newRDNodes = new List <RDNode>(); try { foreach (ConfigNode cfgNodeNew in tree.GetNodes("NEW_NODE")) { //only create RDNodes that are not yet in the Techtree string newName = cfgNodeNew.GetValue("gameObjectName"); RDNode existingNode = GetNodeNamed(newName); //RDNode newNode = createNode(); RDNode newNode = RDNodeFactory.Instance.Create(); if (newNode.tech == null) { Debug.Log("newNode.tech is null after createNode"); newNode.tech = new RDTech(); } if (newNode.gameObject == null) { Debug.Log("newNode.gameObject is still null after Setup"); } Debug.Log("created node and tech, now setting basic tech parameters"); //setup all the basic parameters that are not handled in updatenode newNode.treeNode = true; newNode.gameObject.name = newName; newNode.name = newName.Substring(newName.IndexOf("_") + 1); newNode.tech.techID = newNode.name; newNode.tech.hideIfNoParts = false; Debug.Log("updating node with cfgFile-parameters"); updateNode(newNode, cfgNodeNew); Debug.Log("created new RDNode " + newNode.gameObject.name + " with RDTech.title=" + newNode.tech.title + " techId=" + newNode.tech.techID); newRDNodes.Add(newNode); _newNodes.Add(newNode); }//endof all newnodes nodesWithConfigEntries.AddRange(newRDNodes); } catch (Exception ex) { Debug.LogError("Exception in NEWNODE processing - " + ex.ToString()); } } //end loadTree()
private void clearParentsFromNode(RDNode treeNode) { foreach (RDNode.Parent oldParent in treeNode.parents) { oldParent.parent.node.children.Remove(treeNode); } treeNode.parents = new RDNode.Parent[0]; }
private void clearParentsFromNode(RDNode treeNode) { foreach (RDNode.Parent oldParent in treeNode.parents) { oldParent.parent.node.children.Remove(treeNode); } Array.Clear(treeNode.parents, 0, treeNode.parents.Count()); }
private void moveNode(RDNode treeNode, float xPos, float yPos) { Vector3 newPos = treeNode.transform.localPosition; newPos.x = xPos; newPos.y = yPos; treeNode.transform.localPosition = newPos; }
public void Update() { // Do nothing if there is no PartList if (RDController.Instance == null || RDController.Instance.partList == null) { return; } // In case the node is deselected if (RDController.Instance.node_selected == null) { selectedNode = null; } // Do nothing if the tooltip hasn't changed since last update if (selectedNode == RDController.Instance.node_selected) { return; } // Get the the selected node and partList ui object selectedNode = RDController.Instance.node_selected; // retrieve fieldInfo type if (_fieldInfoRdPartList == null) { _fieldInfoRdPartList = typeof(RDPartList).GetField("partListItems", BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance); } if (_fieldInfoRdPartList == null) { return; } var items = (List <RDPartListItem>)_fieldInfoRdPartList.GetValue(RDController.Instance.partList); if (items == null) { return; } var upgradedTemplateItems = items.Where(p => !p.isPart && p.upgrade != null).ToList(); if (upgradedTemplateItems.Count == 0) { return; } foreach (RDPartListItem item in upgradedTemplateItems) { //Debug.Log("[KSPI]: RDColoredUpgradeIcon upgrade name " + item.upgrade.name + " upgrade techRequired: " + item.upgrade.techRequired); item.gameObject.GetComponent <UnityEngine.UI.Image>().color = greenColor; } }
private void updateParentsForNode(RDNode treeNode, ConfigNode treeCfg) { //Debug.Log("updating parents for node " + treeNode.gameObject.name); //clear all old parents. The RD-Scene will take care of drawing the arrows clearParentsFromNode(treeNode); List <RDNode.Parent> connectionList = new List <RDNode.Parent>(); foreach (ConfigNode parentCfg in treeCfg.GetNodes("PARENT_NODE")) { if (parentCfg.HasValue("name")) { string parentName = parentCfg.GetValue("name"); //RDNode parentNode = Array.Find<RDNode>(AssetBase.RnDTechTree.GetTreeNodes(), x => x.gameObject.name == parentName); //RDNode parentNode = AssetBase.RnDTechTree.GetTreeNodes().FirstOrDefault(rdn => rdn.gameObject.name == parentName); //RDNode parentNode = GameObject.FindObjectsOfType(typeof(RDNode)).Cast<RDNode>().FirstOrDefault(rdn => rdn.gameObject.name == parentName); RDNode parentNode = GetNodeNamed(parentName); if (parentNode) //Default-constructed RDNode (if search fails) fails this test { //Debug.Log(" --- parentnode: " + parentName); parentNode.children.Add(treeNode); RDNode.Parent connection; // only manually override the anchor points if BOTH are specified in the config if (parentCfg.HasValue("parentSide") && parentCfg.HasValue("childSide")) { RDNode.Anchor parentAnchor = (RDNode.Anchor)Enum.Parse(typeof(RDNode.Anchor), parentCfg.GetValue("parentSide")); RDNode.Anchor childAnchor = (RDNode.Anchor)Enum.Parse(typeof(RDNode.Anchor), parentCfg.GetValue("childSide")); //Debug.Log("Overriding auto-assignment for node " + treeNode.gameObject.name + " to " + parentAnchor + "->" + childAnchor); connection = new RDNode.Parent(new RDNode.ParentAnchor(parentNode, parentAnchor), childAnchor); parentConnectionsAlreadyProcessed.Add(connection); } else { //create RDNode.Parent structure - anchors will be corrected once all nodes have been loaded connection = new RDNode.Parent(new RDNode.ParentAnchor(parentNode, RDNode.Anchor.RIGHT), RDNode.Anchor.LEFT); } connectionList.Add(connection); } else { Debug.LogError("ATC: Invalid parent node specified for: " + treeNode.gameObject.name + " parent: " + parentName); } } } treeNode.parents = connectionList.ToArray(); }
private void ForceUnlockTech(string techID) { Debug.Log("[Toppler] Force unlocking " + techID); RDNode node = RDController.Instance.nodes.Find(n => n.tech.techID == techID); lastNode = techID; if (node != null) { node.tech.UnlockTech(true); } }
int NodeDepth(RDNode current) { int depth = 1; while (current.parents.Count() > 0) { current = current.parents[0].parent.node; depth++; } return(depth); }
private bool isAnchorAvailableForOutgoingArrows(RDNode node, RDNode.Anchor anchor) { foreach (RDNode.Parent incomingConnection in node.parents) { if (incomingConnection.anchor == anchor) { return(false); } } return(true); }
private void clearChildrenFromNode(RDNode treeNode) { foreach (RDNode tempChild in treeNode.children) { List <RDNode.Parent> childParentList = tempChild.parents.ToList(); childParentList.Remove(childParentList.Find(tempParentConnection => tempParentConnection.parent.node == treeNode)); tempChild.parents = childParentList.ToArray(); } treeNode.children.Clear(); }
public void OnTreeSpawn(RDController controller) { if (TestFlightManagerScenario.Instance == null || controller.nodes == null) { return; } List <RDNode> nodes = controller.nodes; if (this.baseCost == null) { baseCost = new Dictionary <string, int>(); for (int i = 0; i < nodes.Count; i++) { RDNode node = nodes[i]; if (node != null && node.tech != null) { baseCost.Add(nodes[i].tech.techID, nodes[i].tech.scienceCost); } } } for (int n = 0; n < nodes.Count; n++) { RDNode node = nodes[n]; if (node != null && node.tech != null && !node.IsResearched && node.tech.partsAssigned != null) { float discount = 0f; List <AvailablePart> parts = node.tech.partsAssigned; for (int p = 0; p < parts.Count; p++) { if (parts[p] != null) { Part prefab = parts[p].partPrefab; TestFlightPartData partData = TestFlightManagerScenario.Instance.GetPartDataForPart(parts[p].name); if (partData != null && prefab != null) { TestFlightCore core = (TestFlightCore)prefab.Modules.OfType <TestFlightCore>().FirstOrDefault(); float flightData = partData.GetFloat("flightData"); if (core != null && flightData > core.startFlightData) { discount += (int)(((flightData - core.startFlightData) / (core.maxData - core.startFlightData)) * core.scienceDataValue); } } } } if (discount > 0) { node.tech.scienceCost = (int)Math.Max(0, baseCost[node.tech.techID] - discount); } } } }
private RDNode createNode() { //Debug.Log("creating new RDNode"); RDNode startNode = findStartNode(); GameObject nodePrefab; //if (startNode.prefab == null) //{ Debug.Log("creating new GameObject()"); nodePrefab = new GameObject("newnode", typeof(RDNode), typeof(RDTech)); if (nodePrefab.GetComponent <RDNode>() == null) { Debug.Log("wtf - nodePrefab.getComponent<RDNode> is null"); } if (nodePrefab.GetComponent <RDTech>() == null) { Debug.Log("wtf - nodePrefab.getComponent<RDTech> is null"); } nodePrefab.GetComponent <RDTech>().techID = "newTech_RenameMe"; nodePrefab.GetComponent <RDNode>().tech = nodePrefab.GetComponent <RDTech>(); nodePrefab.GetComponent <RDNode>().prefab = startNode.prefab; nodePrefab.GetComponent <RDNode>().parents = new RDNode.Parent[0]; nodePrefab.GetComponent <RDNode>().icon = startNode.icon; nodePrefab.GetComponent <RDNode>().controller = startNode.controller; nodePrefab.GetComponent <RDNode>().scale = startNode.scale; nodePrefab.SetActive(false); //} //else //{ // nodePrefab = startNode.prefab; //} Debug.Log("Instantiating prefab nodeObject"); GameObject clone = (GameObject)GameObject.Instantiate(nodePrefab); clone.SetActive(true); clone.transform.parent = startNode.transform.parent; clone.transform.localPosition = new Vector3(0, 50, 0); clone.GetComponent <RDNode>().children = new List <RDNode>(); clone.GetComponent <RDNode>().tech = new RDTech(); return(clone.GetComponent <RDNode>()); }
public void UpdateTechlistIconColor() { if (RDController.Instance != null) { for (int i = RDController.Instance.nodes.Count; i-- > 0;) { RDNode node = RDController.Instance.nodes[i]; if (node?.tech != null) { if (HasTechInList(node.tech.techID)) { node.graphics?.SetIconColor(XKCDColors.KSPNotSoGoodOrange); } // else reset? Bleh, why bother. } } } }
public RDNode Create() { GameObject clone = GameObject.Instantiate(NodePrefab) as GameObject; RDNode node = clone.GetComponent <RDNode>(); node.tech = clone.GetComponent <RDTech>(); node.name = _newNodeName; node.children = new List <RDNode>(); node.description = ""; clone.transform.localPosition = NodePrefab.transform.localPosition; clone.transform.parent = NodePrefab.transform.parent; //clone.transform.localRotation = NodePrefab.transform.localRotation; //clone.transform.localScale = NodePrefab.transform.localScale; node.tech.Start(); clone.SetActive(true); return(node); }
internal static void Find(bool clean = false) { List <RDNode> _nodes = RDController.Instance.nodes; for (int _i = _nodes.Count - 1; _i >= 0; --_i) { RDNode _node = _nodes[_i]; RDTech _rdTech = _node.tech; if (_node.graphics != null) { UIStateButton _button = _node.graphics.button; if (!clean && _rdTech.partsAssigned.Find(aPart => QSearch.FindPart(aPart)) != null) { _button.Image.color = new Color(1f, 0f, 0f); continue; } _button.Image.color = new Color(1f, 1f, 1f); } } //QDebug.Log ("Find: " + QSearch.Text, "QRnD"); }
private List <RDNode> calculateTopologicalSorting() { List <RDNode> sortedList = new List <RDNode>(); HashSet <RDNode> tempMarkedNodes = new HashSet <RDNode>(); HashSet <RDNode> markedNodes = new HashSet <RDNode>(); HashSet <RDNode> unmarkedNodes = new HashSet <RDNode>(); foreach (RDNode rdNode in GameObject.FindObjectsOfType(typeof(RDNode)).Cast <RDNode>()) { unmarkedNodes.Add(rdNode); } while (unmarkedNodes.Count > 0) { RDNode n = unmarkedNodes.First(); visitNode(n, ref sortedList, ref unmarkedNodes, ref markedNodes, ref tempMarkedNodes); } return(sortedList); }
private List <RDNode> calculateTopologicalSorting() { List <RDNode> sortedList = new List <RDNode>(); HashSet <RDNode> tempMarkedNodes = new HashSet <RDNode>(); HashSet <RDNode> markedNodes = new HashSet <RDNode>(); HashSet <RDNode> unmarkedNodes = new HashSet <RDNode>(); foreach (RDNode rdNode in AssetBase.RnDTechTree.GetTreeNodes()) { unmarkedNodes.Add(rdNode); } while (unmarkedNodes.Count > 0) { RDNode n = unmarkedNodes.First(); visitNode(n, ref sortedList, ref unmarkedNodes, ref markedNodes, ref tempMarkedNodes); } return(sortedList); }
static private void AddTechNodeToTreeNode(RDNode techNode, ConfigNode treeConfigNode) { ConfigNode techNodeConfigNode = new ConfigNode("TECH_NODE"); techNodeConfigNode.AddValue("name", techNode.gameObject.name); techNodeConfigNode.AddValue("title", techNode.tech.title); techNodeConfigNode.AddValue("description", techNode.tech.description); techNodeConfigNode.AddValue("icon", techNode.icon.ToString()); techNodeConfigNode.AddValue("scienceCost", techNode.tech.scienceCost); techNodeConfigNode.AddValue("anyParentUnlocks", techNode.AnyParentToUnlock); techNodeConfigNode.AddValue("hideIfNoparts", techNode.hideIfNoParts); techNodeConfigNode.AddValue("posX", techNode.transform.localPosition.x); techNodeConfigNode.AddValue("posY", techNode.transform.localPosition.y); if (techNode.parents != null) { foreach (RDNode.Parent tempParentConnection in techNode.parents) { if (tempParentConnection != null) { ConfigNode parentConfigNode = new ConfigNode("PARENT_NODE"); parentConfigNode.AddValue("name", tempParentConnection.parent.node.gameObject.name); techNodeConfigNode.AddNode(parentConfigNode); } } } treeConfigNode.AddNode(techNodeConfigNode); }
public void Update() { // Do nothing if there is no PartList if (RDController.Instance == null) { return; } if (RDController.Instance.partList == null) { return; } // In case the node is deselected if (RDController.Instance.node_selected == null) { selectedNode = null; } // Do nothing if the tooltip hasn't changed since last update if (selectedNode == RDController.Instance.node_selected) { return; } // Get the the selected node and partlist ui object selectedNode = RDController.Instance.node_selected; RDPartList partList = RDController.Instance.partList; var field = typeof(RDPartList).GetField("partListItems", BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance); List <RDPartListItem> items = (List <RDPartListItem>)field.GetValue(partList); foreach (RDPartListItem item in items.Where(p => !p.isPart && p.upgrade != null)) { item.gameObject.GetComponent <UnityEngine.UI.Image>().color = new Color(0.717f, 0.819f, 0.561f); // light green RGB(183,209,143) } }
public void Update() { // Do nothing if there is no PartList if (RDController.Instance == null || RDController.Instance.partList == null) { return; } // In case the node is deselected if (RDController.Instance.node_selected == null) { selectedNode = null; } // Do nothing if the tooltip hasn't changed since last update if (selectedNode == RDController.Instance.node_selected) { return; } // Get the the selected node and partlist ui object selectedNode = RDController.Instance.node_selected; // retrieve fieldInfo type if (fieldInfoRDPartList == null) { fieldInfoRDPartList = typeof(RDPartList).GetField("partListItems", BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance); } var items = (List <RDPartListItem>)fieldInfoRDPartList.GetValue(RDController.Instance.partList); foreach (RDPartListItem item in items.Where(p => !p.isPart && p.upgrade != null)) { item.gameObject.GetComponent <UnityEngine.UI.Image>().color = greenColor; } }
public RDNodeWrapper(RDNode node) { this.node = node; this.traverse = Traverse.Create(node); }
public static List <Vector2> Execute(RDNode node, RDNode.Parent parent) => new RDNodeWrapper(node).GetVectorArray(parent);
private void setupAnchors(RDNode target, ref RDNode.Parent connection) { RDNode source = connection.parent.node; //find main direction from outgoing node (parent) to target (connectionOwner) node to set anchor tags //Exception: Cannot display incoming and outgoing nodes on the same anchor Vector3 connectionVec = target.transform.localPosition - source.transform.localPosition; //calculate/setup anchors List <RDNode.Anchor> possibleParentAnchors = new List <RDNode.Anchor>(); List <RDNode.Anchor> possibleTargetAnchors = new List <RDNode.Anchor>(); if (connectionVec.x >= 0) {//left to right if (isAnchorAvailableForOutgoingArrows(source, RDNode.Anchor.RIGHT)) { possibleParentAnchors.Add(RDNode.Anchor.RIGHT); } possibleTargetAnchors.Add(RDNode.Anchor.LEFT); } else { if (isAnchorAvailableForOutgoingArrows(source, RDNode.Anchor.LEFT)) { possibleParentAnchors.Add(RDNode.Anchor.LEFT); } possibleTargetAnchors.Add(RDNode.Anchor.RIGHT); } if (connectionVec.y >= 0) //up { if (isAnchorAvailableForOutgoingArrows(source, RDNode.Anchor.TOP)) { possibleParentAnchors.Add(RDNode.Anchor.TOP); } possibleTargetAnchors.Add(RDNode.Anchor.BOTTOM); } else // TOP-DOWN connection doesnt work because of parent or target anchor { //neither does or BOTTOM->LEFT RIGHT->TOP neiter //possibleParentAnchors.Add(RDNode.Anchor.BOTTOM); //possibleTargetAnchors.Add(RDNode.Anchor.TOP); } //Debug.Log("options remaining after filtering: " + possibleParentAnchors.Count()); //foreach (RDNode.Anchor anchor in possibleParentAnchors) // Debug.Log("available anchor: " + anchor); //if two options are available, pick the larger distance if (Math.Abs(connectionVec.x) < Math.Abs(connectionVec.y)) //preferrably vertical { { possibleParentAnchors.Reverse(); possibleTargetAnchors.Reverse(); } if (possibleParentAnchors.Count == 0 || possibleTargetAnchors.Count == 0) { Debug.LogWarning("no valid anchor for connection " + source.gameObject.name + "->" + target.gameObject.name + ", direction = " + connectionVec.ToString() + ", defaulting to anchors RIGHT->LEFT"); if (possibleParentAnchors.Count == 0) { possibleParentAnchors.Add(RDNode.Anchor.RIGHT); } if (possibleTargetAnchors.Count == 0) { possibleTargetAnchors.Add(RDNode.Anchor.LEFT); } } //Debug.Log(" anchors for connection " + source.gameObject.name + "->" + target.gameObject.name+ ", direction = " + connectionVec.ToString() + " anchors : " + possibleParentAnchors.First() + " -> " + possibleTargetAnchors.First()); connection.anchor = possibleTargetAnchors.First(); connection.parent.anchor = possibleParentAnchors.First(); }
} //end loadTree() private void updateNode(RDNode treeNode, ConfigNode cfgNode) { if (cfgNode.HasValue("title")) { //treeNode.name = cfgNode.GetValue("title"); treeNode.tech.title = cfgNode.GetValue("title"); } if (cfgNode.HasValue("description")) { treeNode.description = cfgNode.GetValue("description").Replace("\\n", "\n"); treeNode.tech.description = treeNode.description; } if (cfgNode.HasValue("scienceCost")) treeNode.tech.scienceCost = int.Parse(cfgNode.GetValue("scienceCost")); //Debug.Log("checking icon"); if (cfgNode.HasValue("icon")) { //bool success = Enum.TryParse<RDNode.Icon>(cfgNode.GetValue("icon"), out icon); //.NET >= 4.0 try { RDNode.Icon icon = (RDNode.Icon)Enum.Parse(typeof(RDNode.Icon), cfgNode.GetValue("icon")); treeNode.icon = icon; //Debug.Log("Setting iconstate"); //treeNode.SetIconState(icon); //not required, game handles this automatically for stocknodes } catch (Exception ex) { Debug.LogError("Invalid Icon name '" + cfgNode.GetValue("icon") + "'" + ex.Message); } } if (cfgNode.HasValue("anyParentUnlocks")) treeNode.AnyParentToUnlock = bool.Parse(cfgNode.GetValue("anyParentUnlocks")); if (cfgNode.HasValue("hideIfNoparts")) { treeNode.tech.hideIfNoParts = bool.Parse(cfgNode.GetValue("hideIfNoparts")); } else { treeNode.tech.hideIfNoParts = false; } //setup parent/child relations updateParentsForNode(treeNode, cfgNode); if (cfgNode.HasValue("posX") || cfgNode.HasValue("posY")) { Vector3 newPos = treeNode.transform.localPosition; if (cfgNode.HasValue("posX")) newPos.x = float.Parse(cfgNode.GetValue("posX")); if (cfgNode.HasValue("posY")) newPos.y = float.Parse(cfgNode.GetValue("posY")); moveNode(treeNode, newPos.x, newPos.y); } }
private bool isAnchorAvailableForOutgoingArrows(RDNode node, RDNode.Anchor anchor) { foreach (RDNode.Parent incomingConnection in node.parents) if (incomingConnection.anchor == anchor) return false; return true; }
private void visitNode(RDNode rdNode, ref List<RDNode> sortedList, ref HashSet<RDNode> unmarkedNodes, ref HashSet<RDNode> markedNodes, ref HashSet<RDNode> tempMarkedNodes) { //Debug.Log("TOPOSORT visiting " + rdNode.gameObject.name); if (tempMarkedNodes.Contains(rdNode)) { throw new Exception("ATC: Circular dependency in Tech-Node Graph! RDNode " + rdNode.gameObject.name + " is in a circular dependency with one of its direct or indirect parents"); } if (!markedNodes.Contains(rdNode)) //this node has not been visited yet { tempMarkedNodes.Add(rdNode); //DFS-search recursive for all children foreach (RDNode child in rdNode.children) visitNode(child, ref sortedList, ref unmarkedNodes, ref markedNodes, ref tempMarkedNodes); //Debug.Log("TOPOSORT marking node " + rdNode.gameObject.name); markedNodes.Add(rdNode); tempMarkedNodes.Remove(rdNode); unmarkedNodes.Remove(rdNode); sortedList.Insert(0, rdNode);//prepend to list } }
} //end loadTree() private void updateNode(RDNode treeNode, ConfigNode cfgNode) { if (cfgNode.HasValue("title")) { //treeNode.name = cfgNode.GetValue("title"); treeNode.tech.title = cfgNode.GetValue("title"); } if (cfgNode.HasValue("description")) { treeNode.description = cfgNode.GetValue("description").Replace("\\n", "\n"); treeNode.tech.description = treeNode.description; } if (cfgNode.HasValue("scienceCost")) { treeNode.tech.scienceCost = int.Parse(cfgNode.GetValue("scienceCost")); } //Debug.Log("checking icon"); if (cfgNode.HasValue("icon")) { //bool success = Enum.TryParse<RDNode.Icon>(cfgNode.GetValue("icon"), out icon); //.NET >= 4.0 try { RDNode.Icon icon = (RDNode.Icon)Enum.Parse(typeof(RDNode.Icon), cfgNode.GetValue("icon")); treeNode.icon = icon; //Debug.Log("Setting iconstate"); //treeNode.SetIconState(icon); //not required, game handles this automatically for stocknodes } catch (Exception ex) { Debug.LogError("Invalid Icon name '" + cfgNode.GetValue("icon") + "'" + ex.Message); } } if (cfgNode.HasValue("anyParentUnlocks")) { treeNode.AnyParentToUnlock = bool.Parse(cfgNode.GetValue("anyParentUnlocks")); } if (cfgNode.HasValue("hideIfNoparts")) { treeNode.tech.hideIfNoParts = bool.Parse(cfgNode.GetValue("hideIfNoparts")); } else { treeNode.tech.hideIfNoParts = false; } //setup parent/child relations updateParentsForNode(treeNode, cfgNode); if (cfgNode.HasValue("posX") || cfgNode.HasValue("posY")) { Vector3 newPos = treeNode.transform.localPosition; if (cfgNode.HasValue("posX")) { newPos.x = float.Parse(cfgNode.GetValue("posX")); } if (cfgNode.HasValue("posY")) { newPos.y = float.Parse(cfgNode.GetValue("posY")); } moveNode(treeNode, newPos.x, newPos.y); } }
private void clearChildrenFromNode(RDNode treeNode) { foreach (RDNode tempChild in treeNode.children) { List<RDNode.Parent> childParentList = tempChild.parents.ToList(); childParentList.Remove(childParentList.Find(tempParentConnection => tempParentConnection.parent.node == treeNode)); tempChild.parents = childParentList.ToArray(); } treeNode.children.Clear(); }
private void LoadTree() { if (!ATCTreeDumper.m_bHasTreeAlreadyBeenDumped && ATCTreeDumper.m_bIsEnabled) { ATCTreeDumper.DumpCurrentTreeToFile("StockTree.cfg", "stock"); } settings = getActiveSettingCfg(); if (!settings.HasData) { return; } debugCombo = settings.GetValue("debugDumpKeyCombo"); reloadCombo = settings.GetValue("reloadKeyCombo"); nodesWithConfigEntries.Clear(); parentConnectionsAlreadyProcessed.Clear(); foreach (ConfigNode activeTreeCfg in settings.GetNodes("ACTIVE_TECH_TREE")) { ConfigNode tree = getTreeCfgForActiveTreeCfg(activeTreeCfg); if (!tree.HasData) { Debug.LogError("TechChanger: Treeconfig '" + activeTreeCfg.GetValue("name") + "' empty/not found!"); continue; } setupBodyScienceParamsForTree(tree); Debug.Log("ATC: processing all TECH_NODE items"); //check modify-nodes foreach (ConfigNode cfgNodeModify in tree.GetNodes("TECH_NODE")) { string gameObjectName = cfgNodeModify.GetValue("name"); //Debug.Log("processing MODIFY_NODE " + gameObjectName); //RDNode treeNode = Array.Find<RDNode>(AssetBase.RnDTechTree.GetTreeNodes(), x => x.gameObject.name == gameObjectName); RDNode treeNode = GameObject.FindObjectsOfType(typeof(RDNode)).Cast <RDNode>().FirstOrDefault(rdn => rdn.gameObject.name == gameObjectName); if (treeNode.treeNode) { updateNode(treeNode, cfgNodeModify); nodesWithConfigEntries.Add(treeNode); } else { Debug.LogWarning("Could not find RDNode with gameObjectName == " + gameObjectName); } }//end for all nodes; //deactivated for now processNewNodes(tree); }//end foreach tree-config deleteAbsentNodes(); List <RDNode> topoSortedNodes = calculateTopologicalSorting(); foreach (RDNode rdNode in topoSortedNodes) { //Debug.Log("setting up anchors for " + rdNode.gameObject.name); for (int i = 0; i < rdNode.parents.Count(); ++i) { if (parentConnectionsAlreadyProcessed.Contains(rdNode.parents[i])) { //Debug.Log("Skipping auto-anchor assignment for node " + rdNode.gameObject.name); } else { setupAnchors(rdNode, ref rdNode.parents[i]); } //warn for anchors that cannot be displayed properly. This might happen if a user-config overrides the auto-assignment. Or if the auto-assignment screws up if (rdNode.parents[i].parent.anchor == RDNode.Anchor.BOTTOM) { Debug.LogWarning("ATC: Warning: Arrow from " + rdNode.parents[i].parent.node.gameObject.name + "to" + rdNode.gameObject.name + " will cannot be displayed because it uses parent anchor BOTTOM!"); } if (rdNode.parents[i].anchor == RDNode.Anchor.TOP) { Debug.LogWarning("ATC: Warning: Arrow from " + rdNode.parents[i].parent.node.gameObject.name + "to" + rdNode.gameObject.name + " will cannot be displayed because it uses anchor TOP!"); } } } }
private void processNewNodes(ConfigNode tree) { Debug.Log("processing all NEW_NODE items"); //RDController rdControl = GameObject.FindObjectOfType<RDController>(); List <RDNode> newRDNodes = new List <RDNode>(); try { foreach (ConfigNode cfgNodeNew in tree.GetNodes("NEW_NODE")) { //only create RDNodes that are not yet in the Techtree string newName = cfgNodeNew.GetValue("gameObjectName"); //if (!Array.Exists<RDNode>(AssetBase.RnDTechTree.GetTreeNodes(), x => x.gameObject.name == newName)) if (!GameObject.FindObjectsOfType(typeof(RDNode)).Cast <RDNode>().Any(rdn => rdn.gameObject.name == newName)) { RDNode newNode = createNode(); if (newNode.tech == null) { Debug.Log("newNode.tech is null after createNode"); newNode.tech = new RDTech(); } if (newNode.gameObject == null) { Debug.Log("newNode.gameObject is still null after Setup"); } //Debug.Log("calling rdNode.Warmup()"); //newNode.Warmup(newTech); //Debug.Log("NEWNODE: after Setup(), startNode has " + findStartNode().children.Count() + " children"); Debug.Log("created node and tech, now setting basic tech parameters"); //setup all the basic parameters that are not handled in updatenode newNode.treeNode = true; newNode.gameObject.name = newName; newNode.name = newName.Substring(newName.IndexOf("_") + 1); newNode.tech.techID = newNode.name; newNode.tech.hideIfNoParts = false; Debug.Log("updating node with cfgFile-parameters"); updateNode(newNode, cfgNodeNew); Debug.Log("created new RDNode " + newNode.gameObject.name + " with RDTech.title=" + newNode.tech.title + " techId=" + newNode.tech.techID); //Debug.Log("NEWNODE: after updateNode(), startNode has " + findStartNode().children.Count() + " children"); //Debug.Log("NEWNODE: calling RegisterNode(), AssetBase.TechTree has " + AssetBase.RnDTechTree.GetTreeNodes().Count() + " entries"); //newNode.controller.RegisterNode(newNode); //Debug.Log("NEWNODE: after RegisterNode(), AssetBase.TechTree has " + AssetBase.RnDTechTree.GetTreeNodes().Count() + " entries"); //newNode.SetButtonState(RDNode.State.RESEARCHABLE); //newNode.SetButtonState(RDNode.State.RESEARCHABLE); Debug.Log("calling newnode.setup"); newNode.Setup(); //This sets the anchor offsets //Debug.Log("Invoking rdController.registerNode"); typeof(RDNode).GetMethod("InitializeArrows", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(newNode, null); newRDNodes.Add(newNode); //addedNewNodes.Add(newName); }//endif tech not yet added else { RDNode newNode = GameObject.FindObjectsOfType(typeof(RDNode)).Cast <RDNode>().FirstOrDefault(rdn => rdn.gameObject.name == newName); newNode.Setup(); newRDNodes.Add(newNode); } }//endof all newnodes nodesWithConfigEntries.AddRange(newRDNodes); if (newRDNodes.Any()) { Debug.Log("Invoking Warmup"); RDTechTree rd_tree = AssetBase.RnDTechTree; MethodInfo rd_tree_minfo = typeof(RDTechTree).GetMethod("Warmup", BindingFlags.NonPublic | BindingFlags.Instance); //.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance).Where(mtd => mtd.Name.Contains("warmup")).FirstOrDefault(); rd_tree_minfo.Invoke(rd_tree, null); Debug.Log("Warmup Complete"); } //List<RDNode> rdnodes = AssetBase.RnDTechTree.GetTreeNodes().ToList(); //List<RDTech> rdtechs = AssetBase.RnDTechTree.GetTreeTechs().ToList(); //rdnodes.AddRange(newRDNodes); //rdtechs.AddRange(newRDNodes.Select(rdn => rdn.tech)); //FieldInfo rdnodes_info = typeof(RDTechTree).GetFields(BindingFlags.NonPublic | BindingFlags.Static).Where(fld => fld.FieldType.FullName.Contains("RDNode")).FirstOrDefault(); //FieldInfo rdtechs_info = typeof(RDTechTree).GetFields(BindingFlags.NonPublic | BindingFlags.Static).Where(fld => fld.FieldType.FullName.Contains("RDTech")).FirstOrDefault(); //rdnodes_info.SetValue(null, rdnodes.ToArray()); //rdtechs_info.SetValue(null, rdtechs.ToArray()); } catch (Exception ex) { Debug.LogError("Exception in NEWNODE processing - " + ex.Message + " at " + ex.StackTrace); } } //end loadTree()
static private void AddTechNodeToTreeNode( RDNode techNode, ConfigNode treeConfigNode ) { ConfigNode techNodeConfigNode = new ConfigNode( "TECH_NODE" ); techNodeConfigNode.AddValue( "name", techNode.gameObject.name ); techNodeConfigNode.AddValue( "title", techNode.tech.title ); techNodeConfigNode.AddValue( "description", techNode.tech.description ); techNodeConfigNode.AddValue( "icon", techNode.icon.ToString()); techNodeConfigNode.AddValue( "scienceCost", techNode.tech.scienceCost ); techNodeConfigNode.AddValue( "anyParentUnlocks", techNode.AnyParentToUnlock ); techNodeConfigNode.AddValue( "hideIfNoparts", techNode.hideIfNoParts ); techNodeConfigNode.AddValue( "posX", techNode.transform.localPosition.x ); techNodeConfigNode.AddValue( "posY", techNode.transform.localPosition.y ); if ( techNode.parents != null ) { foreach ( RDNode.Parent tempParentConnection in techNode.parents ) { if ( tempParentConnection != null ) { ConfigNode parentConfigNode = new ConfigNode( "PARENT_NODE" ); parentConfigNode.AddValue( "name", tempParentConnection.parent.node.gameObject.name ); techNodeConfigNode.AddNode( parentConfigNode ); } } } treeConfigNode.AddNode( techNodeConfigNode ); }
private void setupAnchors(RDNode target, ref RDNode.Parent connection) { RDNode source = connection.parent.node; //find main direction from outgoing node (parent) to target (connectionOwner) node to set anchor tags //Exception: Cannot display incoming and outgoing nodes on the same anchor Vector3 connectionVec = target.transform.localPosition - source.transform.localPosition; //calculate/setup anchors List<RDNode.Anchor> possibleParentAnchors = new List<RDNode.Anchor>(); List<RDNode.Anchor> possibleTargetAnchors = new List<RDNode.Anchor>(); if (connectionVec.x >= 0) {//left to right if (isAnchorAvailableForOutgoingArrows(source, RDNode.Anchor.RIGHT)) possibleParentAnchors.Add(RDNode.Anchor.RIGHT); possibleTargetAnchors.Add(RDNode.Anchor.LEFT); } else { if (isAnchorAvailableForOutgoingArrows(source, RDNode.Anchor.LEFT)) possibleParentAnchors.Add(RDNode.Anchor.LEFT); possibleTargetAnchors.Add(RDNode.Anchor.RIGHT); } if (connectionVec.y >= 0) //up { if (isAnchorAvailableForOutgoingArrows(source, RDNode.Anchor.TOP)) possibleParentAnchors.Add(RDNode.Anchor.TOP); possibleTargetAnchors.Add(RDNode.Anchor.BOTTOM); } else // TOP-DOWN connection doesnt work because of parent or target anchor { //neither does or BOTTOM->LEFT RIGHT->TOP neiter //possibleParentAnchors.Add(RDNode.Anchor.BOTTOM); //possibleTargetAnchors.Add(RDNode.Anchor.TOP); } //Debug.Log("options remaining after filtering: " + possibleParentAnchors.Count()); //foreach (RDNode.Anchor anchor in possibleParentAnchors) // Debug.Log("available anchor: " + anchor); //if two options are available, pick the larger distance if (Math.Abs(connectionVec.x) < Math.Abs(connectionVec.y)) //preferrably vertical { { possibleParentAnchors.Reverse(); possibleTargetAnchors.Reverse(); } if (possibleParentAnchors.Count == 0 || possibleTargetAnchors.Count == 0) { Debug.LogWarning("no valid anchor for connection " + source.gameObject.name + "->" + target.gameObject.name + ", direction = " + connectionVec.ToString() + ", defaulting to anchors RIGHT->LEFT"); if (possibleParentAnchors.Count == 0) possibleParentAnchors.Add(RDNode.Anchor.RIGHT); if (possibleTargetAnchors.Count == 0) possibleTargetAnchors.Add(RDNode.Anchor.LEFT); } //Debug.Log(" anchors for connection " + source.gameObject.name + "->" + target.gameObject.name+ ", direction = " + connectionVec.ToString() + " anchors : " + possibleParentAnchors.First() + " -> " + possibleTargetAnchors.First()); connection.anchor = possibleTargetAnchors.First(); connection.parent.anchor = possibleParentAnchors.First(); }
private void setupAnchors(RDNode target, ref RDNode.Parent connection) { RDNode source = connection.parent.node; //RDNode source = GetNodeNamed(connection.parent.node.name); //Debug.Log("Setting up anchors for " + target.name); //string state = string.Format("target: {0}\nconnection: {1}\nsource: {2}", target, connection, source); //Debug.Log(state); if (source == null) return; //find main direction from outgoing node (parent) to target (connectionOwner) node to set anchor tags //Exception: Cannot display incoming and outgoing nodes on the same anchor Vector3 connectionVec; try { connectionVec = target.transform.localPosition - source.transform.localPosition; } catch { Debug.Log("A problem occurred while finding the connection vector between " + source.name + " (source) and " + target.name + " (target)"); try { Debug.Log(target.name + " is able to access its transform: " + (target.transform != null)); } catch { } try { Debug.Log(source.name + " is able to access its transform: " + (source.transform != null)); } catch { } return; } //calculate/setup anchors List<RDNode.Anchor> possibleParentAnchors = new List<RDNode.Anchor>(); List<RDNode.Anchor> possibleTargetAnchors = new List<RDNode.Anchor>(); if (connectionVec.x >= 0) {//left to right if (isAnchorAvailableForOutgoingArrows(source, RDNode.Anchor.RIGHT)) possibleParentAnchors.Add(RDNode.Anchor.RIGHT); possibleTargetAnchors.Add(RDNode.Anchor.LEFT); } else { if (isAnchorAvailableForOutgoingArrows(source, RDNode.Anchor.LEFT)) possibleParentAnchors.Add(RDNode.Anchor.LEFT); possibleTargetAnchors.Add(RDNode.Anchor.RIGHT); } if (connectionVec.y >= 0) //up { if (isAnchorAvailableForOutgoingArrows(source, RDNode.Anchor.TOP)) possibleParentAnchors.Add(RDNode.Anchor.TOP); possibleTargetAnchors.Add(RDNode.Anchor.BOTTOM); } else // TOP-DOWN connection doesnt work because of parent or target anchor { //neither does or BOTTOM->LEFT RIGHT->TOP neiter //possibleParentAnchors.Add(RDNode.Anchor.BOTTOM); //possibleTargetAnchors.Add(RDNode.Anchor.TOP); } //Debug.Log("options remaining after filtering: " + possibleParentAnchors.Count()); //foreach (RDNode.Anchor anchor in possibleParentAnchors) // Debug.Log("available anchor: " + anchor); //if two options are available, pick the larger distance if (Math.Abs(connectionVec.x) < Math.Abs(connectionVec.y)) //preferrably vertical { { possibleParentAnchors.Reverse(); possibleTargetAnchors.Reverse(); } if (possibleParentAnchors.Count == 0 || possibleTargetAnchors.Count == 0) { Debug.LogWarning("no valid anchor for connection " + source.gameObject.name + "->" + target.gameObject.name + ", direction = " + connectionVec.ToString() + ", defaulting to anchors RIGHT->LEFT"); if (possibleParentAnchors.Count == 0) possibleParentAnchors.Add(RDNode.Anchor.RIGHT); if (possibleTargetAnchors.Count == 0) possibleTargetAnchors.Add(RDNode.Anchor.LEFT); } //Debug.Log(" anchors for connection " + source.gameObject.name + "->" + target.gameObject.name+ ", direction = " + connectionVec.ToString() + " anchors : " + possibleParentAnchors.First() + " -> " + possibleTargetAnchors.First()); connection.anchor = possibleTargetAnchors.First(); connection.parent.anchor = possibleParentAnchors.First(); }
//draws arrows manually (not required atm) private void recreateArrows(RDNode rdNode) { if (rdNode.state != RDNode.State.HIDDEN) { for (int i = 0; i < rdNode.parents.Count(); ++i) { //Recreate Parent hopefully recreates incoming array? nope, doesnt, also not with calling UpdateGraphics and/or Setup not... //just changing the line does not update the graphics either. RDNode.Parent parentStruct = rdNode.parents[i]; if (parentStruct.line != null) Vector.DestroyLine(ref parentStruct.line); if (parentStruct.arrowHead != null) GameObject.Destroy(parentStruct.arrowHead); }//endfor foreach parentnode RDGridArea gridArea = GameObject.FindObjectOfType<RDGridArea>(); //typeof(RDNode).GetMethod("InitializeArrows", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(treeNode, new object[] { }); if (rdNode.state == RDNode.State.RESEARCHED || rdNode.state == RDNode.State.RESEARCHABLE) typeof(RDNode).GetMethod("DrawArrow", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(rdNode, new object[] { gridArea.LineMaterial }); else typeof(RDNode).GetMethod("DrawArrow", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(rdNode, new object[] { gridArea.LineMaterialGray }); } }
public RDParentAnchor(RDNode node, RDNode.Anchor anchor) { this.node = node; this.anchor = anchor; }
private void updateParentsForNode(RDNode treeNode, ConfigNode treeCfg) { //Debug.Log("updating parents for node " + treeNode.gameObject.name); //clear all old parents. The RD-Scene will take care of drawing the arrows clearParentsFromNode(treeNode); List<RDNode.Parent> connectionList = new List<RDNode.Parent>(); foreach (ConfigNode parentCfg in treeCfg.GetNodes("PARENT_NODE")) { if (parentCfg.HasValue("name")) { string parentName = parentCfg.GetValue("name"); //RDNode parentNode = Array.Find<RDNode>(AssetBase.RnDTechTree.GetTreeNodes(), x => x.gameObject.name == parentName); //RDNode parentNode = AssetBase.RnDTechTree.GetTreeNodes().FirstOrDefault(rdn => rdn.gameObject.name == parentName); //RDNode parentNode = GameObject.FindObjectsOfType(typeof(RDNode)).Cast<RDNode>().FirstOrDefault(rdn => rdn.gameObject.name == parentName); RDNode parentNode = GetNodeNamed(parentName); if (parentNode) //Default-constructed RDNode (if search fails) fails this test { //Debug.Log(" --- parentnode: " + parentName); parentNode.children.Add(treeNode); RDNode.Parent connection; // only manually override the anchor points if BOTH are specified in the config if (parentCfg.HasValue("parentSide") && parentCfg.HasValue("childSide")) { RDNode.Anchor parentAnchor = (RDNode.Anchor)Enum.Parse(typeof(RDNode.Anchor), parentCfg.GetValue("parentSide")); RDNode.Anchor childAnchor = (RDNode.Anchor)Enum.Parse(typeof(RDNode.Anchor), parentCfg.GetValue("childSide")); //Debug.Log("Overriding auto-assignment for node " + treeNode.gameObject.name + " to " + parentAnchor + "->" + childAnchor); connection = new RDNode.Parent(new RDNode.ParentAnchor(parentNode, parentAnchor), childAnchor); parentConnectionsAlreadyProcessed.Add(connection); } else { //create RDNode.Parent structure - anchors will be corrected once all nodes have been loaded connection = new RDNode.Parent(new RDNode.ParentAnchor(parentNode, RDNode.Anchor.RIGHT), RDNode.Anchor.LEFT); } connectionList.Add(connection); } else { Debug.LogError("ATC: Invalid parent node specified for: " + treeNode.gameObject.name + " parent: " + parentName); } } } treeNode.parents = connectionList.ToArray(); }