diff options
316 files changed, 2677 insertions, 583 deletions
diff --git a/SConstruct b/SConstruct index 8feb9e61bb..b6c98eea77 100644 --- a/SConstruct +++ b/SConstruct @@ -683,7 +683,7 @@ if selected_platform in platform_list: if env["minizip"]: env.Append(CPPDEFINES=["MINIZIP_ENABLED"]) - editor_module_list = ["freetype", "regex"] + editor_module_list = ["freetype"] if env["tools"] and not env.module_check_dependencies("tools", editor_module_list): print( "Build option 'module_" diff --git a/core/core_bind.cpp b/core/core_bind.cpp index fd5b3bb731..58aecf39aa 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -2042,6 +2042,42 @@ StringName ClassDB::get_category(const StringName &p_node) const { return ::ClassDB::get_category(p_node); } +bool ClassDB::has_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) const { + return ::ClassDB::has_enum(p_class, p_name, p_no_inheritance); +} + +PackedStringArray ClassDB::get_enum_list(const StringName &p_class, bool p_no_inheritance) const { + List<StringName> enums; + ::ClassDB::get_enum_list(p_class, &enums, p_no_inheritance); + + PackedStringArray ret; + ret.resize(enums.size()); + int idx = 0; + for (const StringName &E : enums) { + ret.set(idx++, E); + } + + return ret; +} + +PackedStringArray ClassDB::get_enum_constants(const StringName &p_class, const StringName &p_enum, bool p_no_inheritance) const { + List<StringName> constants; + ::ClassDB::get_enum_constants(p_class, p_enum, &constants, p_no_inheritance); + + PackedStringArray ret; + ret.resize(constants.size()); + int idx = 0; + for (const StringName &E : constants) { + ret.set(idx++, E); + } + + return ret; +} + +StringName ClassDB::get_integer_constant_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) const { + return ::ClassDB::get_integer_constant_enum(p_class, p_name, p_no_inheritance); +} + bool ClassDB::is_class_enabled(StringName p_class) const { return ::ClassDB::is_class_enabled(p_class); } @@ -2072,6 +2108,11 @@ void ClassDB::_bind_methods() { ::ClassDB::bind_method(D_METHOD("class_has_integer_constant", "class", "name"), &ClassDB::has_integer_constant); ::ClassDB::bind_method(D_METHOD("class_get_integer_constant", "class", "name"), &ClassDB::get_integer_constant); + ::ClassDB::bind_method(D_METHOD("class_has_enum", "class", "name", "no_inheritance"), &ClassDB::has_enum, DEFVAL(false)); + ::ClassDB::bind_method(D_METHOD("class_get_enum_list", "class", "no_inheritance"), &ClassDB::get_enum_list, DEFVAL(false)); + ::ClassDB::bind_method(D_METHOD("class_get_enum_constants", "class", "enum", "no_inheritance"), &ClassDB::get_enum_constants, DEFVAL(false)); + ::ClassDB::bind_method(D_METHOD("class_get_integer_constant_enum", "class", "name", "no_inheritance"), &ClassDB::get_integer_constant_enum, DEFVAL(false)); + ::ClassDB::bind_method(D_METHOD("class_get_category", "class"), &ClassDB::get_category); ::ClassDB::bind_method(D_METHOD("is_class_enabled", "class"), &ClassDB::is_class_enabled); } diff --git a/core/core_bind.h b/core/core_bind.h index a6fac63edd..8e95629695 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -592,6 +592,11 @@ public: int get_integer_constant(const StringName &p_class, const StringName &p_name) const; StringName get_category(const StringName &p_node) const; + bool has_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false) const; + PackedStringArray get_enum_list(const StringName &p_class, bool p_no_inheritance = false) const; + PackedStringArray get_enum_constants(const StringName &p_class, const StringName &p_enum, bool p_no_inheritance = false) const; + StringName get_integer_constant_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false) const; + bool is_class_enabled(StringName p_class) const; ClassDB() {} diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp index a17faafc0c..c6db7be53a 100644 --- a/core/input/input_map.cpp +++ b/core/input/input_map.cpp @@ -703,11 +703,11 @@ void InputMap::load_default() { OrderedHashMap<String, List<Ref<InputEvent>>> builtins = get_builtins(); // List of Builtins which have an override for macOS. - Vector<String> osx_builtins; + Vector<String> macos_builtins; for (OrderedHashMap<String, List<Ref<InputEvent>>>::Element E = builtins.front(); E; E = E.next()) { if (String(E.key()).ends_with(".macos")) { // Strip .macos from name: some_input_name.macos -> some_input_name - osx_builtins.push_back(String(E.key()).split(".")[0]); + macos_builtins.push_back(String(E.key()).split(".")[0]); } } @@ -717,12 +717,12 @@ void InputMap::load_default() { String override_for = fullname.split(".").size() > 1 ? fullname.split(".")[1] : ""; #ifdef APPLE_STYLE_KEYS - if (osx_builtins.has(name) && override_for != "osx") { - // Name has `osx` builtin but this particular one is for non-macOS systems - so skip. + if (macos_builtins.has(name) && override_for != "macos") { + // Name has `macos` builtin but this particular one is for non-macOS systems - so skip. continue; } #else - if (override_for == "osx") { + if (override_for == "macos") { // Override for macOS - not needed on non-macOS platforms. continue; } diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp index 8416ff929e..daeb7fbd17 100644 --- a/core/string/ustring.cpp +++ b/core/string/ustring.cpp @@ -1551,19 +1551,21 @@ String String::num_real(double p_num, bool p_trailing) { bool neg = p_num < 0; p_num = ABS(p_num); - int intn = (int)p_num; + int64_t intn = (int64_t)p_num; // Decimal part. if (intn != p_num) { - double dec = p_num - (double)(intn); + double dec = p_num - (double)intn; int digit = 0; -#if REAL_T_IS_DOUBLE +#ifdef REAL_T_IS_DOUBLE int decimals = 14; + double tolerance = 1e-14; #else int decimals = 6; + double tolerance = 1e-6; #endif // We want to align the digits to the above sane default, so we only // need to subtract log10 for numbers with a positive power of ten. @@ -1575,16 +1577,21 @@ String String::num_real(double p_num, bool p_trailing) { decimals = MAX_DECIMALS; } - int dec_int = 0; - int dec_max = 0; + // In case the value ends up ending in "99999", we want to add a + // tiny bit to the value we're checking when deciding when to stop, + // so we multiply by slightly above 1 (1 + 1e-7 or 1e-15). + double check_multiplier = 1 + tolerance / 10; + + int64_t dec_int = 0; + int64_t dec_max = 0; while (true) { dec *= 10.0; - dec_int = dec_int * 10 + (int)dec % 10; + dec_int = dec_int * 10 + (int64_t)dec % 10; dec_max = dec_max * 10 + 9; digit++; - if ((dec - (double)((int)dec)) < 1e-6) { + if ((dec - (double)(int64_t)(dec * check_multiplier)) < tolerance) { break; } @@ -1594,7 +1601,7 @@ String String::num_real(double p_num, bool p_trailing) { } dec *= 10; - int last = (int)dec % 10; + int last = (int64_t)dec % 10; if (last > 5) { if (dec_int == dec_max) { @@ -3555,7 +3562,7 @@ String String::strip_edges(bool left, bool right) const { } if (right) { - for (int i = (int)(len - 1); i >= 0; i--) { + for (int i = len - 1; i >= 0; i--) { if (operator[](i) <= 32) { end--; } else { diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index 755902c709..c47ce81651 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -1069,7 +1069,7 @@ <member name="TranslationServer" type="TranslationServer" setter="" getter=""> The [TranslationServer] singleton. </member> - <member name="VisualScriptEditor" type="VisualScriptCustomNodes" setter="" getter=""> + <member name="VisualScriptCustomNodes" type="VisualScriptCustomNodes" setter="" getter=""> The [VisualScriptCustomNodes] singleton. </member> <member name="XRServer" type="XRServer" setter="" getter=""> diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml index 02c6b18d55..91450e50a4 100644 --- a/doc/classes/Array.xml +++ b/doc/classes/Array.xml @@ -495,7 +495,7 @@ <argument index="2" name="step" type="int" default="1" /> <argument index="3" name="deep" type="bool" default="false" /> <description> - Duplicates the subset described in the function and returns it in an array, deeply copying the array if [code]deep[/code] is [code]true[/code]. Lower and upper index are inclusive, with the [code]step[/code] describing the change between indices while slicing. If [code]end[/code] is an invalid value, the end of the array is used. + Duplicates the subset described in the function and returns it in an array, deeply copying the array if [code]deep[/code] is [code]true[/code]. Lower and upper index are inclusive, with the [code]step[/code] describing the change between indices while slicing. Wraps around if [code]begin[/code] or [code]end[/code] are out of bounds or negative. Returns an empty array for invalid parameters. </description> </method> <method name="sort"> diff --git a/doc/classes/Camera3D.xml b/doc/classes/Camera3D.xml index 8a91a91b22..cd17a31e23 100644 --- a/doc/classes/Camera3D.xml +++ b/doc/classes/Camera3D.xml @@ -26,7 +26,7 @@ <method name="get_camera_transform" qualifiers="const"> <return type="Transform3D" /> <description> - Gets the camera transform. Subclassed cameras such as [ClippedCamera3D] may provide different transforms than the [Node] transform. + Returns the transform of the camera plus the vertical ([member v_offset]) and horizontal ([member h_offset]) offsets; and any other adjustments made to the position and orientation of the camera by subclassed cameras such as [ClippedCamera3D] and [XRCamera3D]. </description> </method> <method name="get_cull_mask_value" qualifiers="const"> diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml index 4641bc52a4..501f89fa0d 100644 --- a/doc/classes/CanvasItem.xml +++ b/doc/classes/CanvasItem.xml @@ -115,7 +115,7 @@ <argument index="4" name="outline" type="float" default="0.0" /> <argument index="5" name="pixel_range" type="float" default="4.0" /> <description> - Draws a textured rectangle region of the multi-channel signed distance field texture at a given position, optionally modulated by a color. + Draws a textured rectangle region of the multi-channel signed distance field texture at a given position, optionally modulated by a color. See [method FontData.set_multichannel_signed_distance_field] for more information and caveats about MSDF font rendering. If [code]outline[/code] is positive, each alpha channel value of pixel in region is set to maximum value of true distance in the [code]outline[/code] radius. Value of the [code]pixel_range[/code] should the same that was used during distance field texture generation. </description> diff --git a/doc/classes/ClassDB.xml b/doc/classes/ClassDB.xml index 063233fe50..62165a5fce 100644 --- a/doc/classes/ClassDB.xml +++ b/doc/classes/ClassDB.xml @@ -30,6 +30,23 @@ Returns a category associated with the class for use in documentation and the Asset Library. Debug mode required. </description> </method> + <method name="class_get_enum_constants" qualifiers="const"> + <return type="PackedStringArray" /> + <argument index="0" name="class" type="StringName" /> + <argument index="1" name="enum" type="StringName" /> + <argument index="2" name="no_inheritance" type="bool" default="false" /> + <description> + Returns an array with all the keys in [code]enum[/code] of [code]class[/code] or its ancestry. + </description> + </method> + <method name="class_get_enum_list" qualifiers="const"> + <return type="PackedStringArray" /> + <argument index="0" name="class" type="StringName" /> + <argument index="1" name="no_inheritance" type="bool" default="false" /> + <description> + Returns an array with all the enums of [code]class[/code] or its ancestry. + </description> + </method> <method name="class_get_integer_constant" qualifiers="const"> <return type="int" /> <argument index="0" name="class" type="StringName" /> @@ -38,6 +55,15 @@ Returns the value of the integer constant [code]name[/code] of [code]class[/code] or its ancestry. Always returns 0 when the constant could not be found. </description> </method> + <method name="class_get_integer_constant_enum" qualifiers="const"> + <return type="StringName" /> + <argument index="0" name="class" type="StringName" /> + <argument index="1" name="name" type="StringName" /> + <argument index="2" name="no_inheritance" type="bool" default="false" /> + <description> + Returns which enum the integer constant [code]name[/code] of [code]class[/code] or its ancestry belongs to. + </description> + </method> <method name="class_get_integer_constant_list" qualifiers="const"> <return type="PackedStringArray" /> <argument index="0" name="class" type="StringName" /> @@ -87,6 +113,15 @@ Returns an array with all the signals of [code]class[/code] or its ancestry if [code]no_inheritance[/code] is [code]false[/code]. Every element of the array is a [Dictionary] as described in [method class_get_signal]. </description> </method> + <method name="class_has_enum" qualifiers="const"> + <return type="bool" /> + <argument index="0" name="class" type="StringName" /> + <argument index="1" name="name" type="StringName" /> + <argument index="2" name="no_inheritance" type="bool" default="false" /> + <description> + Returns whether [code]class[/code] or its ancestry has an enum called [code]name[/code] or not. + </description> + </method> <method name="class_has_integer_constant" qualifiers="const"> <return type="bool" /> <argument index="0" name="class" type="StringName" /> diff --git a/doc/classes/Cubemap.xml b/doc/classes/Cubemap.xml index 61cb1d43f0..9e31ee8a92 100644 --- a/doc/classes/Cubemap.xml +++ b/doc/classes/Cubemap.xml @@ -1,8 +1,12 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="Cubemap" inherits="ImageTextureLayered" version="4.0"> <brief_description> + 6-sided texture typically used in 3D rendering. </brief_description> <description> + A cubemap is a 6-sided texture typically used for faking reflections in 3D rendering. It can be used to make an object look as if it's reflecting its surroundings. This usually delivers much better performance than other reflection methods. + This resource is typically used as a uniform in custom shaders. Few core Godot methods make use of Cubemap resources. + [b]Note:[/b] Godot doesn't support using cubemaps as a [PanoramaSkyMaterial]. You can use [url=https://danilw.github.io/GLSL-howto/cubemap_to_panorama_js/cubemap_to_panorama.html]this tool[/url] to convert a cube map to an equirectangular sky map. </description> <tutorials> </tutorials> diff --git a/doc/classes/EditorCommandPalette.xml b/doc/classes/EditorCommandPalette.xml index 743c59eec2..1d3b21255f 100644 --- a/doc/classes/EditorCommandPalette.xml +++ b/doc/classes/EditorCommandPalette.xml @@ -1,8 +1,26 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="EditorCommandPalette" inherits="ConfirmationDialog" version="4.0"> <brief_description> + Godot editor's command palette. </brief_description> <description> + Object that holds all the available Commands and their shortcuts text. These Commands can be accessed through [b]Editor > Command Palette[/b] menu. + Command key names use slash delimiters to distinguish sections Example: [code]"example/command1"[/code] then [code]example[/code] will be the section name. + [codeblocks] + [gdscript] + var command_palette = get_editor_interface().get_command_palette() + # external_command is a function that will be called with the command is executed. + var command_callable = Callable(self, "external_command").bind(arguments) + command_palette.add_command("command", "test/command",command_callable) + [/gdscript] + [csharp] + EditorCommandPalette commandPalette = GetEditorInterface().GetCommandPalette(); + // ExternalCommand is a function that will be called with the command is executed. + Callable commandCallable = new Callable(this, nameof(ExternalCommand)); + commandPalette.AddCommand("command", "test/command", commandCallable) + [/csharp] + [/codeblocks] + [b]Note:[/b] This class shouldn't be instantiated directly. Instead, access the singleton using [method EditorInterface.get_command_palette]. </description> <tutorials> </tutorials> @@ -14,12 +32,19 @@ <argument index="2" name="binded_callable" type="Callable" /> <argument index="3" name="shortcut_text" type="String" default=""None"" /> <description> + Adds a custom command to EditorCommandPalette. + - [code]command_name[/code]: [String] (Name of the [b]Command[/b]. This is displayed to the user.) + - [code]key_name[/code]: [String] (Name of the key for a particular [b]Command[/b]. This is used to uniquely identify the [b]Command[/b].) + - [code]binded_callable[/code]: [Callable] (Callable of the [b]Command[/b]. This will be executed when the [b]Command[/b] is selected.) + - [code]shortcut_text[/code]: [String] (Shortcut text of the [b]Command[/b] if available.) </description> </method> <method name="remove_command"> <return type="void" /> <argument index="0" name="key_name" type="String" /> <description> + Removes the custom command from EditorCommandPalette. + - [code]key_name[/code]: [String] (Name of the key for a particular [b]Command[/b].) </description> </method> </methods> diff --git a/doc/classes/EditorInterface.xml b/doc/classes/EditorInterface.xml index 91e1dfbf57..8558f4b9f7 100644 --- a/doc/classes/EditorInterface.xml +++ b/doc/classes/EditorInterface.xml @@ -33,6 +33,7 @@ <method name="get_command_palette" qualifiers="const"> <return type="EditorCommandPalette" /> <description> + Returns the editor's [EditorCommandPalette] instance. </description> </method> <method name="get_current_path" qualifiers="const"> diff --git a/doc/classes/File.xml b/doc/classes/File.xml index 8ecdc8b220..cf08029c72 100644 --- a/doc/classes/File.xml +++ b/doc/classes/File.xml @@ -58,8 +58,20 @@ <method name="eof_reached" qualifiers="const"> <return type="bool" /> <description> - Returns [code]true[/code] if the file cursor has read past the end of the file. - [b]Note:[/b] This function will still return [code]false[/code] while at the end of the file and only activates when reading past it. This can be confusing but it conforms to how low-level file access works in all operating systems. There is always [method get_length] and [method get_position] to implement a custom logic. + Returns [code]true[/code] if the file cursor has already read past the end of the file. + [b]Note:[/b] [code]eof_reached() == false[/code] cannot be used to check whether there is more data available. To loop while there is more data available, use: + [codeblocks] + [gdscript] + while file.get_position() < file.get_length(): + # Read data + [/gdscript] + [csharp] + while (file.GetPosition() < file.GetLength()) + { + // Read data + } + [/csharp] + [/codeblocks] </description> </method> <method name="file_exists" qualifiers="const"> diff --git a/doc/classes/FontData.xml b/doc/classes/FontData.xml index 72af7ca485..384d7c81f4 100644 --- a/doc/classes/FontData.xml +++ b/doc/classes/FontData.xml @@ -558,7 +558,8 @@ <return type="void" /> <argument index="0" name="msdf" type="bool" /> <description> - If set to [code]true[/code], glyphs of all sizes are rendered using single multichannel signed distance field generated from the dynamic font vector data. + If set to [code]true[/code], glyphs of all sizes are rendered using single multichannel signed distance field (MSDF) generated from the dynamic font vector data. MSDF rendering allows displaying the font at any scaling factor without blurriness, and without incurring a CPU cost when the font size changes (since the font no longer needs to be rasterized on the CPU). As a downside, font hinting is not available with MSDF. The lack of font hinting may result in less crisp and less readable fonts at small sizes. + [b]Note:[/b] MSDF font rendering does not render glyphs with overlapping shapes correctly. Overlapping shapes are not valid per the OpenType standard, but are still commonly found in many font files, especially those converted by Google Fonts. To avoid issues with overlapping glyphs, consider downloading the font file directly from the type foundry instead of relying on Google Fonts. </description> </method> <method name="set_oversampling"> diff --git a/doc/classes/MainLoop.xml b/doc/classes/MainLoop.xml index 11124a1436..1df00f556a 100644 --- a/doc/classes/MainLoop.xml +++ b/doc/classes/MainLoop.xml @@ -5,15 +5,14 @@ </brief_description> <description> [MainLoop] is the abstract base class for a Godot project's game loop. It is inherited by [SceneTree], which is the default game loop implementation used in Godot projects, though it is also possible to write and use one's own [MainLoop] subclass instead of the scene tree. - Upon the application start, a [MainLoop] implementation must be provided to the OS; otherwise, the application will exit. This happens automatically (and a [SceneTree] is created) unless a main [Script] is provided from the command line (with e.g. [code]godot -s my_loop.gd[/code], which should then be a [MainLoop] implementation. + Upon the application start, a [MainLoop] implementation must be provided to the OS; otherwise, the application will exit. This happens automatically (and a [SceneTree] is created) unless a [MainLoop] [Script] is provided from the command line (with e.g. [code]godot -s my_loop.gd[/code] or the "Main Loop Type" project setting is overwritten. Here is an example script implementing a simple [MainLoop]: - [b]FIXME:[/b] No longer valid after DisplayServer split and Input refactoring. - [codeblock] + [codeblocks] + [gdscript] + class_name CustomMainLoop extends MainLoop var time_elapsed = 0 - var keys_typed = [] - var quit = false func _initialize(): print("Initialized:") @@ -22,24 +21,41 @@ func _process(delta): time_elapsed += delta # Return true to end the main loop. - return quit - - func _input_event(event): - # Record keys. - if event is InputEventKey and event.pressed and !event.echo: - keys_typed.append(OS.get_keycode_string(event.keycode)) - # Quit on Escape press. - if event.keycode == KEY_ESCAPE: - quit = true - # Quit on any mouse click. - if event is InputEventMouseButton: - quit = true + return Input.get_mouse_button_mask() != 0 || Input.is_key_pressed(KEY_ESCAPE) func _finalize(): print("Finalized:") print(" End time: %s" % str(time_elapsed)) - print(" Keys typed: %s" % var2str(keys_typed)) - [/codeblock] + [/gdscript] + [csharp] + using Godot; + using System; + + public class CustomMainLoop : MainLoop + { + public float TimeElapsed = 0; + + public override void _Initialize() + { + GD.Print("Initialized:"); + GD.Print($" Starting Time: {TimeElapsed}"); + } + + public override bool _Process(float delta) + { + TimeElapsed += delta; + // Return true to end the main loop. + return Input.GetMouseButtonMask() != 0 || Input.IsKeyPressed((int)KeyList.Escape); + } + + private void _Finalize() + { + GD.Print("Finalized:"); + GD.Print($" End Time: {TimeElapsed}"); + } + } + [/csharp] + [/codeblocks] </description> <tutorials> </tutorials> diff --git a/doc/classes/Mutex.xml b/doc/classes/Mutex.xml index f97b2344a5..0e6b1e3e44 100644 --- a/doc/classes/Mutex.xml +++ b/doc/classes/Mutex.xml @@ -14,18 +14,21 @@ <return type="void" /> <description> Locks this [Mutex], blocks until it is unlocked by the current owner. + [b]Note:[/b] This function returns without blocking if the thread already has ownership of the mutex. </description> </method> <method name="try_lock"> <return type="int" enum="Error" /> <description> Tries locking this [Mutex], but does not block. Returns [constant OK] on success, [constant ERR_BUSY] otherwise. + [b]Note:[/b] This function returns [constant OK] if the thread already has ownership of the mutex. </description> </method> <method name="unlock"> <return type="void" /> <description> Unlocks this [Mutex], leaving it to other threads. + [b]Note:[/b] If a thread called [method lock] or [method try_lock] multiple times while already having ownership of the mutex, it must also call [method unlock] the same number of times in order to unlock it correctly. </description> </method> </methods> diff --git a/doc/classes/Node2D.xml b/doc/classes/Node2D.xml index cc790b7c28..4f5c2bbd6e 100644 --- a/doc/classes/Node2D.xml +++ b/doc/classes/Node2D.xml @@ -23,6 +23,7 @@ <argument index="0" name="point" type="Vector2" /> <description> Returns the angle between the node and the [code]point[/code] in radians. + [url=https://raw.githubusercontent.com/godotengine/godot-docs/master/img/node2d_get_angle_to.png]Illustration of the returned angle.[/url] </description> </method> <method name="get_relative_transform_to_parent" qualifiers="const"> diff --git a/doc/classes/PhysicsServer2D.xml b/doc/classes/PhysicsServer2D.xml index b3b7fcd956..7e5d7ca704 100644 --- a/doc/classes/PhysicsServer2D.xml +++ b/doc/classes/PhysicsServer2D.xml @@ -823,7 +823,7 @@ Sets the value for a space parameter. See [enum SpaceParameter] for a list of available parameters. </description> </method> - <method name="world_margin_shape_create"> + <method name="world_boundary_shape_create"> <return type="RID" /> <description> </description> @@ -853,8 +853,8 @@ </constant> <constant name="SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH" value="7" enum="SpaceParameter"> </constant> - <constant name="SHAPE_WORLD_MARGIN" value="0" enum="ShapeType"> - This is the constant for creating world margin shapes. A world margin shape is an [i]infinite[/i] line with an origin point, and a normal. Thus, it can be used for front/behind checks. + <constant name="SHAPE_WORLD_BOUNDARY" value="0" enum="ShapeType"> + This is the constant for creating world boundary shapes. A world boundary shape is an [i]infinite[/i] line with an origin point, and a normal. Thus, it can be used for front/behind checks. </constant> <constant name="SHAPE_SEPARATION_RAY" value="1" enum="ShapeType"> This is the constant for creating separation ray shapes. A separation ray is defined by a length and separates itself from what is touching its far endpoint. Useful for character controllers. diff --git a/doc/classes/PhysicsServer3D.xml b/doc/classes/PhysicsServer3D.xml index 2fbe84b8b1..c7db312b9d 100644 --- a/doc/classes/PhysicsServer3D.xml +++ b/doc/classes/PhysicsServer3D.xml @@ -855,11 +855,6 @@ Sets a pin_joint parameter (see [enum PinJointParam] constants). </description> </method> - <method name="plane_shape_create"> - <return type="RID" /> - <description> - </description> - </method> <method name="separation_ray_shape_create"> <return type="RID" /> <description> @@ -975,6 +970,11 @@ <description> </description> </method> + <method name="world_boundary_shape_create"> + <return type="RID" /> + <description> + </description> + </method> </methods> <constants> <constant name="JOINT_TYPE_PIN" value="0" enum="JointType"> @@ -1184,8 +1184,8 @@ <constant name="G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR" value="5" enum="G6DOFJointAxisFlag"> If [code]set[/code] there is a linear motor on this axis that targets a specific velocity. </constant> - <constant name="SHAPE_PLANE" value="0" enum="ShapeType"> - The [Shape3D] is a [WorldMarginShape3D]. + <constant name="SHAPE_WORLD_BOUNDARY" value="0" enum="ShapeType"> + The [Shape3D] is a [WorldBoundaryShape3D]. </constant> <constant name="SHAPE_SEPARATION_RAY" value="1" enum="ShapeType"> The [Shape3D] is a [SeparationRayShape3D]. diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 46307bb44c..22ed14743a 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -279,6 +279,9 @@ <member name="audio/driver/mix_rate" type="int" setter="" getter="" default="44100"> The mixing rate used for audio (in Hz). In general, it's better to not touch this and leave it to the host operating system. </member> + <member name="audio/driver/mix_rate.web" type="int" setter="" getter="" default="0"> + Safer override for [member audio/driver/mix_rate] in the Web platform. Here [code]0[/code] means "let the browser choose" (since some browsers do not like forcing the mix rate). + </member> <member name="audio/driver/output_latency" type="int" setter="" getter="" default="15"> Output latency in milliseconds for audio. Lower values will result in lower audio latency at the cost of increased CPU usage. Low values may result in audible cracking on slower hardware. </member> diff --git a/doc/classes/Resource.xml b/doc/classes/Resource.xml index 65dedf5280..efb0339aa7 100644 --- a/doc/classes/Resource.xml +++ b/doc/classes/Resource.xml @@ -16,7 +16,8 @@ <return type="Resource" /> <argument index="0" name="subresources" type="bool" default="false" /> <description> - Duplicates the resource, returning a new resource. By default, sub-resources are shared between resource copies for efficiency. This can be changed by passing [code]true[/code] to the [code]subresources[/code] argument which will copy the subresources. + Duplicates the resource, returning a new resource with the exported members copied. [b]Note:[/b] To duplicate the resource the constructor is called without arguments. This method will error when the constructor doesn't have default values. + By default, sub-resources are shared between resource copies for efficiency. This can be changed by passing [code]true[/code] to the [code]subresources[/code] argument which will copy the subresources. [b]Note:[/b] If [code]subresources[/code] is [code]true[/code], this method will only perform a shallow copy. Nested resources within subresources will not be duplicated and will still be shared. [b]Note:[/b] When duplicating a resource, only [code]export[/code]ed properties are copied. Other properties will be set to their default value in the new resource. </description> diff --git a/doc/classes/RichTextLabel.xml b/doc/classes/RichTextLabel.xml index e77232a613..b5d2d46a85 100644 --- a/doc/classes/RichTextLabel.xml +++ b/doc/classes/RichTextLabel.xml @@ -7,6 +7,7 @@ Rich text can contain custom text, fonts, images and some basic formatting. The label manages these as an internal tag stack. It also adapts itself to given width/heights. [b]Note:[/b] Assignments to [member bbcode_text] clear the tag stack and reconstruct it from the property's contents. Any edits made to [member bbcode_text] will erase previous edits made from other manual sources such as [method append_bbcode] and the [code]push_*[/code] / [method pop] methods. [b]Note:[/b] RichTextLabel doesn't support entangled BBCode tags. For example, instead of using [code][b]bold[i]bold italic[/b]italic[/i][/code], use [code][b]bold[i]bold italic[/i][/b][i]italic[/i][/code]. + [b]Note:[/b] [code]push_*/pop[/code] functions won't affect BBCode. [b]Note:[/b] Unlike [Label], RichTextLabel doesn't have a [i]property[/i] to horizontally align text to the center. Instead, enable [member bbcode_enabled] and surround the text in a [code][center][/code] tag as follows: [code][center]Example[/center][/code]. There is currently no built-in way to vertically align text either, but this can be emulated by relying on anchors/containers and the [member fit_content_height] property. </description> <tutorials> diff --git a/doc/classes/SceneTree.xml b/doc/classes/SceneTree.xml index e81eff35ac..9a38e52b23 100644 --- a/doc/classes/SceneTree.xml +++ b/doc/classes/SceneTree.xml @@ -219,7 +219,7 @@ </member> <member name="paused" type="bool" setter="set_pause" getter="is_paused" default="false"> If [code]true[/code], the [SceneTree] is paused. Doing so will have the following behavior: - - 2D and 3D physics will be stopped. + - 2D and 3D physics will be stopped. This includes signals and collision detection. - [method Node._process], [method Node._physics_process] and [method Node._input] will not be called anymore in nodes. </member> <member name="root" type="Window" setter="" getter="get_root"> diff --git a/doc/classes/StyleBoxFlat.xml b/doc/classes/StyleBoxFlat.xml index 59ab724f48..40f6075528 100644 --- a/doc/classes/StyleBoxFlat.xml +++ b/doc/classes/StyleBoxFlat.xml @@ -120,6 +120,7 @@ <members> <member name="anti_aliasing" type="bool" setter="set_anti_aliased" getter="is_anti_aliased" default="true"> Antialiasing draws a small ring around the edges, which fades to transparency. As a result, edges look much smoother. This is only noticeable when using rounded corners. + [b]Note:[/b] When using beveled corners with 45-degree angles ([member corner_detail] = 1), it is recommended to set [member anti_aliasing] to [code]false[/code] to ensure crisp visuals and avoid possible visual glitches. </member> <member name="anti_aliasing_size" type="float" setter="set_aa_size" getter="get_aa_size" default="0.625"> This changes the size of the faded ring. Higher values can be used to achieve a "blurry" effect. diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml index d7af2204cf..661c4f05ef 100644 --- a/doc/classes/TextServer.xml +++ b/doc/classes/TextServer.xml @@ -624,7 +624,8 @@ <argument index="0" name="font_rid" type="RID" /> <argument index="1" name="msdf" type="bool" /> <description> - If set to [code]true[/code], glyphs of all sizes are rendered using single multichannel signed distance field generated from the dynamic font vector data. + If set to [code]true[/code], glyphs of all sizes are rendered using single multichannel signed distance field generated from the dynamic font vector data. MSDF rendering allows displaying the font at any scaling factor without blurriness, and without incurring a CPU cost when the font size changes (since the font no longer needs to be rasterized on the CPU). As a downside, font hinting is not available with MSDF. The lack of font hinting may result in less crisp and less readable fonts at small sizes. + [b]Note:[/b] MSDF font rendering does not render glyphs with overlapping shapes correctly. Overlapping shapes are not valid per the OpenType standard, but are still commonly found in many font files, especially those converted by Google Fonts. To avoid issues with overlapping glyphs, consider downloading the font file directly from the type foundry instead of relying on Google Fonts. </description> </method> <method name="font_set_oversampling"> diff --git a/doc/classes/Tween.xml b/doc/classes/Tween.xml index 372a6e7ebf..ede6e2fdd5 100644 --- a/doc/classes/Tween.xml +++ b/doc/classes/Tween.xml @@ -58,8 +58,8 @@ [codeblock] var tween = create_tween().set_parallel(true) tween.tween_property(...) - tween.tween_property(...) #will run parallelly with above - tween.chain().tween_property(...) #will run after two above are finished + tween.tween_property(...) # Will run parallelly with above. + tween.chain().tween_property(...) # Will run after two above are finished. [/codeblock] </description> </method> @@ -215,11 +215,9 @@ Creates and appends an [IntervalTweener]. This method can be used to create delays in the tween animation, as an alternative for using the delay in other [Tweener]s or when there's no animation (in which case the [Tween] acts as a timer). [code]time[/code] is the length of the interval, in seconds. Example: creating an interval in code execution. [codeblock] - #... some code - var tween = create_tween() - tween.tween_interval(2) - await tween.finished - #... more code + # ... some code + await create_tween().tween_interval(2).finished + # ... more code [/codeblock] Example: creating an object that moves back and forth and jumps every few seconds. [codeblock] @@ -236,15 +234,15 @@ <method name="tween_method"> <return type="MethodTweener" /> <argument index="0" name="method" type="Callable" /> - <argument index="1" name="from" type="float" /> - <argument index="2" name="to" type="float" /> + <argument index="1" name="from" type="Variant" /> + <argument index="2" name="to" type="Variant" /> <argument index="3" name="duration" type="float" /> <description> Creates and appends a [MethodTweener]. This method is similar to a combination of [method tween_callback] and [method tween_property]. It calls a method over time with a tweened value provided as an argument. The value is tweened between [code]from[/code] and [code]to[/code] over the time specified by [code]duration[/code], in seconds. Use [method Callable.bind] to bind additional arguments for the call. You can use [method MethodTweener.set_ease] and [method MethodTweener.set_trans] to tweak the easing and transition of the value or [method MethodTweener.set_delay] to delay the tweening. Example: making a 3D object look from one point to another point. [codeblock] var tween = create_tween() - tween.tween_method(look_at.bind(Vector3.UP), Vector3(-1, 0, -1), Vector3(1, 0, -1), 1) #the look_at() method takes up vector as second argument + tween.tween_method(look_at.bind(Vector3.UP), Vector3(-1, 0, -1), Vector3(1, 0, -1), 1) # The look_at() method takes up vector as second argument. [/codeblock] Example: setting a text of a [Label], using an intermediate method and after a delay. [codeblock] diff --git a/doc/classes/Vector2.xml b/doc/classes/Vector2.xml index ab4d0e181a..e61f1fe951 100644 --- a/doc/classes/Vector2.xml +++ b/doc/classes/Vector2.xml @@ -56,6 +56,7 @@ <description> Returns this vector's angle with respect to the positive X axis, or [code](1, 0)[/code] vector, in radians. For example, [code]Vector2.RIGHT.angle()[/code] will return zero, [code]Vector2.DOWN.angle()[/code] will return [code]PI / 2[/code] (a quarter turn, or 90 degrees), and [code]Vector2(1, -1).angle()[/code] will return [code]-PI / 4[/code] (a negative eighth turn, or -45 degrees). + [url=https://raw.githubusercontent.com/godotengine/godot-docs/master/img/vector2_angle.png]Illustration of the returned angle.[/url] Equivalent to the result of [method @GlobalScope.atan2] when called with the vector's [member y] and [member x] as parameters: [code]atan2(y, x)[/code]. </description> </method> @@ -64,6 +65,7 @@ <argument index="0" name="to" type="Vector2" /> <description> Returns the angle to the given vector, in radians. + [url=https://raw.githubusercontent.com/godotengine/godot-docs/master/img/vector2_angle_to.png]Illustration of the returned angle.[/url] </description> </method> <method name="angle_to_point" qualifiers="const"> @@ -71,6 +73,7 @@ <argument index="0" name="to" type="Vector2" /> <description> Returns the angle between the line connecting the two points and the X axis, in radians. + [url=https://raw.githubusercontent.com/godotengine/godot-docs/master/img/vector2_angle_to_point.png]Illustration of the returned angle.[/url] </description> </method> <method name="aspect" qualifiers="const"> diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml index d7b156cc57..15d844aacb 100644 --- a/doc/classes/Window.xml +++ b/doc/classes/Window.xml @@ -1,8 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="Window" inherits="Viewport" version="4.0"> <brief_description> + Base class for all windows. </brief_description> <description> + A node that creates a window. </description> <tutorials> </tutorials> @@ -10,6 +12,7 @@ <method name="can_draw" qualifiers="const"> <return type="bool" /> <description> + Returns whether the window is being drawn to the screen. </description> </method> <method name="child_controls_changed"> @@ -27,6 +30,7 @@ <return type="bool" /> <argument index="0" name="flag" type="int" enum="Window.Flags" /> <description> + Returns [code]true[/code] if the flag is set. </description> </method> <method name="get_layout_direction" qualifiers="const"> @@ -38,6 +42,7 @@ <method name="get_real_size" qualifiers="const"> <return type="Vector2i" /> <description> + Returns the window's size including its border. </description> </method> <method name="get_theme_color" qualifiers="const"> @@ -87,11 +92,13 @@ <method name="grab_focus"> <return type="void" /> <description> + Causes the window to grab focus, allowing it to receive user input. </description> </method> <method name="has_focus" qualifiers="const"> <return type="bool" /> <description> + Returns [code]true[/code] if the window is focused. </description> </method> <method name="has_theme_color" qualifiers="const"> @@ -148,6 +155,7 @@ <method name="is_embedded" qualifiers="const"> <return type="bool" /> <description> + Returns [code]true[/code] if the window is currently embedded in another window. </description> </method> <method name="is_layout_rtl" qualifiers="const"> @@ -212,6 +220,7 @@ <argument index="0" name="flag" type="int" enum="Window.Flags" /> <argument index="1" name="enabled" type="bool" /> <description> + Sets a specified window flag. </description> </method> <method name="set_ime_active"> @@ -247,11 +256,13 @@ </methods> <members> <member name="always_on_top" type="bool" setter="set_flag" getter="get_flag" default="false"> + If [code]true[/code], the window will be on top of all other windows. </member> <member name="auto_translate" type="bool" setter="set_auto_translate" getter="is_auto_translating" default="true"> Toggles if any text should automatically change to its translated version depending on the current locale. </member> <member name="borderless" type="bool" setter="set_flag" getter="get_flag" default="false"> + If [code]true[/code], the window will have no borders. </member> <member name="content_scale_aspect" type="int" setter="set_content_scale_aspect" getter="get_content_scale_aspect" enum="Window.ContentScaleAspect" default="0"> </member> @@ -260,6 +271,7 @@ <member name="content_scale_size" type="Vector2i" setter="set_content_scale_size" getter="get_content_scale_size" default="Vector2i(0, 0)"> </member> <member name="current_screen" type="int" setter="set_current_screen" getter="get_current_screen" default="0"> + The screen the window is currently on. </member> <member name="exclusive" type="bool" setter="set_exclusive" getter="is_exclusive" default="false"> </member> @@ -268,16 +280,21 @@ <member name="min_size" type="Vector2i" setter="set_min_size" getter="get_min_size" default="Vector2i(0, 0)"> </member> <member name="mode" type="int" setter="set_mode" getter="get_mode" enum="Window.Mode" default="0"> + Set's the window's current mode. + [b]Note:[/b] Fullscreen mode is not exclusive fullscreen on Windows and Linux. </member> <member name="position" type="Vector2i" setter="set_position" getter="get_position" default="Vector2i(0, 0)"> + The window's position in pixels. </member> <member name="size" type="Vector2i" setter="set_size" getter="get_size" default="Vector2i(100, 100)"> + The window's size in pixels. </member> <member name="theme" type="Theme" setter="set_theme" getter="get_theme"> </member> <member name="theme_type_variation" type="StringName" setter="set_theme_type_variation" getter="get_theme_type_variation" default="&"""> </member> <member name="title" type="String" setter="set_title" getter="get_title" default=""""> + The window's title. </member> <member name="transient" type="bool" setter="set_transient" getter="is_transient" default="false"> </member> @@ -286,8 +303,10 @@ <member name="unfocusable" type="bool" setter="set_flag" getter="get_flag" default="false"> </member> <member name="unresizable" type="bool" setter="set_flag" getter="get_flag" default="false"> + If [code]true[/code], the window can't be resized. </member> <member name="visible" type="bool" setter="set_visible" getter="is_visible" default="true"> + If [code]true[/code], the window is visible. </member> <member name="wrap_controls" type="bool" setter="set_wrap_controls" getter="is_wrapping_controls" default="false"> </member> @@ -340,20 +359,26 @@ <constant name="NOTIFICATION_VISIBILITY_CHANGED" value="30"> </constant> <constant name="MODE_WINDOWED" value="0" enum="Mode"> + Windowed mode. </constant> <constant name="MODE_MINIMIZED" value="1" enum="Mode"> + Minimized window mode. </constant> <constant name="MODE_MAXIMIZED" value="2" enum="Mode"> + Maximized window mode. </constant> <constant name="MODE_FULLSCREEN" value="3" enum="Mode"> Fullscreen window mode. Note that this is not [i]exclusive[/i] fullscreen. On Windows and Linux, a borderless window is used to emulate fullscreen. On macOS, a new desktop is used to display the running project. Regardless of the platform, enabling fullscreen will change the window size to match the monitor's size. Therefore, make sure your project supports [url=https://docs.godotengine.org/en/latest/tutorials/rendering/multiple_resolutions.html]multiple resolutions[/url] when enabling fullscreen mode. </constant> <constant name="FLAG_RESIZE_DISABLED" value="0" enum="Flags"> + The window's ability to be resized. </constant> <constant name="FLAG_BORDERLESS" value="1" enum="Flags"> + Borderless window. </constant> <constant name="FLAG_ALWAYS_ON_TOP" value="2" enum="Flags"> + Flag for making the window always on top of all other windows. </constant> <constant name="FLAG_TRANSPARENT" value="3" enum="Flags"> </constant> diff --git a/doc/classes/WorldMarginShape2D.xml b/doc/classes/WorldBoundaryShape2D.xml index 1839ab16ad..190f289601 100644 --- a/doc/classes/WorldMarginShape2D.xml +++ b/doc/classes/WorldBoundaryShape2D.xml @@ -1,10 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="WorldMarginShape2D" inherits="Shape2D" version="4.0"> +<class name="WorldBoundaryShape2D" inherits="Shape2D" version="4.0"> <brief_description> - Line shape for 2D collisions. + World boundary shape for 2D collisions. </brief_description> <description> - Line shape for 2D collisions. It works like a 2D plane and will not allow any physics body to go to the negative side. Not recommended for rigid bodies, and usually not recommended for static bodies either because it forces checks against it on every frame. + World boundary shape for 2D collisions. It works like a 2D plane and will not allow any physics body to go to the negative side. Not recommended for rigid bodies, and usually not recommended for static bodies either because it forces checks against it on every frame. </description> <tutorials> </tutorials> diff --git a/doc/classes/WorldBoundaryShape3D.xml b/doc/classes/WorldBoundaryShape3D.xml new file mode 100644 index 0000000000..837b023a58 --- /dev/null +++ b/doc/classes/WorldBoundaryShape3D.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="WorldBoundaryShape3D" inherits="Shape3D" version="4.0"> + <brief_description> + World boundary shape for 3D collisions. + </brief_description> + <description> + World boundary shape for 3D collisions. It works like an infinite plane and will not allow any physics body to go to the negative side. Note that the [Plane]'s normal matters; anything "below" the plane will collide with it. If the [WorldBoundaryShape3D] is used in a [PhysicsBody3D], it will cause colliding objects placed "below" it to teleport "above" the plane. + </description> + <tutorials> + </tutorials> + <methods> + </methods> + <members> + <member name="plane" type="Plane" setter="set_plane" getter="get_plane" default="Plane(0, 1, 0, 0)"> + The [Plane] used by the [WorldBoundaryShape3D] for collision. + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/WorldMarginShape3D.xml b/doc/classes/WorldMarginShape3D.xml deleted file mode 100644 index 9a26f254f1..0000000000 --- a/doc/classes/WorldMarginShape3D.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="WorldMarginShape3D" inherits="Shape3D" version="4.0"> - <brief_description> - Infinite plane shape for 3D collisions. - </brief_description> - <description> - An infinite plane shape for 3D collisions. Note that the [Plane]'s normal matters; anything "below" the plane will collide with it. If the [WorldMarginShape3D] is used in a [PhysicsBody3D], it will cause colliding objects placed "below" it to teleport "above" the plane. - </description> - <tutorials> - </tutorials> - <methods> - </methods> - <members> - <member name="plane" type="Plane" setter="set_plane" getter="get_plane" default="Plane(0, 1, 0, 0)"> - The [Plane] used by the [WorldMarginShape3D] for collision. - </member> - </members> - <constants> - </constants> -</class> diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 5599076c40..0c49a7169d 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -834,11 +834,9 @@ void CodeTextEditor::_line_col_changed() { } StringBuilder sb; - sb.append("("); - sb.append(itos(text_editor->get_caret_line() + 1).lpad(3)); - sb.append(","); + sb.append(itos(text_editor->get_caret_line() + 1).lpad(4)); + sb.append(" : "); sb.append(itos(positional_column + 1).lpad(3)); - sb.append(")"); line_and_col_txt->set_text(sb.as_string()); } diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index 490c8f287f..8c935b846a 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -117,7 +117,7 @@ void EditorHelp::_class_desc_select(const String &p_select) { } else { if (table->has(link)) { // Found in the current page - class_desc->scroll_to_line((*table)[link]); + class_desc->scroll_to_paragraph((*table)[link]); } else { if (topic == "class_enum") { // Try to find the enum in @GlobalScope @@ -1345,7 +1345,7 @@ void EditorHelp::_help_callback(const String &p_topic) { } } - class_desc->call_deferred(SNAME("scroll_to_line"), line); + class_desc->call_deferred(SNAME("scroll_to_paragraph"), line); } static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) { @@ -1653,7 +1653,7 @@ Vector<Pair<String, int>> EditorHelp::get_sections() { void EditorHelp::scroll_to_section(int p_section_index) { int line = section_line[p_section_index].second; - class_desc->scroll_to_line(line); + class_desc->scroll_to_paragraph(line); } void EditorHelp::popup_search() { diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 9c7f80b2b0..812bbd9b7d 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -615,19 +615,6 @@ void EditorNode::_notification(int p_what) { } break; case NOTIFICATION_READY: { - { - _initializing_addons = true; - Vector<String> addons; - if (ProjectSettings::get_singleton()->has_setting("editor_plugins/enabled")) { - addons = ProjectSettings::get_singleton()->get("editor_plugins/enabled"); - } - - for (int i = 0; i < addons.size(); i++) { - set_addon_plugin_enabled(addons[i], true); - } - _initializing_addons = false; - } - RenderingServer::get_singleton()->viewport_set_disable_2d(get_scene_root()->get_viewport_rid(), true); RenderingServer::get_singleton()->viewport_set_disable_environment(get_viewport()->get_viewport_rid(), true); @@ -986,6 +973,18 @@ void EditorNode::_sources_changed(bool p_exist) { load_scene(defer_load_scene); defer_load_scene = ""; } + + // Only enable addons once resources have been imported + _initializing_addons = true; + Vector<String> addons; + if (ProjectSettings::get_singleton()->has_setting("editor_plugins/enabled")) { + addons = ProjectSettings::get_singleton()->get("editor_plugins/enabled"); + } + + for (int i = 0; i < addons.size(); i++) { + set_addon_plugin_enabled(addons[i], true); + } + _initializing_addons = false; } } diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 8d579753c2..1953270b08 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -300,6 +300,14 @@ bool EditorSettings::has_default_value(const String &p_setting) const { void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _THREAD_SAFE_METHOD_ +// Sets up the editor setting with a default value and hint PropertyInfo. +#define EDITOR_SETTING(m_type, m_property_hint, m_name, m_default_value, m_hint_string) \ + _initial_set(m_name, m_default_value); \ + hints[m_name] = PropertyInfo(m_type, m_name, m_property_hint, m_hint_string); + +#define EDITOR_SETTING_USAGE(m_type, m_property_hint, m_name, m_default_value, m_hint_string, m_usage) \ + _initial_set(m_name, m_default_value); \ + hints[m_name] = PropertyInfo(m_type, m_name, m_property_hint, m_hint_string, m_usage); /* Languages */ @@ -363,103 +371,76 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { best = "en"; } - _initial_set("interface/editor/editor_language", best); - set_restart_if_changed("interface/editor/editor_language", true); - hints["interface/editor/editor_language"] = PropertyInfo(Variant::STRING, "interface/editor/editor_language", PROPERTY_HINT_ENUM, lang_hint, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); + EDITOR_SETTING_USAGE(Variant::STRING, PROPERTY_HINT_ENUM, "interface/editor/editor_language", best, lang_hint, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); } /* Interface */ // Editor - _initial_set("interface/editor/display_scale", 0); // Display what the Auto display scale setting effectively corresponds to. - float scale = get_auto_display_scale(); + const String display_scale_hint_string = vformat("Auto (%d%%),75%%,100%%,125%%,150%%,175%%,200%%,Custom", Math::round(get_auto_display_scale() * 100)); + EDITOR_SETTING_USAGE(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/display_scale", 0, display_scale_hint_string, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED) _initial_set("interface/editor/enable_debugging_pseudolocalization", false); set_restart_if_changed("interface/editor/enable_debugging_pseudolocalization", true); // Use pseudolocalization in editor. - hints["interface/editor/display_scale"] = PropertyInfo(Variant::INT, "interface/editor/display_scale", PROPERTY_HINT_ENUM, vformat("Auto (%d%%),75%%,100%%,125%%,150%%,175%%,200%%,Custom", Math::round(scale * 100)), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); - _initial_set("interface/editor/custom_display_scale", 1.0f); - hints["interface/editor/custom_display_scale"] = PropertyInfo(Variant::FLOAT, "interface/editor/custom_display_scale", PROPERTY_HINT_RANGE, "0.5,3,0.01", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); - _initial_set("interface/editor/main_font_size", 14); - hints["interface/editor/main_font_size"] = PropertyInfo(Variant::INT, "interface/editor/main_font_size", PROPERTY_HINT_RANGE, "8,48,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); - _initial_set("interface/editor/code_font_size", 14); - hints["interface/editor/code_font_size"] = PropertyInfo(Variant::INT, "interface/editor/code_font_size", PROPERTY_HINT_RANGE, "8,48,1", PROPERTY_USAGE_DEFAULT); - _initial_set("interface/editor/code_font_contextual_ligatures", 0); - hints["interface/editor/code_font_contextual_ligatures"] = PropertyInfo(Variant::INT, "interface/editor/code_font_contextual_ligatures", PROPERTY_HINT_ENUM, "Default,Disable Contextual Alternates (Coding Ligatures),Use Custom OpenType Feature Set", PROPERTY_USAGE_DEFAULT); + EDITOR_SETTING_USAGE(Variant::FLOAT, PROPERTY_HINT_RANGE, "interface/editor/custom_display_scale", 1.0, "0.5,3,0.01", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED) + EDITOR_SETTING_USAGE(Variant::INT, PROPERTY_HINT_RANGE, "interface/editor/main_font_size", 14, "8,48,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED) + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "interface/editor/code_font_size", 14, "8,48,1") + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/code_font_contextual_ligatures", 0, "Default,Disable Contextual Alternates (Coding Ligatures),Use Custom OpenType Feature Set") _initial_set("interface/editor/code_font_custom_opentype_features", ""); _initial_set("interface/editor/code_font_custom_variations", ""); _initial_set("interface/editor/font_antialiased", true); - _initial_set("interface/editor/font_hinting", 0); #ifdef OSX_ENABLED - hints["interface/editor/font_hinting"] = PropertyInfo(Variant::INT, "interface/editor/font_hinting", PROPERTY_HINT_ENUM, "Auto (None),None,Light,Normal", PROPERTY_USAGE_DEFAULT); + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/font_hinting", 0, "Auto (None),None,Light,Normal") #else - hints["interface/editor/font_hinting"] = PropertyInfo(Variant::INT, "interface/editor/font_hinting", PROPERTY_HINT_ENUM, "Auto (Light),None,Light,Normal", PROPERTY_USAGE_DEFAULT); + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/font_hinting", 0, "Auto (Light),None,Light,Normal") #endif - _initial_set("interface/editor/main_font", ""); - hints["interface/editor/main_font"] = PropertyInfo(Variant::STRING, "interface/editor/main_font", PROPERTY_HINT_GLOBAL_FILE, "*.ttf,*.otf", PROPERTY_USAGE_DEFAULT); - _initial_set("interface/editor/main_font_bold", ""); - hints["interface/editor/main_font_bold"] = PropertyInfo(Variant::STRING, "interface/editor/main_font_bold", PROPERTY_HINT_GLOBAL_FILE, "*.ttf,*.otf", PROPERTY_USAGE_DEFAULT); - _initial_set("interface/editor/code_font", ""); - hints["interface/editor/code_font"] = PropertyInfo(Variant::STRING, "interface/editor/code_font", PROPERTY_HINT_GLOBAL_FILE, "*.ttf,*.otf", PROPERTY_USAGE_DEFAULT); - _initial_set("interface/editor/low_processor_mode_sleep_usec", 6900); // ~144 FPS - hints["interface/editor/low_processor_mode_sleep_usec"] = PropertyInfo(Variant::FLOAT, "interface/editor/low_processor_mode_sleep_usec", PROPERTY_HINT_RANGE, "1,100000,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); - _initial_set("interface/editor/unfocused_low_processor_mode_sleep_usec", 100000); // 10 FPS - // Allow an unfocused FPS limit as low as 1 FPS for those who really need low power usage - // (but don't need to preview particles or shaders while the editor is unfocused). - // With very low FPS limits, the editor can take a small while to become usable after being focused again, - // so this should be used at the user's discretion. - hints["interface/editor/unfocused_low_processor_mode_sleep_usec"] = PropertyInfo(Variant::FLOAT, "interface/editor/unfocused_low_processor_mode_sleep_usec", PROPERTY_HINT_RANGE, "1,1000000,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); + EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "interface/editor/main_font", "", "*.ttf,*.otf") + EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "interface/editor/main_font_bold", "", "*.ttf,*.otf") + EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "interface/editor/code_font", "", "*.ttf,*.otf") + EDITOR_SETTING_USAGE(Variant::FLOAT, PROPERTY_HINT_RANGE, "interface/editor/low_processor_mode_sleep_usec", 6900, "1,100000,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED) + // Default unfocused usec sleep is for 10 FPS. Allow an unfocused FPS limit + // as low as 1 FPS for those who really need low power usage (but don't need + // to preview particles or shaders while the editor is unfocused). With very + // low FPS limits, the editor can take a small while to become usable after + // being focused again, so this should be used at the user's discretion. + EDITOR_SETTING_USAGE(Variant::FLOAT, PROPERTY_HINT_RANGE, "interface/editor/unfocused_low_processor_mode_sleep_usec", 100000, "1,1000000,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED) _initial_set("interface/editor/separate_distraction_mode", false); _initial_set("interface/editor/automatically_open_screenshots", true); - _initial_set("interface/editor/single_window_mode", false); - hints["interface/editor/single_window_mode"] = PropertyInfo(Variant::BOOL, "interface/editor/single_window_mode", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); + EDITOR_SETTING_USAGE(Variant::BOOL, PROPERTY_HINT_NONE, "interface/editor/single_window_mode", false, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED) _initial_set("interface/editor/hide_console_window", false); _initial_set("interface/editor/save_each_scene_on_quit", true); // Regression // Inspector - _initial_set("interface/inspector/max_array_dictionary_items_per_page", 20); - hints["interface/inspector/max_array_dictionary_items_per_page"] = PropertyInfo(Variant::INT, "interface/inspector/max_array_dictionary_items_per_page", PROPERTY_HINT_RANGE, "10,100,1", PROPERTY_USAGE_DEFAULT); + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "interface/inspector/max_array_dictionary_items_per_page", 20, "10,100,1") // Theme - _initial_set("interface/theme/preset", "Default"); - hints["interface/theme/preset"] = PropertyInfo(Variant::STRING, "interface/theme/preset", PROPERTY_HINT_ENUM, "Default,Breeze Dark,Godot 2,Grey,Light,Solarized (Dark),Solarized (Light),Custom", PROPERTY_USAGE_DEFAULT); - _initial_set("interface/theme/icon_and_font_color", 0); - hints["interface/theme/icon_and_font_color"] = PropertyInfo(Variant::INT, "interface/theme/icon_and_font_color", PROPERTY_HINT_ENUM, "Auto,Dark,Light", PROPERTY_USAGE_DEFAULT); - _initial_set("interface/theme/base_color", Color(0.2, 0.23, 0.31)); - hints["interface/theme/base_color"] = PropertyInfo(Variant::COLOR, "interface/theme/base_color", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT); - _initial_set("interface/theme/accent_color", Color(0.41, 0.61, 0.91)); - hints["interface/theme/accent_color"] = PropertyInfo(Variant::COLOR, "interface/theme/accent_color", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT); - _initial_set("interface/theme/contrast", 0.3); - hints["interface/theme/contrast"] = PropertyInfo(Variant::FLOAT, "interface/theme/contrast", PROPERTY_HINT_RANGE, "-1, 1, 0.01"); - _initial_set("interface/theme/icon_saturation", 1.0); - hints["interface/theme/icon_saturation"] = PropertyInfo(Variant::FLOAT, "interface/theme/icon_saturation", PROPERTY_HINT_RANGE, "0,2,0.01", PROPERTY_USAGE_DEFAULT); - _initial_set("interface/theme/relationship_line_opacity", 0.1); - hints["interface/theme/relationship_line_opacity"] = PropertyInfo(Variant::FLOAT, "interface/theme/relationship_line_opacity", PROPERTY_HINT_RANGE, "0.00, 1, 0.01"); - _initial_set("interface/theme/border_size", 0); - hints["interface/theme/border_size"] = PropertyInfo(Variant::INT, "interface/theme/border_size", PROPERTY_HINT_RANGE, "0,2,1", PROPERTY_USAGE_DEFAULT); - _initial_set("interface/theme/corner_radius", 3); - hints["interface/theme/corner_radius"] = PropertyInfo(Variant::INT, "interface/theme/corner_radius", PROPERTY_HINT_RANGE, "0,6,1", PROPERTY_USAGE_DEFAULT); - _initial_set("interface/theme/additional_spacing", 0); - hints["interface/theme/additional_spacing"] = PropertyInfo(Variant::FLOAT, "interface/theme/additional_spacing", PROPERTY_HINT_RANGE, "0,5,0.1", PROPERTY_USAGE_DEFAULT); - _initial_set("interface/theme/custom_theme", ""); - hints["interface/theme/custom_theme"] = PropertyInfo(Variant::STRING, "interface/theme/custom_theme", PROPERTY_HINT_GLOBAL_FILE, "*.res,*.tres,*.theme", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); + EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_ENUM, "interface/theme/preset", "Default", "Default,Breeze Dark,Godot 2,Grey,Light,Solarized (Dark),Solarized (Light),Custom") + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/theme/icon_and_font_color", 0, "Auto,Dark,Light") + EDITOR_SETTING(Variant::COLOR, PROPERTY_HINT_NONE, "interface/theme/base_color", Color(0.2, 0.23, 0.31), "") + EDITOR_SETTING(Variant::COLOR, PROPERTY_HINT_NONE, "interface/theme/accent_color", Color(0.41, 0.61, 0.91), "") + EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "interface/theme/contrast", 0.3, "-1,1,0.01") + EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "interface/theme/icon_saturation", 1.0, "0,2,0.01") + EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "interface/theme/relationship_line_opacity", 0.1, "0.00,1,0.01") + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "interface/theme/border_size", 0, "0,2,1") + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "interface/theme/corner_radius", 3, "0,6,1") + EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "interface/theme/additional_spacing", 0.0, "0,5,0.1") + EDITOR_SETTING_USAGE(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "interface/theme/custom_theme", "", "*.res,*.tres,*.theme", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED) // Scene tabs _initial_set("interface/scene_tabs/show_thumbnail_on_hover", true); _initial_set("interface/scene_tabs/resize_if_many_tabs", true); - _initial_set("interface/scene_tabs/minimum_width", 50); - hints["interface/scene_tabs/minimum_width"] = PropertyInfo(Variant::INT, "interface/scene_tabs/minimum_width", PROPERTY_HINT_RANGE, "50,500,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); + EDITOR_SETTING_USAGE(Variant::INT, PROPERTY_HINT_RANGE, "interface/scene_tabs/minimum_width", 50, "50,500,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED) _initial_set("interface/scene_tabs/show_script_button", false); /* Filesystem */ // Directories - _initial_set("filesystem/directories/autoscan_project_path", ""); - hints["filesystem/directories/autoscan_project_path"] = PropertyInfo(Variant::STRING, "filesystem/directories/autoscan_project_path", PROPERTY_HINT_GLOBAL_DIR); - _initial_set("filesystem/directories/default_project_path", OS::get_singleton()->has_environment("HOME") ? OS::get_singleton()->get_environment("HOME") : OS::get_singleton()->get_system_dir(OS::SYSTEM_DIR_DOCUMENTS)); - hints["filesystem/directories/default_project_path"] = PropertyInfo(Variant::STRING, "filesystem/directories/default_project_path", PROPERTY_HINT_GLOBAL_DIR); + EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_GLOBAL_DIR, "filesystem/directories/autoscan_project_path", "", "") + const String fs_dir_default_project_path = OS::get_singleton()->has_environment("HOME") ? OS::get_singleton()->get_environment("HOME") : OS::get_singleton()->get_system_dir(OS::SYSTEM_DIR_DOCUMENTS); + EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_GLOBAL_DIR, "filesystem/directories/default_project_path", fs_dir_default_project_path, "") // On save _initial_set("filesystem/on_save/compress_binary_resources", true); @@ -467,10 +448,8 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { // File dialog _initial_set("filesystem/file_dialog/show_hidden_files", false); - _initial_set("filesystem/file_dialog/display_mode", 0); - hints["filesystem/file_dialog/display_mode"] = PropertyInfo(Variant::INT, "filesystem/file_dialog/display_mode", PROPERTY_HINT_ENUM, "Thumbnails,List"); - _initial_set("filesystem/file_dialog/thumbnail_size", 64); - hints["filesystem/file_dialog/thumbnail_size"] = PropertyInfo(Variant::INT, "filesystem/file_dialog/thumbnail_size", PROPERTY_HINT_RANGE, "32,128,16"); + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "filesystem/file_dialog/display_mode", 0, "Thumbnails,List") + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "filesystem/file_dialog/thumbnail_size", 64, "32,128,16") /* Docks */ @@ -478,40 +457,33 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("docks/scene_tree/start_create_dialog_fully_expanded", false); // FileSystem - _initial_set("docks/filesystem/thumbnail_size", 64); - hints["docks/filesystem/thumbnail_size"] = PropertyInfo(Variant::INT, "docks/filesystem/thumbnail_size", PROPERTY_HINT_RANGE, "32,128,16"); + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "docks/filesystem/thumbnail_size", 64, "32,128,16") _initial_set("docks/filesystem/always_show_folders", true); // Property editor _initial_set("docks/property_editor/auto_refresh_interval", 0.2); //update 5 times per second by default - _initial_set("docks/property_editor/subresource_hue_tint", 0.75); - hints["docks/property_editor/subresource_hue_tint"] = PropertyInfo(Variant::FLOAT, "docks/property_editor/subresource_hue_tint", PROPERTY_HINT_RANGE, "0,1,0.01", PROPERTY_USAGE_DEFAULT); + EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "docks/property_editor/subresource_hue_tint", 0.75, "0,1,0.01") /* Text editor */ // Theme - _initial_set("text_editor/theme/color_theme", "Default"); - hints["text_editor/theme/color_theme"] = PropertyInfo(Variant::STRING, "text_editor/theme/color_theme", PROPERTY_HINT_ENUM, "Default,Godot 2,Custom"); + EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_ENUM, "text_editor/theme/color_theme", "Default", "Default,Godot 2,Custom") // Theme: Highlighting _load_godot2_text_editor_theme(); // Appearance // Appearance: Caret - _initial_set("text_editor/appearance/caret/type", 0); - hints["text_editor/appearance/caret/type"] = PropertyInfo(Variant::INT, "text_editor/appearance/caret/type", PROPERTY_HINT_ENUM, "Line,Block"); + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "text_editor/appearance/caret/type", 0, "Line,Block") _initial_set("text_editor/appearance/caret/caret_blink", true); - _initial_set("text_editor/appearance/caret/caret_blink_speed", 0.5); - hints["text_editor/appearance/caret/caret_blink_speed"] = PropertyInfo(Variant::FLOAT, "text_editor/appearance/caret/caret_blink_speed", PROPERTY_HINT_RANGE, "0.1, 10, 0.01"); + EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "text_editor/appearance/caret/caret_blink_speed", 0.5, "0.1,10,0.01") _initial_set("text_editor/appearance/caret/highlight_current_line", true); _initial_set("text_editor/appearance/caret/highlight_all_occurrences", true); // Appearance: Guidelines _initial_set("text_editor/appearance/guidelines/show_line_length_guidelines", true); - _initial_set("text_editor/appearance/guidelines/line_length_guideline_soft_column", 80); - hints["text_editor/appearance/guidelines/line_length_guideline_soft_column"] = PropertyInfo(Variant::INT, "text_editor/appearance/guidelines/line_length_guideline_soft_column", PROPERTY_HINT_RANGE, "20, 160, 1"); - _initial_set("text_editor/appearance/guidelines/line_length_guideline_hard_column", 100); - hints["text_editor/appearance/guidelines/line_length_guideline_hard_column"] = PropertyInfo(Variant::INT, "text_editor/appearance/guidelines/line_length_guideline_hard_column", PROPERTY_HINT_RANGE, "20, 160, 1"); + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "text_editor/appearance/guidelines/line_length_guideline_soft_column", 80, "20,160,1") + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "text_editor/appearance/guidelines/line_length_guideline_hard_column", 100, "20,160,1") // Appearance: Gutters _initial_set("text_editor/appearance/gutters/show_line_numbers", true); @@ -522,19 +494,16 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { // Appearance: Minimap _initial_set("text_editor/appearance/minimap/show_minimap", true); - _initial_set("text_editor/appearance/minimap/minimap_width", 80); - hints["text_editor/appearance/minimap/minimap_width"] = PropertyInfo(Variant::INT, "text_editor/appearance/minimap/minimap_width", PROPERTY_HINT_RANGE, "50,250,1"); + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "text_editor/appearance/minimap/minimap_width", 80, "50,250,1") // Appearance: Lines _initial_set("text_editor/appearance/lines/code_folding", true); - _initial_set("text_editor/appearance/lines/word_wrap", 0); - hints["text_editor/appearance/lines/word_wrap"] = PropertyInfo(Variant::INT, "text_editor/appearance/lines/word_wrap", PROPERTY_HINT_ENUM, "None,Boundary"); + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "text_editor/appearance/lines/word_wrap", 0, "None,Boundary") // Appearance: Whitespace _initial_set("text_editor/appearance/whitespace/draw_tabs", true); _initial_set("text_editor/appearance/whitespace/draw_spaces", false); - _initial_set("text_editor/appearance/whitespace/line_spacing", 6); - hints["text_editor/appearance/whitespace/line_spacing"] = PropertyInfo(Variant::INT, "text_editor/appearance/whitespace/line_spacing", PROPERTY_HINT_RANGE, "0,50,1"); + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "text_editor/appearance/whitespace/line_spacing", 6, "0,50,1") // Behavior // Behavior: Navigation @@ -544,10 +513,8 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("text_editor/behavior/navigation/v_scroll_speed", 80); // Behavior: Indent - _initial_set("text_editor/behavior/indent/type", 0); - hints["text_editor/behavior/indent/type"] = PropertyInfo(Variant::INT, "text_editor/behavior/indent/type", PROPERTY_HINT_ENUM, "Tabs,Spaces"); - _initial_set("text_editor/behavior/indent/size", 4); - hints["text_editor/behavior/indent/size"] = PropertyInfo(Variant::INT, "text_editor/behavior/indent/size", PROPERTY_HINT_RANGE, "1, 64, 1"); // size of 0 crashes. + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "text_editor/behavior/indent/type", 0, "Tabs,Spaces") + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "text_editor/behavior/indent/size", 4, "1,64,1") // size of 0 crashes. _initial_set("text_editor/behavior/indent/auto_indent", true); // Behavior: Files @@ -561,11 +528,9 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("text_editor/script_list/sort_members_outline_alphabetically", false); // Completion - _initial_set("text_editor/completion/idle_parse_delay", 2.0); - hints["text_editor/completion/idle_parse_delay"] = PropertyInfo(Variant::FLOAT, "text_editor/completion/idle_parse_delay", PROPERTY_HINT_RANGE, "0.1, 10, 0.01"); + EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "text_editor/completion/idle_parse_delay", 2.0, "0.1,10,0.01") _initial_set("text_editor/completion/auto_brace_complete", true); - _initial_set("text_editor/completion/code_complete_delay", 0.3); - hints["text_editor/completion/code_complete_delay"] = PropertyInfo(Variant::FLOAT, "text_editor/completion/code_complete_delay", PROPERTY_HINT_RANGE, "0.01, 5, 0.01"); + EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "text_editor/completion/code_complete_delay", 0.3, "0.01,5,0.01") _initial_set("text_editor/completion/put_callhint_tooltip_below_current_line", true); _initial_set("text_editor/completion/complete_file_paths", true); _initial_set("text_editor/completion/add_type_hints", false); @@ -573,14 +538,10 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { // Help _initial_set("text_editor/help/show_help_index", true); - _initial_set("text_editor/help/help_font_size", 15); - hints["text_editor/help/help_font_size"] = PropertyInfo(Variant::INT, "text_editor/help/help_font_size", PROPERTY_HINT_RANGE, "8,48,1"); - _initial_set("text_editor/help/help_source_font_size", 14); - hints["text_editor/help/help_source_font_size"] = PropertyInfo(Variant::INT, "text_editor/help/help_source_font_size", PROPERTY_HINT_RANGE, "8,48,1"); - _initial_set("text_editor/help/help_title_font_size", 23); - hints["text_editor/help/help_title_font_size"] = PropertyInfo(Variant::INT, "text_editor/help/help_title_font_size", PROPERTY_HINT_RANGE, "8,48,1"); - _initial_set("text_editor/help/class_reference_examples", 0); - hints["text_editor/help/class_reference_examples"] = PropertyInfo(Variant::INT, "text_editor/help/class_reference_examples", PROPERTY_HINT_ENUM, "GDScript,C#,GDScript and C#"); + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "text_editor/help/help_font_size", 15, "8,48,1") + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "text_editor/help/help_source_font_size", 14, "8,48,1") + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "text_editor/help/help_title_font_size", 23, "8,48,1") + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "text_editor/help/class_reference_examples", 0, "GDScript,C#,GDScript and C#") /* Editors */ @@ -588,39 +549,23 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("editors/grid_map/pick_distance", 5000.0); // 3D - _initial_set("editors/3d/primary_grid_color", Color(0.56, 0.56, 0.56, 0.5)); - hints["editors/3d/primary_grid_color"] = PropertyInfo(Variant::COLOR, "editors/3d/primary_grid_color", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT); - - _initial_set("editors/3d/secondary_grid_color", Color(0.38, 0.38, 0.38, 0.5)); - hints["editors/3d/secondary_grid_color"] = PropertyInfo(Variant::COLOR, "editors/3d/secondary_grid_color", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT); + EDITOR_SETTING(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d/primary_grid_color", Color(0.56, 0.56, 0.56, 0.5), "") + EDITOR_SETTING(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d/secondary_grid_color", Color(0.38, 0.38, 0.38, 0.5), "") // Use a similar color to the 2D editor selection. - _initial_set("editors/3d/selection_box_color", Color(1.0, 0.5, 0)); - hints["editors/3d/selection_box_color"] = PropertyInfo(Variant::COLOR, "editors/3d/selection_box_color", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); + EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d/selection_box_color", Color(1.0, 0.5, 0), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED) // If a line is a multiple of this, it uses the primary grid color. // Use a power of 2 value by default as it's more common to use powers of 2 in level design. - _initial_set("editors/3d/primary_grid_steps", 8); - hints["editors/3d/primary_grid_steps"] = PropertyInfo(Variant::INT, "editors/3d/primary_grid_steps", PROPERTY_HINT_RANGE, "1,100,1", PROPERTY_USAGE_DEFAULT); - - // At 1000, the grid mostly looks like it has no edge. - _initial_set("editors/3d/grid_size", 200); - hints["editors/3d/grid_size"] = PropertyInfo(Variant::INT, "editors/3d/grid_size", PROPERTY_HINT_RANGE, "1,2000,1", PROPERTY_USAGE_DEFAULT); - - // Default largest grid size is 100m, 10^2 (primary grid lines are 1km apart when primary_grid_steps is 10). - _initial_set("editors/3d/grid_division_level_max", 2); + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "editors/3d/primary_grid_steps", 8, "1,100,1") + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "editors/3d/grid_size", 200, "1,2000,1") // Higher values produce graphical artifacts when far away unless View Z-Far // is increased significantly more than it really should need to be. - hints["editors/3d/grid_division_level_max"] = PropertyInfo(Variant::INT, "editors/3d/grid_division_level_max", PROPERTY_HINT_RANGE, "-1,3,1", PROPERTY_USAGE_DEFAULT); - - // Default smallest grid size is 1m, 10^0. - _initial_set("editors/3d/grid_division_level_min", 0); + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "editors/3d/grid_division_level_max", 2, "-1,3,1") // Lower values produce graphical artifacts regardless of view clipping planes, so limit to -2 as a lower bound. - hints["editors/3d/grid_division_level_min"] = PropertyInfo(Variant::INT, "editors/3d/grid_division_level_min", PROPERTY_HINT_RANGE, "-2,2,1", PROPERTY_USAGE_DEFAULT); - + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "editors/3d/grid_division_level_min", 0, "-2,2,1") // -0.2 seems like a sensible default. -1.0 gives Blender-like behavior, 0.5 gives huge grids. - _initial_set("editors/3d/grid_division_level_bias", -0.2); - hints["editors/3d/grid_division_level_bias"] = PropertyInfo(Variant::FLOAT, "editors/3d/grid_division_level_bias", PROPERTY_HINT_RANGE, "-1.0,0.5,0.1", PROPERTY_USAGE_DEFAULT); + EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/grid_division_level_bias", -0.2, "-1.0,0.5,0.1") _initial_set("editors/3d/grid_xz_plane", true); _initial_set("editors/3d/grid_xy_plane", false); @@ -629,56 +574,37 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { // Use a lower default FOV for the 3D camera compared to the // Camera3D node as the 3D viewport doesn't span the whole screen. // This means it's technically viewed from a further distance, which warrants a narrower FOV. - _initial_set("editors/3d/default_fov", 70.0); - hints["editors/3d/default_fov"] = PropertyInfo(Variant::FLOAT, "editors/3d/default_fov", PROPERTY_HINT_RANGE, "1,179,0.1"); - _initial_set("editors/3d/default_z_near", 0.05); - hints["editors/3d/default_z_near"] = PropertyInfo(Variant::FLOAT, "editors/3d/default_z_near", PROPERTY_HINT_RANGE, "0.01,10,0.01,or_greater"); - _initial_set("editors/3d/default_z_far", 4000.0); - hints["editors/3d/default_z_far"] = PropertyInfo(Variant::FLOAT, "editors/3d/default_z_far", PROPERTY_HINT_RANGE, "0.1,4000,0.1,or_greater"); + EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/default_fov", 70.0, "1,179,0.1") + EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/default_z_near", 0.05, "0.01,10,0.01,or_greater") + EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/default_z_far", 4000.0, "0.1,4000,0.1,or_greater") // 3D: Navigation - _initial_set("editors/3d/navigation/navigation_scheme", 0); - _initial_set("editors/3d/navigation/invert_y_axis", false); _initial_set("editors/3d/navigation/invert_x_axis", false); - hints["editors/3d/navigation/navigation_scheme"] = PropertyInfo(Variant::INT, "editors/3d/navigation/navigation_scheme", PROPERTY_HINT_ENUM, "Godot,Maya,Modo"); - _initial_set("editors/3d/navigation/zoom_style", 0); - hints["editors/3d/navigation/zoom_style"] = PropertyInfo(Variant::INT, "editors/3d/navigation/zoom_style", PROPERTY_HINT_ENUM, "Vertical, Horizontal"); + _initial_set("editors/3d/navigation/invert_y_axis", false); + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "editors/3d/navigation/navigation_scheme", 0, "Godot,Maya,Modo") + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "editors/3d/navigation/zoom_style", 0, "Vertical,Horizontal") _initial_set("editors/3d/navigation/emulate_numpad", false); _initial_set("editors/3d/navigation/emulate_3_button_mouse", false); - _initial_set("editors/3d/navigation/orbit_modifier", 0); - hints["editors/3d/navigation/orbit_modifier"] = PropertyInfo(Variant::INT, "editors/3d/navigation/orbit_modifier", PROPERTY_HINT_ENUM, "None,Shift,Alt,Meta,Ctrl"); - _initial_set("editors/3d/navigation/pan_modifier", 1); - hints["editors/3d/navigation/pan_modifier"] = PropertyInfo(Variant::INT, "editors/3d/navigation/pan_modifier", PROPERTY_HINT_ENUM, "None,Shift,Alt,Meta,Ctrl"); - _initial_set("editors/3d/navigation/zoom_modifier", 4); - hints["editors/3d/navigation/zoom_modifier"] = PropertyInfo(Variant::INT, "editors/3d/navigation/zoom_modifier", PROPERTY_HINT_ENUM, "None,Shift,Alt,Meta,Ctrl"); + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "editors/3d/navigation/orbit_modifier", 0, "None,Shift,Alt,Meta,Ctrl") + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "editors/3d/navigation/pan_modifier", 1, "None,Shift,Alt,Meta,Ctrl") + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "editors/3d/navigation/zoom_modifier", 4, "None,Shift,Alt,Meta,Ctrl") _initial_set("editors/3d/navigation/warped_mouse_panning", true); // 3D: Navigation feel - _initial_set("editors/3d/navigation_feel/orbit_sensitivity", 0.4); - hints["editors/3d/navigation_feel/orbit_sensitivity"] = PropertyInfo(Variant::FLOAT, "editors/3d/navigation_feel/orbit_sensitivity", PROPERTY_HINT_RANGE, "0.0, 2, 0.01"); - _initial_set("editors/3d/navigation_feel/orbit_inertia", 0.05); - hints["editors/3d/navigation_feel/orbit_inertia"] = PropertyInfo(Variant::FLOAT, "editors/3d/navigation_feel/orbit_inertia", PROPERTY_HINT_RANGE, "0.0, 1, 0.01"); - _initial_set("editors/3d/navigation_feel/translation_inertia", 0.15); - hints["editors/3d/navigation_feel/translation_inertia"] = PropertyInfo(Variant::FLOAT, "editors/3d/navigation_feel/translation_inertia", PROPERTY_HINT_RANGE, "0.0, 1, 0.01"); - _initial_set("editors/3d/navigation_feel/zoom_inertia", 0.075); - hints["editors/3d/navigation_feel/zoom_inertia"] = PropertyInfo(Variant::FLOAT, "editors/3d/navigation_feel/zoom_inertia", PROPERTY_HINT_RANGE, "0.0, 1, 0.01"); - _initial_set("editors/3d/navigation_feel/manipulation_orbit_inertia", 0.075); - hints["editors/3d/navigation_feel/manipulation_orbit_inertia"] = PropertyInfo(Variant::FLOAT, "editors/3d/navigation_feel/manipulation_orbit_inertia", PROPERTY_HINT_RANGE, "0.0, 1, 0.01"); - _initial_set("editors/3d/navigation_feel/manipulation_translation_inertia", 0.075); - hints["editors/3d/navigation_feel/manipulation_translation_inertia"] = PropertyInfo(Variant::FLOAT, "editors/3d/navigation_feel/manipulation_translation_inertia", PROPERTY_HINT_RANGE, "0.0, 1, 0.01"); + EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/navigation_feel/orbit_sensitivity", 0.4, "0.0,2,0.01") + EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/navigation_feel/orbit_inertia", 0.05, "0.0,1,0.01") + EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/navigation_feel/translation_inertia", 0.15, "0.0,1,0.01") + EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/navigation_feel/zoom_inertia", 0.075, "0.0,1,0.01") + EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/navigation_feel/manipulation_orbit_inertia", 0.075, "0.0,1,0.01") + EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/navigation_feel/manipulation_translation_inertia", 0.075, "0.0,1,0.01") // 3D: Freelook - _initial_set("editors/3d/freelook/freelook_navigation_scheme", false); - hints["editors/3d/freelook/freelook_navigation_scheme"] = PropertyInfo(Variant::INT, "editors/3d/freelook/freelook_navigation_scheme", PROPERTY_HINT_ENUM, "Default,Partially Axis-Locked (id Tech),Fully Axis-Locked (Minecraft)"); - _initial_set("editors/3d/freelook/freelook_sensitivity", 0.4); - hints["editors/3d/freelook/freelook_sensitivity"] = PropertyInfo(Variant::FLOAT, "editors/3d/freelook/freelook_sensitivity", PROPERTY_HINT_RANGE, "0.0, 2, 0.01"); - _initial_set("editors/3d/freelook/freelook_inertia", 0.1); - hints["editors/3d/freelook/freelook_inertia"] = PropertyInfo(Variant::FLOAT, "editors/3d/freelook/freelook_inertia", PROPERTY_HINT_RANGE, "0.0, 1, 0.01"); - _initial_set("editors/3d/freelook/freelook_base_speed", 5.0); - hints["editors/3d/freelook/freelook_base_speed"] = PropertyInfo(Variant::FLOAT, "editors/3d/freelook/freelook_base_speed", PROPERTY_HINT_RANGE, "0.0, 10, 0.01"); - _initial_set("editors/3d/freelook/freelook_activation_modifier", 0); - hints["editors/3d/freelook/freelook_activation_modifier"] = PropertyInfo(Variant::INT, "editors/3d/freelook/freelook_activation_modifier", PROPERTY_HINT_ENUM, "None,Shift,Alt,Meta,Ctrl"); + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "editors/3d/freelook/freelook_navigation_scheme", 0, "Default,Partially Axis-Locked (id Tech),Fully Axis-Locked (Minecraft)") + EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/freelook/freelook_sensitivity", 0.4, "0.0,2,0.01") + EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/freelook/freelook_inertia", 0.1, "0.0,1,0.01") + EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/freelook/freelook_base_speed", 5.0, "0.0,10,0.01") + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "editors/3d/freelook/freelook_activation_modifier", 0, "None,Shift,Alt,Meta,Ctrl") _initial_set("editors/3d/freelook/freelook_speed_zoom_link", false); // 2D @@ -716,28 +642,24 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("editors/animation/onion_layers_future_color", Color(0, 1, 0)); // Visual editors - _initial_set("editors/visual_editors/minimap_opacity", 0.85); - hints["editors/visual_editors/minimap_opacity"] = PropertyInfo(Variant::FLOAT, "editors/visual_editors/minimap_opacity", PROPERTY_HINT_RANGE, "0.0,1.0,0.01", PROPERTY_USAGE_DEFAULT); + EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/visual_editors/minimap_opacity", 0.85, "0.0,1.0,0.01") /* Run */ // Window placement - _initial_set("run/window_placement/rect", 1); - hints["run/window_placement/rect"] = PropertyInfo(Variant::INT, "run/window_placement/rect", PROPERTY_HINT_ENUM, "Top Left,Centered,Custom Position,Force Maximized,Force Fullscreen"); + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "run/window_placement/rect", 1, "Top Left,Centered,Custom Position,Force Maximized,Force Fullscreen") String screen_hints = "Same as Editor,Previous Monitor,Next Monitor"; for (int i = 0; i < DisplayServer::get_singleton()->get_screen_count(); i++) { screen_hints += ",Monitor " + itos(i + 1); } _initial_set("run/window_placement/rect_custom_position", Vector2()); - _initial_set("run/window_placement/screen", 0); - hints["run/window_placement/screen"] = PropertyInfo(Variant::INT, "run/window_placement/screen", PROPERTY_HINT_ENUM, screen_hints); + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "run/window_placement/screen", 0, screen_hints) // Auto save _initial_set("run/auto_save/save_before_running", true); // Output - _initial_set("run/output/font_size", 13); - hints["run/output/font_size"] = PropertyInfo(Variant::INT, "run/output/font_size", PROPERTY_HINT_RANGE, "8,48,1"); + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "run/output/font_size", 13, "8,48,1") _initial_set("run/output/always_clear_output_on_play", true); _initial_set("run/output/always_open_output_on_play", true); _initial_set("run/output/always_close_output_on_stop", false); @@ -747,17 +669,14 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { // Debug _initial_set("network/debug/remote_host", "127.0.0.1"); // Hints provided in setup_network - _initial_set("network/debug/remote_port", 6007); - hints["network/debug/remote_port"] = PropertyInfo(Variant::INT, "network/debug/remote_port", PROPERTY_HINT_RANGE, "1,65535,1"); + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "network/debug/remote_port", 6007, "1,65535,1") // SSL - _initial_set("network/ssl/editor_ssl_certificates", _SYSTEM_CERTS_PATH); - hints["network/ssl/editor_ssl_certificates"] = PropertyInfo(Variant::STRING, "network/ssl/editor_ssl_certificates", PROPERTY_HINT_GLOBAL_FILE, "*.crt,*.pem"); + EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "network/ssl/editor_ssl_certificates", _SYSTEM_CERTS_PATH, "*.crt,*.pem") /* Extra config */ - _initial_set("project_manager/sorting_order", 0); - hints["project_manager/sorting_order"] = PropertyInfo(Variant::INT, "project_manager/sorting_order", PROPERTY_HINT_ENUM, "Name,Path,Last Edited"); + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "project_manager/sorting_order", 0, "Name,Path,Last Edited") if (p_extra_config.is_valid()) { if (p_extra_config->has_section("init_projects") && p_extra_config->has_section_key("init_projects", "list")) { diff --git a/editor/icons/WorldMarginShape2D.svg b/editor/icons/WorldBoundaryShape2D.svg index f1dbe97c6f..f1dbe97c6f 100644 --- a/editor/icons/WorldMarginShape2D.svg +++ b/editor/icons/WorldBoundaryShape2D.svg diff --git a/editor/icons/WorldMarginShape3D.svg b/editor/icons/WorldBoundaryShape3D.svg index a73e74ad33..a73e74ad33 100644 --- a/editor/icons/WorldMarginShape3D.svg +++ b/editor/icons/WorldBoundaryShape3D.svg diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index 9f617be4ee..753dcb1275 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -49,7 +49,7 @@ #include "scene/resources/separation_ray_shape_3d.h" #include "scene/resources/sphere_shape_3d.h" #include "scene/resources/surface_tool.h" -#include "scene/resources/world_margin_shape_3d.h" +#include "scene/resources/world_boundary_shape_3d.h" uint32_t EditorSceneImporter::get_import_flags() const { int ret; @@ -387,8 +387,8 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<E colshape->set_shape(rayShape); Object::cast_to<Node3D>(sb)->rotate_x(Math_PI / 2); } else if (empty_draw_type == "IMAGE") { - WorldMarginShape3D *world_margin_shape = memnew(WorldMarginShape3D); - colshape->set_shape(world_margin_shape); + WorldBoundaryShape3D *world_boundary_shape = memnew(WorldBoundaryShape3D); + colshape->set_shape(world_boundary_shape); } else { SphereShape3D *sphereShape = memnew(SphereShape3D); sphereShape->set_radius(1); diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp index bfcc293625..fb32d7b1fd 100644 --- a/editor/plugins/collision_shape_2d_editor_plugin.cpp +++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp @@ -39,7 +39,7 @@ #include "scene/resources/rectangle_shape_2d.h" #include "scene/resources/segment_shape_2d.h" #include "scene/resources/separation_ray_shape_2d.h" -#include "scene/resources/world_margin_shape_2d.h" +#include "scene/resources/world_boundary_shape_2d.h" void CollisionShape2DEditor::_node_removed(Node *p_node) { if (p_node == node) { @@ -70,13 +70,13 @@ Variant CollisionShape2DEditor::get_handle_value(int idx) const { case CONVEX_POLYGON_SHAPE: { } break; - case WORLD_MARGIN_SHAPE: { - Ref<WorldMarginShape2D> line = node->get_shape(); + case WORLD_BOUNDARY_SHAPE: { + Ref<WorldBoundaryShape2D> world_boundary = node->get_shape(); if (idx == 0) { - return line->get_distance(); + return world_boundary->get_distance(); } else { - return line->get_normal(); + return world_boundary->get_normal(); } } break; @@ -147,14 +147,14 @@ void CollisionShape2DEditor::set_handle(int idx, Point2 &p_point) { case CONVEX_POLYGON_SHAPE: { } break; - case WORLD_MARGIN_SHAPE: { + case WORLD_BOUNDARY_SHAPE: { if (idx < 2) { - Ref<WorldMarginShape2D> line = node->get_shape(); + Ref<WorldBoundaryShape2D> world_boundary = node->get_shape(); if (idx == 0) { - line->set_distance(p_point.length()); + world_boundary->set_distance(p_point.length()); } else { - line->set_normal(p_point.normalized()); + world_boundary->set_normal(p_point.normalized()); } canvas_item_editor->update_viewport(); @@ -255,18 +255,18 @@ void CollisionShape2DEditor::commit_handle(int idx, Variant &p_org) { // Cannot be edited directly, use CollisionPolygon2D instead. } break; - case WORLD_MARGIN_SHAPE: { - Ref<WorldMarginShape2D> line = node->get_shape(); + case WORLD_BOUNDARY_SHAPE: { + Ref<WorldBoundaryShape2D> world_boundary = node->get_shape(); if (idx == 0) { - undo_redo->add_do_method(line.ptr(), "set_distance", line->get_distance()); + undo_redo->add_do_method(world_boundary.ptr(), "set_distance", world_boundary->get_distance()); undo_redo->add_do_method(canvas_item_editor, "update_viewport"); - undo_redo->add_undo_method(line.ptr(), "set_distance", p_org); + undo_redo->add_undo_method(world_boundary.ptr(), "set_distance", p_org); undo_redo->add_undo_method(canvas_item_editor, "update_viewport"); } else { - undo_redo->add_do_method(line.ptr(), "set_normal", line->get_normal()); + undo_redo->add_do_method(world_boundary.ptr(), "set_normal", world_boundary->get_normal()); undo_redo->add_do_method(canvas_item_editor, "update_viewport"); - undo_redo->add_undo_method(line.ptr(), "set_normal", p_org); + undo_redo->add_undo_method(world_boundary.ptr(), "set_normal", p_org); undo_redo->add_undo_method(canvas_item_editor, "update_viewport"); } @@ -421,8 +421,8 @@ void CollisionShape2DEditor::_get_current_shape_type() { shape_type = CONCAVE_POLYGON_SHAPE; } else if (Object::cast_to<ConvexPolygonShape2D>(*s)) { shape_type = CONVEX_POLYGON_SHAPE; - } else if (Object::cast_to<WorldMarginShape2D>(*s)) { - shape_type = WORLD_MARGIN_SHAPE; + } else if (Object::cast_to<WorldBoundaryShape2D>(*s)) { + shape_type = WORLD_BOUNDARY_SHAPE; } else if (Object::cast_to<SeparationRayShape2D>(*s)) { shape_type = SEPARATION_RAY_SHAPE; } else if (Object::cast_to<RectangleShape2D>(*s)) { @@ -490,8 +490,8 @@ void CollisionShape2DEditor::forward_canvas_draw_over_viewport(Control *p_overla case CONVEX_POLYGON_SHAPE: { } break; - case WORLD_MARGIN_SHAPE: { - Ref<WorldMarginShape2D> shape = node->get_shape(); + case WORLD_BOUNDARY_SHAPE: { + Ref<WorldBoundaryShape2D> shape = node->get_shape(); handles.resize(2); handles.write[0] = shape->get_normal() * shape->get_distance(); diff --git a/editor/plugins/collision_shape_2d_editor_plugin.h b/editor/plugins/collision_shape_2d_editor_plugin.h index 421e674df8..ab95600a52 100644 --- a/editor/plugins/collision_shape_2d_editor_plugin.h +++ b/editor/plugins/collision_shape_2d_editor_plugin.h @@ -46,7 +46,7 @@ class CollisionShape2DEditor : public Control { CIRCLE_SHAPE, CONCAVE_POLYGON_SHAPE, CONVEX_POLYGON_SHAPE, - WORLD_MARGIN_SHAPE, + WORLD_BOUNDARY_SHAPE, SEPARATION_RAY_SHAPE, RECTANGLE_SHAPE, SEGMENT_SHAPE diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp index d20f3d105b..e61571edff 100644 --- a/editor/plugins/node_3d_editor_gizmos.cpp +++ b/editor/plugins/node_3d_editor_gizmos.cpp @@ -69,7 +69,7 @@ #include "scene/resources/separation_ray_shape_3d.h" #include "scene/resources/sphere_shape_3d.h" #include "scene/resources/surface_tool.h" -#include "scene/resources/world_margin_shape_3d.h" +#include "scene/resources/world_boundary_shape_3d.h" #define HANDLE_HALF_SIZE 9.5 @@ -4537,9 +4537,9 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { p_gizmo->add_handles(handles, handles_material); } - if (Object::cast_to<WorldMarginShape3D>(*s)) { - Ref<WorldMarginShape3D> ps = s; - Plane p = ps->get_plane(); + if (Object::cast_to<WorldBoundaryShape3D>(*s)) { + Ref<WorldBoundaryShape3D> wbs = s; + const Plane &p = wbs->get_plane(); Vector<Vector3> points; Vector3 n1 = p.get_any_perpendicular_normal(); diff --git a/editor/plugins/skeleton_2d_editor_plugin.cpp b/editor/plugins/skeleton_2d_editor_plugin.cpp index 7ef680d7ef..c350004f0f 100644 --- a/editor/plugins/skeleton_2d_editor_plugin.cpp +++ b/editor/plugins/skeleton_2d_editor_plugin.cpp @@ -98,9 +98,10 @@ Skeleton2DEditor::Skeleton2DEditor() { options->set_text(TTR("Skeleton2D")); options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Skeleton2D"), SNAME("EditorIcons"))); - options->get_popup()->add_item(TTR("Make Rest Pose (From Bones)"), MENU_OPTION_MAKE_REST); + options->get_popup()->add_item(TTR("Reset to Rest Pose"), MENU_OPTION_MAKE_REST); options->get_popup()->add_separator(); - options->get_popup()->add_item(TTR("Set Bones to Rest Pose"), MENU_OPTION_SET_REST); + // Use the "Overwrite" word to highlight that this is a destructive operation. + options->get_popup()->add_item(TTR("Overwrite Rest Pose"), MENU_OPTION_SET_REST); options->set_switch_on_hover(true); options->get_popup()->connect("id_pressed", callable_mp(this, &Skeleton2DEditor::_menu_option)); diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 50808a25af..aaa085675c 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -4042,7 +4042,7 @@ VisualShaderEditor::VisualShaderEditor() { graph->get_zoom_hbox()->add_child(add_node); add_node->set_text(TTR("Add Node...")); graph->get_zoom_hbox()->move_child(add_node, 0); - add_node->connect("pressed", callable_mp(this, &VisualShaderEditor::_show_members_dialog), varray(false)); + add_node->connect("pressed", callable_mp(this, &VisualShaderEditor::_show_members_dialog), varray(false, VisualShaderNode::PORT_TYPE_MAX, VisualShaderNode::PORT_TYPE_MAX)); preview_shader = memnew(Button); preview_shader->set_flat(true); diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp index d86e2656d4..9063b5c6f8 100644 --- a/editor/rename_dialog.cpp +++ b/editor/rename_dialog.cpp @@ -30,23 +30,19 @@ #include "rename_dialog.h" +#ifdef MODULE_REGEX_ENABLED + #include "core/string/print_string.h" #include "editor_node.h" #include "editor_scale.h" #include "editor_settings.h" #include "editor_themes.h" +#include "modules/regex/regex.h" #include "plugins/script_editor_plugin.h" #include "scene/gui/control.h" #include "scene/gui/label.h" #include "scene/gui/tab_container.h" -#include "modules/modules_enabled.gen.h" -#ifdef MODULE_REGEX_ENABLED -#include "modules/regex/regex.h" -#else -#error "Can't build editor rename dialog without RegEx module." -#endif - RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_undo_redo) { scene_tree_editor = p_scene_tree_editor; undo_redo = p_undo_redo; @@ -655,3 +651,5 @@ void RenameDialog::_features_toggled(bool pressed) { size.y = 0; set_size(size); } + +#endif // MODULE_REGEX_ENABLED diff --git a/editor/rename_dialog.h b/editor/rename_dialog.h index 76e99e3b66..7990862b37 100644 --- a/editor/rename_dialog.h +++ b/editor/rename_dialog.h @@ -31,6 +31,9 @@ #ifndef RENAME_DIALOG_H #define RENAME_DIALOG_H +#include "modules/modules_enabled.gen.h" +#ifdef MODULE_REGEX_ENABLED + #include "scene/gui/check_box.h" #include "scene/gui/dialogs.h" #include "scene/gui/option_button.h" @@ -113,4 +116,6 @@ public: ~RenameDialog() {} }; -#endif +#endif // MODULE_REGEX_ENABLED + +#endif // RENAME_DIALOG_H diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index a08a628216..4bc0905163 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -83,10 +83,12 @@ void SceneTreeDock::unhandled_key_input(const Ref<InputEvent> &p_event) { return; } - if (ED_IS_SHORTCUT("scene_tree/batch_rename", p_event)) { - _tool_selected(TOOL_BATCH_RENAME); - } else if (ED_IS_SHORTCUT("scene_tree/rename", p_event)) { + if (ED_IS_SHORTCUT("scene_tree/rename", p_event)) { _tool_selected(TOOL_RENAME); +#ifdef MODULE_REGEX_ENABLED + } else if (ED_IS_SHORTCUT("scene_tree/batch_rename", p_event)) { + _tool_selected(TOOL_BATCH_RENAME); +#endif // MODULE_REGEX_ENABLED } else if (ED_IS_SHORTCUT("scene_tree/add_child_node", p_event)) { _tool_selected(TOOL_NEW); } else if (ED_IS_SHORTCUT("scene_tree/instance_scene", p_event)) { @@ -336,6 +338,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { current_option = p_tool; switch (p_tool) { +#ifdef MODULE_REGEX_ENABLED case TOOL_BATCH_RENAME: { if (!profile_allow_editing) { break; @@ -344,6 +347,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { rename_dialog->popup_centered(); } } break; +#endif // MODULE_REGEX_ENABLED case TOOL_RENAME: { if (!profile_allow_editing) { break; @@ -2807,11 +2811,13 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { } } +#ifdef MODULE_REGEX_ENABLED if (profile_allow_editing && selection.size() > 1) { //this is not a commonly used action, it makes no sense for it to be where it was nor always present. menu->add_separator(); menu->add_icon_shortcut(get_theme_icon(SNAME("Rename"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/batch_rename"), TOOL_BATCH_RENAME); } +#endif // MODULE_REGEX_ENABLED menu->add_separator(); menu->add_icon_item(get_theme_icon(SNAME("Help"), SNAME("EditorIcons")), TTR("Open Documentation"), TOOL_OPEN_DOCUMENTATION); @@ -3321,8 +3327,10 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel create_dialog->connect("create", callable_mp(this, &SceneTreeDock::_create)); create_dialog->connect("favorites_updated", callable_mp(this, &SceneTreeDock::_update_create_root_dialog)); +#ifdef MODULE_REGEX_ENABLED rename_dialog = memnew(RenameDialog(scene_tree, &editor_data->get_undo_redo())); add_child(rename_dialog); +#endif // MODULE_REGEX_ENABLED script_create_dialog = memnew(ScriptCreateDialog); script_create_dialog->set_inheritance_base_type("Node"); diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h index 1086e8615f..ece0ca5ca4 100644 --- a/editor/scene_tree_dock.h +++ b/editor/scene_tree_dock.h @@ -62,7 +62,9 @@ class SceneTreeDock : public VBoxContainer { TOOL_COPY, TOOL_PASTE, TOOL_RENAME, +#ifdef MODULE_REGEX_ENABLED TOOL_BATCH_RENAME, +#endif // MODULE_REGEX_ENABLED TOOL_REPLACE, TOOL_EXTEND_SCRIPT, TOOL_ATTACH_SCRIPT, @@ -105,7 +107,9 @@ class SceneTreeDock : public VBoxContainer { int current_option; CreateDialog *create_dialog; +#ifdef MODULE_REGEX_ENABLED RenameDialog *rename_dialog; +#endif // MODULE_REGEX_ENABLED Button *button_add; Button *button_instance; diff --git a/misc/scripts/file_format.sh b/misc/scripts/file_format.sh index 0b49b175f2..b241f3da70 100755 --- a/misc/scripts/file_format.sh +++ b/misc/scripts/file_format.sh @@ -20,6 +20,9 @@ while IFS= read -rd '' f; do continue elif [[ "$f" == *"sln" ]]; then continue + elif [[ "$f" == *".out" ]]; then + # GDScript integration testing files. + continue elif [[ "$f" == *"patch" ]]; then continue elif [[ "$f" == *"pot" ]]; then diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp index fc876a81cf..ed05e51e53 100644 --- a/modules/bullet/bullet_physics_server.cpp +++ b/modules/bullet/bullet_physics_server.cpp @@ -87,8 +87,8 @@ RID BulletPhysicsServer3D::shape_create(ShapeType p_shape) { ShapeBullet *shape = nullptr; switch (p_shape) { - case SHAPE_PLANE: { - shape = bulletnew(PlaneShapeBullet); + case SHAPE_WORLD_BOUNDARY: { + shape = bulletnew(WorldBoundaryShapeBullet); } break; case SHAPE_SPHERE: { shape = bulletnew(SphereShapeBullet); diff --git a/modules/bullet/shape_bullet.cpp b/modules/bullet/shape_bullet.cpp index 40e785d699..88ffb9ec67 100644 --- a/modules/bullet/shape_bullet.cpp +++ b/modules/bullet/shape_bullet.cpp @@ -110,7 +110,7 @@ btEmptyShape *ShapeBullet::create_shape_empty() { return bulletnew(btEmptyShape); } -btStaticPlaneShape *ShapeBullet::create_shape_plane(const btVector3 &planeNormal, btScalar planeConstant) { +btStaticPlaneShape *ShapeBullet::create_shape_world_boundary(const btVector3 &planeNormal, btScalar planeConstant) { return bulletnew(btStaticPlaneShape(planeNormal, planeConstant)); } @@ -164,32 +164,32 @@ btRayShape *ShapeBullet::create_shape_ray(real_t p_length, bool p_slips_on_slope return r; } -/* PLANE */ +/* World boundary */ -PlaneShapeBullet::PlaneShapeBullet() : +WorldBoundaryShapeBullet::WorldBoundaryShapeBullet() : ShapeBullet() {} -void PlaneShapeBullet::set_data(const Variant &p_data) { +void WorldBoundaryShapeBullet::set_data(const Variant &p_data) { setup(p_data); } -Variant PlaneShapeBullet::get_data() const { +Variant WorldBoundaryShapeBullet::get_data() const { return plane; } -PhysicsServer3D::ShapeType PlaneShapeBullet::get_type() const { - return PhysicsServer3D::SHAPE_PLANE; +PhysicsServer3D::ShapeType WorldBoundaryShapeBullet::get_type() const { + return PhysicsServer3D::SHAPE_WORLD_BOUNDARY; } -void PlaneShapeBullet::setup(const Plane &p_plane) { +void WorldBoundaryShapeBullet::setup(const Plane &p_plane) { plane = p_plane; notifyShapeChanged(); } -btCollisionShape *PlaneShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) { +btCollisionShape *WorldBoundaryShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) { btVector3 btPlaneNormal; G_TO_B(plane.normal, btPlaneNormal); - return prepare(PlaneShapeBullet::create_shape_plane(btPlaneNormal, plane.d)); + return prepare(WorldBoundaryShapeBullet::create_shape_world_boundary(btPlaneNormal, plane.d)); } /* Sphere */ diff --git a/modules/bullet/shape_bullet.h b/modules/bullet/shape_bullet.h index 5080d13d99..0822399b5e 100644 --- a/modules/bullet/shape_bullet.h +++ b/modules/bullet/shape_bullet.h @@ -81,7 +81,7 @@ public: public: static class btEmptyShape *create_shape_empty(); - static class btStaticPlaneShape *create_shape_plane(const btVector3 &planeNormal, btScalar planeConstant); + static class btStaticPlaneShape *create_shape_world_boundary(const btVector3 &planeNormal, btScalar planeConstant); static class btSphereShape *create_shape_sphere(btScalar radius); static class btBoxShape *create_shape_box(const btVector3 &boxHalfExtents); static class btCapsuleShape *create_shape_capsule(btScalar radius, btScalar height); @@ -93,11 +93,11 @@ public: static class btRayShape *create_shape_ray(real_t p_length, bool p_slips_on_slope); }; -class PlaneShapeBullet : public ShapeBullet { +class WorldBoundaryShapeBullet : public ShapeBullet { Plane plane; public: - PlaneShapeBullet(); + WorldBoundaryShapeBullet(); virtual void set_data(const Variant &p_data); virtual Variant get_data() const; diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 06db46173c..e785151a6b 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -253,6 +253,9 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class, int extends_index = 0; if (!p_class->extends_path.is_empty()) { + if (p_class->extends_path.is_relative_path()) { + p_class->extends_path = class_type.script_path.get_base_dir().plus_file(p_class->extends_path).simplify_path(); + } Ref<GDScriptParserRef> parser = get_parser_for(p_class->extends_path); if (parser.is_null()) { push_error(vformat(R"(Could not resolve super class path "%s".)", p_class->extends_path), p_class); @@ -1490,6 +1493,10 @@ void GDScriptAnalyzer::resolve_parameter(GDScriptParser::ParameterNode *p_parame } } + if (result.builtin_type == Variant::Type::NIL && result.type_source == GDScriptParser::DataType::ANNOTATED_INFERRED && p_parameter->datatype_specifier == nullptr) { + push_error(vformat(R"(Could not infer the type of the variable "%s" because the initial value is "null".)", p_parameter->identifier->name), p_parameter->default_value); + } + p_parameter->set_datatype(result); } diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index b0d0b02443..a8aef84db3 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -440,7 +440,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code break; case GDScriptParser::DictionaryNode::LUA_TABLE: // Lua-style: key is an identifier interpreted as StringName. - StringName key = static_cast<const GDScriptParser::IdentifierNode *>(dn->elements[i].key)->name; + StringName key = dn->elements[i].key->reduced_value.operator StringName(); element = codegen.add_constant(key); break; } @@ -964,7 +964,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code // Perform operator if any. if (assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) { - GDScriptCodeGenerator::Address value = codegen.add_temporary(); + GDScriptCodeGenerator::Address value = codegen.add_temporary(_gdtype_from_datatype(subscript->get_datatype())); if (subscript->is_attribute) { gen->write_get_named(value, name, prev_base); } else { diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 19584ce194..d555be1e8d 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -2123,22 +2123,34 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_unary_operator(ExpressionN operation->operation = UnaryOpNode::OP_NEGATIVE; operation->variant_op = Variant::OP_NEGATE; operation->operand = parse_precedence(PREC_SIGN, false); + if (operation->operand == nullptr) { + push_error(R"(Expected expression after "-" operator.)"); + } break; case GDScriptTokenizer::Token::PLUS: operation->operation = UnaryOpNode::OP_POSITIVE; operation->variant_op = Variant::OP_POSITIVE; operation->operand = parse_precedence(PREC_SIGN, false); + if (operation->operand == nullptr) { + push_error(R"(Expected expression after "+" operator.)"); + } break; case GDScriptTokenizer::Token::TILDE: operation->operation = UnaryOpNode::OP_COMPLEMENT; operation->variant_op = Variant::OP_BIT_NEGATE; operation->operand = parse_precedence(PREC_BIT_NOT, false); + if (operation->operand == nullptr) { + push_error(R"(Expected expression after "~" operator.)"); + } break; case GDScriptTokenizer::Token::NOT: case GDScriptTokenizer::Token::BANG: operation->operation = UnaryOpNode::OP_LOGIC_NOT; operation->variant_op = Variant::OP_NOT; operation->operand = parse_precedence(PREC_LOGIC_NOT, false); + if (operation->operand == nullptr) { + push_error(vformat(R"(Expected expression after "%s" operator.)", op_type == GDScriptTokenizer::Token::NOT ? "not" : "!")); + } break; default: return nullptr; // Unreachable. @@ -2275,6 +2287,10 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_ternary_operator(Expressio operation->false_expr = parse_precedence(PREC_TERNARY, false); + if (operation->false_expr == nullptr) { + push_error(R"(Expected expression after "else".)"); + } + return operation; } @@ -2472,8 +2488,13 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_dictionary(ExpressionNode switch (dictionary->style) { case DictionaryNode::LUA_TABLE: - if (key != nullptr && key->type != Node::IDENTIFIER) { - push_error("Expected identifier as LUA-style dictionary key."); + if (key != nullptr && key->type != Node::IDENTIFIER && key->type != Node::LITERAL) { + push_error("Expected identifier or string as LUA-style dictionary key."); + advance(); + break; + } + if (key != nullptr && key->type == Node::LITERAL && static_cast<LiteralNode *>(key)->value.get_type() != Variant::STRING) { + push_error("Expected identifier or string as LUA-style dictionary key."); advance(); break; } @@ -2487,7 +2508,11 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_dictionary(ExpressionNode } if (key != nullptr) { key->is_constant = true; - key->reduced_value = static_cast<IdentifierNode *>(key)->name; + if (key->type == Node::IDENTIFIER) { + key->reduced_value = static_cast<IdentifierNode *>(key)->name; + } else if (key->type == Node::LITERAL) { + key->reduced_value = StringName(static_cast<LiteralNode *>(key)->value.operator String()); + } } break; case DictionaryNode::PYTHON_DICT: diff --git a/modules/gdscript/tests/scripts/analyzer/errors/bitwise_float_left_operand.gd b/modules/gdscript/tests/scripts/analyzer/errors/bitwise_float_left_operand.gd new file mode 100644 index 0000000000..9b722ea50a --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/bitwise_float_left_operand.gd @@ -0,0 +1,3 @@ +func test(): + # Error here. + print(2.2 << 4) diff --git a/modules/gdscript/tests/scripts/analyzer/errors/bitwise_float_left_operand.out b/modules/gdscript/tests/scripts/analyzer/errors/bitwise_float_left_operand.out new file mode 100644 index 0000000000..7dee854d1a --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/bitwise_float_left_operand.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Invalid operands to operator <<, float and int. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/bitwise_float_right_operand.gd b/modules/gdscript/tests/scripts/analyzer/errors/bitwise_float_right_operand.gd new file mode 100644 index 0000000000..4502960105 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/bitwise_float_right_operand.gd @@ -0,0 +1,3 @@ +func test(): + # Error here. + print(2 << 4.4) diff --git a/modules/gdscript/tests/scripts/analyzer/errors/bitwise_float_right_operand.out b/modules/gdscript/tests/scripts/analyzer/errors/bitwise_float_right_operand.out new file mode 100644 index 0000000000..1879fc1adf --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/bitwise_float_right_operand.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Invalid operands to operator <<, int and float. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/constant_used_as_function.gd b/modules/gdscript/tests/scripts/analyzer/errors/constant_used_as_function.gd new file mode 100644 index 0000000000..0ad2337c15 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/constant_used_as_function.gd @@ -0,0 +1,5 @@ +const CONSTANT = 25 + + +func test(): + CONSTANT(123) diff --git a/modules/gdscript/tests/scripts/analyzer/errors/constant_used_as_function.out b/modules/gdscript/tests/scripts/analyzer/errors/constant_used_as_function.out new file mode 100644 index 0000000000..f4051cd02c --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/constant_used_as_function.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Member "CONSTANT" is not a function. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_lua.gd b/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_lua.gd new file mode 100644 index 0000000000..7a922cd73e --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_lua.gd @@ -0,0 +1,6 @@ +func test(): + var lua_dict = { + a = 1, + b = 2, + a = 3, # Duplicate isn't allowed. + } diff --git a/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_lua.out b/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_lua.out new file mode 100644 index 0000000000..ffdfa56645 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_lua.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Key "a" was already used in this dictionary (at line 3). diff --git a/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_lua_with_string.gd b/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_lua_with_string.gd new file mode 100644 index 0000000000..933e737ac7 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_lua_with_string.gd @@ -0,0 +1,6 @@ +func test(): + var lua_dict_with_string = { + a = 1, + b = 2, + "a" = 3, # Duplicate isn't allowed. + } diff --git a/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_lua_with_string.out b/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_lua_with_string.out new file mode 100644 index 0000000000..ffdfa56645 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_lua_with_string.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Key "a" was already used in this dictionary (at line 3). diff --git a/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_python.gd b/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_python.gd new file mode 100644 index 0000000000..3b8c83e9cb --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_python.gd @@ -0,0 +1,6 @@ +func test(): + var python_dict = { + "a": 1, + "b": 2, + "a": 3, # Duplicate isn't allowed. + } diff --git a/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_python.out b/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_python.out new file mode 100644 index 0000000000..ffdfa56645 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_python.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Key "a" was already used in this dictionary (at line 3). diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_float_value.gd b/modules/gdscript/tests/scripts/analyzer/errors/enum_float_value.gd new file mode 100644 index 0000000000..cf9a0ce038 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_float_value.gd @@ -0,0 +1,7 @@ +enum Size { + # Error here. Enum values must be integers. + S = 0.0, +} + +func test(): + pass diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_float_value.out b/modules/gdscript/tests/scripts/analyzer/errors/enum_float_value.out new file mode 100644 index 0000000000..b315d20508 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_float_value.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Enum values must be integers. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_string_value.gd b/modules/gdscript/tests/scripts/analyzer/errors/enum_string_value.gd new file mode 100644 index 0000000000..cd9b8fabc4 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_string_value.gd @@ -0,0 +1,7 @@ +enum Size { + # Error here. Enum values must be integers. + S = "hello", +} + +func test(): + pass diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_string_value.out b/modules/gdscript/tests/scripts/analyzer/errors/enum_string_value.out new file mode 100644 index 0000000000..b315d20508 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_string_value.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Enum values must be integers. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/function_used_as_property.gd b/modules/gdscript/tests/scripts/analyzer/errors/function_used_as_property.gd new file mode 100644 index 0000000000..4346503fc2 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/function_used_as_property.gd @@ -0,0 +1,6 @@ +func function(): + pass + + +func test(): + function = 25 diff --git a/modules/gdscript/tests/scripts/analyzer/errors/function_used_as_property.out b/modules/gdscript/tests/scripts/analyzer/errors/function_used_as_property.out new file mode 100644 index 0000000000..5275183da2 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/function_used_as_property.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Cannot assign a new value to a constant. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/invalid_array_index.gd b/modules/gdscript/tests/scripts/analyzer/errors/invalid_array_index.gd new file mode 100644 index 0000000000..b8c0b7a8d3 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/invalid_array_index.gd @@ -0,0 +1,3 @@ +func test(): + # Error here. Array indices must be integers. + print([0, 1][true]) diff --git a/modules/gdscript/tests/scripts/analyzer/errors/invalid_array_index.out b/modules/gdscript/tests/scripts/analyzer/errors/invalid_array_index.out new file mode 100644 index 0000000000..015ad756f8 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/invalid_array_index.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Invalid index type "bool" for a base of type "Array". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_bool.gd b/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_bool.gd new file mode 100644 index 0000000000..c159e03140 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_bool.gd @@ -0,0 +1,2 @@ +func test(): + print(true + true) diff --git a/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_bool.out b/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_bool.out new file mode 100644 index 0000000000..c1dc7c7d08 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_bool.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Invalid operands to operator +, bool and bool. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_dictionary.gd b/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_dictionary.gd new file mode 100644 index 0000000000..6aec2e0796 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_dictionary.gd @@ -0,0 +1,2 @@ +func test(): + print({"hello": "world"} + {"godot": "engine"}) diff --git a/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_dictionary.out b/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_dictionary.out new file mode 100644 index 0000000000..1b4451edbe --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_dictionary.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Invalid operands "Dictionary" and "Dictionary" for "+" operator. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_mixed.gd b/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_mixed.gd new file mode 100644 index 0000000000..eb2a6a0ce7 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_mixed.gd @@ -0,0 +1,2 @@ +func test(): + print("hello" + ["world"]) diff --git a/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_mixed.out b/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_mixed.out new file mode 100644 index 0000000000..6d44c6c1bd --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_mixed.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Invalid operands "String" and "Array" for "+" operator. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/invalid_constant.gd b/modules/gdscript/tests/scripts/analyzer/errors/invalid_constant.gd new file mode 100644 index 0000000000..a7426e88da --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/invalid_constant.gd @@ -0,0 +1,5 @@ +func test(): + var i = 12 + # Constants must be made of a constant, deterministic expression. + # A constant that depends on a variable's value is not a constant expression. + const TEST = 13 + i diff --git a/modules/gdscript/tests/scripts/analyzer/errors/invalid_constant.out b/modules/gdscript/tests/scripts/analyzer/errors/invalid_constant.out new file mode 100644 index 0000000000..c40830f123 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/invalid_constant.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Assigned value for constant "TEST" isn't a constant expression. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/leading_number_separator.gd b/modules/gdscript/tests/scripts/analyzer/errors/leading_number_separator.gd new file mode 100644 index 0000000000..d88c02d6ee --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/leading_number_separator.gd @@ -0,0 +1,3 @@ +func test(): + # Number separators may not be placed at the beginning of a number. + var __ = _123 diff --git a/modules/gdscript/tests/scripts/analyzer/errors/leading_number_separator.out b/modules/gdscript/tests/scripts/analyzer/errors/leading_number_separator.out new file mode 100644 index 0000000000..cfb558bf45 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/leading_number_separator.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Identifier "_123" not declared in the current scope. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/missing_argument.gd b/modules/gdscript/tests/scripts/analyzer/errors/missing_argument.gd new file mode 100644 index 0000000000..70bdadf291 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/missing_argument.gd @@ -0,0 +1,6 @@ +func args(a, b): + print(a) + print(b) + +func test(): + args(1,) diff --git a/modules/gdscript/tests/scripts/parser/errors/missing_argument.out b/modules/gdscript/tests/scripts/analyzer/errors/missing_argument.out index fc2a891109..fc2a891109 100644 --- a/modules/gdscript/tests/scripts/parser/errors/missing_argument.out +++ b/modules/gdscript/tests/scripts/analyzer/errors/missing_argument.out diff --git a/modules/gdscript/tests/scripts/analyzer/errors/property_used_as_function.gd b/modules/gdscript/tests/scripts/analyzer/errors/property_used_as_function.gd new file mode 100644 index 0000000000..059d774927 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/property_used_as_function.gd @@ -0,0 +1,4 @@ +var property = 25 + +func test(): + property() diff --git a/modules/gdscript/tests/scripts/analyzer/errors/property_used_as_function.out b/modules/gdscript/tests/scripts/analyzer/errors/property_used_as_function.out new file mode 100644 index 0000000000..94d6c26a1a --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/property_used_as_function.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Member "property" is not a function. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/redefine_class_constant.gd b/modules/gdscript/tests/scripts/analyzer/errors/redefine_class_constant.gd new file mode 100644 index 0000000000..91401d32fc --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/redefine_class_constant.gd @@ -0,0 +1,7 @@ +# See also `parser-warnings/shadowed-constant.gd`. +const TEST = 25 + + +func test(): + # Error here (trying to set a new value to a constant). + TEST = 50 diff --git a/modules/gdscript/tests/scripts/analyzer/errors/redefine_class_constant.out b/modules/gdscript/tests/scripts/analyzer/errors/redefine_class_constant.out new file mode 100644 index 0000000000..5275183da2 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/redefine_class_constant.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Cannot assign a new value to a constant. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/redefine_local_constant.gd b/modules/gdscript/tests/scripts/analyzer/errors/redefine_local_constant.gd new file mode 100644 index 0000000000..97f3e55e81 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/redefine_local_constant.gd @@ -0,0 +1,5 @@ +func test(): + const TEST = 25 + + # Error here (can't assign a new value to a constant). + TEST = 50 diff --git a/modules/gdscript/tests/scripts/analyzer/errors/redefine_local_constant.out b/modules/gdscript/tests/scripts/analyzer/errors/redefine_local_constant.out new file mode 100644 index 0000000000..5275183da2 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/redefine_local_constant.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Cannot assign a new value to a constant. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/super_nonexistent_base_method.gd b/modules/gdscript/tests/scripts/analyzer/errors/super_nonexistent_base_method.gd new file mode 100644 index 0000000000..722a8fcdb7 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/super_nonexistent_base_method.gd @@ -0,0 +1,11 @@ +# `class` extends RefCounted by default. +class Say: + func say(): + super() + print("say something") + + +func test(): + # RefCounted doesn't have a `say()` method, so the `super()` call in the method + # definition will cause a run-time error. + Say.new().say() diff --git a/modules/gdscript/tests/scripts/analyzer/errors/super_nonexistent_base_method.out b/modules/gdscript/tests/scripts/analyzer/errors/super_nonexistent_base_method.out new file mode 100644 index 0000000000..e3dbf81850 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/super_nonexistent_base_method.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Function "say()" not found in base RefCounted. diff --git a/modules/gdscript/tests/scripts/analyzer/features/as.gd b/modules/gdscript/tests/scripts/analyzer/features/as.gd new file mode 100644 index 0000000000..13a36147c0 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/as.gd @@ -0,0 +1,16 @@ +func test(): + var some_bool = 5 as bool + var some_int = 5 as int + var some_float = 5 as float + print(typeof(some_bool)) + print(typeof(some_int)) + print(typeof(some_float)) + + print() + + var some_bool_typed := 5 as bool + var some_int_typed := 5 as int + var some_float_typed := 5 as float + print(typeof(some_bool_typed)) + print(typeof(some_int_typed)) + print(typeof(some_float_typed)) diff --git a/modules/gdscript/tests/scripts/analyzer/features/as.out b/modules/gdscript/tests/scripts/analyzer/features/as.out new file mode 100644 index 0000000000..bcf84aa6f6 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/as.out @@ -0,0 +1,8 @@ +GDTEST_OK +1 +2 +3 + +1 +2 +3 diff --git a/modules/gdscript/tests/scripts/parser/errors/array_consecutive_commas.gd b/modules/gdscript/tests/scripts/parser/errors/array_consecutive_commas.gd new file mode 100644 index 0000000000..b45f99fdd0 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/array_consecutive_commas.gd @@ -0,0 +1,3 @@ +func test(): + # Arrays with consecutive commas are not allowed. + var array = ["arrays",,,,] diff --git a/modules/gdscript/tests/scripts/parser/errors/array_consecutive_commas.out b/modules/gdscript/tests/scripts/parser/errors/array_consecutive_commas.out new file mode 100644 index 0000000000..4ef8526065 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/array_consecutive_commas.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Expected expression as array element. diff --git a/modules/gdscript/tests/scripts/parser/errors/assignment_2_equal_signs.gd b/modules/gdscript/tests/scripts/parser/errors/assignment_2_equal_signs.gd new file mode 100644 index 0000000000..17d5e078e5 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/assignment_2_equal_signs.gd @@ -0,0 +1,2 @@ +func test(): + var hello == "world" diff --git a/modules/gdscript/tests/scripts/parser/errors/assignment_2_equal_signs.out b/modules/gdscript/tests/scripts/parser/errors/assignment_2_equal_signs.out new file mode 100644 index 0000000000..b150fc0d16 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/assignment_2_equal_signs.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Expected end of statement after variable declaration, found "==" instead. diff --git a/modules/gdscript/tests/scripts/parser/errors/assignment_3_equal_signs.gd b/modules/gdscript/tests/scripts/parser/errors/assignment_3_equal_signs.gd new file mode 100644 index 0000000000..8b5f620889 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/assignment_3_equal_signs.gd @@ -0,0 +1,2 @@ +func test(): + var hello === "world" diff --git a/modules/gdscript/tests/scripts/parser/errors/assignment_3_equal_signs.out b/modules/gdscript/tests/scripts/parser/errors/assignment_3_equal_signs.out new file mode 100644 index 0000000000..b150fc0d16 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/assignment_3_equal_signs.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Expected end of statement after variable declaration, found "==" instead. diff --git a/modules/gdscript/tests/scripts/parser/errors/assignment_in_if.gd b/modules/gdscript/tests/scripts/parser/errors/assignment_in_if.gd new file mode 100644 index 0000000000..8c3a908532 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/assignment_in_if.gd @@ -0,0 +1,4 @@ +func test(): + # Error here. + if foo = 25: + print(foo) diff --git a/modules/gdscript/tests/scripts/parser/errors/assignment_in_if.out b/modules/gdscript/tests/scripts/parser/errors/assignment_in_if.out new file mode 100644 index 0000000000..e8f9130706 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/assignment_in_if.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Assignment is not allowed inside an expression. diff --git a/modules/gdscript/tests/scripts/parser/errors/assignment_in_var.gd b/modules/gdscript/tests/scripts/parser/errors/assignment_in_var.gd new file mode 100644 index 0000000000..126a3227ea --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/assignment_in_var.gd @@ -0,0 +1,2 @@ +func test(): + var hello = "world" = "test" diff --git a/modules/gdscript/tests/scripts/parser/errors/assignment_in_var.out b/modules/gdscript/tests/scripts/parser/errors/assignment_in_var.out new file mode 100644 index 0000000000..e8f9130706 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/assignment_in_var.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Assignment is not allowed inside an expression. diff --git a/modules/gdscript/tests/scripts/parser/errors/assignment_in_var_if.gd b/modules/gdscript/tests/scripts/parser/errors/assignment_in_var_if.gd new file mode 100644 index 0000000000..a99557fa3c --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/assignment_in_var_if.gd @@ -0,0 +1,4 @@ +func test(): + # Error here. + if var foo = 25: + print(foo) diff --git a/modules/gdscript/tests/scripts/parser/errors/assignment_in_var_if.out b/modules/gdscript/tests/scripts/parser/errors/assignment_in_var_if.out new file mode 100644 index 0000000000..e84f4652ac --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/assignment_in_var_if.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Expected conditional expression after "if". diff --git a/modules/gdscript/tests/scripts/parser/errors/assignment_without_identifier.gd b/modules/gdscript/tests/scripts/parser/errors/assignment_without_identifier.gd new file mode 100644 index 0000000000..031ea523c8 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/assignment_without_identifier.gd @@ -0,0 +1,2 @@ +func test(): + var = "world" diff --git a/modules/gdscript/tests/scripts/parser/errors/assignment_without_identifier.out b/modules/gdscript/tests/scripts/parser/errors/assignment_without_identifier.out new file mode 100644 index 0000000000..a4bd8beef1 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/assignment_without_identifier.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Expected variable name after "var". diff --git a/modules/gdscript/tests/scripts/parser/errors/binary_complement_without_argument.gd b/modules/gdscript/tests/scripts/parser/errors/binary_complement_without_argument.gd new file mode 100644 index 0000000000..b52a6defcb --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/binary_complement_without_argument.gd @@ -0,0 +1,2 @@ +func test(): + print(~) diff --git a/modules/gdscript/tests/scripts/parser/errors/binary_complement_without_argument.out b/modules/gdscript/tests/scripts/parser/errors/binary_complement_without_argument.out new file mode 100644 index 0000000000..ceabe42d3c --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/binary_complement_without_argument.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Expected expression after "~" operator. diff --git a/modules/gdscript/tests/scripts/parser/errors/boolean_negation_without_argument.gd b/modules/gdscript/tests/scripts/parser/errors/boolean_negation_without_argument.gd new file mode 100644 index 0000000000..b3ea1ba1f6 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/boolean_negation_without_argument.gd @@ -0,0 +1,2 @@ +func test(): + print(not) diff --git a/modules/gdscript/tests/scripts/parser/errors/boolean_negation_without_argument.out b/modules/gdscript/tests/scripts/parser/errors/boolean_negation_without_argument.out new file mode 100644 index 0000000000..6cf191ea98 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/boolean_negation_without_argument.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Expected expression after "not" operator. diff --git a/modules/gdscript/tests/scripts/parser/errors/boolean_negation_without_argument_using_bang.gd b/modules/gdscript/tests/scripts/parser/errors/boolean_negation_without_argument_using_bang.gd new file mode 100644 index 0000000000..8a33079193 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/boolean_negation_without_argument_using_bang.gd @@ -0,0 +1,2 @@ +func test(): + print(!) diff --git a/modules/gdscript/tests/scripts/parser/errors/boolean_negation_without_argument_using_bang.out b/modules/gdscript/tests/scripts/parser/errors/boolean_negation_without_argument_using_bang.out new file mode 100644 index 0000000000..87fcc5e2b0 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/boolean_negation_without_argument_using_bang.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Expected expression after "!" operator. diff --git a/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.gd b/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.gd new file mode 100644 index 0000000000..d13d713454 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.gd @@ -0,0 +1,6 @@ +# Error here. `class_name` should be used *before* annotations, not after. +@icon("res://path/to/optional/icon.svg") +class_name HelloWorld + +func test(): + pass diff --git a/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.out b/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.out new file mode 100644 index 0000000000..0bcc8acc55 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +"class_name" should be used before annotations. diff --git a/modules/gdscript/tests/scripts/parser/errors/constant_conflicts_variable.gd b/modules/gdscript/tests/scripts/parser/errors/constant_conflicts_variable.gd new file mode 100644 index 0000000000..49fb4ffedf --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/constant_conflicts_variable.gd @@ -0,0 +1,3 @@ +func test(): + var TEST = 50 + const TEST = 25 diff --git a/modules/gdscript/tests/scripts/parser/errors/constant_conflicts_variable.out b/modules/gdscript/tests/scripts/parser/errors/constant_conflicts_variable.out new file mode 100644 index 0000000000..407f094ca0 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/constant_conflicts_variable.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +There is already a variable named "TEST" declared in this scope. diff --git a/modules/gdscript/tests/scripts/parser/errors/default_value_in_function_call.gd b/modules/gdscript/tests/scripts/parser/errors/default_value_in_function_call.gd new file mode 100644 index 0000000000..2581d873dd --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/default_value_in_function_call.gd @@ -0,0 +1,7 @@ +func hello(arg1): + print(arg1) + + +func test(): + # Error here. + hello(arg1 = 25) diff --git a/modules/gdscript/tests/scripts/parser/errors/default_value_in_function_call.out b/modules/gdscript/tests/scripts/parser/errors/default_value_in_function_call.out new file mode 100644 index 0000000000..e8f9130706 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/default_value_in_function_call.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Assignment is not allowed inside an expression. diff --git a/modules/gdscript/tests/scripts/parser/errors/function_conflicts_constant.gd b/modules/gdscript/tests/scripts/parser/errors/function_conflicts_constant.gd new file mode 100644 index 0000000000..a8f7cf1810 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/function_conflicts_constant.gd @@ -0,0 +1,5 @@ +const test = 25 + + +func test(): + pass diff --git a/modules/gdscript/tests/scripts/parser/errors/function_conflicts_constant.out b/modules/gdscript/tests/scripts/parser/errors/function_conflicts_constant.out new file mode 100644 index 0000000000..c614acd094 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/function_conflicts_constant.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Function "test" has the same name as a previously declared constant. diff --git a/modules/gdscript/tests/scripts/parser/errors/function_conflicts_variable.gd b/modules/gdscript/tests/scripts/parser/errors/function_conflicts_variable.gd new file mode 100644 index 0000000000..5c86710a40 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/function_conflicts_variable.gd @@ -0,0 +1,7 @@ +func test(): + pass + + +# Error here. The difference with `variable-conflicts-function.gd` is that here, +# the function is defined *before* the variable. +var test = 25 diff --git a/modules/gdscript/tests/scripts/parser/errors/function_conflicts_variable.out b/modules/gdscript/tests/scripts/parser/errors/function_conflicts_variable.out new file mode 100644 index 0000000000..551db61531 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/function_conflicts_variable.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Variable "test" has the same name as a previously declared function. diff --git a/modules/gdscript/tests/scripts/parser/errors/invalid_identifier_number.gd b/modules/gdscript/tests/scripts/parser/errors/invalid_identifier_number.gd new file mode 100644 index 0000000000..081b9faf4b --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/invalid_identifier_number.gd @@ -0,0 +1,3 @@ +func test(): + # Error here. + var 23test = "is not a valid identifier" diff --git a/modules/gdscript/tests/scripts/parser/errors/invalid_identifier_number.out b/modules/gdscript/tests/scripts/parser/errors/invalid_identifier_number.out new file mode 100644 index 0000000000..a4bd8beef1 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/invalid_identifier_number.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Expected variable name after "var". diff --git a/modules/gdscript/tests/scripts/parser/errors/invalid_identifier_string.gd b/modules/gdscript/tests/scripts/parser/errors/invalid_identifier_string.gd new file mode 100644 index 0000000000..fa4d6b5cac --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/invalid_identifier_string.gd @@ -0,0 +1,3 @@ +func test(): + # Error here. + var "yes" = "is not a valid identifier" diff --git a/modules/gdscript/tests/scripts/parser/errors/invalid_identifier_string.out b/modules/gdscript/tests/scripts/parser/errors/invalid_identifier_string.out new file mode 100644 index 0000000000..a4bd8beef1 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/invalid_identifier_string.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Expected variable name after "var". diff --git a/modules/gdscript/tests/scripts/parser/errors/missing_argument.gd b/modules/gdscript/tests/scripts/parser/errors/missing_argument.gd deleted file mode 100644 index c56ad94095..0000000000 --- a/modules/gdscript/tests/scripts/parser/errors/missing_argument.gd +++ /dev/null @@ -1,6 +0,0 @@ -func args(a, b): - print(a) - print(b) - -func test(): - args(1,) diff --git a/modules/gdscript/tests/scripts/parser/errors/missing_closing_expr_paren.gd b/modules/gdscript/tests/scripts/parser/errors/missing_closing_expr_paren.gd index a1077e1985..8af5f123cc 100644 --- a/modules/gdscript/tests/scripts/parser/errors/missing_closing_expr_paren.gd +++ b/modules/gdscript/tests/scripts/parser/errors/missing_closing_expr_paren.gd @@ -1,2 +1,2 @@ func test(): - var a = ("missing paren ->" + var a = ("missing paren ->" diff --git a/modules/gdscript/tests/scripts/parser/errors/missing_colon.gd b/modules/gdscript/tests/scripts/parser/errors/missing_colon.gd index 62cb633e9e..0e5e5ce060 100644 --- a/modules/gdscript/tests/scripts/parser/errors/missing_colon.gd +++ b/modules/gdscript/tests/scripts/parser/errors/missing_colon.gd @@ -1,3 +1,3 @@ func test(): - if true # Missing colon here. - print("true") + if true # Missing colon here. + print("true") diff --git a/modules/gdscript/tests/scripts/parser/errors/missing_expression_after_ternary_else.gd b/modules/gdscript/tests/scripts/parser/errors/missing_expression_after_ternary_else.gd new file mode 100644 index 0000000000..1f66935329 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/missing_expression_after_ternary_else.gd @@ -0,0 +1,4 @@ +func test(): + var x = 1 if false else + print("oops") + print(x) diff --git a/modules/gdscript/tests/scripts/parser/errors/missing_expression_after_ternary_else.out b/modules/gdscript/tests/scripts/parser/errors/missing_expression_after_ternary_else.out new file mode 100644 index 0000000000..dab6b0a1ad --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/missing_expression_after_ternary_else.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Expected expression after "else". diff --git a/modules/gdscript/tests/scripts/parser/errors/missing_paren_after_args.gd b/modules/gdscript/tests/scripts/parser/errors/missing_paren_after_args.gd index 116b0151da..7a35bf688c 100644 --- a/modules/gdscript/tests/scripts/parser/errors/missing_paren_after_args.gd +++ b/modules/gdscript/tests/scripts/parser/errors/missing_paren_after_args.gd @@ -1,6 +1,6 @@ func args(a, b): - print(a) - print(b) + print(a) + print(b) func test(): - args(1,2 + args(1,2 diff --git a/modules/gdscript/tests/scripts/parser/errors/mistaken_decrement_operator.gd b/modules/gdscript/tests/scripts/parser/errors/mistaken_decrement_operator.gd new file mode 100644 index 0000000000..193f824702 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/mistaken_decrement_operator.gd @@ -0,0 +1,3 @@ +func test(): + var a = 0 + print(a--) diff --git a/modules/gdscript/tests/scripts/parser/errors/mistaken_decrement_operator.out b/modules/gdscript/tests/scripts/parser/errors/mistaken_decrement_operator.out new file mode 100644 index 0000000000..b6b577a277 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/mistaken_decrement_operator.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Expected expression after "-" operator. diff --git a/modules/gdscript/tests/scripts/parser/errors/mistaken_increment_operator.gd b/modules/gdscript/tests/scripts/parser/errors/mistaken_increment_operator.gd new file mode 100644 index 0000000000..035d27638c --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/mistaken_increment_operator.gd @@ -0,0 +1,3 @@ +func test(): + var a = 0 + print(a++) diff --git a/modules/gdscript/tests/scripts/parser/errors/mistaken_increment_operator.out b/modules/gdscript/tests/scripts/parser/errors/mistaken_increment_operator.out new file mode 100644 index 0000000000..24eb76593a --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/mistaken_increment_operator.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Expected expression after "+" operator. diff --git a/modules/gdscript/tests/scripts/parser/errors/multiple_number_separators.gd b/modules/gdscript/tests/scripts/parser/errors/multiple_number_separators.gd new file mode 100644 index 0000000000..71a03fbc0d --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/multiple_number_separators.gd @@ -0,0 +1,3 @@ +func test(): + # Number separators may not be placed right next to each other. + var __ = 1__23 diff --git a/modules/gdscript/tests/scripts/parser/errors/multiple_number_separators.out b/modules/gdscript/tests/scripts/parser/errors/multiple_number_separators.out new file mode 100644 index 0000000000..71a3c2fd6a --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/multiple_number_separators.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Only one underscore can be used as a numeric separator. diff --git a/modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.gd b/modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.gd index 3875ce3936..df388a21de 100644 --- a/modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.gd +++ b/modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.gd @@ -1,3 +1,5 @@ extends Node + + func test(): - var a = $ # Expected some node path. + var a = $ # Expected some node path. diff --git a/modules/gdscript/tests/scripts/parser/errors/redefine_keyword.gd b/modules/gdscript/tests/scripts/parser/errors/redefine_keyword.gd new file mode 100644 index 0000000000..c289c9d976 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/redefine_keyword.gd @@ -0,0 +1,2 @@ +func test(): + var while = "it's been a while" diff --git a/modules/gdscript/tests/scripts/parser/errors/redefine_keyword.out b/modules/gdscript/tests/scripts/parser/errors/redefine_keyword.out new file mode 100644 index 0000000000..a4bd8beef1 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/redefine_keyword.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Expected variable name after "var". diff --git a/modules/gdscript/tests/scripts/parser/errors/redefine_local_constant_with_keyword.gd b/modules/gdscript/tests/scripts/parser/errors/redefine_local_constant_with_keyword.gd new file mode 100644 index 0000000000..204259f981 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/redefine_local_constant_with_keyword.gd @@ -0,0 +1,5 @@ +func test(): + const TEST = 25 + + # Error here (can't redeclare a constant on the same scope). + const TEST = 50 diff --git a/modules/gdscript/tests/scripts/parser/errors/redefine_local_constant_with_keyword.out b/modules/gdscript/tests/scripts/parser/errors/redefine_local_constant_with_keyword.out new file mode 100644 index 0000000000..d67cc92953 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/redefine_local_constant_with_keyword.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +There is already a constant named "TEST" declared in this scope. diff --git a/modules/gdscript/tests/scripts/parser/errors/variable_conflicts_constant.gd b/modules/gdscript/tests/scripts/parser/errors/variable_conflicts_constant.gd new file mode 100644 index 0000000000..0d8843df20 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/variable_conflicts_constant.gd @@ -0,0 +1,3 @@ +func test(): + const TEST = 25 + var TEST = 50 diff --git a/modules/gdscript/tests/scripts/parser/errors/variable_conflicts_constant.out b/modules/gdscript/tests/scripts/parser/errors/variable_conflicts_constant.out new file mode 100644 index 0000000000..d67cc92953 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/variable_conflicts_constant.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +There is already a constant named "TEST" declared in this scope. diff --git a/modules/gdscript/tests/scripts/parser/errors/variable_conflicts_function.gd b/modules/gdscript/tests/scripts/parser/errors/variable_conflicts_function.gd new file mode 100644 index 0000000000..ce2c8784d6 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/variable_conflicts_function.gd @@ -0,0 +1,6 @@ +var test = 25 + +# Error here. The difference with `variable-conflicts-function.gd` is that here, +# the function is defined *before* the variable. +func test(): + pass diff --git a/modules/gdscript/tests/scripts/parser/errors/variable_conflicts_function.out b/modules/gdscript/tests/scripts/parser/errors/variable_conflicts_function.out new file mode 100644 index 0000000000..daeaca40ec --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/variable_conflicts_function.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Function "test" has the same name as a previously declared variable. diff --git a/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.gd b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.gd index 6fd2692d47..babe39068c 100644 --- a/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.gd +++ b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.gd @@ -1,3 +1,5 @@ extends Node + + func test(): - $23 # Can't use number here. + $23 # Can't use number here. diff --git a/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.gd b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.gd index 1836d42226..b6b1cf3e52 100644 --- a/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.gd +++ b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.gd @@ -1,3 +1,5 @@ extends Node + + func test(): - $MyNode/23 # Can't use number here. + $MyNode/23 # Can't use number here. diff --git a/modules/gdscript/tests/scripts/parser/features/array.gd b/modules/gdscript/tests/scripts/parser/features/array.gd new file mode 100644 index 0000000000..828ce8d134 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/array.gd @@ -0,0 +1,16 @@ +func test(): + # Indexing from the beginning: + print([1, 2, 3][0]) + print([1, 2, 3][1]) + print([1, 2, 3][2]) + + # Indexing from the end: + print([1, 2, 3][-1]) + print([1, 2, 3][-2]) + print([1, 2, 3][-3]) + + # Float indices are currently allowed, but should probably be an error? + print([1, 2, 3][0.4]) + print([1, 2, 3][0.8]) + print([1, 2, 3][1.0]) + print([1, 2, 3][-1.0]) diff --git a/modules/gdscript/tests/scripts/parser/features/array.out b/modules/gdscript/tests/scripts/parser/features/array.out new file mode 100644 index 0000000000..cf576c59e0 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/array.out @@ -0,0 +1,11 @@ +GDTEST_OK +1 +2 +3 +3 +2 +1 +1 +1 +2 +3 diff --git a/modules/gdscript/tests/scripts/parser/features/bitwise_operators.gd b/modules/gdscript/tests/scripts/parser/features/bitwise_operators.gd new file mode 100644 index 0000000000..de502c6ed1 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/bitwise_operators.gd @@ -0,0 +1,50 @@ +enum Flags { + FIRE = 1 << 1, + ICE = 1 << 2, + SLIPPERY = 1 << 3, + STICKY = 1 << 4, + NONSOLID = 1 << 5, + + ALL = FIRE | ICE | SLIPPERY | STICKY | NONSOLID, +} + + +func test(): + var flags = Flags.FIRE | Flags.SLIPPERY + print(flags) + + flags = Flags.FIRE & Flags.SLIPPERY + print(flags) + + flags = Flags.FIRE ^ Flags.SLIPPERY + print(flags) + + flags = Flags.ALL & (Flags.FIRE | Flags.ICE) + print(flags) + + flags = (Flags.ALL & Flags.FIRE) | Flags.ICE + print(flags) + + flags = Flags.ALL & Flags.FIRE | Flags.ICE + print(flags) + + # Enum value must be casted to an integer. Otherwise, a parser error is emitted. + flags &= int(Flags.ICE) + print(flags) + + flags ^= int(Flags.ICE) + print(flags) + + flags |= int(Flags.STICKY | Flags.SLIPPERY) + print(flags) + + print() + + var num = 2 << 4 + print(num) + + num <<= 2 + print(num) + + num >>= 2 + print(num) diff --git a/modules/gdscript/tests/scripts/parser/features/bitwise_operators.out b/modules/gdscript/tests/scripts/parser/features/bitwise_operators.out new file mode 100644 index 0000000000..410e358a05 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/bitwise_operators.out @@ -0,0 +1,14 @@ +GDTEST_OK +10 +0 +10 +6 +6 +6 +4 +0 +24 + +32 +128 +32 diff --git a/modules/gdscript/tests/scripts/parser/features/class.gd b/modules/gdscript/tests/scripts/parser/features/class.gd new file mode 100644 index 0000000000..6652f85ad9 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/class.gd @@ -0,0 +1,25 @@ +# Test non-nested/slightly nested class architecture. +class Test: + var number = 25 + var string = "hello" + + +class TestSub extends Test: + var other_string = "bye" + + +class TestConstructor: + func _init(argument = 10): + print(str("constructor with argument ", argument)) + + +func test(): + var test_instance = Test.new() + test_instance.number = 42 + + var test_sub = TestSub.new() + assert(test_sub.number == 25) # From Test. + assert(test_sub.other_string == "bye") # From TestSub. + + TestConstructor.new() + TestConstructor.new(500) diff --git a/modules/gdscript/tests/scripts/parser/features/class.out b/modules/gdscript/tests/scripts/parser/features/class.out new file mode 100644 index 0000000000..94dc2d6003 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/class.out @@ -0,0 +1,3 @@ +GDTEST_OK +constructor with argument 10 +constructor with argument 500 diff --git a/modules/gdscript/tests/scripts/parser/features/class_inheritance.gd b/modules/gdscript/tests/scripts/parser/features/class_inheritance.gd new file mode 100644 index 0000000000..3f9b4ea86e --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/class_inheritance.gd @@ -0,0 +1,33 @@ +# Test deeply nested class architectures. +class Test: + var depth = 1 + + class Nested: + var depth_nested = 10 + + +class Test2 extends Test: + var depth2 = 2 + + +class Test3 extends Test2: + var depth3 = 3 + + +class Test4 extends Test3: + var depth4 = 4 + + class Nested2: + var depth4_nested = 100 + + +func test(): + print(Test.new().depth) + print(Test2.new().depth) + print(Test2.new().depth2) + print(Test3.new().depth) + print(Test3.new().depth3) + print(Test4.new().depth) + print(Test4.new().depth4) + print(Test.Nested.new().depth_nested) + print(Test4.Nested2.new().depth4_nested) diff --git a/modules/gdscript/tests/scripts/parser/features/class_inheritance.out b/modules/gdscript/tests/scripts/parser/features/class_inheritance.out new file mode 100644 index 0000000000..75bdde3d94 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/class_inheritance.out @@ -0,0 +1,10 @@ +GDTEST_OK +1 +1 +2 +1 +3 +1 +4 +10 +100 diff --git a/modules/gdscript/tests/scripts/parser/features/class_name.gd b/modules/gdscript/tests/scripts/parser/features/class_name.gd new file mode 100644 index 0000000000..8bd188e247 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/class_name.gd @@ -0,0 +1,5 @@ +class_name HelloWorld +@icon("res://path/to/optional/icon.svg") + +func test(): + pass diff --git a/modules/gdscript/tests/scripts/parser/features/class_name.out b/modules/gdscript/tests/scripts/parser/features/class_name.out new file mode 100644 index 0000000000..d73c5eb7cd --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/class_name.out @@ -0,0 +1 @@ +GDTEST_OK diff --git a/modules/gdscript/tests/scripts/parser/features/concatenation.gd b/modules/gdscript/tests/scripts/parser/features/concatenation.gd new file mode 100644 index 0000000000..e8335c9823 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/concatenation.gd @@ -0,0 +1,4 @@ +func test(): + print(20 + 20) + print("hello" + "world") + print([1, 2] + [3, 4]) diff --git a/modules/gdscript/tests/scripts/parser/features/concatenation.out b/modules/gdscript/tests/scripts/parser/features/concatenation.out new file mode 100644 index 0000000000..23bff08f49 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/concatenation.out @@ -0,0 +1,4 @@ +GDTEST_OK +40 +helloworld +[1, 2, 3, 4] diff --git a/modules/gdscript/tests/scripts/parser/features/constants.gd b/modules/gdscript/tests/scripts/parser/features/constants.gd new file mode 100644 index 0000000000..013c9c074f --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/constants.gd @@ -0,0 +1,11 @@ +func test(): + const _TEST = 12 + 34 - 56 * 78 + const _STRING = "yes" + const _VECTOR = Vector2(5, 6) + const _ARRAY = [] + const _DICTIONARY = {"this": "dictionary"} + + # Create user constants from built-in constants. + const _HELLO = PI + TAU + const _INFINITY = INF + const _NOT_A_NUMBER = NAN diff --git a/modules/gdscript/tests/scripts/parser/features/constants.out b/modules/gdscript/tests/scripts/parser/features/constants.out new file mode 100644 index 0000000000..6093e4a6ca --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/constants.out @@ -0,0 +1,33 @@ +GDTEST_OK +>> WARNING +>> Line: 2 +>> UNUSED_LOCAL_CONSTANT +>> The local constant '_TEST' is declared but never used in the block. If this is intended, prefix it with an underscore: '__TEST' +>> WARNING +>> Line: 3 +>> UNUSED_LOCAL_CONSTANT +>> The local constant '_STRING' is declared but never used in the block. If this is intended, prefix it with an underscore: '__STRING' +>> WARNING +>> Line: 4 +>> UNUSED_LOCAL_CONSTANT +>> The local constant '_VECTOR' is declared but never used in the block. If this is intended, prefix it with an underscore: '__VECTOR' +>> WARNING +>> Line: 5 +>> UNUSED_LOCAL_CONSTANT +>> The local constant '_ARRAY' is declared but never used in the block. If this is intended, prefix it with an underscore: '__ARRAY' +>> WARNING +>> Line: 6 +>> UNUSED_LOCAL_CONSTANT +>> The local constant '_DICTIONARY' is declared but never used in the block. If this is intended, prefix it with an underscore: '__DICTIONARY' +>> WARNING +>> Line: 9 +>> UNUSED_LOCAL_CONSTANT +>> The local constant '_HELLO' is declared but never used in the block. If this is intended, prefix it with an underscore: '__HELLO' +>> WARNING +>> Line: 10 +>> UNUSED_LOCAL_CONSTANT +>> The local constant '_INFINITY' is declared but never used in the block. If this is intended, prefix it with an underscore: '__INFINITY' +>> WARNING +>> Line: 11 +>> UNUSED_LOCAL_CONSTANT +>> The local constant '_NOT_A_NUMBER' is declared but never used in the block. If this is intended, prefix it with an underscore: '__NOT_A_NUMBER' diff --git a/modules/gdscript/tests/scripts/parser/features/dictionary.gd b/modules/gdscript/tests/scripts/parser/features/dictionary.gd new file mode 100644 index 0000000000..99afe166c7 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/dictionary.gd @@ -0,0 +1,37 @@ +func test(): + # Non-string keys are valid. + print({ 12: "world" }[12]) + + var contents = { + 0: "zero", + 0.0: "zero point zero", + null: "null", + false: "false", + []: "empty array", + Vector2i(): "zero Vector2i", + 15: { + 22: { + 4: ["nesting", "arrays"], + }, + }, + } + + print(contents[0.0]) + # Making sure declaration order doesn't affect things... + print({ 0.0: "zero point zero", 0: "zero", null: "null", false: "false", []: "empty array" }[0]) + print({ 0.0: "zero point zero", 0: "zero", null: "null", false: "false", []: "empty array" }[0.0]) + + print(contents[null]) + print(contents[false]) + print(contents[[]]) + print(contents[Vector2i()]) + print(contents[15]) + print(contents[15][22]) + print(contents[15][22][4]) + print(contents[15][22][4][0]) + print(contents[15][22][4][1]) + + # Currently fails with "invalid get index 'hello' on base Dictionary". + # Both syntaxes are valid however. + #print({ "hello": "world" }["hello"]) + #print({ "hello": "world" }.hello) diff --git a/modules/gdscript/tests/scripts/parser/features/dictionary.out b/modules/gdscript/tests/scripts/parser/features/dictionary.out new file mode 100644 index 0000000000..54083c1afc --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/dictionary.out @@ -0,0 +1,14 @@ +GDTEST_OK +world +zero point zero +zero +zero point zero +null +false +empty array +zero Vector2i +{22:{4:[nesting, arrays]}} +{4:[nesting, arrays]} +[nesting, arrays] +nesting +arrays diff --git a/modules/gdscript/tests/scripts/parser/features/dictionary_lua_style.gd b/modules/gdscript/tests/scripts/parser/features/dictionary_lua_style.gd new file mode 100644 index 0000000000..fdd6de2348 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/dictionary_lua_style.gd @@ -0,0 +1,9 @@ +func test(): + var lua_dict = { + a = 1, + "b" = 2, # Using strings are allowed too. + "with spaces" = 3, # Especially useful when key has spaces... + "2" = 4, # ... or invalid identifiers. + } + + print(lua_dict) diff --git a/modules/gdscript/tests/scripts/parser/features/dictionary_lua_style.out b/modules/gdscript/tests/scripts/parser/features/dictionary_lua_style.out new file mode 100644 index 0000000000..447d7e223c --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/dictionary_lua_style.out @@ -0,0 +1,2 @@ +GDTEST_OK +{2:4, a:1, b:2, with spaces:3} diff --git a/modules/gdscript/tests/scripts/parser/features/dictionary_mixed_syntax.gd b/modules/gdscript/tests/scripts/parser/features/dictionary_mixed_syntax.gd new file mode 100644 index 0000000000..cce8538ddd --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/dictionary_mixed_syntax.gd @@ -0,0 +1,12 @@ +func test(): + # Mixing Python-style and Lua-style syntax in the same dictionary declaration + # is allowed. + var dict = { + "hello": { + world = { + "is": "beautiful", + }, + }, + } + + print(dict) diff --git a/modules/gdscript/tests/scripts/parser/features/dictionary_mixed_syntax.out b/modules/gdscript/tests/scripts/parser/features/dictionary_mixed_syntax.out new file mode 100644 index 0000000000..62be807a1f --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/dictionary_mixed_syntax.out @@ -0,0 +1,2 @@ +GDTEST_OK +{hello:{world:{is:beautiful}}} diff --git a/modules/gdscript/tests/scripts/parser/features/dollar_node_paths.gd b/modules/gdscript/tests/scripts/parser/features/dollar_node_paths.gd new file mode 100644 index 0000000000..8ba558e91d --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/dollar_node_paths.gd @@ -0,0 +1,20 @@ +extends Node + + +func test(): + # Create the required node structure. + var hello = Node.new() + hello.name = "Hello" + add_child(hello) + var world = Node.new() + world.name = "World" + hello.add_child(world) + + # All the ways of writing node paths below with the `$` operator are valid. + # Results are assigned to variables to avoid warnings. + var __ = $Hello + __ = $"Hello" + __ = $Hello/World + __ = $"Hello/World" + __ = $"Hello/.." + __ = $"Hello/../Hello/World" diff --git a/modules/gdscript/tests/scripts/parser/features/dollar_node_paths.out b/modules/gdscript/tests/scripts/parser/features/dollar_node_paths.out new file mode 100644 index 0000000000..d73c5eb7cd --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/dollar_node_paths.out @@ -0,0 +1 @@ +GDTEST_OK diff --git a/modules/gdscript/tests/scripts/parser/features/enum.gd b/modules/gdscript/tests/scripts/parser/features/enum.gd new file mode 100644 index 0000000000..bbc66f6f3d --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/enum.gd @@ -0,0 +1,14 @@ +enum Size { + S = -10, + M, + L = 0, + XL = 10, + XXL, +} + +func test(): + print(Size.S) + print(Size.M) + print(Size.L) + print(Size.XL) + print(Size.XXL) diff --git a/modules/gdscript/tests/scripts/parser/features/enum.out b/modules/gdscript/tests/scripts/parser/features/enum.out new file mode 100644 index 0000000000..6f3a4a3e49 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/enum.out @@ -0,0 +1,6 @@ +GDTEST_OK +-10 +-9 +0 +10 +11 diff --git a/modules/gdscript/tests/scripts/parser/features/export_variable.gd b/modules/gdscript/tests/scripts/parser/features/export_variable.gd new file mode 100644 index 0000000000..51e7d4a8ed --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/export_variable.gd @@ -0,0 +1,11 @@ +@export var example = 99 +@export_range(0, 100) var example_range = 100 +@export_range(0, 100, 1) var example_range_step = 101 +@export_range(0, 100, 1, "or_greater") var example_range_step_or_greater = 102 + + +func test(): + print(example) + print(example_range) + print(example_range_step) + print(example_range_step_or_greater) diff --git a/modules/gdscript/tests/scripts/parser/features/export_variable.out b/modules/gdscript/tests/scripts/parser/features/export_variable.out new file mode 100644 index 0000000000..b455196359 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/export_variable.out @@ -0,0 +1,5 @@ +GDTEST_OK +99 +100 +101 +102 diff --git a/modules/gdscript/tests/scripts/parser/features/float_notation.gd b/modules/gdscript/tests/scripts/parser/features/float_notation.gd new file mode 100644 index 0000000000..b207b88820 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/float_notation.gd @@ -0,0 +1,24 @@ +func test(): + # The following floating-point notations are all valid: + print(is_equal_approx(123., 123)) + print(is_equal_approx(.123, 0.123)) + print(is_equal_approx(.123e4, 1230)) + print(is_equal_approx(123.e4, 1.23e6)) + print(is_equal_approx(.123e-1, 0.0123)) + print(is_equal_approx(123.e-1, 12.3)) + + # Same as above, but with negative numbers. + print(is_equal_approx(-123., -123)) + print(is_equal_approx(-.123, -0.123)) + print(is_equal_approx(-.123e4, -1230)) + print(is_equal_approx(-123.e4, -1.23e6)) + print(is_equal_approx(-.123e-1, -0.0123)) + print(is_equal_approx(-123.e-1, -12.3)) + + # Same as above, but with explicit positive numbers (which is redundant). + print(is_equal_approx(+123., +123)) + print(is_equal_approx(+.123, +0.123)) + print(is_equal_approx(+.123e4, +1230)) + print(is_equal_approx(+123.e4, +1.23e6)) + print(is_equal_approx(+.123e-1, +0.0123)) + print(is_equal_approx(+123.e-1, +12.3)) diff --git a/modules/gdscript/tests/scripts/parser/features/float_notation.out b/modules/gdscript/tests/scripts/parser/features/float_notation.out new file mode 100644 index 0000000000..041c4439b0 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/float_notation.out @@ -0,0 +1,19 @@ +GDTEST_OK +true +true +true +true +true +true +true +true +true +true +true +true +true +true +true +true +true +true diff --git a/modules/gdscript/tests/scripts/parser/features/for_range.gd b/modules/gdscript/tests/scripts/parser/features/for_range.gd new file mode 100644 index 0000000000..fd1d002b82 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/for_range.gd @@ -0,0 +1,39 @@ +func test(): + for i in range(5): + print(i) + + print() + + # Equivalent to the above `for` loop: + for i in 5: + print(i) + + print() + + for i in range(1, 5): + print(i) + + print() + + for i in range(1, -5, -1): + print(i) + + print() + + for i in [2, 4, 6, -8]: + print(i) + + print() + + for i in [true, false]: + print(i) + + print() + + for i in [Vector2i(10, 20), Vector2i(-30, -40)]: + print(i) + + print() + + for i in "Hello_Unicôde_world!_🦄": + print(i) diff --git a/modules/gdscript/tests/scripts/parser/features/for_range.out b/modules/gdscript/tests/scripts/parser/features/for_range.out new file mode 100644 index 0000000000..50b2c856c5 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/for_range.out @@ -0,0 +1,58 @@ +GDTEST_OK +0 +1 +2 +3 +4 + +0 +1 +2 +3 +4 + +1 +2 +3 +4 + +1 +0 +-1 +-2 +-3 +-4 + +2 +4 +6 +-8 + +true +false + +(10, 20) +(-30, -40) + +H +e +l +l +o +_ +U +n +i +c +ô +d +e +_ +w +o +r +l +d +! +_ +🦄 diff --git a/modules/gdscript/tests/scripts/parser/features/in.gd b/modules/gdscript/tests/scripts/parser/features/in.gd new file mode 100644 index 0000000000..f7296017c5 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/in.gd @@ -0,0 +1,14 @@ +func test(): + print("dot" in "Godot") + print(not "i" in "team") + + print(true in [true, false]) + print(not null in [true, false]) + print(null in [null]) + + print(26 in [8, 26, 64, 100]) + print(not Vector2i(10, 20) in [Vector2i(20, 10)]) + + print("apple" in { "apple": "fruit" }) + print("apple" in { "apple": null }) + print(not "apple" in { "fruit": "apple" }) diff --git a/modules/gdscript/tests/scripts/parser/features/in.out b/modules/gdscript/tests/scripts/parser/features/in.out new file mode 100644 index 0000000000..7533f6ff54 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/in.out @@ -0,0 +1,11 @@ +GDTEST_OK +true +true +true +true +true +true +true +true +true +true diff --git a/modules/gdscript/tests/scripts/parser/features/match.gd b/modules/gdscript/tests/scripts/parser/features/match.gd new file mode 100644 index 0000000000..4d05490aa5 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/match.gd @@ -0,0 +1,18 @@ +func test(): + var i = "Hello" + match i: + "Hello": + print("hello") + # This will fall through to the default case below. + continue + "Good bye": + print("bye") + _: + print("default") + + var j = 25 + match j: + 26: + print("This won't match") + _: + print("This will match") diff --git a/modules/gdscript/tests/scripts/parser/features/match.out b/modules/gdscript/tests/scripts/parser/features/match.out new file mode 100644 index 0000000000..732885c7a2 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/match.out @@ -0,0 +1,4 @@ +GDTEST_OK +hello +default +This will match diff --git a/modules/gdscript/tests/scripts/parser/features/multiline_arrays.gd b/modules/gdscript/tests/scripts/parser/features/multiline_arrays.gd new file mode 100644 index 0000000000..3b30998853 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/multiline_arrays.gd @@ -0,0 +1,7 @@ +func test(): + var __ = [ + "this", + "is", "a","multiline", + + "array", "with mixed indentation and trailing comma", + ] diff --git a/modules/gdscript/tests/scripts/parser/features/multiline_arrays.out b/modules/gdscript/tests/scripts/parser/features/multiline_arrays.out new file mode 100644 index 0000000000..d73c5eb7cd --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/multiline_arrays.out @@ -0,0 +1 @@ +GDTEST_OK diff --git a/modules/gdscript/tests/scripts/parser/features/multiline_dictionaries.gd b/modules/gdscript/tests/scripts/parser/features/multiline_dictionaries.gd new file mode 100644 index 0000000000..e108cd23d4 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/multiline_dictionaries.gd @@ -0,0 +1,10 @@ +func test(): + var __ = { + "multiline": "dictionary","should": "work", + "even with": "a trailing comma", + } + + __ = { + this_also_applies = "to the", + lua_style_syntax = null, foo = null, + } diff --git a/modules/gdscript/tests/scripts/parser/features/multiline_dictionaries.out b/modules/gdscript/tests/scripts/parser/features/multiline_dictionaries.out new file mode 100644 index 0000000000..d73c5eb7cd --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/multiline_dictionaries.out @@ -0,0 +1 @@ +GDTEST_OK diff --git a/modules/gdscript/tests/scripts/parser/features/multiline_if.gd b/modules/gdscript/tests/scripts/parser/features/multiline_if.gd new file mode 100644 index 0000000000..86152f4543 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/multiline_if.gd @@ -0,0 +1,14 @@ +func test(): + # Line breaks are allowed within parentheses. + if ( + 1 == 1 + and 2 == 2 and + 3 == 3 + ): + pass + + # Alternatively, backslashes can be used. + if 1 == 1 \ + and 2 == 2 and \ + 3 == 3: + pass diff --git a/modules/gdscript/tests/scripts/parser/features/multiline_if.out b/modules/gdscript/tests/scripts/parser/features/multiline_if.out new file mode 100644 index 0000000000..d73c5eb7cd --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/multiline_if.out @@ -0,0 +1 @@ +GDTEST_OK diff --git a/modules/gdscript/tests/scripts/parser/features/multiline_strings.gd b/modules/gdscript/tests/scripts/parser/features/multiline_strings.gd new file mode 100644 index 0000000000..7f5bba85e7 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/multiline_strings.gd @@ -0,0 +1,15 @@ +func test(): + var __ = """ + This is a standalone string, not a multiline comment. + Writing both "double" quotes and 'simple' quotes is fine as + long as there is only ""one"" or ''two'' of those in a row, not more. + + If you have more quotes, they need to be escaped like this: \"\"\" + """ + __ = ''' + Another standalone string, this time with single quotes. + Writing both "double" quotes and 'simple' quotes is fine as + long as there is only ""one"" or ''two'' of those in a row, not more. + + If you have more quotes, they need to be escaped like this: \'\'\' + ''' diff --git a/modules/gdscript/tests/scripts/parser/features/multiline_strings.out b/modules/gdscript/tests/scripts/parser/features/multiline_strings.out new file mode 100644 index 0000000000..d73c5eb7cd --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/multiline_strings.out @@ -0,0 +1 @@ +GDTEST_OK diff --git a/modules/gdscript/tests/scripts/parser/features/multiline_vector.gd b/modules/gdscript/tests/scripts/parser/features/multiline_vector.gd new file mode 100644 index 0000000000..11a40fc00e --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/multiline_vector.gd @@ -0,0 +1,17 @@ +func test(): + Vector2( + 1, + 2 + ) + + Vector3( + 3, + 3.5, + 4, # Trailing comma should work. + ) + + Vector2i(1, 2,) # Trailing comma should work. + + Vector3i(6, + 9, + 12) diff --git a/modules/gdscript/tests/scripts/parser/features/multiline_vector.out b/modules/gdscript/tests/scripts/parser/features/multiline_vector.out new file mode 100644 index 0000000000..d73c5eb7cd --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/multiline_vector.out @@ -0,0 +1 @@ +GDTEST_OK diff --git a/modules/gdscript/tests/scripts/parser/features/nested_arithmetic.gd b/modules/gdscript/tests/scripts/parser/features/nested_arithmetic.gd new file mode 100644 index 0000000000..b9bd19c9c5 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/nested_arithmetic.gd @@ -0,0 +1,22 @@ +func test(): + print(+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++2.718) + + print() + + print(------------------------------------------------------------------2.718) + print(-------------------------------------------------------------------2.718) + + print() + + print(~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~999) + + print() + + print(+-+-+-----+------------+++++++---++--++--+--+---+--++2.718) + + print() + + print(2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 / 2 / 2 / 2 / 2 / 2 / 2 / 2 / 2 / 2 / 2 / 2 / 2 / 2 / 2 / 2 / 2 / 2 / 0.444) + print(153023902390239 % 550 % 29 % 27 % 23 % 17) + print(2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 >> 2 >> 2 >> 2 >> 2 >> 2 >> 2 >> 2 >> 2 >> 2 >> 2 >> 2 >> 2 >> 2 >> 2 >> 2 >> 2 >> 2 >> 2) + print(8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8 ^ -8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8) diff --git a/modules/gdscript/tests/scripts/parser/features/nested_arithmetic.out b/modules/gdscript/tests/scripts/parser/features/nested_arithmetic.out new file mode 100644 index 0000000000..048cfbdfae --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/nested_arithmetic.out @@ -0,0 +1,82 @@ +GDTEST_OK +>> WARNING +>> Line: 19 +>> INTEGER_DIVISION +>> Integer division, decimal part will be discarded. +>> WARNING +>> Line: 19 +>> INTEGER_DIVISION +>> Integer division, decimal part will be discarded. +>> WARNING +>> Line: 19 +>> INTEGER_DIVISION +>> Integer division, decimal part will be discarded. +>> WARNING +>> Line: 19 +>> INTEGER_DIVISION +>> Integer division, decimal part will be discarded. +>> WARNING +>> Line: 19 +>> INTEGER_DIVISION +>> Integer division, decimal part will be discarded. +>> WARNING +>> Line: 19 +>> INTEGER_DIVISION +>> Integer division, decimal part will be discarded. +>> WARNING +>> Line: 19 +>> INTEGER_DIVISION +>> Integer division, decimal part will be discarded. +>> WARNING +>> Line: 19 +>> INTEGER_DIVISION +>> Integer division, decimal part will be discarded. +>> WARNING +>> Line: 19 +>> INTEGER_DIVISION +>> Integer division, decimal part will be discarded. +>> WARNING +>> Line: 19 +>> INTEGER_DIVISION +>> Integer division, decimal part will be discarded. +>> WARNING +>> Line: 19 +>> INTEGER_DIVISION +>> Integer division, decimal part will be discarded. +>> WARNING +>> Line: 19 +>> INTEGER_DIVISION +>> Integer division, decimal part will be discarded. +>> WARNING +>> Line: 19 +>> INTEGER_DIVISION +>> Integer division, decimal part will be discarded. +>> WARNING +>> Line: 19 +>> INTEGER_DIVISION +>> Integer division, decimal part will be discarded. +>> WARNING +>> Line: 19 +>> INTEGER_DIVISION +>> Integer division, decimal part will be discarded. +>> WARNING +>> Line: 19 +>> INTEGER_DIVISION +>> Integer division, decimal part will be discarded. +>> WARNING +>> Line: 19 +>> INTEGER_DIVISION +>> Integer division, decimal part will be discarded. +2.718 + +2.718 +-2.718 + +-1000 + +-2.718 + +36900.9009009009 +2 +8192 +-8 diff --git a/modules/gdscript/tests/scripts/parser/features/nested_array.gd b/modules/gdscript/tests/scripts/parser/features/nested_array.gd new file mode 100644 index 0000000000..3caef96391 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/nested_array.gd @@ -0,0 +1,5 @@ +func test(): + var array = [[[[[[[[[[15]]]]]]]]]] + print(array[0][0][0][0][0][0][0][0]) + print(array[0][0][0][0][0][0][0][0][0]) + print(array[0][0][0][0][0][0][0][0][0][0]) diff --git a/modules/gdscript/tests/scripts/parser/features/nested_array.out b/modules/gdscript/tests/scripts/parser/features/nested_array.out new file mode 100644 index 0000000000..46c6ce3874 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/nested_array.out @@ -0,0 +1,4 @@ +GDTEST_OK +[[15]] +[15] +15 diff --git a/modules/gdscript/tests/scripts/parser/features/nested_dictionary.gd b/modules/gdscript/tests/scripts/parser/features/nested_dictionary.gd new file mode 100644 index 0000000000..d67e142156 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/nested_dictionary.gd @@ -0,0 +1,6 @@ +func test(): + var dictionary = {1: {2: {3: {4: {5: {6: {7: {8: {"key": "value"}}}}}}}}} + print(dictionary[1][2][3][4][5][6][7]) + print(dictionary[1][2][3][4][5][6][7][8]) + print(dictionary[1][2][3][4][5][6][7][8].key) + print(dictionary[1][2][3][4][5][6][7][8]["key"]) diff --git a/modules/gdscript/tests/scripts/parser/features/nested_dictionary.out b/modules/gdscript/tests/scripts/parser/features/nested_dictionary.out new file mode 100644 index 0000000000..4009160439 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/nested_dictionary.out @@ -0,0 +1,5 @@ +GDTEST_OK +{8:{key:value}} +{key:value} +value +value diff --git a/modules/gdscript/tests/scripts/parser/features/nested_if.gd b/modules/gdscript/tests/scripts/parser/features/nested_if.gd new file mode 100644 index 0000000000..7282d08497 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/nested_if.gd @@ -0,0 +1,57 @@ +func test(): + # 20 levels of nesting (and then some). + if true: + print("1") + if true: + print("2") + if true: + print("3") + if true: + print("4") + if true: + print("5") + if true: + print("6") + if true: + print("7") + if true: + print("8") + if true: + print("9") + if true: + print("10") + if true: + print("11") + if true: + print("12") + if true: + print("13") + if true: + print("14") + if true: + print("15") + if true: + print("16") + if true: + print("17") + if true: + print("18") + if true: + print("19") + if true: + print("20") + if false: + print("End") + if true: + if true: + if true: + if true: + if true: + if true: + if true: + if true: + if true: + if true: + if true: + if true: + print("This won't be printed") diff --git a/modules/gdscript/tests/scripts/parser/features/nested_if.out b/modules/gdscript/tests/scripts/parser/features/nested_if.out new file mode 100644 index 0000000000..c2d2e29a06 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/nested_if.out @@ -0,0 +1,21 @@ +GDTEST_OK +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 diff --git a/modules/gdscript/tests/scripts/parser/features/nested_match.gd b/modules/gdscript/tests/scripts/parser/features/nested_match.gd new file mode 100644 index 0000000000..aaddcc7e83 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/nested_match.gd @@ -0,0 +1,79 @@ +func test(): + # 20 levels of nesting (and then some). + var number = 1234 + match number: + 1234: + print("1") + match number: + 1234: + print("2") + match number: + 1234: + print("3") + continue + _: + print("Should also be printed") + match number: + 1234: + print("4") + match number: + _: + print("5") + match number: + false: + print("Should not be printed") + true: + print("Should not be printed") + "hello": + print("Should not be printed") + 1234: + print("6") + match number: + _: + print("7") + match number: + 1234: + print("8") + match number: + _: + print("9") + match number: + 1234: + print("10") + match number: + _: + print("11") + match number: + 1234: + print("12") + match number: + _: + print("13") + match number: + 1234: + print("14") + match number: + _: + print("15") + match number: + _: + print("16") + match number: + 1234: + print("17") + match number: + _: + print("18") + match number: + 1234: + print("19") + match number: + _: + print("20") + match number: + []: + print("Should not be printed") + _: + print("Should not be printed") + 5678: + print("Should not be printed either") diff --git a/modules/gdscript/tests/scripts/parser/features/nested_match.out b/modules/gdscript/tests/scripts/parser/features/nested_match.out new file mode 100644 index 0000000000..651d76cc59 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/nested_match.out @@ -0,0 +1,22 @@ +GDTEST_OK +1 +2 +3 +Should also be printed +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 diff --git a/modules/gdscript/tests/scripts/parser/features/nested_parentheses.gd b/modules/gdscript/tests/scripts/parser/features/nested_parentheses.gd new file mode 100644 index 0000000000..3fef73b9be --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/nested_parentheses.gd @@ -0,0 +1,65 @@ +func test(): + (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((print("Hello world!")))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) + + print(((((((((((((((((((((((((((((((((((((((((((((((((((((((((("Hello world 2!")))))))))))))))))))))))))))))))))))))))))))))))))))))))))) + + print( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + (2)) + ((4)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) diff --git a/modules/gdscript/tests/scripts/parser/features/nested_parentheses.out b/modules/gdscript/tests/scripts/parser/features/nested_parentheses.out new file mode 100644 index 0000000000..27221a56bb --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/nested_parentheses.out @@ -0,0 +1,4 @@ +GDTEST_OK +Hello world! +Hello world 2! +6 diff --git a/modules/gdscript/tests/scripts/parser/features/number_separators.gd b/modules/gdscript/tests/scripts/parser/features/number_separators.gd new file mode 100644 index 0000000000..f5f5661cae --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/number_separators.gd @@ -0,0 +1,12 @@ +func test(): + # `_` can be used as a separator for numbers in GDScript. + # It can be placed anywhere in the number, except at the beginning. + # Currently, GDScript in the `master` branch only allows using one separator + # per number. + # Results are assigned to variables to avoid warnings. + var __ = 1_23 + __ = 123_ # Trailing number separators are OK. + __ = 12_3 + __ = 123_456 + __ = 0x1234_5678 + __ = 0b1001_0101 diff --git a/modules/gdscript/tests/scripts/parser/features/number_separators.out b/modules/gdscript/tests/scripts/parser/features/number_separators.out new file mode 100644 index 0000000000..d73c5eb7cd --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/number_separators.out @@ -0,0 +1 @@ +GDTEST_OK diff --git a/modules/gdscript/tests/scripts/parser/features/operator_assign.gd b/modules/gdscript/tests/scripts/parser/features/operator_assign.gd new file mode 100644 index 0000000000..b5f07675ca --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/operator_assign.gd @@ -0,0 +1,8 @@ +func test(): + var i = 0 + i += 5 + i -= 4 + i *= 10 + i %= 8 + i /= 0.25 + print(round(i)) diff --git a/modules/gdscript/tests/scripts/parser/features/operator_assign.out b/modules/gdscript/tests/scripts/parser/features/operator_assign.out new file mode 100644 index 0000000000..b0cb63ef59 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/operator_assign.out @@ -0,0 +1,2 @@ +GDTEST_OK +8 diff --git a/modules/gdscript/tests/scripts/parser/features/property_setter_getter.gd b/modules/gdscript/tests/scripts/parser/features/property_setter_getter.gd new file mode 100644 index 0000000000..9e4b360fb2 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/property_setter_getter.gd @@ -0,0 +1,37 @@ +# 4.0+ replacement for `setget`: +var _backing: int = 0 +var property: + get: + return _backing + 1000 + set(value): + _backing = value - 1000 + + +func test(): + print("Not using self:") + print(property) + print(_backing) + property = 5000 + print(property) + print(_backing) + _backing = -50 + print(property) + print(_backing) + property = 5000 + print(property) + print(_backing) + + # In Godot 4.0 and later, using `self` no longer makes a difference for + # getter/setter execution in GDScript. + print("Using self:") + print(self.property) + print(self._backing) + self.property = 5000 + print(self.property) + print(self._backing) + self._backing = -50 + print(self.property) + print(self._backing) + self.property = 5000 + print(self.property) + print(self._backing) diff --git a/modules/gdscript/tests/scripts/parser/features/property_setter_getter.out b/modules/gdscript/tests/scripts/parser/features/property_setter_getter.out new file mode 100644 index 0000000000..560e0c3bd7 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/property_setter_getter.out @@ -0,0 +1,19 @@ +GDTEST_OK +Not using self: +1000 +0 +5000 +4000 +950 +-50 +5000 +4000 +Using self: +5000 +4000 +5000 +4000 +950 +-50 +5000 +4000 diff --git a/modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.gd b/modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.gd index 08f2eedb2d..d50776c25c 100644 --- a/modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.gd +++ b/modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.gd @@ -1,2 +1,5 @@ func test(): - print("A"); print("B") + print("A"); print("B") + + # Multiple semicolons and whitespace between them is also valid. + print("A"); ;;;;; ; print("B");; diff --git a/modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.out b/modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.out index fc03f3efe8..bd7f38f516 100644 --- a/modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.out +++ b/modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.out @@ -1,3 +1,5 @@ GDTEST_OK A B +A +B diff --git a/modules/gdscript/tests/scripts/parser/features/space_indentation.gd b/modules/gdscript/tests/scripts/parser/features/space_indentation.gd new file mode 100644 index 0000000000..0a4887c199 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/space_indentation.gd @@ -0,0 +1,4 @@ +func test(): + # 2-space indentation should work, even though the GDScript style guide recommends tabs. + if true: + pass diff --git a/modules/gdscript/tests/scripts/parser/features/space_indentation.out b/modules/gdscript/tests/scripts/parser/features/space_indentation.out new file mode 100644 index 0000000000..d73c5eb7cd --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/space_indentation.out @@ -0,0 +1 @@ +GDTEST_OK diff --git a/modules/gdscript/tests/scripts/parser/features/static_typing.gd b/modules/gdscript/tests/scripts/parser/features/static_typing.gd new file mode 100644 index 0000000000..d42632c82d --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/static_typing.gd @@ -0,0 +1,13 @@ +func test(): + # The following lines are equivalent: + var _integer: int = 1 + var _integer2 : int = 1 + var _inferred := 1 + var _inferred2 : = 1 + + # Type inference is automatic for constants. + const _INTEGER = 1 + const _INTEGER_REDUNDANT_TYPED : int = 1 + const _INTEGER_REDUNDANT_TYPED2 : int = 1 + const _INTEGER_REDUNDANT_INFERRED := 1 + const _INTEGER_REDUNDANT_INFERRED2 : = 1 diff --git a/modules/gdscript/tests/scripts/parser/features/static_typing.out b/modules/gdscript/tests/scripts/parser/features/static_typing.out new file mode 100644 index 0000000000..92ce7bc0e0 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/static_typing.out @@ -0,0 +1,21 @@ +GDTEST_OK +>> WARNING +>> Line: 9 +>> UNUSED_LOCAL_CONSTANT +>> The local constant '_INTEGER' is declared but never used in the block. If this is intended, prefix it with an underscore: '__INTEGER' +>> WARNING +>> Line: 10 +>> UNUSED_LOCAL_CONSTANT +>> The local constant '_INTEGER_REDUNDANT_TYPED' is declared but never used in the block. If this is intended, prefix it with an underscore: '__INTEGER_REDUNDANT_TYPED' +>> WARNING +>> Line: 11 +>> UNUSED_LOCAL_CONSTANT +>> The local constant '_INTEGER_REDUNDANT_TYPED2' is declared but never used in the block. If this is intended, prefix it with an underscore: '__INTEGER_REDUNDANT_TYPED2' +>> WARNING +>> Line: 12 +>> UNUSED_LOCAL_CONSTANT +>> The local constant '_INTEGER_REDUNDANT_INFERRED' is declared but never used in the block. If this is intended, prefix it with an underscore: '__INTEGER_REDUNDANT_INFERRED' +>> WARNING +>> Line: 13 +>> UNUSED_LOCAL_CONSTANT +>> The local constant '_INTEGER_REDUNDANT_INFERRED2' is declared but never used in the block. If this is intended, prefix it with an underscore: '__INTEGER_REDUNDANT_INFERRED2' diff --git a/modules/gdscript/tests/scripts/parser/features/string_formatting.gd b/modules/gdscript/tests/scripts/parser/features/string_formatting.gd new file mode 100644 index 0000000000..a91837145d --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/string_formatting.gd @@ -0,0 +1,18 @@ +func test(): + print("hello %s" % "world" == "hello world") + print("hello %s" % true == "hello true") + print("hello %s" % false == "hello false") + + print("hello %d" % 25 == "hello 25") + print("hello %d %d" % [25, 42] == "hello 25 42") + # Pad with spaces. + print("hello %3d" % 25 == "hello 25") + # Pad with zeroes. + print("hello %03d" % 25 == "hello 025") + + print("hello %.02f" % 0.123456 == "hello 0.12") + + # Dynamic padding: + # <https://docs.godotengine.org/en/stable/getting_started/scripting/gdscript/gdscript_format_string.html#dynamic-padding> + print("hello %*.*f" % [7, 3, 0.123456] == "hello 0.123") + print("hello %0*.*f" % [7, 3, 0.123456] == "hello 000.123") diff --git a/modules/gdscript/tests/scripts/parser/features/string_formatting.out b/modules/gdscript/tests/scripts/parser/features/string_formatting.out new file mode 100644 index 0000000000..7533f6ff54 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/string_formatting.out @@ -0,0 +1,11 @@ +GDTEST_OK +true +true +true +true +true +true +true +true +true +true diff --git a/modules/gdscript/tests/scripts/parser/features/super.gd b/modules/gdscript/tests/scripts/parser/features/super.gd new file mode 100644 index 0000000000..f5ae2a74a7 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/super.gd @@ -0,0 +1,60 @@ +class Say: + var prefix = "S" + + func greet(): + prefix = "S Greeted" + print("hello") + + func say(name): + print(prefix, " say something ", name) + + +class SayAnotherThing extends Say: + # This currently crashes the engine. + #var prefix = "SAT" + + func greet(): + prefix = "SAT Greeted" + print("hi") + + func say(name): + print(prefix, " say another thing ", name) + + +class SayNothing extends Say: + # This currently crashes the engine. + #var prefix = "SN" + + func greet(): + super() + prefix = "SN Greeted" + print("howdy, see above") + + func greet_prefix_before_super(): + prefix = "SN Greeted" + super.greet() + print("howdy, see above") + + func say(name): + super(name + " super'd") + print(prefix, " say nothing... or not? ", name) + + +func test(): + var say = Say.new() + say.greet() + say.say("foo") + print() + + var say_another_thing = SayAnotherThing.new() + say_another_thing.greet() + say_another_thing.say("bar") + print() + + var say_nothing = SayNothing.new() + say_nothing.greet() + print(say_nothing.prefix) + say_nothing.greet_prefix_before_super() + print(say_nothing.prefix) + # This currently triggers a compiler bug: "compiler bug, function name not found" + #say_nothing.say("baz") diff --git a/modules/gdscript/tests/scripts/parser/features/super.out b/modules/gdscript/tests/scripts/parser/features/super.out new file mode 100644 index 0000000000..e0d4f4f098 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/super.out @@ -0,0 +1,13 @@ +GDTEST_OK +hello +S Greeted say something foo + +hi +SAT Greeted say another thing bar + +hello +howdy, see above +SN Greeted +hello +howdy, see above +S Greeted diff --git a/modules/gdscript/tests/scripts/parser/features/truthiness.gd b/modules/gdscript/tests/scripts/parser/features/truthiness.gd new file mode 100644 index 0000000000..9c67a152f5 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/truthiness.gd @@ -0,0 +1,30 @@ +func test(): + # The assertions below should all evaluate to `true` for this test to pass. + assert(true) + assert(not false) + assert(500) + assert(not 0) + assert(500.5) + assert(not 0.0) + assert("non-empty string") + assert(["non-empty array"]) + assert({"non-empty": "dictionary"}) + assert(Vector2(1, 0)) + assert(Vector2i(-1, -1)) + assert(Vector3(0, 0, 0.0001)) + assert(Vector3i(0, 0, 10000)) + + # Zero position is `true` only if the Rect2's size is non-zero. + assert(Rect2(0, 0, 0, 1)) + + # Zero size is `true` only if the position is non-zero. + assert(Rect2(1, 1, 0, 0)) + + # Zero position is `true` only if the Rect2's size is non-zero. + assert(Rect2i(0, 0, 0, 1)) + + # Zero size is `true` only if the position is non-zero. + assert(Rect2i(1, 1, 0, 0)) + + # A fully black color is only truthy if its alpha component is not equal to `1`. + assert(Color(0, 0, 0, 0.5)) diff --git a/modules/gdscript/tests/scripts/parser/features/truthiness.out b/modules/gdscript/tests/scripts/parser/features/truthiness.out new file mode 100644 index 0000000000..705524857b --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/truthiness.out @@ -0,0 +1,65 @@ +GDTEST_OK +>> WARNING +>> Line: 3 +>> ASSERT_ALWAYS_TRUE +>> Assert statement is redundant because the expression is always true. +>> WARNING +>> Line: 4 +>> ASSERT_ALWAYS_TRUE +>> Assert statement is redundant because the expression is always true. +>> WARNING +>> Line: 5 +>> ASSERT_ALWAYS_TRUE +>> Assert statement is redundant because the expression is always true. +>> WARNING +>> Line: 6 +>> ASSERT_ALWAYS_TRUE +>> Assert statement is redundant because the expression is always true. +>> WARNING +>> Line: 7 +>> ASSERT_ALWAYS_TRUE +>> Assert statement is redundant because the expression is always true. +>> WARNING +>> Line: 8 +>> ASSERT_ALWAYS_TRUE +>> Assert statement is redundant because the expression is always true. +>> WARNING +>> Line: 9 +>> ASSERT_ALWAYS_TRUE +>> Assert statement is redundant because the expression is always true. +>> WARNING +>> Line: 12 +>> ASSERT_ALWAYS_TRUE +>> Assert statement is redundant because the expression is always true. +>> WARNING +>> Line: 13 +>> ASSERT_ALWAYS_TRUE +>> Assert statement is redundant because the expression is always true. +>> WARNING +>> Line: 14 +>> ASSERT_ALWAYS_TRUE +>> Assert statement is redundant because the expression is always true. +>> WARNING +>> Line: 15 +>> ASSERT_ALWAYS_TRUE +>> Assert statement is redundant because the expression is always true. +>> WARNING +>> Line: 18 +>> ASSERT_ALWAYS_TRUE +>> Assert statement is redundant because the expression is always true. +>> WARNING +>> Line: 21 +>> ASSERT_ALWAYS_TRUE +>> Assert statement is redundant because the expression is always true. +>> WARNING +>> Line: 24 +>> ASSERT_ALWAYS_TRUE +>> Assert statement is redundant because the expression is always true. +>> WARNING +>> Line: 27 +>> ASSERT_ALWAYS_TRUE +>> Assert statement is redundant because the expression is always true. +>> WARNING +>> Line: 30 +>> ASSERT_ALWAYS_TRUE +>> Assert statement is redundant because the expression is always true. diff --git a/modules/gdscript/tests/scripts/parser/features/variable_declaration.gd b/modules/gdscript/tests/scripts/parser/features/variable_declaration.gd index 38567d35c6..65013c4301 100644 --- a/modules/gdscript/tests/scripts/parser/features/variable_declaration.gd +++ b/modules/gdscript/tests/scripts/parser/features/variable_declaration.gd @@ -3,6 +3,7 @@ var m2 = 22 # Init. var m3: String # No init, typed. var m4: String = "44" # Init, typed. + func test(): var loc5 # No init, local. var loc6 = 66 # Init, local. diff --git a/modules/gdscript/tests/scripts/parser/features/while.gd b/modules/gdscript/tests/scripts/parser/features/while.gd new file mode 100644 index 0000000000..17dd4fbad2 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/while.gd @@ -0,0 +1,5 @@ +func test(): + var i = 0 + while i < 5: + print(i) + i += 1 diff --git a/modules/gdscript/tests/scripts/parser/features/while.out b/modules/gdscript/tests/scripts/parser/features/while.out new file mode 100644 index 0000000000..b4a50885c7 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/while.out @@ -0,0 +1,6 @@ +GDTEST_OK +0 +1 +2 +3 +4 diff --git a/modules/gdscript/tests/scripts/parser/warnings/assert_always_true.gd b/modules/gdscript/tests/scripts/parser/warnings/assert_always_true.gd new file mode 100644 index 0000000000..8feaed899f --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/assert_always_true.gd @@ -0,0 +1,5 @@ +func test(): + # These statements always evaluate to `true`, and therefore emit a warning. + assert(true) + assert(-1.234) + assert(2 + 3 == 5) diff --git a/modules/gdscript/tests/scripts/parser/warnings/assert_always_true.out b/modules/gdscript/tests/scripts/parser/warnings/assert_always_true.out new file mode 100644 index 0000000000..5132792cb7 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/assert_always_true.out @@ -0,0 +1,13 @@ +GDTEST_OK +>> WARNING +>> Line: 3 +>> ASSERT_ALWAYS_TRUE +>> Assert statement is redundant because the expression is always true. +>> WARNING +>> Line: 4 +>> ASSERT_ALWAYS_TRUE +>> Assert statement is redundant because the expression is always true. +>> WARNING +>> Line: 5 +>> ASSERT_ALWAYS_TRUE +>> Assert statement is redundant because the expression is always true. diff --git a/modules/gdscript/tests/scripts/parser/warnings/deprecated_operators.gd b/modules/gdscript/tests/scripts/parser/warnings/deprecated_operators.gd new file mode 100644 index 0000000000..f72b10213f --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/deprecated_operators.gd @@ -0,0 +1,8 @@ +func test(): + # `and` should be used instead. + if true && true: + pass + + # `or` should be used instead. + if false || true: + pass diff --git a/modules/gdscript/tests/scripts/parser/warnings/deprecated_operators.out b/modules/gdscript/tests/scripts/parser/warnings/deprecated_operators.out new file mode 100644 index 0000000000..d73c5eb7cd --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/deprecated_operators.out @@ -0,0 +1 @@ +GDTEST_OK diff --git a/modules/gdscript/tests/scripts/parser/warnings/incompatible_ternary.gd b/modules/gdscript/tests/scripts/parser/warnings/incompatible_ternary.gd new file mode 100644 index 0000000000..a93ecb66b1 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/incompatible_ternary.gd @@ -0,0 +1,8 @@ +func test(): + # The ternary operator below returns values of different types and the + # result is assigned to a typed variable. This will cause a run-time error + # if the branch with the incompatible type is picked. Here, it won't happen + # since the `false` condition never evaluates to `true`. Instead, a warning + # will be emitted. + var __: int = 25 + __ = "hello" if false else -2 diff --git a/modules/gdscript/tests/scripts/parser/warnings/incompatible_ternary.out b/modules/gdscript/tests/scripts/parser/warnings/incompatible_ternary.out new file mode 100644 index 0000000000..7d1558c6fc --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/incompatible_ternary.out @@ -0,0 +1,5 @@ +GDTEST_OK +>> WARNING +>> Line: 8 +>> INCOMPATIBLE_TERNARY +>> Values of the ternary conditional are not mutually compatible. diff --git a/modules/gdscript/tests/scripts/parser/warnings/integer_division.gd b/modules/gdscript/tests/scripts/parser/warnings/integer_division.gd new file mode 100644 index 0000000000..6117425528 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/integer_division.gd @@ -0,0 +1,10 @@ +func test(): + # This should emit a warning. + var __ = 5 / 2 + + # These should not emit warnings. + __ = float(5) / 2 + __ = 5 / float(2) + __ = 5.0 / 2 + __ = 5 / 2.0 + __ = 5.0 / 2.0 diff --git a/modules/gdscript/tests/scripts/parser/warnings/integer_division.out b/modules/gdscript/tests/scripts/parser/warnings/integer_division.out new file mode 100644 index 0000000000..40eb63ffcb --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/integer_division.out @@ -0,0 +1,5 @@ +GDTEST_OK +>> WARNING +>> Line: 3 +>> INTEGER_DIVISION +>> Integer division, decimal part will be discarded. diff --git a/modules/gdscript/tests/scripts/parser/warnings/match_default_not_at_end.gd b/modules/gdscript/tests/scripts/parser/warnings/match_default_not_at_end.gd new file mode 100644 index 0000000000..1eb54059dd --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/match_default_not_at_end.gd @@ -0,0 +1,9 @@ +func test(): + var i = 25 + # The default branch (`_`) should be at the end of the `match` statement. + # Otherwise, a warning will be emitted + match i: + _: + print("default") + 25: + print("is 25") diff --git a/modules/gdscript/tests/scripts/parser/warnings/match_default_not_at_end.out b/modules/gdscript/tests/scripts/parser/warnings/match_default_not_at_end.out new file mode 100644 index 0000000000..8630fab420 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/match_default_not_at_end.out @@ -0,0 +1,6 @@ +GDTEST_OK +>> WARNING +>> Line: 8 +>> UNREACHABLE_PATTERN +>> Unreachable pattern (pattern after wildcard or bind). +default diff --git a/modules/gdscript/tests/scripts/parser/warnings/narrowing_conversion.gd b/modules/gdscript/tests/scripts/parser/warnings/narrowing_conversion.gd new file mode 100644 index 0000000000..954e697145 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/narrowing_conversion.gd @@ -0,0 +1,5 @@ +func i_accept_ints_only(_i: int): + pass + +func test(): + i_accept_ints_only(12.345) diff --git a/modules/gdscript/tests/scripts/parser/warnings/narrowing_conversion.out b/modules/gdscript/tests/scripts/parser/warnings/narrowing_conversion.out new file mode 100644 index 0000000000..6fb592117b --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/narrowing_conversion.out @@ -0,0 +1,5 @@ +GDTEST_OK +>> WARNING +>> Line: 5 +>> NARROWING_CONVERSION +>> Narrowing conversion (float is converted to int and loses precision). diff --git a/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.gd b/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.gd new file mode 100644 index 0000000000..00598e4d50 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.gd @@ -0,0 +1,6 @@ +func i_return_int() -> int: + return 4 + + +func test(): + i_return_int() diff --git a/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.out b/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.out new file mode 100644 index 0000000000..d73c5eb7cd --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.out @@ -0,0 +1 @@ +GDTEST_OK diff --git a/modules/gdscript/tests/scripts/parser/warnings/shadowed_constant.gd b/modules/gdscript/tests/scripts/parser/warnings/shadowed_constant.gd new file mode 100644 index 0000000000..d565d38365 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/shadowed_constant.gd @@ -0,0 +1,8 @@ +# See also `parser-errors/redefine-class-constant.gd`. +const TEST = 25 + + +func test(): + # Warning here. This is not an error because a new constant is created, + # rather than attempting to set the value of an existing constant. + const TEST = 50 diff --git a/modules/gdscript/tests/scripts/parser/warnings/shadowed_constant.out b/modules/gdscript/tests/scripts/parser/warnings/shadowed_constant.out new file mode 100644 index 0000000000..9c9417e11d --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/shadowed_constant.out @@ -0,0 +1,9 @@ +GDTEST_OK +>> WARNING +>> Line: 8 +>> UNUSED_LOCAL_CONSTANT +>> The local constant 'TEST' is declared but never used in the block. If this is intended, prefix it with an underscore: '_TEST' +>> WARNING +>> Line: 8 +>> SHADOWED_VARIABLE +>> The local constant "TEST" is shadowing an already-declared constant at line 2. diff --git a/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_class.gd b/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_class.gd new file mode 100644 index 0000000000..66dcf309e8 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_class.gd @@ -0,0 +1,8 @@ +var foo = 123 + + +func test(): + # Notice the `var` keyword. Without this keyword, no warning would be emitted + # because no new variable would be created. Instead, the class variable's value + # would be overwritten. + var foo = 456 diff --git a/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_class.out b/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_class.out new file mode 100644 index 0000000000..82e467b368 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_class.out @@ -0,0 +1,9 @@ +GDTEST_OK +>> WARNING +>> Line: 8 +>> UNUSED_VARIABLE +>> The local variable 'foo' is declared but never used in the block. If this is intended, prefix it with an underscore: '_foo' +>> WARNING +>> Line: 8 +>> SHADOWED_VARIABLE +>> The local variable "foo" is shadowing an already-declared variable at line 1. diff --git a/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_function.gd b/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_function.gd new file mode 100644 index 0000000000..2c55d68be8 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_function.gd @@ -0,0 +1,2 @@ +func test(): + var test = "This variable has the same name as the test() function." diff --git a/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_function.out b/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_function.out new file mode 100644 index 0000000000..26ce0465b1 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_function.out @@ -0,0 +1,9 @@ +GDTEST_OK +>> WARNING +>> Line: 2 +>> UNUSED_VARIABLE +>> The local variable 'test' is declared but never used in the block. If this is intended, prefix it with an underscore: '_test' +>> WARNING +>> Line: 2 +>> SHADOWED_VARIABLE +>> The local variable "test" is shadowing an already-declared function at line 1. diff --git a/modules/gdscript/tests/scripts/parser/warnings/standalone_expression.gd b/modules/gdscript/tests/scripts/parser/warnings/standalone_expression.gd new file mode 100644 index 0000000000..18ea260fa2 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/standalone_expression.gd @@ -0,0 +1,9 @@ +func test(): + # The following statements should all be reported as standalone expressions: + "This is a standalone expression" + 1234 + 0.0 + 0.0 + Color(1, 1, 1) + Vector3.ZERO + [true, false] + float(125) diff --git a/modules/gdscript/tests/scripts/parser/warnings/standalone_expression.out b/modules/gdscript/tests/scripts/parser/warnings/standalone_expression.out new file mode 100644 index 0000000000..99ec87438e --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/standalone_expression.out @@ -0,0 +1,21 @@ +GDTEST_OK +>> WARNING +>> Line: 3 +>> STANDALONE_EXPRESSION +>> Standalone expression (the line has no effect). +>> WARNING +>> Line: 4 +>> STANDALONE_EXPRESSION +>> Standalone expression (the line has no effect). +>> WARNING +>> Line: 5 +>> STANDALONE_EXPRESSION +>> Standalone expression (the line has no effect). +>> WARNING +>> Line: 7 +>> STANDALONE_EXPRESSION +>> Standalone expression (the line has no effect). +>> WARNING +>> Line: 8 +>> STANDALONE_EXPRESSION +>> Standalone expression (the line has no effect). diff --git a/modules/gdscript/tests/scripts/parser/warnings/unassigned_variable.gd b/modules/gdscript/tests/scripts/parser/warnings/unassigned_variable.gd new file mode 100644 index 0000000000..afb5059eea --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/unassigned_variable.gd @@ -0,0 +1,2 @@ +func test(): + var __ diff --git a/modules/gdscript/tests/scripts/parser/warnings/unassigned_variable.out b/modules/gdscript/tests/scripts/parser/warnings/unassigned_variable.out new file mode 100644 index 0000000000..cf14502e9a --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/unassigned_variable.out @@ -0,0 +1,5 @@ +GDTEST_OK +>> WARNING +>> Line: 2 +>> UNASSIGNED_VARIABLE +>> The variable '__' was used but never assigned a value. diff --git a/modules/gdscript/tests/scripts/parser/warnings/unassigned_variable_op_assign.gd b/modules/gdscript/tests/scripts/parser/warnings/unassigned_variable_op_assign.gd new file mode 100644 index 0000000000..d77791f4c5 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/unassigned_variable_op_assign.gd @@ -0,0 +1,4 @@ +func test(): + var __: int + # Variable has no set value at this point (even though it's implicitly `0` here). + __ += 15 diff --git a/modules/gdscript/tests/scripts/parser/warnings/unassigned_variable_op_assign.out b/modules/gdscript/tests/scripts/parser/warnings/unassigned_variable_op_assign.out new file mode 100644 index 0000000000..ba55a4e0f8 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/unassigned_variable_op_assign.out @@ -0,0 +1,5 @@ +GDTEST_OK +>> WARNING +>> Line: 4 +>> UNASSIGNED_VARIABLE_OP_ASSIGN +>> Using assignment with operation but the variable '__' was not previously assigned a value. diff --git a/modules/gdscript/tests/scripts/parser/warnings/unreachable_code_after_return.gd b/modules/gdscript/tests/scripts/parser/warnings/unreachable_code_after_return.gd new file mode 100644 index 0000000000..3311f342ab --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/unreachable_code_after_return.gd @@ -0,0 +1,7 @@ +func test(): + var i = 25 + + return + + # This will never be run due to the `return` statement above. + print(i) diff --git a/modules/gdscript/tests/scripts/parser/warnings/unreachable_code_after_return.out b/modules/gdscript/tests/scripts/parser/warnings/unreachable_code_after_return.out new file mode 100644 index 0000000000..9316abd5eb --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/unreachable_code_after_return.out @@ -0,0 +1,5 @@ +GDTEST_OK +>> WARNING +>> Line: 7 +>> UNREACHABLE_CODE +>> Unreachable code (statement after return) in function 'test()'. diff --git a/modules/gdscript/tests/scripts/parser/warnings/unused_argument.gd b/modules/gdscript/tests/scripts/parser/warnings/unused_argument.gd new file mode 100644 index 0000000000..e6e24dc6f2 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/unused_argument.gd @@ -0,0 +1,12 @@ +# This should emit a warning since the unused argument is not prefixed with an underscore. +func function_with_unused_argument(p_arg1, p_arg2): + print(p_arg1) + + +# This shouldn't emit a warning since the unused argument is prefixed with an underscore. +func function_with_ignored_unused_argument(p_arg1, _p_arg2): + print(p_arg1) + + +func test(): + pass diff --git a/modules/gdscript/tests/scripts/parser/warnings/unused_argument.out b/modules/gdscript/tests/scripts/parser/warnings/unused_argument.out new file mode 100644 index 0000000000..92f3308f85 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/unused_argument.out @@ -0,0 +1,5 @@ +GDTEST_OK +>> WARNING +>> Line: 2 +>> UNUSED_PARAMETER +>> The parameter 'p_arg2' is never used in the function 'function_with_unused_argument'. If this is intended, prefix it with an underscore: '_p_arg2' diff --git a/modules/gdscript/tests/scripts/parser/warnings/unused_variable.gd b/modules/gdscript/tests/scripts/parser/warnings/unused_variable.gd index 68e3bd424f..013a2e4beb 100644 --- a/modules/gdscript/tests/scripts/parser/warnings/unused_variable.gd +++ b/modules/gdscript/tests/scripts/parser/warnings/unused_variable.gd @@ -1,2 +1,4 @@ func test(): - var unused = "not used" + var unused = "not used" + + var _unused = "not used, but no warning since the variable name starts with an underscore" diff --git a/modules/gdscript/tests/scripts/parser/warnings/void_assignment.gd b/modules/gdscript/tests/scripts/parser/warnings/void_assignment.gd new file mode 100644 index 0000000000..b4a42b3e3d --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/void_assignment.gd @@ -0,0 +1,6 @@ +func i_return_void() -> void: + return + + +func test(): + var __ = i_return_void() diff --git a/modules/gdscript/tests/scripts/parser/warnings/void_assignment.out b/modules/gdscript/tests/scripts/parser/warnings/void_assignment.out new file mode 100644 index 0000000000..84c9598f9a --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/void_assignment.out @@ -0,0 +1,5 @@ +GDTEST_OK +>> WARNING +>> Line: 6 +>> VOID_ASSIGNMENT +>> Assignment operation, but the function 'i_return_void()' returns void. diff --git a/modules/navigation/navigation_mesh_generator.cpp b/modules/navigation/navigation_mesh_generator.cpp index 905d10c9d4..bb6bc578a4 100644 --- a/modules/navigation/navigation_mesh_generator.cpp +++ b/modules/navigation/navigation_mesh_generator.cpp @@ -45,7 +45,7 @@ #include "scene/resources/primitive_meshes.h" #include "scene/resources/shape_3d.h" #include "scene/resources/sphere_shape_3d.h" -#include "scene/resources/world_margin_shape_3d.h" +#include "scene/resources/world_boundary_shape_3d.h" #ifdef TOOLS_ENABLED #include "editor/editor_node.h" diff --git a/modules/text_server_adv/script_iterator.cpp b/modules/text_server_adv/script_iterator.cpp index f9bbd25a5f..d1e849def8 100644 --- a/modules/text_server_adv/script_iterator.cpp +++ b/modules/text_server_adv/script_iterator.cpp @@ -30,6 +30,8 @@ #include "script_iterator.h" +// This implementation is derived from ICU: icu4c/source/extra/scrptrun/scrptrun.cpp + bool ScriptIterator::same_script(int32_t p_script_one, int32_t p_script_two) { return p_script_one <= USCRIPT_INHERITED || p_script_two <= USCRIPT_INHERITED || p_script_one == p_script_two; } @@ -48,7 +50,8 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length p_start = 0; } - ParenStackEntry paren_stack[128]; + int paren_size = PAREN_STACK_DEPTH; + ParenStackEntry *paren_stack = (ParenStackEntry *)memalloc(paren_size * sizeof(ParenStackEntry)); int script_start; int script_end = p_start; @@ -64,13 +67,22 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length UChar32 ch = str[script_end]; UScriptCode sc = uscript_getScript(ch, &err); if (U_FAILURE(err)) { + memfree(paren_stack); ERR_FAIL_MSG(u_errorName(err)); } if (u_getIntPropertyValue(ch, UCHAR_BIDI_PAIRED_BRACKET_TYPE) != U_BPT_NONE) { if (u_getIntPropertyValue(ch, UCHAR_BIDI_PAIRED_BRACKET_TYPE) == U_BPT_OPEN) { - paren_stack[++paren_sp].pair_index = ch; + // If it's an open character, push it onto the stack. + paren_sp++; + if (unlikely(paren_sp >= paren_size)) { + // If the stack is full, allocate more space to handle deeply nested parentheses. This is unlikely to happen with any real text. + paren_size += PAREN_STACK_DEPTH; + paren_stack = (ParenStackEntry *)memrealloc(paren_stack, paren_size * sizeof(ParenStackEntry)); + } + paren_stack[paren_sp].pair_index = ch; paren_stack[paren_sp].script_code = script_code; } else if (paren_sp >= 0) { + // If it's a close character, find the matching open on the stack, and use that script code. Any non-matching open characters above it on the stack will be poped. UChar32 paired_ch = u_getBidiPairedBracket(ch); while (paren_sp >= 0 && paren_stack[paren_sp].pair_index != paired_ch) { paren_sp -= 1; @@ -87,11 +99,13 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length if (same_script(script_code, sc)) { if (script_code <= USCRIPT_INHERITED && sc > USCRIPT_INHERITED) { script_code = sc; + // Now that we have a final script code, fix any open characters we pushed before we knew the script code. while (start_sp < paren_sp) { paren_stack[++start_sp].script_code = script_code; } } if ((u_getIntPropertyValue(ch, UCHAR_BIDI_PAIRED_BRACKET_TYPE) == U_BPT_CLOSE) && paren_sp >= 0) { + // If this character is a close paired character pop the matching open character from the stack. paren_sp -= 1; if (start_sp >= 0) { start_sp -= 1; @@ -109,4 +123,6 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length script_ranges.push_back(rng); } while (script_end < p_length); + + memfree(paren_stack); } diff --git a/modules/text_server_adv/script_iterator.h b/modules/text_server_adv/script_iterator.h index 896a0e5c15..5efd40f7c4 100644 --- a/modules/text_server_adv/script_iterator.h +++ b/modules/text_server_adv/script_iterator.h @@ -43,6 +43,8 @@ #include <hb.h> class ScriptIterator { + static const int PAREN_STACK_DEPTH = 128; + public: struct ScriptRange { int start = 0; diff --git a/modules/visual_script/register_types.cpp b/modules/visual_script/register_types.cpp index 7fb9707fce..890861cf82 100644 --- a/modules/visual_script/register_types.cpp +++ b/modules/visual_script/register_types.cpp @@ -117,7 +117,7 @@ void register_visual_script_types() { GDREGISTER_CLASS(VisualScriptCustomNodes); ClassDB::set_current_api(ClassDB::API_CORE); vs_custom_nodes_singleton = memnew(VisualScriptCustomNodes); - Engine::get_singleton()->add_singleton(Engine::Singleton("VisualScriptEditor", VisualScriptCustomNodes::get_singleton())); + Engine::get_singleton()->add_singleton(Engine::Singleton("VisualScriptCustomNodes", VisualScriptCustomNodes::get_singleton())); VisualScriptEditor::register_editor(); #endif diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index e5422a28af..60ba1c558a 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -221,6 +221,9 @@ static const LauncherIcon launcher_adaptive_icon_backgrounds[icon_densities_coun static const int EXPORT_FORMAT_APK = 0; static const int EXPORT_FORMAT_AAB = 1; +static const char *APK_ASSETS_DIRECTORY = "res://android/build/assets"; +static const char *AAB_ASSETS_DIRECTORY = "res://android/build/assetPacks/installTime/src/main/assets"; + void EditorExportPlatformAndroid::_check_for_changes_poll_thread(void *ud) { EditorExportPlatformAndroid *ea = (EditorExportPlatformAndroid *)ud; @@ -426,6 +429,11 @@ String EditorExportPlatformAndroid::get_package_name(const String &p_package) co return pname; } +String EditorExportPlatformAndroid::get_assets_directory(const Ref<EditorExportPreset> &p_preset) const { + int export_format = int(p_preset->get("custom_template/export_format")); + return export_format == EXPORT_FORMAT_AAB ? AAB_ASSETS_DIRECTORY : APK_ASSETS_DIRECTORY; +} + bool EditorExportPlatformAndroid::is_package_name_valid(const String &p_package, String *r_error) const { String pname = p_package; @@ -2335,11 +2343,21 @@ Error EditorExportPlatformAndroid::sign_apk(const Ref<EditorExportPreset> &p_pre void EditorExportPlatformAndroid::_clear_assets_directory() { DirAccessRef da_res = DirAccess::create(DirAccess::ACCESS_RESOURCES); - if (da_res->dir_exists("res://android/build/assets")) { - print_verbose("Clearing assets directory.."); - DirAccessRef da_assets = DirAccess::open("res://android/build/assets"); + + // Clear the APK assets directory + if (da_res->dir_exists(APK_ASSETS_DIRECTORY)) { + print_verbose("Clearing APK assets directory.."); + DirAccessRef da_assets = DirAccess::open(APK_ASSETS_DIRECTORY); + da_assets->erase_contents_recursive(); + da_res->remove(APK_ASSETS_DIRECTORY); + } + + // Clear the AAB assets directory + if (da_res->dir_exists(AAB_ASSETS_DIRECTORY)) { + print_verbose("Clearing AAB assets directory.."); + DirAccessRef da_assets = DirAccess::open(AAB_ASSETS_DIRECTORY); da_assets->erase_contents_recursive(); - da_res->remove("res://android/build/assets"); + da_res->remove(AAB_ASSETS_DIRECTORY); } } @@ -2459,6 +2477,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP return ERR_UNCONFIGURED; } } + const String assets_directory = get_assets_directory(p_preset); String sdk_path = EDITOR_GET("export/android/android_sdk_path"); ERR_FAIL_COND_V_MSG(sdk_path.is_empty(), ERR_UNCONFIGURED, "Android SDK path must be configured in Editor Settings at 'export/android/android_sdk_path'."); print_verbose("Android sdk path: " + sdk_path); @@ -2480,6 +2499,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP if (!apk_expansion) { print_verbose("Exporting project files.."); CustomExportData user_data; + user_data.assets_directory = assets_directory; user_data.debug = p_debug; err = export_project_files(p_preset, rename_and_store_file_in_gradle_project, &user_data, copy_gradle_so); if (err != OK) { @@ -2501,7 +2521,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP } } print_verbose("Storing command line flags.."); - store_file_at_path("res://android/build/assets/_cl_", command_line_flags); + store_file_at_path(assets_directory + "/_cl_", command_line_flags); print_verbose("Updating ANDROID_HOME environment to " + sdk_path); OS::get_singleton()->set_environment("ANDROID_HOME", sdk_path); //set and overwrite if required diff --git a/platform/android/export/export_plugin.h b/platform/android/export/export_plugin.h index b061ee4e04..d33f616f11 100644 --- a/platform/android/export/export_plugin.h +++ b/platform/android/export/export_plugin.h @@ -87,11 +87,6 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { EditorProgress *ep = nullptr; }; - struct CustomExportData { - bool debug; - Vector<String> libs; - }; - Vector<PluginConfigAndroid> plugins; String last_plugin_names; uint64_t last_custom_build_time = 0; @@ -109,6 +104,8 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { String get_package_name(const String &p_package) const; + String get_assets_directory(const Ref<EditorExportPreset> &p_preset) const; + bool is_package_name_valid(const String &p_package, String *r_error = nullptr) const; static bool _should_compress_asset(const String &p_path, const Vector<uint8_t> &p_data); diff --git a/platform/android/export/gradle_export_util.cpp b/platform/android/export/gradle_export_util.cpp index 6fbdf73cd0..851bd0ac52 100644 --- a/platform/android/export/gradle_export_util.cpp +++ b/platform/android/export/gradle_export_util.cpp @@ -121,7 +121,8 @@ Error store_string_at_path(const String &p_path, const String &p_data) { // It's functionality mirrors that of the method save_apk_file. // This method will be called ONLY when custom build is enabled. Error rename_and_store_file_in_gradle_project(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) { - String dst_path = p_path.replace_first("res://", "res://android/build/assets/"); + CustomExportData *export_data = (CustomExportData *)p_userdata; + String dst_path = p_path.replace_first("res://", export_data->assets_directory + "/"); print_verbose("Saving project files from " + p_path + " into " + dst_path); Error err = store_file_at_path(dst_path, p_data); return err; diff --git a/platform/android/export/gradle_export_util.h b/platform/android/export/gradle_export_util.h index 8a93c25d79..744022f1f9 100644 --- a/platform/android/export/gradle_export_util.h +++ b/platform/android/export/gradle_export_util.h @@ -44,6 +44,12 @@ const String godot_project_name_xml_string = R"(<?xml version="1.0" encoding="ut </resources> )"; +struct CustomExportData { + String assets_directory; + bool debug; + Vector<String> libs; +}; + int _get_android_orientation_value(DisplayServer::ScreenOrientation screen_orientation); String _get_android_orientation_label(DisplayServer::ScreenOrientation screen_orientation); diff --git a/platform/android/java/app/assetPacks/installTime/build.gradle b/platform/android/java/app/assetPacks/installTime/build.gradle new file mode 100644 index 0000000000..b06faac374 --- /dev/null +++ b/platform/android/java/app/assetPacks/installTime/build.gradle @@ -0,0 +1,8 @@ +apply plugin: 'com.android.asset-pack' + +assetPack { + packName = "installTime" // Directory name for the asset pack + dynamicDelivery { + deliveryType = "install-time" // Delivery mode + } +} diff --git a/platform/android/java/app/build.gradle b/platform/android/java/app/build.gradle index 9640887399..a391a3ca9a 100644 --- a/platform/android/java/app/build.gradle +++ b/platform/android/java/app/build.gradle @@ -72,6 +72,8 @@ android { targetCompatibility versions.javaVersion } + assetPacks = [":assetPacks:installTime"] + defaultConfig { // The default ignore pattern for the 'assets' directory includes hidden files and directories which are used by Godot projects. aaptOptions { diff --git a/platform/android/java/app/settings.gradle b/platform/android/java/app/settings.gradle index 33b863c7bf..e38d7b2ba6 100644 --- a/platform/android/java/app/settings.gradle +++ b/platform/android/java/app/settings.gradle @@ -1,2 +1,2 @@ -// Empty settings.gradle file to denote this directory as being the root project -// of the Godot custom build. +// This is the root directory of the Godot custom build. +include ':assetPacks:installTime' diff --git a/platform/android/java/settings.gradle b/platform/android/java/settings.gradle index 524031d93f..584b626900 100644 --- a/platform/android/java/settings.gradle +++ b/platform/android/java/settings.gradle @@ -4,3 +4,6 @@ rootProject.name = "Godot" include ':app' include ':lib' include ':nativeSrcsConfigs' + +include ':assetPacks:installTime' +project(':assetPacks:installTime').projectDir = file("app/assetPacks/installTime") diff --git a/platform/javascript/audio_driver_javascript.cpp b/platform/javascript/audio_driver_javascript.cpp index 478e848675..420cb2f2f7 100644 --- a/platform/javascript/audio_driver_javascript.cpp +++ b/platform/javascript/audio_driver_javascript.cpp @@ -108,7 +108,7 @@ Error AudioDriverJavaScript::init() { mix_rate = GLOBAL_GET("audio/driver/mix_rate"); int latency = GLOBAL_GET("audio/driver/output_latency"); - channel_count = godot_audio_init(mix_rate, latency, &_state_change_callback, &_latency_update_callback); + channel_count = godot_audio_init(&mix_rate, latency, &_state_change_callback, &_latency_update_callback); buffer_length = closest_power_of_2((latency * mix_rate / 1000)); #ifndef NO_THREADS node = memnew(WorkletNode); diff --git a/platform/javascript/display_server_javascript.cpp b/platform/javascript/display_server_javascript.cpp index b43614eb99..be4d2cba20 100644 --- a/platform/javascript/display_server_javascript.cpp +++ b/platform/javascript/display_server_javascript.cpp @@ -497,9 +497,10 @@ EM_BOOL DisplayServerJavaScript::wheel_callback(int p_event_type, const Emscript ev->set_button_mask(MouseButton(input->get_mouse_button_mask() | button_flag)); input->parse_input_event(ev); - ev->set_pressed(false); - ev->set_button_mask(MouseButton(input->get_mouse_button_mask() & ~button_flag)); - input->parse_input_event(ev); + Ref<InputEventMouseButton> release = ev->duplicate(); + release->set_pressed(false); + release->set_button_mask(MouseButton(input->get_mouse_button_mask() & ~button_flag)); + input->parse_input_event(release); return true; } @@ -508,7 +509,6 @@ EM_BOOL DisplayServerJavaScript::wheel_callback(int p_event_type, const Emscript EM_BOOL DisplayServerJavaScript::touch_press_callback(int p_event_type, const EmscriptenTouchEvent *p_event, void *p_user_data) { DisplayServerJavaScript *display = get_singleton(); Ref<InputEventScreenTouch> ev; - ev.instantiate(); int lowest_id_index = -1; for (int i = 0; i < p_event->numTouches; ++i) { const EmscriptenTouchPoint &touch = p_event->touches[i]; @@ -516,6 +516,7 @@ EM_BOOL DisplayServerJavaScript::touch_press_callback(int p_event_type, const Em lowest_id_index = i; if (!touch.isChanged) continue; + ev.instantiate(); ev->set_index(touch.identifier); ev->set_position(compute_position_in_canvas(touch.clientX, touch.clientY)); display->touches[i] = ev->get_position(); @@ -534,7 +535,6 @@ EM_BOOL DisplayServerJavaScript::touch_press_callback(int p_event_type, const Em EM_BOOL DisplayServerJavaScript::touchmove_callback(int p_event_type, const EmscriptenTouchEvent *p_event, void *p_user_data) { DisplayServerJavaScript *display = get_singleton(); Ref<InputEventScreenDrag> ev; - ev.instantiate(); int lowest_id_index = -1; for (int i = 0; i < p_event->numTouches; ++i) { const EmscriptenTouchPoint &touch = p_event->touches[i]; @@ -542,6 +542,7 @@ EM_BOOL DisplayServerJavaScript::touchmove_callback(int p_event_type, const Emsc lowest_id_index = i; if (!touch.isChanged) continue; + ev.instantiate(); ev->set_index(touch.identifier); ev->set_position(compute_position_in_canvas(touch.clientX, touch.clientY)); Point2 &prev = display->touches[i]; diff --git a/platform/javascript/godot_audio.h b/platform/javascript/godot_audio.h index 54fc8fa3b5..de8f046bbd 100644 --- a/platform/javascript/godot_audio.h +++ b/platform/javascript/godot_audio.h @@ -38,7 +38,7 @@ extern "C" { #include "stddef.h" extern int godot_audio_is_available(); -extern int godot_audio_init(int p_mix_rate, int p_latency, void (*_state_cb)(int), void (*_latency_cb)(float)); +extern int godot_audio_init(int *p_mix_rate, int p_latency, void (*_state_cb)(int), void (*_latency_cb)(float)); extern void godot_audio_resume(); extern int godot_audio_capture_start(); diff --git a/platform/javascript/js/libs/library_godot_audio.js b/platform/javascript/js/libs/library_godot_audio.js index 45c3a3fe2e..c9dae1a7af 100644 --- a/platform/javascript/js/libs/library_godot_audio.js +++ b/platform/javascript/js/libs/library_godot_audio.js @@ -37,10 +37,14 @@ const GodotAudio = { interval: 0, init: function (mix_rate, latency, onstatechange, onlatencyupdate) { - const ctx = new (window.AudioContext || window.webkitAudioContext)({ - sampleRate: mix_rate, - // latencyHint: latency / 1000 // Do not specify, leave 'interactive' for good performance. - }); + const opts = {}; + // If mix_rate is 0, let the browser choose. + if (mix_rate) { + opts['sampleRate'] = mix_rate; + } + // Do not specify, leave 'interactive' for good performance. + // opts['latencyHint'] = latency / 1000; + const ctx = new (window.AudioContext || window.webkitAudioContext)(opts); GodotAudio.ctx = ctx; ctx.onstatechange = function () { let state = 0; @@ -159,7 +163,10 @@ const GodotAudio = { godot_audio_init: function (p_mix_rate, p_latency, p_state_change, p_latency_update) { const statechange = GodotRuntime.get_func(p_state_change); const latencyupdate = GodotRuntime.get_func(p_latency_update); - return GodotAudio.init(p_mix_rate, p_latency, statechange, latencyupdate); + const mix_rate = GodotRuntime.getHeapValue(p_mix_rate, 'i32'); + const channels = GodotAudio.init(mix_rate, p_latency, statechange, latencyupdate); + GodotRuntime.setHeapValue(p_mix_rate, GodotAudio.ctx.sampleRate, 'i32'); + return channels; }, godot_audio_resume__sig: 'v', diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp index a39941339a..5c6824cf44 100644 --- a/platform/linuxbsd/display_server_x11.cpp +++ b/platform/linuxbsd/display_server_x11.cpp @@ -3614,7 +3614,8 @@ DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, W DisplayServer *ds = memnew(DisplayServerX11(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error)); if (r_error != OK) { OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan versions.\n" - "Please update your drivers or if you have a very old or integrated GPU upgrade it.", + "Please update your drivers or if you have a very old or integrated GPU, upgrade it.\n" + "If you have updated your graphics drivers recently, try rebooting.", "Unable to initialize Video driver"); } return ds; diff --git a/scene/2d/parallax_layer.cpp b/scene/2d/parallax_layer.cpp index 1fe6a4a4b8..67e35cc7a3 100644 --- a/scene/2d/parallax_layer.cpp +++ b/scene/2d/parallax_layer.cpp @@ -100,6 +100,10 @@ void ParallaxLayer::_notification(int p_what) { _update_mirroring(); } break; case NOTIFICATION_EXIT_TREE: { + if (Engine::get_singleton()->is_editor_hint()) { + break; + } + set_position(orig_offset); set_scale(orig_scale); } break; diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp index 3018fd3ae6..2847031375 100644 --- a/scene/animation/tween.cpp +++ b/scene/animation/tween.cpp @@ -60,6 +60,11 @@ Ref<PropertyTweener> Tween::tween_property(Object *p_target, NodePath p_property ERR_FAIL_COND_V_MSG(!valid, nullptr, "Tween invalid. Either finished or created outside scene tree."); ERR_FAIL_COND_V_MSG(started, nullptr, "Can't append to a Tween that has started. Use stop() first."); +#ifdef DEBUG_ENABLED + Variant::Type property_type = p_target->get_indexed(p_property.get_as_property_path().get_subnames()).get_type(); + ERR_FAIL_COND_V_MSG(property_type != p_to.get_type(), Ref<PropertyTweener>(), "Type mismatch between property and final value: " + Variant::get_type_name(property_type) + " and " + Variant::get_type_name(p_to.get_type())); +#endif + Ref<PropertyTweener> tweener = memnew(PropertyTweener(p_target, p_property, p_to, p_duration)); append(tweener); return tweener; @@ -83,7 +88,7 @@ Ref<CallbackTweener> Tween::tween_callback(Callable p_callback) { return tweener; } -Ref<MethodTweener> Tween::tween_method(Callable p_callback, float p_from, float p_to, float p_duration) { +Ref<MethodTweener> Tween::tween_method(Callable p_callback, Variant p_from, Variant p_to, float p_duration) { ERR_FAIL_COND_V_MSG(!valid, nullptr, "Tween invalid. Either finished or created outside scene tree."); ERR_FAIL_COND_V_MSG(started, nullptr, "Can't append to a Tween that has started. Use stop() first."); @@ -496,6 +501,8 @@ Variant Tween::interpolate_variant(Variant p_initial_val, Variant p_delta_val, f } Variant Tween::calculate_delta_value(Variant p_intial_val, Variant p_final_val) { + ERR_FAIL_COND_V_MSG(p_intial_val.get_type() != p_final_val.get_type(), p_intial_val, "Type mismatch between initial and final value: " + Variant::get_type_name(p_intial_val.get_type()) + " and " + Variant::get_type_name(p_final_val.get_type())); + switch (p_intial_val.get_type()) { case Variant::BOOL: { return (int)p_final_val - (int)p_intial_val; @@ -888,7 +895,7 @@ void MethodTweener::_bind_methods() { ClassDB::bind_method(D_METHOD("set_ease", "ease"), &MethodTweener::set_ease); } -MethodTweener::MethodTweener(Callable p_callback, float p_from, float p_to, float p_duration) { +MethodTweener::MethodTweener(Callable p_callback, Variant p_from, Variant p_to, float p_duration) { callback = p_callback; initial_val = p_from; delta_val = tween->calculate_delta_value(p_from, p_to); diff --git a/scene/animation/tween.h b/scene/animation/tween.h index 953d573539..6a48d332b8 100644 --- a/scene/animation/tween.h +++ b/scene/animation/tween.h @@ -128,7 +128,7 @@ public: Ref<PropertyTweener> tween_property(Object *p_target, NodePath p_property, Variant p_to, float p_duration); Ref<IntervalTweener> tween_interval(float p_time); Ref<CallbackTweener> tween_callback(Callable p_callback); - Ref<MethodTweener> tween_method(Callable p_callback, float p_from, float p_to, float p_duration); + Ref<MethodTweener> tween_method(Callable p_callback, Variant p_from, Variant p_to, float p_duration); void append(Ref<Tweener> p_tweener); bool custom_step(float p_delta); @@ -258,7 +258,7 @@ public: void start() override; bool step(float &r_delta) override; - MethodTweener(Callable p_callback, float p_from, float p_to, float p_duration); + MethodTweener(Callable p_callback, Variant p_from, Variant p_to, float p_duration); MethodTweener(); protected: diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index cabae9feb2..b9b02b1427 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -356,16 +356,6 @@ void GraphEdit::_graph_node_raised(Node *p_gn) { } else { gn->raise(); } - int first_not_comment = 0; - for (int i = 0; i < get_child_count(); i++) { - GraphNode *gn2 = Object::cast_to<GraphNode>(get_child(i)); - if (gn2 && !gn2->is_comment()) { - first_not_comment = i; - break; - } - } - - move_child(connections_layer, first_not_comment); emit_signal(SNAME("node_selected"), p_gn); } diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index c4dfbc0d4e..f62c09925d 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -156,6 +156,7 @@ void TreeItem::set_cell_mode(int p_column, TreeCellMode p_mode) { c.dirty = true; c.icon_max_w = 0; _changed_notify(p_column); + cached_minimum_size_dirty = true; } TreeItem::TreeCellMode TreeItem::get_cell_mode(int p_column) const { @@ -169,6 +170,7 @@ void TreeItem::set_checked(int p_column, bool p_checked) { cells.write[p_column].checked = p_checked; cells.write[p_column].indeterminate = false; _changed_notify(p_column); + cached_minimum_size_dirty = true; } void TreeItem::set_indeterminate(int p_column, bool p_indeterminate) { @@ -180,6 +182,7 @@ void TreeItem::set_indeterminate(int p_column, bool p_indeterminate) { cells.write[p_column].indeterminate = p_indeterminate; cells.write[p_column].checked = false; _changed_notify(p_column); + cached_minimum_size_dirty = true; } bool TreeItem::is_checked(int p_column) const { @@ -212,6 +215,7 @@ void TreeItem::set_text(int p_column, String p_text) { cells.write[p_column].step = 0; } _changed_notify(p_column); + cached_minimum_size_dirty = true; } String TreeItem::get_text(int p_column) const { @@ -227,6 +231,7 @@ void TreeItem::set_text_direction(int p_column, Control::TextDirection p_text_di cells.write[p_column].dirty = true; _changed_notify(p_column); } + cached_minimum_size_dirty = true; } Control::TextDirection TreeItem::get_text_direction(int p_column) const { @@ -239,6 +244,7 @@ void TreeItem::clear_opentype_features(int p_column) { cells.write[p_column].opentype_features.clear(); cells.write[p_column].dirty = true; _changed_notify(p_column); + cached_minimum_size_dirty = true; } void TreeItem::set_opentype_feature(int p_column, const String &p_name, int p_value) { @@ -248,6 +254,7 @@ void TreeItem::set_opentype_feature(int p_column, const String &p_name, int p_va cells.write[p_column].opentype_features[tag] = p_value; cells.write[p_column].dirty = true; _changed_notify(p_column); + cached_minimum_size_dirty = true; } } @@ -266,6 +273,7 @@ void TreeItem::set_structured_text_bidi_override(int p_column, Control::Structur cells.write[p_column].st_parser = p_parser; cells.write[p_column].dirty = true; _changed_notify(p_column); + cached_minimum_size_dirty = true; } } @@ -279,6 +287,7 @@ void TreeItem::set_structured_text_bidi_override_options(int p_column, Array p_a cells.write[p_column].st_args = p_args; cells.write[p_column].dirty = true; _changed_notify(p_column); + cached_minimum_size_dirty = true; } Array TreeItem::get_structured_text_bidi_override_options(int p_column) const { @@ -292,6 +301,7 @@ void TreeItem::set_language(int p_column, const String &p_language) { cells.write[p_column].language = p_language; cells.write[p_column].dirty = true; _changed_notify(p_column); + cached_minimum_size_dirty = true; } } @@ -305,6 +315,7 @@ void TreeItem::set_suffix(int p_column, String p_suffix) { cells.write[p_column].suffix = p_suffix; _changed_notify(p_column); + cached_minimum_size_dirty = true; } String TreeItem::get_suffix(int p_column) const { @@ -316,6 +327,7 @@ void TreeItem::set_icon(int p_column, const Ref<Texture2D> &p_icon) { ERR_FAIL_INDEX(p_column, cells.size()); cells.write[p_column].icon = p_icon; _changed_notify(p_column); + cached_minimum_size_dirty = true; } Ref<Texture2D> TreeItem::get_icon(int p_column) const { @@ -327,6 +339,7 @@ void TreeItem::set_icon_region(int p_column, const Rect2 &p_icon_region) { ERR_FAIL_INDEX(p_column, cells.size()); cells.write[p_column].icon_region = p_icon_region; _changed_notify(p_column); + cached_minimum_size_dirty = true; } Rect2 TreeItem::get_icon_region(int p_column) const { @@ -349,6 +362,7 @@ void TreeItem::set_icon_max_width(int p_column, int p_max) { ERR_FAIL_INDEX(p_column, cells.size()); cells.write[p_column].icon_max_w = p_max; _changed_notify(p_column); + cached_minimum_size_dirty = true; } int TreeItem::get_icon_max_width(int p_column) const { @@ -461,6 +475,7 @@ void TreeItem::uncollapse_tree() { void TreeItem::set_custom_minimum_height(int p_height) { custom_min_height = p_height; _changed_notify(); + cached_minimum_size_dirty = true; } int TreeItem::get_custom_minimum_height() const { @@ -785,6 +800,7 @@ void TreeItem::add_button(int p_column, const Ref<Texture2D> &p_button, int p_id button.tooltip = p_tooltip; cells.write[p_column].buttons.push_back(button); _changed_notify(p_column); + cached_minimum_size_dirty = true; } int TreeItem::get_button_count(int p_column) const { @@ -828,6 +844,7 @@ void TreeItem::set_button(int p_column, int p_idx, const Ref<Texture2D> &p_butto ERR_FAIL_INDEX(p_idx, cells[p_column].buttons.size()); cells.write[p_column].buttons.write[p_idx].texture = p_button; _changed_notify(p_column); + cached_minimum_size_dirty = true; } void TreeItem::set_button_color(int p_column, int p_idx, const Color &p_color) { @@ -843,6 +860,7 @@ void TreeItem::set_button_disabled(int p_column, int p_idx, bool p_disabled) { cells.write[p_column].buttons.write[p_idx].disabled = p_disabled; _changed_notify(p_column); + cached_minimum_size_dirty = true; } bool TreeItem::is_button_disabled(int p_column, int p_idx) const { @@ -856,6 +874,7 @@ void TreeItem::set_editable(int p_column, bool p_editable) { ERR_FAIL_INDEX(p_column, cells.size()); cells.write[p_column].editable = p_editable; _changed_notify(p_column); + cached_minimum_size_dirty = true; } bool TreeItem::is_editable(int p_column) { @@ -888,6 +907,7 @@ void TreeItem::clear_custom_color(int p_column) { void TreeItem::set_custom_font(int p_column, const Ref<Font> &p_font) { ERR_FAIL_INDEX(p_column, cells.size()); cells.write[p_column].custom_font = p_font; + cached_minimum_size_dirty = true; } Ref<Font> TreeItem::get_custom_font(int p_column) const { @@ -898,6 +918,7 @@ Ref<Font> TreeItem::get_custom_font(int p_column) const { void TreeItem::set_custom_font_size(int p_column, int p_font_size) { ERR_FAIL_INDEX(p_column, cells.size()); cells.write[p_column].custom_font_size = p_font_size; + cached_minimum_size_dirty = true; } int TreeItem::get_custom_font_size(int p_column) const { @@ -941,6 +962,7 @@ Color TreeItem::get_custom_bg_color(int p_column) const { void TreeItem::set_custom_as_button(int p_column, bool p_button) { ERR_FAIL_INDEX(p_column, cells.size()); cells.write[p_column].custom_button = p_button; + cached_minimum_size_dirty = true; } bool TreeItem::is_custom_set_as_button(int p_column) const { @@ -952,6 +974,7 @@ void TreeItem::set_text_align(int p_column, TextAlign p_align) { ERR_FAIL_INDEX(p_column, cells.size()); cells.write[p_column].text_align = p_align; _changed_notify(p_column); + cached_minimum_size_dirty = true; } TreeItem::TextAlign TreeItem::get_text_align(int p_column) const { @@ -963,6 +986,7 @@ void TreeItem::set_expand_right(int p_column, bool p_enable) { ERR_FAIL_INDEX(p_column, cells.size()); cells.write[p_column].expand_right = p_enable; _changed_notify(p_column); + cached_minimum_size_dirty = true; } bool TreeItem::get_expand_right(int p_column) const { @@ -973,6 +997,7 @@ bool TreeItem::get_expand_right(int p_column) const { void TreeItem::set_disable_folding(bool p_disable) { disable_folding = p_disable; _changed_notify(0); + cached_minimum_size_dirty = true; } bool TreeItem::is_folding_disabled() const { @@ -984,49 +1009,54 @@ Size2 TreeItem::get_minimum_size(int p_column) { Tree *tree = get_tree(); ERR_FAIL_COND_V(!tree, Size2()); - Size2 size; + if (cached_minimum_size_dirty) { + Size2 size; - // Default offset? - //size.width += (disable_folding || tree->hide_folding) ? tree->cache.hseparation : tree->cache.item_margin; + // Default offset? + //size.width += (disable_folding || tree->hide_folding) ? tree->cache.hseparation : tree->cache.item_margin; - // Text. - const TreeItem::Cell &cell = cells[p_column]; - if (!cell.text.is_empty()) { - if (cell.dirty) { - tree->update_item_cell(this, p_column); + // Text. + const TreeItem::Cell &cell = cells[p_column]; + if (!cell.text.is_empty()) { + if (cell.dirty) { + tree->update_item_cell(this, p_column); + } + Size2 text_size = cell.text_buf->get_size(); + size.width += text_size.width; + size.height = MAX(size.height, text_size.height); } - Size2 text_size = cell.text_buf->get_size(); - size.width += text_size.width; - size.height = MAX(size.height, text_size.height); - } - // Icon. - if (cell.mode == CELL_MODE_CHECK) { - size.width += tree->cache.checked->get_width() + tree->cache.hseparation; - } - if (cell.icon.is_valid()) { - Size2i icon_size = cell.get_icon_size(); - if (cell.icon_max_w > 0 && icon_size.width > cell.icon_max_w) { - icon_size.width = cell.icon_max_w; + // Icon. + if (cell.mode == CELL_MODE_CHECK) { + size.width += tree->cache.checked->get_width() + tree->cache.hseparation; + } + if (cell.icon.is_valid()) { + Size2i icon_size = cell.get_icon_size(); + if (cell.icon_max_w > 0 && icon_size.width > cell.icon_max_w) { + icon_size.width = cell.icon_max_w; + } + size.width += icon_size.width + tree->cache.hseparation; + size.height = MAX(size.height, icon_size.height); } - size.width += icon_size.width + tree->cache.hseparation; - size.height = MAX(size.height, icon_size.height); - } - // Buttons. - for (int i = 0; i < cell.buttons.size(); i++) { - Ref<Texture2D> texture = cell.buttons[i].texture; - if (texture.is_valid()) { - Size2 button_size = texture->get_size() + tree->cache.button_pressed->get_minimum_size(); - size.width += button_size.width; - size.height = MAX(size.height, button_size.height); + // Buttons. + for (int i = 0; i < cell.buttons.size(); i++) { + Ref<Texture2D> texture = cell.buttons[i].texture; + if (texture.is_valid()) { + Size2 button_size = texture->get_size() + tree->cache.button_pressed->get_minimum_size(); + size.width += button_size.width; + size.height = MAX(size.height, button_size.height); + } } - } - if (cell.buttons.size() >= 2) { - size.width += (cell.buttons.size() - 1) * tree->cache.button_margin; + if (cell.buttons.size() >= 2) { + size.width += (cell.buttons.size() - 1) * tree->cache.button_margin; + } + + cached_minimum_size = size; + cached_minimum_size_dirty = false; } - return size; + return cached_minimum_size; } Variant TreeItem::_call_recursive_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { @@ -1307,6 +1337,10 @@ void Tree::update_cache() { cache.title_button_color = get_theme_color(SNAME("title_button_color")); v_scroll->set_custom_step(cache.font->get_height(cache.font_size)); + + for (TreeItem *item = get_root(); item; item = item->get_next()) { + item->cached_minimum_size_dirty = true; + } } int Tree::compute_item_height(TreeItem *p_item) const { diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 8b7ddc3faf..85fed941dc 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -130,6 +130,9 @@ private: bool disable_folding = false; int custom_min_height = 0; + Size2i cached_minimum_size; + bool cached_minimum_size_dirty = true; + TreeItem *parent = nullptr; // parent item TreeItem *prev = nullptr; // previous in list TreeItem *next = nullptr; // next in list diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 015a4d5dba..69f20ac990 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -197,8 +197,8 @@ #include "scene/resources/visual_shader_sdf_nodes.h" #include "scene/resources/world_2d.h" #include "scene/resources/world_3d.h" -#include "scene/resources/world_margin_shape_2d.h" -#include "scene/resources/world_margin_shape_3d.h" +#include "scene/resources/world_boundary_shape_2d.h" +#include "scene/resources/world_boundary_shape_3d.h" #include "scene/scene_string_names.h" #include "scene/main/shader_globals_override.h" @@ -750,7 +750,7 @@ void register_scene_types() { GDREGISTER_CLASS(CapsuleShape3D); GDREGISTER_CLASS(CylinderShape3D); GDREGISTER_CLASS(HeightMapShape3D); - GDREGISTER_CLASS(WorldMarginShape3D); + GDREGISTER_CLASS(WorldBoundaryShape3D); GDREGISTER_CLASS(ConvexPolygonShape3D); GDREGISTER_CLASS(ConcavePolygonShape3D); @@ -831,7 +831,7 @@ void register_scene_types() { OS::get_singleton()->yield(); //may take time to init GDREGISTER_VIRTUAL_CLASS(Shape2D); - GDREGISTER_CLASS(WorldMarginShape2D); + GDREGISTER_CLASS(WorldBoundaryShape2D); GDREGISTER_CLASS(SegmentShape2D); GDREGISTER_CLASS(SeparationRayShape2D); GDREGISTER_CLASS(CircleShape2D); @@ -919,7 +919,7 @@ void register_scene_types() { ClassDB::add_compatibility_class("KinematicBody2D", "CharacterBody2D"); ClassDB::add_compatibility_class("KinematicCollision", "KinematicCollision3D"); ClassDB::add_compatibility_class("Light", "Light3D"); - ClassDB::add_compatibility_class("LineShape2D", "WorldMarginShape2D"); + ClassDB::add_compatibility_class("LineShape2D", "WorldBoundaryShape2D"); ClassDB::add_compatibility_class("Listener", "Listener3D"); ClassDB::add_compatibility_class("MeshInstance", "MeshInstance3D"); ClassDB::add_compatibility_class("MultiMeshInstance", "MultiMeshInstance3D"); @@ -950,7 +950,7 @@ void register_scene_types() { ClassDB::add_compatibility_class("PhysicsServer", "PhysicsServer3D"); ClassDB::add_compatibility_class("PhysicsShapeQueryParameters", "PhysicsShapeQueryParameters3D"); ClassDB::add_compatibility_class("PinJoint", "PinJoint3D"); - ClassDB::add_compatibility_class("PlaneShape", "WorldMarginShape3D"); + ClassDB::add_compatibility_class("PlaneShape", "WorldBoundaryShape3D"); ClassDB::add_compatibility_class("ProceduralSky", "Sky"); ClassDB::add_compatibility_class("ProximityGroup", "ProximityGroup3D"); ClassDB::add_compatibility_class("RayCast", "RayCast3D"); diff --git a/scene/resources/world_margin_shape_2d.cpp b/scene/resources/world_boundary_shape_2d.cpp index 3b43681528..39af92793f 100644 --- a/scene/resources/world_margin_shape_2d.cpp +++ b/scene/resources/world_boundary_shape_2d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* world_margin_shape_2d.cpp */ +/* world_boundary_shape_2d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,13 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "world_margin_shape_2d.h" +#include "world_boundary_shape_2d.h" #include "core/math/geometry_2d.h" #include "servers/physics_server_2d.h" #include "servers/rendering_server.h" -bool WorldMarginShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { +bool WorldBoundaryShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { Vector2 point = get_distance() * get_normal(); Vector2 l[2][2] = { { point - get_normal().orthogonal() * 100, point + get_normal().orthogonal() * 100 }, { point, point + get_normal() * 30 } }; @@ -48,7 +48,7 @@ bool WorldMarginShape2D::_edit_is_selected_on_click(const Point2 &p_point, doubl return false; } -void WorldMarginShape2D::_update_shape() { +void WorldBoundaryShape2D::_update_shape() { Array arr; arr.push_back(normal); arr.push_back(distance); @@ -56,25 +56,25 @@ void WorldMarginShape2D::_update_shape() { emit_changed(); } -void WorldMarginShape2D::set_normal(const Vector2 &p_normal) { +void WorldBoundaryShape2D::set_normal(const Vector2 &p_normal) { normal = p_normal; _update_shape(); } -void WorldMarginShape2D::set_distance(real_t p_distance) { +void WorldBoundaryShape2D::set_distance(real_t p_distance) { distance = p_distance; _update_shape(); } -Vector2 WorldMarginShape2D::get_normal() const { +Vector2 WorldBoundaryShape2D::get_normal() const { return normal; } -real_t WorldMarginShape2D::get_distance() const { +real_t WorldBoundaryShape2D::get_distance() const { return distance; } -void WorldMarginShape2D::draw(const RID &p_to_rid, const Color &p_color) { +void WorldBoundaryShape2D::draw(const RID &p_to_rid, const Color &p_color) { Vector2 point = get_distance() * get_normal(); Vector2 l1[2] = { point - get_normal().orthogonal() * 100, point + get_normal().orthogonal() * 100 }; @@ -83,7 +83,7 @@ void WorldMarginShape2D::draw(const RID &p_to_rid, const Color &p_color) { RS::get_singleton()->canvas_item_add_line(p_to_rid, l2[0], l2[1], p_color, 3); } -Rect2 WorldMarginShape2D::get_rect() const { +Rect2 WorldBoundaryShape2D::get_rect() const { Vector2 point = get_distance() * get_normal(); Vector2 l1[2] = { point - get_normal().orthogonal() * 100, point + get_normal().orthogonal() * 100 }; @@ -96,22 +96,22 @@ Rect2 WorldMarginShape2D::get_rect() const { return rect; } -real_t WorldMarginShape2D::get_enclosing_radius() const { +real_t WorldBoundaryShape2D::get_enclosing_radius() const { return distance; } -void WorldMarginShape2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_normal", "normal"), &WorldMarginShape2D::set_normal); - ClassDB::bind_method(D_METHOD("get_normal"), &WorldMarginShape2D::get_normal); +void WorldBoundaryShape2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_normal", "normal"), &WorldBoundaryShape2D::set_normal); + ClassDB::bind_method(D_METHOD("get_normal"), &WorldBoundaryShape2D::get_normal); - ClassDB::bind_method(D_METHOD("set_distance", "distance"), &WorldMarginShape2D::set_distance); - ClassDB::bind_method(D_METHOD("get_distance"), &WorldMarginShape2D::get_distance); + ClassDB::bind_method(D_METHOD("set_distance", "distance"), &WorldBoundaryShape2D::set_distance); + ClassDB::bind_method(D_METHOD("get_distance"), &WorldBoundaryShape2D::get_distance); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "normal"), "set_normal", "get_normal"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance"), "set_distance", "get_distance"); } -WorldMarginShape2D::WorldMarginShape2D() : - Shape2D(PhysicsServer2D::get_singleton()->world_margin_shape_create()) { +WorldBoundaryShape2D::WorldBoundaryShape2D() : + Shape2D(PhysicsServer2D::get_singleton()->world_boundary_shape_create()) { _update_shape(); } diff --git a/scene/resources/world_margin_shape_2d.h b/scene/resources/world_boundary_shape_2d.h index 3c1d593ffe..4cc60f5985 100644 --- a/scene/resources/world_margin_shape_2d.h +++ b/scene/resources/world_boundary_shape_2d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* world_margin_shape_2d.h */ +/* world_boundary_shape_2d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,15 +28,15 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef WORLD_MARGIN_SHAPE_2D_H -#define WORLD_MARGIN_SHAPE_2D_H +#ifndef WORLD_BOUNDARY_SHAPE_2D_H +#define WORLD_BOUNDARY_SHAPE_2D_H #include "scene/resources/shape_2d.h" -class WorldMarginShape2D : public Shape2D { - GDCLASS(WorldMarginShape2D, Shape2D); +class WorldBoundaryShape2D : public Shape2D { + GDCLASS(WorldBoundaryShape2D, Shape2D); - // WorldMarginShape2D is often used for one-way platforms, where the normal pointing up makes sense. + // WorldBoundaryShape2D is often used for one-way platforms, where the normal pointing up makes sense. Vector2 normal = Vector2(0, -1); real_t distance = 0.0; @@ -58,7 +58,7 @@ public: virtual Rect2 get_rect() const override; virtual real_t get_enclosing_radius() const override; - WorldMarginShape2D(); + WorldBoundaryShape2D(); }; -#endif // WORLD_MARGIN_SHAPE_2D_H +#endif // WORLD_BOUNDARY_SHAPE_2D_H diff --git a/scene/resources/world_margin_shape_3d.cpp b/scene/resources/world_boundary_shape_3d.cpp index 28d50e1921..8cde537164 100644 --- a/scene/resources/world_margin_shape_3d.cpp +++ b/scene/resources/world_boundary_shape_3d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* world_margin_shape_3d.cpp */ +/* world_boundary_shape_3d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,11 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "world_margin_shape_3d.h" +#include "world_boundary_shape_3d.h" #include "servers/physics_server_3d.h" -Vector<Vector3> WorldMarginShape3D::get_debug_mesh_lines() const { +Vector<Vector3> WorldBoundaryShape3D::get_debug_mesh_lines() const { Plane p = get_plane(); Vector<Vector3> points; @@ -60,29 +60,29 @@ Vector<Vector3> WorldMarginShape3D::get_debug_mesh_lines() const { return points; } -void WorldMarginShape3D::_update_shape() { +void WorldBoundaryShape3D::_update_shape() { PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), plane); Shape3D::_update_shape(); } -void WorldMarginShape3D::set_plane(Plane p_plane) { +void WorldBoundaryShape3D::set_plane(const Plane &p_plane) { plane = p_plane; _update_shape(); notify_change_to_owners(); } -Plane WorldMarginShape3D::get_plane() const { +const Plane &WorldBoundaryShape3D::get_plane() const { return plane; } -void WorldMarginShape3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_plane", "plane"), &WorldMarginShape3D::set_plane); - ClassDB::bind_method(D_METHOD("get_plane"), &WorldMarginShape3D::get_plane); +void WorldBoundaryShape3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_plane", "plane"), &WorldBoundaryShape3D::set_plane); + ClassDB::bind_method(D_METHOD("get_plane"), &WorldBoundaryShape3D::get_plane); ADD_PROPERTY(PropertyInfo(Variant::PLANE, "plane"), "set_plane", "get_plane"); } -WorldMarginShape3D::WorldMarginShape3D() : - Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_PLANE)) { +WorldBoundaryShape3D::WorldBoundaryShape3D() : + Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_WORLD_BOUNDARY)) { set_plane(Plane(0, 1, 0, 0)); } diff --git a/scene/resources/world_margin_shape_3d.h b/scene/resources/world_boundary_shape_3d.h index 00417c4408..853f555ebc 100644 --- a/scene/resources/world_margin_shape_3d.h +++ b/scene/resources/world_boundary_shape_3d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* world_margin_shape_3d.h */ +/* world_boundary_shape_3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,13 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef WORLD_MARGIN_SHAPE_3D_H -#define WORLD_MARGIN_SHAPE_3D_H +#ifndef WORLD_BOUNDARY_SHAPE_3D_H +#define WORLD_BOUNDARY_SHAPE_3D_H #include "scene/resources/shape_3d.h" -class WorldMarginShape3D : public Shape3D { - GDCLASS(WorldMarginShape3D, Shape3D); +class WorldBoundaryShape3D : public Shape3D { + GDCLASS(WorldBoundaryShape3D, Shape3D); Plane plane; protected: @@ -42,8 +42,8 @@ protected: virtual void _update_shape() override; public: - void set_plane(Plane p_plane); - Plane get_plane() const; + void set_plane(const Plane &p_plane); + const Plane &get_plane() const; virtual Vector<Vector3> get_debug_mesh_lines() const override; virtual real_t get_enclosing_radius() const override { @@ -51,6 +51,6 @@ public: return 0; } - WorldMarginShape3D(); + WorldBoundaryShape3D(); }; -#endif // WORLD_MARGIN_SHAPE_H +#endif // WORLD_BOUNDARY_SHAPE_H diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index 758ce766c3..ac1569c15d 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -196,6 +196,7 @@ int AudioDriverManager::get_driver_count() { void AudioDriverManager::initialize(int p_driver) { GLOBAL_DEF_RST("audio/driver/enable_input", false); GLOBAL_DEF_RST("audio/driver/mix_rate", DEFAULT_MIX_RATE); + GLOBAL_DEF_RST("audio/driver/mix_rate.web", 0); // Safer default output_latency for web (use browser default). GLOBAL_DEF_RST("audio/driver/output_latency", DEFAULT_OUTPUT_LATENCY); GLOBAL_DEF_RST("audio/driver/output_latency.web", 50); // Safer default output_latency for web. diff --git a/servers/physics_2d/collision_solver_2d_sat.cpp b/servers/physics_2d/collision_solver_2d_sat.cpp index b1aee01bde..5aadfdb496 100644 --- a/servers/physics_2d/collision_solver_2d_sat.cpp +++ b/servers/physics_2d/collision_solver_2d_sat.cpp @@ -1114,13 +1114,13 @@ static void _collision_convex_polygon_convex_polygon(const Shape2DSW *p_a, const bool sat_2d_calculate_penetration(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CollisionSolver2DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap, Vector2 *sep_axis, real_t p_margin_A, real_t p_margin_B) { PhysicsServer2D::ShapeType type_A = p_shape_A->get_type(); - ERR_FAIL_COND_V(type_A == PhysicsServer2D::SHAPE_WORLD_MARGIN, false); + ERR_FAIL_COND_V(type_A == PhysicsServer2D::SHAPE_WORLD_BOUNDARY, false); ERR_FAIL_COND_V(type_A == PhysicsServer2D::SHAPE_SEPARATION_RAY, false); ERR_FAIL_COND_V(p_shape_A->is_concave(), false); PhysicsServer2D::ShapeType type_B = p_shape_B->get_type(); - ERR_FAIL_COND_V(type_B == PhysicsServer2D::SHAPE_WORLD_MARGIN, false); + ERR_FAIL_COND_V(type_B == PhysicsServer2D::SHAPE_WORLD_BOUNDARY, false); ERR_FAIL_COND_V(type_B == PhysicsServer2D::SHAPE_SEPARATION_RAY, false); ERR_FAIL_COND_V(p_shape_B->is_concave(), false); diff --git a/servers/physics_2d/collision_solver_2d_sw.cpp b/servers/physics_2d/collision_solver_2d_sw.cpp index ae50615953..b07b9a86e8 100644 --- a/servers/physics_2d/collision_solver_2d_sw.cpp +++ b/servers/physics_2d/collision_solver_2d_sw.cpp @@ -34,14 +34,14 @@ #define collision_solver sat_2d_calculate_penetration //#define collision_solver gjk_epa_calculate_penetration -bool CollisionSolver2DSW::solve_static_world_margin(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) { - const WorldMarginShape2DSW *world_margin = static_cast<const WorldMarginShape2DSW *>(p_shape_A); - if (p_shape_B->get_type() == PhysicsServer2D::SHAPE_WORLD_MARGIN) { +bool CollisionSolver2DSW::solve_static_world_boundary(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) { + const WorldBoundaryShape2DSW *world_boundary = static_cast<const WorldBoundaryShape2DSW *>(p_shape_A); + if (p_shape_B->get_type() == PhysicsServer2D::SHAPE_WORLD_BOUNDARY) { return false; } - Vector2 n = p_transform_A.basis_xform(world_margin->get_normal()).normalized(); - Vector2 p = p_transform_A.xform(world_margin->get_normal() * world_margin->get_d()); + Vector2 n = p_transform_A.basis_xform(world_boundary->get_normal()).normalized(); + Vector2 p = p_transform_A.xform(world_boundary->get_normal() * world_boundary->get_d()); real_t d = n.dot(p); Vector2 supports[2]; @@ -225,15 +225,15 @@ bool CollisionSolver2DSW::solve(const Shape2DSW *p_shape_A, const Transform2D &p swap = true; } - if (type_A == PhysicsServer2D::SHAPE_WORLD_MARGIN) { - if (type_B == PhysicsServer2D::SHAPE_WORLD_MARGIN) { + if (type_A == PhysicsServer2D::SHAPE_WORLD_BOUNDARY) { + if (type_B == PhysicsServer2D::SHAPE_WORLD_BOUNDARY) { return false; } if (swap) { - return solve_static_world_margin(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true); + return solve_static_world_boundary(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true); } else { - return solve_static_world_margin(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false); + return solve_static_world_boundary(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false); } } else if (type_A == PhysicsServer2D::SHAPE_SEPARATION_RAY) { diff --git a/servers/physics_2d/collision_solver_2d_sw.h b/servers/physics_2d/collision_solver_2d_sw.h index 62fccc4ff3..b87247b89a 100644 --- a/servers/physics_2d/collision_solver_2d_sw.h +++ b/servers/physics_2d/collision_solver_2d_sw.h @@ -38,7 +38,7 @@ public: typedef void (*CallbackResult)(const Vector2 &p_point_A, const Vector2 &p_point_B, void *p_userdata); private: - static bool solve_static_world_margin(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result); + static bool solve_static_world_boundary(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result); static bool concave_callback(void *p_userdata, Shape2DSW *p_convex); static bool solve_concave(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *r_sep_axis = nullptr, real_t p_margin_A = 0, real_t p_margin_B = 0); static bool solve_separation_ray(const Shape2DSW *p_shape_A, const Vector2 &p_motion_A, const Transform2D &p_transform_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *r_sep_axis = nullptr, real_t p_margin = 0); diff --git a/servers/physics_2d/physics_server_2d_sw.cpp b/servers/physics_2d/physics_server_2d_sw.cpp index d0a42ca95b..edac8aef8d 100644 --- a/servers/physics_2d/physics_server_2d_sw.cpp +++ b/servers/physics_2d/physics_server_2d_sw.cpp @@ -43,8 +43,8 @@ RID PhysicsServer2DSW::_shape_create(ShapeType p_shape) { Shape2DSW *shape = nullptr; switch (p_shape) { - case SHAPE_WORLD_MARGIN: { - shape = memnew(WorldMarginShape2DSW); + case SHAPE_WORLD_BOUNDARY: { + shape = memnew(WorldBoundaryShape2DSW); } break; case SHAPE_SEPARATION_RAY: { shape = memnew(SeparationRayShape2DSW); @@ -79,8 +79,8 @@ RID PhysicsServer2DSW::_shape_create(ShapeType p_shape) { return id; } -RID PhysicsServer2DSW::world_margin_shape_create() { - return _shape_create(SHAPE_WORLD_MARGIN); +RID PhysicsServer2DSW::world_boundary_shape_create() { + return _shape_create(SHAPE_WORLD_BOUNDARY); } RID PhysicsServer2DSW::separation_ray_shape_create() { diff --git a/servers/physics_2d/physics_server_2d_sw.h b/servers/physics_2d/physics_server_2d_sw.h index 6a2d9e37e0..000b2f7031 100644 --- a/servers/physics_2d/physics_server_2d_sw.h +++ b/servers/physics_2d/physics_server_2d_sw.h @@ -84,7 +84,7 @@ public: Vector2 *ptr; }; - virtual RID world_margin_shape_create() override; + virtual RID world_boundary_shape_create() override; virtual RID separation_ray_shape_create() override; virtual RID segment_shape_create() override; virtual RID circle_shape_create() override; diff --git a/servers/physics_2d/physics_server_2d_wrap_mt.h b/servers/physics_2d/physics_server_2d_wrap_mt.h index e65c4f5f3a..16ea6e022e 100644 --- a/servers/physics_2d/physics_server_2d_wrap_mt.h +++ b/servers/physics_2d/physics_server_2d_wrap_mt.h @@ -79,7 +79,7 @@ public: #include "servers/server_wrap_mt_common.h" //FUNC1RID(shape,ShapeType); todo fix - FUNCRID(world_margin_shape) + FUNCRID(world_boundary_shape) FUNCRID(separation_ray_shape) FUNCRID(segment_shape) FUNCRID(circle_shape) diff --git a/servers/physics_2d/shape_2d_sw.cpp b/servers/physics_2d/shape_2d_sw.cpp index 064c4afe52..3fe84a0f14 100644 --- a/servers/physics_2d/shape_2d_sw.cpp +++ b/servers/physics_2d/shape_2d_sw.cpp @@ -88,15 +88,15 @@ Shape2DSW::~Shape2DSW() { /*********************************************************/ /*********************************************************/ -void WorldMarginShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const { +void WorldBoundaryShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const { r_amount = 0; } -bool WorldMarginShape2DSW::contains_point(const Vector2 &p_point) const { +bool WorldBoundaryShape2DSW::contains_point(const Vector2 &p_point) const { return normal.dot(p_point) < d; } -bool WorldMarginShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const { +bool WorldBoundaryShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const { Vector2 segment = p_begin - p_end; real_t den = normal.dot(segment); @@ -118,11 +118,11 @@ bool WorldMarginShape2DSW::intersect_segment(const Vector2 &p_begin, const Vecto return true; } -real_t WorldMarginShape2DSW::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const { +real_t WorldBoundaryShape2DSW::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const { return 0; } -void WorldMarginShape2DSW::set_data(const Variant &p_data) { +void WorldBoundaryShape2DSW::set_data(const Variant &p_data) { ERR_FAIL_COND(p_data.get_type() != Variant::ARRAY); Array arr = p_data; ERR_FAIL_COND(arr.size() != 2); @@ -131,7 +131,7 @@ void WorldMarginShape2DSW::set_data(const Variant &p_data) { configure(Rect2(Vector2(-1e4, -1e4), Vector2(1e4 * 2, 1e4 * 2))); } -Variant WorldMarginShape2DSW::get_data() const { +Variant WorldBoundaryShape2DSW::get_data() const { Array arr; arr.resize(2); arr[0] = normal; diff --git a/servers/physics_2d/shape_2d_sw.h b/servers/physics_2d/shape_2d_sw.h index 1185d343ee..ecc829f962 100644 --- a/servers/physics_2d/shape_2d_sw.h +++ b/servers/physics_2d/shape_2d_sw.h @@ -142,7 +142,7 @@ public: r_max = MAX(maxa, maxb); \ } -class WorldMarginShape2DSW : public Shape2DSW { +class WorldBoundaryShape2DSW : public Shape2DSW { Vector2 normal; real_t d; @@ -150,7 +150,7 @@ public: _FORCE_INLINE_ Vector2 get_normal() const { return normal; } _FORCE_INLINE_ real_t get_d() const { return d; } - virtual PhysicsServer2D::ShapeType get_type() const override { return PhysicsServer2D::SHAPE_WORLD_MARGIN; } + virtual PhysicsServer2D::ShapeType get_type() const override { return PhysicsServer2D::SHAPE_WORLD_BOUNDARY; } virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const override { project_range(p_normal, p_transform, r_min, r_max); } virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const override; diff --git a/servers/physics_3d/collision_solver_3d_sat.cpp b/servers/physics_3d/collision_solver_3d_sat.cpp index de81348b4e..30862925d6 100644 --- a/servers/physics_3d/collision_solver_3d_sat.cpp +++ b/servers/physics_3d/collision_solver_3d_sat.cpp @@ -2272,13 +2272,13 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform bool sat_calculate_penetration(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CollisionSolver3DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap, Vector3 *r_prev_axis, real_t p_margin_a, real_t p_margin_b) { PhysicsServer3D::ShapeType type_A = p_shape_A->get_type(); - ERR_FAIL_COND_V(type_A == PhysicsServer3D::SHAPE_PLANE, false); + ERR_FAIL_COND_V(type_A == PhysicsServer3D::SHAPE_WORLD_BOUNDARY, false); ERR_FAIL_COND_V(type_A == PhysicsServer3D::SHAPE_SEPARATION_RAY, false); ERR_FAIL_COND_V(p_shape_A->is_concave(), false); PhysicsServer3D::ShapeType type_B = p_shape_B->get_type(); - ERR_FAIL_COND_V(type_B == PhysicsServer3D::SHAPE_PLANE, false); + ERR_FAIL_COND_V(type_B == PhysicsServer3D::SHAPE_WORLD_BOUNDARY, false); ERR_FAIL_COND_V(type_B == PhysicsServer3D::SHAPE_SEPARATION_RAY, false); ERR_FAIL_COND_V(p_shape_B->is_concave(), false); diff --git a/servers/physics_3d/collision_solver_3d_sw.cpp b/servers/physics_3d/collision_solver_3d_sw.cpp index 4a4a8164d3..dcc363638e 100644 --- a/servers/physics_3d/collision_solver_3d_sw.cpp +++ b/servers/physics_3d/collision_solver_3d_sw.cpp @@ -37,12 +37,12 @@ #define collision_solver sat_calculate_penetration //#define collision_solver gjk_epa_calculate_penetration -bool CollisionSolver3DSW::solve_static_plane(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) { - const PlaneShape3DSW *plane = static_cast<const PlaneShape3DSW *>(p_shape_A); - if (p_shape_B->get_type() == PhysicsServer3D::SHAPE_PLANE) { +bool CollisionSolver3DSW::solve_static_world_boundary(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) { + const WorldBoundaryShape3DSW *world_boundary = static_cast<const WorldBoundaryShape3DSW *>(p_shape_A); + if (p_shape_B->get_type() == PhysicsServer3D::SHAPE_WORLD_BOUNDARY) { return false; } - Plane p = p_transform_A.xform(plane->get_plane()); + Plane p = p_transform_A.xform(world_boundary->get_plane()); static const int max_supports = 16; Vector3 supports[max_supports]; @@ -365,8 +365,8 @@ bool CollisionSolver3DSW::solve_static(const Shape3DSW *p_shape_A, const Transfo swap = true; } - if (type_A == PhysicsServer3D::SHAPE_PLANE) { - if (type_B == PhysicsServer3D::SHAPE_PLANE) { + if (type_A == PhysicsServer3D::SHAPE_WORLD_BOUNDARY) { + if (type_B == PhysicsServer3D::SHAPE_WORLD_BOUNDARY) { return false; } if (type_B == PhysicsServer3D::SHAPE_SEPARATION_RAY) { @@ -377,9 +377,9 @@ bool CollisionSolver3DSW::solve_static(const Shape3DSW *p_shape_A, const Transfo } if (swap) { - return solve_static_plane(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true); + return solve_static_world_boundary(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true); } else { - return solve_static_plane(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false); + return solve_static_world_boundary(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false); } } else if (type_A == PhysicsServer3D::SHAPE_SEPARATION_RAY) { @@ -443,12 +443,12 @@ bool CollisionSolver3DSW::concave_distance_callback(void *p_userdata, Shape3DSW return false; } -bool CollisionSolver3DSW::solve_distance_plane(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B) { - const PlaneShape3DSW *plane = static_cast<const PlaneShape3DSW *>(p_shape_A); - if (p_shape_B->get_type() == PhysicsServer3D::SHAPE_PLANE) { +bool CollisionSolver3DSW::solve_distance_world_boundary(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B) { + const WorldBoundaryShape3DSW *world_boundary = static_cast<const WorldBoundaryShape3DSW *>(p_shape_A); + if (p_shape_B->get_type() == PhysicsServer3D::SHAPE_WORLD_BOUNDARY) { return false; } - Plane p = p_transform_A.xform(plane->get_plane()); + Plane p = p_transform_A.xform(world_boundary->get_plane()); static const int max_supports = 16; Vector3 supports[max_supports]; @@ -500,9 +500,9 @@ bool CollisionSolver3DSW::solve_distance(const Shape3DSW *p_shape_A, const Trans return false; } - if (p_shape_B->get_type() == PhysicsServer3D::SHAPE_PLANE) { + if (p_shape_B->get_type() == PhysicsServer3D::SHAPE_WORLD_BOUNDARY) { Vector3 a, b; - bool col = solve_distance_plane(p_shape_B, p_transform_B, p_shape_A, p_transform_A, a, b); + bool col = solve_distance_world_boundary(p_shape_B, p_transform_B, p_shape_A, p_transform_A, a, b); r_point_A = b; r_point_B = a; return !col; diff --git a/servers/physics_3d/collision_solver_3d_sw.h b/servers/physics_3d/collision_solver_3d_sw.h index c13614ab3e..0a9ea7c0eb 100644 --- a/servers/physics_3d/collision_solver_3d_sw.h +++ b/servers/physics_3d/collision_solver_3d_sw.h @@ -42,12 +42,12 @@ private: static void soft_body_contact_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata); static bool soft_body_concave_callback(void *p_userdata, Shape3DSW *p_convex); static bool concave_callback(void *p_userdata, Shape3DSW *p_convex); - static bool solve_static_plane(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result); + static bool solve_static_world_boundary(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result); static bool solve_separation_ray(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin = 0); static bool solve_soft_body(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result); static bool solve_concave(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin_A = 0, real_t p_margin_B = 0); static bool concave_distance_callback(void *p_userdata, Shape3DSW *p_convex); - static bool solve_distance_plane(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B); + static bool solve_distance_world_boundary(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B); public: static bool solve_static(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, Vector3 *r_sep_axis = nullptr, real_t p_margin_A = 0, real_t p_margin_B = 0); diff --git a/servers/physics_3d/physics_server_3d_sw.cpp b/servers/physics_3d/physics_server_3d_sw.cpp index 8de54c5c48..9393d671c9 100644 --- a/servers/physics_3d/physics_server_3d_sw.cpp +++ b/servers/physics_3d/physics_server_3d_sw.cpp @@ -43,8 +43,8 @@ #define FLUSH_QUERY_CHECK(m_object) \ ERR_FAIL_COND_MSG(m_object->get_space() && flushing_queries, "Can't change this state while flushing queries. Use call_deferred() or set_deferred() to change monitoring state instead."); -RID PhysicsServer3DSW::plane_shape_create() { - Shape3DSW *shape = memnew(PlaneShape3DSW); +RID PhysicsServer3DSW::world_boundary_shape_create() { + Shape3DSW *shape = memnew(WorldBoundaryShape3DSW); RID rid = shape_owner.make_rid(shape); shape->set_self(rid); return rid; diff --git a/servers/physics_3d/physics_server_3d_sw.h b/servers/physics_3d/physics_server_3d_sw.h index 071ad0a694..3beffb3604 100644 --- a/servers/physics_3d/physics_server_3d_sw.h +++ b/servers/physics_3d/physics_server_3d_sw.h @@ -79,7 +79,7 @@ public: static void _shape_col_cbk(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata); - virtual RID plane_shape_create() override; + virtual RID world_boundary_shape_create() override; virtual RID separation_ray_shape_create() override; virtual RID sphere_shape_create() override; virtual RID box_shape_create() override; diff --git a/servers/physics_3d/physics_server_3d_wrap_mt.h b/servers/physics_3d/physics_server_3d_wrap_mt.h index 58986969d4..d2ce06a998 100644 --- a/servers/physics_3d/physics_server_3d_wrap_mt.h +++ b/servers/physics_3d/physics_server_3d_wrap_mt.h @@ -78,7 +78,7 @@ public: #include "servers/server_wrap_mt_common.h" //FUNC1RID(shape,ShapeType); todo fix - FUNCRID(plane_shape) + FUNCRID(world_boundary_shape) FUNCRID(separation_ray_shape) FUNCRID(sphere_shape) FUNCRID(box_shape) diff --git a/servers/physics_3d/shape_3d_sw.cpp b/servers/physics_3d/shape_3d_sw.cpp index 60703c4e2d..c28ea92fb6 100644 --- a/servers/physics_3d/shape_3d_sw.cpp +++ b/servers/physics_3d/shape_3d_sw.cpp @@ -110,21 +110,21 @@ Shape3DSW::~Shape3DSW() { ERR_FAIL_COND(owners.size()); } -Plane PlaneShape3DSW::get_plane() const { +Plane WorldBoundaryShape3DSW::get_plane() const { return plane; } -void PlaneShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { +void WorldBoundaryShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { // gibberish, a plane is infinity r_min = -1e7; r_max = 1e7; } -Vector3 PlaneShape3DSW::get_support(const Vector3 &p_normal) const { +Vector3 WorldBoundaryShape3DSW::get_support(const Vector3 &p_normal) const { return p_normal * 1e15; } -bool PlaneShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const { +bool WorldBoundaryShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const { bool inters = plane.intersects_segment(p_begin, p_end, &r_result); if (inters) { r_normal = plane.normal; @@ -132,11 +132,11 @@ bool PlaneShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_ return inters; } -bool PlaneShape3DSW::intersect_point(const Vector3 &p_point) const { +bool WorldBoundaryShape3DSW::intersect_point(const Vector3 &p_point) const { return plane.distance_to(p_point) < 0; } -Vector3 PlaneShape3DSW::get_closest_point_to(const Vector3 &p_point) const { +Vector3 WorldBoundaryShape3DSW::get_closest_point_to(const Vector3 &p_point) const { if (plane.is_point_over(p_point)) { return plane.project(p_point); } else { @@ -144,24 +144,24 @@ Vector3 PlaneShape3DSW::get_closest_point_to(const Vector3 &p_point) const { } } -Vector3 PlaneShape3DSW::get_moment_of_inertia(real_t p_mass) const { - return Vector3(); //wtf +Vector3 WorldBoundaryShape3DSW::get_moment_of_inertia(real_t p_mass) const { + return Vector3(); // not applicable. } -void PlaneShape3DSW::_setup(const Plane &p_plane) { +void WorldBoundaryShape3DSW::_setup(const Plane &p_plane) { plane = p_plane; configure(AABB(Vector3(-1e4, -1e4, -1e4), Vector3(1e4 * 2, 1e4 * 2, 1e4 * 2))); } -void PlaneShape3DSW::set_data(const Variant &p_data) { +void WorldBoundaryShape3DSW::set_data(const Variant &p_data) { _setup(p_data); } -Variant PlaneShape3DSW::get_data() const { +Variant WorldBoundaryShape3DSW::get_data() const { return plane; } -PlaneShape3DSW::PlaneShape3DSW() { +WorldBoundaryShape3DSW::WorldBoundaryShape3DSW() { } // diff --git a/servers/physics_3d/shape_3d_sw.h b/servers/physics_3d/shape_3d_sw.h index 73eddc469c..b37d35986e 100644 --- a/servers/physics_3d/shape_3d_sw.h +++ b/servers/physics_3d/shape_3d_sw.h @@ -112,7 +112,7 @@ public: ConcaveShape3DSW() {} }; -class PlaneShape3DSW : public Shape3DSW { +class WorldBoundaryShape3DSW : public Shape3DSW { Plane plane; void _setup(const Plane &p_plane); @@ -121,7 +121,7 @@ public: Plane get_plane() const; virtual real_t get_area() const override { return INFINITY; } - virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_PLANE; } + virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_WORLD_BOUNDARY; } virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override; virtual Vector3 get_support(const Vector3 &p_normal) const override; virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override { r_amount = 0; } @@ -134,7 +134,7 @@ public: virtual void set_data(const Variant &p_data) override; virtual Variant get_data() const override; - PlaneShape3DSW(); + WorldBoundaryShape3DSW(); }; class SeparationRayShape3DSW : public Shape3DSW { diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp index 2656ef1d6d..8d5367e735 100644 --- a/servers/physics_server_2d.cpp +++ b/servers/physics_server_2d.cpp @@ -508,7 +508,7 @@ bool PhysicsServer2D::_body_test_motion(RID p_body, const Transform2D &p_from, c } void PhysicsServer2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("world_margin_shape_create"), &PhysicsServer2D::world_margin_shape_create); + ClassDB::bind_method(D_METHOD("world_boundary_shape_create"), &PhysicsServer2D::world_boundary_shape_create); ClassDB::bind_method(D_METHOD("separation_ray_shape_create"), &PhysicsServer2D::separation_ray_shape_create); ClassDB::bind_method(D_METHOD("segment_shape_create"), &PhysicsServer2D::segment_shape_create); ClassDB::bind_method(D_METHOD("circle_shape_create"), &PhysicsServer2D::circle_shape_create); @@ -672,7 +672,7 @@ void PhysicsServer2D::_bind_methods() { BIND_ENUM_CONSTANT(SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS); BIND_ENUM_CONSTANT(SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH); - BIND_ENUM_CONSTANT(SHAPE_WORLD_MARGIN); + BIND_ENUM_CONSTANT(SHAPE_WORLD_BOUNDARY); BIND_ENUM_CONSTANT(SHAPE_SEPARATION_RAY); BIND_ENUM_CONSTANT(SHAPE_SEGMENT); BIND_ENUM_CONSTANT(SHAPE_CIRCLE); diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h index 1145bb8b91..30d3c47051 100644 --- a/servers/physics_server_2d.h +++ b/servers/physics_server_2d.h @@ -218,7 +218,7 @@ public: static PhysicsServer2D *get_singleton(); enum ShapeType { - SHAPE_WORLD_MARGIN, ///< plane:"plane" + SHAPE_WORLD_BOUNDARY, ///< plane:"plane" SHAPE_SEPARATION_RAY, ///< float:"length" SHAPE_SEGMENT, ///< float:"length" SHAPE_CIRCLE, ///< float:"radius" @@ -229,7 +229,7 @@ public: SHAPE_CUSTOM, ///< Server-Implementation based custom shape, calling shape_create() with this value will result in an error }; - virtual RID world_margin_shape_create() = 0; + virtual RID world_boundary_shape_create() = 0; virtual RID separation_ray_shape_create() = 0; virtual RID segment_shape_create() = 0; virtual RID circle_shape_create() = 0; diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp index 0c487b83ea..0ff29394e5 100644 --- a/servers/physics_server_3d.cpp +++ b/servers/physics_server_3d.cpp @@ -454,8 +454,8 @@ bool PhysicsServer3D::_body_test_motion(RID p_body, const Transform3D &p_from, c RID PhysicsServer3D::shape_create(ShapeType p_shape) { switch (p_shape) { - case SHAPE_PLANE: - return plane_shape_create(); + case SHAPE_WORLD_BOUNDARY: + return world_boundary_shape_create(); case SHAPE_SEPARATION_RAY: return separation_ray_shape_create(); case SHAPE_SPHERE: @@ -482,7 +482,7 @@ RID PhysicsServer3D::shape_create(ShapeType p_shape) { void PhysicsServer3D::_bind_methods() { #ifndef _3D_DISABLED - ClassDB::bind_method(D_METHOD("plane_shape_create"), &PhysicsServer3D::plane_shape_create); + ClassDB::bind_method(D_METHOD("world_boundary_shape_create"), &PhysicsServer3D::world_boundary_shape_create); ClassDB::bind_method(D_METHOD("separation_ray_shape_create"), &PhysicsServer3D::separation_ray_shape_create); ClassDB::bind_method(D_METHOD("sphere_shape_create"), &PhysicsServer3D::sphere_shape_create); ClassDB::bind_method(D_METHOD("box_shape_create"), &PhysicsServer3D::box_shape_create); @@ -745,7 +745,7 @@ void PhysicsServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_process_info", "process_info"), &PhysicsServer3D::get_process_info); - BIND_ENUM_CONSTANT(SHAPE_PLANE); + BIND_ENUM_CONSTANT(SHAPE_WORLD_BOUNDARY); BIND_ENUM_CONSTANT(SHAPE_SEPARATION_RAY); BIND_ENUM_CONSTANT(SHAPE_SPHERE); BIND_ENUM_CONSTANT(SHAPE_BOX); diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h index 5677604682..590b0929b1 100644 --- a/servers/physics_server_3d.h +++ b/servers/physics_server_3d.h @@ -219,7 +219,7 @@ public: static PhysicsServer3D *get_singleton(); enum ShapeType { - SHAPE_PLANE, ///< plane:"plane" + SHAPE_WORLD_BOUNDARY, ///< plane:"plane" SHAPE_SEPARATION_RAY, ///< float:"length" SHAPE_SPHERE, ///< float:"radius" SHAPE_BOX, ///< vec3:"extents" @@ -234,7 +234,7 @@ public: RID shape_create(ShapeType p_shape); - virtual RID plane_shape_create() = 0; + virtual RID world_boundary_shape_create() = 0; virtual RID separation_ray_shape_create() = 0; virtual RID sphere_shape_create() = 0; virtual RID box_shape_create() = 0; diff --git a/tests/test_physics_2d.cpp b/tests/test_physics_2d.cpp index 61b8951afa..f63b866c3e 100644 --- a/tests/test_physics_2d.cpp +++ b/tests/test_physics_2d.cpp @@ -248,20 +248,20 @@ protected: return body; } - void _add_plane(const Vector2 &p_normal, real_t p_d) { + void _add_world_boundary(const Vector2 &p_normal, real_t p_d) { PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); Array arr; arr.push_back(p_normal); arr.push_back(p_d); - RID plane = ps->world_margin_shape_create(); - ps->shape_set_data(plane, arr); + RID world_boundary = ps->world_boundary_shape_create(); + ps->shape_set_data(world_boundary, arr); RID plane_body = ps->body_create(); ps->body_set_mode(plane_body, PhysicsServer2D::BODY_MODE_STATIC); ps->body_set_space(plane_body, space); - ps->body_add_shape(plane_body, plane); + ps->body_add_shape(plane_body, world_boundary); } void _add_concave(const Vector<Vector2> &p_points, const Transform2D &p_xform = Transform2D()) { @@ -381,9 +381,9 @@ public: } _add_concave(parr); - //_add_plane(Vector2(0.0,-1).normalized(),-300); - //_add_plane(Vector2(1,0).normalized(),50); - //_add_plane(Vector2(-1,0).normalized(),-600); + //_add_world_boundary(Vector2(0.0,-1).normalized(),-300); + //_add_world_boundary(Vector2(1,0).normalized(),50); + //_add_world_boundary(Vector2(-1,0).normalized(),-600); } virtual bool process(double p_time) override { diff --git a/tests/test_physics_3d.cpp b/tests/test_physics_3d.cpp index ed49b60c71..3d1dad6545 100644 --- a/tests/test_physics_3d.cpp +++ b/tests/test_physics_3d.cpp @@ -100,18 +100,17 @@ protected: return body; } - RID create_static_plane(const Plane &p_plane) { + RID create_world_boundary(const Plane &p_plane) { PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); - RID world_margin_shape = ps->shape_create(PhysicsServer3D::SHAPE_PLANE); - ps->shape_set_data(world_margin_shape, p_plane); + RID world_boundary_shape = ps->shape_create(PhysicsServer3D::SHAPE_WORLD_BOUNDARY); + ps->shape_set_data(world_boundary_shape, p_plane); RID b = ps->body_create(); ps->body_set_mode(b, PhysicsServer3D::BODY_MODE_STATIC); ps->body_set_space(b, space); - //todo set space - ps->body_add_shape(b, world_margin_shape); + ps->body_add_shape(b, world_boundary_shape); return b; } @@ -391,12 +390,12 @@ public: create_body(type, PhysicsServer3D::BODY_MODE_DYNAMIC, t); } - create_static_plane(Plane(Vector3(0, 1, 0), -1)); + create_world_boundary(Plane(Vector3(0, 1, 0), -1)); } void test_activate() { create_body(PhysicsServer3D::SHAPE_BOX, PhysicsServer3D::BODY_MODE_DYNAMIC, Transform3D(Basis(), Vector3(0, 2, 0)), true); - create_static_plane(Plane(Vector3(0, 1, 0), -1)); + create_world_boundary(Plane(Vector3(0, 1, 0), -1)); } virtual bool process(double p_time) override { diff --git a/tests/test_string.h b/tests/test_string.h index bcedaa0db7..c1b7220fdb 100644 --- a/tests/test_string.h +++ b/tests/test_string.h @@ -355,13 +355,23 @@ TEST_CASE("[String] Number to string") { CHECK(String::num(-0.0) == "-0"); // Includes sign even for zero. CHECK(String::num(3.141593) == "3.141593"); CHECK(String::num(3.141593, 3) == "3.142"); - CHECK(String::num_real(3.141593) == "3.141593"); CHECK(String::num_scientific(30000000) == "3e+07"); CHECK(String::num_int64(3141593) == "3141593"); CHECK(String::num_int64(0xA141593, 16) == "a141593"); CHECK(String::num_int64(0xA141593, 16, true) == "A141593"); CHECK(String::num(42.100023, 4) == "42.1"); // No trailing zeros. + // String::num_real tests. + CHECK(String::num_real(3.141593) == "3.141593"); + CHECK(String::num_real(3.141) == "3.141"); // No trailing zeros. +#ifdef REAL_T_IS_DOUBLE + CHECK_MESSAGE(String::num_real(Math_PI) == "3.14159265358979", "Prints the appropriate amount of digits for real_t = double."); + CHECK_MESSAGE(String::num_real(3.1415f) == "3.14149999618530", "Prints more digits of 32-bit float when real_t = double (ones that would be reliable for double)."); +#else + CHECK_MESSAGE(String::num_real(Math_PI) == "3.141593", "Prints the appropriate amount of digits for real_t = float."); + CHECK_MESSAGE(String::num_real(3.1415f) == "3.1415", "Prints only reliable digits of 32-bit float when real_t = float."); +#endif // REAL_T_IS_DOUBLE + // Checks doubles with many decimal places. CHECK(String::num(0.0000012345432123454321, -1) == "0.00000123454321"); // -1 uses 14 as sane default. CHECK(String::num(0.0000012345432123454321) == "0.00000123454321"); // -1 is the default value. |