I used graph edit to make graphs at runtime, but now I want to save them. I tried using packed scenes like this:
public void SaveTree(string tree_name)
{
GD.Print("Saving");
foreach(var child in GetChildren())
{
child.SetOwner(this);
if (child is SaveUi)
{
child.SetOwner(null);
}
}
var scene = new PackedScene();
scene.Pack(this);
ResourceSaver.Save(scene, TreeSavePath + "/" + tree_name + ".tscn");
}
But it has various problems:
-It doesn’t save connections between nodes
-It doesn’t save the text in my “text nodes” (GraphNode with TextEdit as child)
-I get the following message when I open the saved scene: “An incoming node’s name clashes with _connection_layer already in the scene (presumably, from a more nested instance) The less nested node will be renamed. Please fix and re-save the scene”
So I’m completely lost and have no idea how to fix this, besides maybe manually saving each connection and text. Any idead?
Basically ResourceSaver.Save only saves nodes which are owned by the root of the Packed scene (which is the node this script runs on). I also implemented some UI for saving the graph, but since QueueFree takes a frame before it goes into effect, the UI was getting saved as well, so I set the UI scene’s owner to null to make sure it isn’t saved.
(do not really know how C# users do this)
3) As you make graphs at runtime I assume you instantiate scenes/nodes
As documentation said:
remember to set the owner after calling add_child()
I suggest to set owner after calling add_child
In your foreach you iterate only over level 1 children, but if nodes aded deeper they still hasn’t owner
I see Graph node is marked as Experimental, it posible can be bug with save text …
Thank you, I didn’t think of setting the other node’s owners. For now I set up a recursive function to set owners of all the children since I tought it was quicker to implement.
void SetOwnerRecursive(Node root, Node owner)
{
foreach(var child in root.GetChildren())
{
child.SetOwner(owner);
SetOwnerRecursive(child, owner);
if (child is SaveUi)
{
child.SetOwner(null);
}
}
}
This way it saves the text as well, but now I am finding other issues. For starters I now get two “An incoming node’s name clashes with _connection_layer already in the scene (presumably, from a more nested instance) The less nested node will be renamed. Please fix and re-save the scene” messages instead of one, and in the saved scene in the Text Nodes there’s two text edits instead of one (one with the text and another empty one). And node connections still aren’t saved.
Note: Keep in mind that Node.get_children will also return the connection layer node named _connection_layer due to technical limitations. This behavior may change in future releases.
I’m not sure, sounds like GraphEdit have special node _connection_layer . Honestly no idea what to do with it. I can assume when scene loaded and created GraphEdit it creates own _connection_layer, but then scene load _connection_layer from PackedScene, but it already exists…
One posible idea is catch this moment, after GraphEdit created and delete his _connection_layer before saved _connection_layer will instantiated. Another idea more complex. Instead saving this in scene need to make this.duplicate(), set new owner to all, then find _connection_layer in duplicated scene and rename it with unique name and, finally, after loading, replace original _connection_layer with saved one.
void SetOwnerRecursive(Node root, Node owner)
{
foreach(var child in root.GetChildren())
{
child.SetOwner(owner);
SetOwnerRecursive(child, owner);
if (child.Name.ToString().Contains("_connection_layer"))
{
child.SetOwner(null);
}
if (child is SaveUi)
{
child.SetOwner(null);
}
}
}
and that message no longer appears. It seems that the connection layer was used to draw connections between nodes, since in the saved scene the lines between nodes did show up, tough they disappeared at runtime. I don’t think it was saving the actual connections though, just their graphical representation.
I also found that I had misread the second message. It was not a duplicate but the same error for a different node.
“An incoming node’s name clashes with TextNode/TextEdit in the scene (presumably, from a more nested instance) The less nested node will be renamed. Please fix and re-save the scene”
So the duplicate text edit error is because of this. In this case tough I will try to implement your solution, since I want to keep the edited one, rather than the base one.
As for saving the connections I guess I will have to try doing it manually.