summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/io/file_access_pack.cpp16
-rw-r--r--core/string_builder.cpp3
-rw-r--r--core/ustring.cpp6
-rw-r--r--core/ustring.h2
-rw-r--r--core/variant_call.cpp2
-rw-r--r--doc/classes/Camera2D.xml7
-rw-r--r--doc/classes/CameraFeed.xml8
-rw-r--r--doc/classes/ClippedCamera.xml19
-rw-r--r--doc/classes/ColorPicker.xml2
-rw-r--r--doc/classes/Input.xml1
-rw-r--r--doc/classes/ProjectSettings.xml8
-rw-r--r--doc/classes/RigidBody.xml4
-rw-r--r--doc/classes/RigidBody2D.xml2
-rw-r--r--doc/classes/StaticBody.xml2
-rw-r--r--doc/classes/StaticBody2D.xml2
-rw-r--r--doc/classes/StreamPeer.xml8
-rw-r--r--doc/classes/String.xml14
-rw-r--r--doc/classes/TreeItem.xml18
-rw-r--r--doc/classes/VideoPlayer.xml1
-rw-r--r--drivers/gles2/rasterizer_scene_gles2.cpp14
-rw-r--r--drivers/gles2/rasterizer_storage_gles2.cpp3
-rw-r--r--editor/editor_about.cpp2
-rw-r--r--editor/editor_fonts.cpp1
-rw-r--r--editor/editor_properties.cpp1
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp2
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp27
-rw-r--r--editor/plugins/spatial_editor_plugin.cpp35
-rw-r--r--editor/plugins/spatial_editor_plugin.h2
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h1
-rw-r--r--editor/project_export.cpp8
-rw-r--r--editor/project_settings_editor.cpp23
-rw-r--r--editor/project_settings_editor.h1
-rw-r--r--editor/settings_config_dialog.cpp50
-rw-r--r--main/main.cpp7
-rw-r--r--modules/gdnative/doc_classes/GDNativeLibrary.xml15
-rw-r--r--modules/gdscript/gdscript_function.cpp8
-rw-r--r--modules/gdscript/language_server/gdscript_extend_parser.cpp70
-rw-r--r--modules/gdscript/language_server/gdscript_extend_parser.h5
-rw-r--r--modules/gdscript/language_server/gdscript_language_protocol.cpp6
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.cpp73
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.h2
-rw-r--r--modules/gdscript/language_server/gdscript_workspace.cpp26
-rw-r--r--modules/gdscript/language_server/gdscript_workspace.h2
-rw-r--r--modules/gdscript/language_server/lsp.hpp144
-rw-r--r--scene/2d/tile_map.cpp1
-rw-r--r--scene/gui/control.cpp26
-rw-r--r--scene/gui/file_dialog.cpp2
-rw-r--r--scene/gui/item_list.cpp1
-rw-r--r--scene/gui/rich_text_label.cpp5
-rw-r--r--scene/gui/tree.cpp46
-rw-r--r--scene/gui/tree.h4
-rw-r--r--servers/visual/shader_language.cpp38
52 files changed, 571 insertions, 205 deletions
diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp
index 54ef753b7c..34d3eb5344 100644
--- a/core/io/file_access_pack.cpp
+++ b/core/io/file_access_pack.cpp
@@ -151,6 +151,7 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files)
magic = f->get_32();
if (magic != 0x43504447) {
+ f->close();
memdelete(f);
return false;
}
@@ -162,6 +163,7 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files)
magic = f->get_32();
if (magic != 0x43504447) {
+ f->close();
memdelete(f);
return false;
}
@@ -172,8 +174,16 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files)
uint32_t ver_minor = f->get_32();
f->get_32(); // ver_rev
- ERR_FAIL_COND_V_MSG(version != PACK_VERSION, false, "Pack version unsupported: " + itos(version) + ".");
- ERR_FAIL_COND_V_MSG(ver_major > VERSION_MAJOR || (ver_major == VERSION_MAJOR && ver_minor > VERSION_MINOR), false, "Pack created with a newer version of the engine: " + itos(ver_major) + "." + itos(ver_minor) + ".");
+ if (version != PACK_VERSION) {
+ f->close();
+ memdelete(f);
+ ERR_FAIL_V_MSG(false, "Pack version unsupported: " + itos(version) + ".");
+ }
+ if (ver_major > VERSION_MAJOR || (ver_major == VERSION_MAJOR && ver_minor > VERSION_MINOR)) {
+ f->close();
+ memdelete(f);
+ ERR_FAIL_V_MSG(false, "Pack created with a newer version of the engine: " + itos(ver_major) + "." + itos(ver_minor) + ".");
+ }
for (int i = 0; i < 16; i++) {
//reserved
@@ -200,6 +210,8 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files)
PackedData::get_singleton()->add_path(p_path, path, ofs, size, md5, this, p_replace_files);
};
+ f->close();
+ memdelete(f);
return true;
};
diff --git a/core/string_builder.cpp b/core/string_builder.cpp
index 35526e0d70..22eed70f8b 100644
--- a/core/string_builder.cpp
+++ b/core/string_builder.cpp
@@ -34,6 +34,9 @@
StringBuilder &StringBuilder::append(const String &p_string) {
+ if (p_string == String())
+ return *this;
+
strings.push_back(p_string);
appended_strings.push_back(-1);
diff --git a/core/ustring.cpp b/core/ustring.cpp
index 07caa3a018..f029ae4200 100644
--- a/core/ustring.cpp
+++ b/core/ustring.cpp
@@ -3288,9 +3288,7 @@ String String::simplify_path() const {
static int _humanize_digits(int p_num) {
- if (p_num < 10)
- return 2;
- else if (p_num < 100)
+ if (p_num < 100)
return 2;
else if (p_num < 1024)
return 1;
@@ -3298,7 +3296,7 @@ static int _humanize_digits(int p_num) {
return 0;
}
-String String::humanize_size(size_t p_size) {
+String String::humanize_size(uint64_t p_size) {
uint64_t _div = 1;
Vector<String> prefixes;
diff --git a/core/ustring.h b/core/ustring.h
index 87a14bfad7..15e2c07d9f 100644
--- a/core/ustring.h
+++ b/core/ustring.h
@@ -322,7 +322,7 @@ public:
String path_to_file(const String &p_path) const;
String get_base_dir() const;
String get_file() const;
- static String humanize_size(size_t p_size);
+ static String humanize_size(uint64_t p_size);
String simplify_path() const;
String xml_escape(bool p_escape_quotes = false) const;
diff --git a/core/variant_call.cpp b/core/variant_call.cpp
index 53f64fcde6..1b5ca9d3e5 100644
--- a/core/variant_call.cpp
+++ b/core/variant_call.cpp
@@ -284,6 +284,7 @@ struct _VariantCall {
VCALL_LOCALMEM0R(String, sha1_buffer);
VCALL_LOCALMEM0R(String, sha256_buffer);
VCALL_LOCALMEM0R(String, empty);
+ VCALL_LOCALMEM1R(String, humanize_size);
VCALL_LOCALMEM0R(String, is_abs_path);
VCALL_LOCALMEM0R(String, is_rel_path);
VCALL_LOCALMEM0R(String, get_base_dir);
@@ -1561,6 +1562,7 @@ void register_variant_methods() {
ADDFUNC0R(STRING, POOL_BYTE_ARRAY, String, sha1_buffer, varray());
ADDFUNC0R(STRING, POOL_BYTE_ARRAY, String, sha256_buffer, varray());
ADDFUNC0R(STRING, BOOL, String, empty, varray());
+ ADDFUNC1R(STRING, STRING, String, humanize_size, INT, "size", varray());
ADDFUNC0R(STRING, BOOL, String, is_abs_path, varray());
ADDFUNC0R(STRING, BOOL, String, is_rel_path, varray());
ADDFUNC0R(STRING, STRING, String, get_base_dir, varray());
diff --git a/doc/classes/Camera2D.xml b/doc/classes/Camera2D.xml
index aeeebdf00d..6f1627e296 100644
--- a/doc/classes/Camera2D.xml
+++ b/doc/classes/Camera2D.xml
@@ -51,6 +51,7 @@
<argument index="0" name="margin" type="int" enum="Margin">
</argument>
<description>
+ Returns the specified margin. See also [member drag_margin_bottom], [member drag_margin_top], [member drag_margin_left], and [member drag_margin_right].
</description>
</method>
<method name="get_limit" qualifiers="const">
@@ -59,6 +60,7 @@
<argument index="0" name="margin" type="int" enum="Margin">
</argument>
<description>
+ Returns the specified camera limit. See also [member limit_bottom], [member limit_top], [member limit_left], and [member limit_right].
</description>
</method>
<method name="make_current">
@@ -84,6 +86,7 @@
<argument index="1" name="drag_margin" type="float">
</argument>
<description>
+ Sets the specified margin. See also [member drag_margin_bottom], [member drag_margin_top], [member drag_margin_left], and [member drag_margin_right].
</description>
</method>
<method name="set_limit">
@@ -94,6 +97,7 @@
<argument index="1" name="limit" type="int">
</argument>
<description>
+ Sets the specified camera limit. See also [member limit_bottom], [member limit_top], [member limit_left], and [member limit_right].
</description>
</method>
</methods>
@@ -161,6 +165,7 @@
[b]Note:[/b] Used the same as [member offset_h].
</member>
<member name="process_mode" type="int" setter="set_process_mode" getter="get_process_mode" enum="Camera2D.Camera2DProcessMode" default="1">
+ The camera's process callback. See [enum Camera2DProcessMode].
</member>
<member name="rotating" type="bool" setter="set_rotating" getter="is_rotating" default="false">
If [code]true[/code], the camera rotates with the target.
@@ -183,8 +188,10 @@
The camera's position takes into account vertical/horizontal offsets and the screen size.
</constant>
<constant name="CAMERA2D_PROCESS_PHYSICS" value="0" enum="Camera2DProcessMode">
+ The camera updates with the [code]_physics_process[/code] callback.
</constant>
<constant name="CAMERA2D_PROCESS_IDLE" value="1" enum="Camera2DProcessMode">
+ The camera updates with the [code]_process[/code] callback.
</constant>
</constants>
</class>
diff --git a/doc/classes/CameraFeed.xml b/doc/classes/CameraFeed.xml
index 6d7757f9f5..f490faf369 100644
--- a/doc/classes/CameraFeed.xml
+++ b/doc/classes/CameraFeed.xml
@@ -14,28 +14,30 @@
<return type="int">
</return>
<description>
- Gets the unique ID for this feed.
+ Returns the unique ID for this feed.
</description>
</method>
<method name="get_name" qualifiers="const">
<return type="String">
</return>
<description>
- Gets the camera's name.
+ Returns the camera's name.
</description>
</method>
<method name="get_position" qualifiers="const">
<return type="int" enum="CameraFeed.FeedPosition">
</return>
<description>
- Position of camera on the device.
+ Returns the position of camera on the device.
</description>
</method>
</methods>
<members>
<member name="feed_is_active" type="bool" setter="set_active" getter="is_active" default="false">
+ If [code]true[/code], the feed is active.
</member>
<member name="feed_transform" type="Transform2D" setter="set_transform" getter="get_transform" default="Transform2D( 1, 0, 0, -1, 0, 1 )">
+ The transform applied to the camera's image.
</member>
</members>
<constants>
diff --git a/doc/classes/ClippedCamera.xml b/doc/classes/ClippedCamera.xml
index f6a2a3bc11..9eda79bbae 100644
--- a/doc/classes/ClippedCamera.xml
+++ b/doc/classes/ClippedCamera.xml
@@ -1,8 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="ClippedCamera" inherits="Camera" category="Core" version="3.2">
<brief_description>
+ A [Camera] that includes collision.
</brief_description>
<description>
+ This node extends [Camera] to add collisions with [Area] and/or [PhysicsBody] nodes. The camera cannot move through colliding objects.
</description>
<tutorials>
</tutorials>
@@ -13,6 +15,7 @@
<argument index="0" name="node" type="Object">
</argument>
<description>
+ Adds a collision exception so the camera does not collide with the specified node.
</description>
</method>
<method name="add_exception_rid">
@@ -21,18 +24,21 @@
<argument index="0" name="rid" type="RID">
</argument>
<description>
+ Adds a collision exception so the camera does not collide with the specified [RID].
</description>
</method>
<method name="clear_exceptions">
<return type="void">
</return>
<description>
+ Removes all collision exceptions.
</description>
</method>
<method name="get_clip_offset" qualifiers="const">
<return type="float">
</return>
<description>
+ Returns the distance the camera has been offset due to a collision.
</description>
</method>
<method name="get_collision_mask_bit" qualifiers="const">
@@ -41,6 +47,8 @@
<argument index="0" name="bit" type="int">
</argument>
<description>
+ Returns [code]true[/code] if the specified bit index is on.
+ [b]Note:[/b] Bit indices range from 0-19.
</description>
</method>
<method name="remove_exception">
@@ -49,6 +57,7 @@
<argument index="0" name="node" type="Object">
</argument>
<description>
+ Removes a collision exception with the specified node.
</description>
</method>
<method name="remove_exception_rid">
@@ -57,6 +66,7 @@
<argument index="0" name="rid" type="RID">
</argument>
<description>
+ Removes a collision exception with the specified [RID].
</description>
</method>
<method name="set_collision_mask_bit">
@@ -67,25 +77,34 @@
<argument index="1" name="value" type="bool">
</argument>
<description>
+ Sets the specified bit index to the [code]value[/code].
+ [b]Note:[/b] Bit indices range from 0-19.
</description>
</method>
</methods>
<members>
<member name="clip_to_areas" type="bool" setter="set_clip_to_areas" getter="is_clip_to_areas_enabled" default="false">
+ If [code]true[/code], the camera stops on contact with [Area]s.
</member>
<member name="clip_to_bodies" type="bool" setter="set_clip_to_bodies" getter="is_clip_to_bodies_enabled" default="true">
+ If [code]true[/code], the camera stops on contact with [PhysicsBody]s.
</member>
<member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
+ The camera's collision mask. Only objects in at least one collision layer matching the mask will be detected.
</member>
<member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.0">
+ The camera's collision margin. The camera can't get closer than this distance to a colliding object.
</member>
<member name="process_mode" type="int" setter="set_process_mode" getter="get_process_mode" enum="ClippedCamera.ProcessMode" default="0">
+ The camera's process callback. See [enum ProcessMode].
</member>
</members>
<constants>
<constant name="CLIP_PROCESS_PHYSICS" value="0" enum="ProcessMode">
+ The camera updates with the [code]_physics_process[/code] callback.
</constant>
<constant name="CLIP_PROCESS_IDLE" value="1" enum="ProcessMode">
+ The camera updates with the [code]_process[/code] callback.
</constant>
</constants>
</class>
diff --git a/doc/classes/ColorPicker.xml b/doc/classes/ColorPicker.xml
index cd36f4fdf0..07ce76fdb2 100644
--- a/doc/classes/ColorPicker.xml
+++ b/doc/classes/ColorPicker.xml
@@ -51,8 +51,10 @@
[b]Note:[/b] Cannot be enabled if raw mode is on.
</member>
<member name="presets_enabled" type="bool" setter="set_presets_enabled" getter="are_presets_enabled" default="true">
+ If [code]true[/code], the "add preset" button is enabled.
</member>
<member name="presets_visible" type="bool" setter="set_presets_visible" getter="are_presets_visible" default="true">
+ If [code]true[/code], saved color presets are visible.
</member>
<member name="raw_mode" type="bool" setter="set_raw_mode" getter="is_raw_mode" default="false">
If [code]true[/code], allows the color R, G, B component values to go beyond 1.0, which can be used for certain special operations that require it (like tinting without darkening or rendering sprites in HDR).
diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml
index afb3977849..6d4adfad51 100644
--- a/doc/classes/Input.xml
+++ b/doc/classes/Input.xml
@@ -71,6 +71,7 @@
<return type="int" enum="Input.CursorShape">
</return>
<description>
+ Returns the currently assigned cursor shape (see [enum CursorShape]).
</description>
</method>
<method name="get_gravity" qualifiers="const">
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 7d009252c0..9657982016 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -403,19 +403,19 @@
Sets the window to full screen when it starts.
</member>
<member name="display/window/size/height" type="int" setter="" getter="" default="600">
- Sets the main window height. On desktop, this is the default window size. Stretch mode settings use this also as a reference when enabled.
+ Sets the game's main viewport height. On desktop platforms, this is the default window size. Stretch mode settings also use this as a reference when enabled.
</member>
<member name="display/window/size/resizable" type="bool" setter="" getter="" default="true">
Allows the window to be resizable by default.
</member>
<member name="display/window/size/test_height" type="int" setter="" getter="" default="0">
- If greater than zero, uses a different height for the window when running from the editor. The main use for this is to test with stretch modes.
+ If greater than zero, overrides the window height when running the game. Useful for testing stretch modes.
</member>
<member name="display/window/size/test_width" type="int" setter="" getter="" default="0">
- If greater than zero, uses a different width for the window when running from the editor. The main use for this is to test with stretch modes.
+ If greater than zero, overrides the window width when running the game. Useful for testing stretch modes.
</member>
<member name="display/window/size/width" type="int" setter="" getter="" default="1024">
- Sets the main window width. On desktop platforms, this is the default window size. Stretch mode settings use this also as a reference when enabled.
+ Sets the game's main viewport width. On desktop platforms, this is the default window size. Stretch mode settings also use this as a reference when enabled.
</member>
<member name="display/window/vsync/use_vsync" type="bool" setter="" getter="" default="true">
If [code]true[/code], enables vertical synchronization. This eliminates tearing that may appear in moving scenes, at the cost of higher input latency and stuttering at lower framerates. If [code]false[/code], vertical synchronization will be disabled, however, many platforms will enforce it regardless (such as mobile platforms and HTML5).
diff --git a/doc/classes/RigidBody.xml b/doc/classes/RigidBody.xml
index 4378fc3ffe..624b576f4d 100644
--- a/doc/classes/RigidBody.xml
+++ b/doc/classes/RigidBody.xml
@@ -88,6 +88,7 @@
<argument index="0" name="axis" type="int" enum="PhysicsServer.BodyAxis">
</argument>
<description>
+ Returns [code]true[/code] if the specified linear or rotational axis is locked.
</description>
</method>
<method name="get_colliding_bodies" qualifiers="const">
@@ -106,6 +107,7 @@
<argument index="1" name="lock" type="bool">
</argument>
<description>
+ Locks the specified linear or rotational axis.
</description>
</method>
<method name="set_axis_velocity">
@@ -183,6 +185,8 @@
The body mode. See [enum Mode] for possible values.
</member>
<member name="physics_material_override" type="PhysicsMaterial" setter="set_physics_material_override" getter="get_physics_material_override">
+ The physics material override for the body.
+ If a material is assigned to this property, it will be used instead of any other physics material, such as an inherited one.
</member>
<member name="sleeping" type="bool" setter="set_sleeping" getter="is_sleeping" default="false">
If [code]true[/code], the body is sleeping and will not calculate forces until woken up by a collision or the [code]apply_impulse[/code] method.
diff --git a/doc/classes/RigidBody2D.xml b/doc/classes/RigidBody2D.xml
index 32a1634f77..c960ef5aee 100644
--- a/doc/classes/RigidBody2D.xml
+++ b/doc/classes/RigidBody2D.xml
@@ -169,6 +169,8 @@
The body's mode. See [enum Mode] for possible values.
</member>
<member name="physics_material_override" type="PhysicsMaterial" setter="set_physics_material_override" getter="get_physics_material_override">
+ The physics material override for the body.
+ If a material is assigned to this property, it will be used instead of any other physics material, such as an inherited one.
</member>
<member name="sleeping" type="bool" setter="set_sleeping" getter="is_sleeping" default="false">
If [code]true[/code], the body is sleeping and will not calculate forces until woken up by a collision or by using [method apply_impulse] or [method add_force].
diff --git a/doc/classes/StaticBody.xml b/doc/classes/StaticBody.xml
index a9709d00df..f8840ddc14 100644
--- a/doc/classes/StaticBody.xml
+++ b/doc/classes/StaticBody.xml
@@ -28,6 +28,8 @@
Deprecated, use [member PhysicsMaterial.friction] instead via [member physics_material_override].
</member>
<member name="physics_material_override" type="PhysicsMaterial" setter="set_physics_material_override" getter="get_physics_material_override">
+ The physics material override for the body.
+ If a material is assigned to this property, it will be used instead of any other physics material, such as an inherited one.
</member>
</members>
<constants>
diff --git a/doc/classes/StaticBody2D.xml b/doc/classes/StaticBody2D.xml
index 4a7f71b667..34276ec535 100644
--- a/doc/classes/StaticBody2D.xml
+++ b/doc/classes/StaticBody2D.xml
@@ -27,6 +27,8 @@
Deprecated, use [member PhysicsMaterial.friction] instead via [member physics_material_override].
</member>
<member name="physics_material_override" type="PhysicsMaterial" setter="set_physics_material_override" getter="get_physics_material_override">
+ The physics material override for the body.
+ If a material is assigned to this property, it will be used instead of any other physics material, such as an inherited one.
</member>
</members>
<constants>
diff --git a/doc/classes/StreamPeer.xml b/doc/classes/StreamPeer.xml
index 678c587f8d..2a1919071a 100644
--- a/doc/classes/StreamPeer.xml
+++ b/doc/classes/StreamPeer.xml
@@ -211,6 +211,10 @@
</argument>
<description>
Puts a zero-terminated ASCII string into the stream prepended by a 32-bit unsigned integer representing its size.
+ Note: To put an ASCII string without prepending its size, you can use [method put_data]:
+ [codeblock]
+ put_data("Hello world".to_ascii())
+ [/codeblock]
</description>
</method>
<method name="put_u16">
@@ -256,6 +260,10 @@
</argument>
<description>
Puts a zero-terminated UTF-8 string into the stream prepended by a 32 bits unsigned integer representing its size.
+ Note: To put an UTF-8 string without prepending its size, you can use [method put_data]:
+ [codeblock]
+ put_data("Hello world".to_utf8())
+ [/codeblock]
</description>
</method>
<method name="put_var">
diff --git a/doc/classes/String.xml b/doc/classes/String.xml
index 03bc2095c0..cf152e716e 100644
--- a/doc/classes/String.xml
+++ b/doc/classes/String.xml
@@ -437,6 +437,20 @@
[/codeblock]
</description>
</method>
+ <method name="humanize_size">
+ <return type="String">
+ </return>
+ <argument index="0" name="size" type="int">
+ </argument>
+ <description>
+ Converts [code]size[/code] represented as number of bytes to human-readable format using internationalized set of data size units, namely: B, KiB, MiB, GiB, TiB, PiB, EiB. Note that the next smallest unit is picked automatically to hold at most 1024 units.
+ [codeblock]
+ var bytes = 133790307
+ var size = String.humanize_size(bytes)
+ print(size) # prints "127.5 MiB"
+ [/codeblock]
+ </description>
+ </method>
<method name="insert">
<return type="String">
</return>
diff --git a/doc/classes/TreeItem.xml b/doc/classes/TreeItem.xml
index 1ab5c58a30..a4c976591f 100644
--- a/doc/classes/TreeItem.xml
+++ b/doc/classes/TreeItem.xml
@@ -120,6 +120,15 @@
Returns the custom background color of column [code]column[/code].
</description>
</method>
+ <method name="get_custom_color" qualifiers="const">
+ <return type="Color">
+ </return>
+ <argument index="0" name="column" type="int">
+ </argument>
+ <description>
+ Returns the custom color of column [code]column[/code].
+ </description>
+ </method>
<method name="get_expand_right" qualifiers="const">
<return type="bool">
</return>
@@ -585,6 +594,15 @@
Sets the given column's tooltip text.
</description>
</method>
+ <method name="call_recursive" qualifiers="vararg">
+ <return type="Variant">
+ </return>
+ <argument index="0" name="method" type="String">
+ </argument>
+ <description>
+ Calls the [code]method[/code] on the actual TreeItem and its children recursively. Pass parameters as a comma separated list.
+ </description>
+ </method>
</methods>
<members>
<member name="collapsed" type="bool" setter="set_collapsed" getter="is_collapsed">
diff --git a/doc/classes/VideoPlayer.xml b/doc/classes/VideoPlayer.xml
index 18a85d496f..2215f26c23 100644
--- a/doc/classes/VideoPlayer.xml
+++ b/doc/classes/VideoPlayer.xml
@@ -65,6 +65,7 @@
If [code]true[/code], the video is paused.
</member>
<member name="stream" type="VideoStream" setter="set_stream" getter="get_stream">
+ The assigned video stream. See description for supported formats.
</member>
<member name="stream_position" type="float" setter="set_stream_position" getter="get_stream_position">
The current position of the stream, in seconds.
diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp
index 61bcfff419..5ed3a5f6c5 100644
--- a/drivers/gles2/rasterizer_scene_gles2.cpp
+++ b/drivers/gles2/rasterizer_scene_gles2.cpp
@@ -2905,16 +2905,10 @@ void RasterizerSceneGLES2::_post_process(Environment *env, const CameraMatrix &p
glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->depth);
glActiveTexture(GL_TEXTURE0);
- if (!storage->frame.current_rt->used_dof_blur_near) {
- if (storage->frame.current_rt->mip_maps[0].color) {
- glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].color);
- } else {
- for (int i = 0; i < storage->frame.current_rt->mip_maps[i].sizes.size(); i++) {
- glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].sizes[i].color);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, storage->frame.current_rt->mip_maps[0].sizes[i].width, storage->frame.current_rt->mip_maps[0].sizes[i].height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
- }
- glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].sizes[0].color);
- }
+ if (storage->frame.current_rt->mip_maps[0].color) {
+ glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].color);
+ } else {
+ glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].sizes[0].color);
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp
index 6faf76e395..451d6adaa9 100644
--- a/drivers/gles2/rasterizer_storage_gles2.cpp
+++ b/drivers/gles2/rasterizer_storage_gles2.cpp
@@ -5757,7 +5757,8 @@ void RasterizerStorageGLES2::initialize() {
config.multisample_supported = config.extensions.has("GL_EXT_framebuffer_multisample") || config.extensions.has("GL_EXT_multisampled_render_to_texture") || config.extensions.has("GL_APPLE_framebuffer_multisample");
#ifdef GLES_OVER_GL
- config.render_to_mipmap_supported = true;
+ //TODO: causes huge problems with desktop video drivers. Making false for now, needs to be true to render SCREEN_TEXTURE mipmaps
+ config.render_to_mipmap_supported = false;
#else
//check if mipmaps can be used for SCREEN_TEXTURE and Glow on Mobile and web platforms
config.render_to_mipmap_supported = config.extensions.has("GL_OES_fbo_render_mipmap") && config.extensions.has("GL_EXT_texture_lod");
diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp
index b2567249d8..8a03292708 100644
--- a/editor/editor_about.cpp
+++ b/editor/editor_about.cpp
@@ -141,7 +141,7 @@ EditorAbout::EditorAbout() {
hbc->add_child(about_text);
TabContainer *tc = memnew(TabContainer);
- tc->set_custom_minimum_size(Size2(630, 240) * EDSCALE);
+ tc->set_custom_minimum_size(Size2(950, 400) * EDSCALE);
tc->set_v_size_flags(Control::SIZE_EXPAND_FILL);
vbc->add_child(tc);
diff --git a/editor/editor_fonts.cpp b/editor/editor_fonts.cpp
index 55cae35a4a..b6d27d84e0 100644
--- a/editor/editor_fonts.cpp
+++ b/editor/editor_fonts.cpp
@@ -232,6 +232,7 @@ void editor_register_fonts(Ref<Theme> p_theme) {
// Default font
MAKE_DEFAULT_FONT(df, default_font_size);
p_theme->set_default_theme_font(df);
+ p_theme->set_font("main", "EditorFonts", df);
// Bold font
MAKE_BOLD_FONT(df_bold, default_font_size);
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 690b7a8ec4..460f75eef0 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -2649,6 +2649,7 @@ void EditorPropertyResource::update_property() {
if (res == RES()) {
assign->set_icon(Ref<Texture>());
assign->set_text(TTR("[empty]"));
+ assign->set_tooltip("");
} else {
assign->set_icon(EditorNode::get_singleton()->get_object_icon(res.operator->(), "Node"));
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp
index 75a7099ec4..80353bab01 100644
--- a/editor/plugins/animation_player_editor_plugin.cpp
+++ b/editor/plugins/animation_player_editor_plugin.cpp
@@ -484,6 +484,8 @@ double AnimationPlayerEditor::_get_editor_step() const {
if (track_editor->is_snap_enabled()) {
const String current = player->get_assigned_animation();
const Ref<Animation> anim = player->get_animation(current);
+ ERR_FAIL_COND_V(!anim.is_valid(), 0.0);
+
// Use more precise snapping when holding Shift
return Input::get_singleton()->is_key_pressed(KEY_SHIFT) ? anim->get_step() * 0.25 : anim->get_step();
}
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index b1e8ce20d6..7055abd643 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -2708,6 +2708,7 @@ void CanvasItemEditor::_draw_ruler_tool() {
font_secondary_color.a = 0.5;
float text_height = font->get_height();
const float text_width = 76;
+ const float angle_text_width = 54;
Point2 text_pos = (begin + end) / 2 - Vector2(text_width / 2, text_height / 2);
text_pos.x = CLAMP(text_pos.x, text_width / 2, viewport->get_rect().size.x - text_width * 1.5);
@@ -2715,14 +2716,38 @@ void CanvasItemEditor::_draw_ruler_tool() {
viewport->draw_string(font, text_pos, vformat("%.2f px", length_vector.length()), font_color);
if (draw_secondary_lines) {
+ int horizontal_axis_angle = round(180 * atan2(length_vector.y, length_vector.x) / Math_PI);
+ int vertictal_axis_angle = 90 - horizontal_axis_angle;
Point2 text_pos2 = text_pos;
text_pos2.x = begin.x < text_pos.x ? MIN(text_pos.x - text_width, begin.x - text_width / 2) : MAX(text_pos.x + text_width, begin.x - text_width / 2);
viewport->draw_string(font, text_pos2, vformat("%.2f px", length_vector.y), font_secondary_color);
+ Point2 v_angle_text_pos = Point2();
+ v_angle_text_pos.x = CLAMP(begin.x - angle_text_width / 2, angle_text_width / 2, viewport->get_rect().size.x - angle_text_width);
+ v_angle_text_pos.y = begin.y < end.y ? MIN(text_pos2.y - 2 * text_height, begin.y - text_height * 0.5) : MAX(text_pos2.y + text_height * 3, begin.y + text_height * 1.5);
+ viewport->draw_string(font, v_angle_text_pos, vformat("%d deg", vertictal_axis_angle), font_secondary_color);
+
text_pos2 = text_pos;
text_pos2.y = end.y < text_pos.y ? MIN(text_pos.y - text_height * 2, end.y - text_height / 2) : MAX(text_pos.y + text_height * 2, end.y - text_height / 2);
viewport->draw_string(font, text_pos2, vformat("%.2f px", length_vector.x), font_secondary_color);
+
+ Point2 h_angle_text_pos = Point2();
+ h_angle_text_pos.x = CLAMP(end.x - angle_text_width / 2, angle_text_width / 2, viewport->get_rect().size.x - angle_text_width);
+ if (begin.y < end.y) {
+ h_angle_text_pos.y = end.y + text_height * 1.5;
+ if (ABS(text_pos2.x - h_angle_text_pos.x) < text_width) {
+ int height_multiplier = 1.5 + (int)is_snap_active;
+ h_angle_text_pos.y = MAX(text_pos.y + height_multiplier * text_height, MAX(end.y + text_height * 1.5, text_pos2.y + height_multiplier * text_height));
+ }
+ } else {
+ h_angle_text_pos.y = end.y - text_height * 0.5;
+ if (ABS(text_pos2.x - h_angle_text_pos.x) < text_width) {
+ int height_multiplier = 1 + (int)is_snap_active;
+ h_angle_text_pos.y = MIN(text_pos.y - height_multiplier * text_height, MIN(end.y - text_height * 0.5, text_pos2.y - height_multiplier * text_height));
+ }
+ }
+ viewport->draw_string(font, h_angle_text_pos, vformat("%d deg", horizontal_axis_angle), font_secondary_color);
}
if (is_snap_active) {
@@ -5135,6 +5160,8 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
warning_child_of_container = memnew(Label);
warning_child_of_container->hide();
warning_child_of_container->set_text(TTR("Warning: Children of a container get their position and size determined only by their parent."));
+ warning_child_of_container->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("warning_color", "Editor"));
+ warning_child_of_container->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("main", "EditorFonts"));
add_control_to_info_overlay(warning_child_of_container);
h_scroll = memnew(HScrollBar);
diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp
index 127cead57f..095350d0e1 100644
--- a/editor/plugins/spatial_editor_plugin.cpp
+++ b/editor/plugins/spatial_editor_plugin.cpp
@@ -2172,7 +2172,7 @@ void SpatialEditorViewport::_notification(int p_what) {
VisualInstance *vi = Object::cast_to<VisualInstance>(sp);
- se->aabb = vi ? vi->get_aabb() : AABB(Vector3(-0.2, -0.2, -0.2), Vector3(0.4, 0.4, 0.4));
+ se->aabb = vi ? vi->get_aabb() : _calculate_spatial_bounds(sp);
Transform t = sp->get_global_gizmo_transform();
t.translate(se->aabb.position);
@@ -3209,20 +3209,35 @@ Vector3 SpatialEditorViewport::_get_instance_position(const Point2 &p_pos) const
return point + offset;
}
-AABB SpatialEditorViewport::_calculate_spatial_bounds(const Spatial *p_parent, const AABB &p_bounds) {
- AABB bounds = p_bounds;
+AABB SpatialEditorViewport::_calculate_spatial_bounds(const Spatial *p_parent, bool p_exclude_toplevel_transform) {
+ AABB bounds;
+
+ const MeshInstance *mesh_instance = Object::cast_to<MeshInstance>(p_parent);
+ if (mesh_instance) {
+ bounds = mesh_instance->get_aabb();
+ }
+
for (int i = 0; i < p_parent->get_child_count(); i++) {
Spatial *child = Object::cast_to<Spatial>(p_parent->get_child(i));
if (child) {
- MeshInstance *mesh_instance = Object::cast_to<MeshInstance>(child);
- if (mesh_instance) {
- AABB mesh_instance_bounds = mesh_instance->get_aabb();
- mesh_instance_bounds.position += mesh_instance->get_global_gizmo_transform().origin - p_parent->get_global_gizmo_transform().origin;
- bounds.merge_with(mesh_instance_bounds);
+ AABB child_bounds = _calculate_spatial_bounds(child, false);
+
+ if (bounds.size == Vector3() && p_parent->get_class_name() == StringName("Spatial")) {
+ bounds = child_bounds;
+ } else {
+ bounds.merge_with(child_bounds);
}
- bounds = _calculate_spatial_bounds(child, bounds);
}
}
+
+ if (bounds.size == Vector3() && p_parent->get_class_name() != StringName("Spatial")) {
+ bounds = AABB(Vector3(-0.2, -0.2, -0.2), Vector3(0.4, 0.4, 0.4));
+ }
+
+ if (!p_exclude_toplevel_transform) {
+ bounds = p_parent->get_transform().xform(bounds);
+ }
+
return bounds;
}
@@ -3249,7 +3264,7 @@ void SpatialEditorViewport::_create_preview(const Vector<String> &files) const {
editor->get_scene_root()->add_child(preview_node);
}
}
- *preview_bounds = _calculate_spatial_bounds(preview_node, AABB());
+ *preview_bounds = _calculate_spatial_bounds(preview_node);
}
void SpatialEditorViewport::_remove_preview() {
diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h
index 208495c2f5..fe91c33642 100644
--- a/editor/plugins/spatial_editor_plugin.h
+++ b/editor/plugins/spatial_editor_plugin.h
@@ -375,7 +375,7 @@ private:
Point2i _get_warped_mouse_motion(const Ref<InputEventMouseMotion> &p_ev_mouse_motion) const;
Vector3 _get_instance_position(const Point2 &p_pos) const;
- static AABB _calculate_spatial_bounds(const Spatial *p_parent, const AABB &p_bounds);
+ static AABB _calculate_spatial_bounds(const Spatial *p_parent, bool p_exclude_toplevel_transform = true);
void _create_preview(const Vector<String> &files) const;
void _remove_preview();
bool _cyclical_dependency_exists(const String &p_target_scene_path, Node *p_desired_node);
diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h
index 700e7cfd7d..6f77641936 100644
--- a/editor/plugins/visual_shader_editor_plugin.h
+++ b/editor/plugins/visual_shader_editor_plugin.h
@@ -137,6 +137,7 @@ class VisualShaderEditor : public VBoxContainer {
category = p_category;
sub_category = p_sub_category;
description = p_description;
+ sub_func = 0;
sub_func_str = p_sub_func;
return_type = p_return_type;
mode = p_mode;
diff --git a/editor/project_export.cpp b/editor/project_export.cpp
index c54103f6f7..7456396460 100644
--- a/editor/project_export.cpp
+++ b/editor/project_export.cpp
@@ -1149,11 +1149,15 @@ ProjectExportDialog::ProjectExportDialog() {
include_files->connect("item_edited", this, "_tree_changed");
include_filters = memnew(LineEdit);
- resources_vb->add_margin_child(TTR("Filters to export non-resource files (comma separated, e.g: *.json, *.txt)"), include_filters);
+ resources_vb->add_margin_child(
+ TTR("Filters to export non-resource files/folders\n(comma-separated, e.g: *.json, *.txt, docs/*)"),
+ include_filters);
include_filters->connect("text_changed", this, "_filter_changed");
exclude_filters = memnew(LineEdit);
- resources_vb->add_margin_child(TTR("Filters to exclude files from project (comma separated, e.g: *.json, *.txt)"), exclude_filters);
+ resources_vb->add_margin_child(
+ TTR("Filters to exclude files/folders from project\n(comma-separated, e.g: *.json, *.txt, docs/*)"),
+ exclude_filters);
exclude_filters->connect("text_changed", this, "_filter_changed");
VBoxContainer *patch_vb = memnew(VBoxContainer);
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index a56cfede34..f177e634a6 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -74,6 +74,26 @@ static const char *_axis_names[JOY_AXIS_MAX * 2] = {
"", " (R2)"
};
+void ProjectSettingsEditor::_unhandled_input(const Ref<InputEvent> &p_event) {
+
+ const Ref<InputEventKey> k = p_event;
+
+ if (k.is_valid() && is_window_modal_on_top() && k->is_pressed()) {
+
+ if (k->get_scancode_with_modifiers() == (KEY_MASK_CMD | KEY_F)) {
+ if (search_button->is_pressed()) {
+ search_box->grab_focus();
+ search_box->select_all();
+ } else {
+ // This toggles the search bar display while giving the button its "pressed" appearance
+ search_button->set_pressed(true);
+ }
+
+ accept_event();
+ }
+ }
+}
+
void ProjectSettingsEditor::_notification(int p_what) {
switch (p_what) {
@@ -116,6 +136,7 @@ void ProjectSettingsEditor::_notification(int p_what) {
} break;
case NOTIFICATION_POPUP_HIDE: {
EditorSettings::get_singleton()->set_project_metadata("dialog_bounds", "project_settings", get_rect());
+ set_process_unhandled_input(false);
} break;
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
search_button->set_icon(get_icon("Search", "EditorIcons"));
@@ -800,6 +821,7 @@ void ProjectSettingsEditor::popup_project_settings() {
_update_translations();
autoload_settings->update_autoload();
plugin_settings->update_plugins();
+ set_process_unhandled_input(true);
}
void ProjectSettingsEditor::update_plugins() {
@@ -1697,6 +1719,7 @@ void ProjectSettingsEditor::_editor_restart_close() {
void ProjectSettingsEditor::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_unhandled_input"), &ProjectSettingsEditor::_unhandled_input);
ClassDB::bind_method(D_METHOD("_item_selected"), &ProjectSettingsEditor::_item_selected);
ClassDB::bind_method(D_METHOD("_item_add"), &ProjectSettingsEditor::_item_add);
ClassDB::bind_method(D_METHOD("_item_adds"), &ProjectSettingsEditor::_item_adds);
diff --git a/editor/project_settings_editor.h b/editor/project_settings_editor.h
index 4dfd8ba602..c164b49d0e 100644
--- a/editor/project_settings_editor.h
+++ b/editor/project_settings_editor.h
@@ -178,6 +178,7 @@ class ProjectSettingsEditor : public AcceptDialog {
void _editor_restart_close();
protected:
+ void _unhandled_input(const Ref<InputEvent> &p_event);
void _notification(int p_what);
static void _bind_methods();
diff --git a/editor/settings_config_dialog.cpp b/editor/settings_config_dialog.cpp
index c9c1f9c3e0..f8425ebe22 100644
--- a/editor/settings_config_dialog.cpp
+++ b/editor/settings_config_dialog.cpp
@@ -140,32 +140,35 @@ void EditorSettingsDialog::_notification(int p_what) {
void EditorSettingsDialog::_unhandled_input(const Ref<InputEvent> &p_event) {
- Ref<InputEventKey> k = p_event;
+ const Ref<InputEventKey> k = p_event;
- if (k.is_valid() && is_window_modal_on_top()) {
+ if (k.is_valid() && is_window_modal_on_top() && k->is_pressed()) {
- if (k->is_pressed()) {
+ bool handled = false;
- bool handled = false;
+ if (ED_IS_SHORTCUT("editor/undo", p_event)) {
+ String action = undo_redo->get_current_action_name();
+ if (action != "")
+ EditorNode::get_log()->add_message("Undo: " + action, EditorLog::MSG_TYPE_EDITOR);
+ undo_redo->undo();
+ handled = true;
+ }
- if (ED_IS_SHORTCUT("editor/undo", p_event)) {
- String action = undo_redo->get_current_action_name();
- if (action != "")
- EditorNode::get_log()->add_message("Undo: " + action, EditorLog::MSG_TYPE_EDITOR);
- undo_redo->undo();
- handled = true;
- }
- if (ED_IS_SHORTCUT("editor/redo", p_event)) {
- undo_redo->redo();
- String action = undo_redo->get_current_action_name();
- if (action != "")
- EditorNode::get_log()->add_message("Redo: " + action, EditorLog::MSG_TYPE_EDITOR);
- handled = true;
- }
+ if (ED_IS_SHORTCUT("editor/redo", p_event)) {
+ undo_redo->redo();
+ String action = undo_redo->get_current_action_name();
+ if (action != "")
+ EditorNode::get_log()->add_message("Redo: " + action, EditorLog::MSG_TYPE_EDITOR);
+ handled = true;
+ }
- if (handled) {
- accept_event();
- }
+ if (k->get_scancode_with_modifiers() == (KEY_MASK_CMD | KEY_F)) {
+ _focus_current_search_box();
+ handled = true;
+ }
+
+ if (handled) {
+ accept_event();
}
}
}
@@ -408,7 +411,6 @@ EditorSettingsDialog::EditorSettingsDialog() {
tabs->set_tab_align(TabContainer::ALIGN_LEFT);
tabs->connect("tab_changed", this, "_tabs_tab_changed");
add_child(tabs);
- //set_child_rect(tabs);
// General Tab
@@ -425,7 +427,6 @@ EditorSettingsDialog::EditorSettingsDialog() {
hbc->add_child(search_box);
inspector = memnew(SectionedInspector);
- //inspector->hide_top_label();
inspector->get_inspector()->set_use_filter(true);
inspector->register_search_box(search_box);
inspector->set_v_size_flags(Control::SIZE_EXPAND_FILL);
@@ -474,7 +475,6 @@ EditorSettingsDialog::EditorSettingsDialog() {
shortcuts->set_v_size_flags(SIZE_EXPAND_FILL);
shortcuts->set_columns(2);
shortcuts->set_hide_root(true);
- //shortcuts->set_hide_folding(true);
shortcuts->set_column_titles_visible(true);
shortcuts->set_column_title(0, TTR("Name"));
shortcuts->set_column_title(1, TTR("Binding"));
@@ -495,9 +495,7 @@ EditorSettingsDialog::EditorSettingsDialog() {
press_a_key->connect("gui_input", this, "_wait_for_key");
press_a_key->connect("confirmed", this, "_press_a_key_confirm");
- //get_ok()->set_text("Apply");
set_hide_on_ok(true);
- //get_cancel()->set_text("Close");
timer = memnew(Timer);
timer->set_wait_time(1.5);
diff --git a/main/main.cpp b/main/main.cpp
index 6df02af3a5..42c90fc027 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -982,10 +982,13 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
video_mode.height = GLOBAL_GET("display/window/size/height");
if (globals->has_setting("display/window/size/test_width") && globals->has_setting("display/window/size/test_height")) {
+
int tw = globals->get("display/window/size/test_width");
- int th = globals->get("display/window/size/test_height");
- if (tw > 0 && th > 0) {
+ if (tw > 0) {
video_mode.width = tw;
+ }
+ int th = globals->get("display/window/size/test_height");
+ if (th > 0) {
video_mode.height = th;
}
}
diff --git a/modules/gdnative/doc_classes/GDNativeLibrary.xml b/modules/gdnative/doc_classes/GDNativeLibrary.xml
index 7e1cac243a..ae9a00543c 100644
--- a/modules/gdnative/doc_classes/GDNativeLibrary.xml
+++ b/modules/gdnative/doc_classes/GDNativeLibrary.xml
@@ -1,35 +1,50 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="GDNativeLibrary" inherits="Resource" category="Core" version="3.2">
<brief_description>
+ An external library containing functions or script classes to use in Godot.
</brief_description>
<description>
+ A GDNative library can implement [NativeScript]s, global functions to call with the [GDNative] class, or low-level engine extensions through interfaces such as [ARVRInterfaceGDNative]. The library must be compiled for each platform and architecture that the project will run on.
</description>
<tutorials>
+ <link>https://docs.godotengine.org/en/latest/tutorials/plugins/gdnative/gdnative-c-example.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/plugins/gdnative/gdnative-cpp-example.html</link>
</tutorials>
<methods>
<method name="get_current_dependencies" qualifiers="const">
<return type="PoolStringArray">
</return>
<description>
+ Returns paths to all dependency libraries for the current platform and architecture.
</description>
</method>
<method name="get_current_library_path" qualifiers="const">
<return type="String">
</return>
<description>
+ Returns the path to the dynamic library file for the current platform and architecture.
</description>
</method>
</methods>
<members>
<member name="config_file" type="ConfigFile" setter="set_config_file" getter="get_config_file">
+ This resource in INI-style [ConfigFile] format, as in [code].gdnlib[/code] files.
</member>
<member name="load_once" type="bool" setter="set_load_once" getter="should_load_once" default="true">
+ If [code]true[/code], Godot loads only one copy of the library and each script that references the library will share static data like static or global variables.
+ If [code]false[/code], Godot loads a separate copy of the library into memory for each script that references it.
</member>
<member name="reloadable" type="bool" setter="set_reloadable" getter="is_reloadable" default="true">
+ If [code]true[/code], the editor will temporarily unload the library whenever the user switches away from the editor window, allowing the user to recompile the library without restarting Godot.
+ [b]Note:[/b] If the library defines tool scripts that run inside the editor, [code]reloadable[/code] must be [code]false[/code]. Otherwise, the editor will attempt to unload the tool scripts while they're in use and crash.
</member>
<member name="singleton" type="bool" setter="set_singleton" getter="is_singleton" default="false">
+ If [code]true[/code], Godot loads the library at startup rather than the first time a script uses the library, calling [code]gdnative_singleton[/code] after initializing the library. The library remains loaded as long as Godot is running.
+ [b]Note:[/b] A singleton library cannot be [member reloadable].
</member>
<member name="symbol_prefix" type="String" setter="set_symbol_prefix" getter="get_symbol_prefix" default="&quot;godot_&quot;">
+ The prefix this library's entry point functions begin with. For example, a GDNativeLibrary would declare its [code]gdnative_init[/code] function as [code]godot_gdnative_init[/code] by default.
+ On platforms that require statically linking libraries (currently only iOS), each library must have a different [code]symbol_prefix[/code].
</member>
</members>
<constants>
diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp
index bdeea9cef3..83d02e4977 100644
--- a/modules/gdscript/gdscript_function.cpp
+++ b/modules/gdscript/gdscript_function.cpp
@@ -1419,7 +1419,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
if (!container->iter_init(*counter, valid)) {
#ifdef DEBUG_ENABLED
if (!valid) {
- err_text = "Unable to iterate on object of type " + Variant::get_type_name(container->get_type()) + "'.";
+ err_text = "Unable to iterate on object of type '" + Variant::get_type_name(container->get_type()) + "'.";
OPCODE_BREAK;
}
#endif
@@ -1432,7 +1432,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
*iterator = container->iter_get(*counter, valid);
#ifdef DEBUG_ENABLED
if (!valid) {
- err_text = "Unable to obtain iterator object of type " + Variant::get_type_name(container->get_type()) + "'.";
+ err_text = "Unable to obtain iterator object of type '" + Variant::get_type_name(container->get_type()) + "'.";
OPCODE_BREAK;
}
#endif
@@ -1452,7 +1452,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
if (!container->iter_next(*counter, valid)) {
#ifdef DEBUG_ENABLED
if (!valid) {
- err_text = "Unable to iterate on object of type " + Variant::get_type_name(container->get_type()) + "' (type changed since first iteration?).";
+ err_text = "Unable to iterate on object of type '" + Variant::get_type_name(container->get_type()) + "' (type changed since first iteration?).";
OPCODE_BREAK;
}
#endif
@@ -1465,7 +1465,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
*iterator = container->iter_get(*counter, valid);
#ifdef DEBUG_ENABLED
if (!valid) {
- err_text = "Unable to obtain iterator object of type " + Variant::get_type_name(container->get_type()) + "' (but was obtained on first iteration?).";
+ err_text = "Unable to obtain iterator object of type '" + Variant::get_type_name(container->get_type()) + "' (but was obtained on first iteration?).";
OPCODE_BREAK;
}
#endif
diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp
index ae44137fef..03d731a5f0 100644
--- a/modules/gdscript/language_server/gdscript_extend_parser.cpp
+++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp
@@ -157,7 +157,7 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p
r_symbol.selectionRange.start.line = r_symbol.range.start.line;
r_symbol.detail = "class " + r_symbol.name;
bool is_root_class = &r_symbol == &class_symbol;
- r_symbol.documentation = parse_documentation_as_markdown(is_root_class ? 0 : LINE_NUMBER_TO_INDEX(p_class->line), is_root_class);
+ r_symbol.documentation = parse_documentation(is_root_class ? 0 : LINE_NUMBER_TO_INDEX(p_class->line), is_root_class);
for (int i = 0; i < p_class->variables.size(); ++i) {
@@ -184,7 +184,7 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p
symbol.detail += " = " + JSON::print(m.default_value);
}
- symbol.documentation = parse_documentation_as_markdown(line);
+ symbol.documentation = parse_documentation(line);
symbol.uri = uri;
symbol.script_path = path;
@@ -204,7 +204,7 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p
symbol.range.end.line = symbol.range.start.line;
symbol.range.end.character = lines[line].length();
symbol.selectionRange.start.line = symbol.range.start.line;
- symbol.documentation = parse_documentation_as_markdown(line);
+ symbol.documentation = parse_documentation(line);
symbol.uri = uri;
symbol.script_path = path;
symbol.detail = "signal " + signal.name + "(";
@@ -233,7 +233,7 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p
symbol.range.end.line = symbol.range.start.line;
symbol.range.end.character = lines[line].length();
symbol.selectionRange.start.line = symbol.range.start.line;
- symbol.documentation = parse_documentation_as_markdown(line);
+ symbol.documentation = parse_documentation(line);
symbol.uri = uri;
symbol.script_path = path;
@@ -301,7 +301,7 @@ void ExtendGDScriptParser::parse_function_symbol(const GDScriptParser::FunctionN
r_symbol.range.end.line = MAX(p_func->body->end_line - 2, p_func->body->line);
r_symbol.range.end.character = lines[r_symbol.range.end.line].length();
r_symbol.selectionRange.start.line = r_symbol.range.start.line;
- r_symbol.documentation = parse_documentation_as_markdown(line);
+ r_symbol.documentation = parse_documentation(line);
r_symbol.uri = uri;
r_symbol.script_path = path;
@@ -359,65 +359,11 @@ void ExtendGDScriptParser::parse_function_symbol(const GDScriptParser::FunctionN
if (var->datatype.kind != GDScriptParser::DataType::UNRESOLVED) {
symbol.detail += ": " + var->datatype.to_string();
}
- symbol.documentation = parse_documentation_as_markdown(line);
+ symbol.documentation = parse_documentation(line);
r_symbol.children.push_back(symbol);
}
}
-String ExtendGDScriptParser::marked_documentation(const String &p_bbcode) {
-
- String markdown = p_bbcode.strip_edges();
-
- Vector<String> lines = markdown.split("\n");
- bool in_code_block = false;
- int code_block_indent = -1;
-
- markdown = "";
- for (int i = 0; i < lines.size(); i++) {
- String line = lines[i];
- int block_start = line.find("[codeblock]");
- if (block_start != -1) {
- code_block_indent = block_start;
- in_code_block = true;
- line = "\n";
- } else if (in_code_block) {
- line = "\t" + line.substr(code_block_indent, line.length());
- }
-
- if (in_code_block && line.find("[/codeblock]") != -1) {
- line = "\n";
- in_code_block = false;
- }
-
- if (!in_code_block) {
- line = line.strip_edges();
- line = line.replace("[code]", "`");
- line = line.replace("[/code]", "`");
- line = line.replace("[i]", "*");
- line = line.replace("[/i]", "*");
- line = line.replace("[b]", "**");
- line = line.replace("[/b]", "**");
- line = line.replace("[u]", "__");
- line = line.replace("[/u]", "__");
- line = line.replace("[method ", "`");
- line = line.replace("[member ", "`");
- line = line.replace("[signal ", "`");
- line = line.replace("[enum ", "`");
- line = line.replace("[constant ", "`");
- line = line.replace("[", "`");
- line = line.replace("]", "`");
- }
-
- if (!in_code_block && i < lines.size() - 1) {
- line += "\n\n";
- } else if (i < lines.size() - 1) {
- line += "\n";
- }
- markdown += line;
- }
- return markdown;
-}
-
String ExtendGDScriptParser::parse_documentation(int p_line, bool p_docs_down) {
ERR_FAIL_INDEX_V(p_line, lines.size(), String());
@@ -576,10 +522,6 @@ const lsp::DocumentSymbol *ExtendGDScriptParser::search_symbol_defined_at_line(i
return ret;
}
-String ExtendGDScriptParser::parse_documentation_as_markdown(int p_line, bool p_docs_down) {
- return marked_documentation(parse_documentation(p_line, p_docs_down));
-}
-
const lsp::DocumentSymbol *ExtendGDScriptParser::get_symbol_defined_at_line(int p_line) const {
if (p_line <= 0) {
return &class_symbol;
diff --git a/modules/gdscript/language_server/gdscript_extend_parser.h b/modules/gdscript/language_server/gdscript_extend_parser.h
index 71db78c245..a6e0ca5534 100644
--- a/modules/gdscript/language_server/gdscript_extend_parser.h
+++ b/modules/gdscript/language_server/gdscript_extend_parser.h
@@ -75,11 +75,6 @@ class ExtendGDScriptParser : public GDScriptParser {
Array member_completions;
- String parse_documentation_as_markdown(int p_line, bool p_docs_down = false);
-
-public:
- static String marked_documentation(const String &p_bbcode);
-
public:
_FORCE_INLINE_ const String &get_path() const { return path; }
_FORCE_INLINE_ const Vector<String> &get_lines() const { return lines; }
diff --git a/modules/gdscript/language_server/gdscript_language_protocol.cpp b/modules/gdscript/language_server/gdscript_language_protocol.cpp
index ce3de9bc3b..ae2aaf6aee 100644
--- a/modules/gdscript/language_server/gdscript_language_protocol.cpp
+++ b/modules/gdscript/language_server/gdscript_language_protocol.cpp
@@ -153,7 +153,13 @@ Error GDScriptLanguageProtocol::start(int p_port) {
}
void GDScriptLanguageProtocol::stop() {
+ const int *ptr = clients.next(NULL);
+ while (ptr) {
+ clients.get(*ptr)->close();
+ ptr = clients.next(ptr);
+ }
server->stop();
+ clients.clear();
}
void GDScriptLanguageProtocol::notify_all_clients(const String &p_method, const Variant &p_params) {
diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp
index f51f3671dd..b83db718b8 100644
--- a/modules/gdscript/language_server/gdscript_text_document.cpp
+++ b/modules/gdscript/language_server/gdscript_text_document.cpp
@@ -39,6 +39,7 @@
void GDScriptTextDocument::_bind_methods() {
ClassDB::bind_method(D_METHOD("didOpen"), &GDScriptTextDocument::didOpen);
ClassDB::bind_method(D_METHOD("didChange"), &GDScriptTextDocument::didChange);
+ ClassDB::bind_method(D_METHOD("nativeSymbol"), &GDScriptTextDocument::nativeSymbol);
ClassDB::bind_method(D_METHOD("documentSymbol"), &GDScriptTextDocument::documentSymbol);
ClassDB::bind_method(D_METHOD("completion"), &GDScriptTextDocument::completion);
ClassDB::bind_method(D_METHOD("resolve"), &GDScriptTextDocument::resolve);
@@ -75,6 +76,11 @@ lsp::TextDocumentItem GDScriptTextDocument::load_document_item(const Variant &p_
return doc;
}
+void GDScriptTextDocument::notify_client_show_symbol(const lsp::DocumentSymbol *symbol) {
+ ERR_FAIL_NULL(symbol);
+ GDScriptLanguageProtocol::get_singleton()->notify_client("gdscript/show_native_symbol", symbol->to_json(true));
+}
+
void GDScriptTextDocument::initialize() {
if (GDScriptLanguageProtocol::get_singleton()->is_smart_resolve_enabled()) {
@@ -102,6 +108,21 @@ void GDScriptTextDocument::initialize() {
}
}
+Variant GDScriptTextDocument::nativeSymbol(const Dictionary &p_params) {
+
+ Variant ret;
+
+ lsp::NativeSymbolInspectParams params;
+ params.load(p_params);
+
+ if (const lsp::DocumentSymbol *symbol = GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_native_symbol(params)) {
+ ret = symbol->to_json(true);
+ notify_client_show_symbol(symbol);
+ }
+
+ return ret;
+}
+
Array GDScriptTextDocument::documentSymbol(const Dictionary &p_params) {
Dictionary params = p_params["textDocument"];
String uri = params["uri"];
@@ -335,31 +356,35 @@ Array GDScriptTextDocument::definition(const Dictionary &p_params) {
const String &path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(symbol->uri);
if (file_checker->file_exists(path)) {
arr.push_back(location.to_json());
- } else if (!symbol->native_class.empty() && GDScriptLanguageProtocol::get_singleton()->is_goto_native_symbols_enabled()) {
- String id;
- switch (symbol->kind) {
- case lsp::SymbolKind::Class:
- id = "class_name:" + symbol->name;
- break;
- case lsp::SymbolKind::Constant:
- id = "class_constant:" + symbol->native_class + ":" + symbol->name;
- break;
- case lsp::SymbolKind::Property:
- case lsp::SymbolKind::Variable:
- id = "class_property:" + symbol->native_class + ":" + symbol->name;
- break;
- case lsp::SymbolKind::Enum:
- id = "class_enum:" + symbol->native_class + ":" + symbol->name;
- break;
- case lsp::SymbolKind::Method:
- case lsp::SymbolKind::Function:
- id = "class_method:" + symbol->native_class + ":" + symbol->name;
- break;
- default:
- id = "class_global:" + symbol->native_class + ":" + symbol->name;
- break;
+ } else if (!symbol->native_class.empty()) {
+ if (GDScriptLanguageProtocol::get_singleton()->is_goto_native_symbols_enabled()) {
+ String id;
+ switch (symbol->kind) {
+ case lsp::SymbolKind::Class:
+ id = "class_name:" + symbol->name;
+ break;
+ case lsp::SymbolKind::Constant:
+ id = "class_constant:" + symbol->native_class + ":" + symbol->name;
+ break;
+ case lsp::SymbolKind::Property:
+ case lsp::SymbolKind::Variable:
+ id = "class_property:" + symbol->native_class + ":" + symbol->name;
+ break;
+ case lsp::SymbolKind::Enum:
+ id = "class_enum:" + symbol->native_class + ":" + symbol->name;
+ break;
+ case lsp::SymbolKind::Method:
+ case lsp::SymbolKind::Function:
+ id = "class_method:" + symbol->native_class + ":" + symbol->name;
+ break;
+ default:
+ id = "class_global:" + symbol->native_class + ":" + symbol->name;
+ break;
+ }
+ call_deferred("show_native_symbol_in_editor", id);
+ } else {
+ notify_client_show_symbol(symbol);
}
- call_deferred("show_native_symbol_in_editor", id);
}
} else if (GDScriptLanguageProtocol::get_singleton()->is_smart_resolve_enabled()) {
diff --git a/modules/gdscript/language_server/gdscript_text_document.h b/modules/gdscript/language_server/gdscript_text_document.h
index 0b8103f175..235e2c3f6e 100644
--- a/modules/gdscript/language_server/gdscript_text_document.h
+++ b/modules/gdscript/language_server/gdscript_text_document.h
@@ -52,8 +52,10 @@ protected:
private:
lsp::TextDocumentItem load_document_item(const Variant &p_param);
+ void notify_client_show_symbol(const lsp::DocumentSymbol *symbol);
public:
+ Variant nativeSymbol(const Dictionary &p_params);
Array documentSymbol(const Dictionary &p_params);
Array completion(const Dictionary &p_params);
Dictionary resolve(const Dictionary &p_params);
diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp
index b42464aa8a..6baa7e4219 100644
--- a/modules/gdscript/language_server/gdscript_workspace.cpp
+++ b/modules/gdscript/language_server/gdscript_workspace.cpp
@@ -198,7 +198,7 @@ Error GDScriptWorkspace::initialize() {
if (!class_data.inherits.empty()) {
class_symbol.detail += " extends " + class_data.inherits;
}
- class_symbol.documentation = ExtendGDScriptParser::marked_documentation(class_data.brief_description) + "\n" + ExtendGDScriptParser::marked_documentation(class_data.description);
+ class_symbol.documentation = class_data.brief_description + "\n" + class_data.description;
for (int i = 0; i < class_data.constants.size(); i++) {
const DocData::ConstantDoc &const_data = class_data.constants[i];
@@ -211,7 +211,7 @@ Error GDScriptWorkspace::initialize() {
symbol.detail += ": " + const_data.enumeration;
}
symbol.detail += " = " + const_data.value;
- symbol.documentation = ExtendGDScriptParser::marked_documentation(const_data.description);
+ symbol.documentation = const_data.description;
class_symbol.children.push_back(symbol);
}
@@ -232,7 +232,7 @@ Error GDScriptWorkspace::initialize() {
} else {
symbol.detail += ": " + data.type;
}
- symbol.documentation = ExtendGDScriptParser::marked_documentation(data.description);
+ symbol.documentation = data.description;
class_symbol.children.push_back(symbol);
}
@@ -270,7 +270,7 @@ Error GDScriptWorkspace::initialize() {
}
symbol.detail = "func " + class_name + "." + data.name + "(" + params + ") -> " + data.return_type;
- symbol.documentation = ExtendGDScriptParser::marked_documentation(data.description);
+ symbol.documentation = data.description;
class_symbol.children.push_back(symbol);
}
@@ -475,6 +475,24 @@ void GDScriptWorkspace::resolve_related_symbols(const lsp::TextDocumentPositionP
}
}
+const lsp::DocumentSymbol *GDScriptWorkspace::resolve_native_symbol(const lsp::NativeSymbolInspectParams &p_params) {
+
+ if (Map<StringName, lsp::DocumentSymbol>::Element *E = native_symbols.find(p_params.native_class)) {
+ const lsp::DocumentSymbol &symbol = E->get();
+ if (p_params.symbol_name.empty() || p_params.symbol_name == symbol.name) {
+ return &symbol;
+ }
+
+ for (int i = 0; i < symbol.children.size(); ++i) {
+ if (symbol.children[i].name == p_params.symbol_name) {
+ return &(symbol.children[i]);
+ }
+ }
+ }
+
+ return NULL;
+}
+
void GDScriptWorkspace::resolve_document_links(const String &p_uri, List<lsp::DocumentLink> &r_list) {
if (const ExtendGDScriptParser *parser = get_parse_successed_script(get_file_path(p_uri))) {
const List<lsp::DocumentLink> &links = parser->get_document_links();
diff --git a/modules/gdscript/language_server/gdscript_workspace.h b/modules/gdscript/language_server/gdscript_workspace.h
index 23e89ea3f3..a416ae1075 100644
--- a/modules/gdscript/language_server/gdscript_workspace.h
+++ b/modules/gdscript/language_server/gdscript_workspace.h
@@ -80,7 +80,7 @@ public:
const lsp::DocumentSymbol *resolve_symbol(const lsp::TextDocumentPositionParams &p_doc_pos, const String &p_symbol_name = "", bool p_func_requred = false);
void resolve_related_symbols(const lsp::TextDocumentPositionParams &p_doc_pos, List<const lsp::DocumentSymbol *> &r_list);
-
+ const lsp::DocumentSymbol *resolve_native_symbol(const lsp::NativeSymbolInspectParams &p_params);
void resolve_document_links(const String &p_uri, List<lsp::DocumentLink> &r_list);
Dictionary generate_script_api(const String &p_path);
diff --git a/modules/gdscript/language_server/lsp.hpp b/modules/gdscript/language_server/lsp.hpp
index e60e28cc15..61a0980c41 100644
--- a/modules/gdscript/language_server/lsp.hpp
+++ b/modules/gdscript/language_server/lsp.hpp
@@ -37,6 +37,9 @@ namespace lsp {
typedef String DocumentUri;
+/** Format BBCode documentation from DocData to markdown */
+static String marked_documentation(const String &p_bbcode);
+
/**
* Text documents are identified using a URI. On the protocol level, URIs are passed as strings.
*/
@@ -282,6 +285,9 @@ struct Command {
}
};
+// Use namespace instead of enumeration to follow the LSP specifications
+// lsp::EnumName::EnumValue is OK but lsp::EnumValue is not
+
namespace TextDocumentSyncKind {
/**
* Documents should not be synced at all.
@@ -592,6 +598,7 @@ struct TextDocumentContentChangeEvent {
}
};
+// Use namespace instead of enumeration to follow the LSP specifications
namespace DiagnosticSeverity {
/**
* Reports an error.
@@ -692,6 +699,7 @@ struct Diagnostic {
}
};
+// Use namespace instead of enumeration to follow the LSP specifications
/**
* Describes the content type that a client supports in various
* result literals like `Hover`, `ParameterInfo` or `CompletionItem`.
@@ -756,6 +764,9 @@ struct MarkupContent {
}
};
+// Use namespace instead of enumeration to follow the LSP specifications
+// lsp::EnumName::EnumValue is OK but lsp::EnumValue is not
+// And here C++ compilers are unhappy with our enumeration name like Color, File, Reference etc.
/**
* The kind of a completion entry.
*/
@@ -787,6 +798,7 @@ static const int Operator = 24;
static const int TypeParameter = 25;
}; // namespace CompletionItemKind
+// Use namespace instead of enumeration to follow the LSP specifications
/**
* Defines whether the insert text in a completion item should be interpreted as
* plain text or a snippet.
@@ -979,36 +991,39 @@ struct CompletionList {
Vector<CompletionItem> items;
};
+// Use namespace instead of enumeration to follow the LSP specifications
+// lsp::EnumName::EnumValue is OK but lsp::EnumValue is not
+// And here C++ compilers are unhappy with our enumeration name like String, Array, Object etc
/**
* A symbol kind.
*/
namespace SymbolKind {
-static const int File = 1;
-static const int Module = 2;
-static const int Namespace = 3;
-static const int Package = 4;
-static const int Class = 5;
-static const int Method = 6;
-static const int Property = 7;
-static const int Field = 8;
-static const int Constructor = 9;
-static const int Enum = 10;
-static const int Interface = 11;
-static const int Function = 12;
-static const int Variable = 13;
-static const int Constant = 14;
-static const int String = 15;
-static const int Number = 16;
-static const int Boolean = 17;
-static const int Array = 18;
-static const int Object = 19;
-static const int Key = 20;
-static const int Null = 21;
-static const int EnumMember = 22;
-static const int Struct = 23;
-static const int Event = 24;
-static const int Operator = 25;
-static const int TypeParameter = 26;
+static const int File = 0;
+static const int Module = 1;
+static const int Namespace = 2;
+static const int Package = 3;
+static const int Class = 4;
+static const int Method = 5;
+static const int Property = 6;
+static const int Field = 7;
+static const int Constructor = 8;
+static const int Enum = 9;
+static const int Interface = 10;
+static const int Function = 11;
+static const int Variable = 12;
+static const int Constant = 13;
+static const int String = 14;
+static const int Number = 15;
+static const int Boolean = 16;
+static const int Array = 17;
+static const int Object = 18;
+static const int Key = 19;
+static const int Null = 20;
+static const int EnumMember = 21;
+static const int Struct = 22;
+static const int Event = 23;
+static const int Operator = 24;
+static const int TypeParameter = 25;
}; // namespace SymbolKind
/**
@@ -1134,7 +1149,7 @@ struct DocumentSymbol {
*/
Vector<DocumentSymbol> children;
- _FORCE_INLINE_ Dictionary to_json() const {
+ Dictionary to_json(bool with_doc = false) const {
Dictionary dict;
dict["name"] = name;
dict["detail"] = detail;
@@ -1142,10 +1157,14 @@ struct DocumentSymbol {
dict["deprecated"] = deprecated;
dict["range"] = range.to_json();
dict["selectionRange"] = selectionRange.to_json();
+ if (with_doc) {
+ dict["documentation"] = documentation;
+ dict["native_class"] = native_class;
+ }
Array arr;
arr.resize(children.size());
for (int i = 0; i < children.size(); i++) {
- arr[i] = children[i].to_json();
+ arr[i] = children[i].to_json(with_doc);
}
dict["children"] = arr;
return dict;
@@ -1177,7 +1196,7 @@ struct DocumentSymbol {
markdown.value = "\t" + detail + "\n\n";
}
if (documentation.length()) {
- markdown.value += documentation + "\n\n";
+ markdown.value += marked_documentation(documentation) + "\n\n";
}
if (script_path.length()) {
markdown.value += "Defined in [" + script_path + "](" + uri + ")";
@@ -1229,6 +1248,17 @@ struct DocumentSymbol {
}
};
+struct NativeSymbolInspectParams {
+
+ String native_class;
+ String symbol_name;
+
+ void load(const Dictionary &p_params) {
+ native_class = p_params["native_class"];
+ symbol_name = p_params["symbol_name"];
+ }
+};
+
/**
* Enum of known range kinds
*/
@@ -1289,6 +1319,7 @@ struct FoldingRange {
}
};
+// Use namespace instead of enumeration to follow the LSP specifications
/**
* How a completion was triggered
*/
@@ -1536,6 +1567,61 @@ struct InitializeResult {
}
};
+/** Format BBCode documentation from DocData to markdown */
+static String marked_documentation(const String &p_bbcode) {
+
+ String markdown = p_bbcode.strip_edges();
+
+ Vector<String> lines = markdown.split("\n");
+ bool in_code_block = false;
+ int code_block_indent = -1;
+
+ markdown = "";
+ for (int i = 0; i < lines.size(); i++) {
+ String line = lines[i];
+ int block_start = line.find("[codeblock]");
+ if (block_start != -1) {
+ code_block_indent = block_start;
+ in_code_block = true;
+ line = "\n";
+ } else if (in_code_block) {
+ line = "\t" + line.substr(code_block_indent, line.length());
+ }
+
+ if (in_code_block && line.find("[/codeblock]") != -1) {
+ line = "\n";
+ in_code_block = false;
+ }
+
+ if (!in_code_block) {
+ line = line.strip_edges();
+ line = line.replace("[code]", "`");
+ line = line.replace("[/code]", "`");
+ line = line.replace("[i]", "*");
+ line = line.replace("[/i]", "*");
+ line = line.replace("[b]", "**");
+ line = line.replace("[/b]", "**");
+ line = line.replace("[u]", "__");
+ line = line.replace("[/u]", "__");
+ line = line.replace("[method ", "`");
+ line = line.replace("[member ", "`");
+ line = line.replace("[signal ", "`");
+ line = line.replace("[enum ", "`");
+ line = line.replace("[constant ", "`");
+ line = line.replace("[", "`");
+ line = line.replace("]", "`");
+ }
+
+ if (!in_code_block && i < lines.size() - 1) {
+ line += "\n\n";
+ } else if (i < lines.size() - 1) {
+ line += "\n";
+ }
+ markdown += line;
+ }
+ return markdown;
+}
+
} // namespace lsp
#endif
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 2bfdfd7d02..c9ba51bafb 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -1050,6 +1050,7 @@ void TileMap::update_dirty_bitmask() {
void TileMap::fix_invalid_tiles() {
+ ERR_FAIL_COND_MSG(tile_set.is_null(), "Cannot fix invalid tiles if Tileset is not open.");
for (Map<PosKey, Cell>::Element *E = tile_map.front(); E; E = E->next()) {
if (!tile_set->has_tile(get_cell(E->key().x, E->key().y))) {
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index fc67b28095..fafbcf0c55 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -1412,6 +1412,9 @@ void Control::_size_changed() {
}
void Control::set_anchor(Margin p_margin, float p_anchor, bool p_keep_margin, bool p_push_opposite_anchor) {
+
+ ERR_FAIL_INDEX((int)p_margin, 4);
+
Rect2 parent_rect = get_parent_anchorable_rect();
float parent_range = (p_margin == MARGIN_LEFT || p_margin == MARGIN_RIGHT) ? parent_rect.size.x : parent_rect.size.y;
float previous_margin_pos = data.margin[p_margin] + data.anchor[p_margin] * parent_range;
@@ -1456,6 +1459,9 @@ void Control::set_anchor_and_margin(Margin p_margin, float p_anchor, float p_pos
}
void Control::set_anchors_preset(LayoutPreset p_preset, bool p_keep_margins) {
+
+ ERR_FAIL_INDEX((int)p_preset, 16);
+
//Left
switch (p_preset) {
case PRESET_TOP_LEFT:
@@ -1570,6 +1576,10 @@ void Control::set_anchors_preset(LayoutPreset p_preset, bool p_keep_margins) {
}
void Control::set_margins_preset(LayoutPreset p_preset, LayoutPresetMode p_resize_mode, int p_margin) {
+
+ ERR_FAIL_INDEX((int)p_preset, 16);
+ ERR_FAIL_INDEX((int)p_resize_mode, 4);
+
// Calculate the size if the node is not resized
Size2 min_size = get_minimum_size();
Size2 new_size = get_size();
@@ -1704,6 +1714,8 @@ void Control::set_anchors_and_margins_preset(LayoutPreset p_preset, LayoutPreset
float Control::get_anchor(Margin p_margin) const {
+ ERR_FAIL_INDEX_V(int(p_margin), 4, 0.0);
+
return data.anchor[p_margin];
}
@@ -1720,6 +1732,8 @@ void Control::_change_notify_margins() {
void Control::set_margin(Margin p_margin, float p_value) {
+ ERR_FAIL_INDEX((int)p_margin, 4);
+
data.margin[p_margin] = p_value;
_size_changed();
}
@@ -1740,6 +1754,8 @@ void Control::set_end(const Size2 &p_point) {
float Control::get_margin(Margin p_margin) const {
+ ERR_FAIL_INDEX_V((int)p_margin, 4, 0);
+
return data.margin[p_margin];
}
@@ -1951,6 +1967,8 @@ void Control::add_constant_override(const StringName &p_name, int p_constant) {
void Control::set_focus_mode(FocusMode p_focus_mode) {
+ ERR_FAIL_INDEX((int)p_focus_mode, 3);
+
if (is_inside_tree() && p_focus_mode == FOCUS_NONE && data.focus_mode != FOCUS_NONE && has_focus())
release_focus();
@@ -2298,6 +2316,8 @@ Control *Control::make_custom_tooltip(const String &p_text) const {
void Control::set_default_cursor_shape(CursorShape p_shape) {
+ ERR_FAIL_INDEX(int(p_shape), CURSOR_MAX);
+
data.default_cursor = p_shape;
}
@@ -2358,6 +2378,8 @@ NodePath Control::get_focus_previous() const {
Control *Control::_get_focus_neighbour(Margin p_margin, int p_count) {
+ ERR_FAIL_INDEX_V((int)p_margin, 4, NULL);
+
if (p_count >= MAX_NEIGHBOUR_SEARCH_COUNT)
return NULL;
if (!data.focus_neighbour[p_margin].is_empty()) {
@@ -2760,6 +2782,8 @@ bool Control::is_clipping_contents() {
void Control::set_h_grow_direction(GrowDirection p_direction) {
+ ERR_FAIL_INDEX((int)p_direction, 3);
+
data.h_grow = p_direction;
_size_changed();
}
@@ -2771,6 +2795,8 @@ Control::GrowDirection Control::get_h_grow_direction() const {
void Control::set_v_grow_direction(GrowDirection p_direction) {
+ ERR_FAIL_INDEX((int)p_direction, 3);
+
data.v_grow = p_direction;
_size_changed();
}
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index 9bc593ea3b..24c046457b 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -637,6 +637,8 @@ bool FileDialog::is_mode_overriding_title() const {
void FileDialog::set_mode(Mode p_mode) {
+ ERR_FAIL_INDEX((int)p_mode, 5);
+
mode = p_mode;
switch (mode) {
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index a3bc68ffcd..4d06bee0d4 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -430,6 +430,7 @@ ItemList::SelectMode ItemList::get_select_mode() const {
void ItemList::set_icon_mode(IconMode p_mode) {
+ ERR_FAIL_INDEX((int)p_mode, 2);
icon_mode = p_mode;
update();
shape_changed = true;
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index c5330c78e1..42cb89b2d6 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -143,6 +143,8 @@ Rect2 RichTextLabel::_get_text_rect() {
int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &y, int p_width, int p_line, ProcessMode p_mode, const Ref<Font> &p_base_font, const Color &p_base_color, const Color &p_font_color_shadow, bool p_shadow_as_outline, const Point2 &shadow_ofs, const Point2i &p_click_pos, Item **r_click_item, int *r_click_char, bool *r_outside, int p_char_count) {
+ ERR_FAIL_INDEX_V((int)p_mode, 3, 0);
+
RID ci;
if (r_outside)
*r_outside = false;
@@ -1416,6 +1418,9 @@ bool RichTextLabel::_find_strikethrough(Item *p_item) {
}
bool RichTextLabel::_find_by_type(Item *p_item, ItemType p_type) {
+
+ ERR_FAIL_INDEX_V((int)p_type, 19, false);
+
Item *item = p_item;
while (item) {
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 50b0b12029..c9d1295557 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -729,6 +729,43 @@ bool TreeItem::is_folding_disabled() const {
return disable_folding;
}
+Variant TreeItem::_call_recursive_bind(const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
+
+ if (p_argcount < 1) {
+ r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 0;
+ return Variant();
+ }
+
+ if (p_args[0]->get_type() != Variant::STRING) {
+ r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::STRING;
+ return Variant();
+ }
+
+ StringName method = *p_args[0];
+
+ call_recursive(method, &p_args[1], p_argcount - 1, r_error);
+ return Variant();
+}
+
+void recursive_call_aux(TreeItem *p_item, const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
+ if (!p_item) {
+ return;
+ }
+ p_item->call(p_method, p_args, p_argcount, r_error);
+ TreeItem *c = p_item->get_children();
+ while (c) {
+ recursive_call_aux(c, p_method, p_args, p_argcount, r_error);
+ c = c->get_next();
+ }
+}
+
+void TreeItem::call_recursive(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
+ recursive_call_aux(this, p_method, p_args, p_argcount, r_error);
+}
+
void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_cell_mode", "column", "mode"), &TreeItem::set_cell_mode);
@@ -790,6 +827,7 @@ void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_custom_color", "column", "color"), &TreeItem::set_custom_color);
ClassDB::bind_method(D_METHOD("clear_custom_color", "column"), &TreeItem::clear_custom_color);
+ ClassDB::bind_method(D_METHOD("get_custom_color", "column"), &TreeItem::get_custom_color);
ClassDB::bind_method(D_METHOD("set_custom_bg_color", "column", "color", "just_outline"), &TreeItem::set_custom_bg_color, DEFVAL(false));
ClassDB::bind_method(D_METHOD("clear_custom_bg_color", "column"), &TreeItem::clear_custom_bg_color);
@@ -820,6 +858,14 @@ void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_disable_folding", "disable"), &TreeItem::set_disable_folding);
ClassDB::bind_method(D_METHOD("is_folding_disabled"), &TreeItem::is_folding_disabled);
+ {
+ MethodInfo mi;
+ mi.name = "call_recursive";
+ mi.arguments.push_back(PropertyInfo(Variant::STRING, "method"));
+
+ ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "call_recursive", &TreeItem::_call_recursive_bind, mi);
+ }
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collapsed"), "set_collapsed", "is_collapsed");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_folding"), "set_disable_folding", "is_folding_disabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "custom_minimum_height", PROPERTY_HINT_RANGE, "0,1000,1"), "set_custom_minimum_height", "get_custom_minimum_height");
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index 47befb0c15..361830173b 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -172,6 +172,8 @@ protected:
remove_child(Object::cast_to<TreeItem>(p_child));
}
+ Variant _call_recursive_bind(const Variant **p_args, int p_argcount, Variant::CallError &r_error);
+
public:
/* cell mode */
void set_cell_mode(int p_column, TreeCellMode p_mode);
@@ -280,6 +282,8 @@ public:
void set_disable_folding(bool p_disable);
bool is_folding_disabled() const;
+ void call_recursive(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error);
+
~TreeItem();
};
diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp
index 3b549afb02..ae99d64eee 100644
--- a/servers/visual/shader_language.cpp
+++ b/servers/visual/shader_language.cpp
@@ -2914,6 +2914,16 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
bool ok = _parse_function_arguments(p_block, p_builtin_types, func, &carg);
+ // Check if block has a variable with the same name as function to prevent shader crash.
+ ShaderLanguage::BlockNode *bnode = p_block;
+ while (bnode) {
+ if (bnode->variables.has(name)) {
+ _set_error("Expected function name");
+ return NULL;
+ }
+ bnode = bnode->parent_block;
+ }
+
//test if function was parsed first
for (int i = 0; i < shader->functions.size(); i++) {
if (shader->functions[i].name == name) {
@@ -3842,9 +3852,12 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
}
StringName name = tk.text;
- if (_find_identifier(p_block, p_builtin_types, name)) {
- _set_error("Redefinition of '" + String(name) + "'");
- return ERR_PARSE_ERROR;
+ ShaderLanguage::IdentifierType itype;
+ if (_find_identifier(p_block, p_builtin_types, name, (ShaderLanguage::DataType *)0, &itype)) {
+ if (itype != IDENTIFIER_FUNCTION) {
+ _set_error("Redefinition of '" + String(name) + "'");
+ return ERR_PARSE_ERROR;
+ }
}
BlockNode::Variable var;
@@ -4002,6 +4015,11 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
return ERR_PARSE_ERROR;
}
+ if (node->is_const && n->type == Node::TYPE_OPERATOR && ((OperatorNode *)n)->op == OP_CALL) {
+ _set_error("Expected constant expression");
+ return ERR_PARSE_ERROR;
+ }
+
if (var.type != n->get_datatype()) {
_set_error("Invalid assignment of '" + get_datatype_name(n->get_datatype()) + "' to '" + get_datatype_name(var.type) + "'");
return ERR_PARSE_ERROR;
@@ -4062,7 +4080,10 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
if (!n)
return ERR_PARSE_ERROR;
-
+ if (node->is_const && n->type == Node::TYPE_OPERATOR && ((OperatorNode *)n)->op == OP_CALL) {
+ _set_error("Expected constant expression after '='");
+ return ERR_PARSE_ERROR;
+ }
decl.initializer = n;
if (var.type != n->get_datatype()) {
@@ -5121,9 +5142,12 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
pname = tk.text;
- if (_find_identifier(func_node->body, builtin_types, pname)) {
- _set_error("Redefinition of '" + String(pname) + "'");
- return ERR_PARSE_ERROR;
+ ShaderLanguage::IdentifierType itype;
+ if (_find_identifier(func_node->body, builtin_types, pname, (ShaderLanguage::DataType *)0, &itype)) {
+ if (itype != IDENTIFIER_FUNCTION) {
+ _set_error("Redefinition of '" + String(pname) + "'");
+ return ERR_PARSE_ERROR;
+ }
}
FunctionNode::Argument arg;
arg.type = ptype;