├── addons └── totobird_creations.gdscript_plus │ ├── LICENSE │ ├── icon.png │ ├── node_classes │ └── plugin.gd │ ├── plugin.cfg │ ├── plugin.gd │ ├── property_descriptions │ ├── editor.gd │ ├── inspector.gd │ └── plugin.gd │ └── signal_descriptions │ └── plugin.gd ├── example ├── node_class_descriptions │ ├── custom_node.gd │ ├── example.tscn │ ├── recommended_syntax.gd │ └── uncreatable_node.gd └── property_descriptions │ ├── example.gd │ └── example.tscn └── project.godot /addons/totobird_creations.gdscript_plus/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Totobird Creations 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /addons/totobird_creations.gdscript_plus/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Totobird-Creations/Godot-GDScript-Plus/8cb812676c3914da4e1c3817159acbe3ba5baafd/addons/totobird_creations.gdscript_plus/icon.png -------------------------------------------------------------------------------- /addons/totobird_creations.gdscript_plus/node_classes/plugin.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends Object 3 | 4 | 5 | 6 | var plugin : EditorPlugin 7 | 8 | var scene_trees : Array 9 | var create_dialogs : Array 10 | var create_dialog_trees : Array 11 | var create_descriptions : Array 12 | 13 | var scripts : Dictionary # Key: Path to the script. Value: Script source. 14 | var classes : Dictionary # Key: Class name. Value: Script source. 15 | 16 | 17 | 18 | func _enter_tree() -> void: 19 | plugin.get_editor_interface().get_resource_filesystem().connect("filesystem_changed", self, "update_filesystem") 20 | 21 | 22 | func _exit_tree() -> void: 23 | pass 24 | 25 | 26 | 27 | func _ready() -> void: 28 | update_filesystem() 29 | find_all_create_descriptions() 30 | 31 | 32 | 33 | func _process(delta : float) -> void: 34 | if (len(scene_trees) <= 0): 35 | find_all_scene_trees() 36 | if (len(scene_trees) > 0): 37 | parse_all_scene_trees() 38 | if (len(create_dialog_trees) <= 0): 39 | find_all_create_dialogs() 40 | if (len(create_dialog_trees) > 0): 41 | parse_all_create_trees() 42 | if (len(create_descriptions) <= 0): 43 | find_all_create_descriptions() 44 | if (len(create_descriptions) > 0): 45 | parse_all_create_descriptions() 46 | 47 | 48 | 49 | func find_all_scene_trees() -> void: 50 | scene_trees = [] 51 | for node in plugin.find_all_trees(plugin.get_tree().root, true, true): 52 | if (node.get_parent().get_class() == "SceneTreeEditor"): 53 | scene_trees.append(node) 54 | 55 | func parse_all_scene_trees() -> void: 56 | for scene_tree in scene_trees: 57 | parse_scene_tree(scene_tree) 58 | 59 | func parse_scene_tree(scene_tree : Tree) -> void: 60 | if (scene_tree.get_root()): 61 | parse_scene_tree_item(scene_tree.get_root()) 62 | 63 | func parse_scene_tree_item(item : TreeItem) -> void: 64 | var i := get_open_script_button_index(item) 65 | if (i != -1): 66 | var tooltip := item.get_button_tooltip(0, i) 67 | var prefix := TranslationServer.translate("Open Script:") + " " 68 | var fname := tooltip.trim_prefix(prefix) 69 | if (! scripts.has(fname)): 70 | try_load_script(fname) 71 | if (scripts.has(fname)): 72 | var flags := get_script_flags(scripts[fname]) 73 | if ("tree_disable_script" in flags): 74 | item.set_button_disabled(0, i, true) 75 | var next := item.get_children() 76 | while (next): 77 | parse_scene_tree_item(next) 78 | next = next.get_next() 79 | 80 | func get_open_script_button_index(item : TreeItem) -> int: 81 | for i in range(item.get_button_count(0)): 82 | var tooltip := item.get_button_tooltip(0, i) 83 | var prefix := TranslationServer.translate("Open Script:") + " " 84 | if (tooltip.begins_with(prefix)): 85 | return i 86 | return -1 87 | 88 | 89 | 90 | func find_all_create_dialogs() -> void: 91 | create_dialogs = _find_all_create_dialogs() 92 | create_dialog_trees = [] 93 | for create_dialog in create_dialogs: 94 | create_dialog_trees += plugin.find_all_trees(create_dialog, true, true) 95 | 96 | func _find_all_create_dialogs(node : Node = plugin.get_tree().root) -> Array: 97 | var res := [] 98 | if (node is AcceptDialog && node.get_class() == "CreateDialog" && node.get_parent().get_class() == "SceneTreeDock"): 99 | res.append(node) 100 | for child in node.get_children(): 101 | res += _find_all_create_dialogs(child) 102 | return res 103 | 104 | func parse_all_create_trees() -> void: 105 | for create_tree in create_dialog_trees: 106 | parse_create_tree(create_tree) 107 | 108 | func parse_create_tree(create_tree : Tree) -> void: 109 | if (create_tree.get_root()): 110 | parse_create_tree_item(create_tree.get_root()) 111 | 112 | func parse_create_tree_item(item : TreeItem) -> void: 113 | var type := item.get_text(0).split(" (")[0] 114 | if (type in classes.keys()): 115 | var flags := get_script_flags(classes[type]) 116 | var desc := get_script_description(classes[type]) 117 | if (desc != ""): 118 | item.set_tooltip(0, desc) 119 | if ("create_disable" in flags): 120 | item.set_selectable(0, false) 121 | item.set_custom_color(0, Color(1.0, 1.0, 1.0, 0.375)) 122 | if ("create_hide_script" in flags): 123 | item.set_text(0, type) 124 | var next := item.get_children() 125 | while (next): 126 | parse_create_tree_item(next) 127 | next = next.get_next() 128 | 129 | 130 | 131 | func find_all_create_descriptions() -> void: 132 | create_descriptions = [] 133 | for dialog in create_dialogs: 134 | create_descriptions += plugin.find_all_editor_help_bits(dialog) 135 | 136 | func parse_all_create_descriptions() -> void: 137 | var selected : TreeItem 138 | for tree in create_dialog_trees: 139 | selected = tree.get_selected() 140 | if (selected): 141 | var type := selected.get_text(0).split(" (")[0] 142 | if (classes.has(type)): 143 | var description := get_script_description(classes[type]) 144 | for help_bit in create_descriptions: 145 | help_bit.set_text("[b]" + type + "[/b]: " + description) 146 | break 147 | 148 | 149 | 150 | func update_filesystem(path : String = "res:/") -> void: 151 | scripts = {} 152 | classes = {} 153 | var config := ConfigFile.new() 154 | config.load("res://project.godot") 155 | if (config.has_section("") && config.has_section_key("", "_global_script_classes")): 156 | for cls in config.get_value("", "_global_script_classes"): 157 | var rsr := try_load_script(cls.path) 158 | if (rsr): 159 | classes[cls.class] = rsr.source_code 160 | """var dir := Directory.new() 161 | if (path == "res:/"): 162 | dir.open("res://") 163 | else: 164 | dir.open(path) 165 | dir.list_dir_begin(true, true) 166 | while (true): 167 | var fname := dir.get_next() 168 | var fpath := path + "/" + fname 169 | if (fname == ""): 170 | break 171 | elif (dir.dir_exists(fpath)): 172 | update_filesystem(fpath) 173 | elif (dir.file_exists(fpath) && fpath.get_extension() in ResourceLoader.get_recognized_extensions_for_type("GDScript")): 174 | var resource := ResourceLoader.load(fpath, "", false) 175 | if (resource is GDScript): 176 | var type := get_script_class_name(resource.source_code) 177 | if (type != ""): 178 | scripts[fpath] = resource.source_code 179 | classes[type] = resource.source_code 180 | dir.list_dir_end()""" 181 | 182 | func try_load_script(path : String) -> Resource: 183 | var rsr := ResourceLoader.load(path) 184 | if (rsr is GDScript): 185 | scripts[path] = rsr.source_code 186 | return rsr 187 | return null 188 | 189 | 190 | 191 | func get_script_class_name(src : String) -> String: 192 | var regex := RegEx.new() 193 | regex.compile("(?:^|\n)class_name[ \t]+(.*)") 194 | var result := regex.search(src) 195 | if (result): 196 | return result.strings[1] 197 | return "" 198 | 199 | func get_script_flags(src : String) -> Array: 200 | var flags := [] 201 | var regex := RegEx.new() 202 | regex.compile("(?:^|\n)[ \t]*#@(.*)") 203 | var results := regex.search_all(src) 204 | for result in results: 205 | var flag : String = result.strings[1].strip_edges() 206 | if (! flags.has(flag)): 207 | flags.append(flag) 208 | return flags 209 | 210 | func get_script_description(src : String) -> String: 211 | var description := PoolStringArray() 212 | var regex_global := RegEx.new() 213 | regex_global.compile("((?:(?:^|\n)[ \t]*##(?:.*))+)\nclass_name") 214 | var result_global := regex_global.search(src) 215 | if (result_global): 216 | var lines : PoolStringArray = result_global.strings[1].split("\n") 217 | for line in lines: 218 | var regex_line := RegEx.new() 219 | regex_line.compile("(?:^|\n)[ \t]*##(.*)") 220 | var result_line := regex_line.search(line) 221 | if (result_line): 222 | var desc_line : String = result_line.strings[1].strip_edges(false, true).trim_prefix(" ") 223 | description.append(desc_line) 224 | return description.join(" ") 225 | -------------------------------------------------------------------------------- /addons/totobird_creations.gdscript_plus/plugin.cfg: -------------------------------------------------------------------------------- 1 | [plugin] 2 | 3 | name="GDScript Plus" 4 | description="An addon that improves GDScript.\nFeatures:\n- Nodes with scripts can disable the script button in the scene tree.\n- Custom nodes can disable creation using the create node menu.\n- Custom nodes can hide the script filename shown in the create node menu.\n- Custom nodes can show a description in the create node menu.\n- Export properties on nodes can show different property variables.\n- Export properties on nodes can have tooltips and descriptions.\n- Signals on nodes can have tooltips and descriptions." 5 | author="Totobird Creations" 6 | version="1.0" 7 | script="plugin.gd" 8 | -------------------------------------------------------------------------------- /addons/totobird_creations.gdscript_plus/plugin.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends EditorPlugin 3 | 4 | 5 | 6 | var sub_plugins : Dictionary = { 7 | node_classes = preload('./node_classes/plugin.gd').new(), 8 | property_descriptions = preload('./property_descriptions/plugin.gd').new(), 9 | signal_descriptions = preload('./signal_descriptions/plugin.gd').new() 10 | } 11 | 12 | 13 | 14 | func _enter_tree() -> void: 15 | if (Engine.is_editor_hint()): 16 | for plugin in sub_plugins.values(): 17 | plugin.plugin = self 18 | if (plugin.has_method("_enter_tree")): 19 | plugin._enter_tree() 20 | 21 | func _exit_tree() -> void: 22 | if (Engine.is_editor_hint()): 23 | for plugin in sub_plugins.values(): 24 | if (plugin.has_method("_exit_tree")): 25 | plugin._exit_tree() 26 | 27 | 28 | 29 | func _ready() -> void: 30 | if (Engine.is_editor_hint()): 31 | for plugin in sub_plugins.values(): 32 | if (plugin.has_method("_ready")): 33 | plugin._ready() 34 | 35 | 36 | 37 | func _process(delta : float) -> void: 38 | if (Engine.is_editor_hint()): 39 | for plugin in sub_plugins.values(): 40 | if (plugin.has_method("_process")): 41 | plugin._process(delta) 42 | 43 | 44 | 45 | func find_all_editor_help_bits(node : Node, dive : bool = true, dive_past : bool = true) -> Array: 46 | var res := [] 47 | if (node.get_class() == "EditorHelpBit"): 48 | res.append(node) 49 | if (dive): 50 | for child in node.get_children(): 51 | res += find_all_editor_help_bits(child, dive_past, dive_past) 52 | return res 53 | 54 | func find_all_trees(node : Node, dive : bool = true, dive_past : bool = true) -> Array: 55 | var res := [] 56 | if (node is Tree): 57 | res.append(node) 58 | if (dive): 59 | for child in node.get_children(): 60 | res += find_all_trees(child, dive_past, dive_past) 61 | return res 62 | -------------------------------------------------------------------------------- /addons/totobird_creations.gdscript_plus/property_descriptions/editor.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | 4 | # Declare member variables here. Examples: 5 | # var a: int = 2 6 | # var b: String = "text" 7 | 8 | 9 | # Called when the node enters the scene tree for the first time. 10 | func _ready() -> void: 11 | pass # Replace with function body. 12 | 13 | 14 | # Called every frame. 'delta' is the elapsed time since the previous frame. 15 | #func _process(delta: float) -> void: 16 | # pass 17 | -------------------------------------------------------------------------------- /addons/totobird_creations.gdscript_plus/property_descriptions/inspector.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | 4 | # Declare member variables here. Examples: 5 | # var a: int = 2 6 | # var b: String = "text" 7 | 8 | 9 | # Called when the node enters the scene tree for the first time. 10 | func _ready() -> void: 11 | pass # Replace with function body. 12 | 13 | 14 | # Called every frame. 'delta' is the elapsed time since the previous frame. 15 | #func _process(delta: float) -> void: 16 | # pass 17 | -------------------------------------------------------------------------------- /addons/totobird_creations.gdscript_plus/property_descriptions/plugin.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends Object 3 | 4 | 5 | 6 | var plugin : EditorPlugin 7 | 8 | var inspector : Control 9 | 10 | var properties : Array 11 | 12 | 13 | 14 | func _process(_delta : float) -> void: 15 | if (! inspector): 16 | inspector = plugin.get_editor_interface().get_inspector().get_child(0) 17 | if (inspector): 18 | parse_all_properties(inspector) 19 | 20 | 21 | 22 | func parse_all_properties(node : Node) -> void: 23 | if (node is EditorProperty): 24 | if (node.get_edited_object().script is GDScript): 25 | var property : String = node.get_edited_property() 26 | var text_edited : bool = false 27 | var text : String = TranslationServer.translate("Property:") + " [b][u]" + property + "[/u][/b]" 28 | var description : String = "" 29 | if (node.get_edited_object().has_method("get_property_variable")): 30 | var v = node.get_edited_object().get_property_variable(property) 31 | if (v is String && v != ""): 32 | text_edited = true 33 | text = TranslationServer.translate("Property:") + " [b][u]" + v + "[/u][/b]" 34 | if (node.get_edited_object().has_method("get_property_description")): 35 | var v = node.get_edited_object().get_property_description(property) 36 | if (v is String && v != ""): 37 | description = v 38 | if (description == ""): 39 | var src : String = node.get_edited_object().script.source_code 40 | description = get_property_description(src, property) 41 | if (description != ""): 42 | text_edited = true 43 | text += "\n" + description 44 | if (text_edited): 45 | var help_bits : Array = plugin.find_all_editor_help_bits(node) 46 | if (len(help_bits) > 0): 47 | var help_bit : Control = help_bits[0] 48 | help_bit.set_text(text) 49 | help_bit.get_child(0).fit_content_height = true 50 | for child in node.get_children(): 51 | parse_all_properties(child) 52 | 53 | 54 | 55 | func get_property_description(src : String, property : String) -> String: 56 | var description := PoolStringArray() 57 | var regex_global := RegEx.new() 58 | regex_global.compile("((?:(?:^|\n)[ \t]*##(?:.*))+)\nexport *(?:\\(.*\\))?[ \t]*var[ \t]*(?:" + property + ")(?: |\t|\n|=|;)") 59 | var result_global := regex_global.search(src) 60 | if (result_global): 61 | var lines : PoolStringArray = result_global.strings[1].split("\n") 62 | for line in lines: 63 | var regex_line := RegEx.new() 64 | regex_line.compile("(?:^|\n)[ \t]*##(.*)") 65 | var result_line := regex_line.search(line) 66 | if (result_line): 67 | var desc_line : String = result_line.strings[1].strip_edges(false, true).trim_prefix(" ") 68 | description.append(desc_line) 69 | return description.join(" ") 70 | -------------------------------------------------------------------------------- /addons/totobird_creations.gdscript_plus/signal_descriptions/plugin.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends Object 3 | 4 | 5 | 6 | var plugin : EditorPlugin 7 | 8 | var connection_trees : Array 9 | var signals : Dictionary 10 | var fname : String 11 | 12 | 13 | 14 | func _process(delta : float) -> void: 15 | if (len(connection_trees) <= 0): 16 | find_all_connections() 17 | if (len(connection_trees) > 0): 18 | find_fname() 19 | parse_all_connection_trees() 20 | 21 | 22 | 23 | func find_all_connections() -> void: 24 | connection_trees = [] 25 | var docks := _find_all_connection_docks() 26 | for dock in docks: 27 | connection_trees += plugin.find_all_trees(dock, true, false) 28 | 29 | func _find_all_connection_docks(node : Node = plugin.get_tree().root) -> Array: 30 | var res := [] 31 | if (node.get_class() == "ConnectionsDock"): 32 | res.append(node) 33 | for child in node.get_children(): 34 | res += _find_all_connection_docks(child) 35 | return res 36 | 37 | func find_fname() -> void: 38 | fname = "" 39 | var node_classes : Object = plugin.sub_plugins.node_classes 40 | if (len(node_classes.scene_trees) > 0): 41 | var node : TreeItem = node_classes.scene_trees[0].get_selected() 42 | if (node): 43 | var i : int = node_classes.get_open_script_button_index(node) 44 | if (i != -1): 45 | var tooltip := node.get_button_tooltip(0, i) 46 | var prefix := TranslationServer.translate("Open Script:") + " " 47 | fname = tooltip.trim_prefix(prefix) 48 | 49 | func parse_all_connection_trees() -> void: 50 | for connection_tree in connection_trees: 51 | parse_connection_tree(connection_tree) 52 | 53 | func parse_connection_tree(connection_tree : Tree) -> void: 54 | if (connection_tree.get_root()): 55 | parse_connection_tree_item(connection_tree.get_root()) 56 | var help_bits : Array = plugin.find_all_editor_help_bits(connection_tree, true, false) 57 | if (len(help_bits) > 0): 58 | var help_bit : Control = help_bits[0] 59 | if (! help_bit.has_meta("injected_signal_description")): 60 | help_bit.set_meta("injected_signal_description", true) 61 | var parts : PoolStringArray = help_bit.get_child(0).text.trim_prefix(TranslationServer.translate("Signal:") + " ").split("(") 62 | var signame : String = parts[0] 63 | if (signame in signals.keys()): 64 | parts.remove(0) 65 | var args : String = "(" + parts.join("(") 66 | var description : String = signals[signame] 67 | help_bit.set_text(TranslationServer.translate("Signal:") + " [b][u]" + signame + "[/u][/b]" + args + "\n" + description) 68 | help_bit.get_child(0).fit_content_height = true 69 | 70 | func parse_connection_tree_item(item : TreeItem) -> void: 71 | if (fname != ""): 72 | var signame := item.get_text(0).split("(")[0] 73 | var description := get_signal_description(plugin.sub_plugins.node_classes.scripts[fname], signame) 74 | if (description != ""): 75 | signals[signame] = description 76 | var next := item.get_children() 77 | while (next): 78 | parse_connection_tree_item(next) 79 | next = next.get_next() 80 | 81 | 82 | 83 | func get_signal_description(src : String, signame : String) -> String: 84 | var description := PoolStringArray() 85 | var regex_global := RegEx.new() 86 | regex_global.compile("((?:(?:^|\n)[ \t]*##(?:.*))+)\nsignal[ \t]*(?:" + signame + ")(\\(.*\\))?(?: |\t|\n|=|;)") 87 | var result_global := regex_global.search(src) 88 | if (result_global): 89 | var lines : PoolStringArray = result_global.strings[1].split("\n") 90 | for line in lines: 91 | var regex_line := RegEx.new() 92 | regex_line.compile("(?:^|\n)[ \t]*##(.*)") 93 | var result_line := regex_line.search(line) 94 | if (result_line): 95 | var desc_line : String = result_line.strings[1].strip_edges(false, true).trim_prefix(" ") 96 | description.append(desc_line) 97 | return description.join(" ") 98 | -------------------------------------------------------------------------------- /example/node_class_descriptions/custom_node.gd: -------------------------------------------------------------------------------- 1 | extends MyCustomUncreatableNode 2 | ## This one is separated from the class_name so it won't show up 3 | 4 | ## This is my custom node that I made all by myself! 5 | ## Wow! How amazing! 6 | class_name MyCustomNode 7 | 8 | # The line below disables the open script button in the scene tree. 9 | #@ tree_disable_script 10 | 11 | 12 | 13 | func _ready() -> void: 14 | print("This node does have a script.") 15 | -------------------------------------------------------------------------------- /example/node_class_descriptions/example.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=2] 2 | 3 | [ext_resource path="res://example/node_class_descriptions/custom_node.gd" type="Script" id=1] 4 | 5 | [node name="Press create new node" type="Node"] 6 | 7 | [node name="MyCustomNode" type="Node" parent="."] 8 | script = ExtResource( 1 ) 9 | -------------------------------------------------------------------------------- /example/node_class_descriptions/recommended_syntax.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | ## This is the description of this object. 3 | ## Although it can span over multiple lines 4 | ## in the script, it will all be displayed 5 | ## in one line in the create menu. 6 | class_name TheBestObject 7 | #@tree_disable_script 8 | #@create_hide_script 9 | -------------------------------------------------------------------------------- /example/node_class_descriptions/uncreatable_node.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | ## Wow! Yet another node! Look at me go! 3 | class_name MyCustomUncreatableNode 4 | 5 | # The line below prevents the node from being created in the create node menu. 6 | #@ create_disable 7 | 8 | # The line below will hide the script name in the create node menu. 9 | #@ create_hide_script 10 | -------------------------------------------------------------------------------- /example/property_descriptions/example.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends Node 3 | 4 | #@tree_disable_script 5 | 6 | 7 | 8 | ## This is a signal description. 9 | ## More description. 10 | signal custom_signal(arg_0, arg_1) 11 | 12 | 13 | 14 | enum NamedEnum {THING_1, THING_2, ANOTHER_THING = -1} 15 | 16 | ## An integer without the export arguments. 17 | export var object = 0 18 | ## An unrestricted integer. 19 | export(int) var number 20 | ## An integer that allows values from 0 to 20 (inclusive). 21 | export(int, 20) var i; 22 | ## An integer that allows values from -10 to 20 (inclusive). 23 | export(int, -10, 20) var j; 24 | ## This is an integer enum. 25 | export(int, "Warrior", "Magician", "Thief") var character_class; 26 | ## This is an integer enum, generated from an enum. 27 | export(NamedEnum) var x 28 | ## This is an integer bit flag. 29 | export(int, FLAGS, "Fire", "Water", "Earth", "Wind") var spell_elements = 0 30 | ## This is an integer bit flag. 31 | export(int, LAYERS_2D_PHYSICS) var layers_2d_physics 32 | ## This is an integer bit flag. 33 | export(int, LAYERS_2D_RENDER) var layers_2d_render 34 | ## This is an integer bit flag. 35 | export(int, LAYERS_3D_PHYSICS) var layers_3d_physics 36 | # This is an integer bit flag that doesn't show a description. 37 | export(int, LAYERS_3D_RENDER) var layers_3d_render 38 | 39 | ## A float that allows values from -10 to 20 (inclusive), while snapping to multiples of 0.2. 40 | export(float, -10, 20, 0.2) var k 41 | ## Allow values 'y = exp(x)' where 'y' varies between 100 and 1000 42 | ## while snapping to steps of 20. The editor will present a 43 | ## slider for easily editing the value. 44 | ## All of these lines are picked up by the scanner. 45 | export(float, EXP, 100, 1000, 20) var l 46 | # Display a visual representation of the 'ease()' function. 47 | export(float, EASE) var transition_speed 48 | 49 | ## This is a vector2. 50 | export(Vector2) var vec2 51 | ## This is a vector3. 52 | export(Vector3) var vec3 53 | ## This is a quat. 54 | export(Quat) var quat 55 | 56 | ## This is a string. 57 | export(String) var string 58 | ## This is a string enum. 59 | export(String, "Rebecca", "Mary", "Leah") var character_name 60 | ## A string path to a file in this project. 61 | export(String, FILE) var f 62 | ## A string path to a directory in this project. 63 | export(String, DIR) var g 64 | ## A string path to a file in this project, with filter `*.txt`. 65 | export(String, FILE, "*.txt") var h 66 | ## A string path to a file in the global filesystem, with filter `*.png`. 67 | export(String, FILE, GLOBAL, "*.png") var tool_image 68 | ## A string path to a directory in the global filesystem. 69 | export(String, DIR, GLOBAL) var tool_dir 70 | ## This is a string with a large input field that allows multiline editing. 71 | export(String, MULTILINE) var text 72 | 73 | ## This is a colour, where alpha is always 1.0. 74 | export(Color, RGB) var col_rgb 75 | ## This is a colour with alpha. 76 | export(Color, RGBA) var col_rgba 77 | 78 | ## This is a path to another node in the scene. 79 | export(NodePath) var node_path 80 | 81 | ## This is a resource. 82 | export(Resource) var resource 83 | ## This is an animationnode resource. 84 | export(AnimationNode) var specific_resource 85 | ## This is a texture resource. 86 | export(Texture) var character_face 87 | 88 | # This line isn't picked up because it doesn't start with ## 89 | ## This is a packedscene object. 90 | export(PackedScene) var scene_file 91 | 92 | ## This is an unrestricted array. 93 | export(Array) var a 94 | ## This is an integer array. 95 | export(Array, int) var ints 96 | ## This is an integer enum array. 97 | export(Array, int, "Red", "Green", "Blue") var enums 98 | ## This is an float array array. 99 | export(Array, Array, float) var two_dimensional 100 | 101 | ## This is a poolbytearray. 102 | export(PoolByteArray) var pool_byte 103 | ## This is a poolvector3array and this label has 104 | ## [b]fancy[/b] 105 | ## 106 | ## [u]formatting[/u] 107 | ## :) 108 | export(PoolVector3Array) var pool_vector3 109 | 110 | ## This is an unrestricted dictionary. 111 | export(Dictionary) var dictionary 112 | 113 | 114 | 115 | # Return values inside of this function override commends. 116 | func get_property_description(property : String) -> String: 117 | if (property == "dictionary"): 118 | return "The get_property_description method overwrote the dictionary description." 119 | return "" 120 | 121 | 122 | 123 | func get_property_variable(property : String) -> String: 124 | if (property == "object"): 125 | return "amazing_override" 126 | return "" 127 | -------------------------------------------------------------------------------- /example/property_descriptions/example.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=2] 2 | 3 | [ext_resource path="res://example/property_descriptions/example.gd" type="Script" id=1] 4 | 5 | [node name="Hover over something in the inspector" type="Node"] 6 | script = ExtResource( 1 ) 7 | dictionary = { 8 | } 9 | -------------------------------------------------------------------------------- /project.godot: -------------------------------------------------------------------------------- 1 | ; Engine configuration file. 2 | ; It's best edited using the editor UI and not directly, 3 | ; since the parameters that go here are not all obvious. 4 | ; 5 | ; Format: 6 | ; [section] ; section goes between [] 7 | ; param=value ; assign values to parameters 8 | 9 | config_version=4 10 | 11 | _global_script_classes=[ { 12 | "base": "MyCustomUncreatableNode", 13 | "class": "MyCustomNode", 14 | "language": "GDScript", 15 | "path": "res://example/node_class_descriptions/custom_node.gd" 16 | }, { 17 | "base": "Node", 18 | "class": "MyCustomUncreatableNode", 19 | "language": "GDScript", 20 | "path": "res://example/node_class_descriptions/uncreatable_node.gd" 21 | }, { 22 | "base": "Node", 23 | "class": "TheBestObject", 24 | "language": "GDScript", 25 | "path": "res://example/node_class_descriptions/recommended_syntax.gd" 26 | } ] 27 | _global_script_class_icons={ 28 | "MyCustomNode": "", 29 | "MyCustomUncreatableNode": "", 30 | "TheBestObject": "" 31 | } 32 | 33 | [application] 34 | 35 | config/name="GDScript Plus" 36 | run/main_scene="res://example/node_class_descriptions/example.tscn" 37 | 38 | [editor_plugins] 39 | 40 | enabled=PoolStringArray( "res://addons/totobird_creations.gdscript_plus/plugin.cfg", "res://addons/zylann.editor_debugger/plugin.cfg" ) 41 | 42 | [physics] 43 | 44 | common/enable_pause_aware_picking=true 45 | --------------------------------------------------------------------------------