summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/string/ustring.cpp9
-rw-r--r--core/variant/container_type_validate.h15
-rw-r--r--doc/classes/@GlobalScope.xml327
-rw-r--r--doc/classes/ProjectSettings.xml7
-rw-r--r--doc/classes/PropertyTweener.xml2
-rw-r--r--doc/classes/Viewport.xml6
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp39
-rw-r--r--editor/plugins/node_3d_editor_plugin.h8
-rw-r--r--editor/plugins/script_text_editor.cpp95
-rw-r--r--editor/plugins/script_text_editor.h1
-rw-r--r--editor/plugins/tiles/tiles_editor_plugin.cpp6
-rw-r--r--main/main.cpp2
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml96
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp8
-rw-r--r--modules/gltf/doc_classes/GLTFNode.xml19
-rw-r--r--modules/gltf/doc_classes/GLTFState.xml17
-rw-r--r--modules/gltf/gltf_state.cpp10
-rw-r--r--modules/gltf/gltf_state.h4
-rw-r--r--modules/gltf/structures/gltf_node.cpp10
-rw-r--r--modules/gltf/structures/gltf_node.h4
-rw-r--r--modules/mono/editor/bindings_generator.cpp17
-rw-r--r--modules/multiplayer/scene_replication_interface.cpp6
-rw-r--r--modules/openxr/SCsub1
-rw-r--r--modules/openxr/doc_classes/OpenXRInterface.xml13
-rw-r--r--modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.cpp123
-rw-r--r--modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.h70
-rw-r--r--modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp28
-rw-r--r--modules/openxr/openxr_api.cpp39
-rw-r--r--modules/openxr/openxr_api.h8
-rw-r--r--modules/openxr/openxr_interface.cpp88
-rw-r--r--modules/openxr/openxr_interface.h5
-rw-r--r--modules/text_server_adv/text_server_adv.cpp11
-rw-r--r--modules/text_server_fb/text_server_fb.cpp10
-rw-r--r--modules/websocket/wsl_peer.cpp6
-rw-r--r--platform/android/export/export_plugin.cpp26
-rw-r--r--platform/android/java/build.gradle12
-rw-r--r--platform/ios/view_controller.mm12
-rw-r--r--platform/windows/display_server_windows.cpp3
-rw-r--r--platform/windows/display_server_windows.h1
-rw-r--r--scene/3d/node_3d.h4
-rw-r--r--scene/3d/xr_nodes.cpp4
-rw-r--r--scene/gui/text_edit.cpp4
-rw-r--r--scene/main/viewport.cpp1
-rw-r--r--scene/resources/visual_shader_nodes.cpp2
-rw-r--r--tests/core/string/test_string.h4
-rw-r--r--tests/scene/test_text_edit.h26
46 files changed, 879 insertions, 330 deletions
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index 671b06f0ed..2e0ad94fcf 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -1567,10 +1567,11 @@ String String::num_real(double p_num, bool p_trailing) {
#else
int decimals = 6;
#endif
- // We want to align the digits to the above sane default, so we only
- // need to subtract log10 for numbers with a positive power of ten.
- if (p_num > 10) {
- decimals -= (int)floor(log10(p_num));
+ // We want to align the digits to the above sane default, so we only need
+ // to subtract log10 for numbers with a positive power of ten magnitude.
+ double abs_num = Math::abs(p_num);
+ if (abs_num > 10) {
+ decimals -= (int)floor(log10(abs_num));
}
return num(p_num, decimals);
}
diff --git a/core/variant/container_type_validate.h b/core/variant/container_type_validate.h
index 6171c8c88f..427a337aab 100644
--- a/core/variant/container_type_validate.h
+++ b/core/variant/container_type_validate.h
@@ -79,9 +79,12 @@ struct ContainerTypeValidate {
return true;
}
- ERR_FAIL_COND_V_MSG(type != p_variant.get_type(), false, "Attempted to " + String(p_operation) + " a variable of type '" + Variant::get_type_name(p_variant.get_type()) + "' into a " + where + " of type '" + Variant::get_type_name(type) + "'.");
if (type != p_variant.get_type()) {
- return false;
+ if (p_variant.get_type() == Variant::NIL && type == Variant::OBJECT) {
+ return true;
+ }
+
+ ERR_FAIL_V_MSG(false, "Attempted to " + String(p_operation) + " a variable of type '" + Variant::get_type_name(p_variant.get_type()) + "' into a " + where + " of type '" + Variant::get_type_name(type) + "'.");
}
if (type != Variant::OBJECT) {
@@ -90,7 +93,7 @@ struct ContainerTypeValidate {
#ifdef DEBUG_ENABLED
ObjectID object_id = p_variant;
if (object_id == ObjectID()) {
- return true; //fine its null;
+ return true; // This is fine, it's null.
}
Object *object = ObjectDB::get_instance(object_id);
ERR_FAIL_COND_V_MSG(object == nullptr, false, "Attempted to " + String(p_operation) + " an invalid (previously freed?) object instance into a '" + String(where) + ".");
@@ -101,7 +104,7 @@ struct ContainerTypeValidate {
}
#endif
if (class_name == StringName()) {
- return true; //all good, no class type requested
+ return true; // All good, no class type requested.
}
StringName obj_class = object->get_class_name();
@@ -110,12 +113,12 @@ struct ContainerTypeValidate {
}
if (script.is_null()) {
- return true; //all good
+ return true; // All good, no script requested.
}
Ref<Script> other_script = object->get_script();
- //check base script..
+ // Check base script..
ERR_FAIL_COND_V_MSG(other_script.is_null(), false, "Attempted to " + String(p_operation) + " an object into a " + String(where) + ", that does not inherit from '" + String(script->get_class_name()) + "'.");
ERR_FAIL_COND_V_MSG(!other_script->inherits_script(script), false, "Attempted to " + String(p_operation) + " an object into a " + String(where) + ", that does not inherit from '" + String(script->get_class_name()) + "'.");
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index 43f85fcdbc..b04b5549e5 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -16,7 +16,7 @@
<return type="Variant" />
<param index="0" name="x" type="Variant" />
<description>
- Returns the absolute value of a [Variant] parameter [param x] (i.e. non-negative value). Variant types [int], [float] (real), [Vector2], [Vector2i], [Vector3] and [Vector3i] are supported.
+ Returns the absolute value of a [Variant] parameter [param x] (i.e. non-negative value). Variant types [int], [float], [Vector2], [Vector2i], [Vector3] and [Vector3i] are supported.
[codeblock]
var a = abs(-1)
# a is 1
@@ -114,7 +114,7 @@
<param index="3" name="end" type="float" />
<param index="4" name="t" type="float" />
<description>
- Returns the point at the given [param t] on a one-dimnesional [url=https://en.wikipedia.org/wiki/B%C3%A9zier_curve]Bezier curve[/url] defined by the given [param control_1], [param control_2], and [param end] points.
+ Returns the point at the given [param t] on a one-dimensional [url=https://en.wikipedia.org/wiki/B%C3%A9zier_curve]Bezier curve[/url] defined by the given [param control_1], [param control_2], and [param end] points.
</description>
</method>
<method name="bytes_to_var">
@@ -143,7 +143,7 @@
i = ceil(1.001) # i is 2.0
[/codeblock]
See also [method floor], [method round], and [method snapped].
- [b]Note:[/b] For better type safety, you can use [method ceilf], [method ceili], [method Vector2.ceil], [method Vector3.ceil] or [method Vector4.ceil] instead.
+ [b]Note:[/b] For better type safety, see [method ceilf], [method ceili], [method Vector2.ceil], [method Vector3.ceil] and [method Vector4.ceil].
</description>
</method>
<method name="ceilf">
@@ -151,7 +151,7 @@
<param index="0" name="x" type="float" />
<description>
Rounds [param x] upward (towards positive infinity), returning the smallest whole number that is not less than [param x].
- A type-safe version of [method ceil], specialzied in floats.
+ A type-safe version of [method ceil], returning a [float].
</description>
</method>
<method name="ceili">
@@ -159,7 +159,7 @@
<param index="0" name="x" type="float" />
<description>
Rounds [param x] upward (towards positive infinity), returning the smallest whole number that is not less than [param x].
- A type-safe version of [method ceil] that returns integer.
+ A type-safe version of [method ceil], returning an [int].
</description>
</method>
<method name="clamp">
@@ -168,7 +168,7 @@
<param index="1" name="min" type="Variant" />
<param index="2" name="max" type="Variant" />
<description>
- Clamps the [Variant] [param value] and returns a value not less than [param min] and not more than [param max]. Variant types [int], [float] (real), [Vector2], [Vector2i], [Vector3] and [Vector3i] are supported.
+ Clamps the [param value], returning a [Variant] not less than [param min] and not more than [param max]. Variant types [int], [float], [Vector2], [Vector2i], [Vector3] and [Vector3i] are supported.
[codeblock]
var a = clamp(-10, -1, 5)
# a is -1
@@ -196,15 +196,13 @@
<param index="1" name="min" type="float" />
<param index="2" name="max" type="float" />
<description>
- Clamps the float [param value] and returns a value not less than [param min] and not more than [param max].
+ Clamps the [param value], returning a [float] not less than [param min] and not more than [param max].
[codeblock]
var speed = 42.1
- # a is 20.0
- var a = clampf(speed, 1.0, 20.0)
+ var a = clampf(speed, 1.0, 20.5) # a is 20.5
speed = -10.0
- # a is -1.0
- a = clampf(speed, -1.0, 1.0)
+ var b = clampf(speed, -1.0, 1.0) # b is -1.0
[/codeblock]
</description>
</method>
@@ -214,15 +212,13 @@
<param index="1" name="min" type="int" />
<param index="2" name="max" type="int" />
<description>
- Clamps the integer [param value] and returns a value not less than [param min] and not more than [param max].
+ Clamps the [param value], returning an [int] not less than [param min] and not more than [param max].
[codeblock]
var speed = 42
- # a is 20
- var a = clampi(speed, 1, 20)
+ var a = clampi(speed, 1, 20) # a is 20
speed = -10
- # a is -1
- a = clampi(speed, -1, 1)
+ var b = clampi(speed, -1, 1) # b is -1
[/codeblock]
</description>
</method>
@@ -244,8 +240,7 @@
<description>
Returns the hyperbolic cosine of [param x] in radians.
[codeblock]
- # Prints 1.543081
- print(cosh(1))
+ print(cosh(1)) # Prints 1.543081
[/codeblock]
</description>
</method>
@@ -257,7 +252,7 @@
<param index="3" name="post" type="float" />
<param index="4" name="weight" type="float" />
<description>
- Cubic interpolates between two values by the factor defined in [param weight] with pre and post values.
+ Cubic interpolates between two values by the factor defined in [param weight] with [param pre] and [param post] values.
</description>
</method>
<method name="cubic_interpolate_angle">
@@ -268,7 +263,7 @@
<param index="3" name="post" type="float" />
<param index="4" name="weight" type="float" />
<description>
- Cubic interpolates between two rotation values with shortest path by the factor defined in [param weight] with pre and post values. See also [method lerp_angle].
+ Cubic interpolates between two rotation values with shortest path by the factor defined in [param weight] with [param pre] and [param post] values. See also [method lerp_angle].
</description>
</method>
<method name="cubic_interpolate_angle_in_time">
@@ -282,7 +277,7 @@
<param index="6" name="pre_t" type="float" />
<param index="7" name="post_t" type="float" />
<description>
- Cubic interpolates between two rotation values with shortest path by the factor defined in [param weight] with pre and post values. See also [method lerp_angle].
+ Cubic interpolates between two rotation values with shortest path by the factor defined in [param weight] with [param pre] and [param post] values. See also [method lerp_angle].
It can perform smoother interpolation than [code]cubic_interpolate()[/code] by the time values.
</description>
</method>
@@ -297,8 +292,8 @@
<param index="6" name="pre_t" type="float" />
<param index="7" name="post_t" type="float" />
<description>
- Cubic interpolates between two values by the factor defined in [param weight] with pre and post values.
- It can perform smoother interpolation than [code]cubic_interpolate()[/code] by the time values.
+ Cubic interpolates between two values by the factor defined in [param weight] with [param pre] and [param post] values.
+ It can perform smoother interpolation than [method cubic_interpolate] by the time values.
</description>
</method>
<method name="db_to_linear">
@@ -314,8 +309,7 @@
<description>
Converts an angle expressed in degrees to radians.
[codeblock]
- # r is 3.141593
- var r = deg_to_rad(180)
+ var r = deg_to_rad(180) # r is 3.141593
[/codeblock]
</description>
</method>
@@ -342,7 +336,13 @@
<return type="String" />
<param index="0" name="error" type="int" />
<description>
- Returns a human-readable name for the given error code.
+ Returns a human-readable name for the given [enum Error] code.
+ [codeblock]
+ print(OK) # Prints 0
+ print(error_string(OK)) # Prints OK
+ print(error_string(ERR_BUSY)) # Prints Busy
+ print(error_string(ERR_OUT_OF_MEMORY)) # Prints Out of memory
+ [/codeblock]
</description>
</method>
<method name="exp">
@@ -363,13 +363,11 @@
<description>
Rounds [param x] downward (towards negative infinity), returning the largest whole number that is not more than [param x]. Supported types: [int], [float], [Vector2], [Vector3], [Vector4].
[codeblock]
- # a is 2.0
- var a = floor(2.99)
- # a is -3.0
- a = floor(-2.99)
+ var a = floor(2.99) # a is 2.0
+ a = floor(-2.99) # a is -3.0
[/codeblock]
See also [method ceil], [method round], and [method snapped].
- [b]Note:[/b] For better type safety, you can use [method floorf], [method floori], [method Vector2.floor], [method Vector3.floor] or [method Vector4.floor] instead.
+ [b]Note:[/b] For better type safety, see [method floorf], [method floori], [method Vector2.floor], [method Vector3.floor] and [method Vector4.floor].
</description>
</method>
<method name="floorf">
@@ -377,7 +375,7 @@
<param index="0" name="x" type="float" />
<description>
Rounds [param x] downward (towards negative infinity), returning the largest whole number that is not more than [param x].
- A type-safe version of [method floor], specialzied in floats.
+ A type-safe version of [method floor], returning a [float].
</description>
</method>
<method name="floori">
@@ -385,7 +383,8 @@
<param index="0" name="x" type="float" />
<description>
Rounds [param x] downward (towards negative infinity), returning the largest whole number that is not more than [param x].
- Equivalent of doing [code]int(x)[/code].
+ A type-safe version of [method floor], returning an [int].
+ [b]Note:[/b] This function is [i]not[/i] the same as [code]int(x)[/code], which rounds towards 0.
</description>
</method>
<method name="fmod">
@@ -393,10 +392,9 @@
<param index="0" name="x" type="float" />
<param index="1" name="y" type="float" />
<description>
- Returns the floating-point remainder of [code]x/y[/code], keeping the sign of [param x].
+ Returns the floating-point remainder of [param x] divided by [param y], keeping the sign of [param x].
[codeblock]
- # Remainder is 1.5
- var remainder = fmod(7, 5.5)
+ var remainder = fmod(7, 5.5) # remainder is 1.5
[/codeblock]
For the integer remainder operation, use the [code]%[/code] operator.
</description>
@@ -406,21 +404,23 @@
<param index="0" name="x" type="float" />
<param index="1" name="y" type="float" />
<description>
- Returns the floating-point modulus of [code]x/y[/code] that wraps equally in positive and negative.
+ Returns the floating-point modulus of [param x] divided by [param y], wrapping equally in positive and negative.
[codeblock]
+ print(" (x) (fmod(x, 1.5)) (fposmod(x, 1.5))")
for i in 7:
- var x = 0.5 * i - 1.5
- print("%4.1f %4.1f %4.1f" % [x, fmod(x, 1.5), fposmod(x, 1.5)])
+ var x = i * 0.5 - 1.5
+ print("%4.1f %4.1f | %4.1f" % [x, fmod(x, 1.5), fposmod(x, 1.5)])
[/codeblock]
Produces:
[codeblock]
- -1.5 -0.0 0.0
- -1.0 -1.0 0.5
- -0.5 -0.5 1.0
- 0.0 0.0 0.0
- 0.5 0.5 0.5
- 1.0 1.0 1.0
- 1.5 0.0 0.0
+ (x) (fmod(x, 1.5)) (fposmod(x, 1.5))
+ -1.5 -0.0 | 0.0
+ -1.0 -1.0 | 0.5
+ -0.5 -0.5 | 1.0
+ 0.0 0.0 | 0.0
+ 0.5 0.5 | 0.5
+ 1.0 1.0 | 1.0
+ 1.5 0.0 | 0.0
[/codeblock]
</description>
</method>
@@ -428,7 +428,7 @@
<return type="int" />
<param index="0" name="variable" type="Variant" />
<description>
- Returns the integer hash of the variable passed.
+ Returns the integer hash of the passed [param variable].
[codeblock]
print(hash("a")) # Prints 177670
[/codeblock]
@@ -438,7 +438,7 @@
<return type="Object" />
<param index="0" name="instance_id" type="int" />
<description>
- Returns the Object that corresponds to [param instance_id]. All Objects have a unique instance ID.
+ Returns the [Object] that corresponds to [param instance_id]. All Objects have a unique instance ID. See also [method Object.get_instance_id].
[codeblock]
var foo = "bar"
func _ready():
@@ -458,12 +458,13 @@
[codeblock]
# The interpolation ratio in the `lerp()` call below is 0.75.
var middle = lerp(20, 30, 0.75)
- # `middle` is now 27.5.
+ # middle is now 27.5.
+
# Now, we pretend to have forgotten the original ratio and want to get it back.
var ratio = inverse_lerp(20, 30, 27.5)
- # `ratio` is now 0.75.
+ # ratio is now 0.75.
[/codeblock]
- See also [method lerp] which performs the reverse of this operation, and [method remap] to map a continuous series of values to another.
+ See also [method lerp], which performs the reverse of this operation, and [method remap] to map a continuous series of values to another.
</description>
</method>
<method name="is_equal_approx">
@@ -472,7 +473,7 @@
<param index="1" name="b" type="float" />
<description>
Returns [code]true[/code] if [param a] and [param b] are approximately equal to each other.
- Here, approximately equal means that [param a] and [param b] are within a small internal epsilon of each other, which scales with the magnitude of the numbers.
+ Here, "approximately equal" means that [param a] and [param b] are within a small internal epsilon of each other, which scales with the magnitude of the numbers.
Infinity values of the same sign are considered equal.
</description>
</method>
@@ -487,7 +488,7 @@
<return type="bool" />
<param index="0" name="x" type="float" />
<description>
- Returns whether [param x] is an infinity value (either positive infinity or negative infinity).
+ Returns [code]true[/code] if [param x] is either positive infinity or negative infinity.
</description>
</method>
<method name="is_instance_id_valid">
@@ -501,14 +502,14 @@
<return type="bool" />
<param index="0" name="instance" type="Variant" />
<description>
- Returns whether [param instance] is a valid object (e.g. has not been deleted from memory).
+ Returns [code]true[/code] if [param instance] is a valid Object (e.g. has not been deleted from memory).
</description>
</method>
<method name="is_nan">
<return type="bool" />
<param index="0" name="x" type="float" />
<description>
- Returns whether [param x] is a NaN ("Not a Number" or invalid) value.
+ Returns [code]true[/code] if [param x] is a NaN ("Not a Number" or invalid) value.
</description>
</method>
<method name="is_zero_approx">
@@ -516,7 +517,7 @@
<param index="0" name="x" type="float" />
<description>
Returns [code]true[/code] if [param x] is zero or almost zero.
- This method is faster than using [method is_equal_approx] with one value as zero.
+ This function is faster than using [method is_equal_approx] with one value as zero.
</description>
</method>
<method name="lerp">
@@ -525,13 +526,13 @@
<param index="1" name="to" type="Variant" />
<param index="2" name="weight" type="Variant" />
<description>
- Linearly interpolates between two values by the factor defined in [param weight]. To perform interpolation, [param weight] should be between [code]0.0[/code] and [code]1.0[/code] (inclusive). However, values outside this range are allowed and can be used to perform [i]extrapolation[/i]. Use [method clamp] on the result of [method lerp] if this is not desired.
- Both [param from] and [param to] must have matching types. Supported types: [float], [Vector2], [Vector3], [Vector4], [Color], [Quaternion], [Basis].
+ Linearly interpolates between two values by the factor defined in [param weight]. To perform interpolation, [param weight] should be between [code]0.0[/code] and [code]1.0[/code] (inclusive). However, values outside this range are allowed and can be used to perform [i]extrapolation[/i]. If this is not desired, use [method clamp] on the result of this function.
+ Both [param from] and [param to] must be the same type. Supported types: [float], [Vector2], [Vector3], [Vector4], [Color], [Quaternion], [Basis].
[codeblock]
lerp(0, 4, 0.75) # Returns 3.0
[/codeblock]
See also [method inverse_lerp] which performs the reverse of this operation. To perform eased interpolation with [method lerp], combine it with [method ease] or [method smoothstep]. See also [method remap] to map a continuous series of values to another.
- [b]Note:[/b] For better type safety, you can use [method lerpf], [method Vector2.lerp], [method Vector3.lerp], [method Vector4.lerp], [method Color.lerp], [method Quaternion.slerp] or [method Basis.slerp] instead.
+ [b]Note:[/b] For better type safety, use [method lerpf], [method Vector2.lerp], [method Vector3.lerp], [method Vector4.lerp], [method Color.lerp], [method Quaternion.slerp] or [method Basis.slerp].
</description>
</method>
<method name="lerp_angle">
@@ -540,7 +541,7 @@
<param index="1" name="to" type="float" />
<param index="2" name="weight" type="float" />
<description>
- Linearly interpolates between two angles (in radians) by a normalized value.
+ Linearly interpolates between two angles (in radians) by a [param weight] value between 0.0 and 1.0.
Similar to [method lerp], but interpolates correctly when the angles wrap around [constant @GDScript.TAU]. To perform eased interpolation with [method lerp_angle], combine it with [method ease] or [method smoothstep].
[codeblock]
extends Sprite
@@ -551,7 +552,7 @@
rotation = lerp_angle(min_angle, max_angle, elapsed)
elapsed += delta
[/codeblock]
- [b]Note:[/b] This method lerps through the shortest path between [param from] and [param to]. However, when these two angles are approximately [code]PI + k * TAU[/code] apart for any integer [code]k[/code], it's not obvious which way they lerp due to floating-point precision errors. For example, [code]lerp_angle(0, PI, weight)[/code] lerps counter-clockwise, while [code]lerp_angle(0, PI + 5 * TAU, weight)[/code] lerps clockwise.
+ [b]Note:[/b] This function lerps through the shortest path between [param from] and [param to]. However, when these two angles are approximately [code]PI + k * TAU[/code] apart for any integer [code]k[/code], it's not obvious which way they lerp due to floating-point precision errors. For example, [code]lerp_angle(0, PI, weight)[/code] lerps counter-clockwise, while [code]lerp_angle(0, PI + 5 * TAU, weight)[/code] lerps clockwise.
</description>
</method>
<method name="lerpf">
@@ -560,7 +561,7 @@
<param index="1" name="to" type="float" />
<param index="2" name="weight" type="float" />
<description>
- Linearly interpolates between two values by the factor defined in [param weight]. To perform interpolation, [param weight] should be between [code]0.0[/code] and [code]1.0[/code] (inclusive). However, values outside this range are allowed and can be used to perform [i]extrapolation[/i].
+ Linearly interpolates between two values by the factor defined in [param weight]. To perform interpolation, [param weight] should be between [code]0.0[/code] and [code]1.0[/code] (inclusive). However, values outside this range are allowed and can be used to perform [i]extrapolation[/i]. If this is not desired, use [method clampf] on the result of this function.
[codeblock]
lerp(0, 4, 0.75) # Returns 3.0
[/codeblock]
@@ -584,7 +585,7 @@
<return type="float" />
<param index="0" name="x" type="float" />
<description>
- Natural logarithm. The amount of time needed to reach a certain level of continuous growth.
+ Returns the natural logarithm of [param x]. This is the amount of time needed to reach a certain level of continuous growth.
[b]Note:[/b] This is not the same as the "log" function on most calculators, which uses a base 10 logarithm.
[codeblock]
log(10) # Returns 2.302585
@@ -595,7 +596,7 @@
<method name="max" qualifiers="vararg">
<return type="Variant" />
<description>
- Returns the maximum of the given values. This method can take any number of arguments.
+ Returns the maximum of the given values. This function can take any number of arguments.
[codeblock]
max(1, 7, 3, -6, 5) # Returns 7
[/codeblock]
@@ -606,9 +607,9 @@
<param index="0" name="a" type="float" />
<param index="1" name="b" type="float" />
<description>
- Returns the maximum of two float values.
+ Returns the maximum of two [float] values.
[codeblock]
- maxf(3.6, 24) # Returns 24.0
+ maxf(3.6, 24) # Returns 24.0
maxf(-3.99, -4) # Returns -3.99
[/codeblock]
</description>
@@ -618,9 +619,9 @@
<param index="0" name="a" type="int" />
<param index="1" name="b" type="int" />
<description>
- Returns the maximum of two int values.
+ Returns the maximum of two [int] values.
[codeblock]
- maxi(1, 2) # Returns 2
+ maxi(1, 2) # Returns 2
maxi(-3, -4) # Returns -3
[/codeblock]
</description>
@@ -628,7 +629,7 @@
<method name="min" qualifiers="vararg">
<return type="Variant" />
<description>
- Returns the minimum of the given values. This method can take any number of arguments.
+ Returns the minimum of the given values. This function can take any number of arguments.
[codeblock]
min(1, 7, 3, -6, 5) # Returns -6
[/codeblock]
@@ -639,9 +640,9 @@
<param index="0" name="a" type="float" />
<param index="1" name="b" type="float" />
<description>
- Returns the minimum of two float values.
+ Returns the minimum of two [float] values.
[codeblock]
- minf(3.6, 24) # Returns 3.6
+ minf(3.6, 24) # Returns 3.6
minf(-3.99, -4) # Returns -4.0
[/codeblock]
</description>
@@ -651,9 +652,9 @@
<param index="0" name="a" type="int" />
<param index="1" name="b" type="int" />
<description>
- Returns the minimum of two int values.
+ Returns the minimum of two [int] values.
[codeblock]
- mini(1, 2) # Returns 1
+ mini(1, 2) # Returns 1
mini(-3, -4) # Returns -4
[/codeblock]
</description>
@@ -667,8 +668,8 @@
Moves [param from] toward [param to] by the [param delta] value.
Use a negative [param delta] value to move away.
[codeblock]
- move_toward(5, 10, 4) # Returns 9
- move_toward(10, 5, 4) # Returns 6
+ move_toward(5, 10, 4) # Returns 9
+ move_toward(10, 5, 4) # Returns 6
move_toward(10, 5, -1.5) # Returns 11.5
[/codeblock]
</description>
@@ -677,17 +678,17 @@
<return type="int" />
<param index="0" name="value" type="int" />
<description>
- Returns the nearest equal or larger power of 2 for integer [param value].
+ Returns the nearest equal or larger power of 2 for the integer [param value].
In other words, returns the smallest value [code]a[/code] where [code]a = pow(2, n)[/code] such that [code]value &lt;= a[/code] for some non-negative integer [code]n[/code].
[codeblock]
nearest_po2(3) # Returns 4
nearest_po2(4) # Returns 4
nearest_po2(5) # Returns 8
- nearest_po2(0) # Returns 0 (this may not be what you expect)
- nearest_po2(-1) # Returns 0 (this may not be what you expect)
+ nearest_po2(0) # Returns 0 (this may not be expected)
+ nearest_po2(-1) # Returns 0 (this may not be expected)
[/codeblock]
- [b]Warning:[/b] Due to the way it is implemented, this function returns [code]0[/code] rather than [code]1[/code] for non-positive values of [param value] (in reality, 1 is the smallest integer power of 2).
+ [b]Warning:[/b] Due to the way it is implemented, this function returns [code]0[/code] rather than [code]1[/code] for negative values of [param value] (in reality, 1 is the smallest integer power of 2).
</description>
</method>
<method name="pingpong">
@@ -695,18 +696,18 @@
<param index="0" name="value" type="float" />
<param index="1" name="length" type="float" />
<description>
- Returns the [param value] wrapped between [code]0[/code] and the [param length]. If the limit is reached, the next value the function returned is decreased to the [code]0[/code] side or increased to the [param length] side (like a triangle wave). If [param length] is less than zero, it becomes positive.
+ Wraps [param value] between [code]0[/code] and the [param length]. If the limit is reached, the next value the function returns is decreased to the [code]0[/code] side or increased to the [param length] side (like a triangle wave). If [param length] is less than zero, it becomes positive.
[codeblock]
- pingpong(-3.0, 3.0) # Returns 3
- pingpong(-2.0, 3.0) # Returns 2
- pingpong(-1.0, 3.0) # Returns 1
- pingpong(0.0, 3.0) # Returns 0
- pingpong(1.0, 3.0) # Returns 1
- pingpong(2.0, 3.0) # Returns 2
- pingpong(3.0, 3.0) # Returns 3
- pingpong(4.0, 3.0) # Returns 2
- pingpong(5.0, 3.0) # Returns 1
- pingpong(6.0, 3.0) # Returns 0
+ pingpong(-3.0, 3.0) # Returns 3.0
+ pingpong(-2.0, 3.0) # Returns 2.0
+ pingpong(-1.0, 3.0) # Returns 1.0
+ pingpong(0.0, 3.0) # Returns 0.0
+ pingpong(1.0, 3.0) # Returns 1.0
+ pingpong(2.0, 3.0) # Returns 2.0
+ pingpong(3.0, 3.0) # Returns 3.0
+ pingpong(4.0, 3.0) # Returns 2.0
+ pingpong(5.0, 3.0) # Returns 1.0
+ pingpong(6.0, 3.0) # Returns 0.0
[/codeblock]
</description>
</method>
@@ -715,20 +716,22 @@
<param index="0" name="x" type="int" />
<param index="1" name="y" type="int" />
<description>
- Returns the integer modulus of [code]x/y[/code] that wraps equally in positive and negative.
+ Returns the integer modulus of [param x] divided by [param y] that wraps equally in positive and negative.
[codeblock]
+ print("#(i) (i % 3) (posmod(i, 3))")
for i in range(-3, 4):
- print("%2d %2d %2d" % [i, i % 3, posmod(i, 3)])
+ print("%2d %2d | %2d" % [i, i % 3, posmod(i, 3)])
[/codeblock]
Produces:
[codeblock]
- -3 0 0
- -2 -2 1
- -1 -1 2
- 0 0 0
- 1 1 1
- 2 2 2
- 3 0 0
+ (i) (i % 3) (posmod(i, 3))
+ -3 0 | 0
+ -2 -2 | 1
+ -1 -1 | 2
+ 0 0 | 0
+ 1 1 | 1
+ 2 2 | 2
+ 3 0 | 0
[/codeblock]
</description>
</method>
@@ -738,6 +741,7 @@
<param index="1" name="exp" type="float" />
<description>
Returns the result of [param base] raised to the power of [param exp].
+ In GDScript, this is the equivalent of the [code]**[/code] operator.
[codeblock]
pow(2, 5) # Returns 32
[/codeblock]
@@ -750,7 +754,7 @@
var a = [1, 2, 3]
print("a", "b", a) # Prints ab[1, 2, 3]
[/codeblock]
- [b]Note:[/b] Consider using [method push_error] and [method push_warning] to print error and warning messages instead of [method print]. This distinguishes them from print messages used for debugging purposes, while also displaying a stack trace when an error or warning is printed.
+ [b]Note:[/b] Consider using [method push_error] and [method push_warning] to print error and warning messages instead of [method print] or [method print_rich]. This distinguishes them from print messages used for debugging purposes, while also displaying a stack trace when an error or warning is printed.
</description>
</method>
<method name="print_rich" qualifiers="vararg">
@@ -778,11 +782,12 @@
</method>
<method name="printraw" qualifiers="vararg">
<description>
- Prints one or more arguments to strings in the best way possible to console. No newline is added at the end.
+ Prints one or more arguments to strings in the best way possible to console. Unlike [method print], no newline is automatically added at the end.
[codeblock]
printraw("A")
printraw("B")
- # Prints AB
+ printraw("C")
+ # Prints ABC
[/codeblock]
[b]Note:[/b] Due to limitations with Godot's built-in console, this only prints to the terminal. If you need to print in the editor, use another method, such as [method print].
</description>
@@ -809,7 +814,7 @@
[codeblock]
push_error("test error") # Prints "test error" to debugger and terminal as error call
[/codeblock]
- [b]Note:[/b] Errors printed this way will not pause project execution. To print an error message and pause project execution in debug builds, use [code]assert(false, "test error")[/code] instead.
+ [b]Note:[/b] This function does not pause project execution. To print an error message and pause project execution in debug builds, use [code]assert(false, "test error")[/code] instead.
</description>
</method>
<method name="push_warning" qualifiers="vararg">
@@ -827,6 +832,8 @@
Converts an angle expressed in radians to degrees.
[codeblock]
rad_to_deg(0.523599) # Returns 30
+ rad_to_deg(PI) # Returns 180
+ rad_to_deg(PI * 2) # Returns 360
[/codeblock]
</description>
</method>
@@ -834,7 +841,14 @@
<return type="PackedInt64Array" />
<param index="0" name="seed" type="int" />
<description>
- Random from seed: pass a [param seed], and an array with both number and new seed is returned. "Seed" here refers to the internal state of the pseudo random number generator. The internal state of the current implementation is 64 bits.
+ Given a [param seed], returns a [PackedInt64Array] of size [code]2[/code], where its first element is the randomised [int] value, and the second element is the same as [param seed]. Passing the same [param seed] consistently returns the same array.
+ [b]Note:[/b] "Seed" here refers to the internal state of the pseudo random number generator, currently implemented as a 64 bit integer.
+ [codeblock]
+ var a = rand_from_seed(4)
+
+ print(a[0]) # Prints 2879024997
+ print(a[1]) # Prints 4
+ [/codeblock]
</description>
</method>
<method name="randf">
@@ -851,9 +865,10 @@
<param index="0" name="from" type="float" />
<param index="1" name="to" type="float" />
<description>
- Returns a random floating point value on the interval between [param from] and [param to] (inclusive).
+ Returns a random floating point value between [param from] and [param to] (inclusive).
[codeblock]
- prints(randf_range(-10, 10), randf_range(-10, 10)) # Prints e.g. -3.844535 7.45315
+ randf_range(0, 20.5) # Returns e.g. 7.45315
+ randf_range(-10, 10) # Returns e.g. -3.844535
[/codeblock]
</description>
</method>
@@ -884,15 +899,15 @@
<description>
Returns a random signed 32-bit integer between [param from] and [param to] (inclusive). If [param to] is lesser than [param from], they are swapped.
[codeblock]
- print(randi_range(0, 1)) # Prints 0 or 1
- print(randi_range(-10, 1000)) # Prints any number from -10 to 1000
+ randi_range(0, 1) # Returns either 0 or 1
+ randi_range(-10, 1000) # Returns random integer between -10 and 1000
[/codeblock]
</description>
</method>
<method name="randomize">
<description>
- Randomizes the seed (or the internal state) of the random number generator. Current implementation reseeds using a number based on time.
- [b]Note:[/b] This method is called automatically when the project is run. If you need to fix the seed to have reproducible results, use [method seed] to initialize the random number generator.
+ Randomizes the seed (or the internal state) of the random number generator. The current implementation uses a number based on the device's time.
+ [b]Note:[/b] This function is called automatically when the project is run. If you need to fix the seed to have consistent, reproducible results, use [method seed] to initialize the random number generator.
</description>
</method>
<method name="remap">
@@ -903,63 +918,67 @@
<param index="3" name="ostart" type="float" />
<param index="4" name="ostop" type="float" />
<description>
- Maps a [param value] from range [code][istart, istop][/code] to [code][ostart, ostop][/code]. See also [method lerp] and [method inverse_lerp]. If [param value] is outside [code][istart, istop][/code], then the resulting value will also be outside [code][ostart, ostop][/code]. Use [method clamp] on the result of [method remap] if this is not desired.
+ Maps a [param value] from range [code][istart, istop][/code] to [code][ostart, ostop][/code]. See also [method lerp] and [method inverse_lerp]. If [param value] is outside [code][istart, istop][/code], then the resulting value will also be outside [code][ostart, ostop][/code]. If this is not desired, use [method clamp] on the result of this function.
[codeblock]
remap(75, 0, 100, -1, 1) # Returns 0.5
[/codeblock]
- For complex use cases where you need multiple ranges, consider using [Curve] or [Gradient] instead.
+ For complex use cases where multiple ranges are needed, consider using [Curve] or [Gradient] instead.
</description>
</method>
<method name="rid_allocate_id">
<return type="int" />
<description>
- Allocate a unique ID which can be used by the implementation to construct a RID. This is used mainly from native extensions to implement servers.
+ Allocates a unique ID which can be used by the implementation to construct a RID. This is used mainly from native extensions to implement servers.
</description>
</method>
<method name="rid_from_int64">
<return type="RID" />
<param index="0" name="base" type="int" />
<description>
- Create a RID from an int64. This is used mainly from native extensions to build servers.
+ Creates a RID from a [param base]. This is used mainly from native extensions to build servers.
</description>
</method>
<method name="round">
<return type="Variant" />
<param index="0" name="x" type="Variant" />
<description>
- Rounds [param x] to the nearest whole number, with halfway cases rounded away from zero. Supported types: [int], [float], [Vector2], [Vector3], [Vector4].
+ Rounds [param x] to the nearest whole number, with halfway cases rounded away from 0. Supported types: [int], [float], [Vector2], [Vector3], [Vector4].
[codeblock]
round(2.4) # Returns 2
round(2.5) # Returns 3
round(2.6) # Returns 3
[/codeblock]
See also [method floor], [method ceil], and [method snapped].
- [b]Note:[/b] For better type safety, you can use [method roundf], [method roundi], [method Vector2.round], [method Vector3.round] or [method Vector4.round] instead.
+ [b]Note:[/b] For better type safety, use [method roundf], [method roundi], [method Vector2.round], [method Vector3.round] or [method Vector4.round], instead.
</description>
</method>
<method name="roundf">
<return type="float" />
<param index="0" name="x" type="float" />
<description>
- Rounds [param x] to the nearest whole number, with halfway cases rounded away from zero.
- A type-safe version of [method round], specialzied in floats.
+ Rounds [param x] to the nearest whole number, with halfway cases rounded away from 0.
+ A type-safe version of [method round], returning a [float].
</description>
</method>
<method name="roundi">
<return type="int" />
<param index="0" name="x" type="float" />
<description>
- Rounds [param x] to the nearest whole number, with halfway cases rounded away from zero.
- A type-safe version of [method round] that returns integer.
+ Rounds [param x] to the nearest whole number, with halfway cases rounded away from 0.
+ A type-safe version of [method round], returning an [int].
</description>
</method>
<method name="seed">
<param index="0" name="base" type="int" />
<description>
- Sets seed for the random number generator.
+ Sets the seed for the random number generator to [param base]. Setting the seed manually can ensure consistent, repeatable results for most random functions.
[codeblock]
- var my_seed = "Godot Rocks"
- seed(my_seed.hash())
+ var my_seed = "Godot Rocks".hash()
+ seed(my_seed)
+ var a = randf() + randi()
+ seed(my_seed)
+ var b = randf() + randi()
+ # a and b are now identical
[/codeblock]
</description>
</method>
@@ -967,7 +986,7 @@
<return type="Variant" />
<param index="0" name="x" type="Variant" />
<description>
- Returns the sign of [param x] as same type of [Variant] as [param x] with each component being -1, 0 and 1 for each negative, zero and positive values respectivelu. Variant types [int], [float] (real), [Vector2], [Vector2i], [Vector3] and [Vector3i] are supported.
+ Returns the sign of [param x] as same type of [Variant] as [param x] with each component being -1, 0 and 1 for each negative, zero and positive values respectively. Variant types [int], [float], [Vector2], [Vector2i], [Vector3] and [Vector3i] are supported.
[codeblock]
sign(-6.0) # Returns -1
sign(0.0) # Returns 0
@@ -981,11 +1000,11 @@
<return type="float" />
<param index="0" name="x" type="float" />
<description>
- Returns the sign of [param x] as a float: -1.0 or 1.0. Returns 0.0 if [param x] is 0.
+ Returns the sign of [param x] as a [float]: -1.0 or 1.0. Returns 0.0 if [param x] is 0.0.
[codeblock]
- sign(-6.0) # Returns -1.0
+ sign(-6.5) # Returns -1.0
sign(0.0) # Returns 0.0
- sign(6.0) # Returns 1.0
+ sign(6.5) # Returns 1.0
[/codeblock]
</description>
</method>
@@ -993,7 +1012,7 @@
<return type="int" />
<param index="0" name="x" type="int" />
<description>
- Returns the sign of [param x] as an integer: -1 or 1. Returns 0 if [param x] is 0.
+ Returns the sign of [param x] as an [int]: -1 or 1. Returns 0 if [param x] is 0.
[codeblock]
sign(-6) # Returns -1
sign(0) # Returns 0
@@ -1047,7 +1066,7 @@
<param index="0" name="x" type="float" />
<param index="1" name="step" type="float" />
<description>
- Snaps float value [param x] to a given [param step]. This can also be used to round a floating point number to an arbitrary number of decimals.
+ Snaps the float value [param x] to a given [param step]. This can also be used to round a floating point number to an arbitrary number of decimals.
[codeblock]
snapped(100, 32) # Returns 96
snapped(3.14159, 0.01) # Returns 3.14
@@ -1061,9 +1080,11 @@
<description>
Returns the square root of [param x], where [param x] is a non-negative number.
[codeblock]
- sqrt(9) # Returns 3
+ sqrt(9) # Returns 3
+ sqrt(10.24) # Returns 3.2
+ sqrt(-1) # Returns NaN
[/codeblock]
- [b]Note:[/b] Negative values of [param x] return NaN. If you need negative inputs, use [code]System.Numerics.Complex[/code] in C#.
+ [b]Note:[/b] Negative values of [param x] return NaN ("Not a Number"). in C#, if you need negative inputs, use [code]System.Numerics.Complex[/code].
</description>
</method>
<method name="step_decimals">
@@ -1072,30 +1093,27 @@
<description>
Returns the position of the first non-zero digit, after the decimal point. Note that the maximum return value is 10, which is a design decision in the implementation.
[codeblock]
- # n is 0
- var n = step_decimals(5)
- # n is 4
- n = step_decimals(1.0005)
- # n is 9
- n = step_decimals(0.000000005)
+ var n = step_decimals(5) # n is 0
+ n = step_decimals(1.0005) # n is 4
+ n = step_decimals(0.000000005) # n is 9
[/codeblock]
</description>
</method>
<method name="str" qualifiers="vararg">
<return type="String" />
<description>
- Converts one or more arguments of any type to string in the best way possible.
+ Converts one or more arguments of any [Variant] type to [String] in the best way possible.
</description>
</method>
<method name="str_to_var">
<return type="Variant" />
<param index="0" name="string" type="String" />
<description>
- Converts a formatted [param string] that was returned by [method var_to_str] to the original value.
+ Converts a formatted [param string] that was returned by [method var_to_str] to the original [Variant].
[codeblock]
- var a = '{ "a": 1, "b": 2 }'
- var b = str_to_var(a)
- print(b["a"]) # Prints 1
+ var a = '{ "a": 1, "b": 2 }' # a is a String
+ var b = str_to_var(a) # b is a Dictionary
+ print(b["a"]) # Prints 1
[/codeblock]
</description>
</method>
@@ -1116,7 +1134,7 @@
Returns the hyperbolic tangent of [param x].
[codeblock]
var a = log(2.0) # Returns 0.693147
- tanh(a) # Returns 0.6
+ tanh(a) # Returns 0.6
[/codeblock]
</description>
</method>
@@ -1124,7 +1142,7 @@
<return type="int" />
<param index="0" name="variable" type="Variant" />
<description>
- Returns the internal type of the given Variant object, using the [enum Variant.Type] values.
+ Returns the internal type of the given [param variable], using the [enum Variant.Type] values.
[codeblock]
var json = JSON.new()
json.parse('["a", "b", "c"]')
@@ -1148,19 +1166,19 @@
<return type="PackedByteArray" />
<param index="0" name="variable" type="Variant" />
<description>
- Encodes a [Variant] value to a byte array. Encoding objects is allowed (and can potentially include code). Deserialization can be done with [method bytes_to_var_with_objects].
+ Encodes a [Variant] value to a byte array. Encoding objects is allowed (and can potentially include executable code). Deserialization can be done with [method bytes_to_var_with_objects].
</description>
</method>
<method name="var_to_str">
<return type="String" />
<param index="0" name="variable" type="Variant" />
<description>
- Converts a Variant [param variable] to a formatted string that can later be parsed using [method str_to_var].
+ Converts a [Variant] [param variable] to a formatted [String] that can then be parsed using [method str_to_var].
[codeblock]
a = { "a": 1, "b": 2 }
print(var_to_str(a))
[/codeblock]
- prints
+ Prints:
[codeblock]
{
"a": 1,
@@ -1173,7 +1191,7 @@
<return type="Variant" />
<param index="0" name="obj" type="Variant" />
<description>
- Returns a weak reference to an object, or [code]null[/code] if the argument is invalid.
+ Returns a weak reference to an object, or [code]null[/code] if [param obj] is invalid.
A weak reference to an object is not enough to keep the object alive: when the only remaining references to a referent are weak references, garbage collection is free to destroy the referent and reuse its memory for something else. However, until the object is actually destroyed the weak reference may return the object even if there are no strong references to it.
</description>
</method>
@@ -1183,9 +1201,8 @@
<param index="1" name="min" type="Variant" />
<param index="2" name="max" type="Variant" />
<description>
- Wraps the [Variant] [param value] between [param min] and [param max].
- Usable for creating loop-alike behavior or infinite surfaces.
- Variant types [int] and [float] (real) are supported. If any of the argument is [float] the result will be [float], otherwise it is [int].
+ Wraps the [Variant] [param value] between [param min] and [param max]. Can be used for creating loop-alike behavior or infinite surfaces.
+ Variant types [int] and [float] are supported. If any of the arguments is [float] this function returns a [float], otherwise it returns an [int].
[codeblock]
var a = wrap(4, 5, 10)
# a is 9 (int)
@@ -1204,8 +1221,7 @@
<param index="1" name="min" type="float" />
<param index="2" name="max" type="float" />
<description>
- Wraps float [param value] between [param min] and [param max].
- Usable for creating loop-alike behavior or infinite surfaces.
+ Wraps the float [param value] between [param min] and [param max]. Can be used for creating loop-alike behavior or infinite surfaces.
[codeblock]
# Infinite loop between 5.0 and 9.9
value = wrapf(value + 0.1, 5.0, 10.0)
@@ -1228,8 +1244,7 @@
<param index="1" name="min" type="int" />
<param index="2" name="max" type="int" />
<description>
- Wraps integer [param value] between [param min] and [param max].
- Usable for creating loop-alike behavior or infinite surfaces.
+ Wraps the integer [param value] between [param min] and [param max]. Can be used for creating loop-alike behavior or infinite surfaces.
[codeblock]
# Infinite loop between 5 and 9
frame = wrapi(frame + 1, 5, 10)
@@ -2871,7 +2886,7 @@
Variable is of type [int].
</constant>
<constant name="TYPE_FLOAT" value="3" enum="Variant.Type">
- Variable is of type [float] (real).
+ Variable is of type [float].
</constant>
<constant name="TYPE_STRING" value="4" enum="Variant.Type">
Variable is of type [String].
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index ff66affeab..a8080c70c6 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -568,6 +568,13 @@
<member name="display/window/ios/hide_home_indicator" type="bool" setter="" getter="" default="true">
If [code]true[/code], the home indicator is hidden automatically. This only affects iOS devices without a physical home button.
</member>
+ <member name="display/window/ios/hide_status_bar" type="bool" setter="" getter="" default="true">
+ If [code]true[/code], the status bar is hidden while the app is running.
+ </member>
+ <member name="display/window/ios/suppress_ui_gesture" type="bool" setter="" getter="" default="true">
+ If [code]true[/code], it will require two swipes to access iOS UI that uses gestures.
+ [b]Note:[/b] This setting has no effect on the home indicator if [code]hide_home_indicator[/code] is [code]true[/code].
+ </member>
<member name="display/window/per_pixel_transparency/allowed" type="bool" setter="" getter="" default="false">
If [code]true[/code], allows per-pixel transparency for the window background. This affects performance, so leave it on [code]false[/code] unless you need it. See also [member display/window/size/transparent] and [member rendering/transparent_background].
</member>
diff --git a/doc/classes/PropertyTweener.xml b/doc/classes/PropertyTweener.xml
index 75d9c919aa..78ead65cdd 100644
--- a/doc/classes/PropertyTweener.xml
+++ b/doc/classes/PropertyTweener.xml
@@ -27,7 +27,7 @@
Sets a custom initial value to the [PropertyTweener]. Example:
[codeblock]
var tween = get_tree().create_tween()
- tween.tween_property(self, "position", Vector2(200, 100), 1).from(Vector2(100, 100) #this will move the node from position (100, 100) to (200, 100)
+ tween.tween_property(self, "position", Vector2(200, 100), 1).from(Vector2(100, 100)) #this will move the node from position (100, 100) to (200, 100)
[/codeblock]
</description>
</method>
diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml
index 998e782975..fce94fe567 100644
--- a/doc/classes/Viewport.xml
+++ b/doc/classes/Viewport.xml
@@ -71,6 +71,12 @@
<description>
</description>
</method>
+ <method name="get_screen_transform" qualifiers="const">
+ <return type="Transform2D" />
+ <description>
+ Returns the transform from the Viewport's coordinates to the screen coordinates of the containing window manager window.
+ </description>
+ </method>
<method name="get_texture" qualifiers="const">
<return type="ViewportTexture" />
<description>
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 4d3ffdc12b..421e8debed 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -2435,6 +2435,7 @@ void Node3DEditorViewport::_notification(int p_what) {
bool vp_visible = is_visible_in_tree();
set_process(vp_visible);
+ set_physics_process(vp_visible);
if (vp_visible) {
orthogonal = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_ORTHOGONAL));
@@ -2658,6 +2659,21 @@ void Node3DEditorViewport::_notification(int p_what) {
}
} break;
+ case NOTIFICATION_PHYSICS_PROCESS: {
+ if (!update_preview_node) {
+ return;
+ }
+ if (preview_node->is_inside_tree()) {
+ preview_node_pos = _get_instance_position(preview_node_viewport_pos);
+ Transform3D preview_gl_transform = Transform3D(Basis(), preview_node_pos);
+ preview_node->set_global_transform(preview_gl_transform);
+ if (!preview_node->is_visible()) {
+ preview_node->show();
+ }
+ }
+ update_preview_node = false;
+ } break;
+
case NOTIFICATION_ENTER_TREE: {
surface->connect("draw", callable_mp(this, &Node3DEditorViewport::_draw));
surface->connect("gui_input", callable_mp(this, &Node3DEditorViewport::_sinput));
@@ -4029,7 +4045,7 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po
gl_transform = parent_node3d->get_global_gizmo_transform();
}
- gl_transform.origin = spatial_editor->snap_point(_get_instance_position(p_point));
+ gl_transform.origin = spatial_editor->snap_point(preview_node_pos);
gl_transform.basis *= node3d->get_transform().basis;
editor_data->get_undo_redo()->add_do_method(instantiated_scene, "set_global_transform", gl_transform);
@@ -4093,7 +4109,9 @@ void Node3DEditorViewport::_perform_drop_data() {
}
}
-bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
+bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
+ preview_node_viewport_pos = p_point;
+
bool can_instantiate = false;
if (!preview_node->is_inside_tree() && spatial_editor->get_preview_material().is_null()) {
@@ -4157,6 +4175,7 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant
}
if (can_instantiate) {
_create_preview_node(files);
+ preview_node->hide();
}
}
} else {
@@ -4166,8 +4185,7 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant
}
if (can_instantiate) {
- Transform3D gl_transform = Transform3D(Basis(), _get_instance_position(p_point));
- preview_node->set_global_transform(gl_transform);
+ update_preview_node = true;
return true;
}
@@ -6932,6 +6950,10 @@ HashSet<RID> _get_physics_bodies_rid(Node *node) {
}
void Node3DEditor::snap_selected_nodes_to_floor() {
+ do_snap_selected_nodes_to_floor = true;
+}
+
+void Node3DEditor::_snap_selected_nodes_to_floor() {
const List<Node *> &selection = editor_selection->get_selected_node_list();
Dictionary snap_data;
@@ -7229,6 +7251,13 @@ void Node3DEditor::_notification(int p_what) {
tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_pressed(false);
}
} break;
+
+ case NOTIFICATION_PHYSICS_PROCESS: {
+ if (do_snap_selected_nodes_to_floor) {
+ _snap_selected_nodes_to_floor();
+ do_snap_selected_nodes_to_floor = false;
+ }
+ }
}
}
@@ -8349,10 +8378,12 @@ void Node3DEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
spatial_editor->show();
spatial_editor->set_process(true);
+ spatial_editor->set_physics_process(true);
} else {
spatial_editor->hide();
spatial_editor->set_process(false);
+ spatial_editor->set_physics_process(false);
}
}
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
index 60b2d0b5dd..7dbe153efd 100644
--- a/editor/plugins/node_3d_editor_plugin.h
+++ b/editor/plugins/node_3d_editor_plugin.h
@@ -193,6 +193,9 @@ private:
void _menu_option(int p_option);
void _set_auto_orthogonal();
Node3D *preview_node = nullptr;
+ bool update_preview_node = false;
+ Point2 preview_node_viewport_pos;
+ Vector3 preview_node_pos;
AABB *preview_bounds = nullptr;
Vector<String> selected_files;
AcceptDialog *accept = nullptr;
@@ -413,7 +416,7 @@ private:
bool _create_instance(Node *parent, String &path, const Point2 &p_point);
void _perform_drop_data();
- bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
+ bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
void _project_settings_changed();
@@ -720,6 +723,9 @@ private:
void _selection_changed();
void _refresh_menu_icons();
+ bool do_snap_selected_nodes_to_floor = false;
+ void _snap_selected_nodes_to_floor();
+
// Preview Sun and Environment
uint32_t world_env_count = 0;
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 58a0160010..8607f98a90 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -1978,18 +1978,6 @@ void ScriptTextEditor::_enable_code_editor() {
add_child(connection_info_dialog);
- edit_hb->add_child(search_menu);
- search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find"), SEARCH_FIND);
- search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_next"), SEARCH_FIND_NEXT);
- search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_previous"), SEARCH_FIND_PREV);
- search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace"), SEARCH_REPLACE);
- search_menu->get_popup()->add_separator();
- search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_in_files"), SEARCH_IN_FILES);
- search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace_in_files"), REPLACE_IN_FILES);
- search_menu->get_popup()->add_separator();
- search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/contextual_help"), HELP_CONTEXTUAL);
- search_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
-
edit_hb->add_child(edit_menu);
edit_menu->connect("about_to_popup", callable_mp(this, &ScriptTextEditor::_prepare_edit_menu));
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_undo"), EDIT_UNDO);
@@ -2000,38 +1988,73 @@ void ScriptTextEditor::_enable_code_editor() {
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_paste"), EDIT_PASTE);
edit_menu->get_popup()->add_separator();
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_text_select_all"), EDIT_SELECT_ALL);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/duplicate_selection"), EDIT_DUPLICATE_SELECTION);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/evaluate_selection"), EDIT_EVALUATE);
edit_menu->get_popup()->add_separator();
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/move_up"), EDIT_MOVE_LINE_UP);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/move_down"), EDIT_MOVE_LINE_DOWN);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent"), EDIT_INDENT);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unindent"), EDIT_UNINDENT);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/delete_line"), EDIT_DELETE_LINE);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_fold_line"), EDIT_TOGGLE_FOLD_LINE);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_all_lines"), EDIT_FOLD_ALL_LINES);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_all_lines"), EDIT_UNFOLD_ALL_LINES);
+ {
+ PopupMenu *sub_menu = memnew(PopupMenu);
+ sub_menu->set_name("line_menu");
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/move_up"), EDIT_MOVE_LINE_UP);
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/move_down"), EDIT_MOVE_LINE_DOWN);
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent"), EDIT_INDENT);
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unindent"), EDIT_UNINDENT);
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/delete_line"), EDIT_DELETE_LINE);
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT);
+ sub_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
+ edit_menu->get_popup()->add_child(sub_menu);
+ edit_menu->get_popup()->add_submenu_item(TTR("Line"), "line_menu");
+ }
+ {
+ PopupMenu *sub_menu = memnew(PopupMenu);
+ sub_menu->set_name("folding_menu");
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_fold_line"), EDIT_TOGGLE_FOLD_LINE);
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_all_lines"), EDIT_FOLD_ALL_LINES);
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_all_lines"), EDIT_UNFOLD_ALL_LINES);
+ sub_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
+ edit_menu->get_popup()->add_child(sub_menu);
+ edit_menu->get_popup()->add_submenu_item(TTR("Folding"), "folding_menu");
+ }
edit_menu->get_popup()->add_separator();
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/duplicate_selection"), EDIT_DUPLICATE_SELECTION);
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_text_completion_query"), EDIT_COMPLETE);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/evaluate_selection"), EDIT_EVALUATE);
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/trim_trailing_whitespace"), EDIT_TRIM_TRAILING_WHITESAPCE);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_spaces"), EDIT_CONVERT_INDENT_TO_SPACES);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_tabs"), EDIT_CONVERT_INDENT_TO_TABS);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/auto_indent"), EDIT_AUTO_INDENT);
+ {
+ PopupMenu *sub_menu = memnew(PopupMenu);
+ sub_menu->set_name("indent_menu");
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_spaces"), EDIT_CONVERT_INDENT_TO_SPACES);
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_tabs"), EDIT_CONVERT_INDENT_TO_TABS);
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/auto_indent"), EDIT_AUTO_INDENT);
+ sub_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
+ edit_menu->get_popup()->add_child(sub_menu);
+ edit_menu->get_popup()->add_submenu_item(TTR("Indentation"), "indent_menu");
+ }
edit_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
edit_menu->get_popup()->add_separator();
-
- edit_menu->get_popup()->add_child(convert_case);
- edit_menu->get_popup()->add_submenu_item(TTR("Convert Case"), "convert_case");
- convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_uppercase", TTR("Uppercase"), KeyModifierMask::SHIFT | Key::F4), EDIT_TO_UPPERCASE);
- convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_lowercase", TTR("Lowercase"), KeyModifierMask::SHIFT | Key::F5), EDIT_TO_LOWERCASE);
- convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/capitalize", TTR("Capitalize"), KeyModifierMask::SHIFT | Key::F6), EDIT_CAPITALIZE);
- convert_case->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
-
+ {
+ PopupMenu *sub_menu = memnew(PopupMenu);
+ sub_menu->set_name("convert_case");
+ sub_menu->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_uppercase", TTR("Uppercase"), KeyModifierMask::SHIFT | Key::F4), EDIT_TO_UPPERCASE);
+ sub_menu->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_lowercase", TTR("Lowercase"), KeyModifierMask::SHIFT | Key::F5), EDIT_TO_LOWERCASE);
+ sub_menu->add_shortcut(ED_SHORTCUT("script_text_editor/capitalize", TTR("Capitalize"), KeyModifierMask::SHIFT | Key::F6), EDIT_CAPITALIZE);
+ sub_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
+ edit_menu->get_popup()->add_child(sub_menu);
+ edit_menu->get_popup()->add_submenu_item(TTR("Convert Case"), "convert_case");
+ }
edit_menu->get_popup()->add_child(highlighter_menu);
edit_menu->get_popup()->add_submenu_item(TTR("Syntax Highlighter"), "highlighter_menu");
highlighter_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_change_syntax_highlighter));
+ edit_hb->add_child(search_menu);
+ search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find"), SEARCH_FIND);
+ search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_next"), SEARCH_FIND_NEXT);
+ search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_previous"), SEARCH_FIND_PREV);
+ search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace"), SEARCH_REPLACE);
+ search_menu->get_popup()->add_separator();
+ search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_in_files"), SEARCH_IN_FILES);
+ search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace_in_files"), REPLACE_IN_FILES);
+ search_menu->get_popup()->add_separator();
+ search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/contextual_help"), HELP_CONTEXTUAL);
+ search_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
+
_load_theme_settings();
edit_hb->add_child(goto_menu);
@@ -2106,9 +2129,6 @@ ScriptTextEditor::ScriptTextEditor() {
edit_menu->set_switch_on_hover(true);
edit_menu->set_shortcut_context(this);
- convert_case = memnew(PopupMenu);
- convert_case->set_name("convert_case");
-
highlighter_menu = memnew(PopupMenu);
highlighter_menu->set_name("highlighter_menu");
@@ -2153,7 +2173,6 @@ ScriptTextEditor::~ScriptTextEditor() {
memdelete(color_panel);
memdelete(edit_hb);
memdelete(edit_menu);
- memdelete(convert_case);
memdelete(highlighter_menu);
memdelete(search_menu);
memdelete(goto_menu);
diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h
index fb02e5c7c4..c165295a8e 100644
--- a/editor/plugins/script_text_editor.h
+++ b/editor/plugins/script_text_editor.h
@@ -79,7 +79,6 @@ class ScriptTextEditor : public ScriptEditorBase {
PopupMenu *breakpoints_menu = nullptr;
PopupMenu *highlighter_menu = nullptr;
PopupMenu *context_menu = nullptr;
- PopupMenu *convert_case = nullptr;
GotoLineDialog *goto_line_dialog = nullptr;
ScriptEditorQuickOpen *quick_open = nullptr;
diff --git a/editor/plugins/tiles/tiles_editor_plugin.cpp b/editor/plugins/tiles/tiles_editor_plugin.cpp
index 364c3b7246..6fdc9a80e8 100644
--- a/editor/plugins/tiles/tiles_editor_plugin.cpp
+++ b/editor/plugins/tiles/tiles_editor_plugin.cpp
@@ -66,7 +66,9 @@ void TilesEditorPlugin::_thread() {
pattern_preview_sem.wait();
pattern_preview_mutex.lock();
- if (pattern_preview_queue.size()) {
+ if (pattern_preview_queue.size() == 0) {
+ pattern_preview_mutex.unlock();
+ } else {
QueueItem item = pattern_preview_queue.front()->get();
pattern_preview_queue.pop_front();
pattern_preview_mutex.unlock();
@@ -130,8 +132,6 @@ void TilesEditorPlugin::_thread() {
item.callback.callp(args_ptr, 2, r, error);
viewport->queue_delete();
- } else {
- pattern_preview_mutex.unlock();
}
}
}
diff --git a/main/main.cpp b/main/main.cpp
index c990e01ee3..bb6ab11362 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -1808,6 +1808,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
"0,33200,1,or_greater")); // No negative numbers
GLOBAL_DEF("display/window/ios/hide_home_indicator", true);
+ GLOBAL_DEF("display/window/ios/hide_status_bar", true);
+ GLOBAL_DEF("display/window/ios/suppress_ui_gesture", true);
GLOBAL_DEF("input_devices/pointing/ios/touch_delay", 0.15);
ProjectSettings::get_singleton()->set_custom_property_info("input_devices/pointing/ios/touch_delay",
PropertyInfo(Variant::FLOAT,
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index bc44479f93..c8eda53a2d 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -18,13 +18,11 @@
<param index="2" name="b8" type="int" />
<param index="3" name="a8" type="int" default="255" />
<description>
- Returns a color constructed from integer red, green, blue, and alpha channels. Each channel should have 8 bits of information ranging from 0 to 255.
- [code]r8[/code] red channel
- [code]g8[/code] green channel
- [code]b8[/code] blue channel
- [code]a8[/code] alpha channel
+ Returns a [Color] constructed from red ([param r8]), green ([param g8]), blue ([param b8]), and optionally alpha ([param a8]) integer channels, each divided by [code]255.0[/code] for their final value.
[codeblock]
- red = Color8(255, 0, 0)
+ var red = Color8(255, 0, 0) # Same as Color(1, 0, 0)
+ var dark_blue = Color8(0, 0, 51) # Same as Color(0, 0, 0.2).
+ var my_color = Color8(306, 255, 0, 102) # Same as Color(1.2, 1, 0, 0.4).
[/codeblock]
</description>
</method>
@@ -33,9 +31,9 @@
<param index="0" name="condition" type="bool" />
<param index="1" name="message" type="String" default="&quot;&quot;" />
<description>
- Asserts that the [code]condition[/code] is [code]true[/code]. If the [code]condition[/code] is [code]false[/code], an error is generated. When running from the editor, the running project will also be paused until you resume it. This can be used as a stronger form of [method @GlobalScope.push_error] for reporting errors to project developers or add-on users.
- [b]Note:[/b] For performance reasons, the code inside [method assert] is only executed in debug builds or when running the project from the editor. Don't include code that has side effects in an [method assert] call. Otherwise, the project will behave differently when exported in release mode.
- The optional [code]message[/code] argument, if given, is shown in addition to the generic "Assertion failed" message. It must be a static string, so format strings can't be used. You can use this to provide additional details about why the assertion failed.
+ Asserts that the [param condition] is [code]true[/code]. If the [param condition] is [code]false[/code], an error is generated. When running from the editor, the running project will also be paused until you resume it. This can be used as a stronger form of [method @GlobalScope.push_error] for reporting errors to project developers or add-on users.
+ An optional [param message] can be shown in addition to the generic "Assertion failed" message. You can use this to provide additional details about why the assertion failed.
+ [b]Warning:[/b] For performance reasons, the code inside [method assert] is only executed in debug builds or when running the project from the editor. Don't include code that has side effects in an [method assert] call. Otherwise, the project will behave differently when exported in release mode.
[codeblock]
# Imagine we always want speed to be between 0 and 20.
var speed = -10
@@ -50,7 +48,7 @@
<return type="String" />
<param index="0" name="char" type="int" />
<description>
- Returns a character as a String of the given Unicode code point (which is compatible with ASCII code).
+ Returns a single character (as a [String]) of the given Unicode code point (which is compatible with ASCII code).
[codeblock]
a = char(65) # a is "A"
a = char(65 + 32) # a is "a"
@@ -63,14 +61,14 @@
<param index="0" name="what" type="Variant" />
<param index="1" name="type" type="int" />
<description>
- Converts from a type to another in the best way possible. The [code]type[/code] parameter uses the [enum Variant.Type] values.
+ Converts [param what] to [param type] in the best way possible. The [param type] uses the [enum Variant.Type] values.
[codeblock]
- a = Vector2(1, 0)
- # Prints 1
- print(a.length())
- a = convert(a, TYPE_STRING)
- # Prints 6 as "(1, 0)" is 6 characters
- print(a.length())
+ var a = [4, 2.5, 1.2]
+ print(a is Array) # Prints true
+
+ var b = convert(a, TYPE_PACKED_BYTE_ARRAY)
+ print(b) # Prints [4, 2, 1]
+ print(b is Array) # Prints false
[/codeblock]
</description>
</method>
@@ -78,7 +76,7 @@
<return type="Object" />
<param index="0" name="dictionary" type="Dictionary" />
<description>
- Converts a [param dictionary] (previously created with [method inst_to_dict]) back to an Object instance. Useful for deserializing.
+ Converts a [param dictionary] (created with [method inst_to_dict]) back to an Object instance. Can be useful for deserializing.
</description>
</method>
<method name="get_stack">
@@ -95,19 +93,19 @@
func bar():
print(get_stack())
[/codeblock]
- would print
+ Starting from [code]_ready()[/code], [code]bar()[/code] would print:
[codeblock]
[{function:bar, line:12, source:res://script.gd}, {function:foo, line:9, source:res://script.gd}, {function:_ready, line:6, source:res://script.gd}]
[/codeblock]
- [b]Note:[/b] [method get_stack] only works if the running instance is connected to a debugging server (i.e. an editor instance). [method get_stack] will not work in projects exported in release mode, or in projects exported in debug mode if not connected to a debugging server.
- [b]Note:[/b] Not supported for calling from threads. Instead, this will return an empty array.
+ [b]Note:[/b] This function only works if the running instance is connected to a debugging server (i.e. an editor instance). [method get_stack] will not work in projects exported in release mode, or in projects exported in debug mode if not connected to a debugging server.
+ [b]Note:[/b] Calling this function from a [Thread] is not supported. Doing so will return an empty array.
</description>
</method>
<method name="inst_to_dict">
<return type="Dictionary" />
<param index="0" name="instance" type="Object" />
<description>
- Returns the passed [param instance] converted to a Dictionary (useful for serializing).
+ Returns the passed [param instance] converted to a Dictionary. Can be useful for serializing.
[codeblock]
var foo = "bar"
func _ready():
@@ -126,11 +124,13 @@
<return type="int" />
<param index="0" name="var" type="Variant" />
<description>
- Returns length of Variant [code]var[/code]. Length is the character count of String, element count of Array, size of Dictionary, etc.
- [b]Note:[/b] Generates a fatal error if Variant can not provide a length.
+ Returns the length of the given Variant [param var]. The length can be the character count of a [String], the element count of any array type or the size of a [Dictionary]. For every other Variant type, a run-time error is generated and execution is stopped.
[codeblock]
a = [1, 2, 3, 4]
len(a) # Returns 4
+
+ b = "Hello!"
+ len(b) # Returns 6
[/codeblock]
</description>
</method>
@@ -138,25 +138,25 @@
<return type="Resource" />
<param index="0" name="path" type="String" />
<description>
- Loads a resource from the filesystem located at [code]path[/code]. The resource is loaded on the method call (unless it's referenced already elsewhere, e.g. in another script or in the scene), which might cause slight delay, especially when loading scenes. To avoid unnecessary delays when loading something multiple times, either store the resource in a variable or use [method preload].
+ Returns a [Resource] from the filesystem located at the absolute [param path]. Unless it's already referenced elsewhere (such as in another script or in the scene), the resource is loaded from disk on function call, which might cause a slight delay, especially when loading large scenes. To avoid unnecessary delays when loading something multiple times, either store the resource in a variable or use [method preload].
[b]Note:[/b] Resource paths can be obtained by right-clicking on a resource in the FileSystem dock and choosing "Copy Path" or by dragging the file from the FileSystem dock into the script.
[codeblock]
- # Load a scene called main located in the root of the project directory and cache it in a variable.
+ # Load a scene called "main" located in the root of the project directory and cache it in a variable.
var main = load("res://main.tscn") # main will contain a PackedScene resource.
[/codeblock]
- [b]Important:[/b] The path must be absolute, a local path will just return [code]null[/code].
- This method is a simplified version of [method ResourceLoader.load], which can be used for more advanced scenarios.
- [b]Note:[/b] You have to import the files into the engine first to load them using [method load]. If you want to load [Image]s at run-time, you may use [method Image.load]. If you want to import audio files, you can use the snippet described in [member AudioStreamMP3.data].
+ [b]Important:[/b] The path must be absolute. A relative path will always return [code]null[/code].
+ This function is a simplified version of [method ResourceLoader.load], which can be used for more advanced scenarios.
+ [b]Note:[/b] Files have to be imported into the engine first to load them using this function. If you want to load [Image]s at run-time, you may use [method Image.load]. If you want to import audio files, you can use the snippet described in [member AudioStreamMP3.data].
</description>
</method>
<method name="preload">
<return type="Resource" />
<param index="0" name="path" type="String" />
<description>
- Returns a [Resource] from the filesystem located at [code]path[/code]. The resource is loaded during script parsing, i.e. is loaded with the script and [method preload] effectively acts as a reference to that resource. Note that the method requires a constant path. If you want to load a resource from a dynamic/variable path, use [method load].
+ Returns a [Resource] from the filesystem located at [param path]. During run-time, the resource is loaded when the script is being parsed. This function effectively acts as a reference to that resource. Note that this function requires [param path] to be a constant [String]. If you want to load a resource from a dynamic/variable path, use [method load].
[b]Note:[/b] Resource paths can be obtained by right clicking on a resource in the Assets Panel and choosing "Copy Path" or by dragging the file from the FileSystem dock into the script.
[codeblock]
- # Instance a scene.
+ # Create instance of a scene.
var diamond = preload("res://diamond.tscn").instantiate()
[/codeblock]
</description>
@@ -165,24 +165,24 @@
<return type="void" />
<description>
Like [method @GlobalScope.print], but includes the current stack frame when running with the debugger turned on.
- Output in the console would look something like this:
+ The output in the console may look like the following:
[codeblock]
Test print
- At: res://test.gd:15:_process()
+ At: res://test.gd:15:_process()
[/codeblock]
- [b]Note:[/b] Not supported for calling from threads. Instead of the stack frame, this will print the thread ID.
+ [b]Note:[/b] Calling this function from a [Thread] is not supported. Doing so will instead print the thread ID.
</description>
</method>
<method name="print_stack">
<return type="void" />
<description>
Prints a stack trace at the current code location. See also [method get_stack].
- Output in the console would look something like this:
+ The output in the console may look like the following:
[codeblock]
Frame 0 - res://test.gd:16 in function '_process'
[/codeblock]
- [b]Note:[/b] [method print_stack] only works if the running instance is connected to a debugging server (i.e. an editor instance). [method print_stack] will not work in projects exported in release mode, or in projects exported in debug mode if not connected to a debugging server.
- [b]Note:[/b] Not supported for calling from threads. Instead of the stack trace, this will print the thread ID.
+ [b]Note:[/b] This function only works if the running instance is connected to a debugging server (i.e. an editor instance). [method print_stack] will not work in projects exported in release mode, or in projects exported in debug mode if not connected to a debugging server.
+ [b]Note:[/b] Calling this function from a [Thread] is not supported. Doing so will instead print the thread ID.
</description>
</method>
<method name="range" qualifiers="vararg">
@@ -229,7 +229,7 @@
<method name="str" qualifiers="vararg">
<return type="String" />
<description>
- Converts one or more arguments to string in the best way possible.
+ Converts one or more arguments to a [String] in the best way possible.
[codeblock]
var a = [10, 20, 30]
var b = str(a);
@@ -242,7 +242,7 @@
<return type="bool" />
<param index="0" name="type" type="StringName" />
<description>
- Returns whether the given [Object]-derived class exists in [ClassDB]. Note that [Variant] data types are not registered in [ClassDB].
+ Returns [code]true[/code] if the given [Object]-derived class exists in [ClassDB]. Note that [Variant] data types are not registered in [ClassDB].
[codeblock]
type_exists("Sprite2D") # Returns true
type_exists("NonExistentClass") # Returns false
@@ -259,11 +259,11 @@
</constant>
<constant name="INF" value="inf">
Positive floating-point infinity. This is the result of floating-point division when the divisor is [code]0.0[/code]. For negative infinity, use [code]-INF[/code]. Dividing by [code]-0.0[/code] will result in negative infinity if the numerator is positive, so dividing by [code]0.0[/code] is not the same as dividing by [code]-0.0[/code] (despite [code]0.0 == -0.0[/code] returning [code]true[/code]).
- [b]Note:[/b] Numeric infinity is only a concept with floating-point numbers, and has no equivalent for integers. Dividing an integer number by [code]0[/code] will not result in [constant INF] and will result in a run-time error instead.
+ [b]Warning:[/b] Numeric infinity is only a concept with floating-point numbers, and has no equivalent for integers. Dividing an integer number by [code]0[/code] will not result in [constant INF] and will result in a run-time error instead.
</constant>
<constant name="NAN" value="nan">
"Not a Number", an invalid floating-point value. [constant NAN] has special properties, including that it is not equal to itself ([code]NAN == NAN[/code] returns [code]false[/code]). It is output by some invalid operations, such as dividing floating-point [code]0.0[/code] by [code]0.0[/code].
- [b]Note:[/b] "Not a Number" is only a concept with floating-point numbers, and has no equivalent for integers. Dividing an integer [code]0[/code] by [code]0[/code] will not result in [constant NAN] and will result in a run-time error instead.
+ [b]Warning:[/b] "Not a Number" is only a concept with floating-point numbers, and has no equivalent for integers. Dividing an integer [code]0[/code] by [code]0[/code] will not result in [constant NAN] and will result in a run-time error instead.
</constant>
</constants>
<annotations>
@@ -294,7 +294,7 @@
<annotation name="@export_color_no_alpha">
<return type="void" />
<description>
- Export a [Color] property without an alpha (fixed as [code]1.0[/code]).
+ Export a [Color] property without transparency (its alpha fixed as [code]1.0[/code]).
See also [constant PROPERTY_HINT_COLOR_NO_ALPHA].
[codeblock]
@export_color_no_alpha var modulate_color: Color
@@ -320,7 +320,7 @@
[codeblock]
@export_enum("Rebecca", "Mary", "Leah") var character_name: String
@export_enum("Warrior", "Magician", "Thief") var character_class: int
- @export_enum("Walking:30", "Running:60", "Riding:200") var character_speed: int
+ @export_enum("Slow:30", "Average:60", "Very Fast:200") var character_speed: int
[/codeblock]
</description>
</annotation>
@@ -451,7 +451,7 @@
<description>
Define a new group for the following exported properties. This helps to organize properties in the Inspector dock. Groups can be added with an optional [param prefix], which would make group to only consider properties that have this prefix. The grouping will break on the first property that doesn't have a prefix. The prefix is also removed from the property's name in the Inspector dock.
If no [param prefix] is provided, the every following property is added to the group. The group ends when then next group or category is defined. You can also force end a group by using this annotation with empty strings for parameters, [code]@export_group("", "")[/code].
- Groups cannot be nested, use [annotation @export_subgroup] to add subgroups to your groups.
+ Groups cannot be nested, use [annotation @export_subgroup] to add subgroups within groups.
See also [constant PROPERTY_USAGE_GROUP].
[codeblock]
@export_group("My Properties")
@@ -473,7 +473,7 @@
Export a [String] property with a large [TextEdit] widget instead of a [LineEdit]. This adds support for multiline content and makes it easier to edit large amount of text stored in the property.
See also [constant PROPERTY_HINT_MULTILINE_TEXT].
[codeblock]
- @export_multiline var character_bio
+ @export_multiline var character_biography
[/codeblock]
</description>
</annotation>
@@ -547,11 +547,11 @@
<return type="void" />
<param index="0" name="icon_path" type="String" />
<description>
- Add a custom icon to the current script. The icon is displayed in the Scene dock for every node that the script is attached to. For named classes the icon is also displayed in various editor dialogs.
+ Add a custom icon to the current script. After loading an icon at [param icon_path], the icon is displayed in the Scene dock for every node that the script is attached to. For named classes, the icon is also displayed in various editor dialogs.
[codeblock]
@icon("res://path/to/class/icon.svg")
[/codeblock]
- [b]Note:[/b] Only the script can have a custom icon. Inner classes are not supported yet.
+ [b]Note:[/b] Only the script can have a custom icon. Inner classes are not supported.
</description>
</annotation>
<annotation name="@onready">
@@ -590,7 +590,7 @@
<return type="void" />
<param index="0" name="warning" type="String" />
<description>
- Mark the following statement to ignore the specified warning. See [url=$DOCS_URL/tutorials/scripting/gdscript/warning_system.html]GDScript warning system[/url].
+ Mark the following statement to ignore the specified [param warning]. See [url=$DOCS_URL/tutorials/scripting/gdscript/warning_system.html]GDScript warning system[/url].
[codeblock]
func test():
print("hello")
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 6fbdec863f..898e4eb1a6 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -3226,7 +3226,13 @@ void GDScriptAnalyzer::reduce_preload(GDScriptParser::PreloadNode *p_preload) {
}
p_preload->resolved_path = p_preload->resolved_path.simplify_path();
if (!ResourceLoader::exists(p_preload->resolved_path)) {
- push_error(vformat(R"(Preload file "%s" does not exist.)", p_preload->resolved_path), p_preload->path);
+ Ref<FileAccess> file_check = FileAccess::create(FileAccess::ACCESS_RESOURCES);
+
+ if (file_check->file_exists(p_preload->resolved_path)) {
+ push_error(vformat(R"(Preload file "%s" has no resource loaders (unrecognized file extension).)", p_preload->resolved_path), p_preload->path);
+ } else {
+ push_error(vformat(R"(Preload file "%s" does not exist.)", p_preload->resolved_path), p_preload->path);
+ }
} else {
// TODO: Don't load if validating: use completion cache.
p_preload->resource = ResourceLoader::load(p_preload->resolved_path);
diff --git a/modules/gltf/doc_classes/GLTFNode.xml b/modules/gltf/doc_classes/GLTFNode.xml
index 4d1aa89ac9..8e48066623 100644
--- a/modules/gltf/doc_classes/GLTFNode.xml
+++ b/modules/gltf/doc_classes/GLTFNode.xml
@@ -9,6 +9,25 @@
<tutorials>
<link title="GLTF scene and node spec">https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_004_ScenesNodes.md"</link>
</tutorials>
+ <methods>
+ <method name="get_additional_data">
+ <return type="Variant" />
+ <param index="0" name="extension_name" type="StringName" />
+ <description>
+ Gets additional arbitrary data in this [GLTFNode] instance. This can be used to keep per-node state data in [GLTFDocumentExtension] classes, which is important because they are stateless.
+ The argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the GLTF file), and the return value can be anything you set. If nothing was set, the return value is null.
+ </description>
+ </method>
+ <method name="set_additional_data">
+ <return type="void" />
+ <param index="0" name="extension_name" type="StringName" />
+ <param index="1" name="additional_data" type="Variant" />
+ <description>
+ Sets additional arbitrary data in this [GLTFNode] instance. This can be used to keep per-node state data in [GLTFDocumentExtension] classes, which is important because they are stateless.
+ The first argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the GLTF file), and the second argument can be anything you want.
+ </description>
+ </method>
+ </methods>
<members>
<member name="camera" type="int" setter="set_camera" getter="get_camera" default="-1">
</member>
diff --git a/modules/gltf/doc_classes/GLTFState.xml b/modules/gltf/doc_classes/GLTFState.xml
index 56f3a70631..d0740cf7ca 100644
--- a/modules/gltf/doc_classes/GLTFState.xml
+++ b/modules/gltf/doc_classes/GLTFState.xml
@@ -20,6 +20,14 @@
<description>
</description>
</method>
+ <method name="get_additional_data">
+ <return type="Variant" />
+ <param index="0" name="extension_name" type="StringName" />
+ <description>
+ Gets additional arbitrary data in this [GLTFState] instance. This can be used to keep per-file state data in [GLTFDocumentExtension] classes, which is important because they are stateless.
+ The argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the GLTF file), and the return value can be anything you set. If nothing was set, the return value is null.
+ </description>
+ </method>
<method name="get_animation_player">
<return type="AnimationPlayer" />
<param index="0" name="idx" type="int" />
@@ -120,6 +128,15 @@
<description>
</description>
</method>
+ <method name="set_additional_data">
+ <return type="void" />
+ <param index="0" name="extension_name" type="StringName" />
+ <param index="1" name="additional_data" type="Variant" />
+ <description>
+ Sets additional arbitrary data in this [GLTFState] instance. This can be used to keep per-file state data in [GLTFDocumentExtension] classes, which is important because they are stateless.
+ The first argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the GLTF file), and the second argument can be anything you want.
+ </description>
+ </method>
<method name="set_animations">
<return type="void" />
<param index="0" name="animations" type="GLTFAnimation[]" />
diff --git a/modules/gltf/gltf_state.cpp b/modules/gltf/gltf_state.cpp
index 60192c67e6..ac5665e396 100644
--- a/modules/gltf/gltf_state.cpp
+++ b/modules/gltf/gltf_state.cpp
@@ -87,6 +87,8 @@ void GLTFState::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_animations"), &GLTFState::get_animations);
ClassDB::bind_method(D_METHOD("set_animations", "animations"), &GLTFState::set_animations);
ClassDB::bind_method(D_METHOD("get_scene_node", "idx"), &GLTFState::get_scene_node);
+ ClassDB::bind_method(D_METHOD("get_additional_data", "extension_name"), &GLTFState::get_additional_data);
+ ClassDB::bind_method(D_METHOD("set_additional_data", "extension_name", "additional_data"), &GLTFState::set_additional_data);
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "json"), "set_json", "get_json"); // Dictionary
ADD_PROPERTY(PropertyInfo(Variant::INT, "major_version"), "set_major_version", "get_major_version"); // int
@@ -358,3 +360,11 @@ String GLTFState::get_base_path() {
void GLTFState::set_base_path(String p_base_path) {
base_path = p_base_path;
}
+
+Variant GLTFState::get_additional_data(const StringName &p_extension_name) {
+ return additional_data[p_extension_name];
+}
+
+void GLTFState::set_additional_data(const StringName &p_extension_name, Variant p_additional_data) {
+ additional_data[p_extension_name] = p_additional_data;
+}
diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h
index afe7e82010..e24017b0fd 100644
--- a/modules/gltf/gltf_state.h
+++ b/modules/gltf/gltf_state.h
@@ -97,6 +97,7 @@ class GLTFState : public Resource {
HashMap<ObjectID, GLTFSkeletonIndex> skeleton3d_to_gltf_skeleton;
HashMap<ObjectID, HashMap<ObjectID, GLTFSkinIndex>> skin_and_skeleton3d_to_gltf_skin;
+ Dictionary additional_data;
protected:
static void _bind_methods();
@@ -191,6 +192,9 @@ public:
AnimationPlayer *get_animation_player(int idx);
+ Variant get_additional_data(const StringName &p_extension_name);
+ void set_additional_data(const StringName &p_extension_name, Variant p_additional_data);
+
//void set_scene_nodes(RBMap<GLTFNodeIndex, Node *> p_scene_nodes) {
// this->scene_nodes = p_scene_nodes;
//}
diff --git a/modules/gltf/structures/gltf_node.cpp b/modules/gltf/structures/gltf_node.cpp
index 86280603fa..6fd36f93b7 100644
--- a/modules/gltf/structures/gltf_node.cpp
+++ b/modules/gltf/structures/gltf_node.cpp
@@ -57,6 +57,8 @@ void GLTFNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_children", "children"), &GLTFNode::set_children);
ClassDB::bind_method(D_METHOD("get_light"), &GLTFNode::get_light);
ClassDB::bind_method(D_METHOD("set_light", "light"), &GLTFNode::set_light);
+ ClassDB::bind_method(D_METHOD("get_additional_data", "extension_name"), &GLTFNode::get_additional_data);
+ ClassDB::bind_method(D_METHOD("set_additional_data", "extension_name", "additional_data"), &GLTFNode::set_additional_data);
ADD_PROPERTY(PropertyInfo(Variant::INT, "parent"), "set_parent", "get_parent"); // GLTFNodeIndex
ADD_PROPERTY(PropertyInfo(Variant::INT, "height"), "set_height", "get_height"); // int
@@ -176,3 +178,11 @@ GLTFLightIndex GLTFNode::get_light() {
void GLTFNode::set_light(GLTFLightIndex p_light) {
light = p_light;
}
+
+Variant GLTFNode::get_additional_data(const StringName &p_extension_name) {
+ return additional_data[p_extension_name];
+}
+
+void GLTFNode::set_additional_data(const StringName &p_extension_name, Variant p_additional_data) {
+ additional_data[p_extension_name] = p_additional_data;
+}
diff --git a/modules/gltf/structures/gltf_node.h b/modules/gltf/structures/gltf_node.h
index 1a57ea32e2..90a4fa99ed 100644
--- a/modules/gltf/structures/gltf_node.h
+++ b/modules/gltf/structures/gltf_node.h
@@ -53,6 +53,7 @@ private:
Vector3 scale = Vector3(1, 1, 1);
Vector<int> children;
GLTFLightIndex light = -1;
+ Dictionary additional_data;
protected:
static void _bind_methods();
@@ -96,6 +97,9 @@ public:
GLTFLightIndex get_light();
void set_light(GLTFLightIndex p_light);
+
+ Variant get_additional_data(const StringName &p_extension_name);
+ void set_additional_data(const StringName &p_extension_name, Variant p_additional_data);
};
#endif // GLTF_NODE_H
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index d29e0d69ab..3be8dd87c0 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -3119,9 +3119,10 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
for (const KeyValue<StringName, ClassDB::ClassInfo::EnumInfo> &E : enum_map) {
StringName enum_proxy_cname = E.key;
String enum_proxy_name = enum_proxy_cname.operator String();
- if (itype.find_property_by_proxy_name(enum_proxy_cname)) {
- // We have several conflicts between enums and PascalCase properties,
- // so we append 'Enum' to the enum name in those cases.
+ if (itype.find_property_by_proxy_name(enum_proxy_name) || itype.find_method_by_proxy_name(enum_proxy_name) || itype.find_signal_by_proxy_name(enum_proxy_name)) {
+ // In case the enum name conflicts with other PascalCase members,
+ // we append 'Enum' to the enum name in those cases.
+ // We have several conflicts between enums and PascalCase properties.
enum_proxy_name += "Enum";
enum_proxy_cname = StringName(enum_proxy_name);
}
@@ -3170,7 +3171,15 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
int64_t *value = class_info->constant_map.getptr(StringName(constant_name));
ERR_FAIL_NULL_V(value, false);
- ConstantInterface iconstant(constant_name, snake_to_pascal_case(constant_name, true), *value);
+ String constant_proxy_name = snake_to_pascal_case(constant_name, true);
+
+ if (itype.find_property_by_proxy_name(constant_proxy_name) || itype.find_method_by_proxy_name(constant_proxy_name) || itype.find_signal_by_proxy_name(constant_proxy_name)) {
+ // In case the constant name conflicts with other PascalCase members,
+ // we append 'Constant' to the constant name in those cases.
+ constant_proxy_name += "Constant";
+ }
+
+ ConstantInterface iconstant(constant_name, constant_proxy_name, *value);
iconstant.const_doc = nullptr;
for (int i = 0; i < itype.class_doc->constants.size(); i++) {
diff --git a/modules/multiplayer/scene_replication_interface.cpp b/modules/multiplayer/scene_replication_interface.cpp
index df9985916b..8359580805 100644
--- a/modules/multiplayer/scene_replication_interface.cpp
+++ b/modules/multiplayer/scene_replication_interface.cpp
@@ -261,11 +261,11 @@ Error SceneReplicationInterface::_update_sync_visibility(int p_peer, Multiplayer
if (p_peer == 0) {
for (KeyValue<int, PeerInfo> &E : peers_info) {
// Might be visible to this specific peer.
- is_visible = is_visible || p_sync->is_visible_to(E.key);
- if (is_visible == E.value.sync_nodes.has(sid)) {
+ bool is_visible_to_peer = is_visible || p_sync->is_visible_to(E.key);
+ if (is_visible_to_peer == E.value.sync_nodes.has(sid)) {
continue;
}
- if (is_visible) {
+ if (is_visible_to_peer) {
E.value.sync_nodes.insert(sid);
} else {
E.value.sync_nodes.erase(sid);
diff --git a/modules/openxr/SCsub b/modules/openxr/SCsub
index 5ac167ad98..b5978ab134 100644
--- a/modules/openxr/SCsub
+++ b/modules/openxr/SCsub
@@ -96,6 +96,7 @@ env_openxr.add_source_files(module_obj, "extensions/openxr_composition_layer_dep
env_openxr.add_source_files(module_obj, "extensions/openxr_htc_vive_tracker_extension.cpp")
env_openxr.add_source_files(module_obj, "extensions/openxr_hand_tracking_extension.cpp")
env_openxr.add_source_files(module_obj, "extensions/openxr_fb_passthrough_extension_wrapper.cpp")
+env_openxr.add_source_files(module_obj, "extensions/openxr_fb_display_refresh_rate_extension.cpp")
env.modules_sources += module_obj
diff --git a/modules/openxr/doc_classes/OpenXRInterface.xml b/modules/openxr/doc_classes/OpenXRInterface.xml
index 25bf496de9..f089fd066e 100644
--- a/modules/openxr/doc_classes/OpenXRInterface.xml
+++ b/modules/openxr/doc_classes/OpenXRInterface.xml
@@ -10,6 +10,19 @@
<tutorials>
<link title="Setting up XR">$DOCS_URL/tutorials/xr/setting_up_xr.html</link>
</tutorials>
+ <methods>
+ <method name="get_available_display_refresh_rates" qualifiers="const">
+ <return type="Array" />
+ <description>
+ Returns display refresh rates supported by the current HMD. Only returned if this feature is supported by the OpenXR runtime and after the interface has been initialized.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="display_refresh_rate" type="float" setter="set_display_refresh_rate" getter="get_display_refresh_rate" default="0.0">
+ The display refresh rate for the current HMD. Only functional if this feature is supported by the OpenXR runtime and after the interface has been initialized.
+ </member>
+ </members>
<signals>
<signal name="pose_recentered">
<description>
diff --git a/modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.cpp b/modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.cpp
new file mode 100644
index 0000000000..c0bbaea5b4
--- /dev/null
+++ b/modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.cpp
@@ -0,0 +1,123 @@
+/*************************************************************************/
+/* openxr_fb_display_refresh_rate_extension.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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. */
+/*************************************************************************/
+
+#include "openxr_fb_display_refresh_rate_extension.h"
+
+OpenXRDisplayRefreshRateExtension *OpenXRDisplayRefreshRateExtension::singleton = nullptr;
+
+OpenXRDisplayRefreshRateExtension *OpenXRDisplayRefreshRateExtension::get_singleton() {
+ return singleton;
+}
+
+OpenXRDisplayRefreshRateExtension::OpenXRDisplayRefreshRateExtension(OpenXRAPI *p_openxr_api) :
+ OpenXRExtensionWrapper(p_openxr_api) {
+ singleton = this;
+
+ // Extensions we use for our hand tracking.
+ request_extensions[XR_FB_DISPLAY_REFRESH_RATE_EXTENSION_NAME] = &display_refresh_rate_ext;
+}
+
+OpenXRDisplayRefreshRateExtension::~OpenXRDisplayRefreshRateExtension() {
+ display_refresh_rate_ext = false;
+}
+
+void OpenXRDisplayRefreshRateExtension::on_instance_created(const XrInstance p_instance) {
+ if (display_refresh_rate_ext) {
+ EXT_INIT_XR_FUNC(xrEnumerateDisplayRefreshRatesFB);
+ EXT_INIT_XR_FUNC(xrGetDisplayRefreshRateFB);
+ EXT_INIT_XR_FUNC(xrRequestDisplayRefreshRateFB);
+ }
+}
+
+void OpenXRDisplayRefreshRateExtension::on_instance_destroyed() {
+ display_refresh_rate_ext = false;
+}
+
+float OpenXRDisplayRefreshRateExtension::get_refresh_rate() const {
+ float refresh_rate = 0.0;
+
+ if (display_refresh_rate_ext) {
+ float rate;
+ XrResult result = xrGetDisplayRefreshRateFB(openxr_api->get_session(), &rate);
+ if (XR_FAILED(result)) {
+ print_line("OpenXR: Failed to obtain refresh rate [", openxr_api->get_error_string(result), "]");
+ } else {
+ refresh_rate = rate;
+ }
+ }
+
+ return refresh_rate;
+}
+
+void OpenXRDisplayRefreshRateExtension::set_refresh_rate(float p_refresh_rate) {
+ if (display_refresh_rate_ext) {
+ XrResult result = xrRequestDisplayRefreshRateFB(openxr_api->get_session(), p_refresh_rate);
+ if (XR_FAILED(result)) {
+ print_line("OpenXR: Failed to set refresh rate [", openxr_api->get_error_string(result), "]");
+ }
+ }
+}
+
+Array OpenXRDisplayRefreshRateExtension::get_available_refresh_rates() const {
+ Array arr;
+ XrResult result;
+
+ if (display_refresh_rate_ext) {
+ uint32_t display_refresh_rate_count = 0;
+ result = xrEnumerateDisplayRefreshRatesFB(openxr_api->get_session(), 0, &display_refresh_rate_count, nullptr);
+ if (XR_FAILED(result)) {
+ print_line("OpenXR: Failed to obtain refresh rates count [", openxr_api->get_error_string(result), "]");
+ }
+
+ if (display_refresh_rate_count > 0) {
+ float *display_refresh_rates = (float *)memalloc(sizeof(float) * display_refresh_rate_count);
+ if (display_refresh_rates == nullptr) {
+ print_line("OpenXR: Failed to obtain refresh rates memory buffer [", openxr_api->get_error_string(result), "]");
+ return arr;
+ }
+
+ result = xrEnumerateDisplayRefreshRatesFB(openxr_api->get_session(), display_refresh_rate_count, &display_refresh_rate_count, display_refresh_rates);
+ if (XR_FAILED(result)) {
+ print_line("OpenXR: Failed to obtain refresh rates count [", openxr_api->get_error_string(result), "]");
+ memfree(display_refresh_rates);
+ return arr;
+ }
+
+ for (uint32_t i = 0; i < display_refresh_rate_count; i++) {
+ float refresh_rate = display_refresh_rates[i];
+ arr.push_back(Variant(refresh_rate));
+ }
+
+ memfree(display_refresh_rates);
+ }
+ }
+
+ return arr;
+}
diff --git a/modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.h b/modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.h
new file mode 100644
index 0000000000..dcd52fe4d1
--- /dev/null
+++ b/modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.h
@@ -0,0 +1,70 @@
+/*************************************************************************/
+/* openxr_fb_display_refresh_rate_extension.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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 OPENXR_FB_DISPLAY_REFRESH_RATE_EXTENSION_H
+#define OPENXR_FB_DISPLAY_REFRESH_RATE_EXTENSION_H
+
+// This extension gives us access to the possible display refresh rates
+// supported by the HMD.
+// While this is an FB extension it has been adopted by most runtimes and
+// will likely become core in the near future.
+
+#include "../openxr_api.h"
+#include "../util.h"
+
+#include "openxr_extension_wrapper.h"
+
+class OpenXRDisplayRefreshRateExtension : public OpenXRExtensionWrapper {
+public:
+ static OpenXRDisplayRefreshRateExtension *get_singleton();
+
+ OpenXRDisplayRefreshRateExtension(OpenXRAPI *p_openxr_api);
+ virtual ~OpenXRDisplayRefreshRateExtension() override;
+
+ virtual void on_instance_created(const XrInstance p_instance) override;
+ virtual void on_instance_destroyed() override;
+
+ float get_refresh_rate() const;
+ void set_refresh_rate(float p_refresh_rate);
+
+ Array get_available_refresh_rates() const;
+
+private:
+ static OpenXRDisplayRefreshRateExtension *singleton;
+
+ bool display_refresh_rate_ext = false;
+
+ // OpenXR API call wrappers
+ EXT_PROTO_XRRESULT_FUNC4(xrEnumerateDisplayRefreshRatesFB, (XrSession), session, (uint32_t), displayRefreshRateCapacityInput, (uint32_t *), displayRefreshRateCountOutput, (float *), displayRefreshRates);
+ EXT_PROTO_XRRESULT_FUNC2(xrGetDisplayRefreshRateFB, (XrSession), session, (float *), display_refresh_rate);
+ EXT_PROTO_XRRESULT_FUNC2(xrRequestDisplayRefreshRateFB, (XrSession), session, (float), display_refresh_rate);
+};
+
+#endif // OPENXR_FB_DISPLAY_REFRESH_RATE_EXTENSION_H
diff --git a/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp b/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp
index 88cc7c061c..4d996e6283 100644
--- a/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp
+++ b/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp
@@ -69,6 +69,34 @@ bool OpenXRHTCViveTrackerExtension::on_event_polled(const XrEventDataBuffer &eve
bool OpenXRHTCViveTrackerExtension::is_path_supported(const String &p_path) {
if (p_path == "/interaction_profiles/htc/vive_tracker_htcx") {
return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/handheld_object") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/left_foot") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/right_foot") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/left_shoulder") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/right_shoulder") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/left_elbow") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/right_elbow") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/left_knee") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/right_knee") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/waist") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/chest") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/chest") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/camera") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/keyboard") {
+ return available;
}
// Not a path under this extensions control, so we return true;
diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp
index 8a67462613..1ff1dac512 100644
--- a/modules/openxr/openxr_api.cpp
+++ b/modules/openxr/openxr_api.cpp
@@ -50,6 +50,7 @@
#endif
#include "extensions/openxr_composition_layer_depth_extension.h"
+#include "extensions/openxr_fb_display_refresh_rate_extension.h"
#include "extensions/openxr_fb_passthrough_extension_wrapper.h"
#include "extensions/openxr_hand_tracking_extension.h"
#include "extensions/openxr_htc_vive_tracker_extension.h"
@@ -443,12 +444,12 @@ bool OpenXRAPI::load_supported_view_configuration_views(XrViewConfigurationType
for (uint32_t i = 0; i < view_count; i++) {
print_verbose("OpenXR: Found supported view configuration view");
- print_verbose(String(" - width: ") + view_configuration_views[i].maxImageRectWidth);
- print_verbose(String(" - height: ") + view_configuration_views[i].maxImageRectHeight);
- print_verbose(String(" - sample count: ") + view_configuration_views[i].maxSwapchainSampleCount);
- print_verbose(String(" - recommended render width: ") + view_configuration_views[i].recommendedImageRectWidth);
- print_verbose(String(" - recommended render height: ") + view_configuration_views[i].recommendedImageRectHeight);
- print_verbose(String(" - recommended render sample count: ") + view_configuration_views[i].recommendedSwapchainSampleCount);
+ print_verbose(String(" - width: ") + itos(view_configuration_views[i].maxImageRectWidth));
+ print_verbose(String(" - height: ") + itos(view_configuration_views[i].maxImageRectHeight));
+ print_verbose(String(" - sample count: ") + itos(view_configuration_views[i].maxSwapchainSampleCount));
+ print_verbose(String(" - recommended render width: ") + itos(view_configuration_views[i].recommendedImageRectWidth));
+ print_verbose(String(" - recommended render height: ") + itos(view_configuration_views[i].recommendedImageRectHeight));
+ print_verbose(String(" - recommended render sample count: ") + itos(view_configuration_views[i].recommendedSwapchainSampleCount));
}
return true;
@@ -1748,6 +1749,31 @@ void OpenXRAPI::end_frame() {
}
}
+float OpenXRAPI::get_display_refresh_rate() const {
+ OpenXRDisplayRefreshRateExtension *drrext = OpenXRDisplayRefreshRateExtension::get_singleton();
+ if (drrext) {
+ return drrext->get_refresh_rate();
+ }
+
+ return 0.0;
+}
+
+void OpenXRAPI::set_display_refresh_rate(float p_refresh_rate) {
+ OpenXRDisplayRefreshRateExtension *drrext = OpenXRDisplayRefreshRateExtension::get_singleton();
+ if (drrext != nullptr) {
+ drrext->set_refresh_rate(p_refresh_rate);
+ }
+}
+
+Array OpenXRAPI::get_available_display_refresh_rates() const {
+ OpenXRDisplayRefreshRateExtension *drrext = OpenXRDisplayRefreshRateExtension::get_singleton();
+ if (drrext != nullptr) {
+ return drrext->get_available_refresh_rates();
+ }
+
+ return Array();
+}
+
OpenXRAPI::OpenXRAPI() {
// OpenXRAPI is only constructed if OpenXR is enabled.
singleton = this;
@@ -1817,6 +1843,7 @@ OpenXRAPI::OpenXRAPI() {
register_extension_wrapper(memnew(OpenXRHTCViveTrackerExtension(this)));
register_extension_wrapper(memnew(OpenXRHandTrackingExtension(this)));
register_extension_wrapper(memnew(OpenXRFbPassthroughExtensionWrapper(this)));
+ register_extension_wrapper(memnew(OpenXRDisplayRefreshRateExtension(this)));
}
OpenXRAPI::~OpenXRAPI() {
diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h
index bd69432dcb..5dce749351 100644
--- a/modules/openxr/openxr_api.h
+++ b/modules/openxr/openxr_api.h
@@ -84,8 +84,6 @@ private:
bool ext_vive_focus3_available = false;
bool ext_huawei_controller_available = false;
- bool is_path_supported(const String &p_path);
-
// composition layer providers
Vector<OpenXRCompositionLayerProvider *> composition_layer_providers;
@@ -302,6 +300,7 @@ public:
void parse_velocities(const XrSpaceVelocity &p_velocity, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity);
bool xr_result(XrResult result, const char *format, Array args = Array()) const;
+ bool is_path_supported(const String &p_path);
static bool openxr_is_enabled(bool p_check_run_in_editor = true);
static OpenXRAPI *get_singleton();
@@ -336,6 +335,11 @@ public:
void post_draw_viewport(RID p_render_target);
void end_frame();
+ // Display refresh rate
+ float get_display_refresh_rate() const;
+ void set_display_refresh_rate(float p_refresh_rate);
+ Array get_available_display_refresh_rates() const;
+
// action map
String get_default_action_map_resource_name();
diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp
index 68414ae84e..bdf437b0b7 100644
--- a/modules/openxr/openxr_interface.cpp
+++ b/modules/openxr/openxr_interface.cpp
@@ -41,6 +41,13 @@ void OpenXRInterface::_bind_methods() {
ADD_SIGNAL(MethodInfo("session_focussed"));
ADD_SIGNAL(MethodInfo("session_visible"));
ADD_SIGNAL(MethodInfo("pose_recentered"));
+
+ // Display refresh rate
+ ClassDB::bind_method(D_METHOD("get_display_refresh_rate"), &OpenXRInterface::get_display_refresh_rate);
+ ClassDB::bind_method(D_METHOD("set_display_refresh_rate", "refresh_rate"), &OpenXRInterface::set_display_refresh_rate);
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "display_refresh_rate"), "set_display_refresh_rate", "get_display_refresh_rate");
+
+ ClassDB::bind_method(D_METHOD("get_available_display_refresh_rates"), &OpenXRInterface::get_available_display_refresh_rates);
}
StringName OpenXRInterface::get_name() const {
@@ -147,24 +154,25 @@ void OpenXRInterface::_load_action_map() {
Ref<OpenXRAction> xr_action = actions[j];
PackedStringArray toplevel_paths = xr_action->get_toplevel_paths();
- Vector<Tracker *> trackers_new;
+ Vector<Tracker *> trackers_for_action;
for (int k = 0; k < toplevel_paths.size(); k++) {
- Tracker *tracker = find_tracker(toplevel_paths[k], true);
- if (tracker) {
- trackers_new.push_back(tracker);
+ // Only check for our tracker if our path is supported.
+ if (openxr_api->is_path_supported(toplevel_paths[k])) {
+ Tracker *tracker = find_tracker(toplevel_paths[k], true);
+ if (tracker) {
+ trackers_for_action.push_back(tracker);
+ }
}
}
- Action *action = create_action(action_set, xr_action->get_name(), xr_action->get_localized_name(), xr_action->get_action_type(), trackers);
- if (action) {
- // we link our actions back to our trackers so we know which actions to check when we're processing our trackers
- for (int t = 0; t < trackers_new.size(); t++) {
- link_action_to_tracker(trackers_new[t], action);
+ // Only add our action if we have atleast one valid toplevel path
+ if (trackers_for_action.size() > 0) {
+ Action *action = create_action(action_set, xr_action->get_name(), xr_action->get_localized_name(), xr_action->get_action_type(), trackers_for_action);
+ if (action) {
+ // add this to our map for creating our interaction profiles
+ xr_actions[xr_action] = action;
}
-
- // add this to our map for creating our interaction profiles
- xr_actions[xr_action] = action;
}
}
}
@@ -282,6 +290,13 @@ OpenXRInterface::Action *OpenXRInterface::create_action(ActionSet *p_action_set,
action->action_rid = openxr_api->action_create(p_action_set->action_set_rid, p_action_name, p_localized_name, p_action_type, tracker_rids);
p_action_set->actions.push_back(action);
+ // we link our actions back to our trackers so we know which actions to check when we're processing our trackers
+ for (int i = 0; i < p_trackers.size(); i++) {
+ if (p_trackers[i]->actions.find(action) == -1) {
+ p_trackers[i]->actions.push_back(action);
+ }
+ }
+
return action;
}
@@ -330,6 +345,8 @@ OpenXRInterface::Tracker *OpenXRInterface::find_tracker(const String &p_tracker_
return nullptr;
}
+ ERR_FAIL_COND_V(!openxr_api->is_path_supported(p_tracker_name), nullptr);
+
// Create our RID
RID tracker_rid = openxr_api->tracker_create(p_tracker_name);
ERR_FAIL_COND_V(tracker_rid.is_null(), nullptr);
@@ -389,12 +406,6 @@ void OpenXRInterface::tracker_profile_changed(RID p_tracker, RID p_interaction_p
}
}
-void OpenXRInterface::link_action_to_tracker(Tracker *p_tracker, Action *p_action) {
- if (p_tracker->actions.find(p_action) == -1) {
- p_tracker->actions.push_back(p_action);
- }
-}
-
void OpenXRInterface::handle_tracker(Tracker *p_tracker) {
ERR_FAIL_NULL(openxr_api);
ERR_FAIL_COND(p_tracker->positional_tracker.is_null());
@@ -447,9 +458,18 @@ void OpenXRInterface::handle_tracker(Tracker *p_tracker) {
void OpenXRInterface::trigger_haptic_pulse(const String &p_action_name, const StringName &p_tracker_name, double p_frequency, double p_amplitude, double p_duration_sec, double p_delay_sec) {
ERR_FAIL_NULL(openxr_api);
+
Action *action = find_action(p_action_name);
ERR_FAIL_NULL(action);
- Tracker *tracker = find_tracker(p_tracker_name);
+
+ // We need to map our tracker name to our OpenXR name for our inbuild names.
+ String tracker_name = p_tracker_name;
+ if (tracker_name == "left_hand") {
+ tracker_name = "/user/hand/left";
+ } else if (tracker_name == "right_hand") {
+ tracker_name = "/user/hand/right";
+ }
+ Tracker *tracker = find_tracker(tracker_name);
ERR_FAIL_NULL(tracker);
// TODO OpenXR does not support delay, so we may need to add support for that somehow...
@@ -571,6 +591,36 @@ bool OpenXRInterface::set_play_area_mode(XRInterface::PlayAreaMode p_mode) {
return false;
}
+float OpenXRInterface::get_display_refresh_rate() const {
+ if (openxr_api == nullptr) {
+ return 0.0;
+ } else if (!openxr_api->is_initialized()) {
+ return 0.0;
+ } else {
+ return openxr_api->get_display_refresh_rate();
+ }
+}
+
+void OpenXRInterface::set_display_refresh_rate(float p_refresh_rate) {
+ if (openxr_api == nullptr) {
+ return;
+ } else if (!openxr_api->is_initialized()) {
+ return;
+ } else {
+ openxr_api->set_display_refresh_rate(p_refresh_rate);
+ }
+}
+
+Array OpenXRInterface::get_available_display_refresh_rates() const {
+ if (openxr_api == nullptr) {
+ return Array();
+ } else if (!openxr_api->is_initialized()) {
+ return Array();
+ } else {
+ return openxr_api->get_available_display_refresh_rates();
+ }
+}
+
Size2 OpenXRInterface::get_render_target_size() {
if (openxr_api == nullptr) {
return Size2();
diff --git a/modules/openxr/openxr_interface.h b/modules/openxr/openxr_interface.h
index 72935b039c..454612346f 100644
--- a/modules/openxr/openxr_interface.h
+++ b/modules/openxr/openxr_interface.h
@@ -91,7 +91,6 @@ private:
void free_actions(ActionSet *p_action_set);
Tracker *find_tracker(const String &p_tracker_name, bool p_create = false);
- void link_action_to_tracker(Tracker *p_tracker, Action *p_action);
void handle_tracker(Tracker *p_tracker);
void free_trackers();
@@ -120,6 +119,10 @@ public:
virtual XRInterface::PlayAreaMode get_play_area_mode() const override;
virtual bool set_play_area_mode(XRInterface::PlayAreaMode p_mode) override;
+ float get_display_refresh_rate() const;
+ void set_display_refresh_rate(float p_refresh_rate);
+ Array get_available_display_refresh_rates() const;
+
virtual Size2 get_render_target_size() override;
virtual uint32_t get_view_count() override;
virtual Transform3D get_camera_transform() override;
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index eb398f77c7..0929d3a2b0 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -810,12 +810,12 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_
ret.y = 0x7fffffff;
ret.x = 0;
+ const int *ct_offsets_ptr = ct.offsets.ptr();
for (int j = 0; j < ct.texture_w - mw; j++) {
int max_y = 0;
-
for (int k = j; k < j + mw; k++) {
- int y = ct.offsets[k];
+ int y = ct_offsets_ptr[k];
if (y > max_y) {
max_y = y;
}
@@ -1393,7 +1393,10 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_f
int error = 0;
if (!ft_library) {
error = FT_Init_FreeType(&ft_library);
- ERR_FAIL_COND_V_MSG(error != 0, false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");
+ if (error != 0) {
+ memdelete(fd);
+ ERR_FAIL_V_MSG(false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");
+ }
}
memset(&fd->stream, 0, sizeof(FT_StreamRec));
@@ -1422,6 +1425,7 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_f
if (error) {
FT_Done_Face(fd->face);
fd->face = nullptr;
+ memdelete(fd);
ERR_FAIL_V_MSG(false, "FreeType: Error loading font: '" + String(FT_Error_String(error)) + "'.");
}
@@ -1835,6 +1839,7 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_f
FT_Done_MM_Var(ft_library, amaster);
}
#else
+ memdelete(fd);
ERR_FAIL_V_MSG(false, "FreeType: Can't load dynamic font, engine is compiled without FreeType support!");
#endif
} else {
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index 13c997c981..4a46e17868 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -233,12 +233,13 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_
ret.y = 0x7fffffff;
ret.x = 0;
+ const int *ct_offsets_ptr = ct.offsets.ptr();
for (int j = 0; j < ct.texture_w - mw; j++) {
int max_y = 0;
for (int k = j; k < j + mw; k++) {
- int y = ct.offsets[k];
+ int y = ct_offsets_ptr[k];
if (y > max_y) {
max_y = y;
}
@@ -818,7 +819,10 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontFallback *p_f
int error = 0;
if (!ft_library) {
error = FT_Init_FreeType(&ft_library);
- ERR_FAIL_COND_V_MSG(error != 0, false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");
+ if (error != 0) {
+ memdelete(fd);
+ ERR_FAIL_V_MSG(false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");
+ }
}
memset(&fd->stream, 0, sizeof(FT_StreamRec));
@@ -847,6 +851,7 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontFallback *p_f
if (error) {
FT_Done_Face(fd->face);
fd->face = nullptr;
+ memdelete(fd);
ERR_FAIL_V_MSG(false, "FreeType: Error loading font: '" + String(FT_Error_String(error)) + "'.");
}
@@ -945,6 +950,7 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontFallback *p_f
FT_Done_MM_Var(ft_library, amaster);
}
#else
+ memdelete(fd);
ERR_FAIL_V_MSG(false, "FreeType: Can't load dynamic font, engine is compiled without FreeType support!");
#endif
}
diff --git a/modules/websocket/wsl_peer.cpp b/modules/websocket/wsl_peer.cpp
index 4930b178ec..84e022182e 100644
--- a/modules/websocket/wsl_peer.cpp
+++ b/modules/websocket/wsl_peer.cpp
@@ -320,7 +320,9 @@ void WSLPeer::_do_client_handshake() {
}
tcp->poll();
- if (tcp->get_status() != StreamPeerTCP::STATUS_CONNECTED) {
+ if (tcp->get_status() == StreamPeerTCP::STATUS_CONNECTING) {
+ return; // Keep connecting.
+ } else if (tcp->get_status() != StreamPeerTCP::STATUS_CONNECTED) {
close(-1); // Failed to connect.
return;
}
@@ -511,7 +513,7 @@ Error WSLPeer::connect_to_url(const String &p_url, bool p_verify_tls, Ref<X509Ce
resolver.start(host, port);
resolver.try_next_candidate(tcp);
- if (tcp->get_status() != StreamPeerTCP::STATUS_CONNECTING && !resolver.has_more_candidates()) {
+ if (tcp->get_status() != StreamPeerTCP::STATUS_CONNECTING && tcp->get_status() != StreamPeerTCP::STATUS_CONNECTED && !resolver.has_more_candidates()) {
_clear();
return FAILED;
}
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index 317f111202..6426f95b42 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -2901,20 +2901,22 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
_load_image_data(splash_bg_color_image, data);
}
- for (int i = 0; i < icon_densities_count; ++i) {
- if (main_image.is_valid() && !main_image->is_empty()) {
- if (file == launcher_icons[i].export_path) {
- _process_launcher_icons(file, main_image, launcher_icons[i].dimensions, data);
+ if (file.ends_with(".png") && file.contains("mipmap")) {
+ for (int i = 0; i < icon_densities_count; ++i) {
+ if (main_image.is_valid() && !main_image->is_empty()) {
+ if (file == launcher_icons[i].export_path) {
+ _process_launcher_icons(file, main_image, launcher_icons[i].dimensions, data);
+ }
}
- }
- if (foreground.is_valid() && !foreground->is_empty()) {
- if (file == launcher_adaptive_icon_foregrounds[i].export_path) {
- _process_launcher_icons(file, foreground, launcher_adaptive_icon_foregrounds[i].dimensions, data);
+ if (foreground.is_valid() && !foreground->is_empty()) {
+ if (file == launcher_adaptive_icon_foregrounds[i].export_path) {
+ _process_launcher_icons(file, foreground, launcher_adaptive_icon_foregrounds[i].dimensions, data);
+ }
}
- }
- if (background.is_valid() && !background->is_empty()) {
- if (file == launcher_adaptive_icon_backgrounds[i].export_path) {
- _process_launcher_icons(file, background, launcher_adaptive_icon_backgrounds[i].dimensions, data);
+ if (background.is_valid() && !background->is_empty()) {
+ if (file == launcher_adaptive_icon_backgrounds[i].export_path) {
+ _process_launcher_icons(file, background, launcher_adaptive_icon_backgrounds[i].dimensions, data);
+ }
}
}
}
diff --git a/platform/android/java/build.gradle b/platform/android/java/build.gradle
index 05608883d7..5a91e5ce32 100644
--- a/platform/android/java/build.gradle
+++ b/platform/android/java/build.gradle
@@ -276,6 +276,11 @@ task generateDevTemplate {
finalizedBy 'zipCustomBuild'
}
+task clean(type: Delete) {
+ dependsOn 'cleanGodotEditor'
+ dependsOn 'cleanGodotTemplates'
+}
+
/**
* Clean the generated editor artifacts.
*/
@@ -292,8 +297,6 @@ task cleanGodotEditor(type: Delete) {
// Delete the Godot editor apks in the Godot bin directory
delete("$binDir/android_editor.apk")
delete("$binDir/android_editor_dev.apk")
-
- finalizedBy getTasksByName("clean", true)
}
/**
@@ -321,5 +324,8 @@ task cleanGodotTemplates(type: Delete) {
delete("$binDir/godot-lib.template_debug.dev.aar")
delete("$binDir/godot-lib.template_release.aar")
- finalizedBy getTasksByName("clean", true)
+ // Cover deletion for the libs using the previous naming scheme
+ delete("$binDir/godot-lib.debug.aar")
+ delete("$binDir/godot-lib.dev.aar")
+ delete("$binDir/godot-lib.release.aar")
}
diff --git a/platform/ios/view_controller.mm b/platform/ios/view_controller.mm
index 43669d3f94..53c5d3d0b4 100644
--- a/platform/ios/view_controller.mm
+++ b/platform/ios/view_controller.mm
@@ -164,7 +164,11 @@
// MARK: Orientation
- (UIRectEdge)preferredScreenEdgesDeferringSystemGestures {
- return UIRectEdgeAll;
+ if (GLOBAL_GET("display/window/ios/suppress_ui_gesture")) {
+ return UIRectEdgeAll;
+ } else {
+ return UIRectEdgeNone;
+ }
}
- (BOOL)shouldAutorotate {
@@ -206,7 +210,11 @@
}
- (BOOL)prefersStatusBarHidden {
- return YES;
+ if (GLOBAL_GET("display/window/ios/hide_status_bar")) {
+ return YES;
+ } else {
+ return NO;
+ }
}
- (BOOL)prefersHomeIndicatorAutoHidden {
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 3b773685c3..bc767a47e5 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -3087,7 +3087,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
rect_changed = true;
}
#if defined(VULKAN_ENABLED)
- if (context_vulkan && window_created) {
+ if (context_vulkan && window.context_created) {
// Note: Trigger resize event to update swapchains when window is minimized/restored, even if size is not changed.
context_vulkan->window_resize(window_id, window.width, window.height);
}
@@ -3547,6 +3547,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
windows.erase(id);
ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Failed to create Vulkan Window.");
}
+ wd.context_created = true;
}
#endif
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index 6403b57d8d..53cde001ae 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -369,6 +369,7 @@ class DisplayServerWindows : public DisplayServer {
bool no_focus = false;
bool window_has_focus = false;
bool exclusive = false;
+ bool context_created = false;
// Used to transfer data between events using timer.
WPARAM saved_wparam;
diff --git a/scene/3d/node_3d.h b/scene/3d/node_3d.h
index 04f73a4cbd..457f634c34 100644
--- a/scene/3d/node_3d.h
+++ b/scene/3d/node_3d.h
@@ -71,8 +71,8 @@ public:
};
private:
- // For the sake of ease of use, Node3D can operate with Transforms (Basis+Origin), Quaterinon/Scale and Euler Rotation/Scale.
- // Transform and Quaterinon are stored in data.local_transform Basis (so quaternion is not really stored, but converted back/forth from 3x3 matrix on demand).
+ // For the sake of ease of use, Node3D can operate with Transforms (Basis+Origin), Quaternion/Scale and Euler Rotation/Scale.
+ // Transform and Quaternion are stored in data.local_transform Basis (so quaternion is not really stored, but converted back/forth from 3x3 matrix on demand).
// Euler needs to be kept separate because converting to Basis and back may result in a different vector (which is troublesome for users
// editing in the inspector, not only because of the numerical precision loss but because they expect these rotations to be consistent, or support
// "redundant" rotations for animation interpolation, like going from 0 to 720 degrees).
diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp
index fe4ccbc7dc..f5d30c584f 100644
--- a/scene/3d/xr_nodes.cpp
+++ b/scene/3d/xr_nodes.cpp
@@ -363,7 +363,7 @@ void XRNode3D::_unbind_tracker() {
}
void XRNode3D::_changed_tracker(const StringName p_tracker_name, int p_tracker_type) {
- if (p_tracker_name == p_tracker_name) {
+ if (tracker_name == p_tracker_name) {
// just in case unref our current tracker
_unbind_tracker();
@@ -373,7 +373,7 @@ void XRNode3D::_changed_tracker(const StringName p_tracker_name, int p_tracker_t
}
void XRNode3D::_removed_tracker(const StringName p_tracker_name, int p_tracker_type) {
- if (p_tracker_name == p_tracker_name) {
+ if (tracker_name == p_tracker_name) {
// unref our tracker, it's no longer available
_unbind_tracker();
}
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 4cd244306c..90974e31df 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -3863,7 +3863,7 @@ void TextEdit::undo() {
}
caret_pos_dirty = true;
}
- queue_redraw();
+ adjust_viewport_to_caret();
}
void TextEdit::redo() {
@@ -3915,7 +3915,7 @@ void TextEdit::redo() {
}
caret_pos_dirty = true;
}
- queue_redraw();
+ adjust_viewport_to_caret();
}
void TextEdit::clear_undo_history() {
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index f66337a2f9..a2963eadd5 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -3729,6 +3729,7 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_global_canvas_transform", "xform"), &Viewport::set_global_canvas_transform);
ClassDB::bind_method(D_METHOD("get_global_canvas_transform"), &Viewport::get_global_canvas_transform);
ClassDB::bind_method(D_METHOD("get_final_transform"), &Viewport::get_final_transform);
+ ClassDB::bind_method(D_METHOD("get_screen_transform"), &Viewport::get_screen_transform);
ClassDB::bind_method(D_METHOD("get_visible_rect"), &Viewport::get_visible_rect);
ClassDB::bind_method(D_METHOD("set_transparent_background", "enable"), &Viewport::set_transparent_background);
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index de13912b75..a4c958d402 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -7264,7 +7264,7 @@ String VisualShaderNodeProximityFade::generate_code(Shader::Mode p_mode, VisualS
} else {
code += " vec4 __depth_world_pos = INV_PROJECTION_MATRIX * vec4(vec3(SCREEN_UV, __depth_tex) * 2.0 - 1.0, 1.0);\n";
}
- code += " __depth_world_pos.xyz /= __depth_world_pos.z;\n";
+ code += " __depth_world_pos.xyz /= __depth_world_pos.w;\n";
code += vformat(" %s = clamp(1.0 - smoothstep(__depth_world_pos.z + %s, __depth_world_pos.z, VERTEX.z), 0.0, 1.0);\n", p_output_vars[0], p_input_vars[0]);
return code;
diff --git a/tests/core/string/test_string.h b/tests/core/string/test_string.h
index cf34caac28..cd1b421ce8 100644
--- a/tests/core/string/test_string.h
+++ b/tests/core/string/test_string.h
@@ -411,9 +411,13 @@ TEST_CASE("[String] Number to string") {
CHECK(String::num_real(3.141593) == "3.141593");
CHECK(String::num_real(3.141) == "3.141"); // No trailing zeros.
#ifdef REAL_T_IS_DOUBLE
+ CHECK_MESSAGE(String::num_real(123.456789) == "123.456789", "Prints the appropriate amount of digits for real_t = double.");
+ CHECK_MESSAGE(String::num_real(-123.456789) == "-123.456789", "Prints the appropriate amount of digits for real_t = double.");
CHECK_MESSAGE(String::num_real(Math_PI) == "3.14159265358979", "Prints the appropriate amount of digits for real_t = double.");
CHECK_MESSAGE(String::num_real(3.1415f) == "3.1414999961853", "Prints more digits of 32-bit float when real_t = double (ones that would be reliable for double) and no trailing zero.");
#else
+ CHECK_MESSAGE(String::num_real(123.456789) == "123.4568", "Prints the appropriate amount of digits for real_t = float.");
+ CHECK_MESSAGE(String::num_real(-123.456789) == "-123.4568", "Prints the appropriate amount of digits for real_t = float.");
CHECK_MESSAGE(String::num_real(Math_PI) == "3.141593", "Prints the appropriate amount of digits for real_t = float.");
CHECK_MESSAGE(String::num_real(3.1415f) == "3.1415", "Prints only reliable digits of 32-bit float when real_t = float.");
#endif // REAL_T_IS_DOUBLE
diff --git a/tests/scene/test_text_edit.h b/tests/scene/test_text_edit.h
index 3a20ac123b..2ef0a3345f 100644
--- a/tests/scene/test_text_edit.h
+++ b/tests/scene/test_text_edit.h
@@ -3918,6 +3918,32 @@ TEST_CASE("[SceneTree][TextEdit] viewport") {
CHECK(text_edit->get_last_full_visible_line_wrap_index() == 0);
CHECK(text_edit->get_caret_wrap_index() == 0);
+ // Typing and undo / redo should adjust viewport
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(0);
+ text_edit->set_line_as_first_visible(5);
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_first_visible_line() == 5);
+
+ SEND_GUI_KEY_EVENT(text_edit, Key::A);
+ CHECK(text_edit->get_first_visible_line() == 0);
+
+ text_edit->set_line_as_first_visible(5);
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_first_visible_line() == 5);
+
+ text_edit->undo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_first_visible_line() == 0);
+
+ text_edit->set_line_as_first_visible(5);
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_first_visible_line() == 5);
+
+ text_edit->redo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_first_visible_line() == 0);
+
memdelete(text_edit);
}