Created
March 1, 2026 15:28
-
-
Save zvodd/df23f3851685db42630229a96d3ab63e to your computer and use it in GitHub Desktop.
Godot Addon :: Export Node Tree Text - Show AI scene structure + scripts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @tool | |
| extends EditorPlugin | |
| const PanelScript = preload("res://addons/exportnodetree/tree_exporter_panel.gd") | |
| var dock_panel | |
| func _enter_tree(): | |
| # Instantiate the panel script | |
| dock_panel = PanelScript.new() | |
| dock_panel.name = "Node Tree Export" | |
| # Pass the editor interface reference to the panel so it can access selection/root | |
| dock_panel.set_editor_interface(get_editor_interface()) | |
| # Add the control to the bottom dock | |
| add_control_to_bottom_panel(dock_panel, "Node Export") | |
| func _exit_tree(): | |
| if dock_panel: | |
| remove_control_from_bottom_panel(dock_panel) | |
| dock_panel.queue_free() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| [plugin] | |
| name="ExportNodeTree" | |
| description="" | |
| author="" | |
| version="" | |
| script="export_node_tree.gd" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @tool | |
| extends VBoxContainer | |
| const TreeGenerator = preload("res://addons/exportnodetree/tree_generator.gd") | |
| var editor_interface: EditorInterface | |
| # UI Elements | |
| var _text_edit: TextEdit | |
| var _btn_print: Button | |
| var _chk_scripts: CheckBox | |
| var _chk_paths: CheckBox | |
| var _chk_groups: CheckBox | |
| func _ready(): | |
| # Layout Setup | |
| _setup_ui() | |
| func set_editor_interface(ei: EditorInterface): | |
| editor_interface = ei | |
| func _setup_ui(): | |
| # Toolbar HBox | |
| var toolbar = HBoxContainer.new() | |
| add_child(toolbar) | |
| _btn_print = Button.new() | |
| _btn_print.text = "Generate Tree" | |
| _btn_print.pressed.connect(_on_print_pressed) | |
| toolbar.add_child(_btn_print) | |
| var separator = VSeparator.new() | |
| toolbar.add_child(separator) | |
| _chk_scripts = CheckBox.new() | |
| _chk_scripts.text = "Include Script Code" | |
| toolbar.add_child(_chk_scripts) | |
| _chk_paths = CheckBox.new() | |
| _chk_paths.text = "Full Paths" | |
| toolbar.add_child(_chk_paths) | |
| _chk_groups = CheckBox.new() | |
| _chk_groups.text = "Show Groups" | |
| toolbar.add_child(_chk_groups) | |
| # Output Buffer | |
| _text_edit = TextEdit.new() | |
| _text_edit.size_flags_vertical = Control.SIZE_EXPAND_FILL | |
| _text_edit.editable = false # Read only | |
| _text_edit.placeholder_text = "Tree output will appear here..." | |
| # Use code font for alignment | |
| _text_edit.add_theme_font_override("font", get_theme_font("source", "EditorFonts")) | |
| add_child(_text_edit) | |
| func _on_print_pressed(): | |
| if not editor_interface: | |
| return | |
| var root = editor_interface.get_edited_scene_root() | |
| if not root: | |
| _text_edit.text = "Error: No edited scene root found." | |
| return | |
| var selection = editor_interface.get_selection() | |
| var selected_nodes = selection.get_selected_nodes() | |
| var config = { | |
| "include_scripts_content": _chk_scripts.button_pressed, | |
| "show_full_paths": _chk_paths.button_pressed, | |
| "show_groups": _chk_groups.button_pressed | |
| } | |
| var result_text = TreeGenerator.generate_output(root, selected_nodes, config) | |
| _text_edit.text = result_text |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # RuneRealm/addons/exportnodetree/tree_generator.gd | |
| @tool | |
| extends RefCounted | |
| # Generates the complete output string based on the configuration | |
| static func generate_output(root_node: Node, selected_nodes: Array[Node], config: Dictionary) -> String: | |
| if not is_instance_valid(root_node): | |
| return "Error: No Valid Root Node found." | |
| var output: String = "" | |
| var script_list: Array[Script] = [] | |
| var included_nodes: Dictionary = {} | |
| # --- 1. Determine Scope --- | |
| if selected_nodes.size() > 0: | |
| output += "--- Printing Selection Tree ---\n" | |
| for node in selected_nodes: | |
| _add_ancestors(node, included_nodes) | |
| else: | |
| output += "--- Printing Full Scene Tree (No selection made) ---\n" | |
| _mark_all_children(root_node, included_nodes) | |
| # --- 2. Build Tree String --- | |
| output += _build_tree_string(root_node, "", included_nodes, true, config, script_list) | |
| # --- 3. Append Scripts (if requested) --- | |
| if config.get("include_scripts_content", false) and script_list.size() > 0: | |
| output += "\n\n--- Attached Scripts Source Code ---\n" | |
| for script in script_list: | |
| output += "##########################\n" | |
| output += "# %s\n" % script.resource_path.get_file() | |
| output += "##########################\n\n" | |
| output += script.source_code + "\n\n" | |
| return output | |
| # --- Recursive Tree Builder --- | |
| static func _build_tree_string(node: Node, current_indent: String, included_nodes: Dictionary, is_root: bool, config: Dictionary, script_collector: Array[Script]) -> String: | |
| var result = "" | |
| # Check visibility | |
| if not included_nodes.is_empty() and not node in included_nodes: | |
| return result | |
| # Construct line text | |
| var line_text = "%s [%s]" % [node.name, node.get_class()] | |
| var script = node.get_script() | |
| if script: | |
| var script_path = script.resource_path | |
| # When show_full_paths is true, print the full resource path (res://...) | |
| # Otherwise print only the filename. | |
| if not config.get("show_full_paths", false): | |
| script_path = script_path.get_file() | |
| line_text += " (script: %s)" % script_path | |
| # Collect script for later printing if needed | |
| if not script in script_collector: | |
| script_collector.append(script) | |
| if config.get("show_groups", false): | |
| var groups = node.get_groups() | |
| if groups.size() > 0: | |
| line_text += " {groups: %s}" % str(groups) | |
| # Add to result | |
| if is_root: | |
| result += line_text + "\n" | |
| else: | |
| result += current_indent + line_text + "\n" | |
| # Calculate Children Logic | |
| var children = node.get_children() | |
| var visible_children = [] | |
| for child in children: | |
| if included_nodes.is_empty() or child in included_nodes: | |
| visible_children.append(child) | |
| var next_level_indent = "" | |
| if is_root: | |
| next_level_indent = "" | |
| else: | |
| if current_indent.ends_with("└── "): | |
| next_level_indent = current_indent.replace("└── ", " ") | |
| elif current_indent.ends_with("├── "): | |
| next_level_indent = current_indent.replace("├── ", "│ ") | |
| else: | |
| next_level_indent = current_indent | |
| for i in range(visible_children.size()): | |
| var child = visible_children[i] | |
| var is_last_child = (i == visible_children.size() - 1) | |
| var connector = "└── " if is_last_child else "├── " | |
| result += _build_tree_string(child, next_level_indent + connector, included_nodes, false, config, script_collector) | |
| return result | |
| # --- Helpers --- | |
| static func _mark_all_children(node: Node, dict: Dictionary): | |
| dict[node] = true | |
| for child in node.get_children(): | |
| _mark_all_children(child, dict) | |
| static func _add_ancestors(node: Node, included_nodes: Dictionary): | |
| var current = node | |
| while current != null: | |
| included_nodes[current] = true | |
| current = current.get_parent() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment