summaryrefslogtreecommitdiffstats
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/csg/icons/CSGBox3D.svg2
-rw-r--r--modules/csg/icons/CSGCapsule3D.svg2
-rw-r--r--modules/csg/icons/CSGCombiner3D.svg2
-rw-r--r--modules/csg/icons/CSGCylinder3D.svg2
-rw-r--r--modules/csg/icons/CSGMesh3D.svg2
-rw-r--r--modules/csg/icons/CSGPolygon3D.svg2
-rw-r--r--modules/csg/icons/CSGSphere3D.svg2
-rw-r--r--modules/csg/icons/CSGTorus3D.svg2
-rw-r--r--modules/gdscript/gdscript.cpp226
-rw-r--r--modules/gdscript/gdscript.h2
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp50
-rw-r--r--modules/gdscript/gdscript_cache.cpp10
-rw-r--r--modules/gdscript/gdscript_cache.h1
-rw-r--r--modules/gdscript/gdscript_compiler.cpp8
-rw-r--r--modules/gdscript/gdscript_editor.cpp27
-rw-r--r--modules/gdscript/gdscript_parser.cpp22
-rw-r--r--modules/gdscript/gdscript_parser.h3
-rw-r--r--modules/gdscript/gdscript_warning.cpp4
-rw-r--r--modules/gdscript/gdscript_warning.h2
-rw-r--r--modules/gdscript/icons/GDScript.svg2
-rw-r--r--modules/gdscript/icons/GDScriptInternal.svg2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/warnings/confusable_capture_reassignment.gd23
-rw-r--r--modules/gdscript/tests/scripts/analyzer/warnings/confusable_capture_reassignment.out19
-rw-r--r--modules/gdscript/tests/scripts/parser/features/lambda_ends_with_new_line.gd1
-rw-r--r--modules/glslang/register_types.cpp1
-rw-r--r--modules/gridmap/editor/grid_map_editor_plugin.cpp21
-rw-r--r--modules/gridmap/icons/GridMap.svg2
-rw-r--r--modules/mono/icons/BuildCSharp.svg2
-rw-r--r--modules/mono/icons/CSharpScript.svg2
-rw-r--r--modules/navigation/nav_map.cpp7
-rw-r--r--modules/navigation/nav_region.cpp17
-rw-r--r--modules/navigation/nav_utils.h6
-rw-r--r--modules/noise/icons/NoiseTexture2D.svg2
-rw-r--r--modules/noise/icons/NoiseTexture3D.svg2
-rw-r--r--modules/openxr/openxr_api.cpp140
-rw-r--r--modules/openxr/openxr_api.h12
-rw-r--r--modules/regex/icons/RegEx.svg2
-rw-r--r--modules/regex/icons/RegExMatch.svg2
-rw-r--r--modules/webxr/doc_classes/WebXRInterface.xml17
-rw-r--r--modules/webxr/godot_webxr.h2
-rw-r--r--modules/webxr/native/library_godot_webxr.js8
-rw-r--r--modules/webxr/native/webxr.externs.js10
-rw-r--r--modules/webxr/webxr_interface_js.cpp62
-rw-r--r--modules/webxr/webxr_interface_js.h8
44 files changed, 458 insertions, 285 deletions
diff --git a/modules/csg/icons/CSGBox3D.svg b/modules/csg/icons/CSGBox3D.svg
index d425180cf5..ad3e490dcf 100644
--- a/modules/csg/icons/CSGBox3D.svg
+++ b/modules/csg/icons/CSGBox3D.svg
@@ -1 +1 @@
-<svg height="16" width="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><mask id="a"><path d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z" fill="#fefefe"/></mask><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/><path d="m8 2 6 3v6l-6 3-6-3V5zm0 12V8l6-3M8 8 2 5" fill="none" stroke-width="2" stroke="#fc7f7f" mask="url(#a)"/></svg>
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><mask id="a"><path fill="#fefefe" d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z"/></mask><path fill="#5fb2ff" d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z"/><path fill="none" stroke="#fc7f7f" stroke-width="2" d="m8 2 6 3v6l-6 3-6-3V5zm0 12V8l6-3M8 8 2 5" mask="url(#a)"/></svg> \ No newline at end of file
diff --git a/modules/csg/icons/CSGCapsule3D.svg b/modules/csg/icons/CSGCapsule3D.svg
index 3c2657999c..54a5e3d698 100644
--- a/modules/csg/icons/CSGCapsule3D.svg
+++ b/modules/csg/icons/CSGCapsule3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><mask id="a"><path d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z" fill="#fefefe"/></mask><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/><path d="M4 6a4 4 0 0 1 8 0v4a4 4 0 0 1-8 0zm0 1.25a2.5 1 0 0 0 8 0m-4-5v12" fill="none" stroke-width="2" stroke="#fc7f7f" mask="url(#a)"/></svg>
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><mask id="a"><path fill="#fefefe" d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z"/></mask><path fill="#5fb2ff" d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z"/><path fill="none" stroke="#fc7f7f" stroke-width="2" d="M4 6a4 4 0 0 1 8 0v4a4 4 0 0 1-8 0zm0 1.25a2.5 1 0 0 0 8 0m-4-5v12" mask="url(#a)"/></svg> \ No newline at end of file
diff --git a/modules/csg/icons/CSGCombiner3D.svg b/modules/csg/icons/CSGCombiner3D.svg
index 8598897e92..e65bb1c081 100644
--- a/modules/csg/icons/CSGCombiner3D.svg
+++ b/modules/csg/icons/CSGCombiner3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/><path d="M3 1a2 2 0 0 0-2 2h2zm2 0v2h2V1zm4 0v2h2V1zm4 0v2h2a2 2 0 0 0-2-2zM1 5v2h2V5zm12 0v2h2V5zM1 9v2h2V9zm0 4a2 2 0 0 0 2 2v-2zm4 0v2h2v-2z" fill="#fc7f7f"/></svg>
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#5fb2ff" d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z"/><path fill="#fc7f7f" d="M3 1a2 2 0 0 0-2 2h2zm2 0v2h2V1zm4 0v2h2V1zm4 0v2h2a2 2 0 0 0-2-2zM1 5v2h2V5zm12 0v2h2V5zM1 9v2h2V9zm0 4a2 2 0 0 0 2 2v-2zm4 0v2h2v-2z"/></svg> \ No newline at end of file
diff --git a/modules/csg/icons/CSGCylinder3D.svg b/modules/csg/icons/CSGCylinder3D.svg
index 19e48b4dba..366f1d9c4b 100644
--- a/modules/csg/icons/CSGCylinder3D.svg
+++ b/modules/csg/icons/CSGCylinder3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><mask id="a"><path d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z" fill="#fefefe"/></mask><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/><path d="M2 4v8a6 2 0 0 0 12 0V4A6 2 0 0 0 2 4a6 2 0 0 0 12 0" stroke-width="2" fill="none" stroke="#fc7f7f" mask="url(#a)"/></svg>
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><mask id="a"><path fill="#fefefe" d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z"/></mask><path fill="#5fb2ff" d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z"/><path fill="none" stroke="#fc7f7f" stroke-width="2" d="M2 4v8a6 2 0 0 0 12 0V4A6 2 0 0 0 2 4a6 2 0 0 0 12 0" mask="url(#a)"/></svg> \ No newline at end of file
diff --git a/modules/csg/icons/CSGMesh3D.svg b/modules/csg/icons/CSGMesh3D.svg
index a1c2282fe5..d115a64f80 100644
--- a/modules/csg/icons/CSGMesh3D.svg
+++ b/modules/csg/icons/CSGMesh3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M4.73 2A2 2 0 1 0 2 4.73v6.541A2 2 0 1 0 4.729 14H8v-2H4.729A2 2 0 0 0 4 11.271V5.415l4.914 4.916A2 2 0 0 1 9.998 10a2 2 0 0 1 .33-1.084L5.414 4h5.856a2 2 0 0 0 .73.729V8h2V4.729A2 2 0 1 0 11.27 2z" fill="#fc7f7f"/><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/></svg>
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#fc7f7f" d="M4.73 2A2 2 0 1 0 2 4.73v6.541A2 2 0 1 0 4.729 14H8v-2H4.729A2 2 0 0 0 4 11.271V5.415l4.914 4.916A2 2 0 0 1 9.998 10a2 2 0 0 1 .33-1.084L5.414 4h5.856a2 2 0 0 0 .73.729V8h2V4.729A2 2 0 1 0 11.27 2z"/><path fill="#5fb2ff" d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z"/></svg> \ No newline at end of file
diff --git a/modules/csg/icons/CSGPolygon3D.svg b/modules/csg/icons/CSGPolygon3D.svg
index 090047248b..ab7f61132b 100644
--- a/modules/csg/icons/CSGPolygon3D.svg
+++ b/modules/csg/icons/CSGPolygon3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><mask id="a"><path d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z" fill="#fefefe"/></mask><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/><path d="m8 2 6 3.5v5L8 14l-6-3.5v-5h6zm6 3.5L8 9 2 5.5M8 9v5" fill="none" stroke-linejoin="round" stroke-width="2" stroke="#fc7f7f" mask="url(#a)"/></svg>
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><mask id="a"><path fill="#fefefe" d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z"/></mask><path fill="#5fb2ff" d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z"/><path fill="none" stroke="#fc7f7f" stroke-linejoin="round" stroke-width="2" d="m8 2 6 3.5v5L8 14l-6-3.5v-5h6zm6 3.5L8 9 2 5.5M8 9v5" mask="url(#a)"/></svg> \ No newline at end of file
diff --git a/modules/csg/icons/CSGSphere3D.svg b/modules/csg/icons/CSGSphere3D.svg
index a677ffaf5c..96a63df153 100644
--- a/modules/csg/icons/CSGSphere3D.svg
+++ b/modules/csg/icons/CSGSphere3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><mask id="a"><path d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z" fill="#fefefe"/></mask><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/><path d="M8 2a6 6 0 0 0 0 12A6 6 0 0 0 8 2v12M2.05 7.4a6 2 0 0 0 11.9 0" fill="none" stroke-width="2" stroke="#fc7f7f" mask="url(#a)"/></svg>
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><mask id="a"><path fill="#fefefe" d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z"/></mask><path fill="#5fb2ff" d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z"/><path fill="none" stroke="#fc7f7f" stroke-width="2" d="M8 2a6 6 0 0 0 0 12A6 6 0 0 0 8 2v12M2.05 7.4a6 2 0 0 0 11.9 0" mask="url(#a)"/></svg> \ No newline at end of file
diff --git a/modules/csg/icons/CSGTorus3D.svg b/modules/csg/icons/CSGTorus3D.svg
index 60c56bd1ca..1f7565782f 100644
--- a/modules/csg/icons/CSGTorus3D.svg
+++ b/modules/csg/icons/CSGTorus3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><mask id="a"><path d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z" fill="#fefefe"/></mask><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/><g fill="none" stroke="#fc7f7f" mask="url(#a)"><path d="M2.5 10a6 4 0 0 0 11 0 4 4 0 0 0 0-4 6 4 0 0 0-11 0 4 4 0 0 0 0 4z" stroke-width="2"/><path d="M6.2 7.2a2 1 0 1 0 3.6 0" stroke-width="1.75" stroke-linecap="round"/></g></svg>
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><mask id="a"><path fill="#fefefe" d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z"/></mask><path fill="#5fb2ff" d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z"/><g fill="none" stroke="#fc7f7f" mask="url(#a)"><path stroke-width="2" d="M2.5 10a6 4 0 0 0 11 0 4 4 0 0 0 0-4 6 4 0 0 0-11 0 4 4 0 0 0 0 4z"/><path stroke-linecap="round" stroke-width="1.75" d="M6.2 7.2a2 1 0 1 0 3.6 0"/></g></svg> \ No newline at end of file
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 20d424894a..73b1e44db3 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -115,7 +115,7 @@ Variant GDScriptNativeClass::callp(const StringName &p_method, const Variant **p
}
GDScriptFunction *GDScript::_super_constructor(GDScript *p_script) {
- if (p_script->initializer) {
+ if (likely(p_script->valid) && p_script->initializer) {
return p_script->initializer;
} else {
GDScript *base_src = p_script->_base;
@@ -136,7 +136,11 @@ void GDScript::_super_implicit_constructor(GDScript *p_script, GDScriptInstance
}
}
ERR_FAIL_NULL(p_script->implicit_initializer);
- p_script->implicit_initializer->call(p_instance, nullptr, 0, r_error);
+ if (likely(valid)) {
+ p_script->implicit_initializer->call(p_instance, nullptr, 0, r_error);
+ } else {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ }
}
GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_is_ref_counted, Callable::CallError &r_error) {
@@ -662,7 +666,7 @@ String GDScript::_get_debug_path() const {
}
Error GDScript::_static_init() {
- if (static_initializer) {
+ if (likely(valid) && static_initializer) {
Callable::CallError call_err;
static_initializer->call(nullptr, nullptr, 0, call_err);
if (call_err.error != Callable::CallError::CALL_OK) {
@@ -679,8 +683,6 @@ Error GDScript::_static_init() {
return err;
}
-#ifdef TOOLS_ENABLED
-
void GDScript::_static_default_init() {
for (const KeyValue<StringName, MemberInfo> &E : static_variables_indices) {
const GDScriptDataType &type = E.value.data_type;
@@ -702,6 +704,8 @@ void GDScript::_static_default_init() {
}
}
+#ifdef TOOLS_ENABLED
+
void GDScript::_save_old_static_data() {
old_static_variables_indices = static_variables_indices;
old_static_variables = static_variables;
@@ -873,9 +877,6 @@ Error GDScript::reload(bool p_keep_state) {
#ifdef TOOLS_ENABLED
if (can_run && p_keep_state) {
_restore_old_static_data();
- } else if (!can_run) {
- // Initialize static variables with sane default values even if the constructor isn't called.
- _static_default_init();
}
#endif
@@ -912,18 +913,15 @@ void GDScript::unload_static() const {
}
Variant GDScript::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
- if (unlikely(!valid)) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- return Variant();
- }
-
GDScript *top = this;
while (top) {
- HashMap<StringName, GDScriptFunction *>::Iterator E = top->member_functions.find(p_method);
- if (E) {
- ERR_FAIL_COND_V_MSG(!E->value->is_static(), Variant(), "Can't call non-static function '" + String(p_method) + "' in script.");
+ if (likely(top->valid)) {
+ HashMap<StringName, GDScriptFunction *>::Iterator E = top->member_functions.find(p_method);
+ if (E) {
+ ERR_FAIL_COND_V_MSG(!E->value->is_static(), Variant(), "Can't call non-static function '" + String(p_method) + "' in script.");
- return E->value->call(nullptr, p_args, p_argcount, r_error);
+ return E->value->call(nullptr, p_args, p_argcount, r_error);
+ }
}
top = top->_base;
}
@@ -939,10 +937,6 @@ bool GDScript::_get(const StringName &p_name, Variant &r_ret) const {
return true;
}
- if (unlikely(!valid)) {
- return false;
- }
-
const GDScript *top = this;
while (top) {
{
@@ -956,7 +950,7 @@ bool GDScript::_get(const StringName &p_name, Variant &r_ret) const {
{
HashMap<StringName, MemberInfo>::ConstIterator E = top->static_variables_indices.find(p_name);
if (E) {
- if (E->value.getter) {
+ if (likely(top->valid) && E->value.getter) {
Callable::CallError ce;
r_ret = const_cast<GDScript *>(this)->callp(E->value.getter, nullptr, 0, ce);
return true;
@@ -966,7 +960,7 @@ bool GDScript::_get(const StringName &p_name, Variant &r_ret) const {
}
}
- {
+ if (likely(top->valid)) {
HashMap<StringName, GDScriptFunction *>::ConstIterator E = top->member_functions.find(p_name);
if (E && E->value->is_static()) {
if (top->rpc_config.has(p_name)) {
@@ -999,10 +993,6 @@ bool GDScript::_set(const StringName &p_name, const Variant &p_value) {
return true;
}
- if (unlikely(!valid)) {
- return false;
- }
-
GDScript *top = this;
while (top) {
HashMap<StringName, MemberInfo>::ConstIterator E = top->static_variables_indices.find(p_name);
@@ -1017,7 +1007,7 @@ bool GDScript::_set(const StringName &p_name, const Variant &p_value) {
return false;
}
}
- if (member->setter) {
+ if (likely(top->valid) && member->setter) {
const Variant *args = &value;
Callable::CallError err;
callp(member->setter, &args, 1, err);
@@ -1037,10 +1027,6 @@ bool GDScript::_set(const StringName &p_name, const Variant &p_value) {
void GDScript::_get_property_list(List<PropertyInfo> *p_properties) const {
p_properties->push_back(PropertyInfo(Variant::STRING, "script/source", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
- if (unlikely(!valid)) {
- return;
- }
-
List<const GDScript *> classes;
const GDScript *top = this;
while (top) {
@@ -1657,10 +1643,6 @@ GDScript::~GDScript() {
//////////////////////////////
bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) {
- if (unlikely(!script->valid)) {
- return false;
- }
-
{
HashMap<StringName, GDScript::MemberInfo>::Iterator E = script->member_indices.find(p_name);
if (E) {
@@ -1674,7 +1656,7 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) {
return false;
}
}
- if (member->setter) {
+ if (likely(script->valid) && member->setter) {
const Variant *args = &value;
Callable::CallError err;
callp(member->setter, &args, 1, err);
@@ -1701,7 +1683,7 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) {
return false;
}
}
- if (member->setter) {
+ if (likely(sptr->valid) && member->setter) {
const Variant *args = &value;
Callable::CallError err;
callp(member->setter, &args, 1, err);
@@ -1713,7 +1695,7 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) {
}
}
- {
+ if (likely(sptr->valid)) {
HashMap<StringName, GDScriptFunction *>::Iterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._set);
if (E) {
Variant name = p_name;
@@ -1734,14 +1716,10 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) {
}
bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
- if (unlikely(!script->valid)) {
- return false;
- }
-
{
HashMap<StringName, GDScript::MemberInfo>::ConstIterator E = script->member_indices.find(p_name);
if (E) {
- if (E->value.getter) {
+ if (likely(script->valid) && E->value.getter) {
Callable::CallError err;
r_ret = const_cast<GDScriptInstance *>(this)->callp(E->value.getter, nullptr, 0, err);
if (err.error == Callable::CallError::CALL_OK) {
@@ -1766,7 +1744,7 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
{
HashMap<StringName, GDScript::MemberInfo>::ConstIterator E = sptr->static_variables_indices.find(p_name);
if (E) {
- if (E->value.getter) {
+ if (likely(sptr->valid) && E->value.getter) {
Callable::CallError ce;
r_ret = const_cast<GDScript *>(sptr)->callp(E->value.getter, nullptr, 0, ce);
return true;
@@ -1784,7 +1762,7 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
}
}
- {
+ if (likely(sptr->valid)) {
HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(p_name);
if (E) {
if (sptr->rpc_config.has(p_name)) {
@@ -1804,7 +1782,7 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
}
}
- {
+ if (likely(sptr->valid)) {
HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get);
if (E) {
Variant name = p_name;
@@ -1844,13 +1822,15 @@ void GDScriptInstance::validate_property(PropertyInfo &p_property) const {
const GDScript *sptr = script.ptr();
while (sptr) {
- HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._validate_property);
- if (E) {
- Callable::CallError err;
- Variant ret = E->value->call(const_cast<GDScriptInstance *>(this), args, 1, err);
- if (err.error == Callable::CallError::CALL_OK) {
- p_property = PropertyInfo::from_dict(property);
- return;
+ if (likely(sptr->valid)) {
+ HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._validate_property);
+ if (E) {
+ Callable::CallError err;
+ Variant ret = E->value->call(const_cast<GDScriptInstance *>(this), args, 1, err);
+ if (err.error == Callable::CallError::CALL_OK) {
+ p_property = PropertyInfo::from_dict(property);
+ return;
+ }
}
}
sptr = sptr->_base;
@@ -1858,49 +1838,47 @@ void GDScriptInstance::validate_property(PropertyInfo &p_property) const {
}
void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const {
- if (unlikely(!script->valid)) {
- return;
- }
-
// exported members, not done yet!
const GDScript *sptr = script.ptr();
List<PropertyInfo> props;
while (sptr) {
- HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get_property_list);
- if (E) {
- Callable::CallError err;
- Variant ret = const_cast<GDScriptFunction *>(E->value)->call(const_cast<GDScriptInstance *>(this), nullptr, 0, err);
- if (err.error == Callable::CallError::CALL_OK) {
- ERR_FAIL_COND_MSG(ret.get_type() != Variant::ARRAY, "Wrong type for _get_property_list, must be an array of dictionaries.");
-
- Array arr = ret;
- for (int i = 0; i < arr.size(); i++) {
- Dictionary d = arr[i];
- ERR_CONTINUE(!d.has("name"));
- ERR_CONTINUE(!d.has("type"));
-
- PropertyInfo pinfo;
- pinfo.name = d["name"];
- pinfo.type = Variant::Type(d["type"].operator int());
- if (d.has("hint")) {
- pinfo.hint = PropertyHint(d["hint"].operator int());
- }
- if (d.has("hint_string")) {
- pinfo.hint_string = d["hint_string"];
- }
- if (d.has("usage")) {
- pinfo.usage = d["usage"];
- }
- if (d.has("class_name")) {
- pinfo.class_name = d["class_name"];
- }
+ if (likely(sptr->valid)) {
+ HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get_property_list);
+ if (E) {
+ Callable::CallError err;
+ Variant ret = const_cast<GDScriptFunction *>(E->value)->call(const_cast<GDScriptInstance *>(this), nullptr, 0, err);
+ if (err.error == Callable::CallError::CALL_OK) {
+ ERR_FAIL_COND_MSG(ret.get_type() != Variant::ARRAY, "Wrong type for _get_property_list, must be an array of dictionaries.");
+
+ Array arr = ret;
+ for (int i = 0; i < arr.size(); i++) {
+ Dictionary d = arr[i];
+ ERR_CONTINUE(!d.has("name"));
+ ERR_CONTINUE(!d.has("type"));
+
+ PropertyInfo pinfo;
+ pinfo.name = d["name"];
+ pinfo.type = Variant::Type(d["type"].operator int());
+ if (d.has("hint")) {
+ pinfo.hint = PropertyHint(d["hint"].operator int());
+ }
+ if (d.has("hint_string")) {
+ pinfo.hint_string = d["hint_string"];
+ }
+ if (d.has("usage")) {
+ pinfo.usage = d["usage"];
+ }
+ if (d.has("class_name")) {
+ pinfo.class_name = d["class_name"];
+ }
- ERR_CONTINUE(pinfo.name.is_empty() && (pinfo.usage & PROPERTY_USAGE_STORAGE));
- ERR_CONTINUE(pinfo.type < 0 || pinfo.type >= Variant::VARIANT_MAX);
+ ERR_CONTINUE(pinfo.name.is_empty() && (pinfo.usage & PROPERTY_USAGE_STORAGE));
+ ERR_CONTINUE(pinfo.type < 0 || pinfo.type >= Variant::VARIANT_MAX);
- props.push_back(pinfo);
+ props.push_back(pinfo);
+ }
}
}
}
@@ -1940,21 +1918,19 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const
}
bool GDScriptInstance::property_can_revert(const StringName &p_name) const {
- if (unlikely(!script->valid)) {
- return false;
- }
-
Variant name = p_name;
const Variant *args[1] = { &name };
const GDScript *sptr = script.ptr();
while (sptr) {
- HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._property_can_revert);
- if (E) {
- Callable::CallError err;
- Variant ret = E->value->call(const_cast<GDScriptInstance *>(this), args, 1, err);
- if (err.error == Callable::CallError::CALL_OK && ret.get_type() == Variant::BOOL && ret.operator bool()) {
- return true;
+ if (likely(sptr->valid)) {
+ HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._property_can_revert);
+ if (E) {
+ Callable::CallError err;
+ Variant ret = E->value->call(const_cast<GDScriptInstance *>(this), args, 1, err);
+ if (err.error == Callable::CallError::CALL_OK && ret.get_type() == Variant::BOOL && ret.operator bool()) {
+ return true;
+ }
}
}
sptr = sptr->_base;
@@ -1964,22 +1940,20 @@ bool GDScriptInstance::property_can_revert(const StringName &p_name) const {
}
bool GDScriptInstance::property_get_revert(const StringName &p_name, Variant &r_ret) const {
- if (unlikely(!script->valid)) {
- return false;
- }
-
Variant name = p_name;
const Variant *args[1] = { &name };
const GDScript *sptr = script.ptr();
while (sptr) {
- HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._property_get_revert);
- if (E) {
- Callable::CallError err;
- Variant ret = E->value->call(const_cast<GDScriptInstance *>(this), args, 1, err);
- if (err.error == Callable::CallError::CALL_OK && ret.get_type() != Variant::NIL) {
- r_ret = ret;
- return true;
+ if (likely(sptr->valid)) {
+ HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._property_get_revert);
+ if (E) {
+ Callable::CallError err;
+ Variant ret = E->value->call(const_cast<GDScriptInstance *>(this), args, 1, err);
+ if (err.error == Callable::CallError::CALL_OK && ret.get_type() != Variant::NIL) {
+ r_ret = ret;
+ return true;
+ }
}
}
sptr = sptr->_base;
@@ -2035,30 +2009,28 @@ void GDScriptInstance::_call_implicit_ready_recursively(GDScript *p_script) {
if (p_script->_base) {
_call_implicit_ready_recursively(p_script->_base);
}
- if (p_script->implicit_ready) {
+ if (likely(p_script->valid) && p_script->implicit_ready) {
Callable::CallError err;
p_script->implicit_ready->call(this, nullptr, 0, err);
}
}
Variant GDScriptInstance::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
- if (unlikely(!script->valid)) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- return Variant();
- }
-
GDScript *sptr = script.ptr();
if (unlikely(p_method == SceneStringName(_ready))) {
// Call implicit ready first, including for the super classes recursively.
_call_implicit_ready_recursively(sptr);
}
while (sptr) {
- HashMap<StringName, GDScriptFunction *>::Iterator E = sptr->member_functions.find(p_method);
- if (E) {
- return E->value->call(this, p_args, p_argcount, r_error);
+ if (likely(sptr->valid)) {
+ HashMap<StringName, GDScriptFunction *>::Iterator E = sptr->member_functions.find(p_method);
+ if (E) {
+ return E->value->call(this, p_args, p_argcount, r_error);
+ }
}
sptr = sptr->_base;
}
+
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
return Variant();
}
@@ -2083,12 +2055,14 @@ void GDScriptInstance::notification(int p_notification, bool p_reversed) {
sptr = sptr->_base;
}
for (GDScript *sc : pl) {
- HashMap<StringName, GDScriptFunction *>::Iterator E = sc->member_functions.find(GDScriptLanguage::get_singleton()->strings._notification);
- if (E) {
- Callable::CallError err;
- E->value->call(this, args, 1, err);
- if (err.error != Callable::CallError::CALL_OK) {
- //print error about notification call
+ if (likely(sc->valid)) {
+ HashMap<StringName, GDScriptFunction *>::Iterator E = sc->member_functions.find(GDScriptLanguage::get_singleton()->strings._notification);
+ if (E) {
+ Callable::CallError err;
+ E->value->call(this, args, 1, err);
+ if (err.error != Callable::CallError::CALL_OK) {
+ //print error about notification call
+ }
}
}
}
@@ -2759,7 +2733,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
String source = f->get_as_utf8_string();
GDScriptParser parser;
- err = parser.parse(source, p_path, false);
+ err = parser.parse(source, p_path, false, false);
const GDScriptParser::ClassNode *c = parser.get_tree();
if (!c) {
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index 728459de44..d097cb193b 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -169,9 +169,7 @@ private:
GDScriptFunction *static_initializer = nullptr;
Error _static_init();
-#ifdef TOOLS_ENABLED
void _static_default_init(); // Initialize static variables with default values based on their types.
-#endif
int subclass_count = 0;
RBSet<Object *> instances;
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index aa26bb222d..a6b4bce000 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -2663,6 +2663,44 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
reduce_expression(p_assignment->assignee);
+#ifdef DEBUG_ENABLED
+ {
+ bool is_subscript = false;
+ GDScriptParser::ExpressionNode *base = p_assignment->assignee;
+ while (base && base->type == GDScriptParser::Node::SUBSCRIPT) {
+ is_subscript = true;
+ base = static_cast<GDScriptParser::SubscriptNode *>(base)->base;
+ }
+ if (base && base->type == GDScriptParser::Node::IDENTIFIER) {
+ GDScriptParser::IdentifierNode *id = static_cast<GDScriptParser::IdentifierNode *>(base);
+ if (current_lambda && current_lambda->captures_indices.has(id->name)) {
+ bool need_warn = false;
+ if (is_subscript) {
+ const GDScriptParser::DataType &id_type = id->datatype;
+ if (id_type.is_hard_type()) {
+ switch (id_type.kind) {
+ case GDScriptParser::DataType::BUILTIN:
+ // TODO: Change `Variant::is_type_shared()` to include packed arrays?
+ need_warn = !Variant::is_type_shared(id_type.builtin_type) && id_type.builtin_type < Variant::PACKED_BYTE_ARRAY;
+ break;
+ case GDScriptParser::DataType::ENUM:
+ need_warn = true;
+ break;
+ default:
+ break;
+ }
+ }
+ } else {
+ need_warn = true;
+ }
+ if (need_warn) {
+ parser->push_warning(p_assignment, GDScriptWarning::CONFUSABLE_CAPTURE_REASSIGNMENT, id->name);
+ }
+ }
+ }
+ }
+#endif
+
if (p_assignment->assigned_value == nullptr || p_assignment->assignee == nullptr) {
return;
}
@@ -4299,7 +4337,8 @@ void GDScriptAnalyzer::reduce_preload(GDScriptParser::PreloadNode *p_preload) {
// Must load GDScript separately to permit cyclic references
// as ResourceLoader::load() detects and rejects those.
- if (ResourceLoader::get_resource_type(p_preload->resolved_path) == "GDScript") {
+ const String &res_type = ResourceLoader::get_resource_type(p_preload->resolved_path);
+ if (res_type == "GDScript") {
Error err = OK;
Ref<GDScript> res = GDScriptCache::get_shallow_script(p_preload->resolved_path, err, parser->script_path);
p_preload->resource = res;
@@ -4307,7 +4346,11 @@ void GDScriptAnalyzer::reduce_preload(GDScriptParser::PreloadNode *p_preload) {
push_error(vformat(R"(Could not preload resource script "%s".)", p_preload->resolved_path), p_preload->path);
}
} else {
- p_preload->resource = ResourceLoader::load(p_preload->resolved_path);
+ Error err = OK;
+ p_preload->resource = ResourceLoader::load(p_preload->resolved_path, res_type, ResourceFormatLoader::CACHE_MODE_REUSE, &err);
+ if (err == ERR_BUSY) {
+ p_preload->resource = ResourceLoader::ensure_resource_ref_override_for_outer_load(p_preload->resolved_path, res_type);
+ }
if (p_preload->resource.is_null()) {
push_error(vformat(R"(Could not preload resource file "%s".)", p_preload->resolved_path), p_preload->path);
}
@@ -5527,6 +5570,9 @@ bool GDScriptAnalyzer::check_type_compatibility(const GDScriptParser::DataType &
// A script type cannot be a subtype of a GDScript class.
return false;
}
+ if (p_source.script_type.is_null()) {
+ return false;
+ }
if (p_source.is_meta_type) {
src_native = p_source.script_type->get_class_name();
} else {
diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp
index ac6f5f05c6..c56ae0fb14 100644
--- a/modules/gdscript/gdscript_cache.cpp
+++ b/modules/gdscript/gdscript_cache.cpp
@@ -91,12 +91,8 @@ Error GDScriptParserRef::raise_status(Status p_new_status) {
result = get_analyzer()->resolve_interface();
} break;
case INTERFACE_SOLVED: {
- status = BODY_SOLVED;
- result = get_analyzer()->resolve_body();
- } break;
- case BODY_SOLVED: {
status = FULLY_SOLVED;
- result = get_analyzer()->resolve_dependencies();
+ result = get_analyzer()->resolve_body();
} break;
case FULLY_SOLVED: {
return result;
@@ -344,7 +340,11 @@ Ref<GDScript> GDScriptCache::get_full_script(const String &p_path, Error &r_erro
}
}
+ // Allowing lifting the lock might cause a script to be reloaded multiple times,
+ // which, as a last resort deadlock prevention strategy, is a good tradeoff.
+ uint32_t allowance_id = WorkerThreadPool::thread_enter_unlock_allowance_zone(&singleton->mutex);
r_error = script->reload(true);
+ WorkerThreadPool::thread_exit_unlock_allowance_zone(allowance_id);
if (r_error) {
return script;
}
diff --git a/modules/gdscript/gdscript_cache.h b/modules/gdscript/gdscript_cache.h
index c738233beb..16121cc082 100644
--- a/modules/gdscript/gdscript_cache.h
+++ b/modules/gdscript/gdscript_cache.h
@@ -48,7 +48,6 @@ public:
PARSED,
INHERITANCE_SOLVED,
INTERFACE_SOLVED,
- BODY_SOLVED,
FULLY_SOLVED,
};
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index eeffc13a10..5469dad3f7 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -3006,6 +3006,8 @@ Error GDScriptCompiler::_compile_class(GDScript *p_script, const GDScriptParser:
has_static_data = has_static_data || inner_class->has_static_data;
}
+ p_script->_static_default_init();
+
p_script->valid = true;
return OK;
}
@@ -3228,11 +3230,7 @@ Error GDScriptCompiler::compile(const GDScriptParser *p_parser, GDScript *p_scri
GDScriptCache::add_static_script(p_script);
}
- err = GDScriptCache::finish_compiling(main_script->path);
- if (err) {
- main_script->valid = false;
- }
- return err;
+ return GDScriptCache::finish_compiling(main_script->path);
}
String GDScriptCompiler::get_error() const {
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 8da829907e..f557727718 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -3657,11 +3657,21 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
return OK;
}
- StringName enum_name = ClassDB::get_integer_constant_enum(class_name, p_symbol, true);
- if (enum_name != StringName()) {
- r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_ENUM;
+ List<StringName> enums;
+ ClassDB::get_enum_list(class_name, &enums);
+ for (const StringName &E : enums) {
+ if (E == p_symbol) {
+ r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_ENUM;
+ r_result.class_name = base_type.native_type;
+ r_result.class_member = p_symbol;
+ return OK;
+ }
+ }
+
+ if (!String(ClassDB::get_integer_constant_enum(class_name, p_symbol, true)).is_empty()) {
+ r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_CONSTANT;
r_result.class_name = base_type.native_type;
- r_result.class_member = enum_name;
+ r_result.class_member = p_symbol;
return OK;
}
@@ -3735,6 +3745,15 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
return OK;
}
} break;
+ case GDScriptParser::DataType::ENUM: {
+ if (base_type.enum_values.has(p_symbol)) {
+ r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_CONSTANT;
+ r_result.class_name = String(base_type.native_type).get_slicec('.', 0);
+ r_result.class_member = p_symbol;
+ return OK;
+ }
+ base_type.kind = GDScriptParser::DataType::UNRESOLVED;
+ } break;
default: {
base_type.kind = GDScriptParser::DataType::UNRESOLVED;
} break;
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index d0948e4831..a1ea94667d 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -137,11 +137,22 @@ GDScriptParser::GDScriptParser() {
#endif
#ifdef TOOLS_ENABLED
- if (theme_color_names.is_empty()) {
+ if (unlikely(theme_color_names.is_empty())) {
+ // Vectors.
theme_color_names.insert("x", "axis_x_color");
theme_color_names.insert("y", "axis_y_color");
theme_color_names.insert("z", "axis_z_color");
theme_color_names.insert("w", "axis_w_color");
+
+ // Color.
+ theme_color_names.insert("r", "axis_x_color");
+ theme_color_names.insert("r8", "axis_x_color");
+ theme_color_names.insert("g", "axis_y_color");
+ theme_color_names.insert("g8", "axis_y_color");
+ theme_color_names.insert("b", "axis_z_color");
+ theme_color_names.insert("b8", "axis_z_color");
+ theme_color_names.insert("a", "axis_w_color");
+ theme_color_names.insert("a8", "axis_w_color");
}
#endif
}
@@ -298,13 +309,14 @@ void GDScriptParser::set_last_completion_call_arg(int p_argument) {
completion_call_stack.back()->get().argument = p_argument;
}
-Error GDScriptParser::parse(const String &p_source_code, const String &p_script_path, bool p_for_completion) {
+Error GDScriptParser::parse(const String &p_source_code, const String &p_script_path, bool p_for_completion, bool p_parse_body) {
clear();
String source = p_source_code;
int cursor_line = -1;
int cursor_column = -1;
for_completion = p_for_completion;
+ parse_body = p_parse_body;
int tab_size = 4;
#ifdef TOOLS_ENABLED
@@ -678,6 +690,12 @@ void GDScriptParser::parse_program() {
}
}
+ // When the only thing needed is the class name and the icon, we don't need to parse the hole file.
+ // It really speed up the call to GDScriptLanguage::get_global_class_name especially for large script.
+ if (!parse_body) {
+ return;
+ }
+
#undef PUSH_PENDING_ANNOTATIONS_TO_HEAD
parse_class_body(true);
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index 96358165c0..21942222cf 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -1329,6 +1329,7 @@ private:
bool _is_tool = false;
String script_path;
bool for_completion = false;
+ bool parse_body = true;
bool panic_mode = false;
bool can_break = false;
bool can_continue = false;
@@ -1560,7 +1561,7 @@ private:
#endif // TOOLS_ENABLED
public:
- Error parse(const String &p_source_code, const String &p_script_path, bool p_for_completion);
+ Error parse(const String &p_source_code, const String &p_script_path, bool p_for_completion, bool p_parse_body = true);
Error parse_binary(const Vector<uint8_t> &p_binary, const String &p_script_path);
ClassNode *get_tree() const { return head; }
bool is_tool() const { return _is_tool; }
diff --git a/modules/gdscript/gdscript_warning.cpp b/modules/gdscript/gdscript_warning.cpp
index 611a9ad2d9..e8fb1d94b3 100644
--- a/modules/gdscript/gdscript_warning.cpp
+++ b/modules/gdscript/gdscript_warning.cpp
@@ -145,6 +145,9 @@ String GDScriptWarning::get_message() const {
case CONFUSABLE_LOCAL_USAGE:
CHECK_SYMBOLS(1);
return vformat(R"(The identifier "%s" will be shadowed below in the block.)", symbols[0]);
+ case CONFUSABLE_CAPTURE_REASSIGNMENT:
+ CHECK_SYMBOLS(1);
+ return vformat(R"(Reassigning lambda capture does not modify the outer local variable "%s".)", symbols[0]);
case INFERENCE_ON_VARIANT:
CHECK_SYMBOLS(1);
return vformat("The %s type is being inferred from a Variant value, so it will be typed as Variant.", symbols[0]);
@@ -231,6 +234,7 @@ String GDScriptWarning::get_name_from_code(Code p_code) {
"CONFUSABLE_IDENTIFIER",
"CONFUSABLE_LOCAL_DECLARATION",
"CONFUSABLE_LOCAL_USAGE",
+ "CONFUSABLE_CAPTURE_REASSIGNMENT",
"INFERENCE_ON_VARIANT",
"NATIVE_METHOD_OVERRIDE",
"GET_NODE_DEFAULT_WITHOUT_ONREADY",
diff --git a/modules/gdscript/gdscript_warning.h b/modules/gdscript/gdscript_warning.h
index 3ad9488138..1c806bb4e2 100644
--- a/modules/gdscript/gdscript_warning.h
+++ b/modules/gdscript/gdscript_warning.h
@@ -85,6 +85,7 @@ public:
CONFUSABLE_IDENTIFIER, // The identifier contains misleading characters that can be confused. E.g. "usеr" (has Cyrillic "е" instead of Latin "e").
CONFUSABLE_LOCAL_DECLARATION, // The parent block declares an identifier with the same name below.
CONFUSABLE_LOCAL_USAGE, // The identifier will be shadowed below in the block.
+ CONFUSABLE_CAPTURE_REASSIGNMENT, // Reassigning lambda capture does not modify the outer local variable.
INFERENCE_ON_VARIANT, // The declaration uses type inference but the value is typed as Variant.
NATIVE_METHOD_OVERRIDE, // The script method overrides a native one, this may not work as intended.
GET_NODE_DEFAULT_WITHOUT_ONREADY, // A class variable uses `get_node()` (or the `$` notation) as its default value, but does not use the @onready annotation.
@@ -137,6 +138,7 @@ public:
WARN, // CONFUSABLE_IDENTIFIER
WARN, // CONFUSABLE_LOCAL_DECLARATION
WARN, // CONFUSABLE_LOCAL_USAGE
+ WARN, // CONFUSABLE_CAPTURE_REASSIGNMENT
ERROR, // INFERENCE_ON_VARIANT // Most likely done by accident, usually inference is trying for a particular type.
ERROR, // NATIVE_METHOD_OVERRIDE // May not work as expected.
ERROR, // GET_NODE_DEFAULT_WITHOUT_ONREADY // May not work as expected.
diff --git a/modules/gdscript/icons/GDScript.svg b/modules/gdscript/icons/GDScript.svg
index 2671c007f3..e44adf60dc 100644
--- a/modules/gdscript/icons/GDScript.svg
+++ b/modules/gdscript/icons/GDScript.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1-.565 2.258a5 5 0 0 0-.689.28L3.758 2.343 2.344 3.758l1.195 1.994a5 5 0 0 0-.285.685L1 7v2l2.258.564a5 5 0 0 0 .279.688l-1.193 1.99 1.414 1.414 1.994-1.195a5 5 0 0 0 .685.285L7 15h2l.564-2.258a5 5 0 0 0 .688-.28l1.99 1.194 1.414-1.414-1.195-1.994a5 5 0 0 0 .285-.685L15 9V7l-2.258-.564a5 5 0 0 0-.28-.688l1.194-1.99-1.414-1.414-1.994 1.195a5 5 0 0 0-.686-.285L9 1H7zm1 5a2 2 0 0 1 0 4 2 2 0 0 1 0-4z" fill="#e0e0e0"/></svg>
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#e0e0e0" d="m7 1-.565 2.258a5 5 0 0 0-.689.28L3.758 2.343 2.344 3.758l1.195 1.994a5 5 0 0 0-.285.685L1 7v2l2.258.564a5 5 0 0 0 .279.688l-1.193 1.99 1.414 1.414 1.994-1.195a5 5 0 0 0 .685.285L7 15h2l.564-2.258a5 5 0 0 0 .688-.28l1.99 1.194 1.414-1.414-1.195-1.994a5 5 0 0 0 .285-.685L15 9V7l-2.258-.564a5 5 0 0 0-.28-.688l1.194-1.99-1.414-1.414-1.994 1.195a5 5 0 0 0-.686-.285L9 1H7zm1 5a2 2 0 0 1 0 4 2 2 0 0 1 0-4z"/></svg> \ No newline at end of file
diff --git a/modules/gdscript/icons/GDScriptInternal.svg b/modules/gdscript/icons/GDScriptInternal.svg
index 81a59a7387..57471729cd 100644
--- a/modules/gdscript/icons/GDScriptInternal.svg
+++ b/modules/gdscript/icons/GDScriptInternal.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1-.565 2.258a5 5 0 0 0-.689.28L3.758 2.343 2.344 3.758l1.195 1.994a5 5 0 0 0-.285.685L1 7v2l2.258.564a5 5 0 0 0 .279.688l-1.193 1.99 1.414 1.414 1.994-1.195a5 5 0 0 0 .685.285L7 15h2l.564-2.258a5 5 0 0 0 .688-.28l1.99 1.194 1.414-1.414-1.195-1.994a5 5 0 0 0 .285-.685L15 9V7l-2.258-.564a5 5 0 0 0-.28-.688l1.194-1.99-1.414-1.414-1.994 1.195a5 5 0 0 0-.686-.285L9 1H7zm1 5a2 2 0 0 1 0 4 2 2 0 0 1 0-4z" fill="none" stroke="#e0e0e0"/></svg>
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="none" stroke="#e0e0e0" d="m7 1-.565 2.258a5 5 0 0 0-.689.28L3.758 2.343 2.344 3.758l1.195 1.994a5 5 0 0 0-.285.685L1 7v2l2.258.564a5 5 0 0 0 .279.688l-1.193 1.99 1.414 1.414 1.994-1.195a5 5 0 0 0 .685.285L7 15h2l.564-2.258a5 5 0 0 0 .688-.28l1.99 1.194 1.414-1.414-1.195-1.994a5 5 0 0 0 .285-.685L15 9V7l-2.258-.564a5 5 0 0 0-.28-.688l1.194-1.99-1.414-1.414-1.994 1.195a5 5 0 0 0-.686-.285L9 1H7zm1 5a2 2 0 0 1 0 4 2 2 0 0 1 0-4z"/></svg> \ No newline at end of file
diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/confusable_capture_reassignment.gd b/modules/gdscript/tests/scripts/analyzer/warnings/confusable_capture_reassignment.gd
new file mode 100644
index 0000000000..9e1041db54
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/warnings/confusable_capture_reassignment.gd
@@ -0,0 +1,23 @@
+var member := 1
+
+func test():
+ var number := 1
+ var string := "1"
+ var vector := Vector2i(1, 0)
+ var array_assign := [1]
+ var array_index := [1]
+ var dictionary := { x = 0 }
+
+ var lambda := func ():
+ member = 2 # Member variable, not captured.
+ number = 2 # Local variable, captured.
+ string += "2" # Test compound assignment operator.
+ vector.x = 2 # Test subscript assignment.
+ array_assign = [2] # Pass-by-reference type, reassignment.
+ array_index[0] = 2 # Pass-by-reference type, index access.
+ dictionary.x = 2 # Pass-by-reference type, attribute access.
+
+ prints("lambda", member, number, string, vector, array_assign, array_index, dictionary)
+
+ lambda.call()
+ prints("outer", member, number, string, vector, array_assign, array_index, dictionary)
diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/confusable_capture_reassignment.out b/modules/gdscript/tests/scripts/analyzer/warnings/confusable_capture_reassignment.out
new file mode 100644
index 0000000000..8d953818eb
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/warnings/confusable_capture_reassignment.out
@@ -0,0 +1,19 @@
+GDTEST_OK
+>> WARNING
+>> Line: 13
+>> CONFUSABLE_CAPTURE_REASSIGNMENT
+>> Reassigning lambda capture does not modify the outer local variable "number".
+>> WARNING
+>> Line: 14
+>> CONFUSABLE_CAPTURE_REASSIGNMENT
+>> Reassigning lambda capture does not modify the outer local variable "string".
+>> WARNING
+>> Line: 15
+>> CONFUSABLE_CAPTURE_REASSIGNMENT
+>> Reassigning lambda capture does not modify the outer local variable "vector".
+>> WARNING
+>> Line: 16
+>> CONFUSABLE_CAPTURE_REASSIGNMENT
+>> Reassigning lambda capture does not modify the outer local variable "array_assign".
+lambda 2 2 12 (2, 0) [2] [2] { "x": 2 }
+outer 2 1 1 (1, 0) [1] [2] { "x": 2 }
diff --git a/modules/gdscript/tests/scripts/parser/features/lambda_ends_with_new_line.gd b/modules/gdscript/tests/scripts/parser/features/lambda_ends_with_new_line.gd
index 46b6856d22..c3a42288c7 100644
--- a/modules/gdscript/tests/scripts/parser/features/lambda_ends_with_new_line.gd
+++ b/modules/gdscript/tests/scripts/parser/features/lambda_ends_with_new_line.gd
@@ -9,6 +9,7 @@ func four_parameters(_a, callable : Callable, b=func(): print(10)):
func test():
var v
+ @warning_ignore("confusable_capture_reassignment")
v=func():v=1
if true: v=1
print(v)
diff --git a/modules/glslang/register_types.cpp b/modules/glslang/register_types.cpp
index 09ad1d6777..b5f70fb98b 100644
--- a/modules/glslang/register_types.cpp
+++ b/modules/glslang/register_types.cpp
@@ -33,7 +33,6 @@
#include "core/config/engine.h"
#include "servers/rendering/rendering_device.h"
-#include <glslang/Include/Types.h>
#include <glslang/Public/ResourceLimits.h>
#include <glslang/Public/ShaderLang.h>
#include <glslang/SPIRV/GlslangToSpv.h>
diff --git a/modules/gridmap/editor/grid_map_editor_plugin.cpp b/modules/gridmap/editor/grid_map_editor_plugin.cpp
index b93b7c1a8c..f402e2a583 100644
--- a/modules/gridmap/editor/grid_map_editor_plugin.cpp
+++ b/modules/gridmap/editor/grid_map_editor_plugin.cpp
@@ -59,10 +59,18 @@ void GridMapEditor::_menu_option(int p_option) {
switch (p_option) {
case MENU_OPTION_PREV_LEVEL: {
floor->set_value(floor->get_value() - 1);
+ if (selection.active && input_action == INPUT_SELECT) {
+ selection.current[edit_axis]--;
+ _validate_selection();
+ }
} break;
case MENU_OPTION_NEXT_LEVEL: {
floor->set_value(floor->get_value() + 1);
+ if (selection.active && input_action == INPUT_SELECT) {
+ selection.current[edit_axis]++;
+ _validate_selection();
+ }
} break;
case MENU_OPTION_X_AXIS:
@@ -754,19 +762,6 @@ EditorPlugin::AfterGUIInput GridMapEditor::forward_spatial_input_event(Camera3D
}
}
}
-
- if (k->is_shift_pressed() && selection.active && input_action != INPUT_PASTE) {
- if (k->get_keycode() == (Key)options->get_popup()->get_item_accelerator(options->get_popup()->get_item_index(MENU_OPTION_PREV_LEVEL))) {
- selection.click[edit_axis]--;
- _validate_selection();
- return EditorPlugin::AFTER_GUI_INPUT_STOP;
- }
- if (k->get_keycode() == (Key)options->get_popup()->get_item_accelerator(options->get_popup()->get_item_index(MENU_OPTION_NEXT_LEVEL))) {
- selection.click[edit_axis]++;
- _validate_selection();
- return EditorPlugin::AFTER_GUI_INPUT_STOP;
- }
- }
}
}
diff --git a/modules/gridmap/icons/GridMap.svg b/modules/gridmap/icons/GridMap.svg
index 38e48a2707..eddeadbcac 100644
--- a/modules/gridmap/icons/GridMap.svg
+++ b/modules/gridmap/icons/GridMap.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1-6 3v8l6 3 6-3v-2l-2-1-4 2-2-1v-4l2-1v-2l2-1zm4 2-2 1v2l2 1 2-1v-2z" fill="#fc7f7f"/></svg>
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#fc7f7f" d="m8 1-6 3v8l6 3 6-3v-2l-2-1-4 2-2-1v-4l2-1v-2l2-1zm4 2-2 1v2l2 1 2-1v-2z"/></svg> \ No newline at end of file
diff --git a/modules/mono/icons/BuildCSharp.svg b/modules/mono/icons/BuildCSharp.svg
index d4ba5bc293..430433dc38 100644
--- a/modules/mono/icons/BuildCSharp.svg
+++ b/modules/mono/icons/BuildCSharp.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2.256 4.85 1.7 2.945 2.598-1.5 4.5 7.794a1 1-30 0 0 2.598-1.5l-4.65-8.054 3.464-2-.25-.433s-1.25-2.165-3.848-.665l-3.464 2-.31.063z" fill="#e0e0e0"/></svg>
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#e0e0e0" d="m2.256 4.85 1.7 2.945 2.598-1.5 4.5 7.794a1 1-30 0 0 2.598-1.5l-4.65-8.054 3.464-2-.25-.433s-1.25-2.165-3.848-.665l-3.464 2-.31.063z"/></svg> \ No newline at end of file
diff --git a/modules/mono/icons/CSharpScript.svg b/modules/mono/icons/CSharpScript.svg
index 1e1ec96857..7f309fe5fa 100644
--- a/modules/mono/icons/CSharpScript.svg
+++ b/modules/mono/icons/CSharpScript.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M6 10a3 3 0 1 0 0 6h1v-2H6a1 1 0 0 1 0-2h1v-2zm1-9-.564 2.258a4.91 4.91 0 0 0-.69.28L3.758 2.343 2.344 3.758l1.195 1.994-.285.685L1 7v2h5.27a2 2 0 1 1 3.46 0H15V7l-2.258-.565a5.007 5.007 0 0 0-.28-.687l1.194-1.99-1.414-1.414-1.994 1.195a4.998 4.998 0 0 0-.686-.285L9 1zm4 9a2 2 0 1 0 0 4H9v2h2a2 2 0 1 0 0-4h2v-2z" fill="#e0e0e0"/></svg>
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#e0e0e0" d="M6 10a3 3 0 1 0 0 6h1v-2H6a1 1 0 0 1 0-2h1v-2zm1-9-.564 2.258a4.91 4.91 0 0 0-.69.28L3.758 2.343 2.344 3.758l1.195 1.994-.285.685L1 7v2h5.27a2 2 0 1 1 3.46 0H15V7l-2.258-.565a5.007 5.007 0 0 0-.28-.687l1.194-1.99-1.414-1.414-1.994 1.195a4.998 4.998 0 0 0-.686-.285L9 1zm4 9a2 2 0 1 0 0 4H9v2h2a2 2 0 1 0 0-4h2v-2z"/></svg> \ No newline at end of file
diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp
index f0184a155b..8a7da64eb5 100644
--- a/modules/navigation/nav_map.cpp
+++ b/modules/navigation/nav_map.cpp
@@ -1127,13 +1127,6 @@ void NavMap::sync() {
new_polygon.points.push_back({ closest_end_point, get_point_key(closest_end_point) });
new_polygon.points.push_back({ closest_end_point, get_point_key(closest_end_point) });
- Vector3 center;
- for (int p = 0; p < 4; ++p) {
- center += new_polygon.points[p].pos;
- }
- new_polygon.center = center / real_t(new_polygon.points.size());
- new_polygon.clockwise = true;
-
// Setup connections to go forward in the link.
{
gd::Edge::Connection entry_connection;
diff --git a/modules/navigation/nav_region.cpp b/modules/navigation/nav_region.cpp
index c91071a3ab..f30855d697 100644
--- a/modules/navigation/nav_region.cpp
+++ b/modules/navigation/nav_region.cpp
@@ -277,9 +277,6 @@ void NavRegion::update_polygons() {
polygon.surface_area = _new_polygon_surface_area;
_new_region_surface_area += _new_polygon_surface_area;
- Vector3 polygon_center;
- real_t sum(0);
-
for (int j(0); j < navigation_mesh_polygon_size; j++) {
int idx = indices[j];
if (idx < 0 || idx >= len) {
@@ -290,25 +287,11 @@ void NavRegion::update_polygons() {
Vector3 point_position = transform.xform(vertices_r[idx]);
polygon.points[j].pos = point_position;
polygon.points[j].key = map->get_point_key(point_position);
-
- polygon_center += point_position; // Composing the center of the polygon
-
- if (j >= 2) {
- Vector3 epa = transform.xform(vertices_r[indices[j - 2]]);
- Vector3 epb = transform.xform(vertices_r[indices[j - 1]]);
-
- sum += map->get_up().dot((epb - epa).cross(point_position - epa));
- }
}
if (!valid) {
ERR_BREAK_MSG(!valid, "The navigation mesh set in this region is not valid!");
}
-
- polygon.clockwise = sum > 0;
- if (!navigation_mesh_polygon.is_empty()) {
- polygon.center = polygon_center / real_t(navigation_mesh_polygon.size());
- }
}
surface_area = _new_region_surface_area;
diff --git a/modules/navigation/nav_utils.h b/modules/navigation/nav_utils.h
index 175d08ca6d..c3939e9979 100644
--- a/modules/navigation/nav_utils.h
+++ b/modules/navigation/nav_utils.h
@@ -104,15 +104,9 @@ struct Polygon {
/// The points of this `Polygon`
LocalVector<Point> points;
- /// Are the points clockwise?
- bool clockwise;
-
/// The edges of this `Polygon`
LocalVector<Edge> edges;
- /// The center of this `Polygon`
- Vector3 center;
-
real_t surface_area = 0.0;
};
diff --git a/modules/noise/icons/NoiseTexture2D.svg b/modules/noise/icons/NoiseTexture2D.svg
index 0c22cfdcc6..94d550d141 100644
--- a/modules/noise/icons/NoiseTexture2D.svg
+++ b/modules/noise/icons/NoiseTexture2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M2 1a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1zm1 2h10v8H3zm3 1v2h2V4zm2 2v2h2v2h2V4h-2v2zm0 2H6V6H4v4h4z" fill="#e0e0e0"/></svg>
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#e0e0e0" d="M2 1a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1zm1 2h10v8H3zm3 1v2h2V4zm2 2v2h2v2h2V4h-2v2zm0 2H6V6H4v4h4z"/></svg> \ No newline at end of file
diff --git a/modules/noise/icons/NoiseTexture3D.svg b/modules/noise/icons/NoiseTexture3D.svg
index 92da633dce..178bac2dd3 100644
--- a/modules/noise/icons/NoiseTexture3D.svg
+++ b/modules/noise/icons/NoiseTexture3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M1 14a1 1 0 0 0 1 1h9.5a1 1 0 0 0 .707-.293l2.5-2.5A1 1 0 0 0 15 11.5V2a1 1 0 0 0-1-1H4.5a1 1 0 0 0-.707.293l-2.5 2.5A1 1 0 0 0 1 4.5zm1.25-9H11v7H2.25zm10 6.25v-6.5L14 3v6.5zm-1-7.5H3L4.75 2H13zM3 11h4l1.25-1.25V9H9l1.25-1.25v-2h-2L7 7v.75h-.75v-2h-2L3 7z" fill="#e0e0e0"/><path d="M3 7h2l1.25-1.25h-2zm2 2h2V7.75h-.75zm2-2h2l1.25-1.25H8z" fill="#000" fill-opacity=".4"/><path d="M5 7v2l1.25-1.25v-2zm2 2v2l1.25-1.25V9zm2 0V7l1.25-1.25v2z" fill="#000" fill-opacity=".2"/></svg>
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#e0e0e0" d="M1 14a1 1 0 0 0 1 1h9.5a1 1 0 0 0 .707-.293l2.5-2.5A1 1 0 0 0 15 11.5V2a1 1 0 0 0-1-1H4.5a1 1 0 0 0-.707.293l-2.5 2.5A1 1 0 0 0 1 4.5zm1.25-9H11v7H2.25zm10 6.25v-6.5L14 3v6.5zm-1-7.5H3L4.75 2H13zM3 11h4l1.25-1.25V9H9l1.25-1.25v-2h-2L7 7v.75h-.75v-2h-2L3 7z"/><path fill-opacity=".4" d="M3 7h2l1.25-1.25h-2zm2 2h2V7.75h-.75zm2-2h2l1.25-1.25H8z"/><path fill-opacity=".2" d="M5 7v2l1.25-1.25v-2zm2 2v2l1.25-1.25V9zm2 0V7l1.25-1.25v2z"/></svg> \ No newline at end of file
diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp
index 541e369925..04edde8300 100644
--- a/modules/openxr/openxr_api.cpp
+++ b/modules/openxr/openxr_api.cpp
@@ -902,6 +902,47 @@ bool OpenXRAPI::setup_play_space() {
new_reference_space = XR_REFERENCE_SPACE_TYPE_LOCAL;
will_emulate_local_floor = true;
+
+ if (local_floor_emulation.local_space == XR_NULL_HANDLE) {
+ XrReferenceSpaceCreateInfo create_info = {
+ XR_TYPE_REFERENCE_SPACE_CREATE_INFO, // type
+ nullptr, // next
+ XR_REFERENCE_SPACE_TYPE_LOCAL, // referenceSpaceType
+ identityPose, // poseInReferenceSpace
+ };
+
+ XrResult result = xrCreateReferenceSpace(session, &create_info, &local_floor_emulation.local_space);
+ if (XR_FAILED(result)) {
+ print_line("OpenXR: Failed to create LOCAL space in order to emulate LOCAL_FLOOR [", get_error_string(result), "]");
+ will_emulate_local_floor = false;
+ }
+ }
+
+ if (local_floor_emulation.stage_space == XR_NULL_HANDLE) {
+ XrReferenceSpaceCreateInfo create_info = {
+ XR_TYPE_REFERENCE_SPACE_CREATE_INFO, // type
+ nullptr, // next
+ XR_REFERENCE_SPACE_TYPE_STAGE, // referenceSpaceType
+ identityPose, // poseInReferenceSpace
+ };
+
+ XrResult result = xrCreateReferenceSpace(session, &create_info, &local_floor_emulation.stage_space);
+ if (XR_FAILED(result)) {
+ print_line("OpenXR: Failed to create STAGE space in order to emulate LOCAL_FLOOR [", get_error_string(result), "]");
+ will_emulate_local_floor = false;
+ }
+ }
+
+ if (!will_emulate_local_floor) {
+ if (local_floor_emulation.local_space != XR_NULL_HANDLE) {
+ xrDestroySpace(local_floor_emulation.local_space);
+ local_floor_emulation.local_space = XR_NULL_HANDLE;
+ }
+ if (local_floor_emulation.stage_space != XR_NULL_HANDLE) {
+ xrDestroySpace(local_floor_emulation.stage_space);
+ local_floor_emulation.stage_space = XR_NULL_HANDLE;
+ }
+ }
} else {
// Fallback on LOCAL, which all OpenXR runtimes are required to support.
print_verbose(String("OpenXR: ") + OpenXRUtil::get_reference_space_name(requested_reference_space) + String(" isn't supported, defaulting to LOCAL space."));
@@ -931,16 +972,11 @@ bool OpenXRAPI::setup_play_space() {
play_space = new_play_space;
reference_space = new_reference_space;
- emulating_local_floor = will_emulate_local_floor;
- if (emulating_local_floor) {
- // We'll use the STAGE space to get the floor height, but we can't do that until
- // after xrWaitFrame(), so just set this flag for now.
- // Render state will be updated then.
- should_reset_emulated_floor_height = true;
- } else {
- // Update render state so this play space is used rendering the upcoming frame.
- set_render_play_space(play_space);
- }
+ local_floor_emulation.enabled = will_emulate_local_floor;
+ local_floor_emulation.should_reset_floor_height = will_emulate_local_floor;
+
+ // Update render state so this play space is used rendering the upcoming frame.
+ set_render_play_space(play_space);
return true;
}
@@ -975,63 +1011,39 @@ bool OpenXRAPI::setup_view_space() {
}
bool OpenXRAPI::reset_emulated_floor_height() {
- ERR_FAIL_COND_V(!emulating_local_floor, false);
-
- // This is based on the example code in the OpenXR spec which shows how to
- // emulate LOCAL_FLOOR if it's not supported.
- // See: https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#XR_EXT_local_floor
+ ERR_FAIL_COND_V(!local_floor_emulation.enabled, false);
+ ERR_FAIL_COND_V(local_floor_emulation.local_space == XR_NULL_HANDLE, false);
+ ERR_FAIL_COND_V(local_floor_emulation.stage_space == XR_NULL_HANDLE, false);
XrResult result;
- XrPosef identityPose = {
- { 0.0, 0.0, 0.0, 1.0 },
- { 0.0, 0.0, 0.0 }
- };
-
- XrSpace local_space = XR_NULL_HANDLE;
- XrSpace stage_space = XR_NULL_HANDLE;
-
- XrReferenceSpaceCreateInfo create_info = {
- XR_TYPE_REFERENCE_SPACE_CREATE_INFO, // type
- nullptr, // next
- XR_REFERENCE_SPACE_TYPE_LOCAL, // referenceSpaceType
- identityPose, // poseInReferenceSpace
- };
-
- result = xrCreateReferenceSpace(session, &create_info, &local_space);
- if (XR_FAILED(result)) {
- print_line("OpenXR: Failed to create LOCAL space in order to emulate LOCAL_FLOOR [", get_error_string(result), "]");
- return false;
- }
-
- create_info.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_STAGE;
- result = xrCreateReferenceSpace(session, &create_info, &stage_space);
- if (XR_FAILED(result)) {
- print_line("OpenXR: Failed to create STAGE space in order to emulate LOCAL_FLOOR [", get_error_string(result), "]");
- xrDestroySpace(local_space);
- return false;
- }
-
XrSpaceLocation stage_location = {
XR_TYPE_SPACE_LOCATION, // type
nullptr, // next
0, // locationFlags
- identityPose, // pose
+ { { 0.0, 0.0, 0.0, 1.0 }, { 0.0, 0.0, 0.0 } }, // pose
};
- result = xrLocateSpace(stage_space, local_space, get_predicted_display_time(), &stage_location);
-
- xrDestroySpace(local_space);
- xrDestroySpace(stage_space);
+ result = xrLocateSpace(local_floor_emulation.stage_space, local_floor_emulation.local_space, get_predicted_display_time(), &stage_location);
if (XR_FAILED(result)) {
print_line("OpenXR: Failed to locate STAGE space in LOCAL space, in order to emulate LOCAL_FLOOR [", get_error_string(result), "]");
return false;
}
+ XrPosef pose = {
+ { 0.0, 0.0, 0.0, 1.0 },
+ { 0.0, stage_location.pose.position.y, 0.0 }
+ };
+
+ XrReferenceSpaceCreateInfo create_info = {
+ XR_TYPE_REFERENCE_SPACE_CREATE_INFO, // type
+ nullptr, // next
+ XR_REFERENCE_SPACE_TYPE_LOCAL, // referenceSpaceType
+ pose, // poseInReferenceSpace
+ };
+
XrSpace new_play_space;
- create_info.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL;
- create_info.poseInReferenceSpace.position.y = stage_location.pose.position.y;
result = xrCreateReferenceSpace(session, &create_info, &new_play_space);
if (XR_FAILED(result)) {
print_line("OpenXR: Failed to recreate emulated LOCAL_FLOOR play space with latest floor estimate [", get_error_string(result), "]");
@@ -1275,6 +1287,16 @@ void OpenXRAPI::destroy_session() {
xrDestroySpace(view_space);
view_space = XR_NULL_HANDLE;
}
+ if (local_floor_emulation.local_space != XR_NULL_HANDLE) {
+ xrDestroySpace(local_floor_emulation.local_space);
+ local_floor_emulation.local_space = XR_NULL_HANDLE;
+ }
+ if (local_floor_emulation.stage_space != XR_NULL_HANDLE) {
+ xrDestroySpace(local_floor_emulation.stage_space);
+ local_floor_emulation.stage_space = XR_NULL_HANDLE;
+ }
+ local_floor_emulation.enabled = false;
+ local_floor_emulation.should_reset_floor_height = false;
if (supported_reference_spaces != nullptr) {
// free previous results
@@ -1953,8 +1975,8 @@ bool OpenXRAPI::poll_events() {
XrEventDataReferenceSpaceChangePending *event = (XrEventDataReferenceSpaceChangePending *)&runtimeEvent;
print_verbose(String("OpenXR EVENT: reference space type ") + OpenXRUtil::get_reference_space_name(event->referenceSpaceType) + " change pending!");
- if (emulating_local_floor) {
- should_reset_emulated_floor_height = true;
+ if (local_floor_emulation.enabled) {
+ local_floor_emulation.should_reset_floor_height = true;
}
if (event->poseValid && xr_interface) {
xr_interface->on_pose_recentered();
@@ -2097,16 +2119,18 @@ bool OpenXRAPI::process() {
set_render_display_info(frame_state.predictedDisplayTime, frame_state.shouldRender);
+ // This is before setup_play_space() to ensure that it happens on the frame after
+ // the play space has been created.
+ if (unlikely(local_floor_emulation.should_reset_floor_height && !play_space_is_dirty)) {
+ reset_emulated_floor_height();
+ local_floor_emulation.should_reset_floor_height = false;
+ }
+
if (unlikely(play_space_is_dirty)) {
setup_play_space();
play_space_is_dirty = false;
}
- if (unlikely(should_reset_emulated_floor_height)) {
- reset_emulated_floor_height();
- should_reset_emulated_floor_height = false;
- }
-
for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
wrapper->on_process();
}
diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h
index f9d2e60148..748ef3af94 100644
--- a/modules/openxr/openxr_api.h
+++ b/modules/openxr/openxr_api.h
@@ -165,8 +165,16 @@ private:
XrSpace view_space = XR_NULL_HANDLE;
XRPose::TrackingConfidence head_pose_confidence = XRPose::XR_TRACKING_CONFIDENCE_NONE;
- bool emulating_local_floor = false;
- bool should_reset_emulated_floor_height = false;
+ // When LOCAL_FLOOR isn't supported, we use an approach based on the example code in the
+ // OpenXR spec in order to emulate it.
+ // See: https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#XR_EXT_local_floor
+ struct LocalFloorEmulation {
+ bool enabled = false;
+ XrSpace local_space = XR_NULL_HANDLE;
+ XrSpace stage_space = XR_NULL_HANDLE;
+ bool should_reset_floor_height = false;
+ } local_floor_emulation;
+
bool reset_emulated_floor_height();
bool load_layer_properties();
diff --git a/modules/regex/icons/RegEx.svg b/modules/regex/icons/RegEx.svg
index 4df26f41c0..ba232f6f0a 100644
--- a/modules/regex/icons/RegEx.svg
+++ b/modules/regex/icons/RegEx.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M2 14h3v-3H2zM6.561 2.855a21 21 0 0 1 2.82 1.185A21 21 0 0 1 9.137 1h1.77a21 21 0 0 1-.28 3.027 21 21 0 0 1 2.88-1.171l.562 1.733a21 21 0 0 1-3.04.684 21 21 0 0 1 2.1 2.307l-1.465 1.037a21 21 0 0 1-1.672-2.624 21 21 0 0 1-1.587 2.624L6.965 7.58a21 21 0 0 1 2.026-2.308A21 21 0 0 1 6 4.59z" fill="#e0e0e0"/></svg>
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#e0e0e0" d="M2 14h3v-3H2zM6.561 2.855a21 21 0 0 1 2.82 1.185A21 21 0 0 1 9.137 1h1.77a21 21 0 0 1-.28 3.027 21 21 0 0 1 2.88-1.171l.562 1.733a21 21 0 0 1-3.04.684 21 21 0 0 1 2.1 2.307l-1.465 1.037a21 21 0 0 1-1.672-2.624 21 21 0 0 1-1.587 2.624L6.965 7.58a21 21 0 0 1 2.026-2.308A21 21 0 0 1 6 4.59z"/></svg> \ No newline at end of file
diff --git a/modules/regex/icons/RegExMatch.svg b/modules/regex/icons/RegExMatch.svg
index 889cf6cc8a..626ff36691 100644
--- a/modules/regex/icons/RegExMatch.svg
+++ b/modules/regex/icons/RegExMatch.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M5 13h2v-2H5zm2.5-8a14 14 0 0 1 1.88.79 14 14 0 0 1-.163-2.027h1.18a14 14 0 0 1-.186 2.018 14 14 0 0 1 1.92-.78l.374 1.155a14 14 0 0 1-2.026.456 14 14 0 0 1 1.4 1.538l-.977.691a14 14 0 0 1-1.115-1.75 14 14 0 0 1-1.058 1.75l-.96-.691A14 14 0 0 1 9.12 6.61a14 14 0 0 1-1.993-.454zM1.67 2C0 5 0 11 1.67 14h2C2 11 2 5 3.67 2zm10.66 0c1.67 3 1.67 9 0 12h2c1.67-3 1.67-9 0-12z" fill="#e0e0e0"/></svg>
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#e0e0e0" d="M5 13h2v-2H5zm2.5-8a14 14 0 0 1 1.88.79 14 14 0 0 1-.163-2.027h1.18a14 14 0 0 1-.186 2.018 14 14 0 0 1 1.92-.78l.374 1.155a14 14 0 0 1-2.026.456 14 14 0 0 1 1.4 1.538l-.977.691a14 14 0 0 1-1.115-1.75 14 14 0 0 1-1.058 1.75l-.96-.691A14 14 0 0 1 9.12 6.61a14 14 0 0 1-1.993-.454zM1.67 2C0 5 0 11 1.67 14h2C2 11 2 5 3.67 2zm10.66 0c1.67 3 1.67 9 0 12h2c1.67-3 1.67-9 0-12z"/></svg> \ No newline at end of file
diff --git a/modules/webxr/doc_classes/WebXRInterface.xml b/modules/webxr/doc_classes/WebXRInterface.xml
index 9fd4511d2b..bd7192520a 100644
--- a/modules/webxr/doc_classes/WebXRInterface.xml
+++ b/modules/webxr/doc_classes/WebXRInterface.xml
@@ -54,9 +54,10 @@
# supported.
webxr_interface.requested_reference_space_types = 'bounded-floor, local-floor, local'
# In order to use 'local-floor' or 'bounded-floor' we must also
- # mark the features as required or optional.
+ # mark the features as required or optional. By including 'hand-tracking'
+ # as an optional feature, it will be enabled if supported.
webxr_interface.required_features = 'local-floor'
- webxr_interface.optional_features = 'bounded-floor'
+ webxr_interface.optional_features = 'bounded-floor, hand-tracking'
# This will return false if we're unable to even request the session,
# however, it can still fail asynchronously later in the process, so we
@@ -73,7 +74,10 @@
# This will be the reference space type you ultimately got, out of the
# types that you requested above. This is useful if you want the game to
# work a little differently in 'bounded-floor' versus 'local-floor'.
- print ("Reference space type: " + webxr_interface.reference_space_type)
+ print("Reference space type: ", webxr_interface.reference_space_type)
+ # This will be the list of features that were successfully enabled
+ # (except on browsers that don't support this property).
+ print("Enabled features: ", webxr_interface.enabled_features)
func _webxr_session_ended():
$Button.visible = true
@@ -155,13 +159,14 @@
<members>
<member name="enabled_features" type="String" setter="" getter="get_enabled_features">
A comma-separated list of features that were successfully enabled by [method XRInterface.initialize] when setting up the WebXR session.
- This may include features requested by setting [member required_features] and [member optional_features].
+ This may include features requested by setting [member required_features] and [member optional_features], and will only be available after [signal session_started] has been emitted.
+ [b]Note:[/b] This may not be support by all web browsers, in which case it will be an empty string.
</member>
<member name="optional_features" type="String" setter="set_optional_features" getter="get_optional_features">
A comma-seperated list of optional features used by [method XRInterface.initialize] when setting up the WebXR session.
If a user's browser or device doesn't support one of the given features, initialization will continue, but you won't be able to use the requested feature.
This doesn't have any effect on the interface when already initialized.
- Possible values come from [url=https://developer.mozilla.org/en-US/docs/Web/API/XRReferenceSpaceType]WebXR's XRReferenceSpaceType[/url]. If you want to use a particular reference space type, it must be listed in either [member required_features] or [member optional_features].
+ Possible values come from [url=https://developer.mozilla.org/en-US/docs/Web/API/XRReferenceSpaceType]WebXR's XRReferenceSpaceType[/url], or include other features like [code]"hand-tracking"[/code] to enable hand tracking.
</member>
<member name="reference_space_type" type="String" setter="" getter="get_reference_space_type">
The reference space type (from the list of requested types set in the [member requested_reference_space_types] property), that was ultimately used by [method XRInterface.initialize] when setting up the WebXR session.
@@ -177,7 +182,7 @@
A comma-seperated list of required features used by [method XRInterface.initialize] when setting up the WebXR session.
If a user's browser or device doesn't support one of the given features, initialization will fail and [signal session_failed] will be emitted.
This doesn't have any effect on the interface when already initialized.
- Possible values come from [url=https://developer.mozilla.org/en-US/docs/Web/API/XRReferenceSpaceType]WebXR's XRReferenceSpaceType[/url]. If you want to use a particular reference space type, it must be listed in either [member required_features] or [member optional_features].
+ Possible values come from [url=https://developer.mozilla.org/en-US/docs/Web/API/XRReferenceSpaceType]WebXR's XRReferenceSpaceType[/url], or include other features like [code]"hand-tracking"[/code] to enable hand tracking.
</member>
<member name="session_mode" type="String" setter="set_session_mode" getter="get_session_mode">
The session mode used by [method XRInterface.initialize] when setting up the WebXR session.
diff --git a/modules/webxr/godot_webxr.h b/modules/webxr/godot_webxr.h
index caa7f217af..1b3e3b6a41 100644
--- a/modules/webxr/godot_webxr.h
+++ b/modules/webxr/godot_webxr.h
@@ -45,7 +45,7 @@ enum WebXRInputEvent {
};
typedef void (*GodotWebXRSupportedCallback)(char *p_session_mode, int p_supported);
-typedef void (*GodotWebXRStartedCallback)(char *p_reference_space_type, char *p_enabled_features);
+typedef void (*GodotWebXRStartedCallback)(char *p_reference_space_type, char *p_enabled_features, char *p_environment_blend_mode);
typedef void (*GodotWebXREndedCallback)();
typedef void (*GodotWebXRFailedCallback)(char *p_message);
typedef void (*GodotWebXRInputEventCallback)(int p_event_type, int p_input_source_id);
diff --git a/modules/webxr/native/library_godot_webxr.js b/modules/webxr/native/library_godot_webxr.js
index 031530a047..155409f931 100644
--- a/modules/webxr/native/library_godot_webxr.js
+++ b/modules/webxr/native/library_godot_webxr.js
@@ -320,10 +320,14 @@ const GodotWebXR = {
// next reference space.
window.setTimeout(function () {
const reference_space_c_str = GodotRuntime.allocString(reference_space_type);
- const enabled_features_c_str = GodotRuntime.allocString(Array.from(session.enabledFeatures).join(','));
- onstarted(reference_space_c_str, enabled_features_c_str);
+ const enabled_features = 'enabledFeatures' in session ? Array.from(session.enabledFeatures) : [];
+ const enabled_features_c_str = GodotRuntime.allocString(enabled_features.join(','));
+ const environment_blend_mode = 'environmentBlendMode' in session ? session.environmentBlendMode : '';
+ const environment_blend_mode_c_str = GodotRuntime.allocString(environment_blend_mode);
+ onstarted(reference_space_c_str, enabled_features_c_str, environment_blend_mode_c_str);
GodotRuntime.free(reference_space_c_str);
GodotRuntime.free(enabled_features_c_str);
+ GodotRuntime.free(environment_blend_mode_c_str);
}, 0);
}
diff --git a/modules/webxr/native/webxr.externs.js b/modules/webxr/native/webxr.externs.js
index 35ad33fa93..18125d7869 100644
--- a/modules/webxr/native/webxr.externs.js
+++ b/modules/webxr/native/webxr.externs.js
@@ -78,6 +78,16 @@ XRSession.prototype.frameRate;
XRSession.prototype.supportedFrameRates;
/**
+ * @type {Array<string>}
+ */
+XRSession.prototype.enabledFeatures;
+
+/**
+ * @type {string}
+ */
+XRSession.prototype.environmentBlendMode;
+
+/**
* @type {?function (Event)}
*/
XRSession.prototype.onend;
diff --git a/modules/webxr/webxr_interface_js.cpp b/modules/webxr/webxr_interface_js.cpp
index 916566fc1b..78a9db9b19 100644
--- a/modules/webxr/webxr_interface_js.cpp
+++ b/modules/webxr/webxr_interface_js.cpp
@@ -58,7 +58,7 @@ void _emwebxr_on_session_supported(char *p_session_mode, int p_supported) {
interface->emit_signal(SNAME("session_supported"), session_mode, p_supported ? true : false);
}
-void _emwebxr_on_session_started(char *p_reference_space_type, char *p_enabled_features) {
+void _emwebxr_on_session_started(char *p_reference_space_type, char *p_enabled_features, char *p_environment_blend_mode) {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL(xr_server);
@@ -68,6 +68,7 @@ void _emwebxr_on_session_started(char *p_reference_space_type, char *p_enabled_f
String reference_space_type = String(p_reference_space_type);
interface->_set_reference_space_type(reference_space_type);
interface->_set_enabled_features(p_enabled_features);
+ interface->_set_environment_blend_mode(p_environment_blend_mode);
interface->emit_signal(SNAME("session_started"));
}
@@ -230,6 +231,44 @@ Array WebXRInterfaceJS::get_available_display_refresh_rates() const {
return ret;
}
+Array WebXRInterfaceJS::get_supported_environment_blend_modes() {
+ Array blend_modes;
+ // The blend mode can't be changed, so return the current blend mode as the only supported one.
+ blend_modes.push_back(environment_blend_mode);
+ return blend_modes;
+}
+
+XRInterface::EnvironmentBlendMode WebXRInterfaceJS::get_environment_blend_mode() const {
+ return environment_blend_mode;
+}
+
+bool WebXRInterfaceJS::set_environment_blend_mode(EnvironmentBlendMode p_new_environment_blend_mode) {
+ if (environment_blend_mode == p_new_environment_blend_mode) {
+ // Environment blend mode can't be changed, but we'll consider it a success to set it
+ // to what it already is.
+ return true;
+ }
+ return false;
+}
+
+void WebXRInterfaceJS::_set_environment_blend_mode(String p_blend_mode_string) {
+ if (p_blend_mode_string == "opaque") {
+ environment_blend_mode = XRInterface::XR_ENV_BLEND_MODE_OPAQUE;
+ } else if (p_blend_mode_string == "additive") {
+ environment_blend_mode = XRInterface::XR_ENV_BLEND_MODE_ADDITIVE;
+ } else if (p_blend_mode_string == "alpha-blend") {
+ environment_blend_mode = XRInterface::XR_ENV_BLEND_MODE_ALPHA_BLEND;
+ } else {
+ // Not all browsers can give us this information, so as a fallback,
+ // we'll make some guesses about the blend mode.
+ if (session_mode == "immersive-ar") {
+ environment_blend_mode = XRInterface::XR_ENV_BLEND_MODE_ALPHA_BLEND;
+ } else {
+ environment_blend_mode = XRInterface::XR_ENV_BLEND_MODE_OPAQUE;
+ }
+ }
+}
+
StringName WebXRInterfaceJS::get_name() const {
return "WebXR";
};
@@ -336,6 +375,7 @@ void WebXRInterfaceJS::uninitialize() {
texture_cache.clear();
reference_space_type.clear();
enabled_features.clear();
+ environment_blend_mode = XRInterface::XR_ENV_BLEND_MODE_OPAQUE;
initialized = false;
};
};
@@ -740,12 +780,20 @@ void WebXRInterfaceJS::_update_input_source(int p_input_source_id) {
// WebXR doesn't have a palm joint, so we calculate it by finding the middle of the middle finger metacarpal bone.
{
- // 10 is the WebXR middle finger metacarpal joint, and 12 is the offset to the transform origin.
- const float *start_pos = hand_joints + (10 * 16) + 12;
- // 11 is the WebXR middle finger phalanx proximal joint, and 12 is the offset to the transform origin.
- const float *end_pos = hand_joints + (11 * 16) + 12;
- Transform3D palm_transform;
- palm_transform.origin = (Vector3(start_pos[0], start_pos[1], start_pos[2]) + Vector3(end_pos[0], end_pos[1], end_pos[2])) / 2.0;
+ // Start by getting the middle finger metacarpal joint.
+ // Note: 10 is the WebXR middle finger metacarpal joint.
+ Transform3D palm_transform = _js_matrix_to_transform(hand_joints + (10 * 16));
+ palm_transform.basis *= bone_adjustment;
+
+ // Get the middle finger phalanx position.
+ // Note: 11 is the WebXR middle finger phalanx proximal joint and 12 is the origin offset.
+ const float *phalanx_pos = hand_joints + (11 * 16) + 12;
+ Vector3 phalanx(phalanx_pos[0], phalanx_pos[1], phalanx_pos[2]);
+
+ // Offset the palm half-way towards the phalanx joint.
+ palm_transform.origin = (palm_transform.origin + phalanx) / 2.0;
+
+ // Set the palm joint and the pose.
hand_tracker->set_hand_joint_transform(XRHandTracker::HAND_JOINT_PALM, palm_transform);
hand_tracker->set_pose("default", palm_transform, Vector3(), Vector3());
}
diff --git a/modules/webxr/webxr_interface_js.h b/modules/webxr/webxr_interface_js.h
index afce28d410..d02c8d2677 100644
--- a/modules/webxr/webxr_interface_js.h
+++ b/modules/webxr/webxr_interface_js.h
@@ -60,6 +60,8 @@ private:
String reference_space_type;
String enabled_features;
+ XRInterface::EnvironmentBlendMode environment_blend_mode = XRInterface::XR_ENV_BLEND_MODE_OPAQUE;
+
Size2 render_targetsize;
RBMap<unsigned int, RID> texture_cache;
struct Touch {
@@ -113,6 +115,10 @@ public:
virtual void set_display_refresh_rate(float p_refresh_rate) override;
virtual Array get_available_display_refresh_rates() const override;
+ virtual Array get_supported_environment_blend_modes() override;
+ virtual XRInterface::EnvironmentBlendMode get_environment_blend_mode() const override;
+ virtual bool set_environment_blend_mode(EnvironmentBlendMode p_new_environment_blend_mode) override;
+
virtual StringName get_name() const override;
virtual uint32_t get_capabilities() const override;
@@ -136,8 +142,10 @@ public:
void _on_input_event(int p_event_type, int p_input_source_id);
+ // Internal setters used by callbacks from Emscripten.
inline void _set_reference_space_type(String p_reference_space_type) { reference_space_type = p_reference_space_type; }
inline void _set_enabled_features(String p_enabled_features) { enabled_features = p_enabled_features; }
+ void _set_environment_blend_mode(String p_blend_mode_string);
WebXRInterfaceJS();
~WebXRInterfaceJS();