Saving instantiated Child Scene programmatically

Godot Version

4.3

Question

Just like the title says. In the editor you can right click on a node and instantiate a child scene. When you click the root of the instantiated scene you can then click editable children, which will make the children appear in a yellowish color.

These instantiated child scenes are saved super efficiently in .tscn files. I want to create files like these, but programmatically. Like… I load a scene and add it as a child to another scene.

I’ve tried using the following function, which goes through all the nodes recursively and sets the owner node + makes the instantiated scenes editable:

# p_owner is the root node of the scene
func set_ownership(p_owner: Node, node: Node) -> void:
    # Iterate through all the children
	for child in node.get_children():

        # If the node has a scene_file_path, then the node is the root of loaded scene
        # If the the owner of the node is not null, then it's a child scene of the loaded scene
		if child.scene_file_path and child.owner == null:
			child.owner = p_owner
			p_owner.set_editable_instance(child, true)
                
        # Do this recursively for all children
		set_ownership(p_owner, child)

func save(my_scene: Node, path: String) -> void: 
    set_ownership(my_scene, my_scene)
    ...

Unfortunately this does not produce the same result. Signals are copied and all the nodes of the instantiated scene are also saved even if they aren’t changed.

But I think the method above works as intended, because I tried loading and saving a scene with an instantiated child scene that has been created through the editor and it also produces a different .tscn:

  var scene = load("res://test.tscn").instantiate()
  var pack = PackedScene.new(scene)
  ResourceSaver.save(pack, "res://test2.tscn")

As soon as the scene gets instantiated, some of the values are doubled or something. Is there any flag I am missing? I tried all the flags in the save method, but it’s not working.

1 Like

Welp…

I think I’ve found it… kind of. When instantiating a Scene you need to:

 load("res://test.tscn").instantiate(PackedScene.GEN_EDIT_STATE_MAIN_INHERITED)

Not sure if that works when I stick scenes together though.

Edit:
So this does work, but it says in the doc that the flag PackedScene.GEN_EDIT_STATE_MAIN_INHERITED only works in the Editor. I’m trying to build a plugin, so I’m assuming that I can use this. Need to test it though. Maybe this helps someone.

2 Likes

I’ve used this in a plugin as well to modify inherited scenes and save them as inherited scenes, without this flag the saved scene is a base scene, not inherited.

1 Like

So it does work in plugins. Thanks for the confirmation!!!