summaryrefslogtreecommitdiffstats
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml2
-rw-r--r--modules/gdscript/gdscript_parser.cpp110
-rw-r--r--modules/gdscript/tests/scripts/parser/features/export_variable.gd6
-rw-r--r--modules/gdscript/tests/scripts/parser/features/export_variable.notest.gd2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/export_variable.out6
-rw-r--r--modules/gdscript/tests/scripts/parser/features/export_variable_global.notest.gd2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/export_variable_unnamed.notest.gd1
-rw-r--r--modules/navigation/nav_region.cpp4
8 files changed, 74 insertions, 59 deletions
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index 1909ca5ab5..6e7ac0dec9 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -314,7 +314,7 @@
@export var image_array: Array[Image]
@export var node_array: Array[Node]
[/codeblock]
- [b]Note:[/b] Custom resources and nodes must be registered as global classes using [code]class_name[/code].
+ [b]Note:[/b] Custom resources and nodes should be registered as global classes using [code]class_name[/code], since the Inspector currently only supports global classes. Otherwise, a less specific type will be exported instead.
[b]Note:[/b] Node export is only supported in [Node]-derived classes and has a number of other limitations.
</description>
</annotation>
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index f1a35c84b7..d0948e4831 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -4160,6 +4160,64 @@ static String _get_annotation_error_string(const StringName &p_annotation_name,
return vformat(R"("%s" annotation requires a variable of type %s, but type "%s" was given instead.)", p_annotation_name, string, p_provided_type.to_string());
}
+static StringName _find_narrowest_native_or_global_class(const GDScriptParser::DataType &p_type) {
+ switch (p_type.kind) {
+ case GDScriptParser::DataType::NATIVE: {
+ if (p_type.is_meta_type) {
+ return Object::get_class_static(); // `GDScriptNativeClass` is not an exposed class.
+ }
+ return p_type.native_type;
+ } break;
+ case GDScriptParser::DataType::SCRIPT: {
+ Ref<Script> script;
+ if (p_type.script_type.is_valid()) {
+ script = p_type.script_type;
+ } else {
+ script = ResourceLoader::load(p_type.script_path, SNAME("Script"));
+ }
+
+ if (p_type.is_meta_type) {
+ return script.is_valid() ? script->get_class() : Script::get_class_static();
+ }
+ if (script.is_null()) {
+ return p_type.native_type;
+ }
+ if (script->get_global_name() != StringName()) {
+ return script->get_global_name();
+ }
+
+ Ref<Script> base_script = script->get_base_script();
+ if (base_script.is_null()) {
+ return script->get_instance_base_type();
+ }
+
+ GDScriptParser::DataType base_type;
+ base_type.kind = GDScriptParser::DataType::SCRIPT;
+ base_type.builtin_type = Variant::OBJECT;
+ base_type.native_type = base_script->get_instance_base_type();
+ base_type.script_type = base_script;
+ base_type.script_path = base_script->get_path();
+
+ return _find_narrowest_native_or_global_class(base_type);
+ } break;
+ case GDScriptParser::DataType::CLASS: {
+ if (p_type.is_meta_type) {
+ return GDScript::get_class_static();
+ }
+ if (p_type.class_type == nullptr) {
+ return p_type.native_type;
+ }
+ if (p_type.class_type->get_global_name() != StringName()) {
+ return p_type.class_type->get_global_name();
+ }
+ return _find_narrowest_native_or_global_class(p_type.class_type->base_type);
+ } break;
+ default: {
+ ERR_FAIL_V(StringName());
+ } break;
+ }
+}
+
template <PropertyHint t_hint, Variant::Type t_type>
bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class) {
ERR_FAIL_COND_V_MSG(p_target->type != Node::VARIABLE, false, vformat(R"("%s" annotation can only be applied to variables.)", p_annotation->name));
@@ -4302,57 +4360,9 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
variable->export_info.hint_string = String();
break;
case GDScriptParser::DataType::NATIVE:
- if (ClassDB::is_parent_class(export_type.native_type, SNAME("Resource"))) {
- variable->export_info.type = Variant::OBJECT;
- variable->export_info.hint = PROPERTY_HINT_RESOURCE_TYPE;
- variable->export_info.hint_string = export_type.native_type;
- } else if (ClassDB::is_parent_class(export_type.native_type, SNAME("Node"))) {
- variable->export_info.type = Variant::OBJECT;
- variable->export_info.hint = PROPERTY_HINT_NODE_TYPE;
- variable->export_info.hint_string = export_type.native_type;
- } else {
- push_error(R"(Export type can only be built-in, a resource, a node, or an enum.)", p_annotation);
- return false;
- }
- break;
+ case GDScriptParser::DataType::SCRIPT:
case GDScriptParser::DataType::CLASS: {
- StringName class_name;
- if (export_type.class_type) {
- class_name = export_type.class_type->get_global_name();
- }
- if (class_name == StringName()) {
- push_error(R"(Script export type must be a global class.)", p_annotation);
- return false;
- }
- if (ClassDB::is_parent_class(export_type.native_type, SNAME("Resource"))) {
- variable->export_info.type = Variant::OBJECT;
- variable->export_info.hint = PROPERTY_HINT_RESOURCE_TYPE;
- variable->export_info.hint_string = class_name;
- } else if (ClassDB::is_parent_class(export_type.native_type, SNAME("Node"))) {
- variable->export_info.type = Variant::OBJECT;
- variable->export_info.hint = PROPERTY_HINT_NODE_TYPE;
- variable->export_info.hint_string = class_name;
- } else {
- push_error(R"(Export type can only be built-in, a resource, a node, or an enum.)", p_annotation);
- return false;
- }
- } break;
-
- case GDScriptParser::DataType::SCRIPT: {
- StringName class_name;
- if (export_type.script_type.is_valid()) {
- class_name = export_type.script_type->get_global_name();
- }
- if (class_name == StringName()) {
- Ref<Script> script = ResourceLoader::load(export_type.script_path, SNAME("Script"));
- if (script.is_valid()) {
- class_name = script->get_global_name();
- }
- }
- if (class_name == StringName()) {
- push_error(R"(Script export type must be a global class.)", p_annotation);
- return false;
- }
+ const StringName class_name = _find_narrowest_native_or_global_class(export_type);
if (ClassDB::is_parent_class(export_type.native_type, SNAME("Resource"))) {
variable->export_info.type = Variant::OBJECT;
variable->export_info.hint = PROPERTY_HINT_RESOURCE_TYPE;
diff --git a/modules/gdscript/tests/scripts/parser/features/export_variable.gd b/modules/gdscript/tests/scripts/parser/features/export_variable.gd
index 483e6cab0d..8bcb2bcb9a 100644
--- a/modules/gdscript/tests/scripts/parser/features/export_variable.gd
+++ b/modules/gdscript/tests/scripts/parser/features/export_variable.gd
@@ -2,7 +2,8 @@ class_name ExportVariableTest
extends Node
const Utils = preload("../../utils.notest.gd")
-const PreloadedScript = preload("./export_variable.notest.gd")
+const PreloadedGlobalClass = preload("./export_variable_global.notest.gd")
+const PreloadedUnnamedClass = preload("./export_variable_unnamed.notest.gd")
# Built-in types.
@export var test_weak_int = 1
@@ -24,7 +25,8 @@ const PreloadedScript = preload("./export_variable.notest.gd")
# Global custom classes.
@export var test_global_class: ExportVariableTest
-@export var test_preloaded_script: PreloadedScript
+@export var test_preloaded_global_class: PreloadedGlobalClass
+@export var test_preloaded_unnamed_class: PreloadedUnnamedClass # GH-93168
# Arrays.
@export var test_array: Array
diff --git a/modules/gdscript/tests/scripts/parser/features/export_variable.notest.gd b/modules/gdscript/tests/scripts/parser/features/export_variable.notest.gd
deleted file mode 100644
index 6d064351c1..0000000000
--- a/modules/gdscript/tests/scripts/parser/features/export_variable.notest.gd
+++ /dev/null
@@ -1,2 +0,0 @@
-class_name ExportPreloadedClassTest
-extends Node
diff --git a/modules/gdscript/tests/scripts/parser/features/export_variable.out b/modules/gdscript/tests/scripts/parser/features/export_variable.out
index bb094e14b4..d10462bb8d 100644
--- a/modules/gdscript/tests/scripts/parser/features/export_variable.out
+++ b/modules/gdscript/tests/scripts/parser/features/export_variable.out
@@ -25,8 +25,10 @@ var test_timer: Timer = null
hint=NODE_TYPE hint_string="Timer" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"Timer"
var test_global_class: ExportVariableTest = null
hint=NODE_TYPE hint_string="ExportVariableTest" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"ExportVariableTest"
-var test_preloaded_script: ExportPreloadedClassTest = null
- hint=NODE_TYPE hint_string="ExportPreloadedClassTest" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"ExportPreloadedClassTest"
+var test_preloaded_global_class: ExportVariableTestGlobalClass = null
+ hint=NODE_TYPE hint_string="ExportVariableTestGlobalClass" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"ExportVariableTestGlobalClass"
+var test_preloaded_unnamed_class: Node2D = null
+ hint=NODE_TYPE hint_string="Node2D" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"Node2D"
var test_array: Array = []
hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&""
var test_array_bool: Array = Array[bool]([])
diff --git a/modules/gdscript/tests/scripts/parser/features/export_variable_global.notest.gd b/modules/gdscript/tests/scripts/parser/features/export_variable_global.notest.gd
new file mode 100644
index 0000000000..caa2ead214
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/export_variable_global.notest.gd
@@ -0,0 +1,2 @@
+class_name ExportVariableTestGlobalClass
+extends Node2D
diff --git a/modules/gdscript/tests/scripts/parser/features/export_variable_unnamed.notest.gd b/modules/gdscript/tests/scripts/parser/features/export_variable_unnamed.notest.gd
new file mode 100644
index 0000000000..e251cf8aee
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/export_variable_unnamed.notest.gd
@@ -0,0 +1 @@
+extends Node2D
diff --git a/modules/navigation/nav_region.cpp b/modules/navigation/nav_region.cpp
index fc1db391ae..c91071a3ab 100644
--- a/modules/navigation/nav_region.cpp
+++ b/modules/navigation/nav_region.cpp
@@ -84,11 +84,11 @@ void NavRegion::set_transform(Transform3D p_transform) {
void NavRegion::set_navigation_mesh(Ref<NavigationMesh> p_navigation_mesh) {
#ifdef DEBUG_ENABLED
- if (map && !Math::is_equal_approx(double(map->get_cell_size()), double(p_navigation_mesh->get_cell_size()))) {
+ if (map && p_navigation_mesh.is_valid() && !Math::is_equal_approx(double(map->get_cell_size()), double(p_navigation_mesh->get_cell_size()))) {
ERR_PRINT_ONCE(vformat("Attempted to update a navigation region with a navigation mesh that uses a `cell_size` of %s while assigned to a navigation map set to a `cell_size` of %s. The cell size for navigation maps can be changed by using the NavigationServer map_set_cell_size() function. The cell size for default navigation maps can also be changed in the ProjectSettings.", double(p_navigation_mesh->get_cell_size()), double(map->get_cell_size())));
}
- if (map && !Math::is_equal_approx(double(map->get_cell_height()), double(p_navigation_mesh->get_cell_height()))) {
+ if (map && p_navigation_mesh.is_valid() && !Math::is_equal_approx(double(map->get_cell_height()), double(p_navigation_mesh->get_cell_height()))) {
ERR_PRINT_ONCE(vformat("Attempted to update a navigation region with a navigation mesh that uses a `cell_height` of %s while assigned to a navigation map set to a `cell_height` of %s. The cell height for navigation maps can be changed by using the NavigationServer map_set_cell_height() function. The cell height for default navigation maps can also be changed in the ProjectSettings.", double(p_navigation_mesh->get_cell_height()), double(map->get_cell_height())));
}
#endif // DEBUG_ENABLED