diff options
Diffstat (limited to 'modules')
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=""*"" /> <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; |