summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--SConstruct18
-rw-r--r--core/variant/variant.cpp224
-rw-r--r--core/variant/variant.h9
-rw-r--r--core/variant/variant_parser.cpp25
-rw-r--r--core/variant/variant_parser.h4
-rw-r--r--doc/classes/TabBar.xml16
-rw-r--r--doc/classes/TabContainer.xml16
-rw-r--r--doc/classes/WorkerThreadPool.xml4
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp2
-rw-r--r--editor/editor_dock_manager.cpp1
-rw-r--r--editor/editor_inspector.cpp7
-rw-r--r--editor/editor_settings.cpp33
-rw-r--r--editor/editor_settings.h2
-rw-r--r--main/main.cpp8
-rw-r--r--modules/gdscript/editor/gdscript_docgen.cpp48
-rw-r--r--modules/gdscript/editor/gdscript_docgen.h1
-rw-r--r--modules/gdscript/tests/README.md7
-rw-r--r--modules/gdscript/tests/scripts/completion/argument_options/argument_options.tscn3
-rw-r--r--modules/gdscript/tests/scripts/completion/argument_options/connect.cfg8
-rw-r--r--modules/gdscript/tests/scripts/completion/argument_options/connect.gd7
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal/dollar.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal/percent.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local/local.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_interfered/local_interfered.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/class_local_interfered_scene.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/native_local_interfered_scene.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.notest.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.notest.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member/member.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_interfered/member_interfered.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/class_member_interfered_scene.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/native_member_interfered_scene.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.gd1
-rw-r--r--modules/gdscript/tests/test_completion.h52
-rw-r--r--modules/multiplayer/scene_cache_interface.cpp38
-rw-r--r--modules/multiplayer/scene_cache_interface.h3
-rw-r--r--platform/windows/rendering_context_driver_vulkan_windows.h2
-rw-r--r--scene/2d/line_builder.cpp15
-rw-r--r--scene/gui/tab_bar.cpp29
-rw-r--r--scene/gui/tab_bar.h7
-rw-r--r--scene/gui/tab_container.cpp18
-rw-r--r--scene/gui/tab_container.h3
-rw-r--r--scene/resources/resource_format_text.cpp36
-rw-r--r--scene/resources/resource_format_text.h2
-rw-r--r--servers/rendering/renderer_canvas_cull.cpp2
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp2
-rw-r--r--servers/rendering/rendering_device.cpp17
-rw-r--r--tests/core/io/test_resource.h5
69 files changed, 487 insertions, 221 deletions
diff --git a/SConstruct b/SConstruct
index 260e6bb48a..05e69c431d 100644
--- a/SConstruct
+++ b/SConstruct
@@ -13,6 +13,10 @@ import time
from types import ModuleType
from collections import OrderedDict
from importlib.util import spec_from_file_location, module_from_spec
+from SCons import __version__ as scons_raw_version
+from SCons.Script.SConscript import SConsEnvironment
+
+scons_ver = SConsEnvironment._get_major_minor_revision(scons_raw_version)
# Explicitly resolve the helper modules, this is done to avoid clash with
# modules of the same name that might be randomly added (e.g. someone adding
@@ -168,7 +172,11 @@ if profile:
opts = Variables(customs, ARGUMENTS)
# Target build options
-opts.Add(["platform", "p"], "Target platform (%s)" % "|".join(platform_list), "")
+if scons_ver >= (4, 3):
+ opts.Add(["platform", "p"], "Target platform (%s)" % "|".join(platform_list), "")
+else:
+ opts.Add("platform", "Target platform (%s)" % "|".join(platform_list), "")
+ opts.Add("p", "Alias for 'platform'", "")
opts.Add(EnumVariable("target", "Compilation target", "editor", ("editor", "template_release", "template_debug")))
opts.Add(EnumVariable("arch", "CPU architecture", "auto", ["auto"] + architectures, architecture_aliases))
opts.Add(BoolVariable("dev_build", "Developer build with dev-only debugging code (DEV_ENABLED)", False))
@@ -286,6 +294,9 @@ if env["import_env_vars"]:
selected_platform = env["platform"]
+if scons_ver < (4, 3) and not selected_platform:
+ selected_platform = env["p"]
+
if selected_platform == "":
# Missing `platform` argument, try to detect platform automatically
if (
@@ -972,11 +983,6 @@ if env["vsproj"]:
env.vs_incs = []
env.vs_srcs = []
-# CompileDB and Ninja are only available with certain SCons versions which
-# not everybody might have yet, so we have to check.
-from SCons import __version__ as scons_raw_version
-
-scons_ver = env._get_major_minor_revision(scons_raw_version)
if env["compiledb"] and scons_ver < (4, 0, 0):
# Generating the compilation DB (`compile_commands.json`) requires SCons 4.0.0 or later.
print("The `compiledb=yes` option requires SCons 4.0 or later, but your version is %s." % scons_raw_version)
diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp
index 155a5b2781..8e702ce8bb 100644
--- a/core/variant/variant.cpp
+++ b/core/variant/variant.cpp
@@ -2373,184 +2373,183 @@ Variant::operator IPAddress() const {
return IPAddress(operator String());
}
-Variant::Variant(bool p_bool) {
- type = BOOL;
+Variant::Variant(bool p_bool) :
+ type(BOOL) {
_data._bool = p_bool;
}
-Variant::Variant(int64_t p_int64) {
- type = INT;
+Variant::Variant(int64_t p_int64) :
+ type(INT) {
_data._int = p_int64;
}
-Variant::Variant(int32_t p_int32) {
- type = INT;
+Variant::Variant(int32_t p_int32) :
+ type(INT) {
_data._int = p_int32;
}
-Variant::Variant(int16_t p_int16) {
- type = INT;
+Variant::Variant(int16_t p_int16) :
+ type(INT) {
_data._int = p_int16;
}
-Variant::Variant(int8_t p_int8) {
- type = INT;
+Variant::Variant(int8_t p_int8) :
+ type(INT) {
_data._int = p_int8;
}
-Variant::Variant(uint64_t p_uint64) {
- type = INT;
+Variant::Variant(uint64_t p_uint64) :
+ type(INT) {
_data._int = p_uint64;
}
-Variant::Variant(uint32_t p_uint32) {
- type = INT;
+Variant::Variant(uint32_t p_uint32) :
+ type(INT) {
_data._int = p_uint32;
}
-Variant::Variant(uint16_t p_uint16) {
- type = INT;
+Variant::Variant(uint16_t p_uint16) :
+ type(INT) {
_data._int = p_uint16;
}
-Variant::Variant(uint8_t p_uint8) {
- type = INT;
+Variant::Variant(uint8_t p_uint8) :
+ type(INT) {
_data._int = p_uint8;
}
-Variant::Variant(float p_float) {
- type = FLOAT;
+Variant::Variant(float p_float) :
+ type(FLOAT) {
_data._float = p_float;
}
-Variant::Variant(double p_double) {
- type = FLOAT;
+Variant::Variant(double p_double) :
+ type(FLOAT) {
_data._float = p_double;
}
-Variant::Variant(const ObjectID &p_id) {
- type = INT;
+Variant::Variant(const ObjectID &p_id) :
+ type(INT) {
_data._int = p_id;
}
-Variant::Variant(const StringName &p_string) {
- type = STRING_NAME;
+Variant::Variant(const StringName &p_string) :
+ type(STRING_NAME) {
memnew_placement(_data._mem, StringName(p_string));
}
-Variant::Variant(const String &p_string) {
- type = STRING;
+Variant::Variant(const String &p_string) :
+ type(STRING) {
memnew_placement(_data._mem, String(p_string));
}
-Variant::Variant(const char *const p_cstring) {
- type = STRING;
+Variant::Variant(const char *const p_cstring) :
+ type(STRING) {
memnew_placement(_data._mem, String((const char *)p_cstring));
}
-Variant::Variant(const char32_t *p_wstring) {
- type = STRING;
+Variant::Variant(const char32_t *p_wstring) :
+ type(STRING) {
memnew_placement(_data._mem, String(p_wstring));
}
-Variant::Variant(const Vector3 &p_vector3) {
- type = VECTOR3;
+Variant::Variant(const Vector3 &p_vector3) :
+ type(VECTOR3) {
memnew_placement(_data._mem, Vector3(p_vector3));
}
-Variant::Variant(const Vector3i &p_vector3i) {
- type = VECTOR3I;
+Variant::Variant(const Vector3i &p_vector3i) :
+ type(VECTOR3I) {
memnew_placement(_data._mem, Vector3i(p_vector3i));
}
-Variant::Variant(const Vector4 &p_vector4) {
- type = VECTOR4;
+Variant::Variant(const Vector4 &p_vector4) :
+ type(VECTOR4) {
memnew_placement(_data._mem, Vector4(p_vector4));
}
-Variant::Variant(const Vector4i &p_vector4i) {
- type = VECTOR4I;
+Variant::Variant(const Vector4i &p_vector4i) :
+ type(VECTOR4I) {
memnew_placement(_data._mem, Vector4i(p_vector4i));
}
-Variant::Variant(const Vector2 &p_vector2) {
- type = VECTOR2;
+Variant::Variant(const Vector2 &p_vector2) :
+ type(VECTOR2) {
memnew_placement(_data._mem, Vector2(p_vector2));
}
-Variant::Variant(const Vector2i &p_vector2i) {
- type = VECTOR2I;
+Variant::Variant(const Vector2i &p_vector2i) :
+ type(VECTOR2I) {
memnew_placement(_data._mem, Vector2i(p_vector2i));
}
-Variant::Variant(const Rect2 &p_rect2) {
- type = RECT2;
+Variant::Variant(const Rect2 &p_rect2) :
+ type(RECT2) {
memnew_placement(_data._mem, Rect2(p_rect2));
}
-Variant::Variant(const Rect2i &p_rect2i) {
- type = RECT2I;
+Variant::Variant(const Rect2i &p_rect2i) :
+ type(RECT2I) {
memnew_placement(_data._mem, Rect2i(p_rect2i));
}
-Variant::Variant(const Plane &p_plane) {
- type = PLANE;
+Variant::Variant(const Plane &p_plane) :
+ type(PLANE) {
memnew_placement(_data._mem, Plane(p_plane));
}
-Variant::Variant(const ::AABB &p_aabb) {
- type = AABB;
+Variant::Variant(const ::AABB &p_aabb) :
+ type(AABB) {
_data._aabb = (::AABB *)Pools::_bucket_small.alloc();
memnew_placement(_data._aabb, ::AABB(p_aabb));
}
-Variant::Variant(const Basis &p_matrix) {
- type = BASIS;
+Variant::Variant(const Basis &p_matrix) :
+ type(BASIS) {
_data._basis = (Basis *)Pools::_bucket_medium.alloc();
memnew_placement(_data._basis, Basis(p_matrix));
}
-Variant::Variant(const Quaternion &p_quaternion) {
- type = QUATERNION;
+Variant::Variant(const Quaternion &p_quaternion) :
+ type(QUATERNION) {
memnew_placement(_data._mem, Quaternion(p_quaternion));
}
-Variant::Variant(const Transform3D &p_transform) {
- type = TRANSFORM3D;
+Variant::Variant(const Transform3D &p_transform) :
+ type(TRANSFORM3D) {
_data._transform3d = (Transform3D *)Pools::_bucket_medium.alloc();
memnew_placement(_data._transform3d, Transform3D(p_transform));
}
-Variant::Variant(const Projection &pp_projection) {
- type = PROJECTION;
+Variant::Variant(const Projection &pp_projection) :
+ type(PROJECTION) {
_data._projection = (Projection *)Pools::_bucket_large.alloc();
memnew_placement(_data._projection, Projection(pp_projection));
}
-Variant::Variant(const Transform2D &p_transform) {
- type = TRANSFORM2D;
+Variant::Variant(const Transform2D &p_transform) :
+ type(TRANSFORM2D) {
_data._transform2d = (Transform2D *)Pools::_bucket_small.alloc();
memnew_placement(_data._transform2d, Transform2D(p_transform));
}
-Variant::Variant(const Color &p_color) {
- type = COLOR;
+Variant::Variant(const Color &p_color) :
+ type(COLOR) {
memnew_placement(_data._mem, Color(p_color));
}
-Variant::Variant(const NodePath &p_node_path) {
- type = NODE_PATH;
+Variant::Variant(const NodePath &p_node_path) :
+ type(NODE_PATH) {
memnew_placement(_data._mem, NodePath(p_node_path));
}
-Variant::Variant(const ::RID &p_rid) {
- type = RID;
+Variant::Variant(const ::RID &p_rid) :
+ type(RID) {
memnew_placement(_data._mem, ::RID(p_rid));
}
-Variant::Variant(const Object *p_object) {
- type = OBJECT;
-
+Variant::Variant(const Object *p_object) :
+ type(OBJECT) {
memnew_placement(_data._mem, ObjData);
if (p_object) {
@@ -2571,76 +2570,74 @@ Variant::Variant(const Object *p_object) {
}
}
-Variant::Variant(const Callable &p_callable) {
- type = CALLABLE;
+Variant::Variant(const Callable &p_callable) :
+ type(CALLABLE) {
memnew_placement(_data._mem, Callable(p_callable));
}
-Variant::Variant(const Signal &p_callable) {
- type = SIGNAL;
+Variant::Variant(const Signal &p_callable) :
+ type(SIGNAL) {
memnew_placement(_data._mem, Signal(p_callable));
}
-Variant::Variant(const Dictionary &p_dictionary) {
- type = DICTIONARY;
+Variant::Variant(const Dictionary &p_dictionary) :
+ type(DICTIONARY) {
memnew_placement(_data._mem, Dictionary(p_dictionary));
}
-Variant::Variant(const Array &p_array) {
- type = ARRAY;
+Variant::Variant(const Array &p_array) :
+ type(ARRAY) {
memnew_placement(_data._mem, Array(p_array));
}
-Variant::Variant(const PackedByteArray &p_byte_array) {
- type = PACKED_BYTE_ARRAY;
-
+Variant::Variant(const PackedByteArray &p_byte_array) :
+ type(PACKED_BYTE_ARRAY) {
_data.packed_array = PackedArrayRef<uint8_t>::create(p_byte_array);
}
-Variant::Variant(const PackedInt32Array &p_int32_array) {
- type = PACKED_INT32_ARRAY;
+Variant::Variant(const PackedInt32Array &p_int32_array) :
+ type(PACKED_INT32_ARRAY) {
_data.packed_array = PackedArrayRef<int32_t>::create(p_int32_array);
}
-Variant::Variant(const PackedInt64Array &p_int64_array) {
- type = PACKED_INT64_ARRAY;
+Variant::Variant(const PackedInt64Array &p_int64_array) :
+ type(PACKED_INT64_ARRAY) {
_data.packed_array = PackedArrayRef<int64_t>::create(p_int64_array);
}
-Variant::Variant(const PackedFloat32Array &p_float32_array) {
- type = PACKED_FLOAT32_ARRAY;
+Variant::Variant(const PackedFloat32Array &p_float32_array) :
+ type(PACKED_FLOAT32_ARRAY) {
_data.packed_array = PackedArrayRef<float>::create(p_float32_array);
}
-Variant::Variant(const PackedFloat64Array &p_float64_array) {
- type = PACKED_FLOAT64_ARRAY;
+Variant::Variant(const PackedFloat64Array &p_float64_array) :
+ type(PACKED_FLOAT64_ARRAY) {
_data.packed_array = PackedArrayRef<double>::create(p_float64_array);
}
-Variant::Variant(const PackedStringArray &p_string_array) {
- type = PACKED_STRING_ARRAY;
+Variant::Variant(const PackedStringArray &p_string_array) :
+ type(PACKED_STRING_ARRAY) {
_data.packed_array = PackedArrayRef<String>::create(p_string_array);
}
-Variant::Variant(const PackedVector2Array &p_vector2_array) {
- type = PACKED_VECTOR2_ARRAY;
+Variant::Variant(const PackedVector2Array &p_vector2_array) :
+ type(PACKED_VECTOR2_ARRAY) {
_data.packed_array = PackedArrayRef<Vector2>::create(p_vector2_array);
}
-Variant::Variant(const PackedVector3Array &p_vector3_array) {
- type = PACKED_VECTOR3_ARRAY;
+Variant::Variant(const PackedVector3Array &p_vector3_array) :
+ type(PACKED_VECTOR3_ARRAY) {
_data.packed_array = PackedArrayRef<Vector3>::create(p_vector3_array);
}
-Variant::Variant(const PackedColorArray &p_color_array) {
- type = PACKED_COLOR_ARRAY;
+Variant::Variant(const PackedColorArray &p_color_array) :
+ type(PACKED_COLOR_ARRAY) {
_data.packed_array = PackedArrayRef<Color>::create(p_color_array);
}
/* helpers */
-Variant::Variant(const Vector<::RID> &p_array) {
- type = ARRAY;
-
+Variant::Variant(const Vector<::RID> &p_array) :
+ type(ARRAY) {
Array *rid_array = memnew_placement(_data._mem, Array);
rid_array->resize(p_array.size());
@@ -2650,9 +2647,8 @@ Variant::Variant(const Vector<::RID> &p_array) {
}
}
-Variant::Variant(const Vector<Plane> &p_array) {
- type = ARRAY;
-
+Variant::Variant(const Vector<Plane> &p_array) :
+ type(ARRAY) {
Array *plane_array = memnew_placement(_data._mem, Array);
plane_array->resize(p_array.size());
@@ -2662,7 +2658,8 @@ Variant::Variant(const Vector<Plane> &p_array) {
}
}
-Variant::Variant(const Vector<Face3> &p_face_array) {
+Variant::Variant(const Vector<Face3> &p_face_array) :
+ type(NIL) {
PackedVector3Array vertices;
int face_count = p_face_array.size();
vertices.resize(face_count * 3);
@@ -2678,13 +2675,11 @@ Variant::Variant(const Vector<Face3> &p_face_array) {
}
}
- type = NIL;
-
*this = vertices;
}
-Variant::Variant(const Vector<Variant> &p_array) {
- type = NIL;
+Variant::Variant(const Vector<Variant> &p_array) :
+ type(NIL) {
Array arr;
arr.resize(p_array.size());
for (int i = 0; i < p_array.size(); i++) {
@@ -2693,8 +2688,8 @@ Variant::Variant(const Vector<Variant> &p_array) {
*this = arr;
}
-Variant::Variant(const Vector<StringName> &p_array) {
- type = NIL;
+Variant::Variant(const Vector<StringName> &p_array) :
+ type(NIL) {
PackedStringArray v;
int len = p_array.size();
v.resize(len);
@@ -2863,12 +2858,13 @@ void Variant::operator=(const Variant &p_variant) {
}
}
-Variant::Variant(const IPAddress &p_address) {
- type = STRING;
+Variant::Variant(const IPAddress &p_address) :
+ type(STRING) {
memnew_placement(_data._mem, String(p_address));
}
-Variant::Variant(const Variant &p_variant) {
+Variant::Variant(const Variant &p_variant) :
+ type(NIL) {
reference(p_variant);
}
diff --git a/core/variant/variant.h b/core/variant/variant.h
index 10f8dc3c7f..e40df3171f 100644
--- a/core/variant/variant.h
+++ b/core/variant/variant.h
@@ -165,7 +165,7 @@ private:
// Variant takes 20 bytes when real_t is float, and 36 if double
// it only allocates extra memory for aabb/matrix.
- Type type = NIL;
+ Type type;
struct ObjData {
ObjectID id;
@@ -483,8 +483,8 @@ public:
Variant(const IPAddress &p_address);
#define VARIANT_ENUM_CLASS_CONSTRUCTOR(m_enum) \
- Variant(m_enum p_value) { \
- type = INT; \
+ Variant(m_enum p_value) : \
+ type(INT) { \
_data._int = (int64_t)p_value; \
}
@@ -788,7 +788,8 @@ public:
static void unregister_types();
Variant(const Variant &p_variant);
- _FORCE_INLINE_ Variant() {}
+ _FORCE_INLINE_ Variant() :
+ type(NIL) {}
_FORCE_INLINE_ ~Variant() {
clear();
}
diff --git a/core/variant/variant_parser.cpp b/core/variant/variant_parser.cpp
index 06daaab6a2..50f8007efa 100644
--- a/core/variant/variant_parser.cpp
+++ b/core/variant/variant_parser.cpp
@@ -1789,7 +1789,7 @@ static String rtos_fix(double p_value) {
}
}
-Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, int p_recursion_count) {
+Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, int p_recursion_count, bool p_compat) {
switch (p_variant.get_type()) {
case Variant::NIL: {
p_store_string_func(p_store_string_ud, "null");
@@ -2009,7 +2009,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
}
p_store_string_func(p_store_string_ud, "\"" + E.name + "\":");
- write(obj->get(E.name), p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count);
+ write(obj->get(E.name), p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count, p_compat);
}
}
@@ -2035,9 +2035,9 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
p_store_string_func(p_store_string_ud, "{\n");
for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
- write(E->get(), p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count);
+ write(E->get(), p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count, p_compat);
p_store_string_func(p_store_string_ud, ": ");
- write(dict[E->get()], p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count);
+ write(dict[E->get()], p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count, p_compat);
if (E->next()) {
p_store_string_func(p_store_string_ud, ",\n");
} else {
@@ -2096,7 +2096,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
} else {
p_store_string_func(p_store_string_ud, ", ");
}
- write(var, p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count);
+ write(var, p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count, p_compat);
}
p_store_string_func(p_store_string_ud, "]");
@@ -2110,7 +2110,16 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
case Variant::PACKED_BYTE_ARRAY: {
p_store_string_func(p_store_string_ud, "PackedByteArray(");
Vector<uint8_t> data = p_variant;
- if (data.size() > 0) {
+ if (p_compat) {
+ int len = data.size();
+ const uint8_t *ptr = data.ptr();
+ for (int i = 0; i < len; i++) {
+ if (i > 0) {
+ p_store_string_func(p_store_string_ud, ", ");
+ }
+ p_store_string_func(p_store_string_ud, itos(ptr[i]));
+ }
+ } else if (data.size() > 0) {
p_store_string_func(p_store_string_ud, "\"");
p_store_string_func(p_store_string_ud, CryptoCore::b64_encode_str(data.ptr(), data.size()));
p_store_string_func(p_store_string_ud, "\"");
@@ -2255,8 +2264,8 @@ static Error _write_to_str(void *ud, const String &p_string) {
return OK;
}
-Error VariantWriter::write_to_string(const Variant &p_variant, String &r_string, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud) {
+Error VariantWriter::write_to_string(const Variant &p_variant, String &r_string, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, bool p_compat) {
r_string = String();
- return write(p_variant, _write_to_str, &r_string, p_encode_res_func, p_encode_res_ud);
+ return write(p_variant, _write_to_str, &r_string, p_encode_res_func, p_encode_res_ud, 0, p_compat);
}
diff --git a/core/variant/variant_parser.h b/core/variant/variant_parser.h
index 2f8974849f..b0ac07170d 100644
--- a/core/variant/variant_parser.h
+++ b/core/variant/variant_parser.h
@@ -161,8 +161,8 @@ public:
typedef Error (*StoreStringFunc)(void *ud, const String &p_string);
typedef String (*EncodeResourceFunc)(void *ud, const Ref<Resource> &p_resource);
- static Error write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, int p_recursion_count = 0);
- static Error write_to_string(const Variant &p_variant, String &r_string, EncodeResourceFunc p_encode_res_func = nullptr, void *p_encode_res_ud = nullptr);
+ static Error write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, int p_recursion_count = 0, bool p_compat = true);
+ static Error write_to_string(const Variant &p_variant, String &r_string, EncodeResourceFunc p_encode_res_func = nullptr, void *p_encode_res_ud = nullptr, bool p_compat = true);
};
#endif // VARIANT_PARSER_H
diff --git a/doc/classes/TabBar.xml b/doc/classes/TabBar.xml
index a2beef81eb..d080294c1a 100644
--- a/doc/classes/TabBar.xml
+++ b/doc/classes/TabBar.xml
@@ -111,6 +111,13 @@
Returns the title of the tab at index [param tab_idx].
</description>
</method>
+ <method name="get_tab_tooltip" qualifiers="const">
+ <return type="String" />
+ <param index="0" name="tab_idx" type="int" />
+ <description>
+ Returns the tooltip text of the tab at index [param tab_idx].
+ </description>
+ </method>
<method name="is_tab_disabled" qualifiers="const">
<return type="bool" />
<param index="0" name="tab_idx" type="int" />
@@ -224,6 +231,15 @@
Sets a [param title] for the tab at index [param tab_idx].
</description>
</method>
+ <method name="set_tab_tooltip">
+ <return type="void" />
+ <param index="0" name="tab_idx" type="int" />
+ <param index="1" name="tooltip" type="String" />
+ <description>
+ Sets a [param tooltip] for tab at index [param tab_idx].
+ [b]Note:[/b] By default, if the [param tooltip] is empty and the tab text is truncated (not all characters fit into the tab), the title will be displayed as a tooltip. To hide the tooltip, assign [code]" "[/code] as the [param tooltip] text.
+ </description>
+ </method>
</methods>
<members>
<member name="clip_tabs" type="bool" setter="set_clip_tabs" getter="get_clip_tabs" default="true">
diff --git a/doc/classes/TabContainer.xml b/doc/classes/TabContainer.xml
index b0e3f67791..f4d69c3076 100644
--- a/doc/classes/TabContainer.xml
+++ b/doc/classes/TabContainer.xml
@@ -92,6 +92,13 @@
Returns the title of the tab at index [param tab_idx]. Tab titles default to the name of the indexed child node, but this can be overridden with [method set_tab_title].
</description>
</method>
+ <method name="get_tab_tooltip" qualifiers="const">
+ <return type="String" />
+ <param index="0" name="tab_idx" type="int" />
+ <description>
+ Returns the tooltip text of the tab at index [param tab_idx].
+ </description>
+ </method>
<method name="is_tab_disabled" qualifiers="const">
<return type="bool" />
<param index="0" name="tab_idx" type="int" />
@@ -173,6 +180,15 @@
Sets a custom title for the tab at index [param tab_idx] (tab titles default to the name of the indexed child node). Set it back to the child's name to make the tab default to it again.
</description>
</method>
+ <method name="set_tab_tooltip">
+ <return type="void" />
+ <param index="0" name="tab_idx" type="int" />
+ <param index="1" name="tooltip" type="String" />
+ <description>
+ Sets a custom tooltip text for tab at index [param tab_idx].
+ [b]Note:[/b] By default, if the [param tooltip] is empty and the tab text is truncated (not all characters fit into the tab), the title will be displayed as a tooltip. To hide the tooltip, assign [code]" "[/code] as the [param tooltip] text.
+ </description>
+ </method>
</methods>
<members>
<member name="all_tabs_in_front" type="bool" setter="set_all_tabs_in_front" getter="is_all_tabs_in_front" default="false">
diff --git a/doc/classes/WorkerThreadPool.xml b/doc/classes/WorkerThreadPool.xml
index fa1f08b149..2b1bc136cb 100644
--- a/doc/classes/WorkerThreadPool.xml
+++ b/doc/classes/WorkerThreadPool.xml
@@ -58,6 +58,7 @@
Adds [param action] as a group task to be executed by the worker threads. The [Callable] will be called a number of times based on [param elements], with the first thread calling it with the value [code]0[/code] as a parameter, and each consecutive execution incrementing this value by 1 until it reaches [code]element - 1[/code].
The number of threads the task is distributed to is defined by [param tasks_needed], where the default value [code]-1[/code] means it is distributed to all worker threads. [param high_priority] determines if the task has a high priority or a low priority (default). You can optionally provide a [param description] to help with debugging.
Returns a group task ID that can be used by other methods.
+ [b]Warning:[/b] Every task must be waited for completion using [method wait_for_task_completion] or [method wait_for_group_task_completion] at some point so that any allocated resources inside the task can be cleaned up.
</description>
</method>
<method name="add_task">
@@ -68,6 +69,7 @@
<description>
Adds [param action] as a task to be executed by a worker thread. [param high_priority] determines if the task has a high priority or a low priority (default). You can optionally provide a [param description] to help with debugging.
Returns a task ID that can be used by other methods.
+ [b]Warning:[/b] Every task must be waited for completion using [method wait_for_task_completion] or [method wait_for_group_task_completion] at some point so that any allocated resources inside the task can be cleaned up.
</description>
</method>
<method name="get_group_processed_element_count" qualifiers="const">
@@ -83,6 +85,7 @@
<param index="0" name="group_id" type="int" />
<description>
Returns [code]true[/code] if the group task with the given ID is completed.
+ [b]Note:[/b] You should only call this method between adding the group task and awaiting its completion.
</description>
</method>
<method name="is_task_completed" qualifiers="const">
@@ -90,6 +93,7 @@
<param index="0" name="task_id" type="int" />
<description>
Returns [code]true[/code] if the task with the given ID is completed.
+ [b]Note:[/b] You should only call this method between adding the task and awaiting its completion.
</description>
</method>
<method name="wait_for_group_task_completion">
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index 9fa95a93f8..5fabeb94f5 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -1922,7 +1922,7 @@ void RasterizerCanvasGLES3::render_sdf(RID p_render_target, LightOccluderInstanc
while (instance) {
OccluderPolygon *oc = occluder_polygon_owner.get_or_null(instance->occluder);
- if (!oc || oc->sdf_vertex_array == 0) {
+ if (!oc || oc->sdf_vertex_array == 0 || !instance->sdf_collision) {
instance = instance->next;
continue;
}
diff --git a/editor/editor_dock_manager.cpp b/editor/editor_dock_manager.cpp
index 06dd33d8ab..b6250671ee 100644
--- a/editor/editor_dock_manager.cpp
+++ b/editor/editor_dock_manager.cpp
@@ -147,6 +147,7 @@ void EditorDockManager::_update_layout() {
if (!dock_context_popup->is_inside_tree() || EditorNode::get_singleton()->is_exiting()) {
return;
}
+ EditorNode::get_singleton()->edit_current();
dock_context_popup->docks_updated();
_update_docks_menu();
EditorNode::get_singleton()->save_editor_layout_delayed();
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index 98feba38fd..50cc89c618 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -3477,9 +3477,7 @@ void EditorInspector::edit(Object *p_object) {
next_object = p_object; // Some plugins need to know the next edited object when clearing the inspector.
if (object) {
_clear();
- if (object->is_connected("property_list_changed", callable_mp(this, &EditorInspector::_changed_callback))) {
- object->disconnect("property_list_changed", callable_mp(this, &EditorInspector::_changed_callback));
- }
+ object->disconnect("property_list_changed", callable_mp(this, &EditorInspector::_changed_callback));
}
per_array_page.clear();
@@ -4021,13 +4019,14 @@ void EditorInspector::_notification(int p_what) {
} break;
case NOTIFICATION_PREDELETE: {
- edit(nullptr);
+ edit(nullptr); //just in case
} break;
case NOTIFICATION_EXIT_TREE: {
if (!sub_inspector) {
get_tree()->disconnect("node_removed", callable_mp(this, &EditorInspector::_node_removed));
}
+ edit(nullptr);
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index ca6be130f9..752b060513 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -990,6 +990,29 @@ EditorSettings *EditorSettings::get_singleton() {
return singleton.ptr();
}
+String EditorSettings::get_existing_settings_path() {
+ const String config_dir = EditorPaths::get_singleton()->get_config_dir();
+ int minor = VERSION_MINOR;
+ String filename;
+
+ do {
+ if (VERSION_MAJOR == 4 && minor < 3) {
+ // Minor version is used since 4.3, so special case to load older settings.
+ filename = vformat("editor_settings-%d.tres", VERSION_MAJOR);
+ minor = -1;
+ } else {
+ filename = vformat("editor_settings-%d.%d.tres", VERSION_MAJOR, minor);
+ minor--;
+ }
+ } while (minor >= 0 && !FileAccess::exists(config_dir.path_join(filename)));
+ return config_dir.path_join(filename);
+}
+
+String EditorSettings::get_newest_settings_path() {
+ const String config_file_name = vformat("editor_settings-%d.%d.tres", VERSION_MAJOR, VERSION_MINOR);
+ return EditorPaths::get_singleton()->get_config_dir().path_join(config_file_name);
+}
+
void EditorSettings::create() {
// IMPORTANT: create() *must* create a valid EditorSettings singleton,
// as the rest of the engine code will assume it. As such, it should never
@@ -1017,16 +1040,16 @@ void EditorSettings::create() {
if (EditorPaths::get_singleton()->are_paths_valid()) {
// Validate editor config file.
- Ref<DirAccess> dir = DirAccess::open(EditorPaths::get_singleton()->get_config_dir());
- ERR_FAIL_COND(dir.is_null());
+ ERR_FAIL_COND(!DirAccess::dir_exists_absolute(EditorPaths::get_singleton()->get_config_dir()));
- String config_file_name = "editor_settings-" + itos(VERSION_MAJOR) + ".tres";
- config_file_path = EditorPaths::get_singleton()->get_config_dir().path_join(config_file_name);
- if (!dir->file_exists(config_file_name)) {
+ config_file_path = get_existing_settings_path();
+ if (!FileAccess::exists(config_file_path)) {
+ config_file_path = get_newest_settings_path();
goto fail;
}
singleton = ResourceLoader::load(config_file_path, "EditorSettings");
+ singleton->set_path(get_newest_settings_path()); // Settings can be loaded from older version file, so make sure it's newest.
if (singleton.is_null()) {
ERR_PRINT("Could not load editor settings from path: " + config_file_path);
diff --git a/editor/editor_settings.h b/editor/editor_settings.h
index a058f91be8..6a329f6979 100644
--- a/editor/editor_settings.h
+++ b/editor/editor_settings.h
@@ -124,6 +124,8 @@ public:
};
static EditorSettings *get_singleton();
+ static String get_existing_settings_path();
+ static String get_newest_settings_path();
static void create();
void setup_language();
diff --git a/main/main.cpp b/main/main.cpp
index 801e8934b0..78a539fff7 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -2518,12 +2518,10 @@ Error Main::setup2() {
// Editor setting class is not available, load config directly.
if (!init_use_custom_screen && (editor || project_manager) && EditorPaths::get_singleton()->are_paths_valid()) {
- Ref<DirAccess> dir = DirAccess::open(EditorPaths::get_singleton()->get_config_dir());
- ERR_FAIL_COND_V(dir.is_null(), FAILED);
+ ERR_FAIL_COND_V(!DirAccess::dir_exists_absolute(EditorPaths::get_singleton()->get_config_dir()), FAILED);
- String config_file_name = "editor_settings-" + itos(VERSION_MAJOR) + ".tres";
- String config_file_path = EditorPaths::get_singleton()->get_config_dir().path_join(config_file_name);
- if (dir->file_exists(config_file_name)) {
+ String config_file_path = EditorSettings::get_existing_settings_path();
+ if (FileAccess::exists(config_file_path)) {
Error err;
Ref<FileAccess> f = FileAccess::open(config_file_path, FileAccess::READ, &err);
if (f.is_valid()) {
diff --git a/modules/gdscript/editor/gdscript_docgen.cpp b/modules/gdscript/editor/gdscript_docgen.cpp
index 601db5414b..35b69fab8c 100644
--- a/modules/gdscript/editor/gdscript_docgen.cpp
+++ b/modules/gdscript/editor/gdscript_docgen.cpp
@@ -229,6 +229,36 @@ String GDScriptDocGen::_docvalue_from_variant(const Variant &p_variant, int p_re
}
}
+String GDScriptDocGen::_docvalue_from_expression(const GDP::ExpressionNode *p_expression) {
+ ERR_FAIL_NULL_V(p_expression, String());
+
+ if (p_expression->is_constant) {
+ return _docvalue_from_variant(p_expression->reduced_value);
+ }
+
+ switch (p_expression->type) {
+ case GDP::Node::ARRAY: {
+ const GDP::ArrayNode *array = static_cast<const GDP::ArrayNode *>(p_expression);
+ return array->elements.is_empty() ? "[]" : "[...]";
+ } break;
+ case GDP::Node::CALL: {
+ const GDP::CallNode *call = static_cast<const GDP::CallNode *>(p_expression);
+ return call->function_name.operator String() + (call->arguments.is_empty() ? "()" : "(...)");
+ } break;
+ case GDP::Node::DICTIONARY: {
+ const GDP::DictionaryNode *dict = static_cast<const GDP::DictionaryNode *>(p_expression);
+ return dict->elements.is_empty() ? "{}" : "{...}";
+ } break;
+ case GDP::Node::IDENTIFIER: {
+ const GDP::IdentifierNode *id = static_cast<const GDP::IdentifierNode *>(p_expression);
+ return id->name;
+ } break;
+ default: {
+ return "<unknown>";
+ } break;
+ }
+}
+
void GDScriptDocGen::_generate_docs(GDScript *p_script, const GDP::ClassNode *p_class) {
p_script->_clear_doc();
@@ -328,16 +358,12 @@ void GDScriptDocGen::_generate_docs(GDScript *p_script, const GDP::ClassNode *p_
method_doc.return_type = "Variant";
}
- for (const GDScriptParser::ParameterNode *p : m_func->parameters) {
+ for (const GDP::ParameterNode *p : m_func->parameters) {
DocData::ArgumentDoc arg_doc;
arg_doc.name = p->identifier->name;
_doctype_from_gdtype(p->get_datatype(), arg_doc.type, arg_doc.enumeration);
if (p->initializer != nullptr) {
- if (p->initializer->is_constant) {
- arg_doc.default_value = _docvalue_from_variant(p->initializer->reduced_value);
- } else {
- arg_doc.default_value = "<unknown>";
- }
+ arg_doc.default_value = _docvalue_from_expression(p->initializer);
}
method_doc.arguments.push_back(arg_doc);
}
@@ -359,7 +385,7 @@ void GDScriptDocGen::_generate_docs(GDScript *p_script, const GDP::ClassNode *p_
signal_doc.is_experimental = m_signal->doc_data.is_experimental;
signal_doc.experimental_message = m_signal->doc_data.experimental_message;
- for (const GDScriptParser::ParameterNode *p : m_signal->parameters) {
+ for (const GDP::ParameterNode *p : m_signal->parameters) {
DocData::ArgumentDoc arg_doc;
arg_doc.name = p->identifier->name;
_doctype_from_gdtype(p->get_datatype(), arg_doc.type, arg_doc.enumeration);
@@ -405,12 +431,8 @@ void GDScriptDocGen::_generate_docs(GDScript *p_script, const GDP::ClassNode *p_
break;
}
- if (m_var->initializer) {
- if (m_var->initializer->is_constant) {
- prop_doc.default_value = _docvalue_from_variant(m_var->initializer->reduced_value);
- } else {
- prop_doc.default_value = "<unknown>";
- }
+ if (m_var->initializer != nullptr) {
+ prop_doc.default_value = _docvalue_from_expression(m_var->initializer);
}
prop_doc.overridden = false;
diff --git a/modules/gdscript/editor/gdscript_docgen.h b/modules/gdscript/editor/gdscript_docgen.h
index 651a4fb198..0ae37c4133 100644
--- a/modules/gdscript/editor/gdscript_docgen.h
+++ b/modules/gdscript/editor/gdscript_docgen.h
@@ -45,6 +45,7 @@ class GDScriptDocGen {
static String _get_class_name(const GDP::ClassNode &p_class);
static void _doctype_from_gdtype(const GDType &p_gdtype, String &r_type, String &r_enum, bool p_is_return = false);
static String _docvalue_from_variant(const Variant &p_variant, int p_recursion_level = 1);
+ static String _docvalue_from_expression(const GDP::ExpressionNode *p_expression);
static void _generate_docs(GDScript *p_script, const GDP::ClassNode *p_class);
public:
diff --git a/modules/gdscript/tests/README.md b/modules/gdscript/tests/README.md
index 72b5316532..714e38397f 100644
--- a/modules/gdscript/tests/README.md
+++ b/modules/gdscript/tests/README.md
@@ -13,6 +13,12 @@ The `script/completion` folder contains test for the GDScript autocompletion.
Each test case consists of at least one `.gd` file, which contains the code, and one `.cfg` file, which contains expected results and configuration. Inside of the GDScript file the character `➡` represents the cursor position, at which autocompletion is invoked.
+The script files won't be parsable GDScript since it contains an invalid char and and often the code is not complete during autocompletion. To allow for a valid base when used with a scene, the
+runner will remove the line which contains `➡`. Therefore the scripts need to be valid if this line is removed, otherwise the test might behave in unexpected ways. This may for example require
+adding an additional `pass` statement.
+
+This also means, that the runner will add the script to its owner node, so the script should not be loaded through the scene file.
+
The config file contains two section:
`[input]` contains keys that configure the test environment. The following keys are possible:
@@ -20,6 +26,7 @@ The config file contains two section:
- `cs: boolean = false`: If `true`, the test will be skipped when running a non C# build.
- `use_single_quotes: boolean = false`: Configures the corresponding editor setting for the test.
- `scene: String`: Allows to specify a scene which is opened while autocompletion is performed. If this is not set the test runner will search for a `.tscn` file with the same basename as the GDScript file. If that isn't found either, autocompletion will behave as if no scene was opened.
+- `node_path: String`: The node path of the node which holds the current script inside of the scene. Defaults to the scene root node.
`[output]` specifies the expected results for the test. The following key are supported:
diff --git a/modules/gdscript/tests/scripts/completion/argument_options/argument_options.tscn b/modules/gdscript/tests/scripts/completion/argument_options/argument_options.tscn
new file mode 100644
index 0000000000..d3dea6b12b
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/argument_options/argument_options.tscn
@@ -0,0 +1,3 @@
+[gd_scene load_steps=1 format=3 uid="uid://dl28pdkxcjvym"]
+
+[node name="GetNode" type="Node"]
diff --git a/modules/gdscript/tests/scripts/completion/argument_options/connect.cfg b/modules/gdscript/tests/scripts/completion/argument_options/connect.cfg
new file mode 100644
index 0000000000..8c3fbf90da
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/argument_options/connect.cfg
@@ -0,0 +1,8 @@
+[input]
+scene="res://completion/argument_options/argument_options.tscn"
+[output]
+include=[
+ ; Node
+ {"display": "\"signal_a\""},
+ {"display": "\"child_entered_tree\""},
+]
diff --git a/modules/gdscript/tests/scripts/completion/argument_options/connect.gd b/modules/gdscript/tests/scripts/completion/argument_options/connect.gd
new file mode 100644
index 0000000000..1137070c4e
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/argument_options/connect.gd
@@ -0,0 +1,7 @@
+extends Node
+
+signal signal_a()
+
+func _ready():
+ connect(➡)
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal/dollar.gd b/modules/gdscript/tests/scripts/completion/get_node/literal/dollar.gd
index df458a9435..dc7cc99554 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/literal/dollar.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal/dollar.gd
@@ -2,3 +2,4 @@ extends Node
func a():
%AnimationPlayer.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal/percent.gd b/modules/gdscript/tests/scripts/completion/get_node/literal/percent.gd
index 7050761b86..5586317938 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/literal/percent.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal/percent.gd
@@ -2,3 +2,4 @@ extends Node
func a():
$UniqueAnimationPlayer.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.gd
index a84283a1de..69fcac4471 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.gd
@@ -2,3 +2,4 @@ extends Node
func a():
$A.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.gd
index 6e3fee1696..0b13a207ff 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.gd
@@ -2,3 +2,4 @@ extends Node
func a():
$AnimationPlayer.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.gd
index 27f059c944..48945db38e 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.gd
@@ -2,3 +2,4 @@ extends Node
func a():
%UniqueA.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.gd
index 07068fc5a4..3684edc73b 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.gd
@@ -2,3 +2,4 @@ extends Node
func a():
%UniqueAnimationPlayer.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local/local.gd b/modules/gdscript/tests/scripts/completion/get_node/local/local.gd
index 596ad80ef2..dcd232d82d 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local/local.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/local/local.gd
@@ -3,3 +3,4 @@ extends Node
func a():
var test = $AnimationPlayer
test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_interfered/local_interfered.gd b/modules/gdscript/tests/scripts/completion/get_node/local_interfered/local_interfered.gd
index 6f87af3c85..7710c2d13b 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_interfered/local_interfered.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_interfered/local_interfered.gd
@@ -3,3 +3,4 @@ extends Node
func a():
var test := $AnimationPlayer
test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/class_local_interfered_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/class_local_interfered_scene.gd
index a710c8bbd7..6b29bf5526 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/class_local_interfered_scene.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/class_local_interfered_scene.gd
@@ -3,3 +3,4 @@ extends Node
func a():
var test := $A
test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/native_local_interfered_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/native_local_interfered_scene.gd
index 6f87af3c85..7710c2d13b 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/native_local_interfered_scene.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/native_local_interfered_scene.gd
@@ -3,3 +3,4 @@ extends Node
func a():
var test := $AnimationPlayer
test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.gd
index 2fc88f93dd..02c0d2dceb 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.gd
@@ -3,3 +3,4 @@ extends Node
func a():
var test = $A
test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.gd
index 596ad80ef2..dcd232d82d 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.gd
@@ -3,3 +3,4 @@ extends Node
func a():
var test = $AnimationPlayer
test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.gd b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.gd
index b6d2074939..3277beccab 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.gd
@@ -5,3 +5,4 @@ const A := preload("res://completion/class_a.notest.gd")
func a():
var test: A = $A
test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.gd b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.gd
index 13b541a35d..e6d22af296 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.gd
@@ -3,3 +3,4 @@ extends Node
func a():
var test: AnimationPlayer = $AnimationPlayer
test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.gd
index b6d2074939..3277beccab 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.gd
@@ -5,3 +5,4 @@ const A := preload("res://completion/class_a.notest.gd")
func a():
var test: A = $A
test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.gd
index 13b541a35d..e6d22af296 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.gd
@@ -3,3 +3,4 @@ extends Node
func a():
var test: AnimationPlayer = $AnimationPlayer
test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.notest.gd b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.notest.gd
index 5c785b3ddc..3266679a6a 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.notest.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.notest.gd
@@ -4,3 +4,4 @@ extends Node
func a():
var test: Node = $A
test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.notest.gd b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.notest.gd
index 57f4e16e3c..f637fc3d0f 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.notest.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.notest.gd
@@ -4,3 +4,4 @@ extends Node
func a():
var test: Node = $AnimationPlayer
test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.gd b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.gd
index c6adfe0dd3..8ce75d9996 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.gd
@@ -3,3 +3,4 @@ extends Node
func a():
var test: Area2D = $A
test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.gd b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.gd
index f53fce9bfe..2b39e3ada7 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.gd
@@ -3,3 +3,4 @@ extends Node
func a():
var test: Area2D = $AnimationPlayer
test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member/member.gd b/modules/gdscript/tests/scripts/completion/get_node/member/member.gd
index 6bcc0a0298..80b4943953 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member/member.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/member/member.gd
@@ -4,3 +4,4 @@ var test = $AnimationPlayer
func a():
test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_interfered/member_interfered.gd b/modules/gdscript/tests/scripts/completion/get_node/member_interfered/member_interfered.gd
index 542197e643..97b288334e 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_interfered/member_interfered.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_interfered/member_interfered.gd
@@ -4,3 +4,4 @@ var test := $AnimationPlayer
func a():
test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/class_member_interfered_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/class_member_interfered_scene.gd
index da0b1b11d4..402fd1d275 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/class_member_interfered_scene.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/class_member_interfered_scene.gd
@@ -4,3 +4,4 @@ var test := $A
func a():
test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/native_member_interfered_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/native_member_interfered_scene.gd
index 542197e643..97b288334e 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/native_member_interfered_scene.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/native_member_interfered_scene.gd
@@ -4,3 +4,4 @@ var test := $AnimationPlayer
func a():
test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.gd
index 4a35661e94..6188a6e843 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.gd
@@ -4,3 +4,4 @@ var test = $A
func a():
test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.gd
index 6bcc0a0298..80b4943953 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.gd
@@ -4,3 +4,4 @@ var test = $AnimationPlayer
func a():
test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.gd b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.gd
index e4edc3a4e4..01b7c76dbf 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.gd
@@ -6,3 +6,4 @@ var test: A = $A
func a():
test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.gd b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.gd
index eda94ae34d..7f2cb4e8cc 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.gd
@@ -4,3 +4,4 @@ var test: AnimationPlayer = $AnimationPlayer
func a():
test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.gd
index 8f68f54072..43d8b666ab 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.gd
@@ -6,3 +6,4 @@ const A := preload("res://completion/class_a.notest.gd")
func a():
test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.gd
index eda94ae34d..7f2cb4e8cc 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.gd
@@ -4,3 +4,4 @@ var test: AnimationPlayer = $AnimationPlayer
func a():
test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.gd b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.gd
index 7b0ed4ecd8..aac450be9f 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.gd
@@ -4,3 +4,4 @@ var test: Node = $A
func a():
test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.gd b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.gd
index 87342f9a21..9eb10e4933 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.gd
@@ -4,3 +4,4 @@ var test: Node = $AnimationPlayer
func a():
test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.gd b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.gd
index 5f78bcdf04..ff8214c463 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.gd
@@ -4,3 +4,4 @@ var test: Area2D = $A
func a():
test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.gd b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.gd
index c14df5cd1b..30cd7d6a21 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.gd
@@ -4,3 +4,4 @@ var test: Area2D = $AnimationPlayer
func a():
test.➡
+ pass
diff --git a/modules/gdscript/tests/test_completion.h b/modules/gdscript/tests/test_completion.h
index ac9ffcd915..327446acee 100644
--- a/modules/gdscript/tests/test_completion.h
+++ b/modules/gdscript/tests/test_completion.h
@@ -33,6 +33,7 @@
#ifdef TOOLS_ENABLED
+#include "core/config/project_settings.h"
#include "core/io/config_file.h"
#include "core/io/dir_access.h"
#include "core/io/file_access.h"
@@ -111,7 +112,10 @@ static void test_directory(const String &p_dir) {
// For ease of reading ➡ (0x27A1) acts as sentinel char instead of 0xFFFF in the files.
code = code.replace_first(String::chr(0x27A1), String::chr(0xFFFF));
// Require pointer sentinel char in scripts.
- CHECK(code.find_char(0xFFFF) != -1);
+ int location = code.find_char(0xFFFF);
+ CHECK(location != -1);
+
+ String res_path = ProjectSettings::get_singleton()->localize_path(path.path_join(next));
ConfigFile conf;
if (conf.load(path.path_join(next.get_basename() + ".cfg")) != OK) {
@@ -137,20 +141,46 @@ static void test_directory(const String &p_dir) {
String call_hint;
bool forced;
- Node *owner = nullptr;
+ Node *scene = nullptr;
if (conf.has_section_key("input", "scene")) {
- Ref<PackedScene> scene = ResourceLoader::load(conf.get_value("input", "scene"), "PackedScene", ResourceFormatLoader::CACHE_MODE_IGNORE_DEEP);
- if (scene.is_valid()) {
- owner = scene->instantiate();
+ Ref<PackedScene> packed_scene = ResourceLoader::load(conf.get_value("input", "scene"), "PackedScene", ResourceFormatLoader::CACHE_MODE_IGNORE_DEEP);
+ if (packed_scene.is_valid()) {
+ scene = packed_scene->instantiate();
}
} else if (dir->file_exists(next.get_basename() + ".tscn")) {
- Ref<PackedScene> scene = ResourceLoader::load(path.path_join(next.get_basename() + ".tscn"), "PackedScene");
- if (scene.is_valid()) {
- owner = scene->instantiate();
+ Ref<PackedScene> packed_scene = ResourceLoader::load(path.path_join(next.get_basename() + ".tscn"), "PackedScene");
+ if (packed_scene.is_valid()) {
+ scene = packed_scene->instantiate();
+ }
+ }
+ Node *owner = nullptr;
+ if (scene != nullptr) {
+ owner = scene->get_node(conf.get_value("input", "node_path", "."));
+ }
+
+ if (owner != nullptr) {
+ // Remove the line which contains the sentinel char, to get a valid script.
+ Ref<GDScript> scr;
+ scr.instantiate();
+ int start = location;
+ int end = location;
+ for (; start >= 0; --start) {
+ if (code.get(start) == '\n') {
+ break;
+ }
+ }
+ for (; end < code.size(); ++end) {
+ if (code.get(end) == '\n') {
+ break;
+ }
}
+ scr->set_source_code(code.erase(start, end - start));
+ scr->reload();
+ scr->set_path(res_path);
+ owner->set_script(scr);
}
- GDScriptLanguage::get_singleton()->complete_code(code, path.path_join(next), owner, &options, forced, call_hint);
+ GDScriptLanguage::get_singleton()->complete_code(code, res_path, owner, &options, forced, call_hint);
String contains_excluded;
for (ScriptLanguage::CodeCompletionOption &option : options) {
for (const Dictionary &E : exclude) {
@@ -179,8 +209,8 @@ static void test_directory(const String &p_dir) {
CHECK(expected_call_hint == call_hint);
CHECK(expected_forced == forced);
- if (owner) {
- memdelete(owner);
+ if (scene) {
+ memdelete(scene);
}
}
next = dir->get_next();
diff --git a/modules/multiplayer/scene_cache_interface.cpp b/modules/multiplayer/scene_cache_interface.cpp
index 33b05d4cc2..c08ccbe4cc 100644
--- a/modules/multiplayer/scene_cache_interface.cpp
+++ b/modules/multiplayer/scene_cache_interface.cpp
@@ -52,6 +52,9 @@ void SceneCacheInterface::_remove_node_cache(ObjectID p_oid) {
if (!nc) {
return;
}
+ if (nc->cache_id) {
+ assigned_ids.erase(nc->cache_id);
+ }
for (KeyValue<int, int> &E : nc->recv_ids) {
PeerInfo *pinfo = peers_info.getptr(E.key);
ERR_CONTINUE(!pinfo);
@@ -117,16 +120,12 @@ void SceneCacheInterface::process_simplify_path(int p_from, const uint8_t *p_pac
NodeCache &cache = _track(node);
cache.recv_ids.insert(p_from, id);
- // Encode path to send ack.
- CharString pname = String(path).utf8();
- int len = encode_cstring(pname.get_data(), nullptr);
-
+ // Send ack.
Vector<uint8_t> packet;
-
- packet.resize(1 + 1 + len);
+ packet.resize(1 + 1 + 4);
packet.write[0] = SceneMultiplayer::NETWORK_COMMAND_CONFIRM_PATH;
packet.write[1] = valid_rpc_checksum;
- encode_cstring(pname.get_data(), &packet.write[2]);
+ encode_uint32(id, &packet.write[2]);
Ref<MultiplayerPeer> multiplayer_peer = multiplayer->get_multiplayer_peer();
ERR_FAIL_COND(multiplayer_peer.is_null());
@@ -137,26 +136,26 @@ void SceneCacheInterface::process_simplify_path(int p_from, const uint8_t *p_pac
}
void SceneCacheInterface::process_confirm_path(int p_from, const uint8_t *p_packet, int p_packet_len) {
- ERR_FAIL_COND_MSG(p_packet_len < 3, "Invalid packet received. Size too small.");
+ ERR_FAIL_COND_MSG(p_packet_len != 6, "Invalid packet received. Size too small.");
Node *root_node = SceneTree::get_singleton()->get_root()->get_node(multiplayer->get_root_path());
ERR_FAIL_NULL(root_node);
const bool valid_rpc_checksum = p_packet[1];
+ int id = decode_uint32(&p_packet[2]);
- String paths;
- paths.parse_utf8((const char *)&p_packet[2], p_packet_len - 2);
-
- const NodePath path = paths;
+ const ObjectID *oid = assigned_ids.getptr(id);
+ if (oid == nullptr) {
+ return; // May be trying to confirm a node that was removed.
+ }
if (valid_rpc_checksum == false) {
- ERR_PRINT("The rpc node checksum failed. Make sure to have the same methods on both nodes. Node path: " + path);
+ const Node *node = Object::cast_to<Node>(ObjectDB::get_instance(*oid));
+ ERR_FAIL_NULL(node); // Bug.
+ ERR_PRINT("The rpc node checksum failed. Make sure to have the same methods on both nodes. Node path: " + node->get_path());
}
- Node *node = root_node->get_node(path);
- ERR_FAIL_NULL(node);
-
- NodeCache *cache = nodes_cache.getptr(node->get_instance_id());
- ERR_FAIL_NULL_MSG(cache, "Invalid packet received. Tries to confirm a node which was not requested.");
+ NodeCache *cache = nodes_cache.getptr(*oid);
+ ERR_FAIL_NULL(cache); // Bug.
bool *confirmed = cache->confirmed_peers.getptr(p_from);
ERR_FAIL_NULL_MSG(confirmed, "Invalid packet received. Tries to confirm a node which was not requested.");
@@ -216,6 +215,7 @@ int SceneCacheInterface::make_object_cache(Object *p_obj) {
NodeCache &cache = _track(node);
if (cache.cache_id == 0) {
cache.cache_id = last_send_cache_id++;
+ assigned_ids[cache.cache_id] = p_obj->get_instance_id();
}
return cache.cache_id;
}
@@ -227,6 +227,7 @@ bool SceneCacheInterface::send_object_cache(Object *p_obj, int p_peer_id, int &r
NodeCache &cache = _track(node);
if (cache.cache_id == 0) {
cache.cache_id = last_send_cache_id++;
+ assigned_ids[cache.cache_id] = p_obj->get_instance_id();
}
r_id = cache.cache_id;
@@ -289,5 +290,6 @@ void SceneCacheInterface::clear() {
}
peers_info.clear();
nodes_cache.clear();
+ assigned_ids.clear();
last_send_cache_id = 1;
}
diff --git a/modules/multiplayer/scene_cache_interface.h b/modules/multiplayer/scene_cache_interface.h
index ab4a20c078..73d6bde6ef 100644
--- a/modules/multiplayer/scene_cache_interface.h
+++ b/modules/multiplayer/scene_cache_interface.h
@@ -44,7 +44,7 @@ private:
//path sent caches
struct NodeCache {
- int cache_id;
+ int cache_id = 0;
HashMap<int, int> recv_ids; // peer id, remote cache id
HashMap<int, bool> confirmed_peers; // peer id, confirmed
};
@@ -55,6 +55,7 @@ private:
};
HashMap<ObjectID, NodeCache> nodes_cache;
+ HashMap<int, ObjectID> assigned_ids;
HashMap<int, PeerInfo> peers_info;
int last_send_cache_id = 1;
diff --git a/platform/windows/rendering_context_driver_vulkan_windows.h b/platform/windows/rendering_context_driver_vulkan_windows.h
index 34546c9ea6..1bb70cb0ff 100644
--- a/platform/windows/rendering_context_driver_vulkan_windows.h
+++ b/platform/windows/rendering_context_driver_vulkan_windows.h
@@ -52,7 +52,7 @@ public:
};
RenderingContextDriverVulkanWindows();
- ~RenderingContextDriverVulkanWindows() override final;
+ ~RenderingContextDriverVulkanWindows() override;
};
#endif // VULKAN_ENABLED
diff --git a/scene/2d/line_builder.cpp b/scene/2d/line_builder.cpp
index e898dc7fab..f8a8aa487c 100644
--- a/scene/2d/line_builder.cpp
+++ b/scene/2d/line_builder.cpp
@@ -353,7 +353,20 @@ void LineBuilder::build() {
} else if (current_joint_mode == Line2D::LINE_JOINT_ROUND && !(wrap_around && i == segments_count)) {
Vector2 vbegin = cbegin - pos1;
Vector2 vend = cend - pos1;
- strip_add_arc(pos1, vbegin.angle_to(vend), orientation);
+ // We want to use vbegin.angle_to(vend) below, which evaluates to
+ // Math::atan2(vbegin.cross(vend), vbegin.dot(vend)) but we need to
+ // calculate this ourselves as we need to check if the cross product
+ // in that calculation ends up being -0.f and flip it if so, effectively
+ // flipping the resulting angle_delta to not return -PI but +PI instead
+ float cross_product = vbegin.cross(vend);
+ float dot_product = vbegin.dot(vend);
+ // Note that we're comparing against -0.f for clarity but 0.f would
+ // match as well, therefore we need the explicit signbit check too.
+ if (cross_product == -0.f && signbit(cross_product)) {
+ cross_product = 0.f;
+ }
+ float angle_delta = Math::atan2(cross_product, dot_product);
+ strip_add_arc(pos1, angle_delta, orientation);
}
if (!is_intersecting) {
diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp
index 2d687eb201..0e130d60af 100644
--- a/scene/gui/tab_bar.cpp
+++ b/scene/gui/tab_bar.cpp
@@ -323,6 +323,19 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) {
}
}
+String TabBar::get_tooltip(const Point2 &p_pos) const {
+ int tab_idx = get_tab_idx_at_point(p_pos);
+ if (tab_idx < 0) {
+ return Control::get_tooltip(p_pos);
+ }
+
+ if (tabs[tab_idx].tooltip.is_empty() && tabs[tab_idx].truncated) {
+ return tabs[tab_idx].text;
+ }
+
+ return tabs[tab_idx].tooltip;
+}
+
void TabBar::_shape(int p_tab) {
tabs.write[p_tab].text_buf->clear();
tabs.write[p_tab].text_buf->set_width(-1);
@@ -757,6 +770,16 @@ String TabBar::get_tab_title(int p_tab) const {
return tabs[p_tab].text;
}
+void TabBar::set_tab_tooltip(int p_tab, const String &p_tooltip) {
+ ERR_FAIL_INDEX(p_tab, tabs.size());
+ tabs.write[p_tab].tooltip = p_tooltip;
+}
+
+String TabBar::get_tab_tooltip(int p_tab) const {
+ ERR_FAIL_INDEX_V(p_tab, tabs.size(), "");
+ return tabs[p_tab].tooltip;
+}
+
void TabBar::set_tab_text_direction(int p_tab, Control::TextDirection p_text_direction) {
ERR_FAIL_INDEX(p_tab, tabs.size());
ERR_FAIL_COND((int)p_text_direction < -1 || (int)p_text_direction > 3);
@@ -998,7 +1021,8 @@ void TabBar::_update_cache(bool p_update_hover) {
tabs.write[i].size_text = Math::ceil(tabs[i].text_buf->get_size().x);
tabs.write[i].size_cache = get_tab_width(i);
- if (max_width > 0 && tabs[i].size_cache > max_width) {
+ tabs.write[i].truncated = max_width > 0 && tabs[i].size_cache > max_width;
+ if (tabs[i].truncated) {
int size_textless = tabs[i].size_cache - tabs[i].size_text;
int mw = MAX(size_textless, max_width);
@@ -1730,6 +1754,8 @@ void TabBar::_bind_methods() {
ClassDB::bind_method(D_METHOD("select_next_available"), &TabBar::select_next_available);
ClassDB::bind_method(D_METHOD("set_tab_title", "tab_idx", "title"), &TabBar::set_tab_title);
ClassDB::bind_method(D_METHOD("get_tab_title", "tab_idx"), &TabBar::get_tab_title);
+ ClassDB::bind_method(D_METHOD("set_tab_tooltip", "tab_idx", "tooltip"), &TabBar::set_tab_tooltip);
+ ClassDB::bind_method(D_METHOD("get_tab_tooltip", "tab_idx"), &TabBar::get_tab_tooltip);
ClassDB::bind_method(D_METHOD("set_tab_text_direction", "tab_idx", "direction"), &TabBar::set_tab_text_direction);
ClassDB::bind_method(D_METHOD("get_tab_text_direction", "tab_idx"), &TabBar::get_tab_text_direction);
ClassDB::bind_method(D_METHOD("set_tab_language", "tab_idx", "language"), &TabBar::set_tab_language);
@@ -1843,6 +1869,7 @@ void TabBar::_bind_methods() {
base_property_helper.set_prefix("tab_");
base_property_helper.register_property(PropertyInfo(Variant::STRING, "title"), defaults.text, &TabBar::set_tab_title, &TabBar::get_tab_title);
+ base_property_helper.register_property(PropertyInfo(Variant::STRING, "tooltip"), defaults.tooltip, &TabBar::set_tab_tooltip, &TabBar::get_tab_tooltip);
base_property_helper.register_property(PropertyInfo(Variant::OBJECT, "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), defaults.icon, &TabBar::set_tab_icon, &TabBar::get_tab_icon);
base_property_helper.register_property(PropertyInfo(Variant::BOOL, "disabled"), defaults.disabled, &TabBar::set_tab_disabled, &TabBar::is_tab_disabled);
}
diff --git a/scene/gui/tab_bar.h b/scene/gui/tab_bar.h
index 6c09e960f1..52f1da5ec8 100644
--- a/scene/gui/tab_bar.h
+++ b/scene/gui/tab_bar.h
@@ -56,6 +56,7 @@ public:
private:
struct Tab {
String text;
+ String tooltip;
String language;
Control::TextDirection text_direction = Control::TEXT_DIRECTION_INHERITED;
@@ -66,6 +67,8 @@ private:
bool disabled = false;
bool hidden = false;
+ bool truncated = false;
+
Variant metadata;
int ofs_cache = 0;
int size_cache = 0;
@@ -168,6 +171,7 @@ private:
protected:
virtual void gui_input(const Ref<InputEvent> &p_event) override;
+ virtual String get_tooltip(const Point2 &p_pos) const override;
bool _set(const StringName &p_name, const Variant &p_value) { return property_helper.property_set_value(p_name, p_value); }
bool _get(const StringName &p_name, Variant &r_ret) const { return property_helper.property_get_value(p_name, r_ret); }
@@ -192,6 +196,9 @@ public:
void set_tab_title(int p_tab, const String &p_title);
String get_tab_title(int p_tab) const;
+ void set_tab_tooltip(int p_tab, const String &p_tooltip);
+ String get_tab_tooltip(int p_tab) const;
+
void set_tab_text_direction(int p_tab, TextDirection p_text_direction);
TextDirection get_tab_text_direction(int p_tab) const;
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index 16358ac21f..05f44891f6 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -400,6 +400,7 @@ void TabContainer::move_tab_from_tab_container(TabContainer *p_from, int p_from_
// Get the tab properties before they get erased by the child removal.
String tab_title = p_from->get_tab_title(p_from_index);
+ String tab_tooltip = p_from->get_tab_tooltip(p_from_index);
Ref<Texture2D> tab_icon = p_from->get_tab_icon(p_from_index);
Ref<Texture2D> tab_button_icon = p_from->get_tab_button_icon(p_from_index);
bool tab_disabled = p_from->is_tab_disabled(p_from_index);
@@ -417,6 +418,7 @@ void TabContainer::move_tab_from_tab_container(TabContainer *p_from, int p_from_
move_child(moving_tabc, get_tab_control(p_to_index)->get_index(false));
set_tab_title(p_to_index, tab_title);
+ set_tab_tooltip(p_to_index, tab_tooltip);
set_tab_icon(p_to_index, tab_icon);
set_tab_button_icon(p_to_index, tab_button_icon);
set_tab_disabled(p_to_index, tab_disabled);
@@ -760,16 +762,22 @@ void TabContainer::set_tab_title(int p_tab, const String &p_title) {
child->set_meta("_tab_name", p_title);
}
- _update_margins();
- if (!get_clip_tabs()) {
- update_minimum_size();
- }
+ _repaint();
+ queue_redraw();
}
String TabContainer::get_tab_title(int p_tab) const {
return tab_bar->get_tab_title(p_tab);
}
+void TabContainer::set_tab_tooltip(int p_tab, const String &p_tooltip) {
+ tab_bar->set_tab_tooltip(p_tab, p_tooltip);
+}
+
+String TabContainer::get_tab_tooltip(int p_tab) const {
+ return tab_bar->get_tab_tooltip(p_tab);
+}
+
void TabContainer::set_tab_icon(int p_tab, const Ref<Texture2D> &p_icon) {
if (tab_bar->get_tab_icon(p_tab) == p_icon) {
return;
@@ -978,6 +986,8 @@ void TabContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_all_tabs_in_front"), &TabContainer::is_all_tabs_in_front);
ClassDB::bind_method(D_METHOD("set_tab_title", "tab_idx", "title"), &TabContainer::set_tab_title);
ClassDB::bind_method(D_METHOD("get_tab_title", "tab_idx"), &TabContainer::get_tab_title);
+ ClassDB::bind_method(D_METHOD("set_tab_tooltip", "tab_idx", "tooltip"), &TabContainer::set_tab_tooltip);
+ ClassDB::bind_method(D_METHOD("get_tab_tooltip", "tab_idx"), &TabContainer::get_tab_tooltip);
ClassDB::bind_method(D_METHOD("set_tab_icon", "tab_idx", "icon"), &TabContainer::set_tab_icon);
ClassDB::bind_method(D_METHOD("get_tab_icon", "tab_idx"), &TabContainer::get_tab_icon);
ClassDB::bind_method(D_METHOD("set_tab_disabled", "tab_idx", "disabled"), &TabContainer::set_tab_disabled);
diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h
index 8645a6d14e..c11d9824e7 100644
--- a/scene/gui/tab_container.h
+++ b/scene/gui/tab_container.h
@@ -155,6 +155,9 @@ public:
void set_tab_title(int p_tab, const String &p_title);
String get_tab_title(int p_tab) const;
+ void set_tab_tooltip(int p_tab, const String &p_tooltip);
+ String get_tab_tooltip(int p_tab) const;
+
void set_tab_icon(int p_tab, const Ref<Texture2D> &p_icon);
Ref<Texture2D> get_tab_icon(int p_tab) const;
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index 98a12f1400..f70a00a9f6 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -40,6 +40,7 @@
// Version 2: changed names for Basis, AABB, Vectors, etc.
// Version 3: new string ID for ext/subresources, breaks forward compat.
// Version 4: PackedByteArray is now stored as base64 encoded.
+#define FORMAT_VERSION_COMPAT 3
#define FORMAT_VERSION 4
#define BINARY_FORMAT_VERSION 4
@@ -845,7 +846,7 @@ void ResourceLoaderText::set_translation_remapped(bool p_remapped) {
}
ResourceLoaderText::ResourceLoaderText() :
- stream(false) {}
+ stream(false), format_version(FORMAT_VERSION) {}
void ResourceLoaderText::get_dependencies(Ref<FileAccess> p_f, List<String> *p_dependencies, bool p_add_types) {
open(p_f);
@@ -954,13 +955,13 @@ Error ResourceLoaderText::rename_dependencies(Ref<FileAccess> p_f, const String
}
if (is_scene) {
- fw->store_line("[gd_scene load_steps=" + itos(resources_total) + " format=" + itos(FORMAT_VERSION) + uid_text + "]\n");
+ fw->store_line("[gd_scene load_steps=" + itos(resources_total) + " format=" + itos(format_version) + uid_text + "]\n");
} else {
String script_res_text;
if (!script_class.is_empty()) {
script_res_text = "script_class=\"" + script_class + "\" ";
}
- fw->store_line("[gd_resource type=\"" + res_type + "\" " + script_res_text + "load_steps=" + itos(resources_total) + " format=" + itos(FORMAT_VERSION) + uid_text + "]\n");
+ fw->store_line("[gd_resource type=\"" + res_type + "\" " + script_res_text + "load_steps=" + itos(resources_total) + " format=" + itos(format_version) + uid_text + "]\n");
}
}
@@ -1063,13 +1064,15 @@ void ResourceLoaderText::open(Ref<FileAccess> p_f, bool p_skip_first_tag) {
}
if (tag.fields.has("format")) {
- int fmt = tag.fields["format"];
- if (fmt > FORMAT_VERSION) {
+ format_version = tag.fields["format"];
+ if (format_version > FORMAT_VERSION) {
error_text = "Saved with newer format version";
_printerr();
error = ERR_FILE_UNRECOGNIZED;
return;
}
+ } else {
+ format_version = FORMAT_VERSION;
}
if (tag.name == "gd_scene") {
@@ -1970,6 +1973,12 @@ void ResourceFormatSaverTextInstance::_find_resources(const Variant &p_variant,
_find_resources(v);
}
} break;
+ case Variant::PACKED_BYTE_ARRAY: {
+ // Balance between compatibility and performance.
+ if (use_compat && p_variant.operator PackedByteArray().size() > 64) {
+ use_compat = false;
+ }
+ } break;
default: {
}
}
@@ -2005,6 +2014,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso
}
// Save resources.
+ use_compat = true; // _find_resources() changes this.
_find_resources(p_resource, true);
if (packed_scene.is_valid()) {
@@ -2037,7 +2047,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso
if (load_steps > 1) {
title += "load_steps=" + itos(load_steps) + " ";
}
- title += "format=" + itos(FORMAT_VERSION) + "";
+ title += "format=" + itos(use_compat ? FORMAT_VERSION_COMPAT : FORMAT_VERSION) + "";
ResourceUID::ID uid = ResourceSaver::get_resource_id_for_path(local_path, true);
@@ -2223,7 +2233,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso
}
String vars;
- VariantWriter::write_to_string(value, vars, _write_resources, this);
+ VariantWriter::write_to_string(value, vars, _write_resources, this, use_compat);
f->store_string(name.property_name_encode() + " = " + vars + "\n");
}
}
@@ -2287,14 +2297,14 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso
if (!instance_placeholder.is_empty()) {
String vars;
f->store_string(" instance_placeholder=");
- VariantWriter::write_to_string(instance_placeholder, vars, _write_resources, this);
+ VariantWriter::write_to_string(instance_placeholder, vars, _write_resources, this, use_compat);
f->store_string(vars);
}
if (instance.is_valid()) {
String vars;
f->store_string(" instance=");
- VariantWriter::write_to_string(instance, vars, _write_resources, this);
+ VariantWriter::write_to_string(instance, vars, _write_resources, this, use_compat);
f->store_string(vars);
}
@@ -2302,7 +2312,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso
for (int j = 0; j < state->get_node_property_count(i); j++) {
String vars;
- VariantWriter::write_to_string(state->get_node_property_value(i, j), vars, _write_resources, this);
+ VariantWriter::write_to_string(state->get_node_property_value(i, j), vars, _write_resources, this, use_compat);
f->store_string(String(state->get_node_property_name(i, j)).property_name_encode() + " = " + vars + "\n");
}
@@ -2336,7 +2346,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso
f->store_string(connstr);
if (binds.size()) {
String vars;
- VariantWriter::write_to_string(binds, vars, _write_resources, this);
+ VariantWriter::write_to_string(binds, vars, _write_resources, this, use_compat);
f->store_string(" binds= " + vars);
}
@@ -2368,14 +2378,14 @@ Error ResourceLoaderText::set_uid(Ref<FileAccess> p_f, ResourceUID::ID p_uid) {
fw = FileAccess::open(local_path + ".uidren", FileAccess::WRITE);
if (is_scene) {
- fw->store_string("[gd_scene load_steps=" + itos(resources_total) + " format=" + itos(FORMAT_VERSION) + " uid=\"" + ResourceUID::get_singleton()->id_to_text(p_uid) + "\"]");
+ fw->store_string("[gd_scene load_steps=" + itos(resources_total) + " format=" + itos(format_version) + " uid=\"" + ResourceUID::get_singleton()->id_to_text(p_uid) + "\"]");
} else {
String script_res_text;
if (!script_class.is_empty()) {
script_res_text = "script_class=\"" + script_class + "\" ";
}
- fw->store_string("[gd_resource type=\"" + res_type + "\" " + script_res_text + "load_steps=" + itos(resources_total) + " format=" + itos(FORMAT_VERSION) + " uid=\"" + ResourceUID::get_singleton()->id_to_text(p_uid) + "\"]");
+ fw->store_string("[gd_resource type=\"" + res_type + "\" " + script_res_text + "load_steps=" + itos(resources_total) + " format=" + itos(format_version) + " uid=\"" + ResourceUID::get_singleton()->id_to_text(p_uid) + "\"]");
}
uint8_t c = f->get_8();
diff --git a/scene/resources/resource_format_text.h b/scene/resources/resource_format_text.h
index c05b7a24e1..41363fd975 100644
--- a/scene/resources/resource_format_text.h
+++ b/scene/resources/resource_format_text.h
@@ -54,6 +54,7 @@ class ResourceLoaderText {
};
bool is_scene = false;
+ int format_version;
String res_type;
bool ignore_resource_parsing = false;
@@ -178,6 +179,7 @@ class ResourceFormatSaverTextInstance {
List<Ref<Resource>> saved_resources;
HashMap<Ref<Resource>, String> external_resources;
HashMap<Ref<Resource>, String> internal_resources;
+ bool use_compat = true;
struct ResourceSort {
Ref<Resource> resource;
diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp
index 46c84fd230..34f9069649 100644
--- a/servers/rendering/renderer_canvas_cull.cpp
+++ b/servers/rendering/renderer_canvas_cull.cpp
@@ -1970,6 +1970,8 @@ void RendererCanvasCull::canvas_light_occluder_set_polygon(RID p_occluder, RID p
void RendererCanvasCull::canvas_light_occluder_set_as_sdf_collision(RID p_occluder, bool p_enable) {
RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
ERR_FAIL_NULL(occluder);
+
+ occluder->sdf_collision = p_enable;
}
void RendererCanvasCull::canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform) {
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index 6f56711151..fa8cf9c028 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -1931,7 +1931,7 @@ void RendererCanvasRenderRD::render_sdf(RID p_render_target, LightOccluderInstan
while (instance) {
OccluderPolygon *co = occluder_polygon_owner.get_or_null(instance->occluder);
- if (!co || co->sdf_index_array.is_null()) {
+ if (!co || co->sdf_index_array.is_null() || !instance->sdf_collision) {
instance = instance->next;
continue;
}
diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp
index 2b6644e893..962531c866 100644
--- a/servers/rendering/rendering_device.cpp
+++ b/servers/rendering/rendering_device.cpp
@@ -1350,6 +1350,9 @@ Vector<uint8_t> RenderingDevice::texture_get_data(RID p_texture, uint32_t p_laye
thread_local LocalVector<RDD::BufferTextureCopyRegion> command_buffer_texture_copy_regions_vector;
command_buffer_texture_copy_regions_vector.clear();
+ uint32_t block_w = 0, block_h = 0;
+ get_compressed_image_format_block_dimensions(tex->format, block_w, block_h);
+
uint32_t w = tex->width;
uint32_t h = tex->height;
uint32_t d = tex->depth;
@@ -1365,8 +1368,8 @@ Vector<uint8_t> RenderingDevice::texture_get_data(RID p_texture, uint32_t p_laye
copy_region.texture_region_size.z = d;
command_buffer_texture_copy_regions_vector.push_back(copy_region);
- w = MAX(1u, w >> 1);
- h = MAX(1u, h >> 1);
+ w = MAX(block_w, w >> 1);
+ h = MAX(block_h, h >> 1);
d = MAX(1u, d >> 1);
}
@@ -1395,8 +1398,6 @@ Vector<uint8_t> RenderingDevice::texture_get_data(RID p_texture, uint32_t p_laye
for (uint32_t i = 0; i < tex->mipmaps; i++) {
uint32_t width = 0, height = 0, depth = 0;
uint32_t tight_mip_size = get_image_format_required_size(tex->format, w, h, d, 1, &width, &height, &depth);
- uint32_t block_w = 0, block_h = 0;
- get_compressed_image_format_block_dimensions(tex->format, block_w, block_h);
uint32_t tight_row_pitch = tight_mip_size / ((height / block_h) * depth);
// Copy row-by-row to erase padding due to alignments.
@@ -1408,8 +1409,8 @@ Vector<uint8_t> RenderingDevice::texture_get_data(RID p_texture, uint32_t p_laye
wp += tight_row_pitch;
}
- w = MAX(1u, w >> 1);
- h = MAX(1u, h >> 1);
+ w = MAX(block_w, w >> 1);
+ h = MAX(block_h, h >> 1);
d = MAX(1u, d >> 1);
read_ptr += mip_layouts[i].size;
write_ptr += tight_mip_size;
@@ -6400,11 +6401,11 @@ Vector<int64_t> RenderingDevice::_draw_list_switch_to_next_pass_split(uint32_t p
#endif
void RenderingDevice::_draw_list_set_push_constant(DrawListID p_list, const Vector<uint8_t> &p_data, uint32_t p_data_size) {
- ERR_FAIL_COND((uint32_t)p_data.size() > p_data_size);
+ ERR_FAIL_COND(p_data_size > (uint32_t)p_data.size());
draw_list_set_push_constant(p_list, p_data.ptr(), p_data_size);
}
void RenderingDevice::_compute_list_set_push_constant(ComputeListID p_list, const Vector<uint8_t> &p_data, uint32_t p_data_size) {
- ERR_FAIL_COND((uint32_t)p_data.size() > p_data_size);
+ ERR_FAIL_COND(p_data_size > (uint32_t)p_data.size());
compute_list_set_push_constant(p_list, p_data.ptr(), p_data_size);
}
diff --git a/tests/core/io/test_resource.h b/tests/core/io/test_resource.h
index 9ddb51220b..a83e7f88ba 100644
--- a/tests/core/io/test_resource.h
+++ b/tests/core/io/test_resource.h
@@ -38,6 +38,8 @@
#include "thirdparty/doctest/doctest.h"
+#include "tests/test_macros.h"
+
namespace TestResource {
TEST_CASE("[Resource] Duplication") {
@@ -124,9 +126,12 @@ TEST_CASE("[Resource] Breaking circular references on save") {
const String save_path_binary = OS::get_singleton()->get_cache_path().path_join("resource.res");
const String save_path_text = OS::get_singleton()->get_cache_path().path_join("resource.tres");
ResourceSaver::save(resource_a, save_path_binary);
+ // Suppress expected errors caused by the resources above being uncached.
+ ERR_PRINT_OFF;
ResourceSaver::save(resource_a, save_path_text);
const Ref<Resource> &loaded_resource_a_binary = ResourceLoader::load(save_path_binary);
+ ERR_PRINT_ON;
CHECK_MESSAGE(
loaded_resource_a_binary->get_name() == "A",
"The loaded resource name should be equal to the expected value.");