summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/config/project_settings.cpp6
-rw-r--r--core/input/input_event.cpp9
-rw-r--r--core/input/input_event.h2
-rw-r--r--core/io/resource_loader.cpp12
-rw-r--r--doc/Makefile24
-rw-r--r--doc/classes/@GlobalScope.xml1
-rw-r--r--doc/classes/CharacterBody2D.xml8
-rw-r--r--doc/classes/CharacterBody3D.xml8
-rw-r--r--doc/classes/Font.xml11
-rw-r--r--doc/classes/FontVariation.xml11
-rw-r--r--doc/classes/ParticleProcessMaterial.xml6
-rw-r--r--doc/classes/ProjectSettings.xml9
-rw-r--r--doc/classes/XRServer.xml4
-rw-r--r--editor/editor_settings.cpp16
-rw-r--r--editor/editor_settings.h8
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h3
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp16
-rw-r--r--editor/plugins/node_3d_editor_plugin.h2
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp3
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp3
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.cpp2
-rw-r--r--editor/project_converter_3_to_4.cpp108
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.cpp20
-rw-r--r--modules/gltf/doc_classes/GLTFNode.xml13
-rw-r--r--modules/gltf/doc_classes/GLTFState.xml26
-rw-r--r--modules/text_server_adv/text_server_adv.cpp81
-rw-r--r--modules/text_server_adv/text_server_adv.h2
-rw-r--r--modules/text_server_fb/text_server_fb.cpp81
-rw-r--r--modules/text_server_fb/text_server_fb.h2
-rw-r--r--scene/2d/physics_body_2d.cpp17
-rw-r--r--scene/2d/physics_body_2d.h2
-rw-r--r--scene/3d/physics_body_3d.cpp13
-rw-r--r--scene/3d/physics_body_3d.h1
-rw-r--r--scene/animation/tween.cpp5
-rw-r--r--scene/animation/tween.h2
-rw-r--r--scene/resources/font.cpp6
-rw-r--r--servers/xr_server.cpp3
37 files changed, 355 insertions, 191 deletions
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 56e9057a2a..2100f4c62d 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -401,6 +401,10 @@ void ProjectSettings::_get_property_list(List<PropertyInfo> *p_list) const {
vc.flags = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE;
}
+ if (v->internal) {
+ vc.flags |= PROPERTY_USAGE_INTERNAL;
+ }
+
if (v->basic) {
vc.flags |= PROPERTY_USAGE_EDITOR_BASIC_SETTING;
}
@@ -1242,7 +1246,7 @@ void ProjectSettings::_add_builtin_input_map() {
action["events"] = events;
String action_name = "input/" + E.key;
- GLOBAL_DEF_INTERNAL(action_name, action);
+ GLOBAL_DEF(action_name, action);
input_presets.push_back(action_name);
}
}
diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp
index a6c1bb168c..9d5d84a508 100644
--- a/core/input/input_event.cpp
+++ b/core/input/input_event.cpp
@@ -474,10 +474,15 @@ String InputEventKey::to_string() {
return vformat("InputEventKey: keycode=%s, mods=%s, physical=%s, pressed=%s, echo=%s", kc, mods, physical, p, e);
}
-Ref<InputEventKey> InputEventKey::create_reference(Key p_keycode) {
+Ref<InputEventKey> InputEventKey::create_reference(Key p_keycode, bool p_physical) {
Ref<InputEventKey> ie;
ie.instantiate();
- ie->set_keycode(p_keycode & KeyModifierMask::CODE_MASK);
+ if (p_physical) {
+ ie->set_physical_keycode(p_keycode & KeyModifierMask::CODE_MASK);
+ } else {
+ ie->set_keycode(p_keycode & KeyModifierMask::CODE_MASK);
+ }
+
ie->set_unicode(char32_t(p_keycode & KeyModifierMask::CODE_MASK));
if ((p_keycode & KeyModifierMask::SHIFT) != Key::NONE) {
diff --git a/core/input/input_event.h b/core/input/input_event.h
index eff8d479db..4be42d0bd2 100644
--- a/core/input/input_event.h
+++ b/core/input/input_event.h
@@ -195,7 +195,7 @@ public:
virtual String as_text() const override;
virtual String to_string() override;
- static Ref<InputEventKey> create_reference(Key p_keycode_with_modifier_masks);
+ static Ref<InputEventKey> create_reference(Key p_keycode_with_modifier_masks, bool p_physical = false);
InputEventKey() {}
};
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index 77b5e5b66d..a46fac4e7a 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -486,13 +486,21 @@ Ref<Resource> ResourceLoader::load_threaded_get(const String &p_path, Error *r_e
print_lt("GET: load count: " + itos(thread_loading_count) + " / wait count: " + itos(thread_waiting_count) + " / suspended count: " + itos(thread_suspended_count) + " / active: " + itos(thread_loading_count - thread_suspended_count));
}
+ bool still_valid = true;
+ bool was_thread = load_task.thread;
do {
load_task.cond_var->wait(thread_load_lock);
+ if (!thread_load_tasks.has(local_path)) { //may have been erased during unlock and this was always an invalid call
+ still_valid = false;
+ break;
+ }
} while (load_task.cond_var); // In case of spurious wakeup.
- thread_suspended_count--;
+ if (was_thread) {
+ thread_suspended_count--;
+ }
- if (!thread_load_tasks.has(local_path)) { //may have been erased during unlock and this was always an invalid call
+ if (!still_valid) {
if (r_error) {
*r_error = ERR_INVALID_PARAMETER;
}
diff --git a/doc/Makefile b/doc/Makefile
index c8bf32d6e2..cc2ebf9881 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -1,28 +1,28 @@
BASEDIR = .
-CLASSES = $(BASEDIR)/classes/ $(BASEDIR)/../modules/
+CLASSES = "$(BASEDIR)/classes/" "$(BASEDIR)/../modules/"
OUTPUTDIR = $(BASEDIR)/_build
TOOLSDIR = $(BASEDIR)/tools
-JSDIR = $(BASEDIR)/../platform/web
+JSDIR = "$(BASEDIR)/../platform/web"
LANGARG ?= en
LANGCMD = -l $(LANGARG)
.ONESHELL:
clean:
- rm -rf $(OUTPUTDIR)
+ rm -rf "$(OUTPUTDIR)"
doxygen:
- rm -rf $(OUTPUTDIR)/doxygen
- mkdir -p $(OUTPUTDIR)/doxygen
+ rm -rf "$(OUTPUTDIR)/doxygen"
+ mkdir -p "$(OUTPUTDIR)/doxygen"
doxygen Doxyfile
rst:
- rm -rf $(OUTPUTDIR)/rst
- mkdir -p $(OUTPUTDIR)/rst
- python3 $(TOOLSDIR)/make_rst.py -o $(OUTPUTDIR)/rst $(LANGCMD) $(CLASSES)
+ rm -rf "$(OUTPUTDIR)/rst"
+ mkdir -p "$(OUTPUTDIR)/rst"
+ python3 "$(TOOLSDIR)/make_rst.py" -o "$(OUTPUTDIR)/rst" "$(LANGCMD)" $(CLASSES)
rstjs:
- rm -rf $(OUTPUTDIR)/rstjs
- mkdir -p $(OUTPUTDIR)/rstjs
- npm --prefix $(JSDIR) ci
- npm --prefix $(JSDIR) run docs -- --destination $(OUTPUTDIR)/rstjs/html5_shell_classref.rst
+ rm -rf "$(OUTPUTDIR)/rstjs"
+ mkdir -p "$(OUTPUTDIR)/rstjs"
+ npm --prefix "$(JSDIR)" ci
+ npm --prefix "$(JSDIR)" run docs -- --destination "$(OUTPUTDIR)/rstjs/html5_shell_classref.rst"
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index a38d25ea5b..cdaf9bd1be 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -2773,6 +2773,7 @@
The property is shown in the [EditorInspector] (default).
</constant>
<constant name="PROPERTY_USAGE_INTERNAL" value="8" enum="PropertyUsageFlags" is_bitfield="true">
+ The property is excluded from the class reference.
</constant>
<constant name="PROPERTY_USAGE_CHECKABLE" value="16" enum="PropertyUsageFlags" is_bitfield="true">
The property can be checked in the [EditorInspector].
diff --git a/doc/classes/CharacterBody2D.xml b/doc/classes/CharacterBody2D.xml
index 8ecec129a6..40e777ca26 100644
--- a/doc/classes/CharacterBody2D.xml
+++ b/doc/classes/CharacterBody2D.xml
@@ -15,6 +15,12 @@
<link title="2D Platformer Demo">https://godotengine.org/asset-library/asset/120</link>
</tutorials>
<methods>
+ <method name="apply_floor_snap">
+ <return type="void" />
+ <description>
+ Allows to manually apply a snap to the floor regardless of the body's velocity. This function does nothing when [method is_on_floor] returns [code]true[/code].
+ </description>
+ </method>
<method name="get_floor_angle" qualifiers="const">
<return type="float" />
<param index="0" name="up_direction" type="Vector2" default="Vector2(0, -1)" />
@@ -152,7 +158,7 @@
</member>
<member name="floor_snap_length" type="float" setter="set_floor_snap_length" getter="get_floor_snap_length" default="1.0">
Sets a snapping distance. When set to a value different from [code]0.0[/code], the body is kept attached to slopes when calling [method move_and_slide]. The snapping vector is determined by the given distance along the opposite direction of the [member up_direction].
- As long as the snapping vector is in contact with the ground and the body moves against [member up_direction], the body will remain attached to the surface. Snapping is not applied if the body moves along [member up_direction], so it will be able to detach from the ground when jumping.
+ As long as the snapping vector is in contact with the ground and the body moves against [member up_direction], the body will remain attached to the surface. Snapping is not applied if the body moves along [member up_direction], meaning it contains vertical rising velocity, so it will be able to detach from the ground when jumping or when the body is pushed up by something. If you want to apply a snap without taking into account the velocity, use [method apply_floor_snap].
</member>
<member name="floor_stop_on_slope" type="bool" setter="set_floor_stop_on_slope_enabled" getter="is_floor_stop_on_slope_enabled" default="true">
If [code]true[/code], the body will not slide on slopes when calling [method move_and_slide] when the body is standing still.
diff --git a/doc/classes/CharacterBody3D.xml b/doc/classes/CharacterBody3D.xml
index 0db3fad174..830c45a45b 100644
--- a/doc/classes/CharacterBody3D.xml
+++ b/doc/classes/CharacterBody3D.xml
@@ -17,6 +17,12 @@
<link title="Third Person Shooter Demo">https://godotengine.org/asset-library/asset/678</link>
</tutorials>
<methods>
+ <method name="apply_floor_snap">
+ <return type="void" />
+ <description>
+ Allows to manually apply a snap to the floor regardless of the body's velocity. This function does nothing when [method is_on_floor] returns [code]true[/code].
+ </description>
+ </method>
<method name="get_floor_angle" qualifiers="const">
<return type="float" />
<param index="0" name="up_direction" type="Vector3" default="Vector3(0, 1, 0)" />
@@ -144,7 +150,7 @@
</member>
<member name="floor_snap_length" type="float" setter="set_floor_snap_length" getter="get_floor_snap_length" default="0.1">
Sets a snapping distance. When set to a value different from [code]0.0[/code], the body is kept attached to slopes when calling [method move_and_slide]. The snapping vector is determined by the given distance along the opposite direction of the [member up_direction].
- As long as the snapping vector is in contact with the ground and the body moves against [member up_direction], the body will remain attached to the surface. Snapping is not applied if the body moves along [member up_direction], so it will be able to detach from the ground when jumping.
+ As long as the snapping vector is in contact with the ground and the body moves against [member up_direction], the body will remain attached to the surface. Snapping is not applied if the body moves along [member up_direction], meaning it contains vertical rising velocity, so it will be able to detach from the ground when jumping or when the body is pushed up by something. If you want to apply a snap without taking into account the velocity, use [method apply_floor_snap].
</member>
<member name="floor_stop_on_slope" type="bool" setter="set_floor_stop_on_slope_enabled" getter="is_floor_stop_on_slope_enabled" default="true">
If [code]true[/code], the body will not slide on slopes when calling [method move_and_slide] when the body is standing still.
diff --git a/doc/classes/Font.xml b/doc/classes/Font.xml
index bd6a9cf04e..548376f262 100644
--- a/doc/classes/Font.xml
+++ b/doc/classes/Font.xml
@@ -271,6 +271,17 @@
<description>
Returns list of supported [url=https://docs.microsoft.com/en-us/typography/opentype/spec/dvaraxisreg]variation coordinates[/url], each coordinate is returned as [code]tag: Vector3i(min_value,max_value,default_value)[/code].
Font variations allow for continuous change of glyph characteristics along some given design axis, such as weight, width or slant.
+ To print available variation axes of a variable font:
+ [codeblock]
+ var fv = FontVariation.new()
+ fv.set_base_font = load("res://RobotoFlex.ttf")
+ var variation_list = fv.get_supported_variation_list()
+ for tag in variation_list:
+ var name = TextServerManager.get_primary_interface().tag_to_name(tag)
+ var values = variation_list[tag]
+ print("variation axis: %s (%d)\n\tmin, max, default: %s" % [name, tag, values])
+ [/codeblock]
+ [b]Note:[/b] To set and get variation coordinates of a [FontVariation], use [member FontVariation.variation_opentype].
</description>
</method>
<method name="get_underline_position" qualifiers="const">
diff --git a/doc/classes/FontVariation.xml b/doc/classes/FontVariation.xml
index 1b3ec87b60..9bc0e0424b 100644
--- a/doc/classes/FontVariation.xml
+++ b/doc/classes/FontVariation.xml
@@ -22,6 +22,13 @@
GetNode("Label").AddThemeFontSizeOverride("font_size", 64);
[/csharp]
[/codeblocks]
+ To set the coordinate of multiple variation axes:
+ [codeblock]
+ var fv = FontVariation.new();
+ var ts = TextServerManager.get_primary_interface()
+ fv.base_font = load("res://BarlowCondensed-Regular.ttf")
+ fv.variation_opentype = { ts.name_to_tag("wght"): 900, ts.name_to_tag("custom_hght"): 900 }
+ [/codeblock]
</description>
<tutorials>
</tutorials>
@@ -40,7 +47,7 @@
Base font used to create a variation. If not set, default [Theme] font is used.
</member>
<member name="fallbacks" type="Font[]" setter="set_fallbacks" getter="get_fallbacks" default="[]">
- Array of fallback [Font]s. If not set [member base_font] fallback are ussed.
+ Array of fallback [Font]s to use as a substitute if a glyph is not found in this [FontVariation]. If not set, [member base_font]'s fallbacks are used instead.
</member>
<member name="opentype_features" type="Dictionary" setter="set_opentype_features" getter="get_opentype_features" default="{}">
A set of OpenType feature tags. More info: [url=https://docs.microsoft.com/en-us/typography/opentype/spec/featuretags]OpenType feature tags[/url].
@@ -66,6 +73,8 @@
</member>
<member name="variation_opentype" type="Dictionary" setter="set_variation_opentype" getter="get_variation_opentype" default="{}">
Font OpenType variation coordinates. More info: [url=https://docs.microsoft.com/en-us/typography/opentype/spec/dvaraxisreg]OpenType variation tags[/url].
+ [b]Note:[/b] This [Dictionary] uses OpenType tags as keys. Variation axes can be identified both by tags([code]int[/code]) and names ([code]string[/code]). Some axes might be accessible by multiple names. For example, [code]wght[/code] refers to the same axis as [code]weight[/code]. Tags on the other hand are unique. To convert between names and tags, use [method TextServer.name_to_tag] and [method TextServer.tag_to_name].
+ [b]Note:[/b] To get available variation axes of a font, use [method Font.get_supported_variation_list].
</member>
<member name="variation_transform" type="Transform2D" setter="set_variation_transform" getter="get_variation_transform" default="Transform2D(1, 0, 0, 1, 0, 0)">
2D transform, applied to the font outlines, can be used for slanting, flipping and rotating glyphs.
diff --git a/doc/classes/ParticleProcessMaterial.xml b/doc/classes/ParticleProcessMaterial.xml
index a7179dbf0d..6d549e1b67 100644
--- a/doc/classes/ParticleProcessMaterial.xml
+++ b/doc/classes/ParticleProcessMaterial.xml
@@ -285,11 +285,11 @@
Enables and disables Turbulence for the particle system.
</member>
<member name="turbulence_influence_max" type="float" setter="set_param_max" getter="get_param_max" default="0.1">
- Minimum turbulence influence on each particle.
- The actual amount of turbulence influence on each particle is calculated as a random value between [member turbulence_influence_min] and [member turbulence_influence_max] and multiplied by the amount of turbulence influence from [member turbulence_influence_over_life].
+ Maximum turbulence influence on each particle.
+ The actual amount of turbulence influence on each particle is calculated as a random value between [member turbulence_influence_min] and [member turbulence_influence_max] and multiplied by the amount of turbulence influence from [member turbulence_influence_over_life].
</member>
<member name="turbulence_influence_min" type="float" setter="set_param_min" getter="get_param_min" default="0.1">
- Maximum turbulence influence on each particle.
+ Minimum turbulence influence on each particle.
The actual amount of turbulence influence on each particle is calculated as a random value between [member turbulence_influence_min] and [member turbulence_influence_max] and multiplied by the amount of turbulence influence from [member turbulence_influence_over_life].
</member>
<member name="turbulence_influence_over_life" type="Texture2D" setter="set_param_texture" getter="get_param_texture">
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 1876a76d9f..3a363211ca 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -248,9 +248,6 @@
<member name="application/config/description" type="String" setter="" getter="" default="&quot;&quot;">
The project's description, displayed as a tooltip in the Project Manager when hovering the project.
</member>
- <member name="application/config/features" type="PackedStringArray" setter="" getter="">
- List of internal features associated with the project, like [code]Double Precision[/code] or [code]C#[/code]. Not to be confused with feature tags.
- </member>
<member name="application/config/icon" type="String" setter="" getter="" default="&quot;&quot;">
Icon used for the project, set when project loads. Exporters will also use this icon when possible.
</member>
@@ -1161,12 +1158,6 @@
<member name="internationalization/locale/test" type="String" setter="" getter="" default="&quot;&quot;">
If non-empty, this locale will be used when running the project from the editor.
</member>
- <member name="internationalization/locale/translation_remaps" type="PackedStringArray" setter="" getter="">
- Locale-dependent resource remaps. Edit them in the "Localization" tab of Project Settings editor.
- </member>
- <member name="internationalization/locale/translations" type="PackedStringArray" setter="" getter="">
- List of translation files available in the project. Edit them in the "Localization" tab of Project Settings editor.
- </member>
<member name="internationalization/pseudolocalization/double_vowels" type="bool" setter="" getter="" default="false">
Double vowels in strings during pseudolocalization to simulate the lengthening of text due to localization.
</member>
diff --git a/doc/classes/XRServer.xml b/doc/classes/XRServer.xml
index d4ea6104d8..802d7ef2a9 100644
--- a/doc/classes/XRServer.xml
+++ b/doc/classes/XRServer.xml
@@ -108,6 +108,10 @@
<member name="primary_interface" type="XRInterface" setter="set_primary_interface" getter="get_primary_interface">
The primary [XRInterface] currently bound to the [XRServer].
</member>
+ <member name="world_origin" type="Transform3D" setter="set_world_origin" getter="get_world_origin" default="Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)">
+ The current origin of our tracking space in the virtual world. This is used by the renderer to properly position the camera with new tracking data.
+ [b]Note:[/b] This property is managed by the current [XROrigin3D] node. It is exposed for access from GDExtensions.
+ </member>
<member name="world_scale" type="float" setter="set_world_scale" getter="get_world_scale" default="1.0">
Allows you to adjust the scale to your game's units. Most AR/VR platforms assume a scale of 1 game world unit = 1 real world meter.
</member>
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 037bfbfd99..25c84e7447 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -1468,7 +1468,7 @@ Ref<Shortcut> ED_GET_SHORTCUT(const String &p_path) {
return sc;
}
-void ED_SHORTCUT_OVERRIDE(const String &p_path, const String &p_feature, Key p_keycode) {
+void ED_SHORTCUT_OVERRIDE(const String &p_path, const String &p_feature, Key p_keycode, bool p_physical) {
ERR_FAIL_NULL_MSG(EditorSettings::get_singleton(), "EditorSettings not instantiated yet.");
Ref<Shortcut> sc = EditorSettings::get_singleton()->get_shortcut(p_path);
@@ -1477,10 +1477,10 @@ void ED_SHORTCUT_OVERRIDE(const String &p_path, const String &p_feature, Key p_k
PackedInt32Array arr;
arr.push_back((int32_t)p_keycode);
- ED_SHORTCUT_OVERRIDE_ARRAY(p_path, p_feature, arr);
+ ED_SHORTCUT_OVERRIDE_ARRAY(p_path, p_feature, arr, p_physical);
}
-void ED_SHORTCUT_OVERRIDE_ARRAY(const String &p_path, const String &p_feature, const PackedInt32Array &p_keycodes) {
+void ED_SHORTCUT_OVERRIDE_ARRAY(const String &p_path, const String &p_feature, const PackedInt32Array &p_keycodes, bool p_physical) {
ERR_FAIL_NULL_MSG(EditorSettings::get_singleton(), "EditorSettings not instantiated yet.");
Ref<Shortcut> sc = EditorSettings::get_singleton()->get_shortcut(p_path);
@@ -1505,7 +1505,7 @@ void ED_SHORTCUT_OVERRIDE_ARRAY(const String &p_path, const String &p_feature, c
Ref<InputEventKey> ie;
if (keycode != Key::NONE) {
- ie = InputEventKey::create_reference(keycode);
+ ie = InputEventKey::create_reference(keycode, p_physical);
events.push_back(ie);
}
}
@@ -1518,13 +1518,13 @@ void ED_SHORTCUT_OVERRIDE_ARRAY(const String &p_path, const String &p_feature, c
sc->set_meta("original", events.duplicate(true));
}
-Ref<Shortcut> ED_SHORTCUT(const String &p_path, const String &p_name, Key p_keycode) {
+Ref<Shortcut> ED_SHORTCUT(const String &p_path, const String &p_name, Key p_keycode, bool p_physical) {
PackedInt32Array arr;
arr.push_back((int32_t)p_keycode);
- return ED_SHORTCUT_ARRAY(p_path, p_name, arr);
+ return ED_SHORTCUT_ARRAY(p_path, p_name, arr, p_physical);
}
-Ref<Shortcut> ED_SHORTCUT_ARRAY(const String &p_path, const String &p_name, const PackedInt32Array &p_keycodes) {
+Ref<Shortcut> ED_SHORTCUT_ARRAY(const String &p_path, const String &p_name, const PackedInt32Array &p_keycodes, bool p_physical) {
Array events;
for (int i = 0; i < p_keycodes.size(); i++) {
@@ -1539,7 +1539,7 @@ Ref<Shortcut> ED_SHORTCUT_ARRAY(const String &p_path, const String &p_name, cons
Ref<InputEventKey> ie;
if (keycode != Key::NONE) {
- ie = InputEventKey::create_reference(keycode);
+ ie = InputEventKey::create_reference(keycode, p_physical);
events.push_back(ie);
}
}
diff --git a/editor/editor_settings.h b/editor/editor_settings.h
index e1d3e757e0..a21fb9fdfb 100644
--- a/editor/editor_settings.h
+++ b/editor/editor_settings.h
@@ -195,10 +195,10 @@ Variant _EDITOR_DEF(const String &p_setting, const Variant &p_default, bool p_re
Variant _EDITOR_GET(const String &p_setting);
#define ED_IS_SHORTCUT(p_name, p_ev) (EditorSettings::get_singleton()->is_shortcut(p_name, p_ev))
-Ref<Shortcut> ED_SHORTCUT(const String &p_path, const String &p_name, Key p_keycode = Key::NONE);
-Ref<Shortcut> ED_SHORTCUT_ARRAY(const String &p_path, const String &p_name, const PackedInt32Array &p_keycodes);
-void ED_SHORTCUT_OVERRIDE(const String &p_path, const String &p_feature, Key p_keycode = Key::NONE);
-void ED_SHORTCUT_OVERRIDE_ARRAY(const String &p_path, const String &p_feature, const PackedInt32Array &p_keycodes);
+Ref<Shortcut> ED_SHORTCUT(const String &p_path, const String &p_name, Key p_keycode = Key::NONE, bool p_physical = false);
+Ref<Shortcut> ED_SHORTCUT_ARRAY(const String &p_path, const String &p_name, const PackedInt32Array &p_keycodes, bool p_physical = false);
+void ED_SHORTCUT_OVERRIDE(const String &p_path, const String &p_feature, Key p_keycode = Key::NONE, bool p_physical = false);
+void ED_SHORTCUT_OVERRIDE_ARRAY(const String &p_path, const String &p_feature, const PackedInt32Array &p_keycodes, bool p_physical = false);
Ref<Shortcut> ED_GET_SHORTCUT(const String &p_path);
#endif // EDITOR_SETTINGS_H
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index c5b9bf9e0b..5ad8318ca0 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -212,7 +212,8 @@ private:
bool selected_from_canvas = false;
Point2 grid_offset;
- Point2 grid_step = Point2(8, 8); // A power-of-two value works better as a default.
+ // A power-of-two value works better as a default grid size.
+ Point2 grid_step = Point2(8, 8);
int primary_grid_steps = 8;
int grid_step_multiplier = 0;
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 7feb0146bc..5628a6a1be 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -4865,8 +4865,8 @@ void Node3DEditorViewport::finish_transform() {
}
// Register a shortcut and also add it as an input action with the same events.
-void Node3DEditorViewport::register_shortcut_action(const String &p_path, const String &p_name, Key p_keycode) {
- Ref<Shortcut> sc = ED_SHORTCUT(p_path, p_name, p_keycode);
+void Node3DEditorViewport::register_shortcut_action(const String &p_path, const String &p_name, Key p_keycode, bool p_physical) {
+ Ref<Shortcut> sc = ED_SHORTCUT(p_path, p_name, p_keycode, p_physical);
shortcut_changed_callback(sc, p_path);
// Connect to the change event on the shortcut so the input binding can be updated.
sc->connect("changed", callable_mp(this, &Node3DEditorViewport::shortcut_changed_callback).bind(sc, p_path));
@@ -5047,12 +5047,12 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p
view_menu->get_popup()->set_item_tooltip(shadeless_idx, unsupported_tooltip);
}
- register_shortcut_action("spatial_editor/freelook_left", TTR("Freelook Left"), Key::A);
- register_shortcut_action("spatial_editor/freelook_right", TTR("Freelook Right"), Key::D);
- register_shortcut_action("spatial_editor/freelook_forward", TTR("Freelook Forward"), Key::W);
- register_shortcut_action("spatial_editor/freelook_backwards", TTR("Freelook Backwards"), Key::S);
- register_shortcut_action("spatial_editor/freelook_up", TTR("Freelook Up"), Key::E);
- register_shortcut_action("spatial_editor/freelook_down", TTR("Freelook Down"), Key::Q);
+ register_shortcut_action("spatial_editor/freelook_left", TTR("Freelook Left"), Key::A, true);
+ register_shortcut_action("spatial_editor/freelook_right", TTR("Freelook Right"), Key::D, true);
+ register_shortcut_action("spatial_editor/freelook_forward", TTR("Freelook Forward"), Key::W, true);
+ register_shortcut_action("spatial_editor/freelook_backwards", TTR("Freelook Backwards"), Key::S, true);
+ register_shortcut_action("spatial_editor/freelook_up", TTR("Freelook Up"), Key::E, true);
+ register_shortcut_action("spatial_editor/freelook_down", TTR("Freelook Down"), Key::Q, true);
register_shortcut_action("spatial_editor/freelook_speed_modifier", TTR("Freelook Speed Modifier"), Key::SHIFT);
register_shortcut_action("spatial_editor/freelook_slow_modifier", TTR("Freelook Slow Modifier"), Key::ALT);
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
index e5267e5fad..c4193f0420 100644
--- a/editor/plugins/node_3d_editor_plugin.h
+++ b/editor/plugins/node_3d_editor_plugin.h
@@ -441,7 +441,7 @@ private:
void update_transform(Point2 p_mousepos, bool p_shift);
void finish_transform();
- void register_shortcut_action(const String &p_path, const String &p_name, Key p_keycode);
+ void register_shortcut_action(const String &p_path, const String &p_name, Key p_keycode, bool p_physical = false);
void shortcut_changed_callback(const Ref<Shortcut> p_shortcut, const String &p_shortcut_path);
protected:
diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp
index fb35668310..e5e77be7aa 100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -1232,7 +1232,8 @@ Vector2 Polygon2DEditor::snap_point(Vector2 p_target) const {
Polygon2DEditor::Polygon2DEditor() {
snap_offset = EditorSettings::get_singleton()->get_project_metadata("polygon_2d_uv_editor", "snap_offset", Vector2());
- snap_step = EditorSettings::get_singleton()->get_project_metadata("polygon_2d_uv_editor", "snap_step", Vector2(10, 10));
+ // A power-of-two value works better as a default grid size.
+ snap_step = EditorSettings::get_singleton()->get_project_metadata("polygon_2d_uv_editor", "snap_step", Vector2(8, 8));
use_snap = EditorSettings::get_singleton()->get_project_metadata("polygon_2d_uv_editor", "snap_enabled", false);
snap_show_grid = EditorSettings::get_singleton()->get_project_metadata("polygon_2d_uv_editor", "show_grid", false);
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index 7fa16e6cc6..96e9005850 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -1075,7 +1075,8 @@ TextureRegionEditor::TextureRegionEditor() {
preview_tex = Ref<CanvasTexture>(memnew(CanvasTexture));
- snap_step = Vector2(10, 10);
+ // A power-of-two value works better as a default grid size.
+ snap_step = Vector2(8, 8);
snap_separation = Vector2(0, 0);
snap_mode = SNAP_NONE;
edited_margin = -1;
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
index fcefbb7d06..235e34d9b5 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
@@ -648,7 +648,7 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
if (!tile_data_editors.has("texture_origin")) {
TileDataTextureOriginEditor *tile_data_texture_origin_editor = memnew(TileDataTextureOriginEditor);
tile_data_texture_origin_editor->hide();
- tile_data_texture_origin_editor->setup_property_editor(Variant::VECTOR2, "texture_origin");
+ tile_data_texture_origin_editor->setup_property_editor(Variant::VECTOR2I, "texture_origin");
tile_data_texture_origin_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw));
tile_data_texture_origin_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw));
tile_data_editors["texture_origin"] = tile_data_texture_origin_editor;
diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp
index 663a2af065..d00048ec48 100644
--- a/editor/project_converter_3_to_4.cpp
+++ b/editor/project_converter_3_to_4.cpp
@@ -307,7 +307,7 @@ bool ProjectConverter3To4::convert() {
maximum_line_length = 10000; // Use only for tests bigger value, to not break them.
ERR_FAIL_COND_V_MSG(!test_array_names(), false, "Cannot start converting due to problems with data in arrays.");
- ERR_FAIL_COND_V_MSG(!test_conversion(reg_container), false, "Cannot start converting due to problems with converting arrays.");
+ ERR_FAIL_COND_V_MSG(!test_conversion(reg_container), false, "Aborting conversion due to validation tests failing");
maximum_line_length = cached_maximum_line_length;
@@ -487,7 +487,7 @@ bool ProjectConverter3To4::validate_conversion() {
maximum_line_length = 10000; // To avoid breaking the tests, only use this for the their larger value.
ERR_FAIL_COND_V_MSG(!test_array_names(), false, "Cannot start converting due to problems with data in arrays.");
- ERR_FAIL_COND_V_MSG(!test_conversion(reg_container), false, "Cannot start converting due to problems with converting arrays.");
+ ERR_FAIL_COND_V_MSG(!test_conversion(reg_container), false, "Aborting conversion due to validation tests failing");
maximum_line_length = cached_maximum_line_length;
@@ -496,7 +496,7 @@ bool ProjectConverter3To4::validate_conversion() {
{
String conventer_text = "; Project was converted by built-in tool to Godot 4.0";
- ERR_FAIL_COND_V_MSG(!FileAccess::exists("project.godot"), false, "Current directory doesn't contains any Godot 3 project");
+ ERR_FAIL_COND_V_MSG(!FileAccess::exists("project.godot"), false, "Current directory doesn't contain any Godot 3 project");
Error err = OK;
String project_godot_content = FileAccess::get_file_as_string("project.godot", &err);
@@ -735,9 +735,9 @@ bool ProjectConverter3To4::test_conversion(RegExContainer &reg_container) {
// Custom Renames.
- valid = valid && test_conversion_with_regex("(Connect(A,B,C,D,E,F,G) != OK):", "(Connect(A,new Callable(B,C),D,E,F,G) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename csharp", reg_container);
- valid = valid && test_conversion_with_regex("(Disconnect(A,B,C) != OK):", "(Disconnect(A,new Callable(B,C)) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename csharp", reg_container);
- valid = valid && test_conversion_with_regex("(IsConnected(A,B,C) != OK):", "(IsConnected(A,new Callable(B,C)) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename", reg_container);
+ valid = valid && test_conversion_with_regex("(Connect(A,B,C,D,E,F,G) != OK):", "(Connect(A, new Callable(B, C), D, E, F, G) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename csharp", reg_container);
+ valid = valid && test_conversion_with_regex("(Disconnect(A,B,C) != OK):", "(Disconnect(A, new Callable(B, C)) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename csharp", reg_container);
+ valid = valid && test_conversion_with_regex("(IsConnected(A,B,C) != OK):", "(IsConnected(A, new Callable(B, C)) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename", reg_container);
valid = valid && test_conversion_with_regex("[Remote]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
valid = valid && test_conversion_with_regex("[RemoteSync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
@@ -793,11 +793,11 @@ bool ProjectConverter3To4::test_conversion(RegExContainer &reg_container) {
valid = valid && test_conversion_gdscript_builtin("list_dir_begin( a )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("list_dir_begin( )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("sort_custom( a , b )", "sort_custom(Callable(a,b))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("sort_custom( a , b )", "sort_custom(Callable(a, b))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("func c(var a, var b)", "func c(a, b)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("draw_line(1, 2, 3, 4, 5)", "draw_line(1,2,3,4)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("draw_line(1, 2, 3, 4, 5)", "draw_line(1, 2, 3, 4)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("\timage.lock()", "\tfalse # image.lock() # TODOConverter40, Image no longer requires locking, `false` helps to not break one line if/else, so it can freely be removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("\timage.unlock()", "\tfalse # image.unlock() # TODOConverter40, Image no longer requires locking, `false` helps to not break one line if/else, so it can freely be removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
@@ -869,24 +869,24 @@ bool ProjectConverter3To4::test_conversion(RegExContainer &reg_container) {
valid = valid && test_conversion_gdscript_builtin("'.a'", "'.a'", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("\t._input(_event)", "\tsuper._input(_event)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("(connect(A,B,C) != OK):", "(connect(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("(connect(A,B,C,D) != OK):", "(connect(A,Callable(B,C).bind(D)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("(connect(A,B,C,[D]) != OK):", "(connect(A,Callable(B,C).bind(D)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("(connect(A,B,C,[D,E]) != OK):", "(connect(A,Callable(B,C).bind(D,E)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("(connect(A,B,C,[D,E],F) != OK):", "(connect(A,Callable(B,C).bind(D,E),F) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("(connect(A,B,C,D,E) != OK):", "(connect(A,Callable(B,C).bind(D),E) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("(connect(A,B,C) != OK):", "(connect(A, Callable(B, C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("(connect(A,B,C,D) != OK):", "(connect(A, Callable(B, C).bind(D)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("(connect(A,B,C,[D]) != OK):", "(connect(A, Callable(B, C).bind(D)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("(connect(A,B,C,[D,E]) != OK):", "(connect(A, Callable(B, C).bind(D,E)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("(connect(A,B,C,[D,E],F) != OK):", "(connect(A, Callable(B, C).bind(D,E), F) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("(connect(A,B,C,D,E) != OK):", "(connect(A, Callable(B, C).bind(D), E) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("(start(A,B) != OK):", "(start(Callable(A,B)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("(start(A,B) != OK):", "(start(Callable(A, B)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("func start(A,B):", "func start(A,B):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("(start(A,B,C,D,E,F,G) != OK):", "(start(Callable(A,B).bind(C),D,E,F,G) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("disconnect(A,B,C) != OK):", "disconnect(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("is_connected(A,B,C) != OK):", "is_connected(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("is_connected(A,B,C))", "is_connected(A,Callable(B,C)))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("(start(A,B,C,D,E,F,G) != OK):", "(start(Callable(A, B).bind(C), D, E, F, G) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("disconnect(A,B,C) != OK):", "disconnect(A, Callable(B, C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("is_connected(A,B,C) != OK):", "is_connected(A, Callable(B, C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("is_connected(A,B,C))", "is_connected(A, Callable(B, C)))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("(tween_method(A,B,C,D,E).foo())", "(tween_method(Callable(A,B),C,D,E).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("(tween_method(A,B,C,D,E,[F,G]).foo())", "(tween_method(Callable(A,B).bind(F,G),C,D,E).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("(tween_callback(A,B).foo())", "(tween_callback(Callable(A,B)).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("(tween_callback(A,B,[C,D]).foo())", "(tween_callback(Callable(A,B).bind(C,D)).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("(tween_method(A,B,C,D,E).foo())", "(tween_method(Callable(A, B), C, D, E).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("(tween_method(A,B,C,D,E,[F,G]).foo())", "(tween_method(Callable(A, B).bind(F,G), C, D, E).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("(tween_callback(A,B).foo())", "(tween_callback(Callable(A, B)).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("(tween_callback(A,B,[C,D]).foo())", "(tween_callback(Callable(A, B).bind(C,D)).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("func _init(", "func _init(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("func _init(p_x:int)->void:", "func _init(p_x:int):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
@@ -899,18 +899,18 @@ bool ProjectConverter3To4::test_conversion(RegExContainer &reg_container) {
valid = valid && test_conversion_gdscript_builtin("create_from_image(aa, bb)", "create_from_image(aa) #,bb", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("q_ImageTexture.create_from_image(variable1, variable2)", "q_ImageTexture.create_from_image(variable1) #,variable2", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("set_cell_item(a, b, c, d ,e) # AA", "set_cell_item( Vector3(a,b,c) ,d,e) # AA", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("set_cell_item(a, b, c, d ,e) # AA", "set_cell_item(Vector3(a, b, c), d, e) # AA", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("set_cell_item(a, b)", "set_cell_item(a, b)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("get_cell_item_orientation(a, b,c)", "get_cell_item_orientation(Vector3i(a,b,c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("get_cell_item(a, b,c)", "get_cell_item(Vector3i(a,b,c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("map_to_world(a, b,c)", "map_to_local(Vector3i(a,b,c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("get_cell_item_orientation(a, b,c)", "get_cell_item_orientation(Vector3i(a, b, c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("get_cell_item(a, b,c)", "get_cell_item(Vector3i(a, b, c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("map_to_world(a, b,c)", "map_to_local(Vector3i(a, b, c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("PackedStringArray(req_godot).join('.')", "'.'.join(PackedStringArray(req_godot))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("=PackedStringArray(req_godot).join('.')", "='.'.join(PackedStringArray(req_godot))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("apply_force(position, impulse)", "apply_force(impulse, position)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("apply_impulse(position, impulse)", "apply_impulse(impulse, position)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("draw_rect(a,b,c,d,e).abc", "draw_rect(a,b,c,d).abc# e) TODOGODOT4 Antialiasing argument is missing", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("draw_rect(a,b,c,d,e).abc", "draw_rect(a, b, c, d).abc# e) TODOGODOT4 Antialiasing argument is missing", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("get_focus_owner()", "get_viewport().gui_get_focus_owner()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("button.pressed = 1", "button.button_pressed = 1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("button.pressed=1", "button.button_pressed=1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
@@ -1264,13 +1264,13 @@ String ProjectConverter3To4::connect_arguments(const Vector<String> &arguments,
String value;
if (arguments.size() > 0 && from != 0 && from < to) {
- value = ",";
+ value = ", ";
}
for (int i = from; i < to; i++) {
value += arguments[i];
if (i != to - 1) {
- value += ',';
+ value += ", ";
}
}
return value;
@@ -1762,7 +1762,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 2) {
- line = line.substr(0, start) + "sort_custom(Callable(" + parts[0] + "," + parts[1] + "))" + line.substr(end + start);
+ line = line.substr(0, start) + "sort_custom(Callable(" + parts[0] + ", " + parts[1] + "))" + line.substr(end + start);
}
}
}
@@ -1776,14 +1776,14 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
}
- // -- draw_line(1,2,3,4,5) -> draw_line(1,2,3,4) CanvasItem
+ // -- draw_line(1,2,3,4,5) -> draw_line(1, 2, 3, 4) CanvasItem
if (line.contains("draw_line(")) {
int start = line.find("draw_line(");
int end = get_end_parenthesis(line.substr(start)) + 1;
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 5) {
- line = line.substr(0, start) + "draw_line(" + parts[0] + "," + parts[1] + "," + parts[2] + "," + parts[3] + ")" + line.substr(end + start);
+ line = line.substr(0, start) + "draw_line(" + parts[0] + ", " + parts[1] + ", " + parts[2] + ", " + parts[3] + ")" + line.substr(end + start);
}
}
}
@@ -1861,7 +1861,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
}
- // -- "(connect(A,B,C,D,E) != OK):", "(connect(A,Callable(B,C).bind(D),E) Object
+ // -- "(connect(A,B,C,D,E) != OK):", "(connect(A, Callable(B, C).bind(D), E) Object
if (line.contains("connect(")) {
int start = line.find("connect(");
// Protection from disconnect
@@ -1870,9 +1870,9 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 3) {
- line = line.substr(0, start) + "connect(" + parts[0] + ",Callable(" + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
+ line = line.substr(0, start) + "connect(" + parts[0] + ", Callable(" + parts[1] + ", " + parts[2] + "))" + line.substr(end + start);
} else if (parts.size() >= 4) {
- line = line.substr(0, start) + "connect(" + parts[0] + ",Callable(" + parts[1] + "," + parts[2] + ").bind(" + parts[3].lstrip("[").rstrip("]") + ")" + connect_arguments(parts, 4) + ")" + line.substr(end + start);
+ line = line.substr(0, start) + "connect(" + parts[0] + ", Callable(" + parts[1] + ", " + parts[2] + ").bind(" + parts[3].lstrip(" [").rstrip("] ") + ")" + connect_arguments(parts, 4) + ")" + line.substr(end + start);
}
}
}
@@ -1884,7 +1884,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 3) {
- line = line.substr(0, start) + "disconnect(" + parts[0] + ",Callable(" + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
+ line = line.substr(0, start) + "disconnect(" + parts[0] + ", Callable(" + parts[1] + ", " + parts[2] + "))" + line.substr(end + start);
}
}
}
@@ -1895,7 +1895,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 3) {
- line = line.substr(0, start) + "is_connected(" + parts[0] + ",Callable(" + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
+ line = line.substr(0, start) + "is_connected(" + parts[0] + ", Callable(" + parts[1] + ", " + parts[2] + "))" + line.substr(end + start);
}
}
}
@@ -1907,9 +1907,9 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 5) {
- line = line.substr(0, start) + "tween_method(Callable(" + parts[0] + "," + parts[1] + ")," + parts[2] + "," + parts[3] + "," + parts[4] + ")" + line.substr(end + start);
+ line = line.substr(0, start) + "tween_method(Callable(" + parts[0] + ", " + parts[1] + "), " + parts[2] + ", " + parts[3] + ", " + parts[4] + ")" + line.substr(end + start);
} else if (parts.size() >= 6) {
- line = line.substr(0, start) + "tween_method(Callable(" + parts[0] + "," + parts[1] + ").bind(" + connect_arguments(parts, 5).substr(1).lstrip("[").rstrip("]") + ")," + parts[2] + "," + parts[3] + "," + parts[4] + ")" + line.substr(end + start);
+ line = line.substr(0, start) + "tween_method(Callable(" + parts[0] + ", " + parts[1] + ").bind(" + connect_arguments(parts, 5).substr(1).lstrip(" [").rstrip("] ") + "), " + parts[2] + ", " + parts[3] + ", " + parts[4] + ")" + line.substr(end + start);
}
}
}
@@ -1920,14 +1920,14 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 2) {
- line = line.substr(0, start) + "tween_callback(Callable(" + parts[0] + "," + parts[1] + "))" + line.substr(end + start);
+ line = line.substr(0, start) + "tween_callback(Callable(" + parts[0] + ", " + parts[1] + "))" + line.substr(end + start);
} else if (parts.size() >= 3) {
- line = line.substr(0, start) + "tween_callback(Callable(" + parts[0] + "," + parts[1] + ").bind(" + connect_arguments(parts, 2).substr(1).lstrip("[").rstrip("]") + "))" + line.substr(end + start);
+ line = line.substr(0, start) + "tween_callback(Callable(" + parts[0] + ", " + parts[1] + ").bind(" + connect_arguments(parts, 2).substr(1).lstrip(" [").rstrip("] ") + "))" + line.substr(end + start);
}
}
}
- // -- start(a,b) -> start(Callable(a,b)) Thread
- // -- start(a,b,c,d) -> start(Callable(a,b).bind(c),d) Thread
+ // -- start(a,b) -> start(Callable(a, b)) Thread
+ // -- start(a,b,c,d) -> start(Callable(a, b).bind(c), d) Thread
if (line.contains("start(")) {
int start = line.find("start(");
int end = get_end_parenthesis(line.substr(start)) + 1;
@@ -1936,9 +1936,9 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 2) {
- line = line.substr(0, start) + "start(Callable(" + parts[0] + "," + parts[1] + "))" + line.substr(end + start);
+ line = line.substr(0, start) + "start(Callable(" + parts[0] + ", " + parts[1] + "))" + line.substr(end + start);
} else if (parts.size() >= 3) {
- line = line.substr(0, start) + "start(Callable(" + parts[0] + "," + parts[1] + ").bind(" + parts[2] + ")" + connect_arguments(parts, 3) + ")" + line.substr(end + start);
+ line = line.substr(0, start) + "start(Callable(" + parts[0] + ", " + parts[1] + ").bind(" + parts[2] + ")" + connect_arguments(parts, 3) + ")" + line.substr(end + start);
}
}
}
@@ -1983,7 +1983,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() > 2) {
- line = line.substr(0, start) + "set_cell_item( Vector3(" + parts[0] + "," + parts[1] + "," + parts[2] + ") " + connect_arguments(parts, 3) + ")" + line.substr(end + start);
+ line = line.substr(0, start) + "set_cell_item(Vector3(" + parts[0] + ", " + parts[1] + ", " + parts[2] + ")" + connect_arguments(parts, 3).lstrip(" ") + ")" + line.substr(end + start);
}
}
}
@@ -1994,7 +1994,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 3) {
- line = line.substr(0, start) + "get_cell_item(Vector3i(" + parts[0] + "," + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
+ line = line.substr(0, start) + "get_cell_item(Vector3i(" + parts[0] + ", " + parts[1] + ", " + parts[2] + "))" + line.substr(end + start);
}
}
}
@@ -2005,7 +2005,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 3) {
- line = line.substr(0, start) + "get_cell_item_orientation(Vector3i(" + parts[0] + "," + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
+ line = line.substr(0, start) + "get_cell_item_orientation(Vector3i(" + parts[0] + ", " + parts[1] + ", " + parts[2] + "))" + line.substr(end + start);
}
}
}
@@ -2038,7 +2038,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 3) {
- line = line.substr(0, start) + "map_to_local(Vector3i(" + parts[0] + "," + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
+ line = line.substr(0, start) + "map_to_local(Vector3i(" + parts[0] + ", " + parts[1] + ", " + parts[2] + "))" + line.substr(end + start);
} else if (parts.size() == 1) {
line = line.substr(0, start) + "map_to_local(" + parts[0] + ")" + line.substr(end + start);
}
@@ -2076,7 +2076,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 5) {
- line = line.substr(0, start) + "draw_rect(" + parts[0] + "," + parts[1] + "," + parts[2] + "," + parts[3] + ")" + line.substr(end + start) + "# " + parts[4] + ") TODOGODOT4 Antialiasing argument is missing";
+ line = line.substr(0, start) + "draw_rect(" + parts[0] + ", " + parts[1] + ", " + parts[2] + ", " + parts[3] + ")" + line.substr(end + start) + "# " + parts[4] + ") TODOGODOT4 Antialiasing argument is missing";
}
}
}
@@ -2229,7 +2229,7 @@ void ProjectConverter3To4::process_csharp_line(String &line, const RegExContaine
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() >= 3) {
- line = line.substr(0, start) + "Connect(" + parts[0] + ",new Callable(" + parts[1] + "," + parts[2] + ")" + connect_arguments(parts, 3) + ")" + line.substr(end + start);
+ line = line.substr(0, start) + "Connect(" + parts[0] + ", new Callable(" + parts[1] + ", " + parts[2] + ")" + connect_arguments(parts, 3) + ")" + line.substr(end + start);
}
}
}
@@ -2241,7 +2241,7 @@ void ProjectConverter3To4::process_csharp_line(String &line, const RegExContaine
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 3) {
- line = line.substr(0, start) + "Disconnect(" + parts[0] + ",new Callable(" + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
+ line = line.substr(0, start) + "Disconnect(" + parts[0] + ", new Callable(" + parts[1] + ", " + parts[2] + "))" + line.substr(end + start);
}
}
}
@@ -2252,7 +2252,7 @@ void ProjectConverter3To4::process_csharp_line(String &line, const RegExContaine
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 3) {
- line = line.substr(0, start) + "IsConnected(" + parts[0] + ",new Callable(" + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
+ line = line.substr(0, start) + "IsConnected(" + parts[0] + ", new Callable(" + parts[1] + ", " + parts[2] + "))" + line.substr(end + start);
}
}
}
diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp
index 5883ec863d..bba11363d5 100644
--- a/modules/gdscript/editor/gdscript_highlighter.cpp
+++ b/modules/gdscript/editor/gdscript_highlighter.cpp
@@ -294,17 +294,27 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
!(str[j] == '_' && (prev_is_digit || str[j - 1] == 'b' || str[j - 1] == 'x' || str[j - 1] == '.')) &&
!(str[j] == 'e' && (prev_is_digit || str[j - 1] == '_')) &&
!(str[j] == '.' && (prev_is_digit || (!prev_is_binary_op && (j > 0 && (str[j - 1] == '-' || str[j - 1] == '+' || str[j - 1] == '~'))))) &&
- !((str[j] == '-' || str[j] == '+' || str[j] == '~') && !prev_is_binary_op && str[j - 1] != 'e')) {
- /* This condition continues Number highlighting in special cases.
- 1st row: '+' or '-' after scientific notation;
+ !((str[j] == '-' || str[j] == '+' || str[j] == '~') && !is_binary_op && !prev_is_binary_op && str[j - 1] != 'e')) {
+ /* This condition continues number highlighting in special cases.
+ 1st row: '+' or '-' after scientific notation (like 3e-4);
2nd row: '_' as a numeric separator;
3rd row: Scientific notation 'e' and floating points;
4th row: Floating points inside the number, or leading if after a unary mathematical operator;
- 5th row: Multiple unary mathematical operators */
+ 5th row: Multiple unary mathematical operators (like ~-7)*/
in_number = false;
}
- } else if (!is_binary_op && (str[j] == '-' || str[j] == '+' || str[j] == '~' || (str[j] == '.' && str[j + 1] != '.' && (j == 0 || (j > 0 && str[j - 1] != '.'))))) {
+ } else if (str[j] == '.' && !is_binary_op && is_digit(str[j + 1]) && (j == 0 || (j > 0 && str[j - 1] != '.'))) {
+ // Start number highlighting from leading decimal points (like .42)
in_number = true;
+ } else if ((str[j] == '-' || str[j] == '+' || str[j] == '~') && !is_binary_op) {
+ // Only start number highlighting on unary operators if a digit follows them.
+ int non_op = j + 1;
+ while (str[non_op] == '-' || str[non_op] == '+' || str[non_op] == '~') {
+ non_op++;
+ }
+ if (is_digit(str[non_op]) || (str[non_op] == '.' && non_op < line_length && is_digit(str[non_op + 1]))) {
+ in_number = true;
+ }
}
if (!in_word && is_unicode_identifier_start(str[j]) && !in_number) {
diff --git a/modules/gltf/doc_classes/GLTFNode.xml b/modules/gltf/doc_classes/GLTFNode.xml
index 0b84eb15c0..853af99257 100644
--- a/modules/gltf/doc_classes/GLTFNode.xml
+++ b/modules/gltf/doc_classes/GLTFNode.xml
@@ -5,6 +5,7 @@
</brief_description>
<description>
Represents a GLTF node. GLTF nodes may have names, transforms, children (other GLTF nodes), and more specialized properties (represented by their own classes).
+ GLTF nodes generally exist inside of [GLTFState] which represents all data of a GLTF file. Most of GLTFNode's properties are indices of other data in the GLTF file. You can extend a GLTF node with additional properties by using [method get_additional_data] and [method set_additional_data].
</description>
<tutorials>
<link title="GLTF scene and node spec">https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_004_ScenesNodes.md"</link>
@@ -30,28 +31,40 @@
</methods>
<members>
<member name="camera" type="int" setter="set_camera" getter="get_camera" default="-1">
+ If this GLTF node is a camera, the index of the [GLTFCamera] in the [GLTFState] that describes the camera's properties. If -1, this node is not a camera.
</member>
<member name="children" type="PackedInt32Array" setter="set_children" getter="get_children" default="PackedInt32Array()">
+ The indices of the children nodes in the [GLTFState]. If this GLTF node has no children, this will be an empty array.
</member>
<member name="height" type="int" setter="set_height" getter="get_height" default="-1">
+ How deep into the node hierarchy this node is. A root node will have a height of 0, its children will have a height of 1, and so on. If -1, the height has not been calculated.
</member>
<member name="light" type="int" setter="set_light" getter="get_light" default="-1">
+ If this GLTF node is a light, the index of the [GLTFLight] in the [GLTFState] that describes the light's properties. If -1, this node is not a light.
</member>
<member name="mesh" type="int" setter="set_mesh" getter="get_mesh" default="-1">
+ If this GLTF node is a mesh, the index of the [GLTFMesh] in the [GLTFState] that describes the mesh's properties. If -1, this node is not a mesh.
</member>
<member name="parent" type="int" setter="set_parent" getter="get_parent" default="-1">
+ The index of the parent node in the [GLTFState]. If -1, this node is a root node.
</member>
<member name="position" type="Vector3" setter="set_position" getter="get_position" default="Vector3(0, 0, 0)">
+ The position of the GLTF node relative to its parent.
</member>
<member name="rotation" type="Quaternion" setter="set_rotation" getter="get_rotation" default="Quaternion(0, 0, 0, 1)">
+ The rotation of the GLTF node relative to its parent.
</member>
<member name="scale" type="Vector3" setter="set_scale" getter="get_scale" default="Vector3(1, 1, 1)">
+ The scale of the GLTF node relative to its parent.
</member>
<member name="skeleton" type="int" setter="set_skeleton" getter="get_skeleton" default="-1">
+ If this GLTF node has a skeleton, the index of the [GLTFSkeleton] in the [GLTFState] that describes the skeleton's properties. If -1, this node does not have a skeleton.
</member>
<member name="skin" type="int" setter="set_skin" getter="get_skin" default="-1">
+ If this GLTF node has a skin, the index of the [GLTFSkin] in the [GLTFState] that describes the skin's properties. If -1, this node does not have a skin.
</member>
<member name="xform" type="Transform3D" setter="set_xform" getter="get_xform" default="Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)">
+ The transform of the GLTF node relative to its parent. This property is usually unused since the position, rotation, and scale properties are preferred.
</member>
</members>
</class>
diff --git a/modules/gltf/doc_classes/GLTFState.xml b/modules/gltf/doc_classes/GLTFState.xml
index 7f14bdd4c3..b3823ef970 100644
--- a/modules/gltf/doc_classes/GLTFState.xml
+++ b/modules/gltf/doc_classes/GLTFState.xml
@@ -1,8 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="GLTFState" inherits="Resource" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
+ Represents all data of a GLTF file.
</brief_description>
<description>
+ Contains all nodes and resources of a GLTF file. This is used by [GLTFDocument] as data storage, which allows [GLTFDocument] and all [GLTFDocumentExtension] classes to remain stateless.
+ GLTFState can be populated by [GLTFDocument] reading a file or by converting a Godot scene. Then the data can either be used to create a Godot scene or save to a GLTF file. The code that converts to/from a Godot scene can be intercepted at arbitrary points by [GLTFDocumentExtension] classes. This allows for custom data to be stored in the GLTF file or for custom data to be converted to/from Godot nodes.
</description>
<tutorials>
</tutorials>
@@ -32,17 +35,20 @@
<return type="AnimationPlayer" />
<param index="0" name="idx" type="int" />
<description>
+ Returns the [AnimationPlayer] node with the given index. These nodes are only used during the export process when converting Godot [AnimationPlayer] nodes to GLTF animations.
</description>
</method>
<method name="get_animation_players_count">
<return type="int" />
<param index="0" name="idx" type="int" />
<description>
+ Returns the number of [AnimationPlayer] nodes in this [GLTFState]. These nodes are only used during the export process when converting Godot [AnimationPlayer] nodes to GLTF animations.
</description>
</method>
<method name="get_animations">
<return type="GLTFAnimation[]" />
<description>
+ Returns an array of all [GLTFAnimation]s in the GLTF file. When importing, these will be generated as animations in an [AnimationPlayer] node. When exporting, these will be generated from Godot [AnimationPlayer] nodes.
</description>
</method>
<method name="get_buffer_views">
@@ -53,6 +59,7 @@
<method name="get_cameras">
<return type="GLTFCamera[]" />
<description>
+ Returns an array of all [GLTFCamera]s in the GLTF file. These are the cameras that the [member GLTFNode.camera] index refers to.
</description>
</method>
<method name="get_handle_binary_image">
@@ -68,6 +75,7 @@
<method name="get_lights">
<return type="GLTFLight[]" />
<description>
+ Returns an array of all [GLTFLight]s in the GLTF file. These are the lights that the [member GLTFNode.light] index refers to.
</description>
</method>
<method name="get_materials">
@@ -78,27 +86,32 @@
<method name="get_meshes">
<return type="GLTFMesh[]" />
<description>
+ Returns an array of all [GLTFMesh]es in the GLTF file. These are the meshes that the [member GLTFNode.mesh] index refers to.
</description>
</method>
<method name="get_nodes">
<return type="GLTFNode[]" />
<description>
+ Returns an array of all [GLTFNode]s in the GLTF file. These are the nodes that [member GLTFNode.children] and [member root_nodes] refer to. This includes nodes that may not be generated in the Godot scene, or nodes that may generate multiple Godot scene nodes.
</description>
</method>
<method name="get_scene_node">
<return type="Node" />
<param index="0" name="idx" type="int" />
<description>
+ Returns the Godot scene node that corresponds to the same index as the [GLTFNode] it was generated from. Not every [GLTFNode] will have a scene node generated, and not every generated scene node will have a corresponding [GLTFNode].
</description>
</method>
<method name="get_skeletons">
<return type="GLTFSkeleton[]" />
<description>
+ Returns an array of all [GLTFSkeleton]s in the GLTF file. These are the skeletons that the [member GLTFNode.skeleton] index refers to.
</description>
</method>
<method name="get_skins">
<return type="GLTFSkin[]" />
<description>
+ Returns an array of all [GLTFSkin]s in the GLTF file. These are the skins that the [member GLTFNode.skin] index refers to.
</description>
</method>
<method name="get_texture_samplers">
@@ -115,11 +128,13 @@
<method name="get_unique_animation_names">
<return type="String[]" />
<description>
+ Returns an array of unique animation names. This is only used during the import process.
</description>
</method>
<method name="get_unique_names">
<return type="String[]" />
<description>
+ Returns an array of unique node names. This is used in both the import process and export process.
</description>
</method>
<method name="set_accessors">
@@ -141,6 +156,7 @@
<return type="void" />
<param index="0" name="animations" type="GLTFAnimation[]" />
<description>
+ Sets the [GLTFAnimation]s in the state. When importing, these will be generated as animations in an [AnimationPlayer] node. When exporting, these will be generated from Godot [AnimationPlayer] nodes.
</description>
</method>
<method name="set_buffer_views">
@@ -153,6 +169,7 @@
<return type="void" />
<param index="0" name="cameras" type="GLTFCamera[]" />
<description>
+ Sets the [GLTFCamera]s in the state. These are the cameras that the [member GLTFNode.camera] index refers to.
</description>
</method>
<method name="set_handle_binary_image">
@@ -171,6 +188,7 @@
<return type="void" />
<param index="0" name="lights" type="GLTFLight[]" />
<description>
+ Sets the [GLTFLight]s in the state. These are the lights that the [member GLTFNode.light] index refers to.
</description>
</method>
<method name="set_materials">
@@ -183,24 +201,28 @@
<return type="void" />
<param index="0" name="meshes" type="GLTFMesh[]" />
<description>
+ Sets the [GLTFMesh]es in the state. These are the meshes that the [member GLTFNode.mesh] index refers to.
</description>
</method>
<method name="set_nodes">
<return type="void" />
<param index="0" name="nodes" type="GLTFNode[]" />
<description>
+ Sets the [GLTFNode]s in the state. These are the nodes that [member GLTFNode.children] and [member root_nodes] refer to. Some of the nodes set here may not be generated in the Godot scene, or may generate multiple Godot scene nodes.
</description>
</method>
<method name="set_skeletons">
<return type="void" />
<param index="0" name="skeletons" type="GLTFSkeleton[]" />
<description>
+ Sets the [GLTFSkeleton]s in the state. These are the skeletons that the [member GLTFNode.skeleton] index refers to.
</description>
</method>
<method name="set_skins">
<return type="void" />
<param index="0" name="skins" type="GLTFSkin[]" />
<description>
+ Sets the [GLTFSkin]s in the state. These are the skins that the [member GLTFNode.skin] index refers to.
</description>
</method>
<method name="set_texture_samplers">
@@ -220,12 +242,14 @@
<return type="void" />
<param index="0" name="unique_animation_names" type="String[]" />
<description>
+ Sets the unique animation names in the state. This is only used during the import process.
</description>
</method>
<method name="set_unique_names">
<return type="void" />
<param index="0" name="unique_names" type="String[]" />
<description>
+ Sets the unique node names in the state. This is used in both the import process and export process.
</description>
</method>
</methods>
@@ -245,8 +269,10 @@
<member name="minor_version" type="int" setter="set_minor_version" getter="get_minor_version" default="0">
</member>
<member name="root_nodes" type="PackedInt32Array" setter="set_root_nodes" getter="get_root_nodes" default="PackedInt32Array()">
+ The root nodes of the GLTF file. Typically, a GLTF file will only have one scene, and therefore one root node. However, a GLTF file may have multiple scenes and therefore multiple root nodes, which will be generated as siblings of each other and as children of the root node of the generated Godot scene.
</member>
<member name="scene_name" type="String" setter="set_scene_name" getter="get_scene_name" default="&quot;&quot;">
+ The name of the scene. When importing, if not specified, this will be the file name. When exporting, if specified, the scene name will be saved to the GLTF file.
</member>
<member name="use_named_skin_binds" type="bool" setter="set_use_named_skin_binds" getter="get_use_named_skin_binds" default="false">
</member>
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index 007f439a89..2a29d86ec6 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -386,6 +386,8 @@ int64_t TextServerAdvanced::_get_features() const {
void TextServerAdvanced::_free_rid(const RID &p_rid) {
_THREAD_SAFE_METHOD_
if (font_owner.owns(p_rid)) {
+ MutexLock ftlock(ft_mutex);
+
FontAdvanced *fd = font_owner.get_or_null(p_rid);
{
MutexLock lock(fd->mutex);
@@ -1321,45 +1323,48 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_f
// Init dynamic font.
#ifdef MODULE_FREETYPE_ENABLED
int error = 0;
- if (!ft_library) {
- error = FT_Init_FreeType(&ft_library);
- if (error != 0) {
- memdelete(fd);
- ERR_FAIL_V_MSG(false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");
- }
+ {
+ MutexLock ftlock(ft_mutex);
+ if (!ft_library) {
+ error = FT_Init_FreeType(&ft_library);
+ if (error != 0) {
+ memdelete(fd);
+ ERR_FAIL_V_MSG(false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");
+ }
#ifdef MODULE_SVG_ENABLED
- FT_Property_Set(ft_library, "ot-svg", "svg-hooks", get_tvg_svg_in_ot_hooks());
+ FT_Property_Set(ft_library, "ot-svg", "svg-hooks", get_tvg_svg_in_ot_hooks());
#endif
- }
-
- memset(&fd->stream, 0, sizeof(FT_StreamRec));
- fd->stream.base = (unsigned char *)p_font_data->data_ptr;
- fd->stream.size = p_font_data->data_size;
- fd->stream.pos = 0;
-
- FT_Open_Args fargs;
- memset(&fargs, 0, sizeof(FT_Open_Args));
- fargs.memory_base = (unsigned char *)p_font_data->data_ptr;
- fargs.memory_size = p_font_data->data_size;
- fargs.flags = FT_OPEN_MEMORY;
- fargs.stream = &fd->stream;
+ }
- int max_index = 0;
- FT_Face tmp_face = nullptr;
- error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face);
- if (tmp_face && error == 0) {
- max_index = tmp_face->num_faces - 1;
- }
- if (tmp_face) {
- FT_Done_Face(tmp_face);
- }
+ memset(&fd->stream, 0, sizeof(FT_StreamRec));
+ fd->stream.base = (unsigned char *)p_font_data->data_ptr;
+ fd->stream.size = p_font_data->data_size;
+ fd->stream.pos = 0;
+
+ FT_Open_Args fargs;
+ memset(&fargs, 0, sizeof(FT_Open_Args));
+ fargs.memory_base = (unsigned char *)p_font_data->data_ptr;
+ fargs.memory_size = p_font_data->data_size;
+ fargs.flags = FT_OPEN_MEMORY;
+ fargs.stream = &fd->stream;
+
+ int max_index = 0;
+ FT_Face tmp_face = nullptr;
+ error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face);
+ if (tmp_face && error == 0) {
+ max_index = tmp_face->num_faces - 1;
+ }
+ if (tmp_face) {
+ FT_Done_Face(tmp_face);
+ }
- error = FT_Open_Face(ft_library, &fargs, CLAMP(p_font_data->face_index, 0, max_index), &fd->face);
- 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)) + "'.");
+ error = FT_Open_Face(ft_library, &fargs, CLAMP(p_font_data->face_index, 0, max_index), &fd->face);
+ 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)) + "'.");
+ }
}
if (p_font_data->msdf) {
@@ -1786,6 +1791,8 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_f
}
_FORCE_INLINE_ void TextServerAdvanced::_font_clear_cache(FontAdvanced *p_font_data) {
+ MutexLock ftlock(ft_mutex);
+
for (const KeyValue<Vector2i, FontForSizeAdvanced *> &E : p_font_data->cache) {
memdelete(E.value);
}
@@ -1892,6 +1899,8 @@ int64_t TextServerAdvanced::_font_get_face_count(const RID &p_font_rid) const {
fargs.flags = FT_OPEN_MEMORY;
fargs.stream = &stream;
+ MutexLock ftlock(ft_mutex);
+
FT_Face tmp_face = nullptr;
error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face);
if (error == 0) {
@@ -2283,6 +2292,7 @@ void TextServerAdvanced::_font_clear_size_cache(const RID &p_font_rid) {
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
+ MutexLock ftlock(ft_mutex);
for (const KeyValue<Vector2i, FontForSizeAdvanced *> &E : fd->cache) {
memdelete(E.value);
}
@@ -2294,6 +2304,7 @@ void TextServerAdvanced::_font_remove_size_cache(const RID &p_font_rid, const Ve
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
+ MutexLock ftlock(ft_mutex);
if (fd->cache.has(p_size)) {
memdelete(fd->cache[p_size]);
fd->cache.erase(p_size);
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index f092fa8cca..ce08cf7694 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -616,6 +616,8 @@ class TextServerAdvanced : public TextServerExtension {
_FORCE_INLINE_ void _add_featuers(const Dictionary &p_source, Vector<hb_feature_t> &r_ftrs);
+ Mutex ft_mutex;
+
// HarfBuzz bitmap font interface.
static hb_font_funcs_t *funcs;
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index 240ae8310a..e94b330d33 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -113,6 +113,8 @@ int64_t TextServerFallback::_get_features() const {
void TextServerFallback::_free_rid(const RID &p_rid) {
_THREAD_SAFE_METHOD_
if (font_owner.owns(p_rid)) {
+ MutexLock ftlock(ft_mutex);
+
FontFallback *fd = font_owner.get_or_null(p_rid);
{
MutexLock lock(fd->mutex);
@@ -760,45 +762,48 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontFallback *p_f
// Init dynamic font.
#ifdef MODULE_FREETYPE_ENABLED
int error = 0;
- if (!ft_library) {
- error = FT_Init_FreeType(&ft_library);
- if (error != 0) {
- memdelete(fd);
- ERR_FAIL_V_MSG(false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");
- }
+ {
+ MutexLock ftlock(ft_mutex);
+ if (!ft_library) {
+ error = FT_Init_FreeType(&ft_library);
+ if (error != 0) {
+ memdelete(fd);
+ ERR_FAIL_V_MSG(false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");
+ }
#ifdef MODULE_SVG_ENABLED
- FT_Property_Set(ft_library, "ot-svg", "svg-hooks", get_tvg_svg_in_ot_hooks());
+ FT_Property_Set(ft_library, "ot-svg", "svg-hooks", get_tvg_svg_in_ot_hooks());
#endif
- }
-
- memset(&fd->stream, 0, sizeof(FT_StreamRec));
- fd->stream.base = (unsigned char *)p_font_data->data_ptr;
- fd->stream.size = p_font_data->data_size;
- fd->stream.pos = 0;
-
- FT_Open_Args fargs;
- memset(&fargs, 0, sizeof(FT_Open_Args));
- fargs.memory_base = (unsigned char *)p_font_data->data_ptr;
- fargs.memory_size = p_font_data->data_size;
- fargs.flags = FT_OPEN_MEMORY;
- fargs.stream = &fd->stream;
+ }
- int max_index = 0;
- FT_Face tmp_face = nullptr;
- error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face);
- if (tmp_face && error == 0) {
- max_index = tmp_face->num_faces - 1;
- }
- if (tmp_face) {
- FT_Done_Face(tmp_face);
- }
+ memset(&fd->stream, 0, sizeof(FT_StreamRec));
+ fd->stream.base = (unsigned char *)p_font_data->data_ptr;
+ fd->stream.size = p_font_data->data_size;
+ fd->stream.pos = 0;
+
+ FT_Open_Args fargs;
+ memset(&fargs, 0, sizeof(FT_Open_Args));
+ fargs.memory_base = (unsigned char *)p_font_data->data_ptr;
+ fargs.memory_size = p_font_data->data_size;
+ fargs.flags = FT_OPEN_MEMORY;
+ fargs.stream = &fd->stream;
+
+ int max_index = 0;
+ FT_Face tmp_face = nullptr;
+ error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face);
+ if (tmp_face && error == 0) {
+ max_index = tmp_face->num_faces - 1;
+ }
+ if (tmp_face) {
+ FT_Done_Face(tmp_face);
+ }
- error = FT_Open_Face(ft_library, &fargs, CLAMP(p_font_data->face_index, 0, max_index), &fd->face);
- 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)) + "'.");
+ error = FT_Open_Face(ft_library, &fargs, CLAMP(p_font_data->face_index, 0, max_index), &fd->face);
+ 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)) + "'.");
+ }
}
if (p_font_data->msdf) {
@@ -907,6 +912,8 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontFallback *p_f
}
_FORCE_INLINE_ void TextServerFallback::_font_clear_cache(FontFallback *p_font_data) {
+ MutexLock ftlock(ft_mutex);
+
for (const KeyValue<Vector2i, FontForSizeFallback *> &E : p_font_data->cache) {
memdelete(E.value);
}
@@ -1010,6 +1017,8 @@ int64_t TextServerFallback::_font_get_face_count(const RID &p_font_rid) const {
fargs.flags = FT_OPEN_MEMORY;
fargs.stream = &stream;
+ MutexLock ftlock(ft_mutex);
+
FT_Face tmp_face = nullptr;
error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face);
if (error == 0) {
@@ -1391,6 +1400,7 @@ void TextServerFallback::_font_clear_size_cache(const RID &p_font_rid) {
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
+ MutexLock ftlock(ft_mutex);
for (const KeyValue<Vector2i, FontForSizeFallback *> &E : fd->cache) {
memdelete(E.value);
}
@@ -1402,6 +1412,7 @@ void TextServerFallback::_font_remove_size_cache(const RID &p_font_rid, const Ve
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
+ MutexLock ftlock(ft_mutex);
if (fd->cache.has(p_size)) {
memdelete(fd->cache[p_size]);
fd->cache.erase(p_size);
diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h
index 12ed21ee95..d9e471154d 100644
--- a/modules/text_server_fb/text_server_fb.h
+++ b/modules/text_server_fb/text_server_fb.h
@@ -531,6 +531,8 @@ class TextServerFallback : public TextServerExtension {
void _realign(ShapedTextDataFallback *p_sd) const;
+ Mutex ft_mutex;
+
protected:
static void _bind_methods(){};
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index 1721bcde3b..ba361c2656 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -1391,9 +1391,13 @@ void CharacterBody2D::_move_and_slide_floating(double p_delta) {
first_slide = false;
}
}
+void CharacterBody2D::apply_floor_snap() {
+ _apply_floor_snap();
+}
-void CharacterBody2D::_snap_on_floor(bool p_was_on_floor, bool p_vel_dir_facing_up, bool p_wall_as_floor) {
- if (on_floor || !p_was_on_floor || p_vel_dir_facing_up) {
+// Method that avoids the p_wall_as_floor parameter for the public method.
+void CharacterBody2D::_apply_floor_snap(bool p_wall_as_floor) {
+ if (on_floor) {
return;
}
@@ -1428,6 +1432,14 @@ void CharacterBody2D::_snap_on_floor(bool p_was_on_floor, bool p_vel_dir_facing_
}
}
+void CharacterBody2D::_snap_on_floor(bool p_was_on_floor, bool p_vel_dir_facing_up, bool p_wall_as_floor) {
+ if (on_floor || !p_was_on_floor || p_vel_dir_facing_up) {
+ return;
+ }
+
+ _apply_floor_snap(p_wall_as_floor);
+}
+
bool CharacterBody2D::_on_floor_if_snapped(bool p_was_on_floor, bool p_vel_dir_facing_up) {
if (up_direction == Vector2() || on_floor || !p_was_on_floor || p_vel_dir_facing_up) {
return false;
@@ -1699,6 +1711,7 @@ void CharacterBody2D::_notification(int p_what) {
void CharacterBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("move_and_slide"), &CharacterBody2D::move_and_slide);
+ ClassDB::bind_method(D_METHOD("apply_floor_snap"), &CharacterBody2D::apply_floor_snap);
ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &CharacterBody2D::set_velocity);
ClassDB::bind_method(D_METHOD("get_velocity"), &CharacterBody2D::get_velocity);
diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h
index 53bc5b7cd3..c4eb77d861 100644
--- a/scene/2d/physics_body_2d.h
+++ b/scene/2d/physics_body_2d.h
@@ -337,6 +337,7 @@ public:
PLATFORM_ON_LEAVE_DO_NOTHING,
};
bool move_and_slide();
+ void apply_floor_snap();
const Vector2 &get_velocity() const;
void set_velocity(const Vector2 &p_velocity);
@@ -446,6 +447,7 @@ private:
void set_up_direction(const Vector2 &p_up_direction);
void _set_collision_direction(const PhysicsServer2D::MotionResult &p_result);
void _set_platform_data(const PhysicsServer2D::MotionResult &p_result);
+ void _apply_floor_snap(bool p_wall_as_floor = false);
void _snap_on_floor(bool p_was_on_floor, bool p_vel_dir_facing_up, bool p_wall_as_floor = false);
protected:
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index c8cfcf7d7a..ab5b054bb3 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -1565,8 +1565,8 @@ void CharacterBody3D::_move_and_slide_floating(double p_delta) {
}
}
-void CharacterBody3D::_snap_on_floor(bool p_was_on_floor, bool p_vel_dir_facing_up) {
- if (collision_state.floor || !p_was_on_floor || p_vel_dir_facing_up) {
+void CharacterBody3D::apply_floor_snap() {
+ if (collision_state.floor) {
return;
}
@@ -1601,6 +1601,14 @@ void CharacterBody3D::_snap_on_floor(bool p_was_on_floor, bool p_vel_dir_facing_
}
}
+void CharacterBody3D::_snap_on_floor(bool p_was_on_floor, bool p_vel_dir_facing_up) {
+ if (collision_state.floor || !p_was_on_floor || p_vel_dir_facing_up) {
+ return;
+ }
+
+ apply_floor_snap();
+}
+
bool CharacterBody3D::_on_floor_if_snapped(bool p_was_on_floor, bool p_vel_dir_facing_up) {
if (up_direction == Vector3() || collision_state.floor || !p_was_on_floor || p_vel_dir_facing_up) {
return false;
@@ -1954,6 +1962,7 @@ void CharacterBody3D::_notification(int p_what) {
void CharacterBody3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("move_and_slide"), &CharacterBody3D::move_and_slide);
+ ClassDB::bind_method(D_METHOD("apply_floor_snap"), &CharacterBody3D::apply_floor_snap);
ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &CharacterBody3D::set_velocity);
ClassDB::bind_method(D_METHOD("get_velocity"), &CharacterBody3D::get_velocity);
diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h
index 92d4726bb5..d141c1aaa2 100644
--- a/scene/3d/physics_body_3d.h
+++ b/scene/3d/physics_body_3d.h
@@ -354,6 +354,7 @@ public:
PLATFORM_ON_LEAVE_DO_NOTHING,
};
bool move_and_slide();
+ void apply_floor_snap();
const Vector3 &get_velocity() const;
void set_velocity(const Vector3 &p_velocity);
diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp
index 9d1118e0ef..e05c24ae09 100644
--- a/scene/animation/tween.cpp
+++ b/scene/animation/tween.cpp
@@ -489,6 +489,11 @@ Tween::Tween(bool p_valid) {
}
Ref<PropertyTweener> PropertyTweener::from(Variant p_value) {
+ ERR_FAIL_COND_V(tween.is_null(), nullptr);
+ if (!tween->_validate_type_match(p_value, final_val)) {
+ return nullptr;
+ }
+
initial_val = p_value;
do_continue = false;
return this;
diff --git a/scene/animation/tween.h b/scene/animation/tween.h
index c5abcb28a6..b7dc941111 100644
--- a/scene/animation/tween.h
+++ b/scene/animation/tween.h
@@ -61,6 +61,8 @@ class MethodTweener;
class Tween : public RefCounted {
GDCLASS(Tween, RefCounted);
+ friend class PropertyTweener;
+
public:
enum TweenProcessMode {
TWEEN_PROCESS_PHYSICS,
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index 0f7985bee6..f6e224aca0 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -1458,6 +1458,9 @@ Error FontFile::load_bitmap_font(const String &p_path) {
}
if (ch[i] == 1 && first_ol_ch == -1) {
first_ol_ch = i;
+ if (outline == 0) {
+ outline = 1;
+ }
}
if (ch[i] == 2 && first_cm_ch == -1) {
first_cm_ch = i;
@@ -1747,6 +1750,9 @@ Error FontFile::load_bitmap_font(const String &p_path) {
}
if (ch[i] == 1 && first_ol_ch == -1) {
first_ol_ch = i;
+ if (outline == 0) {
+ outline = 1;
+ }
}
if (ch[i] == 2 && first_cm_ch == -1) {
first_cm_ch = i;
diff --git a/servers/xr_server.cpp b/servers/xr_server.cpp
index 85ef684d40..bab8e9ae4b 100644
--- a/servers/xr_server.cpp
+++ b/servers/xr_server.cpp
@@ -52,11 +52,14 @@ XRServer *XRServer::get_singleton() {
void XRServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_world_scale"), &XRServer::get_world_scale);
ClassDB::bind_method(D_METHOD("set_world_scale", "scale"), &XRServer::set_world_scale);
+ ClassDB::bind_method(D_METHOD("get_world_origin"), &XRServer::get_world_origin);
+ ClassDB::bind_method(D_METHOD("set_world_origin", "world_origin"), &XRServer::set_world_origin);
ClassDB::bind_method(D_METHOD("get_reference_frame"), &XRServer::get_reference_frame);
ClassDB::bind_method(D_METHOD("center_on_hmd", "rotation_mode", "keep_height"), &XRServer::center_on_hmd);
ClassDB::bind_method(D_METHOD("get_hmd_transform"), &XRServer::get_hmd_transform);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "world_scale"), "set_world_scale", "get_world_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "world_origin"), "set_world_origin", "get_world_origin");
ClassDB::bind_method(D_METHOD("add_interface", "interface"), &XRServer::add_interface);
ClassDB::bind_method(D_METHOD("get_interface_count"), &XRServer::get_interface_count);