summaryrefslogtreecommitdiffstats
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/dds/texture_loader_dds.cpp2
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml3
-rw-r--r--modules/gdscript/gdscript.cpp6
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp62
-rw-r--r--modules/gdscript/gdscript_analyzer.h2
-rw-r--r--modules/gdscript/gdscript_compiler.cpp12
-rw-r--r--modules/gdscript/gdscript_editor.cpp6
-rw-r--r--modules/gdscript/gdscript_parser.cpp6
-rw-r--r--modules/gdscript/gdscript_parser.h2
-rw-r--r--modules/gdscript/language_server/gdscript_extend_parser.cpp2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/extend_non_gdscript_nested.gd5
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/extend_non_gdscript_nested.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/extend_unknown.gd8
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/extend_unknown.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.gd2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/warnings/redundant_await.gd53
-rw-r--r--modules/gdscript/tests/scripts/analyzer/warnings/redundant_await.out37
-rw-r--r--modules/gdscript/tests/scripts/analyzer/warnings/shadowning.gd12
-rw-r--r--modules/gdscript/tests/scripts/analyzer/warnings/shadowning.out26
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/await_without_coroutine.gd2
-rw-r--r--modules/gridmap/editor/grid_map_editor_plugin.cpp8
-rw-r--r--modules/gridmap/grid_map.cpp8
-rw-r--r--modules/mobile_vr/mobile_vr_interface.cpp9
-rw-r--r--modules/mobile_vr/mobile_vr_interface.h1
-rw-r--r--modules/mono/csharp_script.cpp140
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs6
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.props1
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs2
-rw-r--r--modules/mono/editor/bindings_generator.cpp26
-rw-r--r--modules/mono/editor/bindings_generator.h5
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs6
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs10
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs11
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs12
-rw-r--r--modules/multiplayer/scene_replication_config.cpp16
-rw-r--r--modules/navigation/nav_base.h12
-rw-r--r--modules/navigation/nav_map.cpp45
-rw-r--r--modules/navigation/nav_map.h12
-rw-r--r--modules/navigation/nav_region.cpp4
-rw-r--r--modules/navigation/nav_utils.h2
-rw-r--r--modules/openxr/action_map/openxr_action_map.cpp2
-rw-r--r--modules/openxr/action_map/openxr_interaction_profile_meta_data.cpp2
-rw-r--r--modules/openxr/extensions/openxr_extension_wrapper.h4
-rw-r--r--modules/openxr/extensions/openxr_opengl_extension.cpp41
-rw-r--r--modules/openxr/extensions/openxr_opengl_extension.h6
-rw-r--r--modules/openxr/openxr_api.cpp15
-rw-r--r--modules/openxr/openxr_api.h6
-rw-r--r--modules/openxr/openxr_interface.cpp11
-rw-r--r--modules/openxr/openxr_interface.h1
-rw-r--r--modules/openxr/register_types.cpp18
-rw-r--r--modules/openxr/scene/openxr_hand.cpp2
-rw-r--r--modules/text_server_adv/SCsub19
-rw-r--r--modules/text_server_adv/gdextension_build/SConstruct20
-rw-r--r--modules/text_server_adv/text_server_adv.cpp37
-rw-r--r--modules/text_server_adv/text_server_adv.h2
-rw-r--r--modules/text_server_adv/thorvg_svg_in_ot.cpp4
-rw-r--r--modules/text_server_adv/thorvg_svg_in_ot.h4
-rw-r--r--modules/text_server_fb/text_server_fb.cpp10
-rw-r--r--modules/text_server_fb/text_server_fb.h1
-rw-r--r--modules/text_server_fb/thorvg_svg_in_ot.cpp2
-rw-r--r--modules/text_server_fb/thorvg_svg_in_ot.h4
-rw-r--r--modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml2
-rw-r--r--modules/webxr/webxr_interface_js.cpp10
-rw-r--r--modules/webxr/webxr_interface_js.h1
70 files changed, 597 insertions, 227 deletions
diff --git a/modules/dds/texture_loader_dds.cpp b/modules/dds/texture_loader_dds.cpp
index 0bde6f62ed..e6523e3d09 100644
--- a/modules/dds/texture_loader_dds.cpp
+++ b/modules/dds/texture_loader_dds.cpp
@@ -203,7 +203,7 @@ Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_orig
} else if (format_flags & DDPF_INDEXED && format_rgb_bits == 8) {
dds_format = DDS_BGR565;
} else {
- printf("unrecognized fourcc %x format_flags: %x - rgbbits %i - red_mask %x green mask %x blue mask %x alpha mask %x\n", format_fourcc, format_flags, format_rgb_bits, format_red_mask, format_green_mask, format_blue_mask, format_alpha_mask);
+ //printf("unrecognized fourcc %x format_flags: %x - rgbbits %i - red_mask %x green mask %x blue mask %x alpha mask %x\n", format_fourcc, format_flags, format_rgb_bits, format_red_mask, format_green_mask, format_blue_mask, format_alpha_mask);
ERR_FAIL_V_MSG(Ref<Resource>(), "Unrecognized or unsupported color layout in DDS '" + p_path + "'.");
}
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index 718bf3f6d4..85ff5080f0 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -18,12 +18,13 @@
<param index="2" name="b8" type="int" />
<param index="3" name="a8" type="int" default="255" />
<description>
- Returns a [Color] constructed from red ([param r8]), green ([param g8]), blue ([param b8]), and optionally alpha ([param a8]) integer channels, each divided by [code]255.0[/code] for their final value.
+ Returns a [Color] constructed from red ([param r8]), green ([param g8]), blue ([param b8]), and optionally alpha ([param a8]) integer channels, each divided by [code]255.0[/code] for their final value. Using [method Color8] instead of the standard [Color] constructor is useful when you need to match exact color values in an [Image].
[codeblock]
var red = Color8(255, 0, 0) # Same as Color(1, 0, 0).
var dark_blue = Color8(0, 0, 51) # Same as Color(0, 0, 0.2).
var my_color = Color8(306, 255, 0, 102) # Same as Color(1.2, 1, 0, 0.4).
[/codeblock]
+ [b]Note:[/b] Due to the lower precision of [method Color8] compared to the standard [Color] constructor, a color created with [method Color8] will generally not be equal to the same color created with the standard [Color] constructor. Use [method Color.is_equal_approx] for comparisons to avoid issues with floating-point precision error.
</description>
</method>
<method name="assert">
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 1a1d021dbc..2646c1ad15 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -2483,7 +2483,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
subclass = nullptr;
break;
} else {
- Vector<StringName> extend_classes = subclass->extends;
+ Vector<GDScriptParser::IdentifierNode *> extend_classes = subclass->extends;
Ref<FileAccess> subfile = FileAccess::open(subclass->extends_path, FileAccess::READ);
if (subfile.is_null()) {
@@ -2513,7 +2513,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
}
const GDScriptParser::ClassNode *inner_class = subclass->members[i].m_class;
- if (inner_class->identifier->name == extend_classes[0]) {
+ if (inner_class->identifier->name == extend_classes[0]->name) {
extend_classes.remove_at(0);
found = true;
subclass = inner_class;
@@ -2527,7 +2527,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
}
}
} else if (subclass->extends.size() == 1) {
- *r_base_type = subclass->extends[0];
+ *r_base_type = subclass->extends[0]->name;
subclass = nullptr;
} else {
break;
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 38d5ae6b77..a2cab25ce8 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -415,7 +415,8 @@ Error GDScriptAnalyzer::resolve_class_inheritance(GDScriptParser::ClassNode *p_c
push_error("Could not resolve an empty super class path.", p_class);
return ERR_PARSE_ERROR;
}
- const StringName &name = p_class->extends[extends_index++];
+ GDScriptParser::IdentifierNode *id = p_class->extends[extends_index++];
+ const StringName &name = id->name;
base.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
if (ScriptServer::is_global_class(name)) {
@@ -426,13 +427,13 @@ Error GDScriptAnalyzer::resolve_class_inheritance(GDScriptParser::ClassNode *p_c
} else {
Ref<GDScriptParserRef> base_parser = get_parser_for(base_path);
if (base_parser.is_null()) {
- push_error(vformat(R"(Could not resolve super class "%s".)", name), p_class);
+ push_error(vformat(R"(Could not resolve super class "%s".)", name), id);
return ERR_PARSE_ERROR;
}
Error err = base_parser->raise_status(GDScriptParserRef::INHERITANCE_SOLVED);
if (err != OK) {
- push_error(vformat(R"(Could not resolve super class inheritance from "%s".)", name), p_class);
+ push_error(vformat(R"(Could not resolve super class inheritance from "%s".)", name), id);
return err;
}
base = base_parser->get_parser()->head->get_datatype();
@@ -440,19 +441,19 @@ Error GDScriptAnalyzer::resolve_class_inheritance(GDScriptParser::ClassNode *p_c
} else if (ProjectSettings::get_singleton()->has_autoload(name) && ProjectSettings::get_singleton()->get_autoload(name).is_singleton) {
const ProjectSettings::AutoloadInfo &info = ProjectSettings::get_singleton()->get_autoload(name);
if (info.path.get_extension().to_lower() != GDScriptLanguage::get_singleton()->get_extension()) {
- push_error(vformat(R"(Singleton %s is not a GDScript.)", info.name), p_class);
+ push_error(vformat(R"(Singleton %s is not a GDScript.)", info.name), id);
return ERR_PARSE_ERROR;
}
Ref<GDScriptParserRef> info_parser = get_parser_for(info.path);
if (info_parser.is_null()) {
- push_error(vformat(R"(Could not parse singleton from "%s".)", info.path), p_class);
+ push_error(vformat(R"(Could not parse singleton from "%s".)", info.path), id);
return ERR_PARSE_ERROR;
}
Error err = info_parser->raise_status(GDScriptParserRef::INHERITANCE_SOLVED);
if (err != OK) {
- push_error(vformat(R"(Could not resolve super class inheritance from "%s".)", name), p_class);
+ push_error(vformat(R"(Could not resolve super class inheritance from "%s".)", name), id);
return err;
}
base = info_parser->get_parser()->head->get_datatype();
@@ -467,7 +468,7 @@ Error GDScriptAnalyzer::resolve_class_inheritance(GDScriptParser::ClassNode *p_c
for (GDScriptParser::ClassNode *look_class : script_classes) {
if (look_class->identifier && look_class->identifier->name == name) {
if (!look_class->get_datatype().is_set()) {
- Error err = resolve_class_inheritance(look_class, p_class);
+ Error err = resolve_class_inheritance(look_class, id);
if (err) {
return err;
}
@@ -477,7 +478,7 @@ Error GDScriptAnalyzer::resolve_class_inheritance(GDScriptParser::ClassNode *p_c
break;
}
if (look_class->has_member(name)) {
- resolve_class_member(look_class, name, p_class);
+ resolve_class_member(look_class, name, id);
base = look_class->get_member(name).get_datatype();
found = true;
break;
@@ -485,27 +486,26 @@ Error GDScriptAnalyzer::resolve_class_inheritance(GDScriptParser::ClassNode *p_c
}
if (!found) {
- push_error(vformat(R"(Could not find base class "%s".)", name), p_class);
+ push_error(vformat(R"(Could not find base class "%s".)", name), id);
return ERR_PARSE_ERROR;
}
}
}
for (int index = extends_index; index < p_class->extends.size(); index++) {
+ GDScriptParser::IdentifierNode *id = p_class->extends[index];
+
if (base.kind != GDScriptParser::DataType::CLASS) {
- push_error(R"(Super type "%s" is not a GDScript. Cannot get nested types.)", p_class);
+ push_error(vformat(R"(Cannot get nested types for extension from non-GDScript type "%s".)", base.to_string()), id);
return ERR_PARSE_ERROR;
}
- // TODO: Extends could use identifier nodes. That way errors can be pointed out properly and it can be used here.
- GDScriptParser::IdentifierNode *id = parser->alloc_node<GDScriptParser::IdentifierNode>();
- id->name = p_class->extends[index];
-
reduce_identifier_from_base(id, &base);
-
GDScriptParser::DataType id_type = id->get_datatype();
+
if (!id_type.is_set()) {
- push_error(vformat(R"(Could not find type "%s" under base "%s".)", id->name, base.to_string()), p_class);
+ push_error(vformat(R"(Could not find nested type "%s".)", id->name), id);
+ return ERR_PARSE_ERROR;
}
base = id_type;
@@ -2548,7 +2548,7 @@ void GDScriptAnalyzer::reduce_await(GDScriptParser::AwaitNode *p_await) {
#ifdef DEBUG_ENABLED
GDScriptParser::DataType to_await_type = p_await->to_await->get_datatype();
- if (!(to_await_type.has_no_type() || to_await_type.is_coroutine || to_await_type.builtin_type == Variant::SIGNAL)) {
+ if (!to_await_type.is_coroutine && !to_await_type.is_variant() && to_await_type.builtin_type != Variant::SIGNAL) {
parser->push_warning(p_await, GDScriptWarning::REDUNDANT_AWAIT);
}
#endif
@@ -4778,7 +4778,7 @@ void GDScriptAnalyzer::validate_call_arg(const List<GDScriptParser::DataType> &p
}
#ifdef DEBUG_ENABLED
-bool GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_local, const String &p_context) {
+void GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_local, const String &p_context) {
const StringName &name = p_local->name;
GDScriptParser::DataType base = parser->current_class->get_datatype();
GDScriptParser::ClassNode *base_class = base.class_type;
@@ -4790,50 +4790,52 @@ bool GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_local, con
for (MethodInfo &info : gdscript_funcs) {
if (info.name == name) {
parser->push_warning(p_local, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_context, name, "built-in function");
- return true;
+ return;
}
}
+
if (Variant::has_utility_function(name)) {
parser->push_warning(p_local, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_context, name, "built-in function");
- return true;
+ return;
} else if (ClassDB::class_exists(name)) {
parser->push_warning(p_local, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_context, name, "global class");
- return true;
+ return;
+ } else if (GDScriptParser::get_builtin_type(name) != Variant::VARIANT_MAX) {
+ parser->push_warning(p_local, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_context, name, "built-in type");
+ return;
}
}
while (base_class != nullptr) {
if (base_class->has_member(name)) {
parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE, p_context, p_local->name, base_class->get_member(name).get_type_name(), itos(base_class->get_member(name).get_line()));
- return true;
+ return;
}
base_class = base_class->base_type.class_type;
}
StringName parent = base.native_type;
while (parent != StringName()) {
- ERR_FAIL_COND_V_MSG(!class_exists(parent), false, "Non-existent native base class.");
+ ERR_FAIL_COND_MSG(!class_exists(parent), "Non-existent native base class.");
if (ClassDB::has_method(parent, name, true)) {
parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "method", parent);
- return true;
+ return;
} else if (ClassDB::has_signal(parent, name, true)) {
parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "signal", parent);
- return true;
+ return;
} else if (ClassDB::has_property(parent, name, true)) {
parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "property", parent);
- return true;
+ return;
} else if (ClassDB::has_integer_constant(parent, name, true)) {
parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "constant", parent);
- return true;
+ return;
} else if (ClassDB::has_enum(parent, name, true)) {
parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "enum", parent);
- return true;
+ return;
}
parent = ClassDB::get_parent_class(parent);
}
-
- return false;
}
#endif
diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h
index 7a50b32d4c..5902035bcd 100644
--- a/modules/gdscript/gdscript_analyzer.h
+++ b/modules/gdscript/gdscript_analyzer.h
@@ -131,7 +131,7 @@ class GDScriptAnalyzer {
Ref<GDScriptParserRef> get_parser_for(const String &p_path);
void reduce_identifier_from_base_set_class(GDScriptParser::IdentifierNode *p_identifier, GDScriptParser::DataType p_identifier_datatype);
#ifdef DEBUG_ENABLED
- bool is_shadowing(GDScriptParser::IdentifierNode *p_local, const String &p_context);
+ void is_shadowing(GDScriptParser::IdentifierNode *p_local, const String &p_context);
#endif
public:
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index e27b977e9d..5413eadf60 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -1165,8 +1165,18 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
bool has_operation = assignment->operation != GDScriptParser::AssignmentNode::OP_NONE;
if (has_operation) {
// Perform operation.
- GDScriptCodeGenerator::Address op_result = codegen.add_temporary(_gdtype_from_datatype(assignment->get_datatype(), codegen.script));
GDScriptCodeGenerator::Address og_value = _parse_expression(codegen, r_error, assignment->assignee);
+
+ if (!has_setter && !assignment->use_conversion_assign) {
+ // If there's nothing special about the assignment, perform the assignment as part of the operator
+ gen->write_binary_operator(target, assignment->variant_op, og_value, assigned_value);
+ if (assigned_value.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary(); // Pop assigned value if not done before.
+ }
+ return GDScriptCodeGenerator::Address();
+ }
+
+ GDScriptCodeGenerator::Address op_result = codegen.add_temporary(_gdtype_from_datatype(assignment->get_datatype(), codegen.script));
gen->write_binary_operator(op_result, assignment->variant_op, og_value, assigned_value);
to_assign = op_result;
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 63dfd4d27c..f3a86522ae 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -1956,7 +1956,7 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context,
GDScriptParser::CompletionContext c = p_context;
c.current_line = type_test->operand->start_line;
c.current_suite = suite;
- if ((!id_type.is_set() || id_type.is_variant()) && type_test->test_datatype.is_hard_type()) {
+ if (type_test->test_datatype.is_hard_type()) {
id_type = type_test->test_datatype;
if (last_assign_line < c.current_line) {
// Override last assignment.
@@ -3368,10 +3368,10 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
if (context.current_class && context.current_class->extends.size() > 0) {
bool success = false;
- ClassDB::get_integer_constant(context.current_class->extends[0], p_symbol, &success);
+ ClassDB::get_integer_constant(context.current_class->extends[0]->name, p_symbol, &success);
if (success) {
r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_CONSTANT;
- r_result.class_name = context.current_class->extends[0];
+ r_result.class_name = context.current_class->extends[0]->name;
r_result.class_member = p_symbol;
return OK;
}
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 00a3e41c2b..e2a37ab6e9 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -712,14 +712,14 @@ void GDScriptParser::parse_extends() {
if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected superclass name after "extends".)")) {
return;
}
- current_class->extends.push_back(previous.literal);
+ current_class->extends.push_back(parse_identifier());
while (match(GDScriptTokenizer::Token::PERIOD)) {
make_completion_context(COMPLETION_INHERIT_TYPE, current_class, chain_index++);
if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected superclass name after ".".)")) {
return;
}
- current_class->extends.push_back(previous.literal);
+ current_class->extends.push_back(parse_identifier());
}
}
@@ -4479,7 +4479,7 @@ void GDScriptParser::TreePrinter::print_class(ClassNode *p_class) {
} else {
first = false;
}
- push_text(p_class->extends[i]);
+ push_text(p_class->extends[i]->name);
}
}
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index 346c9bc45d..29841ab060 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -710,7 +710,7 @@ public:
bool extends_used = false;
bool onready_used = false;
String extends_path;
- Vector<StringName> extends; // List for indexing: extends A.B.C
+ Vector<IdentifierNode *> extends; // List for indexing: extends A.B.C
DataType base_type;
String fqcn; // Fully-qualified class name. Identifies uniquely any class in the project.
#ifdef TOOLS_ENABLED
diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp
index 146ed10ceb..2ed444c7ad 100644
--- a/modules/gdscript/language_server/gdscript_extend_parser.cpp
+++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp
@@ -717,7 +717,7 @@ Dictionary ExtendGDScriptParser::dump_class_api(const GDScriptParser::ClassNode
class_api["path"] = path;
Array extends_class;
for (int i = 0; i < p_class->extends.size(); i++) {
- extends_class.append(String(p_class->extends[i]));
+ extends_class.append(String(p_class->extends[i]->name));
}
class_api["extends_class"] = extends_class;
class_api["extends_file"] = String(p_class->extends_path);
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/extend_non_gdscript_nested.gd b/modules/gdscript/tests/scripts/analyzer/errors/extend_non_gdscript_nested.gd
new file mode 100644
index 0000000000..54cf4d89ec
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/extend_non_gdscript_nested.gd
@@ -0,0 +1,5 @@
+class Foo extends RefCounted.Bar:
+ pass
+
+func test():
+ print('not ok')
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/extend_non_gdscript_nested.out b/modules/gdscript/tests/scripts/analyzer/errors/extend_non_gdscript_nested.out
new file mode 100644
index 0000000000..386d6261c6
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/extend_non_gdscript_nested.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot get nested types for extension from non-GDScript type "RefCounted".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/extend_unknown.gd b/modules/gdscript/tests/scripts/analyzer/errors/extend_unknown.gd
new file mode 100644
index 0000000000..0f7d584edb
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/extend_unknown.gd
@@ -0,0 +1,8 @@
+class Foo:
+ pass
+
+class Bar extends Foo.Baz:
+ pass
+
+func test():
+ print('not ok')
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/extend_unknown.out b/modules/gdscript/tests/scripts/analyzer/errors/extend_unknown.out
new file mode 100644
index 0000000000..42873056f2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/extend_unknown.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Could not find nested type "Baz".
diff --git a/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.gd b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.gd
index 4c02fd4b0d..292db30bcd 100644
--- a/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.gd
+++ b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.gd
@@ -11,5 +11,5 @@ func test():
print("done")
-func regular_func():
+func regular_func() -> int:
return 0
diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/redundant_await.gd b/modules/gdscript/tests/scripts/analyzer/warnings/redundant_await.gd
new file mode 100644
index 0000000000..f8844d66a7
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/warnings/redundant_await.gd
@@ -0,0 +1,53 @@
+signal my_signal()
+
+# CI cannot test async things.
+func test_signals():
+ await my_signal
+ var t: Signal = my_signal
+ await t
+
+func coroutine() -> void:
+ @warning_ignore("redundant_await")
+ await 0
+
+func not_coroutine_variant():
+ pass
+
+func not_coroutine_void() -> void:
+ pass
+
+func test():
+ const CONST_NULL = null
+ var var_null = null
+ var var_int: int = 1
+ var var_variant: Variant = 1
+ var var_array: Array = [1]
+
+ await CONST_NULL
+ await var_null
+ await var_int
+ await var_variant
+ await var_array[0]
+
+ await coroutine
+ await coroutine()
+ await coroutine.call()
+ await self.coroutine()
+ await call(&"coroutine")
+
+ await not_coroutine_variant
+ await not_coroutine_variant()
+ await self.not_coroutine_variant()
+ await not_coroutine_variant.call()
+ await call(&"not_coroutine_variant")
+
+ await not_coroutine_void
+ await not_coroutine_void()
+ await self.not_coroutine_void()
+ await not_coroutine_void.call()
+ await call(&"not_coroutine_void")
+
+ var callable: Callable = coroutine
+ await callable
+ await callable.call()
+ await callable.get_method()
diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/redundant_await.out b/modules/gdscript/tests/scripts/analyzer/warnings/redundant_await.out
new file mode 100644
index 0000000000..3d251c2906
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/warnings/redundant_await.out
@@ -0,0 +1,37 @@
+GDTEST_OK
+>> WARNING
+>> Line: 26
+>> REDUNDANT_AWAIT
+>> "await" keyword not needed in this case, because the expression isn't a coroutine nor a signal.
+>> WARNING
+>> Line: 28
+>> REDUNDANT_AWAIT
+>> "await" keyword not needed in this case, because the expression isn't a coroutine nor a signal.
+>> WARNING
+>> Line: 32
+>> REDUNDANT_AWAIT
+>> "await" keyword not needed in this case, because the expression isn't a coroutine nor a signal.
+>> WARNING
+>> Line: 38
+>> REDUNDANT_AWAIT
+>> "await" keyword not needed in this case, because the expression isn't a coroutine nor a signal.
+>> WARNING
+>> Line: 44
+>> REDUNDANT_AWAIT
+>> "await" keyword not needed in this case, because the expression isn't a coroutine nor a signal.
+>> WARNING
+>> Line: 45
+>> REDUNDANT_AWAIT
+>> "await" keyword not needed in this case, because the expression isn't a coroutine nor a signal.
+>> WARNING
+>> Line: 46
+>> REDUNDANT_AWAIT
+>> "await" keyword not needed in this case, because the expression isn't a coroutine nor a signal.
+>> WARNING
+>> Line: 51
+>> REDUNDANT_AWAIT
+>> "await" keyword not needed in this case, because the expression isn't a coroutine nor a signal.
+>> WARNING
+>> Line: 53
+>> REDUNDANT_AWAIT
+>> "await" keyword not needed in this case, because the expression isn't a coroutine nor a signal.
diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/shadowning.gd b/modules/gdscript/tests/scripts/analyzer/warnings/shadowning.gd
new file mode 100644
index 0000000000..61945c9c8f
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/warnings/shadowning.gd
@@ -0,0 +1,12 @@
+var member: int = 0
+
+@warning_ignore("unused_variable")
+func test():
+ var Array := 'Array'
+ var Node := 'Node'
+ var is_same := 'is_same'
+ var sqrt := 'sqrt'
+ var member := 'member'
+ var reference := 'reference'
+
+ print('warn')
diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/shadowning.out b/modules/gdscript/tests/scripts/analyzer/warnings/shadowning.out
new file mode 100644
index 0000000000..9d0e567534
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/warnings/shadowning.out
@@ -0,0 +1,26 @@
+GDTEST_OK
+>> WARNING
+>> Line: 5
+>> SHADOWED_GLOBAL_IDENTIFIER
+>> The variable 'Array' has the same name as a built-in type.
+>> WARNING
+>> Line: 6
+>> SHADOWED_GLOBAL_IDENTIFIER
+>> The variable 'Node' has the same name as a global class.
+>> WARNING
+>> Line: 7
+>> SHADOWED_GLOBAL_IDENTIFIER
+>> The variable 'is_same' has the same name as a built-in function.
+>> WARNING
+>> Line: 8
+>> SHADOWED_GLOBAL_IDENTIFIER
+>> The variable 'sqrt' has the same name as a built-in function.
+>> WARNING
+>> Line: 9
+>> SHADOWED_VARIABLE
+>> The local variable "member" is shadowing an already-declared variable at line 1.
+>> WARNING
+>> Line: 10
+>> SHADOWED_VARIABLE_BASE_CLASS
+>> The local variable "reference" is shadowing an already-declared method at the base class "RefCounted".
+warn
diff --git a/modules/gdscript/tests/scripts/runtime/features/await_without_coroutine.gd b/modules/gdscript/tests/scripts/runtime/features/await_without_coroutine.gd
index 9da61ab184..1c39073be9 100644
--- a/modules/gdscript/tests/scripts/runtime/features/await_without_coroutine.gd
+++ b/modules/gdscript/tests/scripts/runtime/features/await_without_coroutine.gd
@@ -4,5 +4,5 @@ func test():
print(await not_coroutine())
-func not_coroutine():
+func not_coroutine() -> String:
return "awaited"
diff --git a/modules/gridmap/editor/grid_map_editor_plugin.cpp b/modules/gridmap/editor/grid_map_editor_plugin.cpp
index 214d4d8ec2..bb5eb8e643 100644
--- a/modules/gridmap/editor/grid_map_editor_plugin.cpp
+++ b/modules/gridmap/editor/grid_map_editor_plugin.cpp
@@ -608,13 +608,13 @@ EditorPlugin::AfterGUIInput GridMapEditor::forward_spatial_input_event(Camera3D
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (mb->get_button_index() == MouseButton::WHEEL_UP && (mb->is_command_or_control_pressed() || mb->is_shift_pressed())) {
+ if (mb->get_button_index() == MouseButton::WHEEL_UP && (mb->is_command_or_control_pressed())) {
if (mb->is_pressed()) {
floor->set_value(floor->get_value() + mb->get_factor());
}
return EditorPlugin::AFTER_GUI_INPUT_STOP; // Eaten.
- } else if (mb->get_button_index() == MouseButton::WHEEL_DOWN && (mb->is_command_or_control_pressed() || mb->is_shift_pressed())) {
+ } else if (mb->get_button_index() == MouseButton::WHEEL_DOWN && (mb->is_command_or_control_pressed())) {
if (mb->is_pressed()) {
floor->set_value(floor->get_value() - mb->get_factor());
}
@@ -753,7 +753,7 @@ EditorPlugin::AfterGUIInput GridMapEditor::forward_spatial_input_event(Camera3D
Ref<InputEventPanGesture> pan_gesture = p_event;
if (pan_gesture.is_valid()) {
- if (pan_gesture->is_alt_pressed() && (pan_gesture->is_command_or_control_pressed() || pan_gesture->is_shift_pressed())) {
+ if (pan_gesture->is_alt_pressed() && pan_gesture->is_command_or_control_pressed()) {
const real_t delta = pan_gesture->get_delta().y * 0.5;
accumulated_floor_delta += delta;
int step = 0;
@@ -913,7 +913,7 @@ void GridMapEditor::update_palette() {
}
void GridMapEditor::edit(GridMap *p_gridmap) {
- if (node) {
+ if (node && node->is_connected("cell_size_changed", callable_mp(this, &GridMapEditor::_draw_grids))) {
node->disconnect("cell_size_changed", callable_mp(this, &GridMapEditor::_draw_grids));
}
diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp
index 3c0bd56e86..db8c645558 100644
--- a/modules/gridmap/grid_map.cpp
+++ b/modules/gridmap/grid_map.cpp
@@ -557,10 +557,14 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
}
//erase navigation
- for (const KeyValue<IndexKey, Octant::NavigationCell> &E : g.navigation_cell_ids) {
- NavigationServer3D::get_singleton()->free(E.value.region);
+ for (KeyValue<IndexKey, Octant::NavigationCell> &E : g.navigation_cell_ids) {
+ if (E.value.region.is_valid()) {
+ NavigationServer3D::get_singleton()->free(E.value.region);
+ E.value.region = RID();
+ }
if (E.value.navigation_mesh_debug_instance.is_valid()) {
RS::get_singleton()->free(E.value.navigation_mesh_debug_instance);
+ E.value.navigation_mesh_debug_instance = RID();
}
}
g.navigation_cell_ids.clear();
diff --git a/modules/mobile_vr/mobile_vr_interface.cpp b/modules/mobile_vr/mobile_vr_interface.cpp
index 5fab53441c..94a3f0777e 100644
--- a/modules/mobile_vr/mobile_vr_interface.cpp
+++ b/modules/mobile_vr/mobile_vr_interface.cpp
@@ -372,6 +372,15 @@ void MobileVRInterface::uninitialize() {
};
};
+Dictionary MobileVRInterface::get_system_info() {
+ Dictionary dict;
+
+ dict[SNAME("XRRuntimeName")] = String("Godot mobile VR interface");
+ dict[SNAME("XRRuntimeVersion")] = String("");
+
+ return dict;
+}
+
bool MobileVRInterface::supports_play_area_mode(XRInterface::PlayAreaMode p_mode) {
// This interface has no positional tracking so fix this to 3DOF
return p_mode == XR_PLAY_AREA_3DOF;
diff --git a/modules/mobile_vr/mobile_vr_interface.h b/modules/mobile_vr/mobile_vr_interface.h
index 12075eda82..f680d8aa11 100644
--- a/modules/mobile_vr/mobile_vr_interface.h
+++ b/modules/mobile_vr/mobile_vr_interface.h
@@ -141,6 +141,7 @@ public:
virtual bool is_initialized() const override;
virtual bool initialize() override;
virtual void uninitialize() override;
+ virtual Dictionary get_system_info() override;
virtual bool supports_play_area_mode(XRInterface::PlayAreaMode p_mode) override;
virtual XRInterface::PlayAreaMode get_play_area_mode() const override;
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 932e97c46b..a77b1d83ad 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -42,7 +42,6 @@
#ifdef TOOLS_ENABLED
#include "core/os/keyboard.h"
-#include "editor/bindings_generator.h"
#include "editor/editor_internal_calls.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
@@ -103,13 +102,6 @@ void CSharpLanguage::init() {
}
#endif
-#if defined(TOOLS_ENABLED) && defined(DEBUG_METHODS_ENABLED)
- // Generate the bindings here, before loading assemblies. The Godot assemblies
- // may be missing if the glue wasn't generated yet in order to build them.
- List<String> cmdline_args = OS::get_singleton()->get_cmdline_args();
- BindingsGenerator::handle_cmdline_args(cmdline_args);
-#endif
-
GLOBAL_DEF("dotnet/project/assembly_name", "");
#ifdef TOOLS_ENABLED
GLOBAL_DEF("dotnet/project/solution_directory", "");
@@ -342,8 +334,8 @@ bool CSharpLanguage::is_using_templates() {
}
Ref<Script> CSharpLanguage::make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const {
- Ref<CSharpScript> script;
- script.instantiate();
+ Ref<CSharpScript> scr;
+ scr.instantiate();
String class_name_no_spaces = p_class_name.replace(" ", "_");
String base_class_name = get_base_class_name(p_base_class_name, class_name_no_spaces);
@@ -352,8 +344,8 @@ Ref<Script> CSharpLanguage::make_template(const String &p_template, const String
.replace("_BASE_", base_class_name)
.replace("_CLASS_", class_name_no_spaces)
.replace("_TS_", _get_indentation());
- script->set_source_code(processed_template);
- return script;
+ scr->set_source_code(processed_template);
+ return scr;
}
Vector<ScriptLanguage::ScriptTemplate> CSharpLanguage::get_built_in_templates(StringName p_object) {
@@ -788,28 +780,28 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
// As scripts are going to be reloaded, must proceed without locking here
- for (Ref<CSharpScript> &script : scripts) {
+ for (Ref<CSharpScript> &scr : scripts) {
// If someone removes a script from a node, deletes the script, builds, adds a script to the
// same node, then builds again, the script might have no path and also no script_class. In
// that case, we can't (and don't need to) reload it.
- if (script->get_path().is_empty() && !script->valid) {
+ if (scr->get_path().is_empty() && !scr->valid) {
continue;
}
- to_reload.push_back(script);
+ to_reload.push_back(scr);
// Script::instances are deleted during managed object disposal, which happens on domain finalize.
// Only placeholders are kept. Therefore we need to keep a copy before that happens.
- for (Object *obj : script->instances) {
- script->pending_reload_instances.insert(obj->get_instance_id());
+ for (Object *obj : scr->instances) {
+ scr->pending_reload_instances.insert(obj->get_instance_id());
// Since this script instance wasn't a placeholder, add it to the list of placeholders
// that will have to be eventually replaced with a script instance in case it turns into one.
// This list is not cleared after the reload and the collected instances only leave
// the list if the script is instantiated or if it was a tool script but becomes a
// non-tool script in a rebuild.
- script->pending_replace_placeholders.insert(obj->get_instance_id());
+ scr->pending_replace_placeholders.insert(obj->get_instance_id());
RefCounted *rc = Object::cast_to<RefCounted>(obj);
if (rc) {
@@ -818,9 +810,9 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
}
#ifdef TOOLS_ENABLED
- for (PlaceHolderScriptInstance *script_instance : script->placeholders) {
- Object *obj = script_instance->get_owner();
- script->pending_reload_instances.insert(obj->get_instance_id());
+ for (PlaceHolderScriptInstance *instance : scr->placeholders) {
+ Object *obj = instance->get_owner();
+ scr->pending_reload_instances.insert(obj->get_instance_id());
RefCounted *rc = Object::cast_to<RefCounted>(obj);
if (rc) {
@@ -830,9 +822,9 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
#endif
// Save state and remove script from instances
- RBMap<ObjectID, CSharpScript::StateBackup> &owners_map = script->pending_reload_state;
+ RBMap<ObjectID, CSharpScript::StateBackup> &owners_map = scr->pending_reload_state;
- for (Object *obj : script->instances) {
+ for (Object *obj : scr->instances) {
ERR_CONTINUE(!obj->get_script_instance());
CSharpInstance *csi = static_cast<CSharpInstance *>(obj->get_script_instance());
@@ -857,14 +849,14 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
}
// After the state of all instances is saved, clear scripts and script instances
- for (Ref<CSharpScript> &script : scripts) {
- while (script->instances.begin()) {
- Object *obj = *script->instances.begin();
+ for (Ref<CSharpScript> &scr : scripts) {
+ while (scr->instances.begin()) {
+ Object *obj = *scr->instances.begin();
obj->set_script(Ref<RefCounted>()); // Remove script and existing script instances (placeholder are not removed before domain reload)
}
- script->was_tool_before_reload = script->tool;
- script->_clear();
+ scr->was_tool_before_reload = scr->tool;
+ scr->_clear();
}
// Do domain reload
@@ -909,44 +901,44 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
List<Ref<CSharpScript>> to_reload_state;
- for (Ref<CSharpScript> &script : to_reload) {
+ for (Ref<CSharpScript> &scr : to_reload) {
#ifdef TOOLS_ENABLED
- script->exports_invalidated = true;
+ scr->exports_invalidated = true;
#endif
- if (!script->get_path().is_empty()) {
- script->reload(p_soft_reload);
+ if (!scr->get_path().is_empty()) {
+ scr->reload(p_soft_reload);
- if (!script->valid) {
- script->pending_reload_instances.clear();
- script->pending_reload_state.clear();
+ if (!scr->valid) {
+ scr->pending_reload_instances.clear();
+ scr->pending_reload_state.clear();
continue;
}
} else {
- bool success = GDMonoCache::managed_callbacks.ScriptManagerBridge_TryReloadRegisteredScriptWithClass(script.ptr());
+ bool success = GDMonoCache::managed_callbacks.ScriptManagerBridge_TryReloadRegisteredScriptWithClass(scr.ptr());
if (!success) {
// Couldn't reload
- script->pending_reload_instances.clear();
- script->pending_reload_state.clear();
+ scr->pending_reload_instances.clear();
+ scr->pending_reload_state.clear();
continue;
}
}
- StringName native_name = script->get_instance_base_type();
+ StringName native_name = scr->get_instance_base_type();
{
- for (const ObjectID &obj_id : script->pending_reload_instances) {
+ for (const ObjectID &obj_id : scr->pending_reload_instances) {
Object *obj = ObjectDB::get_instance(obj_id);
if (!obj) {
- script->pending_reload_state.erase(obj_id);
+ scr->pending_reload_state.erase(obj_id);
continue;
}
if (!ClassDB::is_parent_class(obj->get_class_name(), native_name)) {
// No longer inherits the same compatible type, can't reload
- script->pending_reload_state.erase(obj_id);
+ scr->pending_reload_state.erase(obj_id);
continue;
}
@@ -954,11 +946,11 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
// Check if the script must be instantiated or kept as a placeholder
// when the script may not be a tool (see #65266)
- bool replace_placeholder = script->pending_replace_placeholders.has(obj->get_instance_id());
- if (!script->is_tool() && script->was_tool_before_reload) {
+ bool replace_placeholder = scr->pending_replace_placeholders.has(obj->get_instance_id());
+ if (!scr->is_tool() && scr->was_tool_before_reload) {
// The script was a tool before the rebuild so the removal was intentional.
replace_placeholder = false;
- script->pending_replace_placeholders.erase(obj->get_instance_id());
+ scr->pending_replace_placeholders.erase(obj->get_instance_id());
}
#ifdef TOOLS_ENABLED
@@ -967,20 +959,20 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
// Non-placeholder script instances are removed in godot_icall_Object_Disposed.
CRASH_COND(!si->is_placeholder());
- if (replace_placeholder || script->is_tool() || ScriptServer::is_scripting_enabled()) {
+ if (replace_placeholder || scr->is_tool() || ScriptServer::is_scripting_enabled()) {
// Replace placeholder with a script instance.
- CSharpScript::StateBackup &state_backup = script->pending_reload_state[obj_id];
+ CSharpScript::StateBackup &state_backup = scr->pending_reload_state[obj_id];
// Backup placeholder script instance state before replacing it with a script instance.
si->get_property_state(state_backup.properties);
- ScriptInstance *script_instance = script->instance_create(obj);
+ ScriptInstance *instance = scr->instance_create(obj);
- if (script_instance) {
- script->placeholders.erase(static_cast<PlaceHolderScriptInstance *>(si));
- script->pending_replace_placeholders.erase(obj->get_instance_id());
- obj->set_script_instance(script_instance);
+ if (instance) {
+ scr->placeholders.erase(static_cast<PlaceHolderScriptInstance *>(si));
+ scr->pending_replace_placeholders.erase(obj->get_instance_id());
+ obj->set_script_instance(instance);
}
}
@@ -991,18 +983,18 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
#endif
// Re-create the script instance.
- if (replace_placeholder || script->is_tool() || ScriptServer::is_scripting_enabled()) {
+ if (replace_placeholder || scr->is_tool() || ScriptServer::is_scripting_enabled()) {
// Create script instance or replace placeholder with a script instance.
- ScriptInstance *script_instance = script->instance_create(obj);
+ ScriptInstance *instance = scr->instance_create(obj);
- if (script_instance) {
- script->pending_replace_placeholders.erase(obj->get_instance_id());
- obj->set_script_instance(script_instance);
+ if (instance) {
+ scr->pending_replace_placeholders.erase(obj->get_instance_id());
+ obj->set_script_instance(instance);
continue;
}
}
// The script instance could not be instantiated or wasn't in the list of placeholders to replace.
- obj->set_script(script);
+ obj->set_script(scr);
#if DEBUG_ENABLED
// If we reached here, the instantiated script must be a placeholder.
CRASH_COND(!obj->get_script_instance()->is_placeholder());
@@ -1010,21 +1002,21 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
}
}
- to_reload_state.push_back(script);
+ to_reload_state.push_back(scr);
}
- for (Ref<CSharpScript> &script : to_reload_state) {
- for (const ObjectID &obj_id : script->pending_reload_instances) {
+ for (Ref<CSharpScript> &scr : to_reload_state) {
+ for (const ObjectID &obj_id : scr->pending_reload_instances) {
Object *obj = ObjectDB::get_instance(obj_id);
if (!obj) {
- script->pending_reload_state.erase(obj_id);
+ scr->pending_reload_state.erase(obj_id);
continue;
}
ERR_CONTINUE(!obj->get_script_instance());
- CSharpScript::StateBackup &state_backup = script->pending_reload_state[obj_id];
+ CSharpScript::StateBackup &state_backup = scr->pending_reload_state[obj_id];
CSharpInstance *csi = CAST_CSHARP_INSTANCE(obj->get_script_instance());
@@ -1041,8 +1033,8 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
}
}
- script->pending_reload_instances.clear();
- script->pending_reload_state.clear();
+ scr->pending_reload_instances.clear();
+ scr->pending_reload_state.clear();
}
// Deserialize managed callables
@@ -2152,8 +2144,8 @@ bool CSharpScript::_update_exports(PlaceHolderScriptInstance *p_instance_to_upda
_update_exports_values(values, propnames);
if (changed) {
- for (PlaceHolderScriptInstance *script_instance : placeholders) {
- script_instance->update(propnames, values);
+ for (PlaceHolderScriptInstance *instance : placeholders) {
+ instance->update(propnames, values);
}
} else {
p_instance_to_update->update(propnames, values);
@@ -2719,28 +2711,28 @@ Ref<Resource> ResourceFormatLoaderCSharpScript::load(const String &p_path, const
// TODO ignore anything inside bin/ and obj/ in tools builds?
- Ref<CSharpScript> script;
+ Ref<CSharpScript> scr;
if (GDMonoCache::godot_api_cache_updated) {
- GDMonoCache::managed_callbacks.ScriptManagerBridge_GetOrCreateScriptBridgeForPath(&p_path, &script);
+ GDMonoCache::managed_callbacks.ScriptManagerBridge_GetOrCreateScriptBridgeForPath(&p_path, &scr);
} else {
- script = Ref<CSharpScript>(memnew(CSharpScript));
+ scr = Ref<CSharpScript>(memnew(CSharpScript));
}
#if defined(DEBUG_ENABLED) || defined(TOOLS_ENABLED)
- Error err = script->load_source_code(p_path);
+ Error err = scr->load_source_code(p_path);
ERR_FAIL_COND_V_MSG(err != OK, Ref<Resource>(), "Cannot load C# script file '" + p_path + "'.");
#endif
- script->set_path(p_original_path);
+ scr->set_path(p_original_path);
- script->reload();
+ scr->reload();
if (r_error) {
*r_error = OK;
}
- return script;
+ return scr;
}
void ResourceFormatLoaderCSharpScript::get_recognized_extensions(List<String> *p_extensions) const {
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
index f0c9043fd5..7f627f0dc4 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
@@ -26,6 +26,12 @@ namespace Godot.SourceGenerators
toggle != null &&
toggle.Equals("true", StringComparison.OrdinalIgnoreCase);
+ public static bool IsGodotSourceGeneratorDisabled(this GeneratorExecutionContext context, string generatorName) =>
+ AreGodotSourceGeneratorsDisabled(context) ||
+ (context.TryGetGlobalAnalyzerProperty("GodotDisabledSourceGenerators", out string? disabledGenerators) &&
+ disabledGenerators != null &&
+ disabledGenerators.Split(';').Contains(generatorName));
+
public static bool InheritsFrom(this INamedTypeSymbol? symbol, string assemblyName, string typeFullName)
{
while (symbol != null)
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.props b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.props
index 2a8ae7f958..56c51159d0 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.props
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.props
@@ -1,6 +1,7 @@
<Project>
<ItemGroup>
<!-- $(GodotProjectDir) is defined by Godot.NET.Sdk -->
+ <CompilerVisibleProperty Include="GodotDisabledSourceGenerators" />
<CompilerVisibleProperty Include="GodotProjectDir" />
<CompilerVisibleProperty Include="GodotProjectDirBase64" />
<CompilerVisibleProperty Include="GodotSourceGenerators" />
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs
index 47a4516948..467313dc28 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs
@@ -13,7 +13,7 @@ namespace Godot.SourceGenerators
public void Execute(GeneratorExecutionContext context)
{
- if (context.IsGodotToolsProject())
+ if (context.IsGodotToolsProject() || context.IsGodotSourceGeneratorDisabled("GodotPluginsInitializer"))
return;
string source =
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs
index f79909589e..8b75530380 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs
@@ -16,7 +16,7 @@ namespace Godot.SourceGenerators
public void Execute(GeneratorExecutionContext context)
{
- if (context.AreGodotSourceGeneratorsDisabled())
+ if (context.IsGodotSourceGeneratorDisabled("ScriptMethods"))
return;
INamedTypeSymbol[] godotClasses = context
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs
index d14e3c3781..01aafe9c74 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs
@@ -14,7 +14,7 @@ namespace Godot.SourceGenerators
{
public void Execute(GeneratorExecutionContext context)
{
- if (context.AreGodotSourceGeneratorsDisabled())
+ if (context.IsGodotSourceGeneratorDisabled("ScriptPathAttribute"))
return;
if (context.IsGodotToolsProject())
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
index d333c24451..ef8e6f8fff 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
@@ -16,7 +16,7 @@ namespace Godot.SourceGenerators
public void Execute(GeneratorExecutionContext context)
{
- if (context.AreGodotSourceGeneratorsDisabled())
+ if (context.IsGodotSourceGeneratorDisabled("ScriptProperties"))
return;
INamedTypeSymbol[] godotClasses = context
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs
index 089ee3f196..ac908a6de3 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs
@@ -17,7 +17,7 @@ namespace Godot.SourceGenerators
public void Execute(GeneratorExecutionContext context)
{
- if (context.AreGodotSourceGeneratorsDisabled())
+ if (context.IsGodotSourceGeneratorDisabled("ScriptPropertyDefVal"))
return;
INamedTypeSymbol[] godotClasses = context
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs
index d8c6f3a196..97771b721d 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs
@@ -16,7 +16,7 @@ namespace Godot.SourceGenerators
public void Execute(GeneratorExecutionContext context)
{
- if (context.AreGodotSourceGeneratorsDisabled())
+ if (context.IsGodotSourceGeneratorDisabled("ScriptSerialization"))
return;
INamedTypeSymbol[] godotClasses = context
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
index d67cb5349d..f40322bd89 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
@@ -23,7 +23,7 @@ namespace Godot.SourceGenerators
public void Execute(GeneratorExecutionContext context)
{
- if (context.AreGodotSourceGeneratorsDisabled())
+ if (context.IsGodotSourceGeneratorDisabled("ScriptSignals"))
return;
INamedTypeSymbol[] godotClasses = context
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index 83101c1443..6690a3badb 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -523,7 +523,10 @@ void BindingsGenerator::_append_xml_method(StringBuilder &p_xml_output, const Ty
p_xml_output.append(target_imethod->proxy_name);
p_xml_output.append("\"/>");
} else {
- ERR_PRINT("Cannot resolve method reference in documentation: '" + p_link_target + "'.");
+ if (!p_target_itype->is_intentionally_ignored(p_link_target)) {
+ ERR_PRINT("Cannot resolve method reference in documentation: '" + p_link_target + "'.");
+ }
+
_append_xml_undeclared(p_xml_output, p_link_target);
}
}
@@ -563,7 +566,10 @@ void BindingsGenerator::_append_xml_member(StringBuilder &p_xml_output, const Ty
p_xml_output.append(target_iprop->proxy_name);
p_xml_output.append("\"/>");
} else {
- ERR_PRINT("Cannot resolve member reference in documentation: '" + p_link_target + "'.");
+ if (!p_target_itype->is_intentionally_ignored(p_link_target)) {
+ ERR_PRINT("Cannot resolve member reference in documentation: '" + p_link_target + "'.");
+ }
+
_append_xml_undeclared(p_xml_output, p_link_target);
}
}
@@ -591,7 +597,10 @@ void BindingsGenerator::_append_xml_signal(StringBuilder &p_xml_output, const Ty
p_xml_output.append(target_isignal->proxy_name);
p_xml_output.append("\"/>");
} else {
- ERR_PRINT("Cannot resolve signal reference in documentation: '" + p_link_target + "'.");
+ if (!p_target_itype->is_intentionally_ignored(p_link_target)) {
+ ERR_PRINT("Cannot resolve signal reference in documentation: '" + p_link_target + "'.");
+ }
+
_append_xml_undeclared(p_xml_output, p_link_target);
}
}
@@ -613,7 +622,10 @@ void BindingsGenerator::_append_xml_enum(StringBuilder &p_xml_output, const Type
p_xml_output.append(target_enum_itype.proxy_name); // Includes nesting class if any
p_xml_output.append("\"/>");
} else {
- ERR_PRINT("Cannot resolve enum reference in documentation: '" + p_link_target + "'.");
+ if (!p_target_itype->is_intentionally_ignored(p_link_target)) {
+ ERR_PRINT("Cannot resolve enum reference in documentation: '" + p_link_target + "'.");
+ }
+
_append_xml_undeclared(p_xml_output, p_link_target);
}
}
@@ -673,7 +685,10 @@ void BindingsGenerator::_append_xml_constant(StringBuilder &p_xml_output, const
// Also search in @GlobalScope as a last resort if no class was specified
_append_xml_constant_in_global_scope(p_xml_output, p_target_cname, p_link_target);
} else {
- ERR_PRINT("Cannot resolve constant reference in documentation: '" + p_link_target + "'.");
+ if (!p_target_itype->is_intentionally_ignored(p_link_target)) {
+ ERR_PRINT("Cannot resolve constant reference in documentation: '" + p_link_target + "'.");
+ }
+
_append_xml_undeclared(p_xml_output, p_link_target);
}
}
@@ -2936,6 +2951,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
if (method_has_ptr_parameter(method_info)) {
// Pointers are not supported.
+ itype.ignored_members.insert(method_info.name);
continue;
}
diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h
index 5c266ed31f..eac281ddb4 100644
--- a/modules/mono/editor/bindings_generator.h
+++ b/modules/mono/editor/bindings_generator.h
@@ -408,6 +408,7 @@ class BindingsGenerator {
List<PropertyInterface> properties;
List<MethodInterface> methods;
List<SignalInterface> signals_;
+ HashSet<String> ignored_members;
bool has_virtual_methods = false;
@@ -471,6 +472,10 @@ class BindingsGenerator {
return nullptr;
}
+ bool is_intentionally_ignored(const String &p_name) const {
+ return ignored_members.has(p_name);
+ }
+
private:
static DocData::ClassDoc *_get_type_doc(TypeInterface &itype) {
String doc_name = itype.name.begins_with("_") ? itype.name.substr(1) : itype.name;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
index 8598c32760..5163ea5113 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
@@ -554,6 +554,7 @@ namespace Godot.Collections
// instead of growing it as we add items.
if (collection.TryGetNonEnumeratedCount(out int count))
{
+ int oldCount = Count;
Resize(Count + count);
using var enumerator = collection.GetEnumerator();
@@ -561,7 +562,7 @@ namespace Godot.Collections
for (int i = 0; i < count; i++)
{
enumerator.MoveNext();
- this[count + i] = Variant.From(enumerator.Current);
+ this[oldCount + i] = Variant.From(enumerator.Current);
}
return;
@@ -1578,6 +1579,7 @@ namespace Godot.Collections
// instead of growing it as we add items.
if (collection.TryGetNonEnumeratedCount(out int count))
{
+ int oldCount = Count;
Resize(Count + count);
using var enumerator = collection.GetEnumerator();
@@ -1585,7 +1587,7 @@ namespace Godot.Collections
for (int i = 0; i < count; i++)
{
enumerator.MoveNext();
- this[count + i] = enumerator.Current;
+ this[oldCount + i] = enumerator.Current;
}
return;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs
index e849939ebb..0dac8205b6 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs
@@ -504,15 +504,15 @@ namespace Godot
}
/// <summary>
- /// Converts a <see cref="Vector2"/> to a <see cref="Vector2I"/>.
+ /// Converts a <see cref="Vector2"/> to a <see cref="Vector2I"/> by truncating
+ /// components' fractional parts (rounding towards zero). For a different
+ /// behavior consider passing the result of <see cref="Vector2.Ceil"/>,
+ /// <see cref="Vector2.Floor"/> or <see cref="Vector2.Round"/> to this conversion operator instead.
/// </summary>
/// <param name="value">The vector to convert.</param>
public static explicit operator Vector2I(Vector2 value)
{
- return new Vector2I(
- Mathf.RoundToInt(value.X),
- Mathf.RoundToInt(value.Y)
- );
+ return new Vector2I((int)value.X, (int)value.Y);
}
/// <summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs
index fe899527ef..a2927533f8 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs
@@ -559,16 +559,15 @@ namespace Godot
}
/// <summary>
- /// Converts a <see cref="Vector3"/> to a <see cref="Vector3I"/>.
+ /// Converts a <see cref="Vector3"/> to a <see cref="Vector3I"/> by truncating
+ /// components' fractional parts (rounding towards zero). For a different
+ /// behavior consider passing the result of <see cref="Vector3.Ceil"/>,
+ /// <see cref="Vector3.Floor"/> or <see cref="Vector3.Round"/> to this conversion operator instead.
/// </summary>
/// <param name="value">The vector to convert.</param>
public static explicit operator Vector3I(Vector3 value)
{
- return new Vector3I(
- Mathf.RoundToInt(value.X),
- Mathf.RoundToInt(value.Y),
- Mathf.RoundToInt(value.Z)
- );
+ return new Vector3I((int)value.X, (int)value.Y, (int)value.Z);
}
/// <summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs
index f065327066..bb552b939d 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs
@@ -580,17 +580,15 @@ namespace Godot
}
/// <summary>
- /// Converts a <see cref="Vector4"/> to a <see cref="Vector4I"/>.
+ /// Converts a <see cref="Vector4"/> to a <see cref="Vector4I"/> by truncating
+ /// components' fractional parts (rounding towards zero). For a different
+ /// behavior consider passing the result of <see cref="Vector4.Ceil"/>,
+ /// <see cref="Vector4.Floor"/> or <see cref="Vector4.Round"/> to this conversion operator instead.
/// </summary>
/// <param name="value">The vector to convert.</param>
public static explicit operator Vector4I(Vector4 value)
{
- return new Vector4I(
- Mathf.RoundToInt(value.X),
- Mathf.RoundToInt(value.Y),
- Mathf.RoundToInt(value.Z),
- Mathf.RoundToInt(value.W)
- );
+ return new Vector4I((int)value.X, (int)value.Y, (int)value.Z, (int)value.W);
}
/// <summary>
diff --git a/modules/multiplayer/scene_replication_config.cpp b/modules/multiplayer/scene_replication_config.cpp
index f8006228de..b91c755c62 100644
--- a/modules/multiplayer/scene_replication_config.cpp
+++ b/modules/multiplayer/scene_replication_config.cpp
@@ -51,6 +51,9 @@ bool SceneReplicationConfig::_set(const StringName &p_name, const Variant &p_val
ERR_FAIL_INDEX_V(idx, properties.size(), false);
ReplicationProperty &prop = properties[idx];
if (what == "sync") {
+ if ((bool)p_value == prop.sync) {
+ return true;
+ }
prop.sync = p_value;
if (prop.sync) {
sync_props.push_back(prop.name);
@@ -59,6 +62,9 @@ bool SceneReplicationConfig::_set(const StringName &p_name, const Variant &p_val
}
return true;
} else if (what == "spawn") {
+ if ((bool)p_value == prop.spawn) {
+ return true;
+ }
prop.spawn = p_value;
if (prop.spawn) {
spawn_props.push_back(prop.name);
@@ -132,16 +138,18 @@ void SceneReplicationConfig::add_property(const NodePath &p_path, int p_index) {
spawn_props.clear();
for (const ReplicationProperty &prop : properties) {
if (prop.sync) {
- sync_props.push_back(p_path);
+ sync_props.push_back(prop.name);
}
if (prop.spawn) {
- spawn_props.push_back(p_path);
+ spawn_props.push_back(prop.name);
}
}
}
void SceneReplicationConfig::remove_property(const NodePath &p_path) {
properties.erase(p_path);
+ sync_props.erase(p_path);
+ spawn_props.erase(p_path);
}
bool SceneReplicationConfig::has_property(const NodePath &p_path) const {
@@ -178,7 +186,7 @@ void SceneReplicationConfig::property_set_spawn(const NodePath &p_path, bool p_e
spawn_props.clear();
for (const ReplicationProperty &prop : properties) {
if (prop.spawn) {
- spawn_props.push_back(p_path);
+ spawn_props.push_back(prop.name);
}
}
}
@@ -199,7 +207,7 @@ void SceneReplicationConfig::property_set_sync(const NodePath &p_path, bool p_en
sync_props.clear();
for (const ReplicationProperty &prop : properties) {
if (prop.sync) {
- sync_props.push_back(p_path);
+ sync_props.push_back(prop.name);
}
}
}
diff --git a/modules/navigation/nav_base.h b/modules/navigation/nav_base.h
index e729f7d408..d4354f929d 100644
--- a/modules/navigation/nav_base.h
+++ b/modules/navigation/nav_base.h
@@ -40,8 +40,8 @@ class NavMap;
class NavBase : public NavRid {
protected:
uint32_t navigation_layers = 1;
- float enter_cost = 0.0;
- float travel_cost = 1.0;
+ real_t enter_cost = 0.0;
+ real_t travel_cost = 1.0;
ObjectID owner_id;
NavigationUtilities::PathSegmentType type;
@@ -51,11 +51,11 @@ public:
void set_navigation_layers(uint32_t p_navigation_layers) { navigation_layers = p_navigation_layers; }
uint32_t get_navigation_layers() const { return navigation_layers; }
- void set_enter_cost(float p_enter_cost) { enter_cost = MAX(p_enter_cost, 0.0); }
- float get_enter_cost() const { return enter_cost; }
+ void set_enter_cost(real_t p_enter_cost) { enter_cost = MAX(p_enter_cost, 0.0); }
+ real_t get_enter_cost() const { return enter_cost; }
- void set_travel_cost(float p_travel_cost) { travel_cost = MAX(p_travel_cost, 0.0); }
- float get_travel_cost() const { return travel_cost; }
+ void set_travel_cost(real_t p_travel_cost) { travel_cost = MAX(p_travel_cost, 0.0); }
+ real_t get_travel_cost() const { return travel_cost; }
void set_owner_id(ObjectID p_owner_id) { owner_id = p_owner_id; }
ObjectID get_owner_id() const { return owner_id; }
diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp
index b1674c8fc5..91b13ba9c4 100644
--- a/modules/navigation/nav_map.cpp
+++ b/modules/navigation/nav_map.cpp
@@ -55,17 +55,17 @@ void NavMap::set_up(Vector3 p_up) {
regenerate_polygons = true;
}
-void NavMap::set_cell_size(float p_cell_size) {
+void NavMap::set_cell_size(real_t p_cell_size) {
cell_size = p_cell_size;
regenerate_polygons = true;
}
-void NavMap::set_edge_connection_margin(float p_edge_connection_margin) {
+void NavMap::set_edge_connection_margin(real_t p_edge_connection_margin) {
edge_connection_margin = p_edge_connection_margin;
regenerate_links = true;
}
-void NavMap::set_link_connection_radius(float p_link_connection_radius) {
+void NavMap::set_link_connection_radius(real_t p_link_connection_radius) {
link_connection_radius = p_link_connection_radius;
regenerate_links = true;
}
@@ -100,8 +100,8 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
const gd::Polygon *end_poly = nullptr;
Vector3 begin_point;
Vector3 end_point;
- float begin_d = 1e20;
- float end_d = 1e20;
+ real_t begin_d = FLT_MAX;
+ real_t end_d = FLT_MAX;
// Find the initial poly and the end poly on this map.
for (const gd::Polygon &p : polygons) {
// Only consider the polygon if it in a region with compatible layers.
@@ -114,7 +114,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
const Face3 face(p.points[0].pos, p.points[point_id - 1].pos, p.points[point_id].pos);
Vector3 point = face.get_closest_point_to(p_origin);
- float distance_to_point = point.distance_to(p_origin);
+ real_t distance_to_point = point.distance_to(p_origin);
if (distance_to_point < begin_d) {
begin_d = distance_to_point;
begin_poly = &p;
@@ -183,7 +183,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
bool found_route = false;
const gd::Polygon *reachable_end = nullptr;
- float reachable_d = 1e30;
+ real_t reachable_d = FLT_MAX;
bool is_reachable = true;
while (true) {
@@ -199,8 +199,8 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
}
const gd::NavigationPoly &least_cost_poly = navigation_polys[least_cost_id];
- float poly_enter_cost = 0.0;
- float poly_travel_cost = least_cost_poly.poly->owner->get_travel_cost();
+ real_t poly_enter_cost = 0.0;
+ real_t poly_travel_cost = least_cost_poly.poly->owner->get_travel_cost();
if (prev_least_cost_id != -1 && (navigation_polys[prev_least_cost_id].poly->owner->get_self() != least_cost_poly.poly->owner->get_self())) {
poly_enter_cost = least_cost_poly.poly->owner->get_enter_cost();
@@ -209,7 +209,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
Vector3 pathway[2] = { connection.pathway_start, connection.pathway_end };
const Vector3 new_entry = Geometry3D::get_closest_point_to_segment(least_cost_poly.entry, pathway);
- const float new_distance = (least_cost_poly.entry.distance_to(new_entry) * poly_travel_cost) + poly_enter_cost + least_cost_poly.traveled_distance;
+ const real_t new_distance = (least_cost_poly.entry.distance_to(new_entry) * poly_travel_cost) + poly_enter_cost + least_cost_poly.traveled_distance;
int64_t already_visited_polygon_index = navigation_polys.find(gd::NavigationPoly(connection.polygon));
@@ -257,11 +257,11 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
// Set as end point the furthest reachable point.
end_poly = reachable_end;
- end_d = 1e20;
+ end_d = FLT_MAX;
for (size_t point_id = 2; point_id < end_poly->points.size(); point_id++) {
Face3 f(end_poly->points[0].pos, end_poly->points[point_id - 1].pos, end_poly->points[point_id].pos);
Vector3 spoint = f.get_closest_point_to(p_destination);
- float dpoint = spoint.distance_to(p_destination);
+ real_t dpoint = spoint.distance_to(p_destination);
if (dpoint < end_d) {
end_point = spoint;
end_d = dpoint;
@@ -284,10 +284,10 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
// Find the polygon with the minimum cost from the list of polygons to visit.
least_cost_id = -1;
- float least_cost = 1e30;
+ real_t least_cost = FLT_MAX;
for (List<uint32_t>::Element *element = to_visit.front(); element != nullptr; element = element->next()) {
gd::NavigationPoly *np = &navigation_polys[element->get()];
- float cost = np->traveled_distance;
+ real_t cost = np->traveled_distance;
cost += (np->entry.distance_to(end_point) * np->poly->owner->get_travel_cost());
if (cost < least_cost) {
least_cost_id = np->self_id;
@@ -299,7 +299,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
// Stores the further reachable end polygon, in case our goal is not reachable.
if (is_reachable) {
- float d = navigation_polys[least_cost_id].entry.distance_to(p_destination) * navigation_polys[least_cost_id].poly->owner->get_travel_cost();
+ real_t d = navigation_polys[least_cost_id].entry.distance_to(p_destination) * navigation_polys[least_cost_id].poly->owner->get_travel_cost();
if (reachable_d > d) {
reachable_d = d;
reachable_end = navigation_polys[least_cost_id].poly;
@@ -459,7 +459,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
Vector3 NavMap::get_closest_point_to_segment(const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision) const {
bool use_collision = p_use_collision;
Vector3 closest_point;
- real_t closest_point_d = 1e20;
+ real_t closest_point_d = FLT_MAX;
for (const gd::Polygon &p : polygons) {
// For each face check the distance to the segment
@@ -520,7 +520,7 @@ RID NavMap::get_closest_point_owner(const Vector3 &p_point) const {
gd::ClosestPointQueryResult NavMap::get_closest_point_info(const Vector3 &p_point) const {
gd::ClosestPointQueryResult result;
- real_t closest_point_ds = 1e20;
+ real_t closest_point_ds = FLT_MAX;
for (size_t i(0); i < polygons.size(); i++) {
const gd::Polygon &p = polygons[i];
@@ -593,6 +593,7 @@ void NavMap::set_agent_as_controlled(NavAgent *agent) {
if (!exist) {
ERR_FAIL_COND(!has_agent(agent));
controlled_agents.push_back(agent);
+ agents_dirty = true;
}
}
@@ -734,8 +735,8 @@ void NavMap::sync() {
// Compute the projection of the opposite edge on the current one
Vector3 edge_vector = edge_p2 - edge_p1;
- float projected_p1_ratio = edge_vector.dot(other_edge_p1 - edge_p1) / (edge_vector.length_squared());
- float projected_p2_ratio = edge_vector.dot(other_edge_p2 - edge_p1) / (edge_vector.length_squared());
+ real_t projected_p1_ratio = edge_vector.dot(other_edge_p1 - edge_p1) / (edge_vector.length_squared());
+ real_t projected_p2_ratio = edge_vector.dot(other_edge_p2 - edge_p1) / (edge_vector.length_squared());
if ((projected_p1_ratio < 0.0 && projected_p2_ratio < 0.0) || (projected_p1_ratio > 1.0 && projected_p2_ratio > 1.0)) {
continue;
}
@@ -894,9 +895,9 @@ void NavMap::sync() {
if (agents_dirty) {
// cannot use LocalVector here as RVO library expects std::vector to build KdTree
std::vector<RVO::Agent *> raw_agents;
- raw_agents.reserve(agents.size());
- for (NavAgent *agent : agents) {
- raw_agents.push_back(agent->get_agent());
+ raw_agents.reserve(controlled_agents.size());
+ for (NavAgent *controlled_agent : controlled_agents) {
+ raw_agents.push_back(controlled_agent->get_agent());
}
rvo.buildAgentTree(raw_agents);
}
diff --git a/modules/navigation/nav_map.h b/modules/navigation/nav_map.h
index ab6a48dd70..5ec2c2826c 100644
--- a/modules/navigation/nav_map.h
+++ b/modules/navigation/nav_map.h
@@ -108,18 +108,18 @@ public:
return up;
}
- void set_cell_size(float p_cell_size);
- float get_cell_size() const {
+ void set_cell_size(real_t p_cell_size);
+ real_t get_cell_size() const {
return cell_size;
}
- void set_edge_connection_margin(float p_edge_connection_margin);
- float get_edge_connection_margin() const {
+ void set_edge_connection_margin(real_t p_edge_connection_margin);
+ real_t get_edge_connection_margin() const {
return edge_connection_margin;
}
- void set_link_connection_radius(float p_link_connection_radius);
- float get_link_connection_radius() const {
+ void set_link_connection_radius(real_t p_link_connection_radius);
+ real_t get_link_connection_radius() const {
return link_connection_radius;
}
diff --git a/modules/navigation/nav_region.cpp b/modules/navigation/nav_region.cpp
index 797c523627..cad4678e5a 100644
--- a/modules/navigation/nav_region.cpp
+++ b/modules/navigation/nav_region.cpp
@@ -114,7 +114,7 @@ void NavRegion::update_polygons() {
p.edges.resize(mesh_poly.size());
Vector3 center;
- float sum(0);
+ real_t sum(0);
for (int j(0); j < mesh_poly.size(); j++) {
int idx = indices[j];
@@ -143,7 +143,7 @@ void NavRegion::update_polygons() {
p.clockwise = sum > 0;
if (mesh_poly.size() != 0) {
- p.center = center / float(mesh_poly.size());
+ p.center = center / real_t(mesh_poly.size());
}
}
}
diff --git a/modules/navigation/nav_utils.h b/modules/navigation/nav_utils.h
index 06a1a1f403..6ddd8b9078 100644
--- a/modules/navigation/nav_utils.h
+++ b/modules/navigation/nav_utils.h
@@ -128,7 +128,7 @@ struct NavigationPoly {
/// The entry position of this poly.
Vector3 entry;
/// The distance to the destination.
- float traveled_distance = 0.0;
+ real_t traveled_distance = 0.0;
NavigationPoly() { poly = nullptr; }
diff --git a/modules/openxr/action_map/openxr_action_map.cpp b/modules/openxr/action_map/openxr_action_map.cpp
index 669c395b3e..d2f6be2233 100644
--- a/modules/openxr/action_map/openxr_action_map.cpp
+++ b/modules/openxr/action_map/openxr_action_map.cpp
@@ -178,6 +178,7 @@ void OpenXRActionMap::create_default_action_sets() {
Ref<OpenXRAction> grip = action_set->add_new_action("grip", "Grip", OpenXRAction::OPENXR_ACTION_FLOAT, "/user/hand/left,/user/hand/right");
Ref<OpenXRAction> grip_click = action_set->add_new_action("grip_click", "Grip click", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
Ref<OpenXRAction> grip_touch = action_set->add_new_action("grip_touch", "Grip touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
+ Ref<OpenXRAction> grip_force = action_set->add_new_action("grip_force", "Grip force", OpenXRAction::OPENXR_ACTION_FLOAT, "/user/hand/left,/user/hand/right");
Ref<OpenXRAction> primary = action_set->add_new_action("primary", "Primary joystick/thumbstick/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2, "/user/hand/left,/user/hand/right");
Ref<OpenXRAction> primary_click = action_set->add_new_action("primary_click", "Primary joystick/thumbstick/trackpad click", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
Ref<OpenXRAction> primary_touch = action_set->add_new_action("primary_touch", "Primary joystick/thumbstick/trackpad touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
@@ -349,6 +350,7 @@ void OpenXRActionMap::create_default_action_sets() {
profile->add_new_binding(trigger_touch, "/user/hand/left/input/trigger/touch,/user/hand/right/input/trigger/touch");
profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value");
profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); // this should do a float to bool conversion
+ profile->add_new_binding(grip_force, "/user/hand/left/input/squeeze/force,/user/hand/right/input/squeeze/force"); // grip force seems to be unique to the Valve Index
// primary on our index controller is our thumbstick
profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick");
profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click");
diff --git a/modules/openxr/action_map/openxr_interaction_profile_meta_data.cpp b/modules/openxr/action_map/openxr_interaction_profile_meta_data.cpp
index 1118b53d65..70879c6b6b 100644
--- a/modules/openxr/action_map/openxr_interaction_profile_meta_data.cpp
+++ b/modules/openxr/action_map/openxr_interaction_profile_meta_data.cpp
@@ -376,7 +376,9 @@ void OpenXRInteractionProfileMetaData::_register_core_metadata() {
register_io_path("/interaction_profiles/valve/index_controller", "Trigger touch", "/user/hand/right", "/user/hand/right/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
register_io_path("/interaction_profiles/valve/index_controller", "Squeeze", "/user/hand/left", "/user/hand/left/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/valve/index_controller", "Squeeze force", "/user/hand/left", "/user/hand/left/input/squeeze/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
register_io_path("/interaction_profiles/valve/index_controller", "Squeeze", "/user/hand/right", "/user/hand/right/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path("/interaction_profiles/valve/index_controller", "Squeeze force", "/user/hand/right", "/user/hand/right/input/squeeze/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
register_io_path("/interaction_profiles/valve/index_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
register_io_path("/interaction_profiles/valve/index_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
diff --git a/modules/openxr/extensions/openxr_extension_wrapper.h b/modules/openxr/extensions/openxr_extension_wrapper.h
index 84279635b5..2c855c3cde 100644
--- a/modules/openxr/extensions/openxr_extension_wrapper.h
+++ b/modules/openxr/extensions/openxr_extension_wrapper.h
@@ -80,7 +80,9 @@ public:
// this happens right before physics process and normal processing is run.
// This is when controller data is queried and made available to game logic.
virtual void on_process() {}
- virtual void on_pre_render() {} // `on_pre_render` is called right before we start rendering our XR viewport.
+ virtual void on_pre_render() {} // `on_pre_render` is called right before we start rendering our XR viewports.
+ virtual void on_pre_draw_viewport(RID p_render_target) {} // `on_pre_draw_viewport` is called right before we start rendering this viewport
+ virtual void on_post_draw_viewport(RID p_render_target) {} // `on_port_draw_viewport` is called right after we start rendering this viewport (note that on Vulkan draw commands may only be queued)
virtual void on_state_idle() {} // `on_state_idle` is called when the OpenXR session state is changed to idle.
virtual void on_state_ready() {} // `on_state_ready` is called when the OpenXR session state is changed to ready, this means OpenXR is ready to setup our session.
diff --git a/modules/openxr/extensions/openxr_opengl_extension.cpp b/modules/openxr/extensions/openxr_opengl_extension.cpp
index 0d201161f1..20ccfe3906 100644
--- a/modules/openxr/extensions/openxr_opengl_extension.cpp
+++ b/modules/openxr/extensions/openxr_opengl_extension.cpp
@@ -37,6 +37,28 @@
#include "servers/rendering/rendering_server_globals.h"
#include "servers/rendering_server.h"
+// OpenXR requires us to submit sRGB textures so that it recognises the content
+// as being in sRGB color space. We do fall back on "normal" textures but this
+// will likely result in incorrect colors as OpenXR will double the sRGB conversion.
+// All major XR runtimes support sRGB textures.
+
+// In OpenGL output of the fragment shader is assumed to be in the color space of
+// the developers choice, however a linear to sRGB HW conversion can be enabled
+// through enabling GL_FRAMEBUFFER_SRGB if an sRGB color attachment is used.
+// This is a global setting.
+// See: https://www.khronos.org/opengl/wiki/Framebuffer
+
+// In OpenGLES output of the fragment shader is assumed to be in linear color space
+// and will be converted by default to sRGB if an sRGB color attachment is used.
+// The extension GL_EXT_sRGB_write_control was introduced to enable turning this
+// feature off.
+// See: https://registry.khronos.org/OpenGL/extensions/EXT/EXT_sRGB_write_control.txt
+
+// On OpenGLES this is not defined in our standard headers..
+#ifndef GL_FRAMEBUFFER_SRGB
+#define GL_FRAMEBUFFER_SRGB 0x8DB9
+#endif
+
HashMap<String, bool *> OpenXROpenGLExtension::get_requested_extensions() {
HashMap<String, bool *> request_extensions;
@@ -157,8 +179,8 @@ void *OpenXROpenGLExtension::set_session_create_and_get_next_pointer(void *p_nex
}
void OpenXROpenGLExtension::get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) {
- p_usable_swap_chains.push_back(GL_RGBA8);
p_usable_swap_chains.push_back(GL_SRGB8_ALPHA8);
+ p_usable_swap_chains.push_back(GL_RGBA8);
}
void OpenXROpenGLExtension::get_usable_depth_formats(Vector<int64_t> &p_usable_depth_formats) {
@@ -168,6 +190,23 @@ void OpenXROpenGLExtension::get_usable_depth_formats(Vector<int64_t> &p_usable_d
p_usable_depth_formats.push_back(GL_DEPTH_COMPONENT24);
}
+void OpenXROpenGLExtension::on_pre_draw_viewport(RID p_render_target) {
+ if (srgb_ext_is_available) {
+ hw_linear_to_srgb_is_enabled = glIsEnabled(GL_FRAMEBUFFER_SRGB);
+ if (hw_linear_to_srgb_is_enabled) {
+ // Disable this.
+ glDisable(GL_FRAMEBUFFER_SRGB);
+ }
+ }
+}
+
+void OpenXROpenGLExtension::on_post_draw_viewport(RID p_render_target) {
+ if (srgb_ext_is_available && hw_linear_to_srgb_is_enabled) {
+ // Re-enable this.
+ glEnable(GL_FRAMEBUFFER_SRGB);
+ }
+}
+
bool OpenXROpenGLExtension::get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) {
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
ERR_FAIL_NULL_V(texture_storage, false);
diff --git a/modules/openxr/extensions/openxr_opengl_extension.h b/modules/openxr/extensions/openxr_opengl_extension.h
index 03a640cbfb..29a9f35c51 100644
--- a/modules/openxr/extensions/openxr_opengl_extension.h
+++ b/modules/openxr/extensions/openxr_opengl_extension.h
@@ -79,6 +79,9 @@ public:
virtual void on_instance_created(const XrInstance p_instance) override;
virtual void *set_session_create_and_get_next_pointer(void *p_next_pointer) override;
+ virtual void on_pre_draw_viewport(RID p_render_target) override;
+ virtual void on_post_draw_viewport(RID p_render_target) override;
+
virtual void get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) override;
virtual void get_usable_depth_formats(Vector<int64_t> &p_usable_swap_chains) override;
virtual String get_swapchain_format_name(int64_t p_swapchain_format) const override;
@@ -103,6 +106,9 @@ private:
Vector<RID> texture_rids;
};
+ bool srgb_ext_is_available = true;
+ bool hw_linear_to_srgb_is_enabled = false;
+
bool check_graphics_api_support(XrVersion p_desired_version);
#ifdef ANDROID_ENABLED
diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp
index ddb3114b59..4b39a6295c 100644
--- a/modules/openxr/openxr_api.cpp
+++ b/modules/openxr/openxr_api.cpp
@@ -385,8 +385,13 @@ bool OpenXRAPI::create_instance() {
if (XR_FAILED(result)) {
// not fatal probably
print_line("OpenXR: Failed to get XR instance properties [", get_error_string(result), "]");
+
+ runtime_name = "";
+ runtime_version = "";
} else {
- print_line("OpenXR: Running on OpenXR runtime: ", instanceProps.runtimeName, " ", OpenXRUtil::make_xr_version_string(instanceProps.runtimeVersion));
+ runtime_name = instanceProps.runtimeName;
+ runtime_version = OpenXRUtil::make_xr_version_string(instanceProps.runtimeVersion);
+ print_line("OpenXR: Running on OpenXR runtime: ", runtime_name, " ", runtime_version);
}
for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
@@ -1815,6 +1820,10 @@ bool OpenXRAPI::pre_draw_viewport(RID p_render_target) {
}
}
+ for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
+ wrapper->on_pre_draw_viewport(p_render_target);
+ }
+
return true;
}
@@ -1839,7 +1848,9 @@ void OpenXRAPI::post_draw_viewport(RID p_render_target) {
return;
}
- // Nothing to do here at this point in time...
+ for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
+ wrapper->on_post_draw_viewport(p_render_target);
+ }
};
void OpenXRAPI::end_frame() {
diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h
index 8c642c4ff4..c8bef5d420 100644
--- a/modules/openxr/openxr_api.h
+++ b/modules/openxr/openxr_api.h
@@ -95,6 +95,10 @@ private:
uint32_t num_swapchain_formats = 0;
int64_t *supported_swapchain_formats = nullptr;
+ // system info
+ String runtime_name;
+ String runtime_version;
+
// configuration
XrFormFactor form_factor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
XrViewConfigurationType view_configuration = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO;
@@ -294,6 +298,8 @@ public:
XrInstance get_instance() const { return instance; };
XrSystemId get_system_id() const { return system_id; };
XrSession get_session() const { return session; };
+ String get_runtime_name() const { return runtime_name; };
+ String get_runtime_version() const { return runtime_version; };
// helper method to convert an XrPosef to a Transform3D
Transform3D transform_from_pose(const XrPosef &p_pose);
diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp
index 51de9b913a..27344c9da7 100644
--- a/modules/openxr/openxr_interface.cpp
+++ b/modules/openxr/openxr_interface.cpp
@@ -583,6 +583,17 @@ void OpenXRInterface::uninitialize() {
initialized = false;
}
+Dictionary OpenXRInterface::get_system_info() {
+ Dictionary dict;
+
+ if (openxr_api) {
+ dict[SNAME("XRRuntimeName")] = openxr_api->get_runtime_name();
+ dict[SNAME("XRRuntimeVersion")] = openxr_api->get_runtime_version();
+ }
+
+ return dict;
+}
+
bool OpenXRInterface::supports_play_area_mode(XRInterface::PlayAreaMode p_mode) {
return false;
}
diff --git a/modules/openxr/openxr_interface.h b/modules/openxr/openxr_interface.h
index 40ee95f02f..de758a8c2d 100644
--- a/modules/openxr/openxr_interface.h
+++ b/modules/openxr/openxr_interface.h
@@ -112,6 +112,7 @@ public:
virtual bool is_initialized() const override;
virtual bool initialize() override;
virtual void uninitialize() override;
+ virtual Dictionary get_system_info() override;
virtual void trigger_haptic_pulse(const String &p_action_name, const StringName &p_tracker_name, double p_frequency, double p_amplitude, double p_duration_sec, double p_delay_sec = 0) override;
diff --git a/modules/openxr/register_types.cpp b/modules/openxr/register_types.cpp
index c39e49387a..b7d239fc73 100644
--- a/modules/openxr/register_types.cpp
+++ b/modules/openxr/register_types.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "register_types.h"
+#include "core/config/project_settings.h"
#include "main/main.h"
#include "openxr_interface.h"
@@ -113,10 +114,19 @@ void initialize_openxr_module(ModuleInitializationLevel p_level) {
ERR_FAIL_NULL(openxr_api);
if (!openxr_api->initialize(Main::get_rendering_driver_name())) {
- OS::get_singleton()->alert("OpenXR was requested but failed to start.\n"
- "Please check if your HMD is connected.\n"
- "When using Windows MR please note that WMR only has DirectX support, make sure SteamVR is your default OpenXR runtime.\n"
- "Godot will start in normal mode.\n");
+ const char *init_error_message =
+ "OpenXR was requested but failed to start.\n"
+ "Please check if your HMD is connected.\n"
+ "When using Windows MR please note that WMR only has DirectX support, make sure SteamVR is your default OpenXR runtime.\n"
+ "Godot will start in normal mode.\n";
+
+ WARN_PRINT(init_error_message);
+
+ bool init_show_startup_alert = GLOBAL_GET("xr/openxr/startup_alert");
+ if (init_show_startup_alert) {
+ OS::get_singleton()->alert(init_error_message);
+ }
+
memdelete(openxr_api);
openxr_api = nullptr;
return;
diff --git a/modules/openxr/scene/openxr_hand.cpp b/modules/openxr/scene/openxr_hand.cpp
index e4bd2dab52..e341d2b1d4 100644
--- a/modules/openxr/scene/openxr_hand.cpp
+++ b/modules/openxr/scene/openxr_hand.cpp
@@ -216,7 +216,7 @@ void OpenXRHand::_update_skeleton() {
const auto &pose = location.pose;
if (location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) {
- if (pose.orientation.x != 0 || pose.orientation.y != 0 || pose.orientation.y != 0 || pose.orientation.w != 0) {
+ if (pose.orientation.x != 0 || pose.orientation.y != 0 || pose.orientation.z != 0 || pose.orientation.w != 0) {
quaternions[i] = Quaternion(pose.orientation.x, pose.orientation.y, pose.orientation.z, pose.orientation.w);
inv_quaternions[i] = quaternions[i].inverse();
diff --git a/modules/text_server_adv/SCsub b/modules/text_server_adv/SCsub
index b7b7dccdb0..73c0851dc7 100644
--- a/modules/text_server_adv/SCsub
+++ b/modules/text_server_adv/SCsub
@@ -53,16 +53,19 @@ if env["builtin_harfbuzz"]:
"src/hb-buffer-serialize.cc",
"src/hb-buffer-verify.cc",
"src/hb-buffer.cc",
+ # "src/hb-cairo-utils.cc",
+ # "src/hb-cairo.cc",
"src/hb-common.cc",
- #'src/hb-coretext.cc',
- #'src/hb-directwrite.cc',
+ # "src/hb-coretext.cc",
+ # "src/hb-directwrite.cc",
"src/hb-draw.cc",
+ "src/hb-face-builder.cc",
"src/hb-face.cc",
"src/hb-fallback-shape.cc",
"src/hb-font.cc",
- #'src/hb-gdi.cc',
- #'src/hb-glib.cc',
- #'src/hb-gobject-structs.cc',
+ # "src/hb-gdi.cc",
+ # "src/hb-glib.cc",
+ # "src/hb-gobject-structs.cc",
"src/hb-icu.cc",
"src/hb-map.cc",
"src/hb-number.cc",
@@ -94,6 +97,9 @@ if env["builtin_harfbuzz"]:
"src/hb-ot-shape.cc",
"src/hb-ot-tag.cc",
"src/hb-ot-var.cc",
+ "src/hb-outline.cc",
+ "src/hb-paint-extents.cc",
+ "src/hb-paint.cc",
"src/hb-set.cc",
"src/hb-shape-plan.cc",
"src/hb-shape.cc",
@@ -104,12 +110,13 @@ if env["builtin_harfbuzz"]:
"src/hb-subset-cff1.cc",
"src/hb-subset-cff2.cc",
"src/hb-subset-input.cc",
+ "src/hb-subset-instancer-solver.cc",
"src/hb-subset-plan.cc",
"src/hb-subset-repacker.cc",
"src/hb-subset.cc",
"src/hb-ucd.cc",
"src/hb-unicode.cc",
- #'src/hb-uniscribe.cc'
+ # "src/hb-uniscribe.cc",
]
if freetype_enabled:
diff --git a/modules/text_server_adv/gdextension_build/SConstruct b/modules/text_server_adv/gdextension_build/SConstruct
index 4a363fdd7a..0ed5721d7d 100644
--- a/modules/text_server_adv/gdextension_build/SConstruct
+++ b/modules/text_server_adv/gdextension_build/SConstruct
@@ -290,16 +290,19 @@ thirdparty_harfbuzz_sources = [
"src/hb-buffer-serialize.cc",
"src/hb-buffer-verify.cc",
"src/hb-buffer.cc",
+ # "src/hb-cairo-utils.cc",
+ # "src/hb-cairo.cc",
"src/hb-common.cc",
- #'src/hb-coretext.cc',
- #'src/hb-directwrite.cc',
+ # "src/hb-coretext.cc",
+ # "src/hb-directwrite.cc",
"src/hb-draw.cc",
+ "src/hb-face-builder.cc",
"src/hb-face.cc",
"src/hb-fallback-shape.cc",
"src/hb-font.cc",
- #'src/hb-gdi.cc',
- #'src/hb-glib.cc',
- #'src/hb-gobject-structs.cc',
+ # "src/hb-gdi.cc",
+ # "src/hb-glib.cc",
+ # "src/hb-gobject-structs.cc",
"src/hb-icu.cc",
"src/hb-map.cc",
"src/hb-number.cc",
@@ -331,6 +334,9 @@ thirdparty_harfbuzz_sources = [
"src/hb-ot-shape.cc",
"src/hb-ot-tag.cc",
"src/hb-ot-var.cc",
+ "src/hb-outline.cc",
+ "src/hb-paint-extents.cc",
+ "src/hb-paint.cc",
"src/hb-set.cc",
"src/hb-shape-plan.cc",
"src/hb-shape.cc",
@@ -341,11 +347,13 @@ thirdparty_harfbuzz_sources = [
"src/hb-subset-cff1.cc",
"src/hb-subset-cff2.cc",
"src/hb-subset-input.cc",
+ "src/hb-subset-instancer-solver.cc",
"src/hb-subset-plan.cc",
+ "src/hb-subset-repacker.cc",
"src/hb-subset.cc",
"src/hb-ucd.cc",
"src/hb-unicode.cc",
- #'src/hb-uniscribe.cc'
+ # "src/hb-uniscribe.cc",
]
if env["freetype_enabled"]:
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index 79c007ace6..c6a21aeefe 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -73,8 +73,10 @@ using namespace godot;
#endif
#ifdef MODULE_SVG_ENABLED
+#ifdef MODULE_FREETYPE_ENABLED
#include "thorvg_svg_in_ot.h"
#endif
+#endif
/*************************************************************************/
/* bmp_font_t HarfBuzz Bitmap font interface */
@@ -1391,7 +1393,9 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_f
FT_Select_Size(fd->face, best_match);
} else {
FT_Set_Pixel_Sizes(fd->face, 0, double(fd->size.x * fd->oversampling));
- fd->scale = ((double)fd->size.x * fd->oversampling) / (double)fd->face->size->metrics.y_ppem;
+ if (fd->face->size->metrics.y_ppem != 0) {
+ fd->scale = ((double)fd->size.x * fd->oversampling) / (double)fd->face->size->metrics.y_ppem;
+ }
}
fd->hb_handle = hb_ft_font_create(fd->face, nullptr);
@@ -3095,6 +3099,37 @@ int64_t TextServerAdvanced::_font_get_glyph_index(const RID &p_font_rid, int64_t
#endif
}
+int64_t TextServerAdvanced::_font_get_char_from_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_glyph_index) const {
+ FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, 0);
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size(fd, p_size);
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0);
+
+#ifdef MODULE_FREETYPE_ENABLED
+ if (fd->cache[size]->inv_glyph_map.is_empty()) {
+ FT_Face face = fd->cache[size]->face;
+ FT_UInt gindex;
+ FT_ULong charcode = FT_Get_First_Char(face, &gindex);
+ while (gindex != 0) {
+ if (charcode != 0) {
+ fd->cache[size]->inv_glyph_map[gindex] = charcode;
+ }
+ charcode = FT_Get_Next_Char(face, charcode, &gindex);
+ }
+ }
+
+ if (fd->cache[size]->inv_glyph_map.has(p_glyph_index)) {
+ return fd->cache[size]->inv_glyph_map[p_glyph_index];
+ } else {
+ return 0;
+ }
+#else
+ return p_glyph_index;
+#endif
+}
+
bool TextServerAdvanced::_font_has_char(const RID &p_font_rid, int64_t p_char) const {
FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V_MSG((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff), false, "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_char, 16) + ".");
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index ce08cf7694..b959dd8544 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -272,6 +272,7 @@ class TextServerAdvanced : public TextServerExtension {
Vector2i size;
Vector<ShelfPackTexture> textures;
+ HashMap<int64_t, int64_t> inv_glyph_map;
HashMap<int32_t, FontGlyph> glyph_map;
HashMap<Vector2i, Vector2> kerning_map;
hb_font_t *hb_handle = nullptr;
@@ -814,6 +815,7 @@ public:
MODBIND3RC(Vector2, font_get_kerning, const RID &, int64_t, const Vector2i &);
MODBIND4RC(int64_t, font_get_glyph_index, const RID &, int64_t, int64_t, int64_t);
+ MODBIND3RC(int64_t, font_get_char_from_glyph_index, const RID &, int64_t, int64_t);
MODBIND2RC(bool, font_has_char, const RID &, int64_t);
MODBIND1RC(String, font_get_supported_chars, const RID &);
diff --git a/modules/text_server_adv/thorvg_svg_in_ot.cpp b/modules/text_server_adv/thorvg_svg_in_ot.cpp
index 1406e3aaa0..08e92c8ce9 100644
--- a/modules/text_server_adv/thorvg_svg_in_ot.cpp
+++ b/modules/text_server_adv/thorvg_svg_in_ot.cpp
@@ -49,10 +49,11 @@ using namespace godot;
#include "core/typedefs.h"
#include "core/variant/variant.h"
-#include "modules/modules_enabled.gen.h" // For svg.
+#include "modules/modules_enabled.gen.h" // For svg, freetype.
#endif
#ifdef MODULE_SVG_ENABLED
+#ifdef MODULE_FREETYPE_ENABLED
#include "thorvg_bounds_iterator.h"
#include "thorvg_svg_in_ot.h"
@@ -284,4 +285,5 @@ SVG_RendererHooks *get_tvg_svg_in_ot_hooks() {
return &tvg_svg_in_ot_hooks;
}
+#endif // MODULE_FREETYPE_ENABLED
#endif // MODULE_SVG_ENABLED
diff --git a/modules/text_server_adv/thorvg_svg_in_ot.h b/modules/text_server_adv/thorvg_svg_in_ot.h
index 4035a984b6..95ba29a20d 100644
--- a/modules/text_server_adv/thorvg_svg_in_ot.h
+++ b/modules/text_server_adv/thorvg_svg_in_ot.h
@@ -47,10 +47,11 @@ using namespace godot;
#include "core/templates/hash_map.h"
#include "core/typedefs.h"
-#include "modules/modules_enabled.gen.h" // For svg.
+#include "modules/modules_enabled.gen.h" // For svg, freetype.
#endif
#ifdef MODULE_SVG_ENABLED
+#ifdef MODULE_FREETYPE_ENABLED
#include <freetype/freetype.h>
#include <freetype/otsvg.h>
@@ -81,6 +82,7 @@ FT_Error tvg_svg_in_ot_render(FT_GlyphSlot p_slot, FT_Pointer *p_state);
SVG_RendererHooks *get_tvg_svg_in_ot_hooks();
+#endif // MODULE_FREETYPE_ENABLED
#endif // MODULE_SVG_ENABLED
#endif // THORVG_SVG_IN_OT_H
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index 9a9dcb3a31..9095be46af 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -66,8 +66,10 @@ using namespace godot;
#endif
#ifdef MODULE_SVG_ENABLED
+#ifdef MODULE_FREETYPE_ENABLED
#include "thorvg_svg_in_ot.h"
#endif
+#endif
/*************************************************************************/
@@ -830,7 +832,9 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontFallback *p_f
FT_Select_Size(fd->face, best_match);
} else {
FT_Set_Pixel_Sizes(fd->face, 0, Math::round(fd->size.x * fd->oversampling));
- fd->scale = ((double)fd->size.x * fd->oversampling) / (double)fd->face->size->metrics.y_ppem;
+ if (fd->face->size->metrics.y_ppem != 0) {
+ fd->scale = ((double)fd->size.x * fd->oversampling) / (double)fd->face->size->metrics.y_ppem;
+ }
}
fd->ascent = (fd->face->size->metrics.ascender / 64.0) / fd->oversampling * fd->scale;
@@ -2171,6 +2175,10 @@ int64_t TextServerFallback::_font_get_glyph_index(const RID &p_font_rid, int64_t
return (int64_t)p_char;
}
+int64_t TextServerFallback::_font_get_char_from_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_glyph_index) const {
+ return p_glyph_index;
+}
+
bool TextServerFallback::_font_has_char(const RID &p_font_rid, int64_t p_char) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V_MSG((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff), false, "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_char, 16) + ".");
diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h
index d9e471154d..8abcc41b2a 100644
--- a/modules/text_server_fb/text_server_fb.h
+++ b/modules/text_server_fb/text_server_fb.h
@@ -687,6 +687,7 @@ public:
MODBIND3RC(Vector2, font_get_kerning, const RID &, int64_t, const Vector2i &);
MODBIND4RC(int64_t, font_get_glyph_index, const RID &, int64_t, int64_t, int64_t);
+ MODBIND3RC(int64_t, font_get_char_from_glyph_index, const RID &, int64_t, int64_t);
MODBIND2RC(bool, font_has_char, const RID &, int64_t);
MODBIND1RC(String, font_get_supported_chars, const RID &);
diff --git a/modules/text_server_fb/thorvg_svg_in_ot.cpp b/modules/text_server_fb/thorvg_svg_in_ot.cpp
index 1406e3aaa0..a646d904be 100644
--- a/modules/text_server_fb/thorvg_svg_in_ot.cpp
+++ b/modules/text_server_fb/thorvg_svg_in_ot.cpp
@@ -53,6 +53,7 @@ using namespace godot;
#endif
#ifdef MODULE_SVG_ENABLED
+#ifdef MODULE_FREETYPE_ENABLED
#include "thorvg_bounds_iterator.h"
#include "thorvg_svg_in_ot.h"
@@ -284,4 +285,5 @@ SVG_RendererHooks *get_tvg_svg_in_ot_hooks() {
return &tvg_svg_in_ot_hooks;
}
+#endif // MODULE_FREETYPE_ENABLED
#endif // MODULE_SVG_ENABLED
diff --git a/modules/text_server_fb/thorvg_svg_in_ot.h b/modules/text_server_fb/thorvg_svg_in_ot.h
index 4035a984b6..95ba29a20d 100644
--- a/modules/text_server_fb/thorvg_svg_in_ot.h
+++ b/modules/text_server_fb/thorvg_svg_in_ot.h
@@ -47,10 +47,11 @@ using namespace godot;
#include "core/templates/hash_map.h"
#include "core/typedefs.h"
-#include "modules/modules_enabled.gen.h" // For svg.
+#include "modules/modules_enabled.gen.h" // For svg, freetype.
#endif
#ifdef MODULE_SVG_ENABLED
+#ifdef MODULE_FREETYPE_ENABLED
#include <freetype/freetype.h>
#include <freetype/otsvg.h>
@@ -81,6 +82,7 @@ FT_Error tvg_svg_in_ot_render(FT_GlyphSlot p_slot, FT_Pointer *p_state);
SVG_RendererHooks *get_tvg_svg_in_ot_hooks();
+#endif // MODULE_FREETYPE_ENABLED
#endif // MODULE_SVG_ENABLED
#endif // THORVG_SVG_IN_OT_H
diff --git a/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml b/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml
index fba954d547..57feadcc99 100644
--- a/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml
+++ b/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml
@@ -25,7 +25,7 @@
<param index="1" name="bind_address" type="String" default="&quot;*&quot;" />
<param index="2" name="tls_server_options" type="TLSOptions" default="null" />
<description>
- Starts a new multiplayer server listening on the given [param port]. You can optionally specify a [param bind_address], and provide valiid [param tls_server_options] to use TLS. See [method TLSOptions.server].
+ Starts a new multiplayer server listening on the given [param port]. You can optionally specify a [param bind_address], and provide valid [param tls_server_options] to use TLS. See [method TLSOptions.server].
</description>
</method>
<method name="get_peer" qualifiers="const">
diff --git a/modules/webxr/webxr_interface_js.cpp b/modules/webxr/webxr_interface_js.cpp
index 97b2eea4d7..d3710bd0df 100644
--- a/modules/webxr/webxr_interface_js.cpp
+++ b/modules/webxr/webxr_interface_js.cpp
@@ -301,6 +301,16 @@ void WebXRInterfaceJS::uninitialize() {
};
};
+Dictionary WebXRInterfaceJS::get_system_info() {
+ Dictionary dict;
+
+ // TODO get actual information from WebXR to return here
+ dict[SNAME("XRRuntimeName")] = String("WebXR");
+ dict[SNAME("XRRuntimeVersion")] = String("");
+
+ return dict;
+}
+
Transform3D WebXRInterfaceJS::_js_matrix_to_transform(float *p_js_matrix) {
Transform3D transform;
diff --git a/modules/webxr/webxr_interface_js.h b/modules/webxr/webxr_interface_js.h
index 31d2e200c0..20516e89e2 100644
--- a/modules/webxr/webxr_interface_js.h
+++ b/modules/webxr/webxr_interface_js.h
@@ -108,6 +108,7 @@ public:
virtual bool is_initialized() const override;
virtual bool initialize() override;
virtual void uninitialize() override;
+ virtual Dictionary get_system_info() override;
virtual Size2 get_render_target_size() override;
virtual uint32_t get_view_count() override;