summaryrefslogtreecommitdiffstats
path: root/modules
diff options
context:
space:
mode:
authorSpartan322 <Megacake1234@gmail.com>2024-11-26 12:56:19 -0500
committerSpartan322 <Megacake1234@gmail.com>2024-11-26 12:56:19 -0500
commite58e18261ea7ed3978146ef8d77a900be2601be3 (patch)
tree79c2a4c34f2d888ff962d76edf474c518d1abdea /modules
parentc5b1645e60a59c0292c04bece3fdb0715a61afea (diff)
parentd09d82d433b03bb3773fd2a8cc8d6ccc2f8739ce (diff)
downloadredot-engine-e58e18261ea7ed3978146ef8d77a900be2601be3.tar.gz
Merge commit godotengine/godot@d09d82d433b03bb3773fd2a8cc8d6ccc2f8739ce
Diffstat (limited to 'modules')
-rw-r--r--modules/SCsub5
-rw-r--r--modules/betsy/CrossPlatformSettings_piece_all.glsl1
-rw-r--r--modules/betsy/UavCrossPlatform_piece_all.glsl1
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp97
-rw-r--r--modules/gdscript/gdscript_byte_codegen.cpp21
-rw-r--r--modules/gdscript/gdscript_editor.cpp21
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/enum_builtin_access.gd2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/enum_builtin_access.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/enum_global_access.gd2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/enum_global_access.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/enum_native_access.gd2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/enum_native_access.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/global_builtin_and_native_enums.gd28
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/global_builtin_and_native_enums.out25
-rw-r--r--modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute_identifier.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/common/identifiers_in_call.cfg8
-rw-r--r--modules/gdscript/tests/scripts/completion/common/identifiers_in_function_body.cfg8
-rw-r--r--modules/gdscript/tests/scripts/completion/common/identifiers_in_unclosed_call.cfg8
-rw-r--r--modules/gdscript/tests/scripts/completion/common/no_completion_in_string.cfg10
-rw-r--r--modules/gdscript/tests/scripts/completion/common/self.cfg8
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal/dollar.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal/percent.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local/local.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_infered/local_infered.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_infered_scene/class_local_infered_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_infered_scene/native_local_infered_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.cfg6
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.cfg6
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member/member.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_infered/member_infered.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_infered_scene/class_member_infered_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_infered_scene/native_member_infered_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.cfg6
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.cfg6
-rw-r--r--modules/gdscript/tests/scripts/completion/types/local/infered.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/types/local/no_type.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/types/local/typehint.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/types/local/typehint_broad.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/types/local/typehint_incompatible.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/types/member/infered.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/types/member/no_type.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/types/member/typehint.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/types/member/typehint_broad.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/types/member/typehint_incompatible.cfg4
-rw-r--r--modules/gdscript/tests/scripts/runtime/errors/division_by_zero.gd3
-rw-r--r--modules/gdscript/tests/scripts/runtime/errors/division_by_zero.out6
-rw-r--r--modules/gdscript/tests/scripts/runtime/errors/modulo_by_zero.gd3
-rw-r--r--modules/gdscript/tests/scripts/runtime/errors/modulo_by_zero.out6
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/stringify.gd9
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/stringify.out10
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.cpp115
-rw-r--r--modules/lightmapper_rd/lm_common_inc.glsl1
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs17
-rw-r--r--modules/mono/editor/bindings_generator.cpp35
-rw-r--r--modules/upnp/SCsub2
-rw-r--r--modules/upnp/register_types.cpp14
-rw-r--r--modules/upnp/upnp.cpp299
-rw-r--r--modules/upnp/upnp.h61
-rw-r--r--modules/upnp/upnp_device.cpp126
-rw-r--r--modules/upnp/upnp_device.h57
-rw-r--r--modules/upnp/upnp_device_miniupnp.cpp155
-rw-r--r--modules/upnp/upnp_device_miniupnp.h85
-rw-r--r--modules/upnp/upnp_miniupnp.cpp336
-rw-r--r--modules/upnp/upnp_miniupnp.h95
85 files changed, 1195 insertions, 669 deletions
diff --git a/modules/SCsub b/modules/SCsub
index fea2f2eeb8..09944241ea 100644
--- a/modules/SCsub
+++ b/modules/SCsub
@@ -63,7 +63,6 @@ register_module_types = env.CommandNoCache(
)
-vs_sources = []
test_headers = []
# libmodule_<name>.a for each active module.
for name, path in env.module_list.items():
@@ -75,8 +74,6 @@ for name, path in env.module_list.items():
lib = env_modules.add_library("module_%s" % name, env.modules_sources)
env.Prepend(LIBS=[lib])
- if env["vsproj"]:
- vs_sources += env.modules_sources
if env["tests"]:
# Lookup potential headers in `tests` subfolder.
@@ -104,5 +101,3 @@ env.modules_sources = []
env_modules.add_source_files(env.modules_sources, register_module_types)
lib = env_modules.add_library("modules", env.modules_sources)
env.Prepend(LIBS=[lib])
-if env["vsproj"]:
- env.modules_sources += vs_sources
diff --git a/modules/betsy/CrossPlatformSettings_piece_all.glsl b/modules/betsy/CrossPlatformSettings_piece_all.glsl
index b7abac7fcc..001d8e63b2 100644
--- a/modules/betsy/CrossPlatformSettings_piece_all.glsl
+++ b/modules/betsy/CrossPlatformSettings_piece_all.glsl
@@ -1,4 +1,3 @@
-
#define min3(a, b, c) min(a, min(b, c))
#define max3(a, b, c) max(a, max(b, c))
diff --git a/modules/betsy/UavCrossPlatform_piece_all.glsl b/modules/betsy/UavCrossPlatform_piece_all.glsl
index 30854df637..5f074137af 100644
--- a/modules/betsy/UavCrossPlatform_piece_all.glsl
+++ b/modules/betsy/UavCrossPlatform_piece_all.glsl
@@ -1,4 +1,3 @@
-
#define OGRE_imageLoad2D(inImage, iuv) imageLoad(inImage, int2(iuv))
#define OGRE_imageLoad2DArray(inImage, iuvw) imageLoad(inImage, int3(iuvw))
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index ba0b5c35e6..edfd538527 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -171,7 +171,9 @@ static GDScriptParser::DataType make_native_enum_type(const StringName &p_enum_n
GDScriptParser::DataType type = make_enum_type(p_enum_name, native_base, p_meta);
if (p_meta) {
- type.builtin_type = Variant::NIL; // Native enum types are not Dictionaries.
+ // Native enum types are not dictionaries.
+ type.builtin_type = Variant::NIL;
+ type.is_pseudo_type = true;
}
List<StringName> enum_values;
@@ -184,10 +186,29 @@ static GDScriptParser::DataType make_native_enum_type(const StringName &p_enum_n
return type;
}
+static GDScriptParser::DataType make_builtin_enum_type(const StringName &p_enum_name, Variant::Type p_type, bool p_meta = true) {
+ GDScriptParser::DataType type = make_enum_type(p_enum_name, Variant::get_type_name(p_type), p_meta);
+ if (p_meta) {
+ // Built-in enum types are not dictionaries.
+ type.builtin_type = Variant::NIL;
+ type.is_pseudo_type = true;
+ }
+
+ List<StringName> enum_values;
+ Variant::get_enumerations_for_enum(p_type, p_enum_name, &enum_values);
+
+ for (const StringName &E : enum_values) {
+ type.enum_values[E] = Variant::get_enum_value(p_type, p_enum_name, E);
+ }
+
+ return type;
+}
+
static GDScriptParser::DataType make_global_enum_type(const StringName &p_enum_name, const StringName &p_base, bool p_meta = true) {
GDScriptParser::DataType type = make_enum_type(p_enum_name, p_base, p_meta);
if (p_meta) {
- type.builtin_type = Variant::NIL; // Native enum types are not Dictionaries.
+ // Global enum types are not dictionaries.
+ type.builtin_type = Variant::NIL;
type.is_pseudo_type = true;
}
@@ -705,8 +726,8 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
if (first == SNAME("Variant")) {
if (p_type->type_chain.size() == 2) {
// May be nested enum.
- StringName enum_name = p_type->type_chain[1]->name;
- StringName qualified_name = String(first) + ENUM_SEPARATOR + String(p_type->type_chain[1]->name);
+ const StringName enum_name = p_type->type_chain[1]->name;
+ const StringName qualified_name = String(first) + ENUM_SEPARATOR + String(p_type->type_chain[1]->name);
if (CoreConstants::is_global_enum(qualified_name)) {
result = make_global_enum_type(enum_name, first, true);
return result;
@@ -721,21 +742,34 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
result.kind = GDScriptParser::DataType::VARIANT;
} else if (GDScriptParser::get_builtin_type(first) < Variant::VARIANT_MAX) {
// Built-in types.
- if (p_type->type_chain.size() > 1) {
- push_error(R"(Built-in types don't contain nested types.)", p_type->type_chain[1]);
+ const Variant::Type builtin_type = GDScriptParser::get_builtin_type(first);
+
+ if (p_type->type_chain.size() == 2) {
+ // May be nested enum.
+ const StringName enum_name = p_type->type_chain[1]->name;
+ if (Variant::has_enum(builtin_type, enum_name)) {
+ result = make_builtin_enum_type(enum_name, builtin_type, true);
+ return result;
+ } else {
+ push_error(vformat(R"(Name "%s" is not a nested type of "%s".)", enum_name, first), p_type->type_chain[1]);
+ return bad_type;
+ }
+ } else if (p_type->type_chain.size() > 2) {
+ push_error(R"(Built-in types only contain enum types, which do not have nested types.)", p_type->type_chain[2]);
return bad_type;
}
+
result.kind = GDScriptParser::DataType::BUILTIN;
- result.builtin_type = GDScriptParser::get_builtin_type(first);
+ result.builtin_type = builtin_type;
- if (result.builtin_type == Variant::ARRAY) {
+ if (builtin_type == Variant::ARRAY) {
GDScriptParser::DataType container_type = type_from_metatype(resolve_datatype(p_type->get_container_type_or_null(0)));
if (container_type.kind != GDScriptParser::DataType::VARIANT) {
container_type.is_constant = false;
result.set_container_element_type(0, container_type);
}
}
- if (result.builtin_type == Variant::DICTIONARY) {
+ if (builtin_type == Variant::DICTIONARY) {
GDScriptParser::DataType key_type = type_from_metatype(resolve_datatype(p_type->get_container_type_or_null(0)));
if (key_type.kind != GDScriptParser::DataType::VARIANT) {
key_type.is_constant = false;
@@ -3972,13 +4006,36 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
if (base.kind == GDScriptParser::DataType::BUILTIN) {
if (base.is_meta_type) {
- bool valid = true;
- Variant result = Variant::get_constant_value(base.builtin_type, name, &valid);
- if (valid) {
+ bool valid = false;
+
+ if (Variant::has_constant(base.builtin_type, name)) {
+ valid = true;
+
+ const Variant constant_value = Variant::get_constant_value(base.builtin_type, name);
+
p_identifier->is_constant = true;
- p_identifier->reduced_value = result;
- p_identifier->set_datatype(type_from_variant(result, p_identifier));
- } else if (base.is_hard_type()) {
+ p_identifier->reduced_value = constant_value;
+ p_identifier->set_datatype(type_from_variant(constant_value, p_identifier));
+ }
+
+ if (!valid) {
+ const StringName enum_name = Variant::get_enum_for_enumeration(base.builtin_type, name);
+ if (enum_name != StringName()) {
+ valid = true;
+
+ p_identifier->is_constant = true;
+ p_identifier->reduced_value = Variant::get_enum_value(base.builtin_type, enum_name, name);
+ p_identifier->set_datatype(make_builtin_enum_type(enum_name, base.builtin_type, false));
+ }
+ }
+
+ if (!valid && Variant::has_enum(base.builtin_type, name)) {
+ valid = true;
+
+ p_identifier->set_datatype(make_builtin_enum_type(name, base.builtin_type, true));
+ }
+
+ if (!valid && base.is_hard_type()) {
#ifdef SUGGEST_GODOT4_RENAMES
String rename_hint;
if (GLOBAL_GET(GDScriptWarning::get_settings_path_from_code(GDScriptWarning::RENAMED_IN_GODOT_4_HINT)).booleanize()) {
@@ -3987,9 +4044,9 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
rename_hint = " " + vformat(R"(Did you mean to use "%s"?)", renamed_identifier_name);
}
}
- push_error(vformat(R"(Cannot find constant "%s" on base "%s".%s)", name, base.to_string(), rename_hint), p_identifier);
+ push_error(vformat(R"(Cannot find member "%s" in base "%s".%s)", name, base.to_string(), rename_hint), p_identifier);
#else
- push_error(vformat(R"(Cannot find constant "%s" on base "%s".)", name, base.to_string()), p_identifier);
+ push_error(vformat(R"(Cannot find member "%s" in base "%s".)", name, base.to_string()), p_identifier);
#endif // SUGGEST_GODOT4_RENAMES
}
} else {
@@ -4031,9 +4088,9 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
rename_hint = " " + vformat(R"(Did you mean to use "%s"?)", renamed_identifier_name);
}
}
- push_error(vformat(R"(Cannot find property "%s" on base "%s".%s)", name, base.to_string(), rename_hint), p_identifier);
+ push_error(vformat(R"(Cannot find member "%s" in base "%s".%s)", name, base.to_string(), rename_hint), p_identifier);
#else
- push_error(vformat(R"(Cannot find property "%s" on base "%s".)", name, base.to_string()), p_identifier);
+ push_error(vformat(R"(Cannot find member "%s" in base "%s".)", name, base.to_string()), p_identifier);
#endif // SUGGEST_GODOT4_RENAMES
}
}
@@ -5574,7 +5631,7 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_property(const PropertyInfo
} else {
Vector<String> names = String(p_property.class_name).split(ENUM_SEPARATOR);
if (names.size() == 2) {
- result = make_native_enum_type(names[1], names[0], false);
+ result = make_enum_type(names[1], names[0], false);
result.is_constant = false;
}
}
diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp
index 5740e6e137..e97f50a42b 100644
--- a/modules/gdscript/gdscript_byte_codegen.cpp
+++ b/modules/gdscript/gdscript_byte_codegen.cpp
@@ -587,8 +587,25 @@ void GDScriptByteCodeGenerator::write_unary_operator(const Address &p_target, Va
}
void GDScriptByteCodeGenerator::write_binary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) {
- // Avoid validated evaluator for modulo and division when operands are int, since there's no check for division by zero.
- if (HAS_BUILTIN_TYPE(p_left_operand) && HAS_BUILTIN_TYPE(p_right_operand) && ((p_operator != Variant::OP_DIVIDE && p_operator != Variant::OP_MODULE) || p_left_operand.type.builtin_type != Variant::INT || p_right_operand.type.builtin_type != Variant::INT)) {
+ bool valid = HAS_BUILTIN_TYPE(p_left_operand) && HAS_BUILTIN_TYPE(p_right_operand);
+
+ // Avoid validated evaluator for modulo and division when operands are int or integer vector, since there's no check for division by zero.
+ if (valid && (p_operator == Variant::OP_DIVIDE || p_operator == Variant::OP_MODULE)) {
+ switch (p_left_operand.type.builtin_type) {
+ case Variant::INT:
+ valid = p_right_operand.type.builtin_type != Variant::INT;
+ break;
+ case Variant::VECTOR2I:
+ case Variant::VECTOR3I:
+ case Variant::VECTOR4I:
+ valid = p_right_operand.type.builtin_type != Variant::INT && p_right_operand.type.builtin_type != p_left_operand.type.builtin_type;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (valid) {
if (p_target.mode == Address::TEMPORARY) {
Variant::Type result_type = Variant::get_operator_return_type(p_operator, p_left_operand.type.builtin_type, p_right_operand.type.builtin_type);
Variant::Type temp_type = temporaries[p_target.address].type;
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index c3f091a2a3..1011fb6a86 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -1141,10 +1141,12 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class,
continue;
}
option = ScriptLanguage::CodeCompletionOption(member.function->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, location);
- if (member.function->parameters.size() > 0) {
+ if (member.function->parameters.size() > 0 || (member.function->info.flags & METHOD_FLAG_VARARG)) {
option.insert_text += "(";
+ option.display += U"(\u2026)";
} else {
option.insert_text += "()";
+ option.display += "()";
}
break;
case GDScriptParser::ClassNode::Member::SIGNAL:
@@ -1186,6 +1188,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
if (!p_types_only && base_type.is_meta_type && base_type.kind != GDScriptParser::DataType::BUILTIN && base_type.kind != GDScriptParser::DataType::ENUM) {
ScriptLanguage::CodeCompletionOption option("new", ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, ScriptLanguage::LOCATION_LOCAL);
option.insert_text += "(";
+ option.display += U"(\u2026)";
r_result.insert(option.display, option);
}
@@ -1243,10 +1246,12 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
}
int location = p_recursion_depth + _get_method_location(scr->get_class_name(), E.name);
ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, location);
- if (E.arguments.size()) {
+ if (E.arguments.size() || (E.flags & METHOD_FLAG_VARARG)) {
option.insert_text += "(";
+ option.display += U"(\u2026)";
} else {
option.insert_text += "()";
+ option.display += "()";
}
r_result.insert(option.display, option);
}
@@ -1329,10 +1334,12 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
}
int location = p_recursion_depth + _get_method_location(type, E.name);
ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, location);
- if (E.arguments.size()) {
+ if (E.arguments.size() || (E.flags & METHOD_FLAG_VARARG)) {
option.insert_text += "(";
+ option.display += U"(\u2026)";
} else {
option.insert_text += "()";
+ option.display += "()";
}
r_result.insert(option.display, option);
}
@@ -1400,10 +1407,12 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
continue;
}
ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, location);
- if (E.arguments.size()) {
+ if (E.arguments.size() || (E.flags & METHOD_FLAG_VARARG)) {
option.insert_text += "(";
+ option.display += U"(\u2026)";
} else {
option.insert_text += "()";
+ option.display += "()";
}
r_result.insert(option.display, option);
}
@@ -1435,8 +1444,10 @@ static void _find_identifiers(const GDScriptParser::CompletionContext &p_context
ScriptLanguage::CodeCompletionOption option(String(E), ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
if (function.arguments.size() || (function.flags & METHOD_FLAG_VARARG)) {
option.insert_text += "(";
+ option.display += U"(\u2026)";
} else {
option.insert_text += "()";
+ option.display += "()";
}
r_result.insert(option.display, option);
}
@@ -1483,6 +1494,7 @@ static void _find_identifiers(const GDScriptParser::CompletionContext &p_context
while (*kwa) {
ScriptLanguage::CodeCompletionOption option(*kwa, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
option.insert_text += "(";
+ option.display += U"(\u2026)";
r_result.insert(option.display, option);
kwa++;
}
@@ -1493,6 +1505,7 @@ static void _find_identifiers(const GDScriptParser::CompletionContext &p_context
for (List<StringName>::Element *E = utility_func_names.front(); E; E = E->next()) {
ScriptLanguage::CodeCompletionOption option(E->get(), ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
option.insert_text += "(";
+ option.display += U"(\u2026)"; // As all utility functions contain an argument or more, this is hardcoded here.
r_result.insert(option.display, option);
}
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_builtin_access.gd b/modules/gdscript/tests/scripts/analyzer/errors/enum_builtin_access.gd
new file mode 100644
index 0000000000..6367d50980
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_builtin_access.gd
@@ -0,0 +1,2 @@
+func test():
+ print(Vector3.Axis)
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_builtin_access.out b/modules/gdscript/tests/scripts/analyzer/errors/enum_builtin_access.out
new file mode 100644
index 0000000000..9c476031f3
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_builtin_access.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Type "Axis" in base "Vector3" cannot be used on its own.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_global_access.gd b/modules/gdscript/tests/scripts/analyzer/errors/enum_global_access.gd
new file mode 100644
index 0000000000..badcd3a83c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_global_access.gd
@@ -0,0 +1,2 @@
+func test():
+ print(Variant.Operator)
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_global_access.out b/modules/gdscript/tests/scripts/analyzer/errors/enum_global_access.out
new file mode 100644
index 0000000000..191acade73
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_global_access.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Type "Operator" in base "Variant" cannot be used on its own.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_native_access.gd b/modules/gdscript/tests/scripts/analyzer/errors/enum_native_access.gd
new file mode 100644
index 0000000000..e07998ddf6
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_native_access.gd
@@ -0,0 +1,2 @@
+func test():
+ print(Node.ProcessMode)
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_native_access.out b/modules/gdscript/tests/scripts/analyzer/errors/enum_native_access.out
new file mode 100644
index 0000000000..83671fc493
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_native_access.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Type "ProcessMode" in base "Node" cannot be used on its own.
diff --git a/modules/gdscript/tests/scripts/analyzer/features/global_builtin_and_native_enums.gd b/modules/gdscript/tests/scripts/analyzer/features/global_builtin_and_native_enums.gd
new file mode 100644
index 0000000000..4ccd7de994
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/global_builtin_and_native_enums.gd
@@ -0,0 +1,28 @@
+extends Node
+
+@export var test_type_1 := TYPE_BOOL
+@export var test_type_2 := Variant.Type.TYPE_BOOL
+@export var test_type_3: Variant.Type
+
+@export var test_side_1 := SIDE_RIGHT
+@export var test_side_2 := Side.SIDE_RIGHT
+@export var test_side_3: Side
+
+@export var test_axis_1 := Vector3.AXIS_Y
+@export var test_axis_2 := Vector3.Axis.AXIS_Y
+@export var test_axis_3: Vector3.Axis
+
+@export var test_mode_1 := Node.PROCESS_MODE_ALWAYS
+@export var test_mode_2 := Node.ProcessMode.PROCESS_MODE_ALWAYS
+@export var test_mode_3: Node.ProcessMode
+
+func test():
+ for property in get_property_list():
+ if str(property.name).begins_with("test_"):
+ Utils.print_property_extended_info(property, self)
+
+func test_no_exec():
+ # GH-99309
+ var sprite: Sprite3D = $Sprite3D
+ sprite.axis = Vector3.AXIS_Y # No warning.
+ sprite.set_axis(Vector3.AXIS_Y) # No warning.
diff --git a/modules/gdscript/tests/scripts/analyzer/features/global_builtin_and_native_enums.out b/modules/gdscript/tests/scripts/analyzer/features/global_builtin_and_native_enums.out
new file mode 100644
index 0000000000..6c45dee323
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/global_builtin_and_native_enums.out
@@ -0,0 +1,25 @@
+GDTEST_OK
+var test_type_1: Variant.Type = 1
+ hint=ENUM hint_string="Type Nil:0,Type Bool:1,Type Int:2,Type Float:3,Type String:4,Type Vector 2:5,Type Vector 2i:6,Type Rect 2:7,Type Rect 2i:8,Type Vector 3:9,Type Vector 3i:10,Type Transform 2d:11,Type Vector 4:12,Type Vector 4i:13,Type Plane:14,Type Quaternion:15,Type Aabb:16,Type Basis:17,Type Transform 3d:18,Type Projection:19,Type Color:20,Type String Name:21,Type Node Path:22,Type Rid:23,Type Object:24,Type Callable:25,Type Signal:26,Type Dictionary:27,Type Array:28,Type Packed Byte Array:29,Type Packed Int 32 Array:30,Type Packed Int 64 Array:31,Type Packed Float 32 Array:32,Type Packed Float 64 Array:33,Type Packed String Array:34,Type Packed Vector 2 Array:35,Type Packed Vector 3 Array:36,Type Packed Color Array:37,Type Packed Vector 4 Array:38,Type Max:39" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Variant.Type"
+var test_type_2: Variant.Type = 1
+ hint=ENUM hint_string="Type Nil:0,Type Bool:1,Type Int:2,Type Float:3,Type String:4,Type Vector 2:5,Type Vector 2i:6,Type Rect 2:7,Type Rect 2i:8,Type Vector 3:9,Type Vector 3i:10,Type Transform 2d:11,Type Vector 4:12,Type Vector 4i:13,Type Plane:14,Type Quaternion:15,Type Aabb:16,Type Basis:17,Type Transform 3d:18,Type Projection:19,Type Color:20,Type String Name:21,Type Node Path:22,Type Rid:23,Type Object:24,Type Callable:25,Type Signal:26,Type Dictionary:27,Type Array:28,Type Packed Byte Array:29,Type Packed Int 32 Array:30,Type Packed Int 64 Array:31,Type Packed Float 32 Array:32,Type Packed Float 64 Array:33,Type Packed String Array:34,Type Packed Vector 2 Array:35,Type Packed Vector 3 Array:36,Type Packed Color Array:37,Type Packed Vector 4 Array:38,Type Max:39" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Variant.Type"
+var test_type_3: Variant.Type = 0
+ hint=ENUM hint_string="Type Nil:0,Type Bool:1,Type Int:2,Type Float:3,Type String:4,Type Vector 2:5,Type Vector 2i:6,Type Rect 2:7,Type Rect 2i:8,Type Vector 3:9,Type Vector 3i:10,Type Transform 2d:11,Type Vector 4:12,Type Vector 4i:13,Type Plane:14,Type Quaternion:15,Type Aabb:16,Type Basis:17,Type Transform 3d:18,Type Projection:19,Type Color:20,Type String Name:21,Type Node Path:22,Type Rid:23,Type Object:24,Type Callable:25,Type Signal:26,Type Dictionary:27,Type Array:28,Type Packed Byte Array:29,Type Packed Int 32 Array:30,Type Packed Int 64 Array:31,Type Packed Float 32 Array:32,Type Packed Float 64 Array:33,Type Packed String Array:34,Type Packed Vector 2 Array:35,Type Packed Vector 3 Array:36,Type Packed Color Array:37,Type Packed Vector 4 Array:38,Type Max:39" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Variant.Type"
+var test_side_1: Side = 2
+ hint=ENUM hint_string="Side Left:0,Side Top:1,Side Right:2,Side Bottom:3" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Side"
+var test_side_2: Side = 2
+ hint=ENUM hint_string="Side Left:0,Side Top:1,Side Right:2,Side Bottom:3" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Side"
+var test_side_3: Side = 0
+ hint=ENUM hint_string="Side Left:0,Side Top:1,Side Right:2,Side Bottom:3" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Side"
+var test_axis_1: Vector3.Axis = 1
+ hint=ENUM hint_string="Axis X:0,Axis Y:1,Axis Z:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Vector3.Axis"
+var test_axis_2: Vector3.Axis = 1
+ hint=ENUM hint_string="Axis X:0,Axis Y:1,Axis Z:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Vector3.Axis"
+var test_axis_3: Vector3.Axis = 0
+ hint=ENUM hint_string="Axis X:0,Axis Y:1,Axis Z:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Vector3.Axis"
+var test_mode_1: Node.ProcessMode = 3
+ hint=ENUM hint_string="Process Mode Inherit:0,Process Mode Pausable:1,Process Mode When Paused:2,Process Mode Always:3,Process Mode Disabled:4" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Node.ProcessMode"
+var test_mode_2: Node.ProcessMode = 3
+ hint=ENUM hint_string="Process Mode Inherit:0,Process Mode Pausable:1,Process Mode When Paused:2,Process Mode Always:3,Process Mode Disabled:4" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Node.ProcessMode"
+var test_mode_3: Node.ProcessMode = 0
+ hint=ENUM hint_string="Process Mode Inherit:0,Process Mode Pausable:1,Process Mode When Paused:2,Process Mode Always:3,Process Mode Disabled:4" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Node.ProcessMode"
diff --git a/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute.cfg b/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute.cfg
index e4759ac76b..a2c332adad 100644
--- a/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute.cfg
+++ b/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute.cfg
@@ -1,6 +1,6 @@
[output]
include=[
- {"display": "new"},
+ {"display": "new(…)"},
{"display": "SIZE_EXPAND"},
{"display": "SIZE_EXPAND_FILL"},
{"display": "SIZE_FILL"},
diff --git a/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute_identifier.cfg b/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute_identifier.cfg
index e4759ac76b..a2c332adad 100644
--- a/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute_identifier.cfg
+++ b/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute_identifier.cfg
@@ -1,6 +1,6 @@
[output]
include=[
- {"display": "new"},
+ {"display": "new(…)"},
{"display": "SIZE_EXPAND"},
{"display": "SIZE_EXPAND_FILL"},
{"display": "SIZE_FILL"},
diff --git a/modules/gdscript/tests/scripts/completion/common/identifiers_in_call.cfg b/modules/gdscript/tests/scripts/completion/common/identifiers_in_call.cfg
index 5f08f9c265..f2dff734b6 100644
--- a/modules/gdscript/tests/scripts/completion/common/identifiers_in_call.cfg
+++ b/modules/gdscript/tests/scripts/completion/common/identifiers_in_call.cfg
@@ -2,13 +2,13 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
; GDScript: identifiers.gd
@@ -16,8 +16,8 @@ include=[
{"display": "test_signal_2"},
{"display": "test_var_1"},
{"display": "test_var_2"},
- {"display": "test_func_1"},
- {"display": "test_func_2"},
+ {"display": "test_func_1(…)"},
+ {"display": "test_func_2(…)"},
{"display": "test_parameter_1"},
{"display": "test_parameter_2"},
{"display": "local_test_var_1"},
diff --git a/modules/gdscript/tests/scripts/completion/common/identifiers_in_function_body.cfg b/modules/gdscript/tests/scripts/completion/common/identifiers_in_function_body.cfg
index 5f08f9c265..f2dff734b6 100644
--- a/modules/gdscript/tests/scripts/completion/common/identifiers_in_function_body.cfg
+++ b/modules/gdscript/tests/scripts/completion/common/identifiers_in_function_body.cfg
@@ -2,13 +2,13 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
; GDScript: identifiers.gd
@@ -16,8 +16,8 @@ include=[
{"display": "test_signal_2"},
{"display": "test_var_1"},
{"display": "test_var_2"},
- {"display": "test_func_1"},
- {"display": "test_func_2"},
+ {"display": "test_func_1(…)"},
+ {"display": "test_func_2(…)"},
{"display": "test_parameter_1"},
{"display": "test_parameter_2"},
{"display": "local_test_var_1"},
diff --git a/modules/gdscript/tests/scripts/completion/common/identifiers_in_unclosed_call.cfg b/modules/gdscript/tests/scripts/completion/common/identifiers_in_unclosed_call.cfg
index 5f08f9c265..f2dff734b6 100644
--- a/modules/gdscript/tests/scripts/completion/common/identifiers_in_unclosed_call.cfg
+++ b/modules/gdscript/tests/scripts/completion/common/identifiers_in_unclosed_call.cfg
@@ -2,13 +2,13 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
; GDScript: identifiers.gd
@@ -16,8 +16,8 @@ include=[
{"display": "test_signal_2"},
{"display": "test_var_1"},
{"display": "test_var_2"},
- {"display": "test_func_1"},
- {"display": "test_func_2"},
+ {"display": "test_func_1(…)"},
+ {"display": "test_func_2(…)"},
{"display": "test_parameter_1"},
{"display": "test_parameter_2"},
{"display": "local_test_var_1"},
diff --git a/modules/gdscript/tests/scripts/completion/common/no_completion_in_string.cfg b/modules/gdscript/tests/scripts/completion/common/no_completion_in_string.cfg
index 462846c9b2..e012919051 100644
--- a/modules/gdscript/tests/scripts/completion/common/no_completion_in_string.cfg
+++ b/modules/gdscript/tests/scripts/completion/common/no_completion_in_string.cfg
@@ -2,14 +2,14 @@ scene="res://completion/get_node/get_node.tscn"
[output]
exclude=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
- {"display": "add_child"},
+ {"display": "add_child(…)"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
; GDScript: no_completion_in_string.gd
@@ -17,8 +17,8 @@ exclude=[
{"display": "test_signal_2"},
{"display": "test_var_1"},
{"display": "test_var_2"},
- {"display": "test_func_1"},
- {"display": "test_func_2"},
+ {"display": "test_func_1(…)"},
+ {"display": "test_func_2(…)"},
{"display": "test_parameter_1"},
{"display": "test_parameter_2"},
{"display": "local_test_var_1"},
diff --git a/modules/gdscript/tests/scripts/completion/common/self.cfg b/modules/gdscript/tests/scripts/completion/common/self.cfg
index 871a404e3a..dcce1df0d0 100644
--- a/modules/gdscript/tests/scripts/completion/common/self.cfg
+++ b/modules/gdscript/tests/scripts/completion/common/self.cfg
@@ -2,13 +2,13 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
; GDScript: self.gd
@@ -16,6 +16,6 @@ include=[
{"display": "test_signal_2"},
{"display": "test_var_1"},
{"display": "test_var_2"},
- {"display": "test_func_1"},
- {"display": "test_func_2"},
+ {"display": "test_func_1(…)"},
+ {"display": "test_func_2(…)"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal/dollar.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal/dollar.cfg
index ae7d34d87d..319c5121b5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/literal/dollar.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal/dollar.cfg
@@ -1,7 +1,7 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal/percent.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal/percent.cfg
index ae7d34d87d..319c5121b5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/literal/percent.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal/percent.cfg
@@ -1,7 +1,7 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.cfg
index 9c580b711d..7518bf5ae5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.cfg
index 446198dd35..174fdcb184 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.cfg
index 9c580b711d..7518bf5ae5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.cfg
index 446198dd35..174fdcb184 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local/local.cfg b/modules/gdscript/tests/scripts/completion/get_node/local/local.cfg
index ae7d34d87d..319c5121b5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local/local.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local/local.cfg
@@ -1,7 +1,7 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_infered/local_infered.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_infered/local_infered.cfg
index ae7d34d87d..319c5121b5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_infered/local_infered.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_infered/local_infered.cfg
@@ -1,7 +1,7 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_infered_scene/class_local_infered_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_infered_scene/class_local_infered_scene.cfg
index 9c580b711d..7518bf5ae5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_infered_scene/class_local_infered_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_infered_scene/class_local_infered_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_infered_scene/native_local_infered_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_infered_scene/native_local_infered_scene.cfg
index 446198dd35..174fdcb184 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_infered_scene/native_local_infered_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_infered_scene/native_local_infered_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.cfg
index 9c580b711d..7518bf5ae5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.cfg
index 446198dd35..174fdcb184 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.cfg
index 8b68d51a89..050b0d61a3 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.cfg
index 72c0549d3b..d647135bc6 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.cfg
index 9c580b711d..7518bf5ae5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.cfg
index 446198dd35..174fdcb184 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.cfg
index 9c580b711d..7518bf5ae5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.cfg
index 446198dd35..174fdcb184 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.cfg
index 1894e72c65..a6118908de 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.cfg
@@ -3,18 +3,18 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; Area2D
- {"display": "get_overlapping_areas"},
+ {"display": "get_overlapping_areas()"},
{"display": "linear_damp"},
{"display": "area_entered"},
]
exclude=[
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.cfg
index c8ab63f6d6..d8390ca33c 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.cfg
@@ -3,18 +3,18 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; Area2D
- {"display": "get_overlapping_areas"},
+ {"display": "get_overlapping_areas()"},
{"display": "linear_damp"},
{"display": "area_entered"},
]
exclude=[
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member/member.cfg b/modules/gdscript/tests/scripts/completion/get_node/member/member.cfg
index ae7d34d87d..319c5121b5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member/member.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member/member.cfg
@@ -1,7 +1,7 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_infered/member_infered.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_infered/member_infered.cfg
index ae7d34d87d..319c5121b5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_infered/member_infered.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_infered/member_infered.cfg
@@ -1,7 +1,7 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_infered_scene/class_member_infered_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_infered_scene/class_member_infered_scene.cfg
index 9c580b711d..7518bf5ae5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_infered_scene/class_member_infered_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_infered_scene/class_member_infered_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_infered_scene/native_member_infered_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_infered_scene/native_member_infered_scene.cfg
index 446198dd35..174fdcb184 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_infered_scene/native_member_infered_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_infered_scene/native_member_infered_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.cfg
index 9c580b711d..7518bf5ae5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.cfg
index 446198dd35..174fdcb184 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.cfg
index 8b68d51a89..050b0d61a3 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.cfg
index 72c0549d3b..d647135bc6 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.cfg
index 9c580b711d..7518bf5ae5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.cfg
index 446198dd35..174fdcb184 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.cfg
index 502038bef7..2f747e0bac 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.cfg
@@ -3,7 +3,7 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
@@ -11,6 +11,6 @@ include=[
exclude=[
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.cfg
index 1810e9fe5f..f060413898 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.cfg
@@ -3,7 +3,7 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
@@ -11,6 +11,6 @@ include=[
exclude=[
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.cfg
index 1894e72c65..a6118908de 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.cfg
@@ -3,18 +3,18 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; Area2D
- {"display": "get_overlapping_areas"},
+ {"display": "get_overlapping_areas()"},
{"display": "linear_damp"},
{"display": "area_entered"},
]
exclude=[
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.cfg
index c8ab63f6d6..d8390ca33c 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.cfg
@@ -3,18 +3,18 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; Area2D
- {"display": "get_overlapping_areas"},
+ {"display": "get_overlapping_areas()"},
{"display": "linear_damp"},
{"display": "area_entered"},
]
exclude=[
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/types/local/infered.cfg b/modules/gdscript/tests/scripts/completion/types/local/infered.cfg
index 8b68d51a89..050b0d61a3 100644
--- a/modules/gdscript/tests/scripts/completion/types/local/infered.cfg
+++ b/modules/gdscript/tests/scripts/completion/types/local/infered.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/types/local/no_type.cfg b/modules/gdscript/tests/scripts/completion/types/local/no_type.cfg
index 8b68d51a89..050b0d61a3 100644
--- a/modules/gdscript/tests/scripts/completion/types/local/no_type.cfg
+++ b/modules/gdscript/tests/scripts/completion/types/local/no_type.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/types/local/typehint.cfg b/modules/gdscript/tests/scripts/completion/types/local/typehint.cfg
index 8b68d51a89..050b0d61a3 100644
--- a/modules/gdscript/tests/scripts/completion/types/local/typehint.cfg
+++ b/modules/gdscript/tests/scripts/completion/types/local/typehint.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/types/local/typehint_broad.cfg b/modules/gdscript/tests/scripts/completion/types/local/typehint_broad.cfg
index 8b68d51a89..050b0d61a3 100644
--- a/modules/gdscript/tests/scripts/completion/types/local/typehint_broad.cfg
+++ b/modules/gdscript/tests/scripts/completion/types/local/typehint_broad.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/types/local/typehint_incompatible.cfg b/modules/gdscript/tests/scripts/completion/types/local/typehint_incompatible.cfg
index 8b68d51a89..050b0d61a3 100644
--- a/modules/gdscript/tests/scripts/completion/types/local/typehint_incompatible.cfg
+++ b/modules/gdscript/tests/scripts/completion/types/local/typehint_incompatible.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/types/member/infered.cfg b/modules/gdscript/tests/scripts/completion/types/member/infered.cfg
index 8b68d51a89..050b0d61a3 100644
--- a/modules/gdscript/tests/scripts/completion/types/member/infered.cfg
+++ b/modules/gdscript/tests/scripts/completion/types/member/infered.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/types/member/no_type.cfg b/modules/gdscript/tests/scripts/completion/types/member/no_type.cfg
index 8b68d51a89..050b0d61a3 100644
--- a/modules/gdscript/tests/scripts/completion/types/member/no_type.cfg
+++ b/modules/gdscript/tests/scripts/completion/types/member/no_type.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/types/member/typehint.cfg b/modules/gdscript/tests/scripts/completion/types/member/typehint.cfg
index 8b68d51a89..050b0d61a3 100644
--- a/modules/gdscript/tests/scripts/completion/types/member/typehint.cfg
+++ b/modules/gdscript/tests/scripts/completion/types/member/typehint.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/types/member/typehint_broad.cfg b/modules/gdscript/tests/scripts/completion/types/member/typehint_broad.cfg
index 81401316ec..d32bbac65e 100644
--- a/modules/gdscript/tests/scripts/completion/types/member/typehint_broad.cfg
+++ b/modules/gdscript/tests/scripts/completion/types/member/typehint_broad.cfg
@@ -1,13 +1,13 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
]
exclude=[
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/types/member/typehint_incompatible.cfg b/modules/gdscript/tests/scripts/completion/types/member/typehint_incompatible.cfg
index 8b68d51a89..050b0d61a3 100644
--- a/modules/gdscript/tests/scripts/completion/types/member/typehint_incompatible.cfg
+++ b/modules/gdscript/tests/scripts/completion/types/member/typehint_incompatible.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/runtime/errors/division_by_zero.gd b/modules/gdscript/tests/scripts/runtime/errors/division_by_zero.gd
new file mode 100644
index 0000000000..ace5397f40
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/errors/division_by_zero.gd
@@ -0,0 +1,3 @@
+func test():
+ var integer: int = 1
+ integer /= 0
diff --git a/modules/gdscript/tests/scripts/runtime/errors/division_by_zero.out b/modules/gdscript/tests/scripts/runtime/errors/division_by_zero.out
new file mode 100644
index 0000000000..6a9d11cd77
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/errors/division_by_zero.out
@@ -0,0 +1,6 @@
+GDTEST_RUNTIME_ERROR
+>> SCRIPT ERROR
+>> on function: test()
+>> runtime/errors/division_by_zero.gd
+>> 3
+>> Division by zero error in operator '/'.
diff --git a/modules/gdscript/tests/scripts/runtime/errors/modulo_by_zero.gd b/modules/gdscript/tests/scripts/runtime/errors/modulo_by_zero.gd
new file mode 100644
index 0000000000..99792e4e32
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/errors/modulo_by_zero.gd
@@ -0,0 +1,3 @@
+func test():
+ var integer: int = 1
+ integer %= 0
diff --git a/modules/gdscript/tests/scripts/runtime/errors/modulo_by_zero.out b/modules/gdscript/tests/scripts/runtime/errors/modulo_by_zero.out
new file mode 100644
index 0000000000..79c512888f
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/errors/modulo_by_zero.out
@@ -0,0 +1,6 @@
+GDTEST_RUNTIME_ERROR
+>> SCRIPT ERROR
+>> on function: test()
+>> runtime/errors/modulo_by_zero.gd
+>> 3
+>> Modulo by zero error in operator '%'.
diff --git a/modules/gdscript/tests/scripts/runtime/features/stringify.gd b/modules/gdscript/tests/scripts/runtime/features/stringify.gd
index 8579baf876..463d207e59 100644
--- a/modules/gdscript/tests/scripts/runtime/features/stringify.gd
+++ b/modules/gdscript/tests/scripts/runtime/features/stringify.gd
@@ -4,15 +4,18 @@ func test():
print(-1.25, 0.25, 1.25)
print("hello world")
- print(Vector2(0.25, 0.25))
+ print(Vector2(0.25, 1))
print(Vector2i(0, 0))
- print(Rect2(0.25, 0.25, 0.5, 0.5))
+ print(Rect2(0.25, 0.25, 0.5, 1))
print(Rect2i(0, 0, 0, 0))
- print(Vector3(0.25, 0.25, 0.25))
+ print(Vector3(0.25, 0.25, 1))
print(Vector3i(0, 0, 0))
+ print(Vector4(0.25, 0.25, 0.25, 1))
+ print(Vector4i(0, 0, 0, 0))
+
print(Transform2D.IDENTITY)
print(Plane(1, 2, 3, 4))
print(Quaternion(1, 2, 3, 4))
diff --git a/modules/gdscript/tests/scripts/runtime/features/stringify.out b/modules/gdscript/tests/scripts/runtime/features/stringify.out
index 2463d70ef4..9983366db0 100644
--- a/modules/gdscript/tests/scripts/runtime/features/stringify.out
+++ b/modules/gdscript/tests/scripts/runtime/features/stringify.out
@@ -3,12 +3,14 @@ truefalse
-101
-1.250.251.25
hello world
-(0.25, 0.25)
+(0.25, 1.0)
(0, 0)
-[P: (0.25, 0.25), S: (0.5, 0.5)]
+[P: (0.25, 0.25), S: (0.5, 1.0)]
[P: (0, 0), S: (0, 0)]
-(0.25, 0.25, 0.25)
+(0.25, 0.25, 1.0)
(0, 0, 0)
+(0.25, 0.25, 0.25, 1.0)
+(0, 0, 0, 0)
[X: (1.0, 0.0), Y: (0.0, 1.0), O: (0.0, 0.0)]
[N: (1.0, 2.0, 3.0), D: 4]
(1, 2, 3, 4)
@@ -32,4 +34,4 @@ Node::[signal]property_list_changed
[(1.0, 1.0), (0.0, 0.0)]
[(1.0, 1.0, 1.0), (0.0, 0.0, 0.0)]
[(1.0, 0.0, 0.0, 1.0), (0.0, 0.0, 1.0, 1.0), (0.0, 1.0, 0.0, 1.0)]
-[(1, 1, 1, 1), (0, 0, 0, 0)]
+[(1.0, 1.0, 1.0, 1.0), (0.0, 0.0, 0.0, 0.0)]
diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp
index b9df3d1bbf..ee17835b3e 100644
--- a/modules/lightmapper_rd/lightmapper_rd.cpp
+++ b/modules/lightmapper_rd/lightmapper_rd.cpp
@@ -249,7 +249,9 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_
}
if (p_step_function) {
- p_step_function(0.1, RTR("Determining optimal atlas size"), p_bake_userdata, true);
+ if (p_step_function(0.1, RTR("Determining optimal atlas size"), p_bake_userdata, true)) {
+ return BAKE_ERROR_USER_ABORTED;
+ }
}
atlas_size = Size2i(max, max);
@@ -326,7 +328,9 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_
emission_images.resize(atlas_slices);
if (p_step_function) {
- p_step_function(0.2, RTR("Blitting albedo and emission"), p_bake_userdata, true);
+ if (p_step_function(0.2, RTR("Blitting albedo and emission"), p_bake_userdata, true)) {
+ return BAKE_ERROR_USER_ABORTED;
+ }
}
for (int i = 0; i < atlas_slices; i++) {
@@ -1015,7 +1019,9 @@ LightmapperRD::BakeError LightmapperRD::_denoise(RenderingDevice *p_rd, Ref<RDSh
if (p_step_function) {
int percent = (s + 1) * 100 / p_atlas_slices;
float p = float(s) / p_atlas_slices * 0.1;
- p_step_function(0.8 + p, vformat(RTR("Denoising %d%%"), percent), p_bake_userdata, false);
+ if (p_step_function(0.8 + p, vformat(RTR("Denoising %d%%"), percent), p_bake_userdata, false)) {
+ return BAKE_ERROR_USER_ABORTED;
+ }
}
}
@@ -1267,7 +1273,15 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
rd->buffer_update(bake_parameters_buffer, 0, sizeof(BakeParameters), &bake_parameters);
if (p_step_function) {
- p_step_function(0.47, RTR("Preparing shaders"), p_bake_userdata, true);
+ if (p_step_function(0.47, RTR("Preparing shaders"), p_bake_userdata, true)) {
+ FREE_TEXTURES
+ FREE_BUFFERS
+ memdelete(rd);
+ if (rcd != nullptr) {
+ memdelete(rcd);
+ }
+ return BAKE_ERROR_USER_ABORTED;
+ }
}
//shaders
@@ -1499,7 +1513,17 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
rd->sync();
if (p_step_function) {
- p_step_function(0.49, RTR("Un-occluding geometry"), p_bake_userdata, true);
+ if (p_step_function(0.49, RTR("Un-occluding geometry"), p_bake_userdata, true)) {
+ FREE_TEXTURES
+ FREE_BUFFERS
+ FREE_RASTER_RESOURCES
+ FREE_COMPUTE_RESOURCES
+ memdelete(rd);
+ if (rcd != nullptr) {
+ memdelete(rcd);
+ }
+ return BAKE_ERROR_USER_ABORTED;
+ }
}
PushConstant push_constant;
@@ -1541,7 +1565,17 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
}
if (p_step_function) {
- p_step_function(0.5, RTR("Plot direct lighting"), p_bake_userdata, true);
+ if (p_step_function(0.5, RTR("Plot direct lighting"), p_bake_userdata, true)) {
+ FREE_TEXTURES
+ FREE_BUFFERS
+ FREE_RASTER_RESOURCES
+ FREE_COMPUTE_RESOURCES
+ memdelete(rd);
+ if (rcd != nullptr) {
+ memdelete(rcd);
+ }
+ return BAKE_ERROR_USER_ABORTED;
+ }
}
// Set ray count to the quality used for direct light and bounces.
@@ -1701,7 +1735,17 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
rd->sync();
if (p_step_function) {
- p_step_function(0.6, RTR("Integrate indirect lighting"), p_bake_userdata, true);
+ if (p_step_function(0.6, RTR("Integrate indirect lighting"), p_bake_userdata, true)) {
+ FREE_TEXTURES
+ FREE_BUFFERS
+ FREE_RASTER_RESOURCES
+ FREE_COMPUTE_RESOURCES
+ memdelete(rd);
+ if (rcd != nullptr) {
+ memdelete(rcd);
+ }
+ return BAKE_ERROR_USER_ABORTED;
+ }
}
int count = 0;
@@ -1740,7 +1784,17 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
int total = (atlas_slices * x_regions * y_regions * ray_iterations);
int percent = count * 100 / total;
float p = float(count) / total * 0.1;
- p_step_function(0.6 + p, vformat(RTR("Integrate indirect lighting %d%%"), percent), p_bake_userdata, false);
+ if (p_step_function(0.6 + p, vformat(RTR("Integrate indirect lighting %d%%"), percent), p_bake_userdata, false)) {
+ FREE_TEXTURES
+ FREE_BUFFERS
+ FREE_RASTER_RESOURCES
+ FREE_COMPUTE_RESOURCES
+ memdelete(rd);
+ if (rcd != nullptr) {
+ memdelete(rcd);
+ }
+ return BAKE_ERROR_USER_ABORTED;
+ }
}
}
}
@@ -1756,7 +1810,20 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
light_probe_buffer = rd->storage_buffer_create(sizeof(float) * 4 * 9 * probe_positions.size());
if (p_step_function) {
- p_step_function(0.7, RTR("Baking light probes"), p_bake_userdata, true);
+ if (p_step_function(0.7, RTR("Baking light probes"), p_bake_userdata, true)) {
+ FREE_TEXTURES
+ FREE_BUFFERS
+ FREE_RASTER_RESOURCES
+ FREE_COMPUTE_RESOURCES
+ if (probe_positions.size() > 0) {
+ rd->free(light_probe_buffer);
+ }
+ memdelete(rd);
+ if (rcd != nullptr) {
+ memdelete(rcd);
+ }
+ return BAKE_ERROR_USER_ABORTED;
+ }
}
Vector<RD::Uniform> uniforms;
@@ -1824,7 +1891,20 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
if (p_step_function) {
int percent = i * 100 / ray_iterations;
float p = float(i) / ray_iterations * 0.1;
- p_step_function(0.7 + p, vformat(RTR("Integrating light probes %d%%"), percent), p_bake_userdata, false);
+ if (p_step_function(0.7 + p, vformat(RTR("Integrating light probes %d%%"), percent), p_bake_userdata, false)) {
+ FREE_TEXTURES
+ FREE_BUFFERS
+ FREE_RASTER_RESOURCES
+ FREE_COMPUTE_RESOURCES
+ if (probe_positions.size() > 0) {
+ rd->free(light_probe_buffer);
+ }
+ memdelete(rd);
+ if (rcd != nullptr) {
+ memdelete(rcd);
+ }
+ return BAKE_ERROR_USER_ABORTED;
+ }
}
}
}
@@ -1846,7 +1926,20 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
if (p_use_denoiser) {
if (p_step_function) {
- p_step_function(0.8, RTR("Denoising"), p_bake_userdata, true);
+ if (p_step_function(0.8, RTR("Denoising"), p_bake_userdata, true)) {
+ FREE_TEXTURES
+ FREE_BUFFERS
+ FREE_RASTER_RESOURCES
+ FREE_COMPUTE_RESOURCES
+ if (probe_positions.size() > 0) {
+ rd->free(light_probe_buffer);
+ }
+ memdelete(rd);
+ if (rcd != nullptr) {
+ memdelete(rcd);
+ }
+ return BAKE_ERROR_USER_ABORTED;
+ }
}
{
diff --git a/modules/lightmapper_rd/lm_common_inc.glsl b/modules/lightmapper_rd/lm_common_inc.glsl
index 98d11b9e69..962e444911 100644
--- a/modules/lightmapper_rd/lm_common_inc.glsl
+++ b/modules/lightmapper_rd/lm_common_inc.glsl
@@ -1,4 +1,3 @@
-
/* SET 0, static data that does not change between any call */
layout(set = 0, binding = 0) uniform BakeParameters {
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 9e88e81920..883a56f435 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
@@ -781,8 +781,18 @@ namespace Godot.SourceGenerators
return false; // Non-generic Dictionary, so there's no hint to add
Debug.Assert(elementTypes.Length == 2);
- var keyElementMarshalType = MarshalUtils.ConvertManagedTypeToMarshalType(elementTypes[0], typeCache)!.Value;
- var keyElementVariantType = MarshalUtils.ConvertMarshalTypeToVariantType(keyElementMarshalType)!.Value;
+ var keyElementMarshalType = MarshalUtils.ConvertManagedTypeToMarshalType(elementTypes[0], typeCache);
+ var valueElementMarshalType = MarshalUtils.ConvertManagedTypeToMarshalType(elementTypes[1], typeCache);
+
+ if (keyElementMarshalType == null || valueElementMarshalType == null)
+ {
+ // To maintain compatibility with previous versions of Godot before 4.4,
+ // we must preserve the old behavior for generic dictionaries with non-marshallable
+ // generic type arguments.
+ return false;
+ }
+
+ var keyElementVariantType = MarshalUtils.ConvertMarshalTypeToVariantType(keyElementMarshalType.Value)!.Value;
var keyIsPresetHint = false;
var keyHintString = (string?)null;
@@ -809,8 +819,7 @@ namespace Godot.SourceGenerators
}
}
- var valueElementMarshalType = MarshalUtils.ConvertManagedTypeToMarshalType(elementTypes[1], typeCache)!.Value;
- var valueElementVariantType = MarshalUtils.ConvertMarshalTypeToVariantType(valueElementMarshalType)!.Value;
+ var valueElementVariantType = MarshalUtils.ConvertMarshalTypeToVariantType(valueElementMarshalType.Value)!.Value;
var valueIsPresetHint = false;
var valueHintString = (string?)null;
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index efe03298b9..5d7e346453 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -5042,22 +5042,25 @@ void BindingsGenerator::_populate_global_constants() {
}
}
- // HARDCODED
- List<StringName> hardcoded_enums;
- hardcoded_enums.push_back("Vector2.Axis");
- hardcoded_enums.push_back("Vector2I.Axis");
- hardcoded_enums.push_back("Vector3.Axis");
- hardcoded_enums.push_back("Vector3I.Axis");
- for (const StringName &enum_cname : hardcoded_enums) {
- // These enums are not generated and must be written manually (e.g.: Vector3.Axis)
- // Here, we assume core types do not begin with underscore
- TypeInterface enum_itype;
- enum_itype.is_enum = true;
- enum_itype.name = enum_cname.operator String();
- enum_itype.cname = enum_cname;
- enum_itype.proxy_name = pascal_to_pascal_case(enum_itype.name);
- TypeInterface::postsetup_enum_type(enum_itype);
- enum_types.insert(enum_itype.cname, enum_itype);
+ for (int i = 0; i < Variant::VARIANT_MAX; i++) {
+ if (i == Variant::OBJECT) {
+ continue;
+ }
+
+ const Variant::Type type = Variant::Type(i);
+
+ List<StringName> enum_names;
+ Variant::get_enums_for_type(type, &enum_names);
+
+ for (const StringName &enum_name : enum_names) {
+ TypeInterface enum_itype;
+ enum_itype.is_enum = true;
+ enum_itype.name = Variant::get_type_name(type) + "." + enum_name;
+ enum_itype.cname = enum_itype.name;
+ enum_itype.proxy_name = pascal_to_pascal_case(enum_itype.name);
+ TypeInterface::postsetup_enum_type(enum_itype);
+ enum_types.insert(enum_itype.cname, enum_itype);
+ }
}
}
diff --git a/modules/upnp/SCsub b/modules/upnp/SCsub
index 6657d75cae..ba4a842cb6 100644
--- a/modules/upnp/SCsub
+++ b/modules/upnp/SCsub
@@ -10,7 +10,7 @@ env_upnp = env_modules.Clone()
thirdparty_obj = []
-if env["builtin_miniupnpc"]:
+if env["builtin_miniupnpc"] and env["platform"] != "web":
thirdparty_dir = "#thirdparty/miniupnpc/"
thirdparty_sources = [
"igd_desc_parse.c",
diff --git a/modules/upnp/register_types.cpp b/modules/upnp/register_types.cpp
index c2e25224ea..58e5b31ace 100644
--- a/modules/upnp/register_types.cpp
+++ b/modules/upnp/register_types.cpp
@@ -35,6 +35,11 @@
#include "upnp.h"
#include "upnp_device.h"
+#ifndef WEB_ENABLED
+#include "upnp_device_miniupnp.h"
+#include "upnp_miniupnp.h"
+#endif
+
#include "core/error/error_macros.h"
void initialize_upnp_module(ModuleInitializationLevel p_level) {
@@ -42,8 +47,13 @@ void initialize_upnp_module(ModuleInitializationLevel p_level) {
return;
}
- GDREGISTER_CLASS(UPNP);
- GDREGISTER_CLASS(UPNPDevice);
+ ClassDB::register_custom_instance_class<UPNP>();
+ ClassDB::register_custom_instance_class<UPNPDevice>();
+
+#ifndef WEB_ENABLED
+ UPNPMiniUPNP::make_default();
+ UPNPDeviceMiniUPNP::make_default();
+#endif
}
void uninitialize_upnp_module(ModuleInitializationLevel p_level) {
diff --git a/modules/upnp/upnp.cpp b/modules/upnp/upnp.cpp
index dcdb8df77a..c7c0562b7b 100644
--- a/modules/upnp/upnp.cpp
+++ b/modules/upnp/upnp.cpp
@@ -32,298 +32,7 @@
#include "upnp.h"
-#include <miniwget.h>
-#include <upnpcommands.h>
-
-#include <stdlib.h>
-
-bool UPNP::is_common_device(const String &dev) const {
- return dev.is_empty() ||
- dev.contains("InternetGatewayDevice") ||
- dev.contains("WANIPConnection") ||
- dev.contains("WANPPPConnection") ||
- dev.contains("rootdevice");
-}
-
-int UPNP::discover(int timeout, int ttl, const String &device_filter) {
- ERR_FAIL_COND_V_MSG(timeout < 0, UPNP_RESULT_INVALID_PARAM, "The response's wait time can't be negative.");
- ERR_FAIL_COND_V_MSG(ttl < 0 || ttl > 255, UPNP_RESULT_INVALID_PARAM, "The time-to-live must be set between 0 and 255 (inclusive).");
-
- devices.clear();
-
- int error = 0;
- struct UPNPDev *devlist;
-
- CharString cs = discover_multicast_if.utf8();
- const char *m_if = cs.length() ? cs.get_data() : nullptr;
- if (is_common_device(device_filter)) {
- devlist = upnpDiscover(timeout, m_if, nullptr, discover_local_port, discover_ipv6, ttl, &error);
- } else {
- devlist = upnpDiscoverAll(timeout, m_if, nullptr, discover_local_port, discover_ipv6, ttl, &error);
- }
-
- if (error != UPNPDISCOVER_SUCCESS) {
- switch (error) {
- case UPNPDISCOVER_SOCKET_ERROR:
- return UPNP_RESULT_SOCKET_ERROR;
- case UPNPDISCOVER_MEMORY_ERROR:
- return UPNP_RESULT_MEM_ALLOC_ERROR;
- default:
- return UPNP_RESULT_UNKNOWN_ERROR;
- }
- }
-
- if (!devlist) {
- return UPNP_RESULT_NO_DEVICES;
- }
-
- struct UPNPDev *dev = devlist;
-
- while (dev) {
- if (device_filter.is_empty() || strstr(dev->st, device_filter.utf8().get_data())) {
- add_device_to_list(dev, devlist);
- }
-
- dev = dev->pNext;
- }
-
- freeUPNPDevlist(devlist);
-
- return UPNP_RESULT_SUCCESS;
-}
-
-void UPNP::add_device_to_list(UPNPDev *dev, UPNPDev *devlist) {
- Ref<UPNPDevice> new_device;
- new_device.instantiate();
-
- new_device->set_description_url(dev->descURL);
- new_device->set_service_type(dev->st);
-
- parse_igd(new_device, devlist);
-
- devices.push_back(new_device);
-}
-
-char *UPNP::load_description(const String &url, int *size, int *status_code) const {
- return (char *)miniwget(url.utf8().get_data(), size, 0, status_code);
-}
-
-void UPNP::parse_igd(Ref<UPNPDevice> dev, UPNPDev *devlist) {
- int size = 0;
- int status_code = -1;
- char *xml = load_description(dev->get_description_url(), &size, &status_code);
-
- if (status_code != 200) {
- dev->set_igd_status(UPNPDevice::IGD_STATUS_HTTP_ERROR);
- return;
- }
-
- if (!xml || size < 1) {
- dev->set_igd_status(UPNPDevice::IGD_STATUS_HTTP_EMPTY);
- return;
- }
-
- struct UPNPUrls urls = {};
- struct IGDdatas data;
-
- parserootdesc(xml, size, &data);
- free(xml);
- xml = nullptr;
-
- GetUPNPUrls(&urls, &data, dev->get_description_url().utf8().get_data(), 0);
-
- char addr[16];
-#if MINIUPNPC_API_VERSION >= 18
- int i = UPNP_GetValidIGD(devlist, &urls, &data, (char *)&addr, 16, nullptr, 0);
-#else
- int i = UPNP_GetValidIGD(devlist, &urls, &data, (char *)&addr, 16);
-#endif
-
- if (i != 1) {
- FreeUPNPUrls(&urls);
-
- switch (i) {
- case 0:
- dev->set_igd_status(UPNPDevice::IGD_STATUS_NO_IGD);
- return;
- case 2:
- dev->set_igd_status(UPNPDevice::IGD_STATUS_DISCONNECTED);
- return;
- case 3:
- dev->set_igd_status(UPNPDevice::IGD_STATUS_UNKNOWN_DEVICE);
- return;
- default:
- dev->set_igd_status(UPNPDevice::IGD_STATUS_UNKNOWN_ERROR);
- return;
- }
- }
-
- if (urls.controlURL[0] == '\0') {
- FreeUPNPUrls(&urls);
- dev->set_igd_status(UPNPDevice::IGD_STATUS_INVALID_CONTROL);
- return;
- }
-
- dev->set_igd_control_url(urls.controlURL);
- dev->set_igd_service_type(data.first.servicetype);
- dev->set_igd_our_addr(addr);
- dev->set_igd_status(UPNPDevice::IGD_STATUS_OK);
-
- FreeUPNPUrls(&urls);
-}
-
-int UPNP::upnp_result(int in) {
- switch (in) {
- case UPNPCOMMAND_SUCCESS:
- return UPNP_RESULT_SUCCESS;
- case UPNPCOMMAND_UNKNOWN_ERROR:
- return UPNP_RESULT_UNKNOWN_ERROR;
- case UPNPCOMMAND_INVALID_ARGS:
- return UPNP_RESULT_INVALID_ARGS;
- case UPNPCOMMAND_HTTP_ERROR:
- return UPNP_RESULT_HTTP_ERROR;
- case UPNPCOMMAND_INVALID_RESPONSE:
- return UPNP_RESULT_INVALID_RESPONSE;
- case UPNPCOMMAND_MEM_ALLOC_ERROR:
- return UPNP_RESULT_MEM_ALLOC_ERROR;
-
- case 402:
- return UPNP_RESULT_INVALID_ARGS;
- case 403:
- return UPNP_RESULT_NOT_AUTHORIZED;
- case 501:
- return UPNP_RESULT_ACTION_FAILED;
- case 606:
- return UPNP_RESULT_NOT_AUTHORIZED;
- case 714:
- return UPNP_RESULT_NO_SUCH_ENTRY_IN_ARRAY;
- case 715:
- return UPNP_RESULT_SRC_IP_WILDCARD_NOT_PERMITTED;
- case 716:
- return UPNP_RESULT_EXT_PORT_WILDCARD_NOT_PERMITTED;
- case 718:
- return UPNP_RESULT_CONFLICT_WITH_OTHER_MAPPING;
- case 724:
- return UPNP_RESULT_SAME_PORT_VALUES_REQUIRED;
- case 725:
- return UPNP_RESULT_ONLY_PERMANENT_LEASE_SUPPORTED;
- case 726:
- return UPNP_RESULT_REMOTE_HOST_MUST_BE_WILDCARD;
- case 727:
- return UPNP_RESULT_EXT_PORT_MUST_BE_WILDCARD;
- case 728:
- return UPNP_RESULT_NO_PORT_MAPS_AVAILABLE;
- case 729:
- return UPNP_RESULT_CONFLICT_WITH_OTHER_MECHANISM;
- case 732:
- return UPNP_RESULT_INT_PORT_WILDCARD_NOT_PERMITTED;
- case 733:
- return UPNP_RESULT_INCONSISTENT_PARAMETERS;
- }
-
- return UPNP_RESULT_UNKNOWN_ERROR;
-}
-
-int UPNP::get_device_count() const {
- return devices.size();
-}
-
-Ref<UPNPDevice> UPNP::get_device(int index) const {
- ERR_FAIL_INDEX_V(index, devices.size(), nullptr);
-
- return devices.get(index);
-}
-
-void UPNP::add_device(Ref<UPNPDevice> device) {
- ERR_FAIL_COND(device.is_null());
-
- devices.push_back(device);
-}
-
-void UPNP::set_device(int index, Ref<UPNPDevice> device) {
- ERR_FAIL_INDEX(index, devices.size());
- ERR_FAIL_COND(device.is_null());
-
- devices.set(index, device);
-}
-
-void UPNP::remove_device(int index) {
- ERR_FAIL_INDEX(index, devices.size());
-
- devices.remove_at(index);
-}
-
-void UPNP::clear_devices() {
- devices.clear();
-}
-
-Ref<UPNPDevice> UPNP::get_gateway() const {
- ERR_FAIL_COND_V_MSG(devices.is_empty(), nullptr, "Couldn't find any UPNPDevices.");
-
- for (int i = 0; i < devices.size(); i++) {
- Ref<UPNPDevice> dev = get_device(i);
-
- if (dev.is_valid() && dev->is_valid_gateway()) {
- return dev;
- }
- }
-
- return nullptr;
-}
-
-void UPNP::set_discover_multicast_if(const String &m_if) {
- discover_multicast_if = m_if;
-}
-
-String UPNP::get_discover_multicast_if() const {
- return discover_multicast_if;
-}
-
-void UPNP::set_discover_local_port(int port) {
- discover_local_port = port;
-}
-
-int UPNP::get_discover_local_port() const {
- return discover_local_port;
-}
-
-void UPNP::set_discover_ipv6(bool ipv6) {
- discover_ipv6 = ipv6;
-}
-
-bool UPNP::is_discover_ipv6() const {
- return discover_ipv6;
-}
-
-String UPNP::query_external_address() const {
- Ref<UPNPDevice> dev = get_gateway();
-
- if (dev.is_null()) {
- return "";
- }
-
- return dev->query_external_address();
-}
-
-int UPNP::add_port_mapping(int port, int port_internal, String desc, String proto, int duration) const {
- Ref<UPNPDevice> dev = get_gateway();
-
- if (dev.is_null()) {
- return UPNP_RESULT_NO_GATEWAY;
- }
-
- return dev->add_port_mapping(port, port_internal, desc, proto, duration);
-}
-
-int UPNP::delete_port_mapping(int port, String proto) const {
- Ref<UPNPDevice> dev = get_gateway();
-
- if (dev.is_null()) {
- return UPNP_RESULT_NO_GATEWAY;
- }
-
- return dev->delete_port_mapping(port, proto);
-}
+UPNP *(*UPNP::_create)(bool p_notify_postinitialize) = nullptr;
void UPNP::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_device_count"), &UPNP::get_device_count);
@@ -384,9 +93,3 @@ void UPNP::_bind_methods() {
BIND_ENUM_CONSTANT(UPNP_RESULT_NO_DEVICES);
BIND_ENUM_CONSTANT(UPNP_RESULT_UNKNOWN_ERROR);
}
-
-UPNP::UPNP() {
-}
-
-UPNP::~UPNP() {
-}
diff --git a/modules/upnp/upnp.h b/modules/upnp/upnp.h
index fe6724193d..a89cfa1944 100644
--- a/modules/upnp/upnp.h
+++ b/modules/upnp/upnp.h
@@ -37,26 +37,14 @@
#include "core/object/ref_counted.h"
-#include <miniupnpc.h>
-
class UPNP : public RefCounted {
GDCLASS(UPNP, RefCounted);
-private:
- String discover_multicast_if = "";
- int discover_local_port = 0;
- bool discover_ipv6 = false;
-
- Vector<Ref<UPNPDevice>> devices;
-
- bool is_common_device(const String &dev) const;
- void add_device_to_list(UPNPDev *dev, UPNPDev *devlist);
- void parse_igd(Ref<UPNPDevice> dev, UPNPDev *devlist);
- char *load_description(const String &url, int *size, int *status_code) const;
-
protected:
static void _bind_methods();
+ static UPNP *(*_create)(bool p_notify_postinitialize);
+
public:
enum UPNPResult {
UPNP_RESULT_SUCCESS,
@@ -90,35 +78,40 @@ public:
UPNP_RESULT_UNKNOWN_ERROR,
};
- static int upnp_result(int in);
+ static UPNP *create(bool p_notify_postinitialize = true) {
+ if (!_create) {
+ return nullptr;
+ }
+ return _create(p_notify_postinitialize);
+ }
- int get_device_count() const;
- Ref<UPNPDevice> get_device(int index) const;
- void add_device(Ref<UPNPDevice> device);
- void set_device(int index, Ref<UPNPDevice> device);
- void remove_device(int index);
- void clear_devices();
+ virtual int get_device_count() const = 0;
+ virtual Ref<UPNPDevice> get_device(int index) const = 0;
+ virtual void add_device(Ref<UPNPDevice> device) = 0;
+ virtual void set_device(int index, Ref<UPNPDevice> device) = 0;
+ virtual void remove_device(int index) = 0;
+ virtual void clear_devices() = 0;
- Ref<UPNPDevice> get_gateway() const;
+ virtual Ref<UPNPDevice> get_gateway() const = 0;
- int discover(int timeout = 2000, int ttl = 2, const String &device_filter = "InternetGatewayDevice");
+ virtual int discover(int timeout = 2000, int ttl = 2, const String &device_filter = "InternetGatewayDevice") = 0;
- String query_external_address() const;
+ virtual String query_external_address() const = 0;
- int add_port_mapping(int port, int port_internal = 0, String desc = "", String proto = "UDP", int duration = 0) const;
- int delete_port_mapping(int port, String proto = "UDP") const;
+ virtual int add_port_mapping(int port, int port_internal = 0, String desc = "", String proto = "UDP", int duration = 0) const = 0;
+ virtual int delete_port_mapping(int port, String proto = "UDP") const = 0;
- void set_discover_multicast_if(const String &m_if);
- String get_discover_multicast_if() const;
+ virtual void set_discover_multicast_if(const String &m_if) = 0;
+ virtual String get_discover_multicast_if() const = 0;
- void set_discover_local_port(int port);
- int get_discover_local_port() const;
+ virtual void set_discover_local_port(int port) = 0;
+ virtual int get_discover_local_port() const = 0;
- void set_discover_ipv6(bool ipv6);
- bool is_discover_ipv6() const;
+ virtual void set_discover_ipv6(bool ipv6) = 0;
+ virtual bool is_discover_ipv6() const = 0;
- UPNP();
- ~UPNP();
+ UPNP() {}
+ virtual ~UPNP() {}
};
VARIANT_ENUM_CAST(UPNP::UPNPResult)
diff --git a/modules/upnp/upnp_device.cpp b/modules/upnp/upnp_device.cpp
index 1af2b2e8cc..d01d718530 100644
--- a/modules/upnp/upnp_device.cpp
+++ b/modules/upnp/upnp_device.cpp
@@ -32,119 +32,7 @@
#include "upnp_device.h"
-#include "upnp.h"
-
-#include <upnpcommands.h>
-
-String UPNPDevice::query_external_address() const {
- ERR_FAIL_COND_V_MSG(!is_valid_gateway(), "", "The Internet Gateway Device must be valid.");
-
- char addr[16];
- int i = UPNP_GetExternalIPAddress(
- igd_control_url.utf8().get_data(),
- igd_service_type.utf8().get_data(),
- (char *)&addr);
-
- ERR_FAIL_COND_V_MSG(i != UPNPCOMMAND_SUCCESS, "", "Couldn't get external IP address.");
-
- return String(addr);
-}
-
-int UPNPDevice::add_port_mapping(int port, int port_internal, String desc, String proto, int duration) const {
- ERR_FAIL_COND_V_MSG(!is_valid_gateway(), UPNP::UPNP_RESULT_INVALID_GATEWAY, "The Internet Gateway Device must be valid.");
- ERR_FAIL_COND_V_MSG(port < 1 || port > 65535, UPNP::UPNP_RESULT_INVALID_PORT, "The port number must be set between 1 and 65535 (inclusive).");
- ERR_FAIL_COND_V_MSG(port_internal < 0 || port_internal > 65535, UPNP::UPNP_RESULT_INVALID_PORT, "The port number must be set between 0 and 65535 (inclusive)."); // Needs to allow 0 because 0 signifies "use external port as internal port"
- ERR_FAIL_COND_V_MSG(proto != "UDP" && proto != "TCP", UPNP::UPNP_RESULT_INVALID_PROTOCOL, "The protocol must be either TCP or UDP.");
- ERR_FAIL_COND_V_MSG(duration < 0, UPNP::UPNP_RESULT_INVALID_DURATION, "The port mapping's lease duration can't be negative.");
-
- if (port_internal < 1) {
- port_internal = port;
- }
-
- int i = UPNP_AddPortMapping(
- igd_control_url.utf8().get_data(),
- igd_service_type.utf8().get_data(),
- itos(port).utf8().get_data(),
- itos(port_internal).utf8().get_data(),
- igd_our_addr.utf8().get_data(),
- desc.is_empty() ? nullptr : desc.utf8().get_data(),
- proto.utf8().get_data(),
- nullptr, // Remote host, always nullptr as IGDs don't support it
- duration > 0 ? itos(duration).utf8().get_data() : nullptr);
-
- ERR_FAIL_COND_V_MSG(i != UPNPCOMMAND_SUCCESS, UPNP::upnp_result(i), "Couldn't add port mapping.");
-
- return UPNP::UPNP_RESULT_SUCCESS;
-}
-
-int UPNPDevice::delete_port_mapping(int port, String proto) const {
- ERR_FAIL_COND_V_MSG(port < 1 || port > 65535, UPNP::UPNP_RESULT_INVALID_PORT, "The port number must be set between 1 and 65535 (inclusive).");
- ERR_FAIL_COND_V_MSG(proto != "UDP" && proto != "TCP", UPNP::UPNP_RESULT_INVALID_PROTOCOL, "The protocol must be either TCP or UDP.");
-
- int i = UPNP_DeletePortMapping(
- igd_control_url.utf8().get_data(),
- igd_service_type.utf8().get_data(),
- itos(port).utf8().get_data(),
- proto.utf8().get_data(),
- nullptr // Remote host, always nullptr as IGDs don't support it
- );
-
- ERR_FAIL_COND_V_MSG(i != UPNPCOMMAND_SUCCESS, UPNP::upnp_result(i), "Couldn't delete port mapping.");
-
- return UPNP::UPNP_RESULT_SUCCESS;
-}
-
-void UPNPDevice::set_description_url(const String &url) {
- description_url = url;
-}
-
-String UPNPDevice::get_description_url() const {
- return description_url;
-}
-
-void UPNPDevice::set_service_type(const String &type) {
- service_type = type;
-}
-
-String UPNPDevice::get_service_type() const {
- return service_type;
-}
-
-void UPNPDevice::set_igd_control_url(const String &url) {
- igd_control_url = url;
-}
-
-String UPNPDevice::get_igd_control_url() const {
- return igd_control_url;
-}
-
-void UPNPDevice::set_igd_service_type(const String &type) {
- igd_service_type = type;
-}
-
-String UPNPDevice::get_igd_service_type() const {
- return igd_service_type;
-}
-
-void UPNPDevice::set_igd_our_addr(const String &addr) {
- igd_our_addr = addr;
-}
-
-String UPNPDevice::get_igd_our_addr() const {
- return igd_our_addr;
-}
-
-void UPNPDevice::set_igd_status(IGDStatus status) {
- igd_status = status;
-}
-
-UPNPDevice::IGDStatus UPNPDevice::get_igd_status() const {
- return igd_status;
-}
-
-bool UPNPDevice::is_valid_gateway() const {
- return igd_status == IGD_STATUS_OK;
-}
+UPNPDevice *(*UPNPDevice::_create)(bool p_notify_postinitialize) = nullptr;
void UPNPDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_valid_gateway"), &UPNPDevice::is_valid_gateway);
@@ -187,15 +75,3 @@ void UPNPDevice::_bind_methods() {
BIND_ENUM_CONSTANT(IGD_STATUS_MALLOC_ERROR);
BIND_ENUM_CONSTANT(IGD_STATUS_UNKNOWN_ERROR);
}
-
-UPNPDevice::UPNPDevice() {
- description_url = "";
- service_type = "";
- igd_control_url = "";
- igd_service_type = "";
- igd_our_addr = "";
- igd_status = IGD_STATUS_UNKNOWN_ERROR;
-}
-
-UPNPDevice::~UPNPDevice() {
-}
diff --git a/modules/upnp/upnp_device.h b/modules/upnp/upnp_device.h
index bbebe3149d..b594c50b8c 100644
--- a/modules/upnp/upnp_device.h
+++ b/modules/upnp/upnp_device.h
@@ -38,6 +38,11 @@
class UPNPDevice : public RefCounted {
GDCLASS(UPNPDevice, RefCounted);
+protected:
+ static void _bind_methods();
+
+ static UPNPDevice *(*_create)(bool p_notify_postinitialize);
+
public:
enum IGDStatus {
IGD_STATUS_OK,
@@ -52,42 +57,38 @@ public:
IGD_STATUS_UNKNOWN_ERROR,
};
- void set_description_url(const String &url);
- String get_description_url() const;
+ static UPNPDevice *create(bool p_notify_postinitialize = true) {
+ if (!_create) {
+ return nullptr;
+ }
+ return _create(p_notify_postinitialize);
+ }
- void set_service_type(const String &type);
- String get_service_type() const;
+ virtual void set_description_url(const String &url) = 0;
+ virtual String get_description_url() const = 0;
- void set_igd_control_url(const String &url);
- String get_igd_control_url() const;
+ virtual void set_service_type(const String &type) = 0;
+ virtual String get_service_type() const = 0;
- void set_igd_service_type(const String &type);
- String get_igd_service_type() const;
+ virtual void set_igd_control_url(const String &url) = 0;
+ virtual String get_igd_control_url() const = 0;
- void set_igd_our_addr(const String &addr);
- String get_igd_our_addr() const;
+ virtual void set_igd_service_type(const String &type) = 0;
+ virtual String get_igd_service_type() const = 0;
- void set_igd_status(IGDStatus status);
- IGDStatus get_igd_status() const;
+ virtual void set_igd_our_addr(const String &addr) = 0;
+ virtual String get_igd_our_addr() const = 0;
- bool is_valid_gateway() const;
- String query_external_address() const;
- int add_port_mapping(int port, int port_internal = 0, String desc = "", String proto = "UDP", int duration = 0) const;
- int delete_port_mapping(int port, String proto = "UDP") const;
+ virtual void set_igd_status(IGDStatus status) = 0;
+ virtual IGDStatus get_igd_status() const = 0;
- UPNPDevice();
- ~UPNPDevice();
-
-protected:
- static void _bind_methods();
+ virtual bool is_valid_gateway() const = 0;
+ virtual String query_external_address() const = 0;
+ virtual int add_port_mapping(int port, int port_internal = 0, String desc = "", String proto = "UDP", int duration = 0) const = 0;
+ virtual int delete_port_mapping(int port, String proto = "UDP") const = 0;
-private:
- String description_url;
- String service_type;
- String igd_control_url;
- String igd_service_type;
- String igd_our_addr;
- IGDStatus igd_status;
+ UPNPDevice() {}
+ virtual ~UPNPDevice() {}
};
VARIANT_ENUM_CAST(UPNPDevice::IGDStatus)
diff --git a/modules/upnp/upnp_device_miniupnp.cpp b/modules/upnp/upnp_device_miniupnp.cpp
new file mode 100644
index 0000000000..34f2a189d5
--- /dev/null
+++ b/modules/upnp/upnp_device_miniupnp.cpp
@@ -0,0 +1,155 @@
+/**************************************************************************/
+/* upnp_device_miniupnp.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* REDOT ENGINE */
+/* https://redotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2024-present Redot Engine contributors */
+/* (see REDOT_AUTHORS.md) */
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef WEB_ENABLED
+
+#include "upnp_device_miniupnp.h"
+
+#include "upnp_miniupnp.h"
+
+#include <upnpcommands.h>
+
+void UPNPDeviceMiniUPNP::make_default() {
+ UPNPDevice::_create = UPNPDeviceMiniUPNP::_create;
+}
+
+String UPNPDeviceMiniUPNP::query_external_address() const {
+ ERR_FAIL_COND_V_MSG(!is_valid_gateway(), "", "The Internet Gateway Device must be valid.");
+
+ char addr[16];
+ int i = UPNP_GetExternalIPAddress(
+ igd_control_url.utf8().get_data(),
+ igd_service_type.utf8().get_data(),
+ (char *)&addr);
+
+ ERR_FAIL_COND_V_MSG(i != UPNPCOMMAND_SUCCESS, "", "Couldn't get external IP address.");
+
+ return String(addr);
+}
+
+int UPNPDeviceMiniUPNP::add_port_mapping(int port, int port_internal, String desc, String proto, int duration) const {
+ ERR_FAIL_COND_V_MSG(!is_valid_gateway(), UPNP::UPNP_RESULT_INVALID_GATEWAY, "The Internet Gateway Device must be valid.");
+ ERR_FAIL_COND_V_MSG(port < 1 || port > 65535, UPNP::UPNP_RESULT_INVALID_PORT, "The port number must be set between 1 and 65535 (inclusive).");
+ ERR_FAIL_COND_V_MSG(port_internal < 0 || port_internal > 65535, UPNP::UPNP_RESULT_INVALID_PORT, "The port number must be set between 0 and 65535 (inclusive)."); // Needs to allow 0 because 0 signifies "use external port as internal port"
+ ERR_FAIL_COND_V_MSG(proto != "UDP" && proto != "TCP", UPNP::UPNP_RESULT_INVALID_PROTOCOL, "The protocol must be either TCP or UDP.");
+ ERR_FAIL_COND_V_MSG(duration < 0, UPNP::UPNP_RESULT_INVALID_DURATION, "The port mapping's lease duration can't be negative.");
+
+ if (port_internal < 1) {
+ port_internal = port;
+ }
+
+ int i = UPNP_AddPortMapping(
+ igd_control_url.utf8().get_data(),
+ igd_service_type.utf8().get_data(),
+ itos(port).utf8().get_data(),
+ itos(port_internal).utf8().get_data(),
+ igd_our_addr.utf8().get_data(),
+ desc.is_empty() ? nullptr : desc.utf8().get_data(),
+ proto.utf8().get_data(),
+ nullptr, // Remote host, always nullptr as IGDs don't support it
+ duration > 0 ? itos(duration).utf8().get_data() : nullptr);
+
+ ERR_FAIL_COND_V_MSG(i != UPNPCOMMAND_SUCCESS, UPNPMiniUPNP::upnp_result(i), "Couldn't add port mapping.");
+
+ return UPNP::UPNP_RESULT_SUCCESS;
+}
+
+int UPNPDeviceMiniUPNP::delete_port_mapping(int port, String proto) const {
+ ERR_FAIL_COND_V_MSG(port < 1 || port > 65535, UPNP::UPNP_RESULT_INVALID_PORT, "The port number must be set between 1 and 65535 (inclusive).");
+ ERR_FAIL_COND_V_MSG(proto != "UDP" && proto != "TCP", UPNP::UPNP_RESULT_INVALID_PROTOCOL, "The protocol must be either TCP or UDP.");
+
+ int i = UPNP_DeletePortMapping(
+ igd_control_url.utf8().get_data(),
+ igd_service_type.utf8().get_data(),
+ itos(port).utf8().get_data(),
+ proto.utf8().get_data(),
+ nullptr // Remote host, always nullptr as IGDs don't support it
+ );
+
+ ERR_FAIL_COND_V_MSG(i != UPNPCOMMAND_SUCCESS, UPNPMiniUPNP::upnp_result(i), "Couldn't delete port mapping.");
+
+ return UPNP::UPNP_RESULT_SUCCESS;
+}
+
+void UPNPDeviceMiniUPNP::set_description_url(const String &url) {
+ description_url = url;
+}
+
+String UPNPDeviceMiniUPNP::get_description_url() const {
+ return description_url;
+}
+
+void UPNPDeviceMiniUPNP::set_service_type(const String &type) {
+ service_type = type;
+}
+
+String UPNPDeviceMiniUPNP::get_service_type() const {
+ return service_type;
+}
+
+void UPNPDeviceMiniUPNP::set_igd_control_url(const String &url) {
+ igd_control_url = url;
+}
+
+String UPNPDeviceMiniUPNP::get_igd_control_url() const {
+ return igd_control_url;
+}
+
+void UPNPDeviceMiniUPNP::set_igd_service_type(const String &type) {
+ igd_service_type = type;
+}
+
+String UPNPDeviceMiniUPNP::get_igd_service_type() const {
+ return igd_service_type;
+}
+
+void UPNPDeviceMiniUPNP::set_igd_our_addr(const String &addr) {
+ igd_our_addr = addr;
+}
+
+String UPNPDeviceMiniUPNP::get_igd_our_addr() const {
+ return igd_our_addr;
+}
+
+void UPNPDeviceMiniUPNP::set_igd_status(IGDStatus status) {
+ igd_status = status;
+}
+
+UPNPDeviceMiniUPNP::IGDStatus UPNPDeviceMiniUPNP::get_igd_status() const {
+ return igd_status;
+}
+
+bool UPNPDeviceMiniUPNP::is_valid_gateway() const {
+ return igd_status == IGD_STATUS_OK;
+}
+
+#endif // WEB_ENABLED
diff --git a/modules/upnp/upnp_device_miniupnp.h b/modules/upnp/upnp_device_miniupnp.h
new file mode 100644
index 0000000000..231180df11
--- /dev/null
+++ b/modules/upnp/upnp_device_miniupnp.h
@@ -0,0 +1,85 @@
+/**************************************************************************/
+/* upnp_device_miniupnp.h */
+/**************************************************************************/
+/* This file is part of: */
+/* REDOT ENGINE */
+/* https://redotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2024-present Redot Engine contributors */
+/* (see REDOT_AUTHORS.md) */
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef UPNP_DEVICE_MINIUPNP_H
+#define UPNP_DEVICE_MINIUPNP_H
+
+#ifndef WEB_ENABLED
+
+#include "upnp_device.h"
+
+class UPNPDeviceMiniUPNP : public UPNPDevice {
+ GDCLASS(UPNPDeviceMiniUPNP, UPNPDevice);
+
+private:
+ static UPNPDevice *_create(bool p_notify_postinitialize) { return static_cast<UPNPDevice *>(ClassDB::creator<UPNPDeviceMiniUPNP>(p_notify_postinitialize)); }
+
+ String description_url;
+ String service_type;
+ String igd_control_url;
+ String igd_service_type;
+ String igd_our_addr;
+ IGDStatus igd_status = IGD_STATUS_UNKNOWN_ERROR;
+
+public:
+ static void make_default();
+
+ virtual void set_description_url(const String &url) override;
+ virtual String get_description_url() const override;
+
+ virtual void set_service_type(const String &type) override;
+ virtual String get_service_type() const override;
+
+ virtual void set_igd_control_url(const String &url) override;
+ virtual String get_igd_control_url() const override;
+
+ virtual void set_igd_service_type(const String &type) override;
+ virtual String get_igd_service_type() const override;
+
+ virtual void set_igd_our_addr(const String &addr) override;
+ virtual String get_igd_our_addr() const override;
+
+ virtual void set_igd_status(IGDStatus status) override;
+ virtual IGDStatus get_igd_status() const override;
+
+ virtual bool is_valid_gateway() const override;
+ virtual String query_external_address() const override;
+ virtual int add_port_mapping(int port, int port_internal = 0, String desc = "", String proto = "UDP", int duration = 0) const override;
+ virtual int delete_port_mapping(int port, String proto = "UDP") const override;
+
+ UPNPDeviceMiniUPNP() {}
+ virtual ~UPNPDeviceMiniUPNP() {}
+};
+
+#endif // WEB_ENABLED
+
+#endif // UPNP_DEVICE_MINIUPNP_H
diff --git a/modules/upnp/upnp_miniupnp.cpp b/modules/upnp/upnp_miniupnp.cpp
new file mode 100644
index 0000000000..45c1018fb6
--- /dev/null
+++ b/modules/upnp/upnp_miniupnp.cpp
@@ -0,0 +1,336 @@
+/**************************************************************************/
+/* upnp_miniupnp.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* REDOT ENGINE */
+/* https://redotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2024-present Redot Engine contributors */
+/* (see REDOT_AUTHORS.md) */
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef WEB_ENABLED
+
+#include "upnp_miniupnp.h"
+
+#include "upnp_device_miniupnp.h"
+
+#include <miniwget.h>
+#include <upnpcommands.h>
+
+#include <stdlib.h>
+
+void UPNPMiniUPNP::make_default() {
+ UPNP::_create = UPNPMiniUPNP::_create;
+}
+
+bool UPNPMiniUPNP::is_common_device(const String &dev) const {
+ return dev.is_empty() ||
+ dev.contains("InternetGatewayDevice") ||
+ dev.contains("WANIPConnection") ||
+ dev.contains("WANPPPConnection") ||
+ dev.contains("rootdevice");
+}
+
+int UPNPMiniUPNP::discover(int timeout, int ttl, const String &device_filter) {
+ ERR_FAIL_COND_V_MSG(timeout < 0, UPNP_RESULT_INVALID_PARAM, "The response's wait time can't be negative.");
+ ERR_FAIL_COND_V_MSG(ttl < 0 || ttl > 255, UPNP_RESULT_INVALID_PARAM, "The time-to-live must be set between 0 and 255 (inclusive).");
+
+ devices.clear();
+
+ int error = 0;
+ struct UPNPDev *devlist;
+
+ CharString cs = discover_multicast_if.utf8();
+ const char *m_if = cs.length() ? cs.get_data() : nullptr;
+ if (is_common_device(device_filter)) {
+ devlist = upnpDiscover(timeout, m_if, nullptr, discover_local_port, discover_ipv6, ttl, &error);
+ } else {
+ devlist = upnpDiscoverAll(timeout, m_if, nullptr, discover_local_port, discover_ipv6, ttl, &error);
+ }
+
+ if (error != UPNPDISCOVER_SUCCESS) {
+ switch (error) {
+ case UPNPDISCOVER_SOCKET_ERROR:
+ return UPNP_RESULT_SOCKET_ERROR;
+ case UPNPDISCOVER_MEMORY_ERROR:
+ return UPNP_RESULT_MEM_ALLOC_ERROR;
+ default:
+ return UPNP_RESULT_UNKNOWN_ERROR;
+ }
+ }
+
+ if (!devlist) {
+ return UPNP_RESULT_NO_DEVICES;
+ }
+
+ struct UPNPDev *dev = devlist;
+
+ while (dev) {
+ if (device_filter.is_empty() || strstr(dev->st, device_filter.utf8().get_data())) {
+ add_device_to_list(dev, devlist);
+ }
+
+ dev = dev->pNext;
+ }
+
+ freeUPNPDevlist(devlist);
+
+ return UPNP_RESULT_SUCCESS;
+}
+
+void UPNPMiniUPNP::add_device_to_list(UPNPDev *dev, UPNPDev *devlist) {
+ Ref<UPNPDeviceMiniUPNP> new_device;
+ new_device.instantiate();
+
+ new_device->set_description_url(dev->descURL);
+ new_device->set_service_type(dev->st);
+
+ parse_igd(new_device, devlist);
+
+ devices.push_back(new_device);
+}
+
+char *UPNPMiniUPNP::load_description(const String &url, int *size, int *status_code) const {
+ return (char *)miniwget(url.utf8().get_data(), size, 0, status_code);
+}
+
+void UPNPMiniUPNP::parse_igd(Ref<UPNPDevice> dev, UPNPDev *devlist) {
+ int size = 0;
+ int status_code = -1;
+ char *xml = load_description(dev->get_description_url(), &size, &status_code);
+
+ if (status_code != 200) {
+ dev->set_igd_status(UPNPDevice::IGD_STATUS_HTTP_ERROR);
+ return;
+ }
+
+ if (!xml || size < 1) {
+ dev->set_igd_status(UPNPDevice::IGD_STATUS_HTTP_EMPTY);
+ return;
+ }
+
+ struct UPNPUrls urls = {};
+ struct IGDdatas data;
+
+ parserootdesc(xml, size, &data);
+ free(xml);
+ xml = nullptr;
+
+ GetUPNPUrls(&urls, &data, dev->get_description_url().utf8().get_data(), 0);
+
+ char addr[16];
+#if MINIUPNPC_API_VERSION >= 18
+ int i = UPNP_GetValidIGD(devlist, &urls, &data, (char *)&addr, 16, nullptr, 0);
+#else
+ int i = UPNP_GetValidIGD(devlist, &urls, &data, (char *)&addr, 16);
+#endif
+
+ if (i != 1) {
+ FreeUPNPUrls(&urls);
+
+ switch (i) {
+ case 0:
+ dev->set_igd_status(UPNPDevice::IGD_STATUS_NO_IGD);
+ return;
+ case 2:
+ dev->set_igd_status(UPNPDevice::IGD_STATUS_DISCONNECTED);
+ return;
+ case 3:
+ dev->set_igd_status(UPNPDevice::IGD_STATUS_UNKNOWN_DEVICE);
+ return;
+ default:
+ dev->set_igd_status(UPNPDevice::IGD_STATUS_UNKNOWN_ERROR);
+ return;
+ }
+ }
+
+ if (urls.controlURL[0] == '\0') {
+ FreeUPNPUrls(&urls);
+ dev->set_igd_status(UPNPDevice::IGD_STATUS_INVALID_CONTROL);
+ return;
+ }
+
+ dev->set_igd_control_url(urls.controlURL);
+ dev->set_igd_service_type(data.first.servicetype);
+ dev->set_igd_our_addr(addr);
+ dev->set_igd_status(UPNPDevice::IGD_STATUS_OK);
+
+ FreeUPNPUrls(&urls);
+}
+
+int UPNPMiniUPNP::upnp_result(int in) {
+ switch (in) {
+ case UPNPCOMMAND_SUCCESS:
+ return UPNP_RESULT_SUCCESS;
+ case UPNPCOMMAND_UNKNOWN_ERROR:
+ return UPNP_RESULT_UNKNOWN_ERROR;
+ case UPNPCOMMAND_INVALID_ARGS:
+ return UPNP_RESULT_INVALID_ARGS;
+ case UPNPCOMMAND_HTTP_ERROR:
+ return UPNP_RESULT_HTTP_ERROR;
+ case UPNPCOMMAND_INVALID_RESPONSE:
+ return UPNP_RESULT_INVALID_RESPONSE;
+ case UPNPCOMMAND_MEM_ALLOC_ERROR:
+ return UPNP_RESULT_MEM_ALLOC_ERROR;
+
+ case 402:
+ return UPNP_RESULT_INVALID_ARGS;
+ case 403:
+ return UPNP_RESULT_NOT_AUTHORIZED;
+ case 501:
+ return UPNP_RESULT_ACTION_FAILED;
+ case 606:
+ return UPNP_RESULT_NOT_AUTHORIZED;
+ case 714:
+ return UPNP_RESULT_NO_SUCH_ENTRY_IN_ARRAY;
+ case 715:
+ return UPNP_RESULT_SRC_IP_WILDCARD_NOT_PERMITTED;
+ case 716:
+ return UPNP_RESULT_EXT_PORT_WILDCARD_NOT_PERMITTED;
+ case 718:
+ return UPNP_RESULT_CONFLICT_WITH_OTHER_MAPPING;
+ case 724:
+ return UPNP_RESULT_SAME_PORT_VALUES_REQUIRED;
+ case 725:
+ return UPNP_RESULT_ONLY_PERMANENT_LEASE_SUPPORTED;
+ case 726:
+ return UPNP_RESULT_REMOTE_HOST_MUST_BE_WILDCARD;
+ case 727:
+ return UPNP_RESULT_EXT_PORT_MUST_BE_WILDCARD;
+ case 728:
+ return UPNP_RESULT_NO_PORT_MAPS_AVAILABLE;
+ case 729:
+ return UPNP_RESULT_CONFLICT_WITH_OTHER_MECHANISM;
+ case 732:
+ return UPNP_RESULT_INT_PORT_WILDCARD_NOT_PERMITTED;
+ case 733:
+ return UPNP_RESULT_INCONSISTENT_PARAMETERS;
+ }
+
+ return UPNP_RESULT_UNKNOWN_ERROR;
+}
+
+int UPNPMiniUPNP::get_device_count() const {
+ return devices.size();
+}
+
+Ref<UPNPDevice> UPNPMiniUPNP::get_device(int index) const {
+ ERR_FAIL_INDEX_V(index, devices.size(), nullptr);
+
+ return devices.get(index);
+}
+
+void UPNPMiniUPNP::add_device(Ref<UPNPDevice> device) {
+ ERR_FAIL_COND(device.is_null());
+
+ devices.push_back(device);
+}
+
+void UPNPMiniUPNP::set_device(int index, Ref<UPNPDevice> device) {
+ ERR_FAIL_INDEX(index, devices.size());
+ ERR_FAIL_COND(device.is_null());
+
+ devices.set(index, device);
+}
+
+void UPNPMiniUPNP::remove_device(int index) {
+ ERR_FAIL_INDEX(index, devices.size());
+
+ devices.remove_at(index);
+}
+
+void UPNPMiniUPNP::clear_devices() {
+ devices.clear();
+}
+
+Ref<UPNPDevice> UPNPMiniUPNP::get_gateway() const {
+ ERR_FAIL_COND_V_MSG(devices.is_empty(), nullptr, "Couldn't find any UPNPDevices.");
+
+ for (int i = 0; i < devices.size(); i++) {
+ Ref<UPNPDevice> dev = get_device(i);
+
+ if (dev.is_valid() && dev->is_valid_gateway()) {
+ return dev;
+ }
+ }
+
+ return nullptr;
+}
+
+void UPNPMiniUPNP::set_discover_multicast_if(const String &m_if) {
+ discover_multicast_if = m_if;
+}
+
+String UPNPMiniUPNP::get_discover_multicast_if() const {
+ return discover_multicast_if;
+}
+
+void UPNPMiniUPNP::set_discover_local_port(int port) {
+ discover_local_port = port;
+}
+
+int UPNPMiniUPNP::get_discover_local_port() const {
+ return discover_local_port;
+}
+
+void UPNPMiniUPNP::set_discover_ipv6(bool ipv6) {
+ discover_ipv6 = ipv6;
+}
+
+bool UPNPMiniUPNP::is_discover_ipv6() const {
+ return discover_ipv6;
+}
+
+String UPNPMiniUPNP::query_external_address() const {
+ Ref<UPNPDevice> dev = get_gateway();
+
+ if (dev.is_null()) {
+ return "";
+ }
+
+ return dev->query_external_address();
+}
+
+int UPNPMiniUPNP::add_port_mapping(int port, int port_internal, String desc, String proto, int duration) const {
+ Ref<UPNPDevice> dev = get_gateway();
+
+ if (dev.is_null()) {
+ return UPNP_RESULT_NO_GATEWAY;
+ }
+
+ return dev->add_port_mapping(port, port_internal, desc, proto, duration);
+}
+
+int UPNPMiniUPNP::delete_port_mapping(int port, String proto) const {
+ Ref<UPNPDevice> dev = get_gateway();
+
+ if (dev.is_null()) {
+ return UPNP_RESULT_NO_GATEWAY;
+ }
+
+ return dev->delete_port_mapping(port, proto);
+}
+
+#endif // WEB_ENABLED
diff --git a/modules/upnp/upnp_miniupnp.h b/modules/upnp/upnp_miniupnp.h
new file mode 100644
index 0000000000..c9ca153d6b
--- /dev/null
+++ b/modules/upnp/upnp_miniupnp.h
@@ -0,0 +1,95 @@
+/**************************************************************************/
+/* upnp_miniupnp.h */
+/**************************************************************************/
+/* This file is part of: */
+/* REDOT ENGINE */
+/* https://redotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2024-present Redot Engine contributors */
+/* (see REDOT_AUTHORS.md) */
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef UPNP_MINIUPNP_H
+#define UPNP_MINIUPNP_H
+
+#ifndef WEB_ENABLED
+
+#include "upnp.h"
+
+#include <miniupnpc.h>
+
+class UPNPMiniUPNP : public UPNP {
+ GDCLASS(UPNPMiniUPNP, UPNP);
+
+private:
+ static UPNP *_create(bool p_notify_postinitialize) { return static_cast<UPNP *>(ClassDB::creator<UPNPMiniUPNP>(p_notify_postinitialize)); }
+
+ String discover_multicast_if = "";
+ int discover_local_port = 0;
+ bool discover_ipv6 = false;
+
+ Vector<Ref<UPNPDevice>> devices;
+
+ bool is_common_device(const String &dev) const;
+ void add_device_to_list(UPNPDev *dev, UPNPDev *devlist);
+ void parse_igd(Ref<UPNPDevice> dev, UPNPDev *devlist);
+ char *load_description(const String &url, int *size, int *status_code) const;
+
+public:
+ static void make_default();
+
+ static int upnp_result(int in);
+
+ virtual int get_device_count() const override;
+ virtual Ref<UPNPDevice> get_device(int index) const override;
+ virtual void add_device(Ref<UPNPDevice> device) override;
+ virtual void set_device(int index, Ref<UPNPDevice> device) override;
+ virtual void remove_device(int index) override;
+ virtual void clear_devices() override;
+
+ virtual Ref<UPNPDevice> get_gateway() const override;
+
+ virtual int discover(int timeout = 2000, int ttl = 2, const String &device_filter = "InternetGatewayDevice") override;
+
+ virtual String query_external_address() const override;
+
+ virtual int add_port_mapping(int port, int port_internal = 0, String desc = "", String proto = "UDP", int duration = 0) const override;
+ virtual int delete_port_mapping(int port, String proto = "UDP") const override;
+
+ virtual void set_discover_multicast_if(const String &m_if) override;
+ virtual String get_discover_multicast_if() const override;
+
+ virtual void set_discover_local_port(int port) override;
+ virtual int get_discover_local_port() const override;
+
+ virtual void set_discover_ipv6(bool ipv6) override;
+ virtual bool is_discover_ipv6() const override;
+
+ UPNPMiniUPNP() {}
+ virtual ~UPNPMiniUPNP() {}
+};
+
+#endif // WEB_ENABLED
+
+#endif // UPNP_MINIUPNP_H