summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/config/project_settings.cpp2
-rw-r--r--core/extension/gdextension.cpp2
-rw-r--r--core/math/basis.cpp2
-rw-r--r--core/object/script_instance.h2
-rw-r--r--core/object/worker_thread_pool.cpp2
-rw-r--r--core/string/ustring.cpp2
-rw-r--r--core/templates/rid_owner.h2
-rw-r--r--core/variant/variant_construct.h2
-rw-r--r--doc/classes/Quaternion.xml99
-rw-r--r--doc/classes/Skeleton3D.xml5
-rw-r--r--doc/classes/String.xml4
-rw-r--r--doc/classes/Vector2.xml6
-rw-r--r--doc/classes/Vector3.xml6
-rw-r--r--drivers/d3d12/rendering_device_driver_d3d12.cpp2
-rw-r--r--drivers/gles3/storage/mesh_storage.cpp2
-rw-r--r--editor/editor_resource_preview.cpp31
-rw-r--r--editor/editor_resource_preview.h11
-rw-r--r--editor/editor_run_native.cpp27
-rw-r--r--editor/editor_run_native.h4
-rw-r--r--editor/editor_settings.cpp6
-rw-r--r--editor/export/editor_export_platform.h1
-rw-r--r--editor/gui/scene_tree_editor.cpp2
-rw-r--r--editor/plugins/editor_preview_plugins.cpp48
-rw-r--r--editor/plugins/editor_preview_plugins.h15
-rw-r--r--editor/plugins/script_editor_plugin.cpp4
-rw-r--r--misc/extension_api_validation/4.2-stable.expected9
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp11
-rw-r--r--modules/gdscript/gdscript_cache.cpp79
-rw-r--r--modules/gdscript/gdscript_cache.h6
-rw-r--r--modules/gdscript/language_server/godot_lsp.h2
-rw-r--r--modules/mono/csharp_script.cpp17
-rw-r--r--modules/mono/editor/bindings_generator.cpp671
-rw-r--r--modules/mono/editor/bindings_generator.h21
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs12
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs12
-rw-r--r--modules/multiplayer/editor/replication_editor.cpp2
-rw-r--r--modules/multiplayer/scene_replication_interface.cpp2
-rw-r--r--modules/openxr/extensions/openxr_eye_gaze_interaction.cpp7
-rw-r--r--modules/openxr/register_types.cpp4
-rw-r--r--platform/android/export/export_plugin.cpp9
-rw-r--r--platform/android/export/export_plugin.h3
-rw-r--r--platform/macos/dir_access_macos.mm7
-rw-r--r--platform/macos/godot_application_delegate.mm3
-rw-r--r--platform/windows/display_server_windows.cpp60
-rw-r--r--scene/2d/tile_map_layer.cpp4
-rw-r--r--scene/3d/skeleton_3d.compat.inc41
-rw-r--r--scene/3d/skeleton_3d.cpp10
-rw-r--r--scene/3d/skeleton_3d.h8
-rw-r--r--scene/gui/button.cpp16
-rw-r--r--scene/gui/button.h3
-rw-r--r--scene/gui/check_box.cpp16
-rw-r--r--scene/gui/check_button.cpp16
-rw-r--r--scene/gui/option_button.cpp2
-rw-r--r--scene/gui/text_edit.cpp6
-rw-r--r--scene/main/node.cpp8
-rw-r--r--scene/main/viewport.cpp2
-rw-r--r--scene/resources/skeleton_modification_2d_twoboneik.cpp12
-rw-r--r--servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp2
-rw-r--r--servers/rendering/rendering_device.cpp10
59 files changed, 1054 insertions, 328 deletions
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index d3cbae2f29..d9a5a5094a 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -1093,7 +1093,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
} else if (p_path.ends_with(".binary")) {
return _save_settings_binary(p_path, save_props, p_custom, save_features);
} else {
- ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED, "Unknown config file format: " + p_path + ".");
+ ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED, "Unknown config file format: " + p_path);
}
}
diff --git a/core/extension/gdextension.cpp b/core/extension/gdextension.cpp
index c1298c8687..5d43dceece 100644
--- a/core/extension/gdextension.cpp
+++ b/core/extension/gdextension.cpp
@@ -431,7 +431,7 @@ void GDExtension::_register_extension_class_internal(GDExtensionClassLibraryPtr
//inheriting from engine class
}
} else {
- ERR_FAIL_MSG("Attempt to register an extension class '" + String(class_name) + "' using non-existing parent class '" + String(parent_class_name) + "'");
+ ERR_FAIL_MSG("Attempt to register an extension class '" + String(class_name) + "' using non-existing parent class '" + String(parent_class_name) + "'.");
}
#ifdef TOOLS_ENABLED
diff --git a/core/math/basis.cpp b/core/math/basis.cpp
index 1ff6cdd588..5c31095960 100644
--- a/core/math/basis.cpp
+++ b/core/math/basis.cpp
@@ -685,7 +685,7 @@ void Basis::set_euler(const Vector3 &p_euler, EulerOrder p_order) {
*this = zmat * ymat * xmat;
} break;
default: {
- ERR_FAIL_MSG("Invalid order parameter for set_euler(vec3,order)");
+ ERR_FAIL_MSG("Invalid Euler order parameter.");
}
}
}
diff --git a/core/object/script_instance.h b/core/object/script_instance.h
index df978a25ea..45d51534fc 100644
--- a/core/object/script_instance.h
+++ b/core/object/script_instance.h
@@ -76,7 +76,7 @@ public:
}
//this is used by script languages that keep a reference counter of their own
- //you can make make Ref<> not die when it reaches zero, so deleting the reference
+ //you can make Ref<> not die when it reaches zero, so deleting the reference
//depends entirely from the script
virtual void refcount_incremented() {}
diff --git a/core/object/worker_thread_pool.cpp b/core/object/worker_thread_pool.cpp
index e2ab473b01..ef3d315e4b 100644
--- a/core/object/worker_thread_pool.cpp
+++ b/core/object/worker_thread_pool.cpp
@@ -551,7 +551,7 @@ void WorkerThreadPool::wait_for_group_task_completion(GroupID p_group) {
Group **groupp = groups.getptr(p_group);
task_mutex.unlock();
if (!groupp) {
- ERR_FAIL_MSG("Invalid Group ID");
+ ERR_FAIL_MSG("Invalid Group ID.");
}
{
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index 540891b3b0..a8a96e6e3f 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -1536,7 +1536,7 @@ String String::num(double p_num, int p_decimals) {
fmt[5] = 'f';
fmt[6] = 0;
}
- // if we want to convert a double with as much decimal places as as
+ // if we want to convert a double with as much decimal places as
// DBL_MAX or DBL_MIN then we would theoretically need a buffer of at least
// DBL_MAX_10_EXP + 2 for DBL_MAX and DBL_MAX_10_EXP + 4 for DBL_MIN.
// BUT those values where still giving me exceptions, so I tested from
diff --git a/core/templates/rid_owner.h b/core/templates/rid_owner.h
index e6c62ebf43..f92e0f4162 100644
--- a/core/templates/rid_owner.h
+++ b/core/templates/rid_owner.h
@@ -270,7 +270,7 @@ public:
if (THREAD_SAFE) {
spin_lock.unlock();
}
- ERR_FAIL_MSG("Attempted to free an uninitialized or invalid RID");
+ ERR_FAIL_MSG("Attempted to free an uninitialized or invalid RID.");
} else if (unlikely(validator_chunks[idx_chunk][idx_element] != validator)) {
if (THREAD_SAFE) {
spin_lock.unlock();
diff --git a/core/variant/variant_construct.h b/core/variant/variant_construct.h
index ef7bf2dfc2..36935907ae 100644
--- a/core/variant/variant_construct.h
+++ b/core/variant/variant_construct.h
@@ -661,7 +661,7 @@ public:
VariantInternal::clear(r_ret);
}
static void ptr_construct(void *base, const void **p_args) {
- ERR_FAIL_MSG("can't ptrcall nil constructor");
+ ERR_FAIL_MSG("Cannot ptrcall nil constructor");
}
static int get_argument_count() {
diff --git a/doc/classes/Quaternion.xml b/doc/classes/Quaternion.xml
index 411935aa79..8b59448555 100644
--- a/doc/classes/Quaternion.xml
+++ b/doc/classes/Quaternion.xml
@@ -4,19 +4,24 @@
A unit quaternion used for representing 3D rotations.
</brief_description>
<description>
- Quaternions are similar to [Basis], which implements the matrix representation of rotations. Unlike [Basis], which stores rotation, scale, and shearing, quaternions only store rotation.
- Quaternions can be parametrized using both an axis-angle pair or Euler angles. Due to their compactness and the way they are stored in memory, certain operations (obtaining axis-angle and performing SLERP, in particular) are more efficient and robust against floating-point errors.
- [b]Note:[/b] Quaternions need to be normalized before being used for rotation.
+ The [Quaternion] built-in [Variant] type is a 4D data structure that represents rotation in the form of a [url=https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation]Hamilton convention quaternion[/url]. Compared to the [Basis] type which can store both rotation and scale, quaternions can [i]only[/i] store rotation.
+ A [Quaternion] is composed by 4 floating-point components: [member w], [member x], [member y], and [member z]. These components are very compact in memory, and because of this some operations are more efficient and less likely to cause floating-point errors. Methods such as [method get_angle], [method get_axis], and [method slerp] are faster than their [Basis] counterparts.
+ For a great introduction to quaternions, see [url=https://www.youtube.com/watch?v=d4EgbgTm0Bg]this video by 3Blue1Brown[/url]. You do not need to know the math behind quaternions, as Godot provides several helper methods that handle it for you. These include [method slerp] and [method spherical_cubic_interpolate], as well as the [code]*[/code] operator.
+ [b]Note:[/b] Quaternions must be normalized before being used for rotation (see [method normalized]).
+ [b]Note:[/b] Similarly to [Vector2] and [Vector3], the components of a quaternion use 32-bit precision by default, unlike [float] which is always 64-bit. If double precision is needed, compile the engine with the option [code]precision=double[/code].
</description>
<tutorials>
+ <link title="3Blue1Brown&apos;s video on Quaternions">https://www.youtube.com/watch?v=d4EgbgTm0Bg</link>
+ <link title="Online Quaternion Visualization">https://quaternions.online/</link>
<link title="Using 3D transforms">$DOCS_URL/tutorials/3d/using_transforms.html#interpolating-with-quaternions</link>
<link title="Third Person Shooter Demo">https://godotengine.org/asset-library/asset/678</link>
+ <link title="Advanced Quaternion Visualization">https://iwatake2222.github.io/rotation_master/rotation_master.html</link>
</tutorials>
<constructors>
<constructor name="Quaternion">
<return type="Quaternion" />
<description>
- Constructs a default-initialized quaternion with all components set to [code]0[/code].
+ Constructs a [Quaternion] identical to the [constant IDENTITY].
</description>
</constructor>
<constructor name="Quaternion">
@@ -31,7 +36,7 @@
<param index="0" name="arc_from" type="Vector3" />
<param index="1" name="arc_to" type="Vector3" />
<description>
- Constructs a quaternion representing the shortest arc between two points on the surface of a sphere with a radius of [code]1.0[/code].
+ Constructs a [Quaternion] representing the shortest arc between [param arc_from] and [param arc_to]. These can be imagined as two points intersecting a sphere's surface, with a radius of [code]1.0[/code].
</description>
</constructor>
<constructor name="Quaternion">
@@ -39,14 +44,15 @@
<param index="0" name="axis" type="Vector3" />
<param index="1" name="angle" type="float" />
<description>
- Constructs a quaternion that will rotate around the given axis by the specified angle. The axis must be a normalized vector.
+ Constructs a [Quaternion] representing rotation around the [param axis] by the given [param angle], in radians. The axis must be a normalized vector.
</description>
</constructor>
<constructor name="Quaternion">
<return type="Quaternion" />
<param index="0" name="from" type="Basis" />
<description>
- Constructs a quaternion from the given [Basis].
+ Constructs a [Quaternion] from the given rotation [Basis].
+ This constructor is faster than [method Basis.get_rotation_quaternion], but the given basis must be [i]orthonormalized[/i] (see [method Basis.orthonormalized]). Otherwise, the constructor fails and returns [constant IDENTITY].
</description>
</constructor>
<constructor name="Quaternion">
@@ -56,7 +62,8 @@
<param index="2" name="z" type="float" />
<param index="3" name="w" type="float" />
<description>
- Constructs a quaternion defined by the given values.
+ Constructs a [Quaternion] defined by the given values.
+ [b]Note:[/b] Only normalized quaternions represent rotation; if these values are not normalized, the new [Quaternion] will not be a valid rotation.
</description>
</constructor>
</constructors>
@@ -73,7 +80,8 @@
<return type="float" />
<param index="0" name="with" type="Quaternion" />
<description>
- Returns the dot product of two quaternions.
+ Returns the dot product between this quaternion and [param with].
+ This is equivalent to [code](quat.x * with.x) + (quat.y * with.y) + (quat.z * with.z) + (quat.w * with.w)[/code].
</description>
</method>
<method name="exp" qualifiers="const">
@@ -86,7 +94,7 @@
<return type="Quaternion" />
<param index="0" name="euler" type="Vector3" />
<description>
- Constructs a Quaternion from Euler angles in YXZ rotation order.
+ Constructs a new [Quaternion] from the given [Vector3] of [url=https://en.wikipedia.org/wiki/Euler_angles]Euler angles[/url], in radians. This method always uses the YXZ convention ([constant EULER_ORDER_YXZ]).
</description>
</method>
<method name="get_angle" qualifiers="const">
@@ -106,13 +114,14 @@
<return type="Vector3" />
<param index="0" name="order" type="int" default="2" />
<description>
- Returns the quaternion's rotation in the form of Euler angles. The Euler order depends on the [param order] parameter, for example using the YXZ convention: since this method decomposes, first Z, then X, and Y last. See the [enum EulerOrder] enum for possible values. The returned vector contains the rotation angles in the format (X angle, Y angle, Z angle).
+ Returns this quaternion's rotation as a [Vector3] of [url=https://en.wikipedia.org/wiki/Euler_angles]Euler angles[/url], in radians.
+ The order of each consecutive rotation can be changed with [param order] (see [enum EulerOrder] constants). By default, the YXZ convention is used ([constant EULER_ORDER_YXZ]): Z (roll) is calculated first, then X (pitch), and lastly Y (yaw). When using the opposite method [method from_euler], this order is reversed.
</description>
</method>
<method name="inverse" qualifiers="const">
<return type="Quaternion" />
<description>
- Returns the inverse of the quaternion.
+ Returns the inverse version of this quaternion, inverting the sign of every component except [member w].
</description>
</method>
<method name="is_equal_approx" qualifiers="const">
@@ -131,31 +140,32 @@
<method name="is_normalized" qualifiers="const">
<return type="bool" />
<description>
- Returns whether the quaternion is normalized or not.
+ Returns [code]true[/code] if this quaternion is normalized. See also [method normalized].
</description>
</method>
<method name="length" qualifiers="const" keywords="size">
<return type="float" />
<description>
- Returns the length of the quaternion.
+ Returns this quaternion's length, also called magnitude.
</description>
</method>
<method name="length_squared" qualifiers="const">
<return type="float" />
<description>
- Returns the length of the quaternion, squared.
+ Returns this quaternion's length, squared.
+ [b]Note:[/b] This method is faster than [method length], so prefer it if you only need to compare quaternion lengths.
</description>
</method>
<method name="log" qualifiers="const">
<return type="Quaternion" />
<description>
- Returns the logarithm of this quaternion. The vector part of the result is the rotation axis of this quaternion multiplied by its rotation angle, the real part of the result is zero.
+ Returns the logarithm of this quaternion. Multiplies this quaternion's rotation axis by its rotation angle, and stores the result in the returned quaternion's vector part ([member x], [member y], and [member z]). The returned quaternion's real part ([member w]) is always [code]0.0[/code].
</description>
</method>
<method name="normalized" qualifiers="const">
<return type="Quaternion" />
<description>
- Returns a copy of the quaternion, normalized to unit length.
+ Returns a copy of this quaternion, normalized so that its length is [code]1.0[/code]. See also [method is_normalized].
</description>
</method>
<method name="slerp" qualifiers="const" keywords="interpolate">
@@ -163,8 +173,7 @@
<param index="0" name="to" type="Quaternion" />
<param index="1" name="weight" type="float" />
<description>
- Returns the result of the spherical linear interpolation between this quaternion and [param to] by amount [param weight].
- [b]Note:[/b] Both quaternions must be normalized.
+ Performs a spherical-linear interpolation with the [param to] quaternion, given a [param weight] and returns the result. Both this quaternion and [param to] must be normalized.
</description>
</method>
<method name="slerpni" qualifiers="const">
@@ -172,7 +181,7 @@
<param index="0" name="to" type="Quaternion" />
<param index="1" name="weight" type="float" />
<description>
- Returns the result of the spherical linear interpolation between this quaternion and [param to] by amount [param weight], but without checking if the rotation path is not bigger than 90 degrees.
+ Performs a spherical-linear interpolation with the [param to] quaternion, given a [param weight] and returns the result. Unlike [method slerp], this method does not check if the rotation path is smaller than 90 degrees. Both this quaternion and [param to] must be normalized.
</description>
</method>
<method name="spherical_cubic_interpolate" qualifiers="const">
@@ -202,25 +211,26 @@
</methods>
<members>
<member name="w" type="float" setter="" getter="" default="1.0">
- W component of the quaternion (real part).
- Quaternion components should usually not be manipulated directly.
+ W component of the quaternion. This is the "real" part.
+ [b]Note:[/b] Quaternion components should usually not be manipulated directly.
</member>
<member name="x" type="float" setter="" getter="" default="0.0">
- X component of the quaternion (imaginary [code]i[/code] axis part).
- Quaternion components should usually not be manipulated directly.
+ X component of the quaternion. This is the value along the "imaginary" [code]i[/code] axis.
+ [b]Note:[/b] Quaternion components should usually not be manipulated directly.
</member>
<member name="y" type="float" setter="" getter="" default="0.0">
- Y component of the quaternion (imaginary [code]j[/code] axis part).
- Quaternion components should usually not be manipulated directly.
+ Y component of the quaternion. This is the value along the "imaginary" [code]j[/code] axis.
+ [b]Note:[/b] Quaternion components should usually not be manipulated directly.
</member>
<member name="z" type="float" setter="" getter="" default="0.0">
- Z component of the quaternion (imaginary [code]k[/code] axis part).
- Quaternion components should usually not be manipulated directly.
+ Z component of the quaternion. This is the value along the "imaginary" [code]k[/code] axis.
+ [b]Note:[/b] Quaternion components should usually not be manipulated directly.
</member>
</members>
<constants>
<constant name="IDENTITY" value="Quaternion(0, 0, 0, 1)">
- The identity quaternion, representing no rotation. Equivalent to an identity [Basis] matrix. If a vector is transformed by an identity quaternion, it will not change.
+ The identity quaternion, representing no rotation. This has the same rotation as [constant Basis.IDENTITY].
+ If a [Vector3] is rotated (multiplied) by this quaternion, it does not change.
</constant>
</constants>
<operators>
@@ -228,7 +238,7 @@
<return type="bool" />
<param index="0" name="right" type="Quaternion" />
<description>
- Returns [code]true[/code] if the quaternions are not equal.
+ Returns [code]true[/code] if the components of both quaternions are not exactly equal.
[b]Note:[/b] Due to floating-point precision errors, consider using [method is_equal_approx] instead, which is more reliable.
</description>
</operator>
@@ -236,63 +246,69 @@
<return type="Quaternion" />
<param index="0" name="right" type="Quaternion" />
<description>
- Composes these two quaternions by multiplying them together. This has the effect of rotating the second quaternion (the child) by the first quaternion (the parent).
+ Composes (multiplies) two quaternions. This rotates the [param right] quaternion (the child) by this quaternion (the parent).
</description>
</operator>
<operator name="operator *">
<return type="Vector3" />
<param index="0" name="right" type="Vector3" />
<description>
- Rotates (multiplies) the [Vector3] by the given [Quaternion].
+ Rotates (multiplies) the [param right] vector by this quaternion, returning a [Vector3].
</description>
</operator>
<operator name="operator *">
<return type="Quaternion" />
<param index="0" name="right" type="float" />
<description>
- Multiplies each component of the [Quaternion] by the given value. This operation is not meaningful on its own, but it can be used as a part of a larger expression.
+ Multiplies each component of the [Quaternion] by the right [float] value.
+ This operation is not meaningful on its own, but it can be used as a part of a larger expression.
</description>
</operator>
<operator name="operator *">
<return type="Quaternion" />
<param index="0" name="right" type="int" />
<description>
- Multiplies each component of the [Quaternion] by the given value. This operation is not meaningful on its own, but it can be used as a part of a larger expression.
+ Multiplies each component of the [Quaternion] by the right [int] value.
+ This operation is not meaningful on its own, but it can be used as a part of a larger expression.
</description>
</operator>
<operator name="operator +">
<return type="Quaternion" />
<param index="0" name="right" type="Quaternion" />
<description>
- Adds each component of the left [Quaternion] to the right [Quaternion]. This operation is not meaningful on its own, but it can be used as a part of a larger expression, such as approximating an intermediate rotation between two nearby rotations.
+ Adds each component of the left [Quaternion] to the right [Quaternion].
+ This operation is not meaningful on its own, but it can be used as a part of a larger expression, such as approximating an intermediate rotation between two nearby rotations.
</description>
</operator>
<operator name="operator -">
<return type="Quaternion" />
<param index="0" name="right" type="Quaternion" />
<description>
- Subtracts each component of the left [Quaternion] by the right [Quaternion]. This operation is not meaningful on its own, but it can be used as a part of a larger expression.
+ Subtracts each component of the left [Quaternion] by the right [Quaternion].
+ This operation is not meaningful on its own, but it can be used as a part of a larger expression.
</description>
</operator>
<operator name="operator /">
<return type="Quaternion" />
<param index="0" name="right" type="float" />
<description>
- Divides each component of the [Quaternion] by the given value. This operation is not meaningful on its own, but it can be used as a part of a larger expression.
+ Divides each component of the [Quaternion] by the right [float] value.
+ This operation is not meaningful on its own, but it can be used as a part of a larger expression.
</description>
</operator>
<operator name="operator /">
<return type="Quaternion" />
<param index="0" name="right" type="int" />
<description>
- Divides each component of the [Quaternion] by the given value. This operation is not meaningful on its own, but it can be used as a part of a larger expression.
+ Divides each component of the [Quaternion] by the right [int] value.
+ This operation is not meaningful on its own, but it can be used as a part of a larger expression.
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
<param index="0" name="right" type="Quaternion" />
<description>
- Returns [code]true[/code] if the quaternions are exactly equal.
+ Returns [code]true[/code] if the components of both quaternions are exactly equal.
[b]Note:[/b] Due to floating-point precision errors, consider using [method is_equal_approx] instead, which is more reliable.
</description>
</operator>
@@ -300,7 +316,8 @@
<return type="float" />
<param index="0" name="index" type="int" />
<description>
- Access quaternion components using their index. [code]q[0][/code] is equivalent to [code]q.x[/code], [code]q[1][/code] is equivalent to [code]q.y[/code], [code]q[2][/code] is equivalent to [code]q.z[/code], and [code]q[3][/code] is equivalent to [code]q.w[/code].
+ Accesses each component of this quaternion by their index.
+ Index [code]0[/code] is the same as [member x], index [code]1[/code] is the same as [member y], index [code]2[/code] is the same as [member z], and index [code]3[/code] is the same as [member w].
</description>
</operator>
<operator name="operator unary+">
@@ -312,7 +329,7 @@
<operator name="operator unary-">
<return type="Quaternion" />
<description>
- Returns the negative value of the [Quaternion]. This is the same as writing [code]Quaternion(-q.x, -q.y, -q.z, -q.w)[/code]. This operation results in a quaternion that represents the same rotation.
+ Returns the negative value of the [Quaternion]. This is the same as multiplying all components by [code]-1[/code]. This operation results in a quaternion that represents the same rotation.
</description>
</operator>
</operators>
diff --git a/doc/classes/Skeleton3D.xml b/doc/classes/Skeleton3D.xml
index 2c55f0dcd1..b6be0e92a3 100644
--- a/doc/classes/Skeleton3D.xml
+++ b/doc/classes/Skeleton3D.xml
@@ -14,10 +14,11 @@
</tutorials>
<methods>
<method name="add_bone">
- <return type="void" />
+ <return type="int" />
<param index="0" name="name" type="String" />
<description>
- Adds a bone, with name [param name]. [method get_bone_count] will become the bone index.
+ Adds a new bone with the given name. Returns the new bone's index, or [code]-1[/code] if this method fails.
+ [b]Note:[/b] Bone names should be unique, non empty, and cannot include the [code]:[/code] and [code]/[/code] characters.
</description>
</method>
<method name="clear_bones">
diff --git a/doc/classes/String.xml b/doc/classes/String.xml
index cffe9e219d..17f953f48f 100644
--- a/doc/classes/String.xml
+++ b/doc/classes/String.xml
@@ -651,8 +651,8 @@
[codeblocks]
[gdscript]
var n = -5.2e8
- print(n) # Prints -520000000
- print(String.NumScientific(n)) # Prints -5.2e+08
+ print(n) # Prints -520000000
+ print(String.num_scientific(n)) # Prints -5.2e+08
[/gdscript]
[csharp]
// This method is not implemented in C#.
diff --git a/doc/classes/Vector2.xml b/doc/classes/Vector2.xml
index 76f97d0968..bdc49b5c31 100644
--- a/doc/classes/Vector2.xml
+++ b/doc/classes/Vector2.xml
@@ -315,7 +315,8 @@
<return type="Vector2" />
<param index="0" name="b" type="Vector2" />
<description>
- Returns the result of projecting the vector onto the given vector [param b].
+ Returns a new vector resulting from projecting this vector onto the given vector [param b]. The resulting new vector is parallel to [param b]. See also [method slide].
+ [b]Note:[/b] If the vector [param b] is a zero vector, the components of the resulting new vector will be [constant @GDScript.NAN].
</description>
</method>
<method name="reflect" qualifiers="const">
@@ -357,7 +358,8 @@
<return type="Vector2" />
<param index="0" name="n" type="Vector2" />
<description>
- Returns the result of sliding the vector along a plane defined by the given normal.
+ Returns a new vector resulting from sliding this vector along a line with normal [param n]. The resulting new vector is perpendicular to [param n], and is equivalent to this vector minus its projection on [param n]. See also [method project].
+ [b]Note:[/b] The vector [param n] must be normalized. See also [method normalized].
</description>
</method>
<method name="snapped" qualifiers="const">
diff --git a/doc/classes/Vector3.xml b/doc/classes/Vector3.xml
index 5730826043..b9b0346250 100644
--- a/doc/classes/Vector3.xml
+++ b/doc/classes/Vector3.xml
@@ -299,7 +299,8 @@
<return type="Vector3" />
<param index="0" name="b" type="Vector3" />
<description>
- Returns the result of projecting the vector onto the given vector [param b].
+ Returns a new vector resulting from projecting this vector onto the given vector [param b]. The resulting new vector is parallel to [param b]. See also [method slide].
+ [b]Note:[/b] If the vector [param b] is a zero vector, the components of the resulting new vector will be [constant @GDScript.NAN].
</description>
</method>
<method name="reflect" qualifiers="const">
@@ -350,7 +351,8 @@
<return type="Vector3" />
<param index="0" name="n" type="Vector3" />
<description>
- Returns a new vector slid along a plane defined by the given normal.
+ Returns a new vector resulting from sliding this vector along a plane with normal [param n]. The resulting new vector is perpendicular to [param n], and is equivalent to this vector minus its projection on [param n]. See also [method project].
+ [b]Note:[/b] The vector [param n] must be normalized. See also [method normalized].
</description>
</method>
<method name="snapped" qualifiers="const">
diff --git a/drivers/d3d12/rendering_device_driver_d3d12.cpp b/drivers/d3d12/rendering_device_driver_d3d12.cpp
index 6efef0fb34..e74ea910a0 100644
--- a/drivers/d3d12/rendering_device_driver_d3d12.cpp
+++ b/drivers/d3d12/rendering_device_driver_d3d12.cpp
@@ -1860,7 +1860,7 @@ void RenderingDeviceDriverD3D12::command_pipeline_barrier(
VectorView<RDD::BufferBarrier> p_buffer_barriers,
VectorView<RDD::TextureBarrier> p_texture_barriers) {
if (p_src_stages.has_flag(PIPELINE_STAGE_ALL_COMMANDS_BIT) && p_dst_stages.has_flag(PIPELINE_STAGE_ALL_COMMANDS_BIT)) {
- // Looks like the intent is a a full barrier.
+ // Looks like the intent is a full barrier.
// In the resource barriers world, we can force a full barrier by discarding some resource, as per
// https://microsoft.github.io/DirectX-Specs/d3d/D3D12EnhancedBarriers.html#synchronous-copy-discard-and-resolve.
const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp
index 8ab66e2bc6..1dcd29553d 100644
--- a/drivers/gles3/storage/mesh_storage.cpp
+++ b/drivers/gles3/storage/mesh_storage.cpp
@@ -219,7 +219,7 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
glGenBuffers(1, &s->vertex_buffer);
glBindBuffer(GL_ARRAY_BUFFER, s->vertex_buffer);
// If we have an uncompressed surface that contains normals, but not tangents, we need to differentiate the array
- // from a compressed array in the shader. To do so, we allow the the normal to read 4 components out of the buffer
+ // from a compressed array in the shader. To do so, we allow the normal to read 4 components out of the buffer
// But only give it 2 components per normal. So essentially, each vertex reads the next normal in normal.zw.
// This allows us to avoid adding a shader permutation, and avoid passing dummy tangents. Since the stride is kept small
// this should still be a net win for bandwidth.
diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp
index bae7887c02..fc1dda9669 100644
--- a/editor/editor_resource_preview.cpp
+++ b/editor/editor_resource_preview.cpp
@@ -95,8 +95,35 @@ void EditorResourcePreviewGenerator::_bind_methods() {
EditorResourcePreviewGenerator::EditorResourcePreviewGenerator() {
}
+void EditorResourcePreviewGenerator::DrawRequester::request_and_wait(RID p_viewport) const {
+ if (EditorResourcePreview::get_singleton()->is_threaded()) {
+ Callable request_vp_update_once = callable_mp(RS::get_singleton(), &RS::viewport_set_update_mode).bind(p_viewport, RS::VIEWPORT_UPDATE_ONCE);
+ RS::get_singleton()->connect(SNAME("frame_pre_draw"), request_vp_update_once, Object::CONNECT_ONE_SHOT);
+ RS::get_singleton()->request_frame_drawn_callback(callable_mp(const_cast<EditorResourcePreviewGenerator::DrawRequester *>(this), &EditorResourcePreviewGenerator::DrawRequester::_post_semaphore));
+
+ semaphore.wait();
+ } else {
+ RS::get_singleton()->draw(false);
+ }
+}
+
+void EditorResourcePreviewGenerator::DrawRequester::abort() const {
+ if (EditorResourcePreview::get_singleton()->is_threaded()) {
+ semaphore.post();
+ }
+}
+
+Variant EditorResourcePreviewGenerator::DrawRequester::_post_semaphore() const {
+ semaphore.post();
+ return Variant(); // Needed because of how the callback is used.
+}
+
EditorResourcePreview *EditorResourcePreview::singleton = nullptr;
+bool EditorResourcePreview::is_threaded() const {
+ return RSG::texture_storage->can_create_resources_async();
+}
+
void EditorResourcePreview::_thread_func(void *ud) {
EditorResourcePreview *erp = (EditorResourcePreview *)ud;
erp->_thread();
@@ -470,7 +497,7 @@ void EditorResourcePreview::start() {
return;
}
- if (RSG::texture_storage->can_create_resources_async()) {
+ if (is_threaded()) {
ERR_FAIL_COND_MSG(thread.is_started(), "Thread already started.");
thread.start(_thread_func, this);
} else {
@@ -481,7 +508,7 @@ void EditorResourcePreview::start() {
}
void EditorResourcePreview::stop() {
- if (RSG::texture_storage->can_create_resources_async()) {
+ if (is_threaded()) {
if (thread.is_started()) {
exiting.set();
preview_sem.post();
diff --git a/editor/editor_resource_preview.h b/editor/editor_resource_preview.h
index bc99372bc2..3cad56f75e 100644
--- a/editor/editor_resource_preview.h
+++ b/editor/editor_resource_preview.h
@@ -51,6 +51,16 @@ protected:
GDVIRTUAL0RC(bool, _generate_small_preview_automatically)
GDVIRTUAL0RC(bool, _can_generate_small_preview)
+ class DrawRequester : public Object {
+ Semaphore semaphore;
+
+ Variant _post_semaphore() const;
+
+ public:
+ void request_and_wait(RID p_viewport) const;
+ void abort() const;
+ };
+
public:
virtual bool handles(const String &p_type) const;
virtual Ref<Texture2D> generate(const Ref<Resource> &p_from, const Size2 &p_size, Dictionary &p_metadata) const;
@@ -132,6 +142,7 @@ public:
void start();
void stop();
+ bool is_threaded() const;
EditorResourcePreview();
~EditorResourcePreview();
diff --git a/editor/editor_run_native.cpp b/editor/editor_run_native.cpp
index a380ebd4ad..4eb3f07c47 100644
--- a/editor/editor_run_native.cpp
+++ b/editor/editor_run_native.cpp
@@ -79,6 +79,11 @@ void EditorRunNative::_notification(int p_what) {
}
}
+void EditorRunNative::_confirm_run_native() {
+ run_confirmed = true;
+ resume_run_native();
+}
+
Error EditorRunNative::start_run_native(int p_id) {
if (p_id < 0) {
return OK;
@@ -86,9 +91,9 @@ Error EditorRunNative::start_run_native(int p_id) {
int platform = p_id / 10000;
int idx = p_id % 10000;
+ resume_id = p_id;
if (!EditorNode::get_singleton()->ensure_main_scene(true)) {
- resume_id = p_id;
return OK;
}
@@ -110,6 +115,22 @@ Error EditorRunNative::start_run_native(int p_id) {
return ERR_UNAVAILABLE;
}
+ String architecture = eep->get_device_architecture(idx);
+ if (!run_confirmed && !architecture.is_empty()) {
+ String preset_arch = "architectures/" + architecture;
+ bool is_arch_enabled = preset->get(preset_arch);
+
+ if (!is_arch_enabled) {
+ String warning_message = vformat(TTR("Warning: The CPU architecture '%s' is not active in your export preset.\n\n"), Variant(architecture));
+ warning_message += TTR("Run 'Remote Debug' anyway?");
+
+ run_native_confirm->set_text(warning_message);
+ run_native_confirm->popup_centered();
+ return OK;
+ }
+ }
+ run_confirmed = false;
+
emit_signal(SNAME("native_run"), preset);
int flags = 0;
@@ -174,5 +195,9 @@ EditorRunNative::EditorRunNative() {
add_child(result_dialog);
result_dialog->hide();
+ run_native_confirm = memnew(ConfirmationDialog);
+ add_child(run_native_confirm);
+ run_native_confirm->connect("confirmed", callable_mp(this, &EditorRunNative::_confirm_run_native));
+
set_process(true);
}
diff --git a/editor/editor_run_native.h b/editor/editor_run_native.h
index f52a455bb2..b7638f235e 100644
--- a/editor/editor_run_native.h
+++ b/editor/editor_run_native.h
@@ -41,12 +41,16 @@ class EditorRunNative : public HBoxContainer {
RichTextLabel *result_dialog_log = nullptr;
AcceptDialog *result_dialog = nullptr;
+ ConfirmationDialog *run_native_confirm = nullptr;
+ bool run_confirmed = false;
MenuButton *remote_debug = nullptr;
bool first = true;
int resume_id = -1;
+ void _confirm_run_native();
+
protected:
static void _bind_methods();
void _notification(int p_what);
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 63a9ab5684..853a4cd410 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -1588,7 +1588,7 @@ Ref<Shortcut> ED_GET_SHORTCUT(const String &p_path) {
Ref<Shortcut> sc = EditorSettings::get_singleton()->get_shortcut(p_path);
- ERR_FAIL_COND_V_MSG(!sc.is_valid(), sc, "Used ED_GET_SHORTCUT with invalid shortcut: " + p_path + ".");
+ ERR_FAIL_COND_V_MSG(!sc.is_valid(), sc, "Used ED_GET_SHORTCUT with invalid shortcut: " + p_path);
return sc;
}
@@ -1597,7 +1597,7 @@ void ED_SHORTCUT_OVERRIDE(const String &p_path, const String &p_feature, Key p_k
ERR_FAIL_NULL_MSG(EditorSettings::get_singleton(), "EditorSettings not instantiated yet.");
Ref<Shortcut> sc = EditorSettings::get_singleton()->get_shortcut(p_path);
- ERR_FAIL_COND_MSG(!sc.is_valid(), "Used ED_SHORTCUT_OVERRIDE with invalid shortcut: " + p_path + ".");
+ ERR_FAIL_COND_MSG(!sc.is_valid(), "Used ED_SHORTCUT_OVERRIDE with invalid shortcut: " + p_path);
PackedInt32Array arr;
arr.push_back((int32_t)p_keycode);
@@ -1609,7 +1609,7 @@ void ED_SHORTCUT_OVERRIDE_ARRAY(const String &p_path, const String &p_feature, c
ERR_FAIL_NULL_MSG(EditorSettings::get_singleton(), "EditorSettings not instantiated yet.");
Ref<Shortcut> sc = EditorSettings::get_singleton()->get_shortcut(p_path);
- ERR_FAIL_COND_MSG(!sc.is_valid(), "Used ED_SHORTCUT_OVERRIDE_ARRAY with invalid shortcut: " + p_path + ".");
+ ERR_FAIL_COND_MSG(!sc.is_valid(), "Used ED_SHORTCUT_OVERRIDE_ARRAY with invalid shortcut: " + p_path);
// Only add the override if the OS supports the provided feature.
if (!OS::get_singleton()->has_feature(p_feature)) {
diff --git a/editor/export/editor_export_platform.h b/editor/export/editor_export_platform.h
index 0b922cc6c8..8f2288d409 100644
--- a/editor/export/editor_export_platform.h
+++ b/editor/export/editor_export_platform.h
@@ -227,6 +227,7 @@ public:
virtual Ref<ImageTexture> get_option_icon(int p_index) const;
virtual String get_option_label(int p_device) const { return ""; }
virtual String get_option_tooltip(int p_device) const { return ""; }
+ virtual String get_device_architecture(int p_device) const { return ""; }
enum DebugFlags {
DEBUG_FLAG_DUMB_CLIENT = 1,
diff --git a/editor/gui/scene_tree_editor.cpp b/editor/gui/scene_tree_editor.cpp
index 14af49aabf..f54ded7c74 100644
--- a/editor/gui/scene_tree_editor.cpp
+++ b/editor/gui/scene_tree_editor.cpp
@@ -767,7 +767,7 @@ bool SceneTreeEditor::_item_matches_all_terms(TreeItem *p_item, PackedStringArra
// Filter by Type.
String type = get_node(p_item->get_metadata(0))->get_class();
bool term_in_inherited_class = false;
- // Every Node is is a Node, duh!
+ // Every Node is a Node, duh!
while (type != "Node") {
if (type.to_lower().contains(argument)) {
term_in_inherited_class = true;
diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp
index fbec9ca68f..e8804fdf12 100644
--- a/editor/plugins/editor_preview_plugins.cpp
+++ b/editor/plugins/editor_preview_plugins.cpp
@@ -285,18 +285,8 @@ EditorPackedScenePreviewPlugin::EditorPackedScenePreviewPlugin() {
//////////////////////////////////////////////////////////////////
-void EditorMaterialPreviewPlugin::_generate_frame_started() {
- RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_ONCE); //once used for capture
-
- RS::get_singleton()->request_frame_drawn_callback(callable_mp(const_cast<EditorMaterialPreviewPlugin *>(this), &EditorMaterialPreviewPlugin::_preview_done));
-}
-
-void EditorMaterialPreviewPlugin::_preview_done() {
- preview_done.post();
-}
-
void EditorMaterialPreviewPlugin::abort() {
- preview_done.post();
+ draw_requester.abort();
}
bool EditorMaterialPreviewPlugin::handles(const String &p_type) const {
@@ -314,9 +304,7 @@ Ref<Texture2D> EditorMaterialPreviewPlugin::generate(const Ref<Resource> &p_from
if (material->get_shader_mode() == Shader::MODE_SPATIAL) {
RS::get_singleton()->mesh_surface_set_material(sphere, 0, material->get_rid());
- RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<EditorMaterialPreviewPlugin *>(this), &EditorMaterialPreviewPlugin::_generate_frame_started), Object::CONNECT_ONE_SHOT);
-
- preview_done.wait();
+ draw_requester.request_and_wait(viewport);
Ref<Image> img = RS::get_singleton()->texture_2d_get(viewport_texture);
RS::get_singleton()->mesh_surface_set_material(sphere, 0, RID());
@@ -701,18 +689,8 @@ EditorAudioStreamPreviewPlugin::EditorAudioStreamPreviewPlugin() {
///////////////////////////////////////////////////////////////////////////
-void EditorMeshPreviewPlugin::_generate_frame_started() {
- RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_ONCE); //once used for capture
-
- RS::get_singleton()->request_frame_drawn_callback(callable_mp(const_cast<EditorMeshPreviewPlugin *>(this), &EditorMeshPreviewPlugin::_preview_done));
-}
-
-void EditorMeshPreviewPlugin::_preview_done() {
- preview_done.post();
-}
-
void EditorMeshPreviewPlugin::abort() {
- preview_done.post();
+ draw_requester.abort();
}
bool EditorMeshPreviewPlugin::handles(const String &p_type) const {
@@ -743,9 +721,7 @@ Ref<Texture2D> EditorMeshPreviewPlugin::generate(const Ref<Resource> &p_from, co
xform.origin.z -= rot_aabb.size.z * 2;
RS::get_singleton()->instance_set_transform(mesh_instance, xform);
- RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<EditorMeshPreviewPlugin *>(this), &EditorMeshPreviewPlugin::_generate_frame_started), Object::CONNECT_ONE_SHOT);
-
- preview_done.wait();
+ draw_requester.request_and_wait(viewport);
Ref<Image> img = RS::get_singleton()->texture_2d_get(viewport_texture);
ERR_FAIL_COND_V(img.is_null(), Ref<ImageTexture>());
@@ -822,18 +798,8 @@ EditorMeshPreviewPlugin::~EditorMeshPreviewPlugin() {
///////////////////////////////////////////////////////////////////////////
-void EditorFontPreviewPlugin::_generate_frame_started() {
- RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_ONCE); //once used for capture
-
- RS::get_singleton()->request_frame_drawn_callback(callable_mp(const_cast<EditorFontPreviewPlugin *>(this), &EditorFontPreviewPlugin::_preview_done));
-}
-
-void EditorFontPreviewPlugin::_preview_done() {
- preview_done.post();
-}
-
void EditorFontPreviewPlugin::abort() {
- preview_done.post();
+ draw_requester.abort();
}
bool EditorFontPreviewPlugin::handles(const String &p_type) const {
@@ -865,9 +831,7 @@ Ref<Texture2D> EditorFontPreviewPlugin::generate_from_path(const String &p_path,
const float fg = c.get_luminance() < 0.5 ? 1.0 : 0.0;
sampled_font->draw_string(canvas_item, pos, sample, HORIZONTAL_ALIGNMENT_LEFT, -1.f, 50, Color(fg, fg, fg));
- RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<EditorFontPreviewPlugin *>(this), &EditorFontPreviewPlugin::_generate_frame_started), Object::CONNECT_ONE_SHOT);
-
- preview_done.wait();
+ draw_requester.request_and_wait(viewport);
RS::get_singleton()->canvas_item_clear(canvas_item);
diff --git a/editor/plugins/editor_preview_plugins.h b/editor/plugins/editor_preview_plugins.h
index fa7015f423..2b3da76a9d 100644
--- a/editor/plugins/editor_preview_plugins.h
+++ b/editor/plugins/editor_preview_plugins.h
@@ -96,10 +96,7 @@ class EditorMaterialPreviewPlugin : public EditorResourcePreviewGenerator {
RID light_instance2;
RID camera;
RID camera_attributes;
- Semaphore preview_done;
-
- void _generate_frame_started();
- void _preview_done();
+ DrawRequester draw_requester;
public:
virtual bool handles(const String &p_type) const override;
@@ -147,10 +144,7 @@ class EditorMeshPreviewPlugin : public EditorResourcePreviewGenerator {
RID light_instance2;
RID camera;
RID camera_attributes;
- Semaphore preview_done;
-
- void _generate_frame_started();
- void _preview_done();
+ DrawRequester draw_requester;
public:
virtual bool handles(const String &p_type) const override;
@@ -168,10 +162,7 @@ class EditorFontPreviewPlugin : public EditorResourcePreviewGenerator {
RID viewport_texture;
RID canvas;
RID canvas_item;
- Semaphore preview_done;
-
- void _generate_frame_started();
- void _preview_done();
+ DrawRequester draw_requester;
public:
virtual bool handles(const String &p_type) const override;
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 4a127e5d87..d639121ae0 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -867,8 +867,6 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save, bool p_history_back) {
if (script_close_queue.is_empty()) {
_update_history_arrows();
_update_script_names();
- _update_members_overview_visibility();
- _update_help_overview_visibility();
_save_layout();
_update_find_replace_bar();
}
@@ -1671,7 +1669,6 @@ void ScriptEditor::_notification(int p_what) {
recent_scripts->reset_size();
if (is_inside_tree()) {
- _update_script_colors();
_update_script_names();
}
} break;
@@ -2821,7 +2818,6 @@ void ScriptEditor::_apply_editor_settings() {
EditorSettings::get_singleton()->load_text_editor_theme();
}
- _update_script_colors();
_update_script_names();
ScriptServer::set_reload_scripts_on_save(EDITOR_GET("text_editor/behavior/files/auto_reload_and_parse_scripts_on_save"));
diff --git a/misc/extension_api_validation/4.2-stable.expected b/misc/extension_api_validation/4.2-stable.expected
index ef70c4ab18..c0a1e58c62 100644
--- a/misc/extension_api_validation/4.2-stable.expected
+++ b/misc/extension_api_validation/4.2-stable.expected
@@ -215,3 +215,12 @@ Renamed to EditorSceneFormatImporterFBX2GLTF.
The compat breakage was deemed necessary as this is a class most users wouldn't
use directly, and the name needs to be disambiguated with the new
EditorSceneFormatImporterUFBX.
+
+
+GH-88791
+--------
+Validate extension JSON: JSON file: Field was added in a way that breaks compatibility 'classes/Skeleton3D/methods/add_bone': return_value
+
+Added a return value for add_bone.
+Should not affect existing regular use - the return value would just be unused.
+Compatibility method registered.
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 6f45aca8b8..2f1ae3380e 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -4219,8 +4219,8 @@ void GDScriptAnalyzer::reduce_preload(GDScriptParser::PreloadNode *p_preload) {
} else {
// TODO: Don't load if validating: use completion cache.
- // Must load GDScript and PackedScenes separately to permit cyclic references
- // as ResourceLoader::load() detect and reject those.
+ // Must load GDScript separately to permit cyclic references
+ // as ResourceLoader::load() detects and rejects those.
if (ResourceLoader::get_resource_type(p_preload->resolved_path) == "GDScript") {
Error err = OK;
Ref<GDScript> res = GDScriptCache::get_shallow_script(p_preload->resolved_path, err, parser->script_path);
@@ -4228,13 +4228,6 @@ void GDScriptAnalyzer::reduce_preload(GDScriptParser::PreloadNode *p_preload) {
if (err != OK) {
push_error(vformat(R"(Could not preload resource script "%s".)", p_preload->resolved_path), p_preload->path);
}
- } else if (ResourceLoader::get_resource_type(p_preload->resolved_path) == "PackedScene") {
- Error err = OK;
- Ref<PackedScene> res = GDScriptCache::get_packed_scene(p_preload->resolved_path, err, parser->script_path);
- p_preload->resource = res;
- if (err != OK) {
- push_error(vformat(R"(Could not preload resource scene "%s".)", p_preload->resolved_path), p_preload->path);
- }
} else {
p_preload->resource = ResourceLoader::load(p_preload->resolved_path);
if (p_preload->resource.is_null()) {
diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp
index ef783ab564..7c27127dce 100644
--- a/modules/gdscript/gdscript_cache.cpp
+++ b/modules/gdscript/gdscript_cache.cpp
@@ -37,7 +37,6 @@
#include "core/io/file_access.h"
#include "core/templates/vector.h"
-#include "scene/resources/packed_scene.h"
bool GDScriptParserRef::is_valid() const {
return parser != nullptr;
@@ -144,13 +143,6 @@ void GDScriptCache::move_script(const String &p_from, const String &p_to) {
return;
}
- for (KeyValue<String, HashSet<String>> &E : singleton->packed_scene_dependencies) {
- if (E.value.has(p_from)) {
- E.value.insert(p_to);
- E.value.erase(p_from);
- }
- }
-
if (singleton->parser_map.has(p_from) && !p_from.is_empty()) {
singleton->parser_map[p_to] = singleton->parser_map[p_from];
}
@@ -178,15 +170,6 @@ void GDScriptCache::remove_script(const String &p_path) {
return;
}
- for (KeyValue<String, HashSet<String>> &E : singleton->packed_scene_dependencies) {
- if (!E.value.has(p_path)) {
- continue;
- }
- E.value.erase(p_path);
- }
-
- GDScriptCache::clear_unreferenced_packed_scenes();
-
if (singleton->parser_map.has(p_path)) {
singleton->parser_map[p_path]->clear();
singleton->parser_map.erase(p_path);
@@ -400,62 +383,6 @@ void GDScriptCache::remove_static_script(const String &p_fqcn) {
singleton->static_gdscript_cache.erase(p_fqcn);
}
-Ref<PackedScene> GDScriptCache::get_packed_scene(const String &p_path, Error &r_error, const String &p_owner) {
- MutexLock lock(singleton->mutex);
-
- String path = p_path;
- if (path.begins_with("uid://")) {
- path = ResourceUID::get_singleton()->get_id_path(ResourceUID::get_singleton()->text_to_id(path));
- }
-
- if (singleton->packed_scene_cache.has(path)) {
- singleton->packed_scene_dependencies[path].insert(p_owner);
- return singleton->packed_scene_cache[path];
- }
-
- Ref<PackedScene> scene = ResourceCache::get_ref(path);
- if (scene.is_valid()) {
- singleton->packed_scene_cache[path] = scene;
- singleton->packed_scene_dependencies[path].insert(p_owner);
- return scene;
- }
- scene.instantiate();
-
- r_error = OK;
- if (path.is_empty()) {
- r_error = ERR_FILE_BAD_PATH;
- return scene;
- }
-
- scene->set_path(path);
- singleton->packed_scene_cache[path] = scene;
- singleton->packed_scene_dependencies[path].insert(p_owner);
-
- scene->reload_from_file();
- return scene;
-}
-
-void GDScriptCache::clear_unreferenced_packed_scenes() {
- if (singleton == nullptr) {
- return;
- }
-
- MutexLock lock(singleton->mutex);
-
- if (singleton->cleared) {
- return;
- }
-
- for (KeyValue<String, HashSet<String>> &E : singleton->packed_scene_dependencies) {
- if (E.value.size() > 0 || !ResourceLoader::is_imported(E.key)) {
- continue;
- }
-
- singleton->packed_scene_dependencies.erase(E.key);
- singleton->packed_scene_cache.erase(E.key);
- }
-}
-
void GDScriptCache::clear() {
if (singleton == nullptr) {
return;
@@ -478,16 +405,10 @@ void GDScriptCache::clear() {
E->clear();
}
- singleton->packed_scene_dependencies.clear();
- singleton->packed_scene_cache.clear();
-
parser_map_refs.clear();
singleton->parser_map.clear();
singleton->shallow_gdscript_cache.clear();
singleton->full_gdscript_cache.clear();
-
- singleton->packed_scene_cache.clear();
- singleton->packed_scene_dependencies.clear();
}
GDScriptCache::GDScriptCache() {
diff --git a/modules/gdscript/gdscript_cache.h b/modules/gdscript/gdscript_cache.h
index 0754e9feb6..fc7abbd46e 100644
--- a/modules/gdscript/gdscript_cache.h
+++ b/modules/gdscript/gdscript_cache.h
@@ -37,7 +37,6 @@
#include "core/os/mutex.h"
#include "core/templates/hash_map.h"
#include "core/templates/hash_set.h"
-#include "scene/resources/packed_scene.h"
class GDScriptAnalyzer;
class GDScriptParser;
@@ -81,8 +80,6 @@ class GDScriptCache {
HashMap<String, Ref<GDScript>> full_gdscript_cache;
HashMap<String, Ref<GDScript>> static_gdscript_cache;
HashMap<String, HashSet<String>> dependencies;
- HashMap<String, Ref<PackedScene>> packed_scene_cache;
- HashMap<String, HashSet<String>> packed_scene_dependencies;
friend class GDScript;
friend class GDScriptParserRef;
@@ -107,9 +104,6 @@ public:
static void add_static_script(Ref<GDScript> p_script);
static void remove_static_script(const String &p_fqcn);
- static Ref<PackedScene> get_packed_scene(const String &p_path, Error &r_error, const String &p_owner = "");
- static void clear_unreferenced_packed_scenes();
-
static void clear();
GDScriptCache();
diff --git a/modules/gdscript/language_server/godot_lsp.h b/modules/gdscript/language_server/godot_lsp.h
index e09adb74bd..284762018f 100644
--- a/modules/gdscript/language_server/godot_lsp.h
+++ b/modules/gdscript/language_server/godot_lsp.h
@@ -200,7 +200,7 @@ struct LocationLink {
/**
* The range that should be selected and revealed when this link is being followed, e.g the name of a function.
- * Must be contained by the the `targetRange`. See also `DocumentSymbol#range`
+ * Must be contained by the `targetRange`. See also `DocumentSymbol#range`
*/
Range targetSelectionRange;
};
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 0345eebef6..88fe82c6b8 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -2851,7 +2851,22 @@ Ref<Resource> ResourceFormatLoaderCSharpScript::load(const String &p_path, const
ERR_FAIL_COND_V_MSG(!scr->get_path().is_empty() && scr->get_path() != p_original_path, Ref<Resource>(),
"The C# script path is different from the path it was registered in the C# dictionary.");
- scr->set_path(p_original_path, true);
+ Ref<Resource> existing = ResourceCache::get_ref(p_path);
+ switch (p_cache_mode) {
+ case ResourceFormatLoader::CACHE_MODE_IGNORE:
+ break;
+ case ResourceFormatLoader::CACHE_MODE_REUSE:
+ if (existing.is_null()) {
+ scr->set_path(p_original_path);
+ } else {
+ scr = existing;
+ }
+ break;
+ case ResourceFormatLoader::CACHE_MODE_REPLACE:
+ scr->set_path(p_original_path, true);
+ break;
+ }
+
scr->reload();
if (r_error) {
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index 675651ccf7..7960a1ad5b 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -150,8 +150,268 @@ static String fix_doc_description(const String &p_bbcode) {
.strip_edges();
}
+String BindingsGenerator::bbcode_to_text(const String &p_bbcode, const TypeInterface *p_itype) {
+ // Based on the version in EditorHelp.
+
+ if (p_bbcode.is_empty()) {
+ return String();
+ }
+
+ DocTools *doc = EditorHelp::get_doc_data();
+
+ String bbcode = p_bbcode;
+
+ StringBuilder output;
+
+ List<String> tag_stack;
+ bool code_tag = false;
+
+ int pos = 0;
+ while (pos < bbcode.length()) {
+ int brk_pos = bbcode.find("[", pos);
+
+ if (brk_pos < 0) {
+ brk_pos = bbcode.length();
+ }
+
+ if (brk_pos > pos) {
+ String text = bbcode.substr(pos, brk_pos - pos);
+ if (code_tag || tag_stack.size() > 0) {
+ output.append("'" + text + "'");
+ } else {
+ output.append(text);
+ }
+ }
+
+ if (brk_pos == bbcode.length()) {
+ // Nothing else to add.
+ break;
+ }
+
+ int brk_end = bbcode.find("]", brk_pos + 1);
+
+ if (brk_end == -1) {
+ String text = bbcode.substr(brk_pos, bbcode.length() - brk_pos);
+ if (code_tag || tag_stack.size() > 0) {
+ output.append("'" + text + "'");
+ }
+
+ break;
+ }
+
+ String tag = bbcode.substr(brk_pos + 1, brk_end - brk_pos - 1);
+
+ if (tag.begins_with("/")) {
+ bool tag_ok = tag_stack.size() && tag_stack.front()->get() == tag.substr(1, tag.length());
+
+ if (!tag_ok) {
+ output.append("]");
+ pos = brk_pos + 1;
+ continue;
+ }
+
+ tag_stack.pop_front();
+ pos = brk_end + 1;
+ code_tag = false;
+ } else if (code_tag) {
+ output.append("[");
+ pos = brk_pos + 1;
+ } else if (tag.begins_with("method ") || tag.begins_with("constructor ") || tag.begins_with("operator ") || tag.begins_with("member ") || tag.begins_with("signal ") || tag.begins_with("enum ") || tag.begins_with("constant ") || tag.begins_with("theme_item ") || tag.begins_with("param ")) {
+ const int tag_end = tag.find(" ");
+ const String link_tag = tag.substr(0, tag_end);
+ const String link_target = tag.substr(tag_end + 1, tag.length()).lstrip(" ");
+
+ const Vector<String> link_target_parts = link_target.split(".");
+
+ if (link_target_parts.size() <= 0 || link_target_parts.size() > 2) {
+ ERR_PRINT("Invalid reference format: '" + tag + "'.");
+
+ output.append(tag);
+
+ pos = brk_end + 1;
+ continue;
+ }
+
+ const TypeInterface *target_itype;
+ StringName target_cname;
+
+ if (link_target_parts.size() == 2) {
+ target_itype = _get_type_or_null(TypeReference(link_target_parts[0]));
+ if (!target_itype) {
+ target_itype = _get_type_or_null(TypeReference("_" + link_target_parts[0]));
+ }
+ target_cname = link_target_parts[1];
+ } else {
+ target_itype = p_itype;
+ target_cname = link_target_parts[0];
+ }
+
+ if (link_tag == "method") {
+ _append_text_method(output, target_itype, target_cname, link_target, link_target_parts);
+ } else if (link_tag == "constructor") {
+ // TODO: Support constructors?
+ _append_text_undeclared(output, link_target);
+ } else if (link_tag == "operator") {
+ // TODO: Support operators?
+ _append_text_undeclared(output, link_target);
+ } else if (link_tag == "member") {
+ _append_text_member(output, target_itype, target_cname, link_target, link_target_parts);
+ } else if (link_tag == "signal") {
+ _append_text_signal(output, target_itype, target_cname, link_target, link_target_parts);
+ } else if (link_tag == "enum") {
+ _append_text_enum(output, target_itype, target_cname, link_target, link_target_parts);
+ } else if (link_tag == "constant") {
+ _append_text_constant(output, target_itype, target_cname, link_target, link_target_parts);
+ } else if (link_tag == "param") {
+ _append_text_param(output, link_target);
+ } else if (link_tag == "theme_item") {
+ // We do not declare theme_items in any way in C#, so there is nothing to reference.
+ _append_text_undeclared(output, link_target);
+ }
+
+ pos = brk_end + 1;
+ } else if (doc->class_list.has(tag)) {
+ if (tag == "Array" || tag == "Dictionary") {
+ output.append("'" BINDINGS_NAMESPACE_COLLECTIONS ".");
+ output.append(tag);
+ output.append("'");
+ } else if (tag == "bool" || tag == "int") {
+ output.append(tag);
+ } else if (tag == "float") {
+ output.append(
+#ifdef REAL_T_IS_DOUBLE
+ "double"
+#else
+ "float"
+#endif
+ );
+ } else if (tag == "Variant") {
+ output.append("'Godot.Variant'");
+ } else if (tag == "String") {
+ output.append("string");
+ } else if (tag == "Nil") {
+ output.append("null");
+ } else if (tag.begins_with("@")) {
+ // @GlobalScope, @GDScript, etc.
+ output.append("'" + tag + "'");
+ } else if (tag == "PackedByteArray") {
+ output.append("byte[]");
+ } else if (tag == "PackedInt32Array") {
+ output.append("int[]");
+ } else if (tag == "PackedInt64Array") {
+ output.append("long[]");
+ } else if (tag == "PackedFloat32Array") {
+ output.append("float[]");
+ } else if (tag == "PackedFloat64Array") {
+ output.append("double[]");
+ } else if (tag == "PackedStringArray") {
+ output.append("string[]");
+ } else if (tag == "PackedVector2Array") {
+ output.append("'" BINDINGS_NAMESPACE ".Vector2[]'");
+ } else if (tag == "PackedVector3Array") {
+ output.append("'" BINDINGS_NAMESPACE ".Vector3[]'");
+ } else if (tag == "PackedColorArray") {
+ output.append("'" BINDINGS_NAMESPACE ".Color[]'");
+ } else {
+ const TypeInterface *target_itype = _get_type_or_null(TypeReference(tag));
+
+ if (!target_itype) {
+ target_itype = _get_type_or_null(TypeReference("_" + tag));
+ }
+
+ if (target_itype) {
+ output.append("'" + target_itype->proxy_name + "'");
+ } else {
+ ERR_PRINT("Cannot resolve type reference in documentation: '" + tag + "'.");
+ output.append("'" + tag + "'");
+ }
+ }
+
+ pos = brk_end + 1;
+ } else if (tag == "b") {
+ // Bold is not supported.
+ pos = brk_end + 1;
+ tag_stack.push_front(tag);
+ } else if (tag == "i") {
+ // Italic is not supported.
+ pos = brk_end + 1;
+ tag_stack.push_front(tag);
+ } else if (tag == "code" || tag.begins_with("code ")) {
+ code_tag = true;
+ pos = brk_end + 1;
+ tag_stack.push_front("code");
+ } else if (tag == "kbd") {
+ // Keyboard combinations are not supported.
+ pos = brk_end + 1;
+ tag_stack.push_front(tag);
+ } else if (tag == "center") {
+ // Center alignment is not supported.
+ pos = brk_end + 1;
+ tag_stack.push_front(tag);
+ } else if (tag == "br") {
+ // Break is not supported.
+ pos = brk_end + 1;
+ tag_stack.push_front(tag);
+ } else if (tag == "u") {
+ // Underline is not supported.
+ pos = brk_end + 1;
+ tag_stack.push_front(tag);
+ } else if (tag == "s") {
+ // Strikethrough is not supported.
+ pos = brk_end + 1;
+ tag_stack.push_front(tag);
+ } else if (tag == "url") {
+ int end = bbcode.find("[", brk_end);
+ if (end == -1) {
+ end = bbcode.length();
+ }
+ String url = bbcode.substr(brk_end + 1, end - brk_end - 1);
+ // Not supported. Just append the url.
+ output.append(url);
+
+ pos = brk_end + 1;
+ tag_stack.push_front(tag);
+ } else if (tag.begins_with("url=")) {
+ String url = tag.substr(4, tag.length());
+ // Not supported. Just append the url.
+ output.append(url);
+
+ pos = brk_end + 1;
+ tag_stack.push_front("url");
+ } else if (tag == "img") {
+ int end = bbcode.find("[", brk_end);
+ if (end == -1) {
+ end = bbcode.length();
+ }
+ String image = bbcode.substr(brk_end + 1, end - brk_end - 1);
+
+ // Not supported. Just append the bbcode.
+ output.append("[img]");
+ output.append(image);
+ output.append("[/img]");
+
+ pos = end;
+ tag_stack.push_front(tag);
+ } else if (tag.begins_with("color=")) {
+ // Not supported.
+ pos = brk_end + 1;
+ tag_stack.push_front("color");
+ } else if (tag.begins_with("font=")) {
+ // Not supported.
+ pos = brk_end + 1;
+ tag_stack.push_front("font");
+ } else {
+ // Ignore unrecognized tag.
+ output.append("[");
+ pos = brk_pos + 1;
+ }
+ }
+
+ return output.as_string();
+}
+
String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterface *p_itype, bool p_is_signal) {
- // Based on the version in EditorHelp
+ // Based on the version in EditorHelp.
if (p_bbcode.is_empty()) {
return String();
@@ -200,7 +460,8 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf
}
if (brk_pos == bbcode.length()) {
- break; // nothing else to add
+ // Nothing else to add.
+ break;
}
int brk_end = bbcode.find("]", brk_pos + 1);
@@ -316,7 +577,7 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf
} else if (link_tag == "param") {
_append_xml_param(xml_output, link_target, p_is_signal);
} else if (link_tag == "theme_item") {
- // We do not declare theme_items in any way in C#, so there is nothing to reference
+ // We do not declare theme_items in any way in C#, so there is nothing to reference.
_append_xml_undeclared(xml_output, link_target);
}
@@ -345,7 +606,7 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf
} else if (tag == "Nil") {
xml_output.append("<see langword=\"null\"/>");
} else if (tag.begins_with("@")) {
- // @GlobalScope, @GDScript, etc
+ // @GlobalScope, @GDScript, etc.
xml_output.append("<c>");
xml_output.append(tag);
xml_output.append("</c>");
@@ -432,22 +693,22 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf
pos = brk_end + 1;
tag_stack.push_front("csharp");
} else if (tag == "kbd") {
- // keyboard combinations are not supported in xml comments
+ // Keyboard combinations are not supported in xml comments.
pos = brk_end + 1;
tag_stack.push_front(tag);
} else if (tag == "center") {
- // center alignment is not supported in xml comments
+ // Center alignment is not supported in xml comments.
pos = brk_end + 1;
tag_stack.push_front(tag);
} else if (tag == "br") {
xml_output.append("\n"); // FIXME: Should use <para> instead. Luckily this tag isn't used for now.
pos = brk_end + 1;
} else if (tag == "u") {
- // underline is not supported in Rider xml comments
+ // Underline is not supported in Rider xml comments.
pos = brk_end + 1;
tag_stack.push_front(tag);
} else if (tag == "s") {
- // strikethrough is not supported in xml comments
+ // Strikethrough is not supported in xml comments.
pos = brk_end + 1;
tag_stack.push_front(tag);
} else if (tag == "url") {
@@ -495,7 +756,8 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf
tag_stack.push_front("font");
} else {
if (!line_del) {
- xml_output.append("["); // ignore
+ // Ignore unrecognized tag.
+ xml_output.append("[");
}
pos = brk_pos + 1;
}
@@ -506,6 +768,285 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf
return xml_output.as_string();
}
+void BindingsGenerator::_append_text_method(StringBuilder &p_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts) {
+ if (p_link_target_parts[0] == name_cache.type_at_GlobalScope) {
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ OS::get_singleton()->print("Cannot resolve @GlobalScope method reference in documentation: %s\n", p_link_target.utf8().get_data());
+ }
+
+ // TODO Map what we can
+ _append_text_undeclared(p_output, p_link_target);
+ } else if (!p_target_itype || !p_target_itype->is_object_type) {
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ if (p_target_itype) {
+ OS::get_singleton()->print("Cannot resolve method reference for non-GodotObject type in documentation: %s\n", p_link_target.utf8().get_data());
+ } else {
+ OS::get_singleton()->print("Cannot resolve type from method reference in documentation: %s\n", p_link_target.utf8().get_data());
+ }
+ }
+
+ // TODO Map what we can
+ _append_text_undeclared(p_output, p_link_target);
+ } else {
+ if (p_target_cname == "_init") {
+ // The _init method is not declared in C#, reference the constructor instead
+ p_output.append("'new " BINDINGS_NAMESPACE ".");
+ p_output.append(p_target_itype->proxy_name);
+ p_output.append("()'");
+ } else {
+ const MethodInterface *target_imethod = p_target_itype->find_method_by_name(p_target_cname);
+
+ if (target_imethod) {
+ p_output.append("'" BINDINGS_NAMESPACE ".");
+ p_output.append(p_target_itype->proxy_name);
+ p_output.append(".");
+ p_output.append(target_imethod->proxy_name);
+ p_output.append("(");
+ bool first_key = true;
+ for (const ArgumentInterface &iarg : target_imethod->arguments) {
+ const TypeInterface *arg_type = _get_type_or_null(iarg.type);
+
+ if (first_key) {
+ first_key = false;
+ } else {
+ p_output.append(", ");
+ }
+ if (!arg_type) {
+ ERR_PRINT("Cannot resolve argument type in documentation: '" + p_link_target + "'.");
+ p_output.append(iarg.type.cname);
+ continue;
+ }
+ if (iarg.def_param_mode == ArgumentInterface::NULLABLE_VAL) {
+ p_output.append("Nullable<");
+ }
+ String arg_cs_type = arg_type->cs_type + _get_generic_type_parameters(*arg_type, iarg.type.generic_type_parameters);
+ p_output.append(arg_cs_type.replacen("params ", ""));
+ if (iarg.def_param_mode == ArgumentInterface::NULLABLE_VAL) {
+ p_output.append(">");
+ }
+ }
+ p_output.append(")'");
+ } else {
+ if (!p_target_itype->is_intentionally_ignored(p_link_target)) {
+ ERR_PRINT("Cannot resolve method reference in documentation: '" + p_link_target + "'.");
+ }
+
+ _append_text_undeclared(p_output, p_link_target);
+ }
+ }
+ }
+}
+
+void BindingsGenerator::_append_text_member(StringBuilder &p_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts) {
+ if (p_link_target.find("/") >= 0) {
+ // Properties with '/' (slash) in the name are not declared in C#, so there is nothing to reference.
+ _append_text_undeclared(p_output, p_link_target);
+ } else if (!p_target_itype || !p_target_itype->is_object_type) {
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ if (p_target_itype) {
+ OS::get_singleton()->print("Cannot resolve member reference for non-GodotObject type in documentation: %s\n", p_link_target.utf8().get_data());
+ } else {
+ OS::get_singleton()->print("Cannot resolve type from member reference in documentation: %s\n", p_link_target.utf8().get_data());
+ }
+ }
+
+ // TODO Map what we can
+ _append_text_undeclared(p_output, p_link_target);
+ } else {
+ const TypeInterface *current_itype = p_target_itype;
+ const PropertyInterface *target_iprop = nullptr;
+
+ while (target_iprop == nullptr && current_itype != nullptr) {
+ target_iprop = current_itype->find_property_by_name(p_target_cname);
+ if (target_iprop == nullptr) {
+ current_itype = _get_type_or_null(TypeReference(current_itype->base_name));
+ }
+ }
+
+ if (target_iprop) {
+ p_output.append("'" BINDINGS_NAMESPACE ".");
+ p_output.append(current_itype->proxy_name);
+ p_output.append(".");
+ p_output.append(target_iprop->proxy_name);
+ p_output.append("'");
+ } else {
+ if (!p_target_itype->is_intentionally_ignored(p_link_target)) {
+ ERR_PRINT("Cannot resolve member reference in documentation: '" + p_link_target + "'.");
+ }
+
+ _append_text_undeclared(p_output, p_link_target);
+ }
+ }
+}
+
+void BindingsGenerator::_append_text_signal(StringBuilder &p_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts) {
+ if (!p_target_itype || !p_target_itype->is_object_type) {
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ if (p_target_itype) {
+ OS::get_singleton()->print("Cannot resolve signal reference for non-GodotObject type in documentation: %s\n", p_link_target.utf8().get_data());
+ } else {
+ OS::get_singleton()->print("Cannot resolve type from signal reference in documentation: %s\n", p_link_target.utf8().get_data());
+ }
+ }
+
+ // TODO Map what we can
+ _append_text_undeclared(p_output, p_link_target);
+ } else {
+ const SignalInterface *target_isignal = p_target_itype->find_signal_by_name(p_target_cname);
+
+ if (target_isignal) {
+ p_output.append("'" BINDINGS_NAMESPACE ".");
+ p_output.append(p_target_itype->proxy_name);
+ p_output.append(".");
+ p_output.append(target_isignal->proxy_name);
+ p_output.append("'");
+ } else {
+ if (!p_target_itype->is_intentionally_ignored(p_link_target)) {
+ ERR_PRINT("Cannot resolve signal reference in documentation: '" + p_link_target + "'.");
+ }
+
+ _append_text_undeclared(p_output, p_link_target);
+ }
+ }
+}
+
+void BindingsGenerator::_append_text_enum(StringBuilder &p_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts) {
+ const StringName search_cname = !p_target_itype ? p_target_cname : StringName(p_target_itype->name + "." + (String)p_target_cname);
+
+ HashMap<StringName, TypeInterface>::ConstIterator enum_match = enum_types.find(search_cname);
+
+ if (!enum_match && search_cname != p_target_cname) {
+ enum_match = enum_types.find(p_target_cname);
+ }
+
+ if (enum_match) {
+ const TypeInterface &target_enum_itype = enum_match->value;
+
+ p_output.append("'" BINDINGS_NAMESPACE ".");
+ p_output.append(target_enum_itype.proxy_name); // Includes nesting class if any
+ p_output.append("'");
+ } else {
+ if (!p_target_itype->is_intentionally_ignored(p_link_target)) {
+ ERR_PRINT("Cannot resolve enum reference in documentation: '" + p_link_target + "'.");
+ }
+
+ _append_text_undeclared(p_output, p_link_target);
+ }
+}
+
+void BindingsGenerator::_append_text_constant(StringBuilder &p_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts) {
+ if (p_link_target_parts[0] == name_cache.type_at_GlobalScope) {
+ _append_text_constant_in_global_scope(p_output, p_target_cname, p_link_target);
+ } else if (!p_target_itype || !p_target_itype->is_object_type) {
+ // Search in @GlobalScope as a last resort if no class was specified
+ if (p_link_target_parts.size() == 1) {
+ _append_text_constant_in_global_scope(p_output, p_target_cname, p_link_target);
+ return;
+ }
+
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ if (p_target_itype) {
+ OS::get_singleton()->print("Cannot resolve constant reference for non-GodotObject type in documentation: %s\n", p_link_target.utf8().get_data());
+ } else {
+ OS::get_singleton()->print("Cannot resolve type from constant reference in documentation: %s\n", p_link_target.utf8().get_data());
+ }
+ }
+
+ // TODO Map what we can
+ _append_text_undeclared(p_output, p_link_target);
+ } else {
+ // Try to find the constant in the current class
+ if (p_target_itype->is_singleton_instance) {
+ // Constants and enums are declared in the static singleton class.
+ p_target_itype = &obj_types[p_target_itype->cname];
+ }
+
+ const ConstantInterface *target_iconst = find_constant_by_name(p_target_cname, p_target_itype->constants);
+
+ if (target_iconst) {
+ // Found constant in current class
+ p_output.append("'" BINDINGS_NAMESPACE ".");
+ p_output.append(p_target_itype->proxy_name);
+ p_output.append(".");
+ p_output.append(target_iconst->proxy_name);
+ p_output.append("'");
+ } else {
+ // Try to find as enum constant in the current class
+ const EnumInterface *target_ienum = nullptr;
+
+ for (const EnumInterface &ienum : p_target_itype->enums) {
+ target_ienum = &ienum;
+ target_iconst = find_constant_by_name(p_target_cname, target_ienum->constants);
+ if (target_iconst) {
+ break;
+ }
+ }
+
+ if (target_iconst) {
+ p_output.append("'" BINDINGS_NAMESPACE ".");
+ p_output.append(p_target_itype->proxy_name);
+ p_output.append(".");
+ p_output.append(target_ienum->proxy_name);
+ p_output.append(".");
+ p_output.append(target_iconst->proxy_name);
+ p_output.append("'");
+ } else if (p_link_target_parts.size() == 1) {
+ // Also search in @GlobalScope as a last resort if no class was specified
+ _append_text_constant_in_global_scope(p_output, p_target_cname, p_link_target);
+ } else {
+ if (!p_target_itype->is_intentionally_ignored(p_link_target)) {
+ ERR_PRINT("Cannot resolve constant reference in documentation: '" + p_link_target + "'.");
+ }
+
+ _append_xml_undeclared(p_output, p_link_target);
+ }
+ }
+ }
+}
+
+void BindingsGenerator::_append_text_constant_in_global_scope(StringBuilder &p_output, const String &p_target_cname, const String &p_link_target) {
+ // Try to find as a global constant
+ const ConstantInterface *target_iconst = find_constant_by_name(p_target_cname, global_constants);
+
+ if (target_iconst) {
+ // Found global constant
+ p_output.append("'" BINDINGS_NAMESPACE "." BINDINGS_GLOBAL_SCOPE_CLASS ".");
+ p_output.append(target_iconst->proxy_name);
+ p_output.append("'");
+ } else {
+ // Try to find as global enum constant
+ const EnumInterface *target_ienum = nullptr;
+
+ for (const EnumInterface &ienum : global_enums) {
+ target_ienum = &ienum;
+ target_iconst = find_constant_by_name(p_target_cname, target_ienum->constants);
+ if (target_iconst) {
+ break;
+ }
+ }
+
+ if (target_iconst) {
+ p_output.append("'" BINDINGS_NAMESPACE ".");
+ p_output.append(target_ienum->proxy_name);
+ p_output.append(".");
+ p_output.append(target_iconst->proxy_name);
+ p_output.append("'");
+ } else {
+ ERR_PRINT("Cannot resolve global constant reference in documentation: '" + p_link_target + "'.");
+ _append_text_undeclared(p_output, p_link_target);
+ }
+ }
+}
+
+void BindingsGenerator::_append_text_param(StringBuilder &p_output, const String &p_link_target) {
+ const String link_target = snake_to_camel_case(p_link_target);
+ p_output.append("'" + link_target + "'");
+}
+
+void BindingsGenerator::_append_text_undeclared(StringBuilder &p_output, const String &p_link_target) {
+ p_output.append("'" + p_link_target + "'");
+}
+
void BindingsGenerator::_append_xml_method(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts) {
if (p_link_target_parts[0] == name_cache.type_at_GlobalScope) {
if (OS::get_singleton()->is_stdout_verbose()) {
@@ -1429,10 +1970,12 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
output.append("/// </summary>\n");
}
+ }
- if (class_doc->is_deprecated) {
- output.append("[Obsolete(\"This class is deprecated.\")]\n");
- }
+ if (itype.is_deprecated) {
+ output.append("[Obsolete(\"");
+ output.append(bbcode_to_text(itype.deprecation_message, &itype));
+ output.append("\")]\n");
}
// We generate a `GodotClassName` attribute if the engine class name is not the same as the
@@ -1489,10 +2032,12 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
output.append(INDENT1 "/// </summary>");
}
+ }
- if (iconstant.const_doc->is_deprecated) {
- output.append(MEMBER_BEGIN "[Obsolete(\"This constant is deprecated.\")]");
- }
+ if (iconstant.is_deprecated) {
+ output.append(MEMBER_BEGIN "[Obsolete(\"");
+ output.append(bbcode_to_text(iconstant.deprecation_message, &itype));
+ output.append("\")]");
}
output.append(MEMBER_BEGIN "public const long ");
@@ -1537,10 +2082,12 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
output.append(INDENT2 "/// </summary>\n");
}
+ }
- if (iconstant.const_doc->is_deprecated) {
- output.append(INDENT2 "[Obsolete(\"This enum member is deprecated.\")]\n");
- }
+ if (iconstant.is_deprecated) {
+ output.append(INDENT2 "[Obsolete(\"");
+ output.append(bbcode_to_text(iconstant.deprecation_message, &itype));
+ output.append("\")]\n");
}
output.append(INDENT2);
@@ -1992,10 +2539,12 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
p_output.append(INDENT1 "/// </summary>");
}
+ }
- if (p_iprop.prop_doc->is_deprecated) {
- p_output.append(MEMBER_BEGIN "[Obsolete(\"This property is deprecated.\")]");
- }
+ if (p_iprop.is_deprecated) {
+ p_output.append(MEMBER_BEGIN "[Obsolete(\"");
+ p_output.append(bbcode_to_text(p_iprop.deprecation_message, &p_itype));
+ p_output.append("\")]");
}
p_output.append(MEMBER_BEGIN "public ");
@@ -2248,15 +2797,9 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
}
if (p_imethod.is_deprecated) {
- if (p_imethod.deprecation_message.is_empty()) {
- WARN_PRINT("An empty deprecation message is discouraged. Method: '" + p_imethod.proxy_name + "'.");
- }
-
p_output.append(MEMBER_BEGIN "[Obsolete(\"");
- p_output.append(p_imethod.deprecation_message);
+ p_output.append(bbcode_to_text(p_imethod.deprecation_message, &p_itype));
p_output.append("\")]");
- } else if (p_imethod.method_doc && p_imethod.method_doc->is_deprecated) {
- p_output.append(MEMBER_BEGIN "[Obsolete(\"This method is deprecated.\")]");
}
if (p_imethod.is_compat) {
@@ -2401,12 +2944,8 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
p_output.append(INDENT1 "/// </summary>");
if (p_isignal.is_deprecated) {
- if (p_isignal.deprecation_message.is_empty()) {
- WARN_PRINT("An empty deprecation message is discouraged. Signal: '" + p_isignal.proxy_name + "'.");
- }
-
p_output.append(MEMBER_BEGIN "[Obsolete(\"");
- p_output.append(p_isignal.deprecation_message);
+ p_output.append(bbcode_to_text(p_isignal.deprecation_message, &p_itype));
p_output.append("\")]");
}
@@ -2459,15 +2998,11 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
p_output.append(INDENT1 "/// </summary>");
}
-
- if (p_isignal.method_doc->is_deprecated) {
- p_output.append(MEMBER_BEGIN "[Obsolete(\"This signal is deprecated.\")]");
- }
}
if (p_isignal.is_deprecated) {
p_output.append(MEMBER_BEGIN "[Obsolete(\"");
- p_output.append(p_isignal.deprecation_message);
+ p_output.append(bbcode_to_text(p_isignal.deprecation_message, &p_itype));
p_output.append("\")]");
}
@@ -3029,6 +3564,16 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
itype.is_ref_counted = ClassDB::is_parent_class(type_cname, name_cache.type_RefCounted);
itype.memory_own = itype.is_ref_counted;
+ if (itype.class_doc) {
+ itype.is_deprecated = itype.class_doc->is_deprecated;
+ itype.deprecation_message = itype.class_doc->deprecated_message;
+
+ if (itype.deprecation_message.is_empty()) {
+ WARN_PRINT("An empty deprecation message is discouraged. Type: '" + itype.proxy_name + "'.");
+ itype.deprecation_message = "This class is deprecated.";
+ }
+ }
+
if (itype.is_singleton && compat_singletons.has(itype.cname)) {
itype.is_singleton = false;
itype.is_compat_singleton = true;
@@ -3103,6 +3648,16 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
}
}
+ if (iprop.prop_doc) {
+ iprop.is_deprecated = iprop.prop_doc->is_deprecated;
+ iprop.deprecation_message = iprop.prop_doc->deprecated_message;
+
+ if (iprop.deprecation_message.is_empty()) {
+ WARN_PRINT("An empty deprecation message is discouraged. Property: '" + itype.proxy_name + "." + iprop.proxy_name + "'.");
+ iprop.deprecation_message = "This property is deprecated.";
+ }
+ }
+
itype.properties.push_back(iprop);
}
@@ -3282,6 +3837,16 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
}
}
+ if (imethod.method_doc) {
+ imethod.is_deprecated = imethod.method_doc->is_deprecated;
+ imethod.deprecation_message = imethod.method_doc->deprecated_message;
+
+ if (imethod.deprecation_message.is_empty()) {
+ WARN_PRINT("An empty deprecation message is discouraged. Method: '" + itype.proxy_name + "." + imethod.proxy_name + "'.");
+ imethod.deprecation_message = "This method is deprecated.";
+ }
+ }
+
ERR_FAIL_COND_V_MSG(itype.find_property_by_name(imethod.cname), false,
"Method name conflicts with property: '" + itype.name + "." + imethod.name + "'.");
@@ -3388,6 +3953,16 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
}
}
+ if (isignal.method_doc) {
+ isignal.is_deprecated = isignal.method_doc->is_deprecated;
+ isignal.deprecation_message = isignal.method_doc->deprecated_message;
+
+ if (isignal.deprecation_message.is_empty()) {
+ WARN_PRINT("An empty deprecation message is discouraged. Signal: '" + itype.proxy_name + "." + isignal.proxy_name + "'.");
+ isignal.deprecation_message = "This signal is deprecated.";
+ }
+ }
+
itype.signals_.push_back(isignal);
}
@@ -3428,6 +4003,16 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
}
}
+ if (iconstant.const_doc) {
+ iconstant.is_deprecated = iconstant.const_doc->is_deprecated;
+ iconstant.deprecation_message = iconstant.const_doc->deprecated_message;
+
+ if (iconstant.deprecation_message.is_empty()) {
+ WARN_PRINT("An empty deprecation message is discouraged. Enum member: '" + itype.proxy_name + "." + ienum.proxy_name + "." + iconstant.proxy_name + "'.");
+ iconstant.deprecation_message = "This enum member is deprecated.";
+ }
+ }
+
ienum.constants.push_back(iconstant);
}
@@ -3470,6 +4055,16 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
}
}
+ if (iconstant.const_doc) {
+ iconstant.is_deprecated = iconstant.const_doc->is_deprecated;
+ iconstant.deprecation_message = iconstant.const_doc->deprecated_message;
+
+ if (iconstant.deprecation_message.is_empty()) {
+ WARN_PRINT("An empty deprecation message is discouraged. Constant: '" + itype.proxy_name + "." + iconstant.proxy_name + "'.");
+ iconstant.deprecation_message = "This constant is deprecated.";
+ }
+ }
+
itype.constants.push_back(iconstant);
}
diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h
index aa4e5ea093..bb0ba0cb00 100644
--- a/modules/mono/editor/bindings_generator.h
+++ b/modules/mono/editor/bindings_generator.h
@@ -47,7 +47,10 @@ class BindingsGenerator {
String name;
String proxy_name;
int64_t value = 0;
- const DocData::ConstantDoc *const_doc;
+ const DocData::ConstantDoc *const_doc = nullptr;
+
+ bool is_deprecated = false;
+ String deprecation_message;
ConstantInterface() {}
@@ -86,6 +89,9 @@ class BindingsGenerator {
StringName getter;
const DocData::PropertyDoc *prop_doc;
+
+ bool is_deprecated = false;
+ String deprecation_message;
};
struct TypeReference {
@@ -427,6 +433,9 @@ class BindingsGenerator {
const DocData::ClassDoc *class_doc = nullptr;
+ bool is_deprecated = false;
+ String deprecation_message;
+
List<ConstantInterface> constants;
List<EnumInterface> enums;
List<PropertyInterface> properties;
@@ -765,8 +774,18 @@ class BindingsGenerator {
return p_type->name;
}
+ String bbcode_to_text(const String &p_bbcode, const TypeInterface *p_itype);
String bbcode_to_xml(const String &p_bbcode, const TypeInterface *p_itype, bool p_is_signal = false);
+ void _append_text_method(StringBuilder &p_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts);
+ void _append_text_member(StringBuilder &p_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts);
+ void _append_text_signal(StringBuilder &p_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts);
+ void _append_text_enum(StringBuilder &p_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts);
+ void _append_text_constant(StringBuilder &p_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts);
+ void _append_text_constant_in_global_scope(StringBuilder &p_output, const String &p_target_cname, const String &p_link_target);
+ void _append_text_param(StringBuilder &p_output, const String &p_link_target);
+ void _append_text_undeclared(StringBuilder &p_output, const String &p_link_target);
+
void _append_xml_method(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts);
void _append_xml_member(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts);
void _append_xml_signal(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts);
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
index bd92e48bce..8f1bc109c0 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
@@ -492,7 +492,10 @@ namespace Godot
}
/// <summary>
- /// Returns this vector projected onto another vector <paramref name="onNormal"/>.
+ /// Returns a new vector resulting from projecting this vector onto the given vector <paramref name="onNormal"/>.
+ /// The resulting new vector is parallel to <paramref name="onNormal"/>.
+ /// See also <see cref="Slide(Vector2)"/>.
+ /// Note: If the vector <paramref name="onNormal"/> is a zero vector, the components of the resulting new vector will be <see cref="real_t.NaN"/>.
/// </summary>
/// <param name="onNormal">The vector to project onto.</param>
/// <returns>The projected vector.</returns>
@@ -583,9 +586,12 @@ namespace Godot
}
/// <summary>
- /// Returns this vector slid along a plane defined by the given <paramref name="normal"/>.
+ /// Returns a new vector resulting from sliding this vector along a line with normal <paramref name="normal"/>.
+ /// The resulting new vector is perpendicular to <paramref name="normal"/>, and is equivalent to this vector minus its projection on <paramref name="normal"/>.
+ /// See also <see cref="Project(Vector2)"/>.
+ /// Note: The vector <paramref name="normal"/> must be normalized. See also <see cref="Normalized()"/>.
/// </summary>
- /// <param name="normal">The normal vector defining the plane to slide on.</param>
+ /// <param name="normal">The normal vector of the plane to slide on.</param>
/// <returns>The slid vector.</returns>
public readonly Vector2 Slide(Vector2 normal)
{
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
index 6e77512fc8..74c1616e3d 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
@@ -514,7 +514,10 @@ namespace Godot
}
/// <summary>
- /// Returns this vector projected onto another vector <paramref name="onNormal"/>.
+ /// Returns a new vector resulting from projecting this vector onto the given vector <paramref name="onNormal"/>.
+ /// The resulting new vector is parallel to <paramref name="onNormal"/>.
+ /// See also <see cref="Slide(Vector3)"/>.
+ /// Note: If the vector <paramref name="onNormal"/> is a zero vector, the components of the resulting new vector will be <see cref="real_t.NaN"/>.
/// </summary>
/// <param name="onNormal">The vector to project onto.</param>
/// <returns>The projected vector.</returns>
@@ -626,9 +629,12 @@ namespace Godot
}
/// <summary>
- /// Returns this vector slid along a plane defined by the given <paramref name="normal"/>.
+ /// Returns a new vector resulting from sliding this vector along a plane with normal <paramref name="normal"/>.
+ /// The resulting new vector is perpendicular to <paramref name="normal"/>, and is equivalent to this vector minus its projection on <paramref name="normal"/>.
+ /// See also <see cref="Project(Vector3)"/>.
+ /// Note: The vector <paramref name="normal"/> must be normalized. See also <see cref="Normalized()"/>.
/// </summary>
- /// <param name="normal">The normal vector defining the plane to slide on.</param>
+ /// <param name="normal">The normal vector of the plane to slide on.</param>
/// <returns>The slid vector.</returns>
public readonly Vector3 Slide(Vector3 normal)
{
diff --git a/modules/multiplayer/editor/replication_editor.cpp b/modules/multiplayer/editor/replication_editor.cpp
index 51974e7767..f6df212d35 100644
--- a/modules/multiplayer/editor/replication_editor.cpp
+++ b/modules/multiplayer/editor/replication_editor.cpp
@@ -292,7 +292,7 @@ ReplicationEditor::ReplicationEditor() {
vb->add_child(tree);
drop_label = memnew(Label);
- drop_label->set_text(TTR("Add properties using the options above, or\ndrag them them from the inspector and drop them here."));
+ drop_label->set_text(TTR("Add properties using the options above, or\ndrag them from the inspector and drop them here."));
drop_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
drop_label->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
tree->add_child(drop_label);
diff --git a/modules/multiplayer/scene_replication_interface.cpp b/modules/multiplayer/scene_replication_interface.cpp
index b61cf0bf1d..bb32eed1a9 100644
--- a/modules/multiplayer/scene_replication_interface.cpp
+++ b/modules/multiplayer/scene_replication_interface.cpp
@@ -421,7 +421,7 @@ Error SceneReplicationInterface::_update_spawn_visibility(int p_peer, const Obje
// Check visibility for each peers.
for (const KeyValue<int, PeerInfo> &E : peers_info) {
if (is_visible) {
- // This is fast, since the the object is visible to everyone, we don't need to check each peer.
+ // This is fast, since the object is visible to everyone, we don't need to check each peer.
if (E.value.spawn_nodes.has(p_oid)) {
// Already spawned.
continue;
diff --git a/modules/openxr/extensions/openxr_eye_gaze_interaction.cpp b/modules/openxr/extensions/openxr_eye_gaze_interaction.cpp
index e57491e7c6..477a1c2609 100644
--- a/modules/openxr/extensions/openxr_eye_gaze_interaction.cpp
+++ b/modules/openxr/extensions/openxr_eye_gaze_interaction.cpp
@@ -30,6 +30,7 @@
#include "openxr_eye_gaze_interaction.h"
+#include "core/config/project_settings.h"
#include "core/os/os.h"
#include "../action_map/openxr_interaction_profile_metadata.h"
@@ -52,7 +53,11 @@ OpenXREyeGazeInteractionExtension::~OpenXREyeGazeInteractionExtension() {
HashMap<String, bool *> OpenXREyeGazeInteractionExtension::get_requested_extensions() {
HashMap<String, bool *> request_extensions;
- request_extensions[XR_EXT_EYE_GAZE_INTERACTION_EXTENSION_NAME] = &available;
+ // Only enable this extension when requested.
+ // We still register our meta data or the action map editor will fail.
+ if (GLOBAL_GET("xr/openxr/extensions/eye_gaze_interaction") && (!OS::get_singleton()->has_feature("mobile") || OS::get_singleton()->has_feature(XR_EXT_EYE_GAZE_INTERACTION_EXTENSION_NAME))) {
+ request_extensions[XR_EXT_EYE_GAZE_INTERACTION_EXTENSION_NAME] = &available;
+ }
return request_extensions;
}
diff --git a/modules/openxr/register_types.cpp b/modules/openxr/register_types.cpp
index a0a93c8694..3d34b27407 100644
--- a/modules/openxr/register_types.cpp
+++ b/modules/openxr/register_types.cpp
@@ -117,11 +117,9 @@ void initialize_openxr_module(ModuleInitializationLevel p_level) {
OpenXRAPI::register_extension_wrapper(memnew(OpenXRWMRControllerExtension));
OpenXRAPI::register_extension_wrapper(memnew(OpenXRML2ControllerExtension));
OpenXRAPI::register_extension_wrapper(memnew(OpenXRMetaControllerExtension));
+ OpenXRAPI::register_extension_wrapper(memnew(OpenXREyeGazeInteractionExtension));
// register gated extensions
- if (GLOBAL_GET("xr/openxr/extensions/eye_gaze_interaction") && (!OS::get_singleton()->has_feature("mobile") || OS::get_singleton()->has_feature(XR_EXT_EYE_GAZE_INTERACTION_EXTENSION_NAME))) {
- OpenXRAPI::register_extension_wrapper(memnew(OpenXREyeGazeInteractionExtension));
- }
if (GLOBAL_GET("xr/openxr/extensions/hand_tracking")) {
OpenXRAPI::register_extension_wrapper(memnew(OpenXRHandTrackingExtension));
}
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index 28ab8e3335..471fda74bf 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -379,7 +379,8 @@ void EditorExportPlatformAndroid::_check_for_changes_poll_thread(void *ud) {
} else if (p.begins_with("ro.build.version.sdk=")) {
d.api_level = p.get_slice("=", 1).to_int();
} else if (p.begins_with("ro.product.cpu.abi=")) {
- d.description += "CPU: " + p.get_slice("=", 1).strip_edges() + "\n";
+ d.architecture = p.get_slice("=", 1).strip_edges();
+ d.description += "CPU: " + d.architecture + "\n";
} else if (p.begins_with("ro.product.manufacturer=")) {
d.description += "Manufacturer: " + p.get_slice("=", 1).strip_edges() + "\n";
} else if (p.begins_with("ro.board.platform=")) {
@@ -1992,6 +1993,12 @@ String EditorExportPlatformAndroid::get_option_tooltip(int p_index) const {
return s;
}
+String EditorExportPlatformAndroid::get_device_architecture(int p_index) const {
+ ERR_FAIL_INDEX_V(p_index, devices.size(), "");
+ MutexLock lock(device_lock);
+ return devices[p_index].architecture;
+}
+
Error EditorExportPlatformAndroid::run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) {
ERR_FAIL_INDEX_V(p_device, devices.size(), ERR_INVALID_PARAMETER);
diff --git a/platform/android/export/export_plugin.h b/platform/android/export/export_plugin.h
index e25655c6cc..b968302449 100644
--- a/platform/android/export/export_plugin.h
+++ b/platform/android/export/export_plugin.h
@@ -76,6 +76,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
String name;
String description;
int api_level = 0;
+ String architecture;
};
struct APKExportData {
@@ -221,6 +222,8 @@ public:
virtual String get_option_tooltip(int p_index) const override;
+ virtual String get_device_architecture(int p_index) const override;
+
virtual Error run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) override;
virtual Ref<Texture2D> get_run_icon() const override;
diff --git a/platform/macos/dir_access_macos.mm b/platform/macos/dir_access_macos.mm
index 66d81f2687..37f717c9de 100644
--- a/platform/macos/dir_access_macos.mm
+++ b/platform/macos/dir_access_macos.mm
@@ -41,9 +41,10 @@
String DirAccessMacOS::fix_unicode_name(const char *p_name) const {
String fname;
- NSString *nsstr = [[NSString stringWithUTF8String:p_name] precomposedStringWithCanonicalMapping];
-
- fname.parse_utf8([nsstr UTF8String]);
+ if (p_name != nullptr) {
+ NSString *nsstr = [[NSString stringWithUTF8String:p_name] precomposedStringWithCanonicalMapping];
+ fname.parse_utf8([nsstr UTF8String]);
+ }
return fname;
}
diff --git a/platform/macos/godot_application_delegate.mm b/platform/macos/godot_application_delegate.mm
index 2e76d4aa97..b3759e66f5 100644
--- a/platform/macos/godot_application_delegate.mm
+++ b/platform/macos/godot_application_delegate.mm
@@ -125,7 +125,8 @@
- (void)applicationDidFinishLaunching:(NSNotification *)notice {
NSString *nsappname = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
- NSString *nsbundleid_env = [NSString stringWithUTF8String:getenv("__CFBundleIdentifier")];
+ const char *bundled_id = getenv("__CFBundleIdentifier");
+ NSString *nsbundleid_env = [NSString stringWithUTF8String:(bundled_id != nullptr) ? bundled_id : ""];
NSString *nsbundleid = [[NSBundle mainBundle] bundleIdentifier];
if (nsappname == nil || isatty(STDOUT_FILENO) || isatty(STDIN_FILENO) || isatty(STDERR_FILENO) || ![nsbundleid isEqualToString:nsbundleid_env]) {
// If the executable is started from terminal or is not bundled, macOS WindowServer won't register and activate app window correctly (menu and title bar are grayed out and input ignored).
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 16eabf6855..6f3f6189e5 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -35,6 +35,7 @@
#include "core/config/project_settings.h"
#include "core/io/marshalls.h"
+#include "core/version.h"
#include "drivers/png/png_driver_common.h"
#include "main/main.h"
#include "scene/resources/atlas_texture.h"
@@ -51,6 +52,9 @@
#include <avrt.h>
#include <dwmapi.h>
+#include <propkey.h>
+#include <propvarutil.h>
+#include <shellapi.h>
#include <shlwapi.h>
#include <shobjidl.h>
#include <wbemcli.h>
@@ -1375,6 +1379,15 @@ void DisplayServerWindows::delete_sub_window(WindowID p_window) {
WindowData &wd = windows[p_window];
+ IPropertyStore *prop_store;
+ HRESULT hr = SHGetPropertyStoreForWindow(wd.hWnd, IID_IPropertyStore, (void **)&prop_store);
+ if (hr == S_OK) {
+ PROPVARIANT val;
+ PropVariantInit(&val);
+ prop_store->SetValue(PKEY_AppUserModel_ID, val);
+ prop_store->Release();
+ }
+
while (wd.transient_children.size()) {
window_set_transient(*wd.transient_children.begin(), INVALID_WINDOW_ID);
}
@@ -4956,6 +4969,33 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
wd.last_pressure_update = 0;
wd.last_tilt = Vector2();
+ IPropertyStore *prop_store;
+ HRESULT hr = SHGetPropertyStoreForWindow(wd.hWnd, IID_IPropertyStore, (void **)&prop_store);
+ if (hr == S_OK) {
+ PROPVARIANT val;
+ String appname;
+ if (Engine::get_singleton()->is_editor_hint()) {
+ appname = "Godot.GodotEditor." + String(VERSION_BRANCH);
+ } else {
+ String name = GLOBAL_GET("application/config/name");
+ String version = GLOBAL_GET("application/config/version");
+ if (version.is_empty()) {
+ version = "0";
+ }
+ String clean_app_name = name.to_pascal_case();
+ for (int i = 0; i < clean_app_name.length(); i++) {
+ if (!is_ascii_alphanumeric_char(clean_app_name[i]) && clean_app_name[i] != '_' && clean_app_name[i] != '.') {
+ clean_app_name[i] = '_';
+ }
+ }
+ clean_app_name = clean_app_name.substr(0, 120 - version.length()).trim_suffix(".");
+ appname = "Godot." + clean_app_name + "." + version;
+ }
+ InitPropVariantFromString((PCWSTR)appname.utf16().get_data(), &val);
+ prop_store->SetValue(PKEY_AppUserModel_ID, val);
+ prop_store->Release();
+ }
+
// IME.
wd.im_himc = ImmGetContext(wd.hWnd);
ImmAssociateContext(wd.hWnd, (HIMC)0);
@@ -5354,6 +5394,26 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
}
#endif
+ String appname;
+ if (Engine::get_singleton()->is_editor_hint()) {
+ appname = "Godot.GodotEditor." + String(VERSION_BRANCH);
+ } else {
+ String name = GLOBAL_GET("application/config/name");
+ String version = GLOBAL_GET("application/config/version");
+ if (version.is_empty()) {
+ version = "0";
+ }
+ String clean_app_name = name.to_pascal_case();
+ for (int i = 0; i < clean_app_name.length(); i++) {
+ if (!is_ascii_alphanumeric_char(clean_app_name[i]) && clean_app_name[i] != '_' && clean_app_name[i] != '.') {
+ clean_app_name[i] = '_';
+ }
+ }
+ clean_app_name = clean_app_name.substr(0, 120 - version.length()).trim_suffix(".");
+ appname = "Godot." + clean_app_name + "." + version;
+ }
+ SetCurrentProcessExplicitAppUserModelID((PCWSTR)appname.utf16().get_data());
+
mouse_monitor = SetWindowsHookEx(WH_MOUSE, ::MouseProc, nullptr, GetCurrentThreadId());
Point2i window_position;
diff --git a/scene/2d/tile_map_layer.cpp b/scene/2d/tile_map_layer.cpp
index 8b2542b34e..2753fee7e9 100644
--- a/scene/2d/tile_map_layer.cpp
+++ b/scene/2d/tile_map_layer.cpp
@@ -1666,7 +1666,7 @@ void TileMapLayer::_internal_update() {
Vector<Vector2i> to_delete;
for (SelfList<CellData> *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) {
CellData &cell_data = *cell_data_list_element->self();
- // Select the the cell from tile_map if it is invalid.
+ // Select the cell from tile_map if it is invalid.
if (cell_data.cell.source_id == TileSet::INVALID_SOURCE) {
to_delete.push_back(cell_data.coords);
}
@@ -2978,4 +2978,4 @@ TerrainConstraint::TerrainConstraint(Ref<TileSet> p_tile_set, const Vector2i &p_
}
}
terrain = p_terrain;
-} \ No newline at end of file
+}
diff --git a/scene/3d/skeleton_3d.compat.inc b/scene/3d/skeleton_3d.compat.inc
new file mode 100644
index 0000000000..6410ab335a
--- /dev/null
+++ b/scene/3d/skeleton_3d.compat.inc
@@ -0,0 +1,41 @@
+/**************************************************************************/
+/* skeleton_3d.compat.inc */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef DISABLE_DEPRECATED
+
+void Skeleton3D::_add_bone_bind_compat_88791(const String &p_name) {
+ add_bone(p_name);
+}
+
+void Skeleton3D::_bind_compatibility_methods() {
+ ClassDB::bind_compatibility_method(D_METHOD("add_bone", "p_name"), &Skeleton3D::_add_bone_bind_compat_88791);
+}
+
+#endif // DISABLE_DEPRECATED
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp
index cae1b2ce9c..f448d1c6e2 100644
--- a/scene/3d/skeleton_3d.cpp
+++ b/scene/3d/skeleton_3d.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "skeleton_3d.h"
+#include "skeleton_3d.compat.inc"
#include "core/variant/type_info.h"
#include "scene/3d/physics_body_3d.h"
@@ -409,18 +410,21 @@ uint64_t Skeleton3D::get_version() const {
return version;
}
-void Skeleton3D::add_bone(const String &p_name) {
- ERR_FAIL_COND(p_name.is_empty() || p_name.contains(":") || p_name.contains("/") || name_to_bone_index.has(p_name));
+int Skeleton3D::add_bone(const String &p_name) {
+ ERR_FAIL_COND_V_MSG(p_name.is_empty() || p_name.contains(":") || p_name.contains("/"), -1, vformat("Bone name cannot be empty or contain ':' or '/'.", p_name));
+ ERR_FAIL_COND_V_MSG(name_to_bone_index.has(p_name), -1, vformat("Skeleton3D \"%s\" already has a bone with name \"%s\".", to_string(), p_name));
Bone b;
b.name = p_name;
bones.push_back(b);
- name_to_bone_index.insert(p_name, bones.size() - 1);
+ int new_idx = bones.size() - 1;
+ name_to_bone_index.insert(p_name, new_idx);
process_order_dirty = true;
version++;
rest_dirty = true;
_make_dirty();
update_gizmos();
+ return new_idx;
}
int Skeleton3D::find_bone(const String &p_name) const {
diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h
index 7d4df1d1f2..458bbfb979 100644
--- a/scene/3d/skeleton_3d.h
+++ b/scene/3d/skeleton_3d.h
@@ -138,6 +138,12 @@ private:
void _update_process_order();
+#ifndef DISABLE_DEPRECATED
+ void _add_bone_bind_compat_88791(const String &p_name);
+
+ static void _bind_compatibility_methods();
+#endif // DISABLE_DEPRECATED
+
protected:
bool _get(const StringName &p_path, Variant &r_ret) const;
bool _set(const StringName &p_path, const Variant &p_value);
@@ -153,7 +159,7 @@ public:
// skeleton creation api
uint64_t get_version() const;
- void add_bone(const String &p_name);
+ int add_bone(const String &p_name);
int find_bone(const String &p_name) const;
String get_bone_name(int p_bone) const;
void set_bone_name(int p_bone, const String &p_name);
diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp
index 978fb56f78..b1870eea55 100644
--- a/scene/gui/button.cpp
+++ b/scene/gui/button.cpp
@@ -50,10 +50,6 @@ void Button::_set_internal_margin(Side p_side, float p_value) {
void Button::_queue_update_size_cache() {
}
-void Button::_set_h_separation_is_valid_when_no_text(bool p_h_separation_is_valid_when_no_text) {
- h_separation_is_valid_when_no_text = p_h_separation_is_valid_when_no_text;
-}
-
Ref<StyleBox> Button::_get_current_stylebox() const {
Ref<StyleBox> stylebox = theme_cache.normal;
const bool rtl = is_layout_rtl();
@@ -180,14 +176,12 @@ void Button::_notification(int p_what) {
float right_internal_margin_with_h_separation = _internal_margin[SIDE_RIGHT];
{ // The width reserved for internal element in derived classes (and h_separation if need).
- if (!xl_text.is_empty() || h_separation_is_valid_when_no_text) {
- if (_internal_margin[SIDE_LEFT] > 0.0f) {
- left_internal_margin_with_h_separation += h_separation;
- }
+ if (_internal_margin[SIDE_LEFT] > 0.0f) {
+ left_internal_margin_with_h_separation += h_separation;
+ }
- if (_internal_margin[SIDE_RIGHT] > 0.0f) {
- right_internal_margin_with_h_separation += h_separation;
- }
+ if (_internal_margin[SIDE_RIGHT] > 0.0f) {
+ right_internal_margin_with_h_separation += h_separation;
}
drawable_size_remained.width -= left_internal_margin_with_h_separation + right_internal_margin_with_h_separation; // The size after the internal element is stripped.
diff --git a/scene/gui/button.h b/scene/gui/button.h
index 6efbafe0ad..86fdbd35d5 100644
--- a/scene/gui/button.h
+++ b/scene/gui/button.h
@@ -56,8 +56,6 @@ private:
VerticalAlignment vertical_icon_alignment = VERTICAL_ALIGNMENT_CENTER;
float _internal_margin[4] = {};
- bool h_separation_is_valid_when_no_text = false;
-
struct ThemeCache {
Ref<StyleBox> normal;
Ref<StyleBox> normal_mirrored;
@@ -105,7 +103,6 @@ protected:
void _set_internal_margin(Side p_side, float p_value);
virtual void _queue_update_size_cache();
- void _set_h_separation_is_valid_when_no_text(bool p_h_separation_is_valid_when_no_text);
Ref<StyleBox> _get_current_stylebox() const;
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/gui/check_box.cpp b/scene/gui/check_box.cpp
index 6c02ba1a86..46c20e4a1c 100644
--- a/scene/gui/check_box.cpp
+++ b/scene/gui/check_box.cpp
@@ -64,12 +64,18 @@ Size2 CheckBox::get_icon_size() const {
Size2 CheckBox::get_minimum_size() const {
Size2 minsize = Button::get_minimum_size();
- Size2 tex_size = get_icon_size();
- minsize.width += tex_size.width;
- if (get_text().length() > 0) {
- minsize.width += MAX(0, theme_cache.h_separation);
+ const Size2 tex_size = get_icon_size();
+ if (tex_size.width > 0 || tex_size.height > 0) {
+ const Size2 padding = _get_current_stylebox()->get_minimum_size();
+ Size2 content_size = minsize - padding;
+ if (content_size.width > 0 && tex_size.width > 0) {
+ content_size.width += MAX(0, theme_cache.h_separation);
+ }
+ content_size.width += tex_size.width;
+ content_size.height = MAX(content_size.height, tex_size.height);
+
+ minsize = content_size + padding;
}
- minsize.height = MAX(minsize.height, tex_size.height + theme_cache.normal_style->get_margin(SIDE_TOP) + theme_cache.normal_style->get_margin(SIDE_BOTTOM));
return minsize;
}
diff --git a/scene/gui/check_button.cpp b/scene/gui/check_button.cpp
index d9fabc5459..ca2ef220fd 100644
--- a/scene/gui/check_button.cpp
+++ b/scene/gui/check_button.cpp
@@ -68,12 +68,18 @@ Size2 CheckButton::get_icon_size() const {
Size2 CheckButton::get_minimum_size() const {
Size2 minsize = Button::get_minimum_size();
- Size2 tex_size = get_icon_size();
- minsize.width += tex_size.width;
- if (get_text().length() > 0) {
- minsize.width += MAX(0, theme_cache.h_separation);
+ const Size2 tex_size = get_icon_size();
+ if (tex_size.width > 0 || tex_size.height > 0) {
+ const Size2 padding = _get_current_stylebox()->get_minimum_size();
+ Size2 content_size = minsize - padding;
+ if (content_size.width > 0 && tex_size.width > 0) {
+ content_size.width += MAX(0, theme_cache.h_separation);
+ }
+ content_size.width += tex_size.width;
+ content_size.height = MAX(content_size.height, tex_size.height);
+
+ minsize = content_size + padding;
}
- minsize.height = MAX(minsize.height, tex_size.height + theme_cache.normal_style->get_margin(SIDE_TOP) + theme_cache.normal_style->get_margin(SIDE_BOTTOM));
return minsize;
}
diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp
index 6613f25b4c..0e10652f07 100644
--- a/scene/gui/option_button.cpp
+++ b/scene/gui/option_button.cpp
@@ -614,8 +614,6 @@ void OptionButton::set_disable_shortcuts(bool p_disabled) {
OptionButton::OptionButton(const String &p_text) :
Button(p_text) {
- _set_h_separation_is_valid_when_no_text(true);
-
set_toggle_mode(true);
set_process_shortcut_input(true);
set_text_alignment(HORIZONTAL_ALIGNMENT_LEFT);
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 59be64b6dc..79a5f2b557 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -229,7 +229,7 @@ void TextEdit::Text::invalidate_cache(int p_line, int p_column, bool p_text_chan
}
text.write[p_line].height = height;
- // If this line has shrunk, this may no longer the the tallest line.
+ // If this line has shrunk, this may no longer the tallest line.
if (old_height == line_height && height < line_height) {
_calculate_line_height();
} else {
@@ -241,7 +241,7 @@ void TextEdit::Text::invalidate_cache(int p_line, int p_column, bool p_text_chan
int line_width = get_line_width(p_line);
text.write[p_line].width = line_width;
- // If this line has shrunk, this may no longer the the longest line.
+ // If this line has shrunk, this may no longer the longest line.
if (old_width == max_width && line_width < max_width) {
_calculate_max_line_width();
} else if (!is_hidden(p_line)) {
@@ -731,7 +731,7 @@ void TextEdit::_notification(int p_what) {
// Draw the minimap.
- // Add visual feedback when dragging or hovering the the visible area rectangle.
+ // Add visual feedback when dragging or hovering the visible area rectangle.
float viewport_alpha;
if (dragging_minimap) {
viewport_alpha = 0.25;
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index f827f68def..67f8a97212 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -2963,12 +2963,12 @@ void Node::replace_by(Node *p_node, bool p_keep_groups) {
}
p_node->set_owner(owner);
- for (int i = 0; i < owned.size(); i++) {
- owned[i]->set_owner(p_node);
+ for (Node *E : owned) {
+ E->set_owner(p_node);
}
- for (int i = 0; i < owned_by_owner.size(); i++) {
- owned_by_owner[i]->set_owner(owner);
+ for (Node *E : owned_by_owner) {
+ E->set_owner(owner);
}
p_node->set_scene_file_path(get_scene_file_path());
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index b582576412..0bb2688fea 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -4769,7 +4769,7 @@ void Viewport::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "is_using_debanding");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_occlusion_culling"), "set_use_occlusion_culling", "is_using_occlusion_culling");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mesh_lod_threshold", PROPERTY_HINT_RANGE, "0,1024,0.1"), "set_mesh_lod_threshold", "get_mesh_lod_threshold");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "debug_draw", PROPERTY_HINT_ENUM, "Disabled,Unshaded,Lighting,Overdraw,Wireframe"), "set_debug_draw", "get_debug_draw");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "debug_draw", PROPERTY_HINT_ENUM, "Disabled,Unshaded,Lighting,Overdraw,Wireframe,Normal Buffer,VoxelGI Albedo,VoxelGI Lighting,VoxelGI Emission,Shadow Atlas,Directional Shadow Map,Scene Luminance,SSAO,SSIL,Directional Shadow Splits,Decal Atlas,SDFGI Cascades,SDFGI Probes,VoxelGI/SDFGI Buffer,Disable Mesh LOD,OmniLight3D Cluster,SpotLight3D Cluster,Decal Cluster,ReflectionProbe Cluster,Occlusion Culling Buffer,Motion Vectors,Internal Buffer"), "set_debug_draw", "get_debug_draw");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_hdr_2d"), "set_use_hdr_2d", "is_using_hdr_2d");
#ifndef _3D_DISABLED
diff --git a/scene/resources/skeleton_modification_2d_twoboneik.cpp b/scene/resources/skeleton_modification_2d_twoboneik.cpp
index 4458cdc0e3..c3366d5c36 100644
--- a/scene/resources/skeleton_modification_2d_twoboneik.cpp
+++ b/scene/resources/skeleton_modification_2d_twoboneik.cpp
@@ -281,16 +281,16 @@ void SkeletonModification2DTwoBoneIK::update_joint_one_bone2d_cache() {
if (stack->skeleton->has_node(joint_one_bone2d_node)) {
Node *node = stack->skeleton->get_node(joint_one_bone2d_node);
ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
- "Cannot update update joint one Bone2D cache: node is this modification's skeleton or cannot be found!");
+ "Cannot update joint one Bone2D cache: node is this modification's skeleton or cannot be found!");
ERR_FAIL_COND_MSG(!node->is_inside_tree(),
- "Cannot update update joint one Bone2D cache: node is not in the scene tree!");
+ "Cannot update joint one Bone2D cache: node is not in the scene tree!");
joint_one_bone2d_node_cache = node->get_instance_id();
Bone2D *bone = Object::cast_to<Bone2D>(node);
if (bone) {
joint_one_bone_idx = bone->get_index_in_skeleton();
} else {
- ERR_FAIL_MSG("update joint one Bone2D cache: Nodepath to Bone2D is not a Bone2D node!");
+ ERR_FAIL_MSG("Update joint one Bone2D cache: Nodepath to Bone2D is not a Bone2D node!");
}
}
}
@@ -309,16 +309,16 @@ void SkeletonModification2DTwoBoneIK::update_joint_two_bone2d_cache() {
if (stack->skeleton->has_node(joint_two_bone2d_node)) {
Node *node = stack->skeleton->get_node(joint_two_bone2d_node);
ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
- "Cannot update update joint two Bone2D cache: node is this modification's skeleton or cannot be found!");
+ "Cannot update joint two Bone2D cache: node is this modification's skeleton or cannot be found!");
ERR_FAIL_COND_MSG(!node->is_inside_tree(),
- "Cannot update update joint two Bone2D cache: node is not in scene tree!");
+ "Cannot update joint two Bone2D cache: node is not in scene tree!");
joint_two_bone2d_node_cache = node->get_instance_id();
Bone2D *bone = Object::cast_to<Bone2D>(node);
if (bone) {
joint_two_bone_idx = bone->get_index_in_skeleton();
} else {
- ERR_FAIL_MSG("update joint two Bone2D cache: Nodepath to Bone2D is not a Bone2D node!");
+ ERR_FAIL_MSG("Update joint two Bone2D cache: Nodepath to Bone2D is not a Bone2D node!");
}
}
}
diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
index 1f362ffd21..9d3def1246 100644
--- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
@@ -374,7 +374,7 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
if (new_surface.vertex_data.size()) {
// If we have an uncompressed surface that contains normals, but not tangents, we need to differentiate the array
- // from a compressed array in the shader. To do so, we allow the the normal to read 4 components out of the buffer
+ // from a compressed array in the shader. To do so, we allow the normal to read 4 components out of the buffer
// But only give it 2 components per normal. So essentially, each vertex reads the next normal in normal.zw.
// This allows us to avoid adding a shader permutation, and avoid passing dummy tangents. Since the stride is kept small
// this should still be a net win for bandwidth.
diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp
index 2cfee25f91..e1709fdb00 100644
--- a/servers/rendering/rendering_device.cpp
+++ b/servers/rendering/rendering_device.cpp
@@ -3782,12 +3782,12 @@ void RenderingDevice::draw_list_draw(DrawListID p_list, bool p_use_indices, uint
#ifdef DEBUG_ENABLED
if (dl->state.sets[i].pipeline_expected_format != dl->state.sets[i].uniform_set_format) {
if (dl->state.sets[i].uniform_set_format == 0) {
- ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline");
+ ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline.");
} else if (uniform_set_owner.owns(dl->state.sets[i].uniform_set)) {
UniformSet *us = uniform_set_owner.get_or_null(dl->state.sets[i].uniform_set);
ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + "):\n" + _shader_uniform_debug(us->shader_id, us->shader_set) + "\nare not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(dl->state.pipeline_shader));
} else {
- ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ", which was was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(dl->state.pipeline_shader));
+ ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ", which was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(dl->state.pipeline_shader));
}
}
#endif
@@ -4173,12 +4173,12 @@ void RenderingDevice::compute_list_dispatch(ComputeListID p_list, uint32_t p_x_g
#ifdef DEBUG_ENABLED
if (cl->state.sets[i].pipeline_expected_format != cl->state.sets[i].uniform_set_format) {
if (cl->state.sets[i].uniform_set_format == 0) {
- ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline");
+ ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline.");
} else if (uniform_set_owner.owns(cl->state.sets[i].uniform_set)) {
UniformSet *us = uniform_set_owner.get_or_null(cl->state.sets[i].uniform_set);
ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + "):\n" + _shader_uniform_debug(us->shader_id, us->shader_set) + "\nare not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(cl->state.pipeline_shader));
} else {
- ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ", which was was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(cl->state.pipeline_shader));
+ ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ", which was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(cl->state.pipeline_shader));
}
}
#endif
@@ -4271,7 +4271,7 @@ void RenderingDevice::compute_list_dispatch_indirect(ComputeListID p_list, RID p
UniformSet *us = uniform_set_owner.get_or_null(cl->state.sets[i].uniform_set);
ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + "):\n" + _shader_uniform_debug(us->shader_id, us->shader_set) + "\nare not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(cl->state.pipeline_shader));
} else {
- ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ", which was was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(cl->state.pipeline_shader));
+ ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ", which was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(cl->state.pipeline_shader));
}
}
#endif