diff options
Diffstat (limited to 'modules')
35 files changed, 296 insertions, 125 deletions
diff --git a/modules/basis_universal/register_types.cpp b/modules/basis_universal/register_types.cpp index 155f7809b0..8d21541341 100644 --- a/modules/basis_universal/register_types.cpp +++ b/modules/basis_universal/register_types.cpp @@ -277,6 +277,7 @@ void initialize_basis_universal_module(ModuleInitializationLevel p_level) { basisu_encoder_init(); Image::basis_universal_packer = basis_universal_packer; #endif + basist::basisu_transcoder_init(); Image::basis_universal_unpacker = basis_universal_unpacker; Image::basis_universal_unpacker_ptr = basis_universal_unpacker_ptr; } diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 0aea2b9c16..fc2e6e94f3 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -901,18 +901,19 @@ void GDScriptAnalyzer::resolve_class_member(GDScriptParser::ClassNode *p_class, member.signal->set_datatype(resolving_datatype); + // This is the _only_ way to declare a signal. Therefore, we can generate its + // MethodInfo inline so it's a tiny bit more efficient. + MethodInfo mi = MethodInfo(member.signal->identifier->name); + for (int j = 0; j < member.signal->parameters.size(); j++) { - GDScriptParser::DataType signal_type = resolve_datatype(member.signal->parameters[j]->datatype_specifier); - signal_type.is_meta_type = false; - member.signal->parameters[j]->set_datatype(signal_type); + GDScriptParser::ParameterNode *param = member.signal->parameters[j]; + GDScriptParser::DataType param_type = resolve_datatype(param->datatype_specifier); + param_type.is_meta_type = false; + param->set_datatype(param_type); + mi.arguments.push_back(PropertyInfo(param_type.builtin_type, param->identifier->name)); + // TODO: add signal parameter default values } - // TODO: Make MethodInfo from signal. - GDScriptParser::DataType signal_type; - signal_type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; - signal_type.kind = GDScriptParser::DataType::BUILTIN; - signal_type.builtin_type = Variant::SIGNAL; - - member.signal->set_datatype(signal_type); + member.signal->set_datatype(make_signal_type(mi)); // Apply annotations. for (GDScriptParser::AnnotationNode *&E : member.signal->annotations) { @@ -1747,6 +1748,12 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable type = p_variable->initializer->get_datatype(); +#ifdef DEBUG_ENABLED + if (p_variable->initializer->type == GDScriptParser::Node::CALL && type.is_hard_type() && type.kind == GDScriptParser::DataType::BUILTIN && type.builtin_type == Variant::NIL) { + parser->push_warning(p_variable->initializer, GDScriptWarning::VOID_ASSIGNMENT, static_cast<GDScriptParser::CallNode *>(p_variable->initializer)->function_name); + } +#endif + if (p_variable->infer_datatype) { type.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED; @@ -1760,11 +1767,6 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable } else { type.type_source = GDScriptParser::DataType::INFERRED; } -#ifdef DEBUG_ENABLED - if (p_variable->initializer->type == GDScriptParser::Node::CALL && type.kind == GDScriptParser::DataType::BUILTIN && type.builtin_type == Variant::NIL) { - parser->push_warning(p_variable->initializer, GDScriptWarning::VOID_ASSIGNMENT, static_cast<GDScriptParser::CallNode *>(p_variable->initializer)->function_name); - } -#endif } if (p_variable->datatype_specifier != nullptr) { @@ -1843,7 +1845,7 @@ void GDScriptAnalyzer::resolve_constant(GDScriptParser::ConstantNode *p_constant type = p_constant->initializer->get_datatype(); #ifdef DEBUG_ENABLED - if (p_constant->initializer->type == GDScriptParser::Node::CALL && type.kind == GDScriptParser::DataType::BUILTIN && type.builtin_type == Variant::NIL) { + if (p_constant->initializer->type == GDScriptParser::Node::CALL && type.is_hard_type() && type.kind == GDScriptParser::DataType::BUILTIN && type.builtin_type == Variant::NIL) { parser->push_warning(p_constant->initializer, GDScriptWarning::VOID_ASSIGNMENT, static_cast<GDScriptParser::CallNode *>(p_constant->initializer)->function_name); } #endif @@ -2331,7 +2333,7 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig } #ifdef DEBUG_ENABLED - if (p_assignment->assigned_value->type == GDScriptParser::Node::CALL && assigned_value_type.kind == GDScriptParser::DataType::BUILTIN && assigned_value_type.builtin_type == Variant::NIL) { + if (p_assignment->assigned_value->type == GDScriptParser::Node::CALL && assigned_value_type.is_hard_type() && assigned_value_type.kind == GDScriptParser::DataType::BUILTIN && assigned_value_type.builtin_type == Variant::NIL) { parser->push_warning(p_assignment->assigned_value, GDScriptWarning::VOID_ASSIGNMENT, static_cast<GDScriptParser::CallNode *>(p_assignment->assigned_value)->function_name); } else if (assignee_type.is_hard_type() && assignee_type.builtin_type == Variant::INT && assigned_value_type.builtin_type == Variant::FLOAT) { parser->push_warning(p_assignment->assigned_value, GDScriptWarning::NARROWING_CONVERSION); @@ -3137,6 +3139,12 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod p_identifier->reduced_value = member.enum_value.value; p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_CONSTANT; break; + case GDScriptParser::ClassNode::Member::ENUM: + if (p_base != nullptr && p_base->is_constant) { + p_identifier->is_constant = true; + p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_CONSTANT; + } + break; case GDScriptParser::ClassNode::Member::VARIABLE: p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_VARIABLE; p_identifier->variable_source = member.variable; @@ -3150,12 +3158,14 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod break; case GDScriptParser::ClassNode::Member::CLASS: if (p_base != nullptr && p_base->is_constant) { + p_identifier->is_constant = true; + p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_CONSTANT; + Error err = OK; GDScript *scr = GDScriptCache::get_full_script(base.script_path, err).ptr(); ERR_FAIL_COND_MSG(err != OK, "Error while getting subscript full script."); scr = scr->find_class(p_identifier->get_datatype().class_type->fqcn); p_identifier->reduced_value = scr; - p_identifier->is_constant = true; } break; default: @@ -3970,10 +3980,7 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_va result.builtin_type = p_value.get_type(); result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; // Constant has explicit type. - if (p_value.get_type() == Variant::NIL) { - // A null value is a variant, not void. - result.kind = GDScriptParser::DataType::VARIANT; - } else if (p_value.get_type() == Variant::OBJECT) { + if (p_value.get_type() == Variant::OBJECT) { // Object is treated as a native type, not a builtin type. result.kind = GDScriptParser::DataType::NATIVE; diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 50588110c4..cf9e734b05 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -490,24 +490,29 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code } break; case GDScriptParser::Node::CAST: { const GDScriptParser::CastNode *cn = static_cast<const GDScriptParser::CastNode *>(p_expression); - GDScriptParser::DataType og_cast_type = cn->cast_type->get_datatype(); + GDScriptParser::DataType og_cast_type = cn->get_datatype(); GDScriptDataType cast_type = _gdtype_from_datatype(og_cast_type, codegen.script); - if (og_cast_type.kind == GDScriptParser::DataType::ENUM) { - // Enum types are usually treated as dictionaries, but in this case we want to cast to an integer. - cast_type.kind = GDScriptDataType::BUILTIN; - cast_type.builtin_type = Variant::INT; - } + GDScriptCodeGenerator::Address result; + if (cast_type.has_type) { + if (og_cast_type.kind == GDScriptParser::DataType::ENUM) { + // Enum types are usually treated as dictionaries, but in this case we want to cast to an integer. + cast_type.kind = GDScriptDataType::BUILTIN; + cast_type.builtin_type = Variant::INT; + } - // Create temporary for result first since it will be deleted last. - GDScriptCodeGenerator::Address result = codegen.add_temporary(cast_type); + // Create temporary for result first since it will be deleted last. + result = codegen.add_temporary(cast_type); - GDScriptCodeGenerator::Address src = _parse_expression(codegen, r_error, cn->operand); + GDScriptCodeGenerator::Address src = _parse_expression(codegen, r_error, cn->operand); - gen->write_cast(result, src, cast_type); + gen->write_cast(result, src, cast_type); - if (src.mode == GDScriptCodeGenerator::Address::TEMPORARY) { - gen->pop_temporary(); + if (src.mode == GDScriptCodeGenerator::Address::TEMPORARY) { + gen->pop_temporary(); + } + } else { + result = _parse_expression(codegen, r_error, cn->operand); } return result; diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 79387d1bf6..d84af0c63c 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -2848,16 +2848,6 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c break; } - GDScriptParser::CompletionContext c = completion_context; - c.current_function = nullptr; - c.current_suite = nullptr; - c.base = base.value.get_type() == Variant::OBJECT ? base.value.operator Object *() : nullptr; - if (base.type.kind == GDScriptParser::DataType::CLASS) { - c.current_class = base.type.class_type; - } else { - c.current_class = nullptr; - } - _find_identifiers_in_base(base, false, options, 0); } break; case GDScriptParser::COMPLETION_TYPE_ATTRIBUTE: { diff --git a/modules/gdscript/tests/scripts/analyzer/errors/assign_signal.gd b/modules/gdscript/tests/scripts/analyzer/errors/assign_signal.gd new file mode 100644 index 0000000000..0e1f7256f8 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/assign_signal.gd @@ -0,0 +1,4 @@ +signal your_base +signal my_base +func test(): + your_base = my_base diff --git a/modules/gdscript/tests/scripts/analyzer/errors/assign_signal.out b/modules/gdscript/tests/scripts/analyzer/errors/assign_signal.out new file mode 100644 index 0000000000..5275183da2 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/assign_signal.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Cannot assign a new value to a constant. diff --git a/modules/gdscript/tests/scripts/analyzer/features/cast_non_null.gd b/modules/gdscript/tests/scripts/analyzer/features/cast_non_null.gd new file mode 100644 index 0000000000..ba1b198cbf --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/cast_non_null.gd @@ -0,0 +1,5 @@ +# https://github.com/godotengine/godot/issues/69504#issuecomment-1345725988 + +func test(): + print("cast to Variant == null: ", 1 as Variant == null) + print("cast to Object == null: ", self as Object == null) diff --git a/modules/gdscript/tests/scripts/analyzer/features/cast_non_null.out b/modules/gdscript/tests/scripts/analyzer/features/cast_non_null.out new file mode 100644 index 0000000000..541de99b8e --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/cast_non_null.out @@ -0,0 +1,3 @@ +GDTEST_OK +cast to Variant == null: false +cast to Object == null: false diff --git a/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant.gd b/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant.gd new file mode 100644 index 0000000000..757744b6f1 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant.gd @@ -0,0 +1,6 @@ +const External = preload("external_enum_as_constant_external.notest.gd") +const MyEnum = External.MyEnum + +func test(): + print(MyEnum.WAITING == 0) + print(MyEnum.GODOT == 1) diff --git a/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant.out b/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant.out new file mode 100644 index 0000000000..9d111a8322 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant.out @@ -0,0 +1,3 @@ +GDTEST_OK +true +true diff --git a/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant_external.notest.gd b/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant_external.notest.gd new file mode 100644 index 0000000000..7c090844d0 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant_external.notest.gd @@ -0,0 +1,4 @@ +enum MyEnum { + WAITING, + GODOT +} diff --git a/modules/gdscript/tests/scripts/analyzer/features/inner_class_constant_assignment.gd b/modules/gdscript/tests/scripts/analyzer/features/external_inner_class_as_constant.gd index ed5fb18b73..18dca109fb 100644 --- a/modules/gdscript/tests/scripts/analyzer/features/inner_class_constant_assignment.gd +++ b/modules/gdscript/tests/scripts/analyzer/features/external_inner_class_as_constant.gd @@ -1,4 +1,4 @@ -const External = preload("inner_class_constant_assignment_external.notest.gd") +const External = preload("external_inner_class_as_constant_external.notest.gd") const ExternalInnerClass = External.InnerClass func test(): diff --git a/modules/gdscript/tests/scripts/analyzer/features/inner_class_constant_assignment.out b/modules/gdscript/tests/scripts/analyzer/features/external_inner_class_as_constant.out index 15666c46ad..15666c46ad 100644 --- a/modules/gdscript/tests/scripts/analyzer/features/inner_class_constant_assignment.out +++ b/modules/gdscript/tests/scripts/analyzer/features/external_inner_class_as_constant.out diff --git a/modules/gdscript/tests/scripts/analyzer/features/inner_class_constant_assignment_external.notest.gd b/modules/gdscript/tests/scripts/analyzer/features/external_inner_class_as_constant_external.notest.gd index 788c99d469..788c99d469 100644 --- a/modules/gdscript/tests/scripts/analyzer/features/inner_class_constant_assignment_external.notest.gd +++ b/modules/gdscript/tests/scripts/analyzer/features/external_inner_class_as_constant_external.notest.gd diff --git a/modules/gdscript/tests/scripts/analyzer/features/inferred_return_type.gd b/modules/gdscript/tests/scripts/analyzer/features/inferred_return_type.gd new file mode 100644 index 0000000000..39ced354df --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/inferred_return_type.gd @@ -0,0 +1,9 @@ +# https://github.com/godotengine/godot/issues/61159 + +func get_param(): + return null + +func test(): + var v = get_param() + v = get_param() + print(v) diff --git a/modules/gdscript/tests/scripts/analyzer/features/inferred_return_type.out b/modules/gdscript/tests/scripts/analyzer/features/inferred_return_type.out new file mode 100644 index 0000000000..f0c83a69b3 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/inferred_return_type.out @@ -0,0 +1,2 @@ +GDTEST_OK +<null> diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index eca53c4831..26739bcdea 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -451,7 +451,7 @@ static String variant_type_to_managed_name(const String &p_var_type_name) { } if (p_var_type_name == Variant::get_type_name(Variant::SIGNAL)) { - return "SignalInfo"; + return "Signal"; } Variant::Type var_types[] = { 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 d67e57edc2..8852b7ebad 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs @@ -295,8 +295,8 @@ namespace Godot.SourceGenerators foreach (var property in properties) { // TODO: We should still restore read-only properties after reloading assembly. Two possible ways: reflection or turn RestoreGodotObjectData into a constructor overload. - // Ignore properties without a getter or without a setter. Godot properties must be both readable and writable. - if (property.IsWriteOnly || property.IsReadOnly) + // Ignore properties without a getter, without a setter or with an init-only setter. Godot properties must be both readable and writable. + if (property.IsWriteOnly || property.IsReadOnly || property.SetMethod!.IsInitOnly) continue; var marshalType = MarshalUtils.ConvertManagedTypeToMarshalType(property.Type, typeCache); diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs index 8b2f96036b..f0a6a72281 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs @@ -311,12 +311,12 @@ namespace Godot.SourceGenerators inputExpr, ")"), // We need a special case for generic Godot collections and GodotObjectOrDerived[], because VariantUtils.ConvertTo<T> is slower MarshalType.GodotGenericDictionary => - source.Append(VariantUtils, ".ConvertToDictionaryObject<", + source.Append(VariantUtils, ".ConvertToDictionary<", ((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedNameIncludeGlobal(), ", ", ((INamedTypeSymbol)typeSymbol).TypeArguments[1].FullQualifiedNameIncludeGlobal(), ">(", inputExpr, ")"), MarshalType.GodotGenericArray => - source.Append(VariantUtils, ".ConvertToArrayObject<", + source.Append(VariantUtils, ".ConvertToArray<", ((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedNameIncludeGlobal(), ">(", inputExpr, ")"), _ => source.Append(VariantUtils, ".ConvertTo<", 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 6c4206a575..b64b843b7c 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs @@ -158,7 +158,7 @@ namespace Godot.SourceGenerators // Generate SetGodotClassPropertyValue bool allPropertiesAreReadOnly = godotClassFields.All(fi => fi.FieldSymbol.IsReadOnly) && - godotClassProperties.All(pi => pi.PropertySymbol.IsReadOnly); + godotClassProperties.All(pi => pi.PropertySymbol.IsReadOnly || pi.PropertySymbol.SetMethod!.IsInitOnly); if (!allPropertiesAreReadOnly) { @@ -168,7 +168,7 @@ namespace Godot.SourceGenerators isFirstEntry = true; foreach (var property in godotClassProperties) { - if (property.PropertySymbol.IsReadOnly) + if (property.PropertySymbol.IsReadOnly || property.PropertySymbol.SetMethod!.IsInitOnly) continue; GeneratePropertySetter(property.PropertySymbol.Name, @@ -407,7 +407,7 @@ namespace Godot.SourceGenerators return null; } - if (propertySymbol.SetMethod == null) + if (propertySymbol.SetMethod == null || propertySymbol.SetMethod.IsInitOnly) { // This should never happen, as we filtered ReadOnly properties, but just in case. Common.ReportExportedMemberIsReadOnly(context, propertySymbol); 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 aa9dd9583e..99a4c95e73 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs @@ -138,14 +138,14 @@ namespace Godot.SourceGenerators } // TODO: We should still restore read-only properties after reloading assembly. Two possible ways: reflection or turn RestoreGodotObjectData into a constructor overload. - // Ignore properties without a getter or without a setter. Godot properties must be both readable and writable. + // Ignore properties without a getter, without a setter or with an init-only setter. Godot properties must be both readable and writable. if (property.IsWriteOnly) { Common.ReportExportedMemberIsWriteOnly(context, property); continue; } - if (property.IsReadOnly) + if (property.IsReadOnly || property.SetMethod!.IsInitOnly) { Common.ReportExportedMemberIsReadOnly(context, property); continue; diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 6559cbf75d..6cfdb15627 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -3650,7 +3650,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype = TypeInterface(); itype.name = "Signal"; itype.cname = itype.name; - itype.proxy_name = "SignalInfo"; + itype.proxy_name = "Signal"; itype.cs_type = itype.proxy_name; itype.cs_in_expr = "%0"; itype.c_in = "%5using %0 %1_in = " C_METHOD_MANAGED_TO_SIGNAL "(in %1);\n"; @@ -3732,7 +3732,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.cname = itype.name; itype.cs_out = "%5return new %2(%0(%1));"; // For generic Godot collections, Variant.From<T>/As<T> is slower, so we need this special case - itype.cs_variant_to_managed = "VariantUtils.ConvertToArrayObject(%0)"; + itype.cs_variant_to_managed = "VariantUtils.ConvertToArray(%0)"; itype.cs_managed_to_variant = "VariantUtils.CreateFromArray(%0)"; builtin_types.insert(itype.cname, itype); @@ -3759,7 +3759,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.cname = itype.name; itype.cs_out = "%5return new %2(%0(%1));"; // For generic Godot collections, Variant.From<T>/As<T> is slower, so we need this special case - itype.cs_variant_to_managed = "VariantUtils.ConvertToDictionaryObject(%0)"; + itype.cs_variant_to_managed = "VariantUtils.ConvertToDictionary(%0)"; itype.cs_managed_to_variant = "VariantUtils.CreateFromDictionary(%0)"; builtin_types.insert(itype.cname, itype); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs index 130776499b..df306e5244 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs @@ -499,7 +499,7 @@ namespace Godot.Collections VariantUtils.CreateFromArray(godotArray); private static Array<T> FromVariantFunc(in godot_variant variant) => - VariantUtils.ConvertToArrayObject<T>(variant); + VariantUtils.ConvertToArray<T>(variant); static unsafe Array() { diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs index cf25e1f0ae..b5a8742d3d 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs @@ -366,7 +366,7 @@ namespace Godot.Collections VariantUtils.CreateFromDictionary(godotDictionary); private static Dictionary<TKey, TValue> FromVariantFunc(in godot_variant variant) => - VariantUtils.ConvertToDictionaryObject<TKey, TValue>(variant); + VariantUtils.ConvertToDictionary<TKey, TValue>(variant); static unsafe Dictionary() { diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs index 6a4717f2c3..9c9258dd9e 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs @@ -170,39 +170,66 @@ namespace Godot.NativeInterop [MethodImpl(MethodImplOptions.AggressiveInlining)] public static godot_variant CreateFromPackedByteArray(Span<byte> from) - => CreateFromPackedByteArray(Marshaling.ConvertSystemArrayToNativePackedByteArray(from)); + { + using var nativePackedArray = Marshaling.ConvertSystemArrayToNativePackedByteArray(from); + return CreateFromPackedByteArray(nativePackedArray); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static godot_variant CreateFromPackedInt32Array(Span<int> from) - => CreateFromPackedInt32Array(Marshaling.ConvertSystemArrayToNativePackedInt32Array(from)); + { + using var nativePackedArray = Marshaling.ConvertSystemArrayToNativePackedInt32Array(from); + return CreateFromPackedInt32Array(nativePackedArray); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static godot_variant CreateFromPackedInt64Array(Span<long> from) - => CreateFromPackedInt64Array(Marshaling.ConvertSystemArrayToNativePackedInt64Array(from)); + { + using var nativePackedArray = Marshaling.ConvertSystemArrayToNativePackedInt64Array(from); + return CreateFromPackedInt64Array(nativePackedArray); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static godot_variant CreateFromPackedFloat32Array(Span<float> from) - => CreateFromPackedFloat32Array(Marshaling.ConvertSystemArrayToNativePackedFloat32Array(from)); + { + using var nativePackedArray = Marshaling.ConvertSystemArrayToNativePackedFloat32Array(from); + return CreateFromPackedFloat32Array(nativePackedArray); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static godot_variant CreateFromPackedFloat64Array(Span<double> from) - => CreateFromPackedFloat64Array(Marshaling.ConvertSystemArrayToNativePackedFloat64Array(from)); + { + using var nativePackedArray = Marshaling.ConvertSystemArrayToNativePackedFloat64Array(from); + return CreateFromPackedFloat64Array(nativePackedArray); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static godot_variant CreateFromPackedStringArray(Span<string> from) - => CreateFromPackedStringArray(Marshaling.ConvertSystemArrayToNativePackedStringArray(from)); + { + using var nativePackedArray = Marshaling.ConvertSystemArrayToNativePackedStringArray(from); + return CreateFromPackedStringArray(nativePackedArray); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static godot_variant CreateFromPackedVector2Array(Span<Vector2> from) - => CreateFromPackedVector2Array(Marshaling.ConvertSystemArrayToNativePackedVector2Array(from)); + { + using var nativePackedArray = Marshaling.ConvertSystemArrayToNativePackedVector2Array(from); + return CreateFromPackedVector2Array(nativePackedArray); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static godot_variant CreateFromPackedVector3Array(Span<Vector3> from) - => CreateFromPackedVector3Array(Marshaling.ConvertSystemArrayToNativePackedVector3Array(from)); + { + using var nativePackedArray = Marshaling.ConvertSystemArrayToNativePackedVector3Array(from); + return CreateFromPackedVector3Array(nativePackedArray); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static godot_variant CreateFromPackedColorArray(Span<Color> from) - => CreateFromPackedColorArray(Marshaling.ConvertSystemArrayToNativePackedColorArray(from)); + { + using var nativePackedArray = Marshaling.ConvertSystemArrayToNativePackedColorArray(from); + return CreateFromPackedColorArray(nativePackedArray); + } public static godot_variant CreateFromSystemArrayOfStringName(Span<StringName> from) => CreateFromArray(new Collections.Array(from)); @@ -436,7 +463,7 @@ namespace Godot.NativeInterop public static Godot.Object ConvertToGodotObject(in godot_variant p_var) => InteropUtils.UnmanagedGetManaged(ConvertToGodotObjectPtr(p_var)); - public static string ConvertToStringObject(in godot_variant p_var) + public static string ConvertToString(in godot_variant p_var) { switch (p_var.Type) { @@ -455,65 +482,65 @@ namespace Godot.NativeInterop } } - public static godot_string_name ConvertToStringName(in godot_variant p_var) + public static godot_string_name ConvertToNativeStringName(in godot_variant p_var) => p_var.Type == Variant.Type.StringName ? NativeFuncs.godotsharp_string_name_new_copy(p_var.StringName) : NativeFuncs.godotsharp_variant_as_string_name(p_var); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static StringName ConvertToStringNameObject(in godot_variant p_var) - => StringName.CreateTakingOwnershipOfDisposableValue(ConvertToStringName(p_var)); + public static StringName ConvertToStringName(in godot_variant p_var) + => StringName.CreateTakingOwnershipOfDisposableValue(ConvertToNativeStringName(p_var)); - public static godot_node_path ConvertToNodePath(in godot_variant p_var) + public static godot_node_path ConvertToNativeNodePath(in godot_variant p_var) => p_var.Type == Variant.Type.NodePath ? NativeFuncs.godotsharp_node_path_new_copy(p_var.NodePath) : NativeFuncs.godotsharp_variant_as_node_path(p_var); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static NodePath ConvertToNodePathObject(in godot_variant p_var) - => NodePath.CreateTakingOwnershipOfDisposableValue(ConvertToNodePath(p_var)); + public static NodePath ConvertToNodePath(in godot_variant p_var) + => NodePath.CreateTakingOwnershipOfDisposableValue(ConvertToNativeNodePath(p_var)); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static godot_callable ConvertToCallable(in godot_variant p_var) + public static godot_callable ConvertToNativeCallable(in godot_variant p_var) => NativeFuncs.godotsharp_variant_as_callable(p_var); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Callable ConvertToCallableManaged(in godot_variant p_var) - => Marshaling.ConvertCallableToManaged(ConvertToCallable(p_var)); + public static Callable ConvertToCallable(in godot_variant p_var) + => Marshaling.ConvertCallableToManaged(ConvertToNativeCallable(p_var)); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static godot_signal ConvertToSignal(in godot_variant p_var) + public static godot_signal ConvertToNativeSignal(in godot_variant p_var) => NativeFuncs.godotsharp_variant_as_signal(p_var); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Signal ConvertToSignalManaged(in godot_variant p_var) - => Marshaling.ConvertSignalToManaged(ConvertToSignal(p_var)); + public static Signal ConvertToSignal(in godot_variant p_var) + => Marshaling.ConvertSignalToManaged(ConvertToNativeSignal(p_var)); - public static godot_array ConvertToArray(in godot_variant p_var) + public static godot_array ConvertToNativeArray(in godot_variant p_var) => p_var.Type == Variant.Type.Array ? NativeFuncs.godotsharp_array_new_copy(p_var.Array) : NativeFuncs.godotsharp_variant_as_array(p_var); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Collections.Array ConvertToArrayObject(in godot_variant p_var) - => Collections.Array.CreateTakingOwnershipOfDisposableValue(ConvertToArray(p_var)); + public static Collections.Array ConvertToArray(in godot_variant p_var) + => Collections.Array.CreateTakingOwnershipOfDisposableValue(ConvertToNativeArray(p_var)); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Array<T> ConvertToArrayObject<T>(in godot_variant p_var) - => Array<T>.CreateTakingOwnershipOfDisposableValue(ConvertToArray(p_var)); + public static Array<T> ConvertToArray<T>(in godot_variant p_var) + => Array<T>.CreateTakingOwnershipOfDisposableValue(ConvertToNativeArray(p_var)); - public static godot_dictionary ConvertToDictionary(in godot_variant p_var) + public static godot_dictionary ConvertToNativeDictionary(in godot_variant p_var) => p_var.Type == Variant.Type.Dictionary ? NativeFuncs.godotsharp_dictionary_new_copy(p_var.Dictionary) : NativeFuncs.godotsharp_variant_as_dictionary(p_var); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Dictionary ConvertToDictionaryObject(in godot_variant p_var) - => Dictionary.CreateTakingOwnershipOfDisposableValue(ConvertToDictionary(p_var)); + public static Dictionary ConvertToDictionary(in godot_variant p_var) + => Dictionary.CreateTakingOwnershipOfDisposableValue(ConvertToNativeDictionary(p_var)); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Dictionary<TKey, TValue> ConvertToDictionaryObject<TKey, TValue>(in godot_variant p_var) - => Dictionary<TKey, TValue>.CreateTakingOwnershipOfDisposableValue(ConvertToDictionary(p_var)); + public static Dictionary<TKey, TValue> ConvertToDictionary<TKey, TValue>(in godot_variant p_var) + => Dictionary<TKey, TValue>.CreateTakingOwnershipOfDisposableValue(ConvertToNativeDictionary(p_var)); public static byte[] ConvertAsPackedByteArrayToSystemArray(in godot_variant p_var) { diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.generic.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.generic.cs index ebfc713ee4..3d64533269 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.generic.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.generic.cs @@ -315,13 +315,13 @@ public partial class VariantUtils return UnsafeAsT(ConvertToPlane(variant)); if (typeof(T) == typeof(Callable)) - return UnsafeAsT(ConvertToCallableManaged(variant)); + return UnsafeAsT(ConvertToCallable(variant)); if (typeof(T) == typeof(Signal)) - return UnsafeAsT(ConvertToSignalManaged(variant)); + return UnsafeAsT(ConvertToSignal(variant)); if (typeof(T) == typeof(string)) - return UnsafeAsT(ConvertToStringObject(variant)); + return UnsafeAsT(ConvertToString(variant)); if (typeof(T) == typeof(byte[])) return UnsafeAsT(ConvertAsPackedByteArrayToSystemArray(variant)); @@ -360,19 +360,19 @@ public partial class VariantUtils return UnsafeAsT(ConvertToSystemArrayOfRID(variant)); if (typeof(T) == typeof(StringName)) - return UnsafeAsT(ConvertToStringNameObject(variant)); + return UnsafeAsT(ConvertToStringName(variant)); if (typeof(T) == typeof(NodePath)) - return UnsafeAsT(ConvertToNodePathObject(variant)); + return UnsafeAsT(ConvertToNodePath(variant)); if (typeof(T) == typeof(RID)) return UnsafeAsT(ConvertToRID(variant)); if (typeof(T) == typeof(Godot.Collections.Dictionary)) - return UnsafeAsT(ConvertToDictionaryObject(variant)); + return UnsafeAsT(ConvertToDictionary(variant)); if (typeof(T) == typeof(Godot.Collections.Array)) - return UnsafeAsT(ConvertToArrayObject(variant)); + return UnsafeAsT(ConvertToArray(variant)); if (typeof(T) == typeof(Variant)) return UnsafeAsT(Variant.CreateCopyingBorrowed(variant)); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs index c4c53a39f9..da12309217 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs @@ -212,7 +212,7 @@ public partial struct Variant : IDisposable [MethodImpl(MethodImplOptions.AggressiveInlining)] public string AsString() => - VariantUtils.ConvertToStringObject((godot_variant)NativeVar); + VariantUtils.ConvertToString((godot_variant)NativeVar); [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector2 AsVector2() => @@ -280,11 +280,11 @@ public partial struct Variant : IDisposable [MethodImpl(MethodImplOptions.AggressiveInlining)] public Callable AsCallable() => - VariantUtils.ConvertToCallableManaged((godot_variant)NativeVar); + VariantUtils.ConvertToCallable((godot_variant)NativeVar); [MethodImpl(MethodImplOptions.AggressiveInlining)] public Signal AsSignal() => - VariantUtils.ConvertToSignalManaged((godot_variant)NativeVar); + VariantUtils.ConvertToSignal((godot_variant)NativeVar); [MethodImpl(MethodImplOptions.AggressiveInlining)] public byte[] AsByteArray() => @@ -329,11 +329,11 @@ public partial struct Variant : IDisposable [MethodImpl(MethodImplOptions.AggressiveInlining)] public Collections.Dictionary<TKey, TValue> AsGodotDictionary<TKey, TValue>() => - VariantUtils.ConvertToDictionaryObject<TKey, TValue>((godot_variant)NativeVar); + VariantUtils.ConvertToDictionary<TKey, TValue>((godot_variant)NativeVar); [MethodImpl(MethodImplOptions.AggressiveInlining)] public Collections.Array<T> AsGodotArray<T>() => - VariantUtils.ConvertToArrayObject<T>((godot_variant)NativeVar); + VariantUtils.ConvertToArray<T>((godot_variant)NativeVar); [MethodImpl(MethodImplOptions.AggressiveInlining)] public StringName[] AsSystemArrayOfStringName() => @@ -353,11 +353,11 @@ public partial struct Variant : IDisposable [MethodImpl(MethodImplOptions.AggressiveInlining)] public StringName AsStringName() => - VariantUtils.ConvertToStringNameObject((godot_variant)NativeVar); + VariantUtils.ConvertToStringName((godot_variant)NativeVar); [MethodImpl(MethodImplOptions.AggressiveInlining)] public NodePath AsNodePath() => - VariantUtils.ConvertToNodePathObject((godot_variant)NativeVar); + VariantUtils.ConvertToNodePath((godot_variant)NativeVar); [MethodImpl(MethodImplOptions.AggressiveInlining)] public RID AsRID() => @@ -365,11 +365,11 @@ public partial struct Variant : IDisposable [MethodImpl(MethodImplOptions.AggressiveInlining)] public Collections.Dictionary AsGodotDictionary() => - VariantUtils.ConvertToDictionaryObject((godot_variant)NativeVar); + VariantUtils.ConvertToDictionary((godot_variant)NativeVar); [MethodImpl(MethodImplOptions.AggressiveInlining)] public Collections.Array AsGodotArray() => - VariantUtils.ConvertToArrayObject((godot_variant)NativeVar); + VariantUtils.ConvertToArray((godot_variant)NativeVar); // Explicit conversion operators to supported types diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs index c471eceded..4c60080ee9 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs @@ -139,7 +139,7 @@ namespace Godot /// <returns>The angle between the two vectors, in radians.</returns> public readonly real_t AngleToPoint(Vector2 to) { - return Mathf.Atan2(y - to.y, x - to.x); + return Mathf.Atan2(to.y - y, to.x - x); } /// <summary> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs index 08f2a3a8af..91be548a21 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs @@ -123,7 +123,7 @@ namespace Godot /// <returns>The angle between the two vectors, in radians.</returns> public readonly real_t AngleToPoint(Vector2i to) { - return Mathf.Atan2(y - to.y, x - to.x); + return Mathf.Atan2(to.y - y, to.x - x); } /// <summary> diff --git a/modules/navigation/godot_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp index c5c1912621..58a0982425 100644 --- a/modules/navigation/godot_navigation_server.cpp +++ b/modules/navigation/godot_navigation_server.cpp @@ -36,6 +36,8 @@ #include "navigation_mesh_generator.h" #endif +using namespace NavigationUtilities; + /// Creates a struct for each function and a function that once called creates /// an instance of that struct with the submitted parameters. /// Then, that struct is stored in an array; the `sync` function consume that array. @@ -228,7 +230,7 @@ Vector<Vector3> GodotNavigationServer::map_get_path(RID p_map, Vector3 p_origin, const NavMap *map = map_owner.get_or_null(p_map); ERR_FAIL_COND_V(map == nullptr, Vector<Vector3>()); - return map->get_path(p_origin, p_destination, p_optimize, p_navigation_layers); + return map->get_path(p_origin, p_destination, p_optimize, p_navigation_layers, nullptr, nullptr, nullptr); } Vector3 GodotNavigationServer::map_get_closest_point_to_segment(RID p_map, const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision) const { @@ -838,20 +840,34 @@ void GodotNavigationServer::process(real_t p_delta_time) { } } -NavigationUtilities::PathQueryResult GodotNavigationServer::_query_path(const NavigationUtilities::PathQueryParameters &p_parameters) const { - NavigationUtilities::PathQueryResult r_query_result; +PathQueryResult GodotNavigationServer::_query_path(const PathQueryParameters &p_parameters) const { + PathQueryResult r_query_result; const NavMap *map = map_owner.get_or_null(p_parameters.map); ERR_FAIL_COND_V(map == nullptr, r_query_result); // run the pathfinding - if (p_parameters.pathfinding_algorithm == NavigationUtilities::PathfindingAlgorithm::PATHFINDING_ALGORITHM_ASTAR) { + if (p_parameters.pathfinding_algorithm == PathfindingAlgorithm::PATHFINDING_ALGORITHM_ASTAR) { // while postprocessing is still part of map.get_path() need to check and route it here for the correct "optimize" post-processing - if (p_parameters.path_postprocessing == NavigationUtilities::PathPostProcessing::PATH_POSTPROCESSING_CORRIDORFUNNEL) { - r_query_result.path = map->get_path(p_parameters.start_position, p_parameters.target_position, true, p_parameters.navigation_layers); - } else if (p_parameters.path_postprocessing == NavigationUtilities::PathPostProcessing::PATH_POSTPROCESSING_EDGECENTERED) { - r_query_result.path = map->get_path(p_parameters.start_position, p_parameters.target_position, false, p_parameters.navigation_layers); + if (p_parameters.path_postprocessing == PathPostProcessing::PATH_POSTPROCESSING_CORRIDORFUNNEL) { + r_query_result.path = map->get_path( + p_parameters.start_position, + p_parameters.target_position, + true, + p_parameters.navigation_layers, + p_parameters.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_TYPES) ? &r_query_result.path_types : nullptr, + p_parameters.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_RIDS) ? &r_query_result.path_rids : nullptr, + p_parameters.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_OWNERS) ? &r_query_result.path_owner_ids : nullptr); + } else if (p_parameters.path_postprocessing == PathPostProcessing::PATH_POSTPROCESSING_EDGECENTERED) { + r_query_result.path = map->get_path( + p_parameters.start_position, + p_parameters.target_position, + false, + p_parameters.navigation_layers, + p_parameters.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_TYPES) ? &r_query_result.path_types : nullptr, + p_parameters.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_RIDS) ? &r_query_result.path_rids : nullptr, + p_parameters.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_OWNERS) ? &r_query_result.path_owner_ids : nullptr); } } else { return r_query_result; diff --git a/modules/navigation/nav_base.h b/modules/navigation/nav_base.h index f5d2880d36..a3ab77301b 100644 --- a/modules/navigation/nav_base.h +++ b/modules/navigation/nav_base.h @@ -33,6 +33,7 @@ #include "nav_rid.h" #include "nav_utils.h" +#include "servers/navigation/navigation_utilities.h" class NavMap; @@ -42,8 +43,11 @@ protected: float enter_cost = 0.0; float travel_cost = 1.0; ObjectID owner_id; + NavigationUtilities::PathSegmentType type; public: + NavigationUtilities::PathSegmentType get_type() const { return type; } + void set_navigation_layers(uint32_t p_navigation_layers) { navigation_layers = p_navigation_layers; } uint32_t get_navigation_layers() const { return navigation_layers; } diff --git a/modules/navigation/nav_link.h b/modules/navigation/nav_link.h index 8f51a63951..e9c69286f9 100644 --- a/modules/navigation/nav_link.h +++ b/modules/navigation/nav_link.h @@ -43,6 +43,10 @@ class NavLink : public NavBase { bool link_dirty = true; public: + NavLink() { + type = NavigationUtilities::PathSegmentType::PATH_SEGMENT_TYPE_LINK; + } + void set_map(NavMap *p_map); NavMap *get_map() const { return map; diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp index 83862e1e34..8d58c9335d 100644 --- a/modules/navigation/nav_map.cpp +++ b/modules/navigation/nav_map.cpp @@ -38,6 +38,18 @@ #define THREE_POINTS_CROSS_PRODUCT(m_a, m_b, m_c) (((m_c) - (m_a)).cross((m_b) - (m_a))) +// Helper macro +#define APPEND_METADATA(poly) \ + if (r_path_types) { \ + r_path_types->push_back(poly->owner->get_type()); \ + } \ + if (r_path_rids) { \ + r_path_rids->push_back(poly->owner->get_self()); \ + } \ + if (r_path_owners) { \ + r_path_owners->push_back(poly->owner->get_owner_id()); \ + } + void NavMap::set_up(Vector3 p_up) { up = p_up; regenerate_polygons = true; @@ -71,7 +83,18 @@ gd::PointKey NavMap::get_point_key(const Vector3 &p_pos) const { return p; } -Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers) const { +Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers, Vector<int32_t> *r_path_types, TypedArray<RID> *r_path_rids, Vector<int64_t> *r_path_owners) const { + // Clear metadata outputs. + if (r_path_types) { + r_path_types->clear(); + } + if (r_path_rids) { + r_path_rids->clear(); + } + if (r_path_owners) { + r_path_owners->clear(); + } + // Find the start poly and the end poly on this map. const gd::Polygon *begin_poly = nullptr; const gd::Polygon *end_poly = nullptr; @@ -115,6 +138,24 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p return Vector<Vector3>(); } if (begin_poly == end_poly) { + if (r_path_types) { + r_path_types->resize(2); + r_path_types->write[0] = begin_poly->owner->get_type(); + r_path_types->write[1] = end_poly->owner->get_type(); + } + + if (r_path_rids) { + r_path_rids->resize(2); + (*r_path_rids)[0] = begin_poly->owner->get_self(); + (*r_path_rids)[1] = end_poly->owner->get_self(); + } + + if (r_path_owners) { + r_path_owners->resize(2); + r_path_owners->write[0] = begin_poly->owner->get_owner_id(); + r_path_owners->write[1] = end_poly->owner->get_owner_id(); + } + Vector<Vector3> path; path.resize(2); path.write[0] = begin_point; @@ -296,6 +337,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p gd::NavigationPoly *p = apex_poly; path.push_back(end_point); + APPEND_METADATA(end_poly); while (p) { // Set left and right points of the pathway between polygons. @@ -312,7 +354,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p left_poly = p; left_portal = left; } else { - clip_path(navigation_polys, path, apex_poly, right_portal, right_poly); + clip_path(navigation_polys, path, apex_poly, right_portal, right_poly, r_path_types, r_path_rids, r_path_owners); apex_point = right_portal; p = right_poly; @@ -320,7 +362,9 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p apex_poly = p; left_portal = apex_point; right_portal = apex_point; + path.push_back(apex_point); + APPEND_METADATA(apex_poly->poly); skip = true; } } @@ -331,7 +375,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p right_poly = p; right_portal = right; } else { - clip_path(navigation_polys, path, apex_poly, left_portal, left_poly); + clip_path(navigation_polys, path, apex_poly, left_portal, left_poly, r_path_types, r_path_rids, r_path_owners); apex_point = left_portal; p = left_poly; @@ -339,7 +383,9 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p apex_poly = p; right_portal = apex_point; left_portal = apex_point; + path.push_back(apex_point); + APPEND_METADATA(apex_poly->poly); } } @@ -355,12 +401,23 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p // If the last point is not the begin point, add it to the list. if (path[path.size() - 1] != begin_point) { path.push_back(begin_point); + APPEND_METADATA(begin_poly); } path.reverse(); + if (r_path_types) { + r_path_types->reverse(); + } + if (r_path_rids) { + r_path_rids->reverse(); + } + if (r_path_owners) { + r_path_owners->reverse(); + } } else { path.push_back(end_point); + APPEND_METADATA(end_poly); // Add mid points int np_id = least_cost_id; @@ -369,18 +426,37 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p int prev = navigation_polys[np_id].back_navigation_edge; int prev_n = (navigation_polys[np_id].back_navigation_edge + 1) % navigation_polys[np_id].poly->points.size(); Vector3 point = (navigation_polys[np_id].poly->points[prev].pos + navigation_polys[np_id].poly->points[prev_n].pos) * 0.5; + path.push_back(point); + APPEND_METADATA(navigation_polys[np_id].poly); } else { path.push_back(navigation_polys[np_id].entry); + APPEND_METADATA(navigation_polys[np_id].poly); } np_id = navigation_polys[np_id].back_navigation_poly_id; } path.push_back(begin_point); + APPEND_METADATA(begin_poly); + path.reverse(); + if (r_path_types) { + r_path_types->reverse(); + } + if (r_path_rids) { + r_path_rids->reverse(); + } + if (r_path_owners) { + r_path_owners->reverse(); + } } + // Ensure post conditions (path arrays MUST match in size). + CRASH_COND(r_path_types && path.size() != r_path_types->size()); + CRASH_COND(r_path_rids && path.size() != r_path_rids->size()); + CRASH_COND(r_path_owners && path.size() != r_path_owners->size()); + return path; } @@ -837,7 +913,7 @@ void NavMap::dispatch_callbacks() { } } -void NavMap::clip_path(const LocalVector<gd::NavigationPoly> &p_navigation_polys, Vector<Vector3> &path, const gd::NavigationPoly *from_poly, const Vector3 &p_to_point, const gd::NavigationPoly *p_to_poly) const { +void NavMap::clip_path(const LocalVector<gd::NavigationPoly> &p_navigation_polys, Vector<Vector3> &path, const gd::NavigationPoly *from_poly, const Vector3 &p_to_point, const gd::NavigationPoly *p_to_poly, Vector<int32_t> *r_path_types, TypedArray<RID> *r_path_rids, Vector<int64_t> *r_path_owners) const { Vector3 from = path[path.size() - 1]; if (from.is_equal_approx(p_to_point)) { @@ -863,6 +939,7 @@ void NavMap::clip_path(const LocalVector<gd::NavigationPoly> &p_navigation_polys if (cut_plane.intersects_segment(pathway_start, pathway_end, &inters)) { if (!inters.is_equal_approx(p_to_point) && !inters.is_equal_approx(path[path.size() - 1])) { path.push_back(inters); + APPEND_METADATA(from_poly->poly); } } } diff --git a/modules/navigation/nav_map.h b/modules/navigation/nav_map.h index a3da9fa727..3be13133d2 100644 --- a/modules/navigation/nav_map.h +++ b/modules/navigation/nav_map.h @@ -115,7 +115,7 @@ public: gd::PointKey get_point_key(const Vector3 &p_pos) const; - Vector<Vector3> get_path(Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers = 1) const; + Vector<Vector3> get_path(Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers, Vector<int32_t> *r_path_types, TypedArray<RID> *r_path_rids, Vector<int64_t> *r_path_owners) const; Vector3 get_closest_point_to_segment(const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision) const; Vector3 get_closest_point(const Vector3 &p_point) const; Vector3 get_closest_point_normal(const Vector3 &p_point) const; @@ -154,7 +154,7 @@ public: private: void compute_single_step(uint32_t index, RvoAgent **agent); - void clip_path(const LocalVector<gd::NavigationPoly> &p_navigation_polys, Vector<Vector3> &path, const gd::NavigationPoly *from_poly, const Vector3 &p_to_point, const gd::NavigationPoly *p_to_poly) const; + void clip_path(const LocalVector<gd::NavigationPoly> &p_navigation_polys, Vector<Vector3> &path, const gd::NavigationPoly *from_poly, const Vector3 &p_to_point, const gd::NavigationPoly *p_to_poly, Vector<int32_t> *r_path_types, TypedArray<RID> *r_path_rids, Vector<int64_t> *r_path_owners) const; }; #endif // NAV_MAP_H diff --git a/modules/navigation/nav_region.h b/modules/navigation/nav_region.h index 8d2b5aa9eb..3ef3ef5748 100644 --- a/modules/navigation/nav_region.h +++ b/modules/navigation/nav_region.h @@ -48,7 +48,9 @@ class NavRegion : public NavBase { LocalVector<gd::Polygon> polygons; public: - NavRegion() {} + NavRegion() { + type = NavigationUtilities::PathSegmentType::PATH_SEGMENT_TYPE_REGION; + } void scratch_polygons() { polygons_dirty = true; |