diff --git a/core/extension/gdextension.cpp b/core/extension/gdextension.cpp index 29225d6d5fe..d6ba7313b9d 100644 --- a/core/extension/gdextension.cpp +++ b/core/extension/gdextension.cpp @@ -862,6 +862,19 @@ String GDExtensionResourceLoader::get_resource_type(const String &p_path) const } #ifdef TOOLS_ENABLED +void GDExtensionResourceLoader::get_classes_used(const String &p_path, HashSet *r_classes) { + Ref gdext = ResourceLoader::load(p_path); + if (gdext.is_null()) { + return; + } + + for (const StringName class_name : gdext->get_classes_used()) { + if (ClassDB::class_exists(class_name)) { + r_classes->insert(class_name); + } + } +} + bool GDExtension::has_library_changed() const { return loader->has_library_changed(); } diff --git a/core/extension/gdextension.h b/core/extension/gdextension.h index 0daf57d6da9..6c875284fb3 100644 --- a/core/extension/gdextension.h +++ b/core/extension/gdextension.h @@ -184,6 +184,9 @@ public: virtual void get_recognized_extensions(List *p_extensions) const override; virtual bool handles_type(const String &p_type) const override; virtual String get_resource_type(const String &p_path) const override; +#ifdef TOOLS_ENABLED + virtual void get_classes_used(const String &p_path, HashSet *r_classes) override; +#endif // TOOLS_ENABLED }; #ifdef TOOLS_ENABLED diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index f089fd345d8..42de02a9e63 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -36,6 +36,7 @@ #include "core/io/missing_resource.h" #include "core/object/script_language.h" #include "core/version.h" +#include "scene/resources/packed_scene.h" //#define print_bl(m_what) print_line(m_what) #define print_bl(m_what) (void)(m_what) @@ -937,11 +938,10 @@ void ResourceLoaderBinary::get_classes_used(Ref p_f, HashSetseek(internal_resources[i].offset); + for (const IntResource &res : internal_resources) { + p_f->seek(res.offset); String t = get_unicode_string(); - ERR_FAIL_COND(p_f->get_error() != OK); - if (t != String()) { + if (!p_f->get_error() && t != String() && ClassDB::class_exists(t)) { p_classes->insert(t); } } @@ -1518,6 +1518,37 @@ void ResourceFormatLoaderBinary::get_classes_used(const String &p_path, HashSet< loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path); loader.res_path = loader.local_path; loader.get_classes_used(f, r_classes); + + // Fetch the nodes inside scene files. + if (loader.type == "PackedScene") { + ERR_FAIL_COND(loader.load() != OK); + + Ref state = Ref(loader.get_resource())->get_state(); + for (int i = 0; i < state->get_node_count(); i++) { + const StringName node_name = state->get_node_type(i); + if (ClassDB::class_exists(node_name)) { + r_classes->insert(node_name); + } + + // Fetch the values of properties in the node. + for (int j = 0; j < state->get_node_property_count(i); j++) { + const Variant var = state->get_node_property_value(i, j); + if (var.get_type() != Variant::OBJECT) { + continue; + } + + const Object *obj = var.get_validated_object(); + if (obj == nullptr) { + continue; + } + + const StringName obj_name = obj->get_class_name(); + if (ClassDB::class_exists(obj_name)) { + r_classes->insert(obj_name); + } + } + } + } } String ResourceFormatLoaderBinary::get_resource_type(const String &p_path) const { diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp index a13c76a0ed8..fc36e5e131b 100644 --- a/core/io/resource_importer.cpp +++ b/core/io/resource_importer.cpp @@ -434,6 +434,7 @@ Variant ResourceFormatImporter::get_resource_metadata(const String &p_path) cons return pat.metadata; } + void ResourceFormatImporter::get_classes_used(const String &p_path, HashSet *r_classes) { PathAndType pat; Error err = _get_path_and_type(p_path, pat, false); @@ -456,6 +457,18 @@ void ResourceFormatImporter::get_dependencies(const String &p_path, List ResourceLoader::get_dependencies(pat.path, p_dependencies, p_add_types); } +void ResourceFormatImporter::get_build_dependencies(const String &p_path, HashSet *r_dependencies) { + if (!exists(p_path)) { + return; + } + + List> valid_importers; + get_importers_for_file(p_path, &valid_importers); + for (Ref importer : valid_importers) { + importer->get_build_dependencies(p_path, r_dependencies); + } +} + Ref ResourceFormatImporter::get_importer_by_name(const String &p_name) const { for (int i = 0; i < importers.size(); i++) { if (importers[i]->get_importer_name() == p_name) { @@ -555,9 +568,21 @@ ResourceFormatImporter::ResourceFormatImporter() { ////////////// +void ResourceImporter::get_build_dependencies(const String &p_path, HashSet *r_dependencies) { + Vector ret; + if (GDVIRTUAL_CALL(_get_build_dependencies, p_path, ret)) { + for (int i = 0; i < ret.size(); i++) { + r_dependencies->insert(ret[i]); + } + return; + } +} + void ResourceImporter::_bind_methods() { BIND_ENUM_CONSTANT(IMPORT_ORDER_DEFAULT); BIND_ENUM_CONSTANT(IMPORT_ORDER_SCENE); + + GDVIRTUAL_BIND(_get_build_dependencies, "path"); } ///// diff --git a/core/io/resource_importer.h b/core/io/resource_importer.h index f8be5f505d8..4ab2b0f951d 100644 --- a/core/io/resource_importer.h +++ b/core/io/resource_importer.h @@ -78,6 +78,8 @@ public: virtual void get_classes_used(const String &p_path, HashSet *r_classes) override; virtual bool exists(const String &p_path) const override; + void get_build_dependencies(const String &p_path, HashSet *r_dependencies); + virtual int get_import_order(const String &p_path) const override; Error get_import_order_threads_and_importer(const String &p_path, int &r_order, bool &r_can_threads, String &r_importer) const; @@ -106,6 +108,8 @@ class ResourceImporter : public RefCounted { GDCLASS(ResourceImporter, RefCounted); protected: + GDVIRTUAL1RC(Vector, _get_build_dependencies, String) + static void _bind_methods(); public: @@ -155,6 +159,8 @@ public: virtual Error import_group_file(const String &p_group_file, const HashMap> &p_source_file_options, const HashMap &p_base_paths) { return ERR_UNAVAILABLE; } virtual bool are_import_settings_valid(const String &p_path, const Dictionary &p_meta) const { return true; } virtual String get_import_settings_string() const { return String(); } + + virtual void get_build_dependencies(const String &p_path, HashSet *r_build_dependencies); }; VARIANT_ENUM_CAST(ResourceImporter::ImportOrder); diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp index c84c903cc73..e8c82aae7af 100644 --- a/core/object/class_db.cpp +++ b/core/object/class_db.cpp @@ -2152,6 +2152,30 @@ bool ClassDB::is_class_runtime(const StringName &p_class) { return ti->is_runtime; } +#ifdef TOOLS_ENABLED +void ClassDB::add_class_dependency(const StringName &p_class, const StringName &p_dependency) { + Locker::Lock lock(Locker::STATE_WRITE); + + ERR_FAIL_COND_MSG(!classes.has(p_class), vformat("Request for nonexistent class '%s'.", p_class)); + if (classes[p_class].dependency_list.find(p_dependency)) { + ERR_FAIL(); + } + + classes[p_class].dependency_list.push_back(p_dependency); +} + +void ClassDB::get_class_dependencies(const StringName &p_class, List *r_rependencies) { + Locker::Lock lock(Locker::STATE_READ); + + ClassInfo *ti = classes.getptr(p_class); + ERR_FAIL_NULL_MSG(ti, vformat("Cannot get class '%s'.", String(p_class))); + + for (const StringName &dep : ti->dependency_list) { + r_rependencies->push_back(dep); + } +} +#endif // TOOLS_ENABLED + void ClassDB::add_resource_base_extension(const StringName &p_extension, const StringName &p_class) { if (resource_base_extensions.has(p_extension)) { return; diff --git a/core/object/class_db.h b/core/object/class_db.h index 06db161dffd..f6c377b247e 100644 --- a/core/object/class_db.h +++ b/core/object/class_db.h @@ -118,6 +118,7 @@ public: HashMap signal_map; List property_list; HashMap property_map; + #ifdef DEBUG_ENABLED List constant_order; List method_order; @@ -127,6 +128,11 @@ public: HashMap> method_error_values; HashMap> linked_properties; #endif // DEBUG_ENABLED + +#ifdef TOOLS_ENABLED + List dependency_list; +#endif + HashMap property_setget; HashMap> virtual_methods_compat; @@ -499,6 +505,11 @@ public: static bool is_class_reloadable(const StringName &p_class); static bool is_class_runtime(const StringName &p_class); +#ifdef TOOLS_ENABLED + static void add_class_dependency(const StringName &p_class, const StringName &p_dependency); + static void get_class_dependencies(const StringName &p_class, List *r_rependencies); +#endif + static void add_resource_base_extension(const StringName &p_extension, const StringName &p_class); static void get_resource_base_extensions(List *p_extensions); static void get_extensions_for_type(const StringName &p_class, List *p_extensions); diff --git a/core/object/object.h b/core/object/object.h index 50c6950f65d..4d3d340ca1a 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -147,6 +147,12 @@ enum PropertyUsageFlags { #define ADD_SUBGROUP_INDENT(m_name, m_prefix, m_depth) ::ClassDB::add_property_subgroup(get_class_static(), m_name, m_prefix, m_depth) #define ADD_LINKED_PROPERTY(m_property, m_linked_property) ::ClassDB::add_linked_property(get_class_static(), m_property, m_linked_property) +#ifdef TOOLS_ENABLED +#define ADD_CLASS_DEPENDENCY(m_class) ::ClassDB::add_class_dependency(get_class_static(), m_class) +#else +#define ADD_CLASS_DEPENDENCY(m_class) +#endif + #define ADD_ARRAY_COUNT(m_label, m_count_property, m_count_property_setter, m_count_property_getter, m_prefix) ClassDB::add_property_array_count(get_class_static(), m_label, m_count_property, StringName(m_count_property_setter), StringName(m_count_property_getter), m_prefix) #define ADD_ARRAY_COUNT_WITH_USAGE_FLAGS(m_label, m_count_property, m_count_property_setter, m_count_property_getter, m_prefix, m_property_usage_flags) ClassDB::add_property_array_count(get_class_static(), m_label, m_count_property, StringName(m_count_property_setter), StringName(m_count_property_getter), m_prefix, m_property_usage_flags) #define ADD_ARRAY(m_array_path, m_prefix) ClassDB::add_property_array(get_class_static(), m_array_path, m_prefix) @@ -979,7 +985,6 @@ public: bool editor_is_section_unfolded(const String &p_section); const HashSet &editor_get_section_folding() const { return editor_section_folding; } void editor_clear_section_folding() { editor_section_folding.clear(); } - #endif // Used by script languages to store binding data. diff --git a/doc/classes/ResourceImporter.xml b/doc/classes/ResourceImporter.xml index c34b27913f6..7797db51c32 100644 --- a/doc/classes/ResourceImporter.xml +++ b/doc/classes/ResourceImporter.xml @@ -9,6 +9,25 @@ $DOCS_URL/tutorials/plugins/editor/import_plugins.html + + + + + + Called when the engine compilation profile editor wants to check what build options an imported resource needs. For example, [ResourceImporterDynamicFont] has a property called [member ResourceImporterDynamicFont.multichannel_signed_distance_field], that depends on the engine to be build with the "msdfgen" module. If that resource happened to be a custom one, it would be handled like this: + [codeblock] + func _get_build_dependencies(path): + var resource = load(path) + var dependencies = PackedStringArray() + + if resource.multichannel_signed_distance_field: + dependencies.push_back("module_msdfgen_enabled") + + return dependencies + [/codeblock] + + + The default import order. diff --git a/editor/editor_build_profile.cpp b/editor/editor_build_profile.cpp index 426934e0001..70dd490a005 100644 --- a/editor/editor_build_profile.cpp +++ b/editor/editor_build_profile.cpp @@ -30,6 +30,7 @@ #include "editor_build_profile.h" +#include "core/config/project_settings.h" #include "core/io/json.h" #include "editor/editor_file_system.h" #include "editor/editor_node.h" @@ -41,36 +42,60 @@ #include "scene/gui/line_edit.h" #include "scene/gui/separator.h" +#include "modules/modules_enabled.gen.h" // For mono. + const char *EditorBuildProfile::build_option_identifiers[BUILD_OPTION_MAX] = { // This maps to SCons build options. "disable_3d", - "disable_2d_physics", - "disable_3d_physics", - "disable_navigation", + "disable_navigation_2d", + "disable_navigation_3d", "disable_xr", - "rendering_device", // FIXME: there's no scons option to disable rendering device - "opengl3", + "module_openxr_enabled", + "wayland", + "x11", + "rendering_device", // FIXME: There's no scons option to disable rendering device. + "forward_plus_renderer", + "forward_mobile_renderer", "vulkan", + "d3d12", + "metal", + "opengl3", + "disable_physics_2d", + "module_godot_physics_2d_enabled", + "disable_physics_3d", + "module_godot_physics_3d_enabled", + "module_jolt_physics_enabled", "module_text_server_fb_enabled", "module_text_server_adv_enabled", "module_freetype_enabled", "brotli", "graphite", - "module_msdfgen_enabled" + "module_msdfgen_enabled", }; const bool EditorBuildProfile::build_option_disabled_by_default[BUILD_OPTION_MAX] = { // This maps to SCons build options. false, // 3D - false, // PHYSICS_2D - false, // PHYSICS_3D - false, // NAVIGATION + false, // NAVIGATION_2D + false, // NAVIGATION_3D false, // XR + false, // OPENXR + false, // WAYLAND + false, // X11 false, // RENDERING_DEVICE - false, // OPENGL + false, // FORWARD_RENDERER + false, // MOBILE_RENDERER false, // VULKAN + false, // D3D12 + false, // METAL + false, // OPENGL + false, // PHYSICS_2D + false, // PHYSICS_GODOT_2D + false, // PHYSICS_3D + false, // PHYSICS_GODOT_3D + false, // PHYSICS_JOLT true, // TEXT_SERVER_FALLBACK - false, // TEXT_SERVER_COMPLEX + false, // TEXT_SERVER_ADVANCED false, // DYNAMIC_FONTS false, // WOFF2_FONTS false, // GRAPHITE_FONTS @@ -80,38 +105,215 @@ const bool EditorBuildProfile::build_option_disabled_by_default[BUILD_OPTION_MAX const bool EditorBuildProfile::build_option_disable_values[BUILD_OPTION_MAX] = { // This maps to SCons build options. true, // 3D - true, // PHYSICS_2D - true, // PHYSICS_3D - true, // NAVIGATION + true, // NAVIGATION_2D + true, // NAVIGATION_3D true, // XR + false, // OPENXR + false, // WAYLAND + false, // X11 false, // RENDERING_DEVICE - false, // OPENGL + false, // FORWARD_RENDERER + false, // MOBILE_RENDERER false, // VULKAN + false, // D3D12 + false, // METAL + false, // OPENGL + true, // PHYSICS_2D + false, // PHYSICS_GODOT_2D + true, // PHYSICS_3D + false, // PHYSICS_GODOT_3D + false, // PHYSICS_JOLT false, // TEXT_SERVER_FALLBACK - false, // TEXT_SERVER_COMPLEX + false, // TEXT_SERVER_ADVANCED false, // DYNAMIC_FONTS false, // WOFF2_FONTS false, // GRAPHITE_FONTS false, // MSDFGEN }; +// Options that require some resource explicitly asking for them when detecting from the project. +const bool EditorBuildProfile::build_option_explicit_use[BUILD_OPTION_MAX] = { + false, // 3D + false, // NAVIGATION_2D + false, // NAVIGATION_3D + false, // XR + false, // OPENXR + false, // WAYLAND + false, // X11 + false, // RENDERING_DEVICE + false, // FORWARD_RENDERER + false, // MOBILE_RENDERER + false, // VULKAN + false, // D3D12 + false, // METAL + false, // OPENGL + false, // PHYSICS_2D + false, // PHYSICS_GODOT_2D + false, // PHYSICS_3D + false, // PHYSICS_GODOT_3D + false, // PHYSICS_JOLT + false, // TEXT_SERVER_FALLBACK + false, // TEXT_SERVER_ADVANCED + false, // DYNAMIC_FONTS + false, // WOFF2_FONTS + false, // GRAPHITE_FONTS + true, // MSDFGEN +}; + const EditorBuildProfile::BuildOptionCategory EditorBuildProfile::build_option_category[BUILD_OPTION_MAX] = { BUILD_OPTION_CATEGORY_GENERAL, // 3D - BUILD_OPTION_CATEGORY_GENERAL, // PHYSICS_2D - BUILD_OPTION_CATEGORY_GENERAL, // PHYSICS_3D - BUILD_OPTION_CATEGORY_GENERAL, // NAVIGATION + BUILD_OPTION_CATEGORY_GENERAL, // NAVIGATION_2D + BUILD_OPTION_CATEGORY_GENERAL, // NAVIGATION_3D BUILD_OPTION_CATEGORY_GENERAL, // XR - BUILD_OPTION_CATEGORY_GENERAL, // RENDERING_DEVICE - BUILD_OPTION_CATEGORY_GENERAL, // OPENGL - BUILD_OPTION_CATEGORY_GENERAL, // VULKAN + BUILD_OPTION_CATEGORY_GENERAL, // OPENXR + BUILD_OPTION_CATEGORY_GENERAL, // WAYLAND + BUILD_OPTION_CATEGORY_GENERAL, // X11 + BUILD_OPTION_CATEGORY_GRAPHICS, // RENDERING_DEVICE + BUILD_OPTION_CATEGORY_GRAPHICS, // FORWARD_RENDERER + BUILD_OPTION_CATEGORY_GRAPHICS, // MOBILE_RENDERER + BUILD_OPTION_CATEGORY_GRAPHICS, // VULKAN + BUILD_OPTION_CATEGORY_GRAPHICS, // D3D12 + BUILD_OPTION_CATEGORY_GRAPHICS, // METAL + BUILD_OPTION_CATEGORY_GRAPHICS, // OPENGL + BUILD_OPTION_CATEGORY_PHYSICS, // PHYSICS_2D + BUILD_OPTION_CATEGORY_PHYSICS, // PHYSICS_GODOT_2D + BUILD_OPTION_CATEGORY_PHYSICS, // PHYSICS_3D + BUILD_OPTION_CATEGORY_PHYSICS, // PHYSICS_GODOT_3D + BUILD_OPTION_CATEGORY_PHYSICS, // PHYSICS_JOLT BUILD_OPTION_CATEGORY_TEXT_SERVER, // TEXT_SERVER_FALLBACK - BUILD_OPTION_CATEGORY_TEXT_SERVER, // TEXT_SERVER_COMPLEX + BUILD_OPTION_CATEGORY_TEXT_SERVER, // TEXT_SERVER_ADVANCED BUILD_OPTION_CATEGORY_TEXT_SERVER, // DYNAMIC_FONTS BUILD_OPTION_CATEGORY_TEXT_SERVER, // WOFF2_FONTS BUILD_OPTION_CATEGORY_TEXT_SERVER, // GRAPHITE_FONTS BUILD_OPTION_CATEGORY_TEXT_SERVER, // MSDFGEN }; +// Can't assign HashMaps to a HashMap at declaration, so do it in the class' constructor. +HashMap>> EditorBuildProfile::build_option_settings = {}; + +/* clang-format off */ + +const HashMap> EditorBuildProfile::build_option_dependencies = { + { BUILD_OPTION_OPENXR, { + BUILD_OPTION_XR, + } }, + { BUILD_OPTION_FORWARD_RENDERER, { + BUILD_OPTION_RENDERING_DEVICE, + } }, + { BUILD_OPTION_MOBILE_RENDERER, { + BUILD_OPTION_RENDERING_DEVICE, + } }, + { BUILD_OPTION_VULKAN, { + BUILD_OPTION_FORWARD_RENDERER, + BUILD_OPTION_MOBILE_RENDERER, + } }, + { BUILD_OPTION_D3D12, { + BUILD_OPTION_FORWARD_RENDERER, + BUILD_OPTION_MOBILE_RENDERER, + } }, + { BUILD_OPTION_METAL, { + BUILD_OPTION_FORWARD_RENDERER, + BUILD_OPTION_MOBILE_RENDERER, + } }, + { BUILD_OPTION_PHYSICS_GODOT_2D, { + BUILD_OPTION_PHYSICS_2D, + } }, + { BUILD_OPTION_PHYSICS_GODOT_3D, { + BUILD_OPTION_PHYSICS_3D, + } }, + { BUILD_OPTION_PHYSICS_JOLT, { + BUILD_OPTION_PHYSICS_3D, + } }, + { BUILD_OPTION_DYNAMIC_FONTS, { + BUILD_OPTION_TEXT_SERVER_ADVANCED, + } }, + { BUILD_OPTION_WOFF2_FONTS, { + BUILD_OPTION_TEXT_SERVER_ADVANCED, + } }, + { BUILD_OPTION_GRAPHITE_FONTS, { + BUILD_OPTION_TEXT_SERVER_ADVANCED, + } }, +}; + +const HashMap> EditorBuildProfile::build_option_classes = { + { BUILD_OPTION_3D, { + "Node3D", + } }, + { BUILD_OPTION_NAVIGATION_2D, { + "NavigationAgent2D", + "NavigationLink2D", + "NavigationMeshSourceGeometryData2D", + "NavigationObstacle2D" + "NavigationPolygon", + "NavigationRegion2D", + } }, + { BUILD_OPTION_NAVIGATION_3D, { + "NavigationAgent3D", + "NavigationLink3D", + "NavigationMeshSourceGeometryData3D", + "NavigationObstacle3D", + "NavigationRegion3D", + } }, + { BUILD_OPTION_XR, { + "XRBodyModifier3D", + "XRBodyTracker", + "XRControllerTracker", + "XRFaceModifier3D", + "XRFaceTracker", + "XRHandModifier3D", + "XRHandTracker", + "XRInterface", + "XRInterfaceExtension", + "XRNode3D", + "XROrigin3D", + "XRPose", + "XRPositionalTracker", + "XRServer", + "XRTracker", + "XRVRS", + } }, + { BUILD_OPTION_RENDERING_DEVICE, { + "RenderingDevice", + } }, + { BUILD_OPTION_PHYSICS_2D, { + "CollisionObject2D", + "CollisionPolygon2D", + "CollisionShape2D", + "Joint2D", + "PhysicsServer2D", + "PhysicsServer2DManager", + "ShapeCast2D", + "RayCast2D", + "TouchScreenButton", + } }, + { BUILD_OPTION_PHYSICS_3D, { + "CollisionObject3D", + "CollisionPolygon3D", + "CollisionShape3D", + "CSGShape3D", + "GPUParticlesAttractor3D", + "GPUParticlesCollision3D", + "Joint3D", + "PhysicalBoneSimulator3D", + "PhysicsServer3D", + "PhysicsServer3DManager", + "PhysicsServer3DRenderingServerHandler", + "RayCast3D", + "SoftBody3D", + "SpringArm3D", + "SpringBoneCollision3D", + "SpringBoneSimulator3D", + "VehicleWheel3D", + } }, + { BUILD_OPTION_TEXT_SERVER_ADVANCED, { + "CanvasItem", + "Label3D", + "TextServerAdvanced", + } }, +}; + +/* clang-format on */ + void EditorBuildProfile::set_disable_class(const StringName &p_class, bool p_disabled) { if (p_disabled) { disabled_classes.insert(p_class); @@ -159,6 +361,17 @@ bool EditorBuildProfile::get_build_option_disable_value(BuildOption p_build_opti return build_option_disable_values[p_build_option]; } +bool EditorBuildProfile::get_build_option_explicit_use(BuildOption p_build_option) { + ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, false); + return build_option_explicit_use[p_build_option]; +} + +void EditorBuildProfile::reset_build_options() { + for (int i = 0; i < EditorBuildProfile::BUILD_OPTION_MAX; i++) { + build_options_disabled[i] = build_option_disabled_by_default[i]; + } +} + void EditorBuildProfile::set_force_detect_classes(const String &p_classes) { force_detect_classes = p_classes; } @@ -171,13 +384,24 @@ String EditorBuildProfile::get_build_option_name(BuildOption p_build_option) { ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, String()); const char *build_option_names[BUILD_OPTION_MAX] = { TTRC("3D Engine"), - TTRC("2D Physics"), - TTRC("3D Physics"), - TTRC("Navigation"), + TTRC("Navigation (2D)"), + TTRC("Navigation (3D)"), TTRC("XR"), + TTRC("OpenXR"), + TTRC("Wayland"), + TTRC("X11"), TTRC("RenderingDevice"), - TTRC("OpenGL"), + TTRC("Forward+ Renderer"), + TTRC("Mobile Renderer"), TTRC("Vulkan"), + TTRC("D3D12"), + TTRC("Metal"), + TTRC("OpenGL"), + TTRC("Physics Server (2D)"), + TTRC("Godot Physics (2D)"), + TTRC("Physics Server (3D)"), + TTRC("Godot Physics (3D)"), + TTRC("Jolt Physics"), TTRC("Text Server: Fallback"), TTRC("Text Server: Advanced"), TTRC("TTF, OTF, Type 1, WOFF1 Fonts"), @@ -193,13 +417,24 @@ String EditorBuildProfile::get_build_option_description(BuildOption p_build_opti const char *build_option_descriptions[BUILD_OPTION_MAX] = { TTRC("3D Nodes as well as RenderingServer access to 3D features."), - TTRC("2D Physics nodes and PhysicsServer2D."), - TTRC("3D Physics nodes and PhysicsServer3D."), - TTRC("Navigation, both 2D and 3D."), + TTRC("Navigation Server and capabilities for 2D."), + TTRC("Navigation Server and capabilities for 3D."), TTRC("XR (AR and VR)."), - TTRC("RenderingDevice based rendering (if disabled, the OpenGL back-end is required)."), - TTRC("OpenGL back-end (if disabled, the RenderingDevice back-end is required)."), - TTRC("Vulkan back-end of RenderingDevice."), + TTRC("OpenXR standard implementation (requires XR to be enabled)."), + TTRC("Wayland display (Linux only)."), + TTRC("X11 display (Linux only)."), + TTRC("RenderingDevice based rendering (if disabled, the OpenGL backend is required)."), + TTRC("Forward+ renderer for advanced 3D graphics."), + TTRC("Mobile renderer for less advanced 3D graphics."), + TTRC("Vulkan backend of RenderingDevice."), + TTRC("Direct3D 12 backend of RenderingDevice."), + TTRC("Metal backend of RenderingDevice (Apple arm64 only)."), + TTRC("OpenGL backend (if disabled, the RenderingDevice backend is required)."), + TTRC("Physics Server and capabilities for 2D."), + TTRC("Godot Physics backend (2D)."), + TTRC("Physics Server and capabilities for 3D."), + TTRC("Godot Physics backend (3D)."), + TTRC("Jolt Physics backend (3D only)."), TTRC("Fallback implementation of Text Server\nSupports basic text layouts."), TTRC("Text Server implementation powered by ICU and HarfBuzz libraries.\nSupports complex text layouts, BiDi, and contextual OpenType font features."), TTRC("TrueType, OpenType, Type 1, and WOFF1 font format support using FreeType library (if disabled, WOFF2 support is also disabled)."), @@ -211,16 +446,38 @@ String EditorBuildProfile::get_build_option_description(BuildOption p_build_opti return TTRGET(build_option_descriptions[p_build_option]); } +String EditorBuildProfile::get_build_option_identifier(BuildOption p_build_option) { + ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, String()); + return build_option_identifiers[p_build_option]; +} + EditorBuildProfile::BuildOptionCategory EditorBuildProfile::get_build_option_category(BuildOption p_build_option) { ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, BUILD_OPTION_CATEGORY_GENERAL); return build_option_category[p_build_option]; } +LocalVector EditorBuildProfile::get_build_option_dependencies(BuildOption p_build_option) { + ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, LocalVector()); + return build_option_dependencies.has(p_build_option) ? build_option_dependencies[p_build_option] : LocalVector(); +} + +HashMap> EditorBuildProfile::get_build_option_settings(BuildOption p_build_option) { + ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, (HashMap>())); + return build_option_settings.has(p_build_option) ? build_option_settings[p_build_option] : HashMap>(); +} + +LocalVector EditorBuildProfile::get_build_option_classes(BuildOption p_build_option) { + ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, LocalVector()); + return build_option_classes.has(p_build_option) ? build_option_classes[p_build_option] : LocalVector(); +} + String EditorBuildProfile::get_build_option_category_name(BuildOptionCategory p_build_option_category) { ERR_FAIL_INDEX_V(p_build_option_category, BUILD_OPTION_CATEGORY_MAX, String()); const char *build_option_subcategories[BUILD_OPTION_CATEGORY_MAX]{ TTRC("General Features:"), + TTRC("Graphics and Rendering:"), + TTRC("Physics Systems:"), TTRC("Text Rendering and Font Options:"), }; @@ -332,13 +589,24 @@ void EditorBuildProfile::_bind_methods() { ClassDB::bind_method(D_METHOD("load_from_file", "path"), &EditorBuildProfile::load_from_file); BIND_ENUM_CONSTANT(BUILD_OPTION_3D); - BIND_ENUM_CONSTANT(BUILD_OPTION_PHYSICS_2D); - BIND_ENUM_CONSTANT(BUILD_OPTION_PHYSICS_3D); - BIND_ENUM_CONSTANT(BUILD_OPTION_NAVIGATION); + BIND_ENUM_CONSTANT(BUILD_OPTION_NAVIGATION_2D); + BIND_ENUM_CONSTANT(BUILD_OPTION_NAVIGATION_3D); BIND_ENUM_CONSTANT(BUILD_OPTION_XR); + BIND_ENUM_CONSTANT(BUILD_OPTION_OPENXR); + BIND_ENUM_CONSTANT(BUILD_OPTION_WAYLAND); + BIND_ENUM_CONSTANT(BUILD_OPTION_X11); BIND_ENUM_CONSTANT(BUILD_OPTION_RENDERING_DEVICE); - BIND_ENUM_CONSTANT(BUILD_OPTION_OPENGL); + BIND_ENUM_CONSTANT(BUILD_OPTION_FORWARD_RENDERER); + BIND_ENUM_CONSTANT(BUILD_OPTION_MOBILE_RENDERER); BIND_ENUM_CONSTANT(BUILD_OPTION_VULKAN); + BIND_ENUM_CONSTANT(BUILD_OPTION_D3D12); + BIND_ENUM_CONSTANT(BUILD_OPTION_METAL); + BIND_ENUM_CONSTANT(BUILD_OPTION_OPENGL); + BIND_ENUM_CONSTANT(BUILD_OPTION_PHYSICS_2D); + BIND_ENUM_CONSTANT(BUILD_OPTION_PHYSICS_GODOT_2D); + BIND_ENUM_CONSTANT(BUILD_OPTION_PHYSICS_3D); + BIND_ENUM_CONSTANT(BUILD_OPTION_PHYSICS_GODOT_3D); + BIND_ENUM_CONSTANT(BUILD_OPTION_PHYSICS_JOLT); BIND_ENUM_CONSTANT(BUILD_OPTION_TEXT_SERVER_FALLBACK); BIND_ENUM_CONSTANT(BUILD_OPTION_TEXT_SERVER_ADVANCED); BIND_ENUM_CONSTANT(BUILD_OPTION_DYNAMIC_FONTS); @@ -348,14 +616,78 @@ void EditorBuildProfile::_bind_methods() { BIND_ENUM_CONSTANT(BUILD_OPTION_MAX); BIND_ENUM_CONSTANT(BUILD_OPTION_CATEGORY_GENERAL); + BIND_ENUM_CONSTANT(BUILD_OPTION_CATEGORY_GRAPHICS); + BIND_ENUM_CONSTANT(BUILD_OPTION_CATEGORY_PHYSICS); BIND_ENUM_CONSTANT(BUILD_OPTION_CATEGORY_TEXT_SERVER); BIND_ENUM_CONSTANT(BUILD_OPTION_CATEGORY_MAX); } EditorBuildProfile::EditorBuildProfile() { - for (int i = 0; i < EditorBuildProfile::BUILD_OPTION_MAX; i++) { - build_options_disabled[i] = build_option_disabled_by_default[i]; - } + reset_build_options(); + + HashMap> settings_openxr = { + { "xr/openxr/enabled", { true } }, + }; + build_option_settings.insert(BUILD_OPTION_OPENXR, settings_openxr); + HashMap> settings_wayland = { + { "display/display_server/driver.linuxbsd", { "default", "wayland" } }, + }; + build_option_settings.insert(BUILD_OPTION_OPENXR, settings_wayland); + HashMap> settings_x11 = { + { "display/display_server/driver.linuxbsd", { "default", "x11" } }, + }; + build_option_settings.insert(BUILD_OPTION_OPENXR, settings_x11); + HashMap> settings_rd = { + { "rendering/renderer/rendering_method", { "forward_plus", "mobile" } }, + { "rendering/renderer/rendering_method.mobile", { "forward_plus", "mobile" } }, + { "rendering/renderer/rendering_method.web", { "forward_plus", "mobile" } }, + }; + build_option_settings.insert(BUILD_OPTION_RENDERING_DEVICE, settings_rd); + HashMap> settings_vulkan = { + { "rendering/rendering_device/driver", { "vulkan" } }, + { "rendering/rendering_device/driver.windows", { "vulkan" } }, + { "rendering/rendering_device/driver.linuxbsd", { "vulkan" } }, + { "rendering/rendering_device/driver.android", { "vulkan" } }, + { "rendering/rendering_device/driver.ios", { "vulkan" } }, + { "rendering/rendering_device/driver.macos", { "vulkan" } }, + { "rendering/rendering_device/fallback_to_vulkan", { true } }, + }; + build_option_settings.insert(BUILD_OPTION_VULKAN, settings_vulkan); + HashMap> settings_d3d12 = { + { "rendering/rendering_device/driver", { "d3d12" } }, + { "rendering/rendering_device/driver.windows", { "d3d12" } }, + { "rendering/rendering_device/driver.linuxbsd", { "d3d12" } }, + { "rendering/rendering_device/driver.android", { "d3d12" } }, + { "rendering/rendering_device/driver.ios", { "d3d12" } }, + { "rendering/rendering_device/driver.macos", { "d3d12" } }, + { "rendering/rendering_device/fallback_to_d3d12", { true } }, + }; + build_option_settings.insert(BUILD_OPTION_VULKAN, settings_vulkan); + HashMap> settings_metal = { + { "rendering/rendering_device/driver", { "metal" } }, + { "rendering/rendering_device/driver.ios", { "metal" } }, + { "rendering/rendering_device/driver.macos", { "metal" } }, + }; + build_option_settings.insert(BUILD_OPTION_METAL, settings_metal); + HashMap> settings_opengl = { + { "rendering/renderer/rendering_method", { "gl_compatibility" } }, + { "rendering/renderer/rendering_method.mobile", { "gl_compatibility" } }, + { "rendering/renderer/rendering_method.web", { "gl_compatibility" } }, + { "rendering/rendering_device/fallback_to_opengl3", { true } }, + }; + build_option_settings.insert(BUILD_OPTION_OPENGL, settings_opengl); + HashMap> settings_phy_godot_3d = { + { "physics/3d/physics_engine", { "DEFAULT", "GodotPhysics3D" } }, + }; + build_option_settings.insert(BUILD_OPTION_PHYSICS_GODOT_3D, settings_phy_godot_3d); + HashMap> settings_jolt = { + { "physics/3d/physics_engine", { "Jolt Physics" } }, + }; + build_option_settings.insert(BUILD_OPTION_PHYSICS_JOLT, settings_jolt); + HashMap> settings_msdfgen = { + { "gui/theme/default_font_multichannel_signed_distance_field", { true } }, + }; + build_option_settings.insert(BUILD_OPTION_MSDFGEN, settings_msdfgen); } ////////////////////////// @@ -406,7 +738,11 @@ void EditorBuildProfileManager::_profile_action(int p_action) { confirm_dialog->popup_centered(); } break; case ACTION_DETECT: { - confirm_dialog->set_text(TTR("This will scan all files in the current project to detect used classes.")); + String text = TTR("This will scan all files in the current project to detect used classes.\nNote that the first scan may take a while, specially in larger projects."); +#ifdef MODULE_MONO_ENABLED + text += "\n\n" + TTR("Warning: Class detection for C# scripts is not currently available, and such files will be ignored."); +#endif // MODULE_MONO_ENABLED + confirm_dialog->set_text(text); confirm_dialog->popup_centered(); } break; case ACTION_MAX: { @@ -415,23 +751,35 @@ void EditorBuildProfileManager::_profile_action(int p_action) { } void EditorBuildProfileManager::_find_files(EditorFileSystemDirectory *p_dir, const HashMap &p_cache, HashMap &r_detected) { - if (p_dir == nullptr) { + if (p_dir == nullptr || p_dir->get_path().get_file().begins_with(".")) { return; } for (int i = 0; i < p_dir->get_file_count(); i++) { String p = p_dir->get_file_path(i); + if (EditorNode::get_singleton()->progress_task_step("detect_classes_from_project", p, 1)) { + project_scan_canceled = true; + return; + } + + String p_check = p; + // Make so that the import file is the one checked if available, + // so the cache can be updated when it changes. + if (ResourceFormatImporter::get_singleton()->exists(p_check)) { + p_check += ".import"; + } + uint64_t timestamp = 0; String md5; if (p_cache.has(p)) { const DetectedFile &cache = p_cache[p]; // Check if timestamp and MD5 match. - timestamp = FileAccess::get_modified_time(p); + timestamp = FileAccess::get_modified_time(p_check); bool cache_valid = true; if (cache.timestamp != timestamp) { - md5 = FileAccess::get_md5(p); + md5 = FileAccess::get_md5(p_check); if (md5 != cache.md5) { cache_valid = false; } @@ -449,14 +797,19 @@ void EditorBuildProfileManager::_find_files(EditorFileSystemDirectory *p_dir, co HashSet classes; ResourceLoader::get_classes_used(p, &classes); - for (const StringName &E : classes) { cache.classes.push_back(E); } + HashSet build_deps; + ResourceFormatImporter::get_singleton()->get_build_dependencies(p, &build_deps); + for (const String &E : build_deps) { + cache.build_deps.push_back(E); + } + if (md5.is_empty()) { - cache.timestamp = FileAccess::get_modified_time(p); - cache.md5 = FileAccess::get_md5(p); + cache.timestamp = FileAccess::get_modified_time(p_check); + cache.md5 = FileAccess::get_md5(p_check); } else { cache.timestamp = timestamp; cache.md5 = md5; @@ -470,7 +823,9 @@ void EditorBuildProfileManager::_find_files(EditorFileSystemDirectory *p_dir, co } } -void EditorBuildProfileManager::_detect_classes() { +void EditorBuildProfileManager::_detect_from_project() { + EditorNode::get_singleton()->progress_add_task("detect_classes_from_project", TTRC("Scanning Project for Used Classes"), 3, true); + HashMap previous_file_cache; Ref f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().path_join("used_class_cache"), FileAccess::READ); @@ -478,12 +833,13 @@ void EditorBuildProfileManager::_detect_classes() { while (!f->eof_reached()) { String l = f->get_line(); Vector fields = l.split("::"); - if (fields.size() == 4) { + if (fields.size() == 5) { const String &path = fields[0]; DetectedFile df; df.timestamp = fields[1].to_int(); df.md5 = fields[2]; - df.classes = fields[3].split(","); + df.classes = fields[3].split(",", false); + df.build_deps = fields[4].split(",", false); previous_file_cache.insert(path, df); } } @@ -494,7 +850,17 @@ void EditorBuildProfileManager::_detect_classes() { _find_files(EditorFileSystem::get_singleton()->get_filesystem(), previous_file_cache, updated_file_cache); + if (project_scan_canceled) { + project_scan_canceled = false; + EditorNode::get_singleton()->progress_end_task("detect_classes_from_project"); + + return; + } + + EditorNode::get_singleton()->progress_task_step("detect_classes_from_project", TTRC("Processing Classes Found"), 2); + HashSet used_classes; + LocalVector used_build_deps; // Find classes and update the disk cache in the process. f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().path_join("used_class_cache"), FileAccess::WRITE); @@ -509,20 +875,41 @@ void EditorBuildProfileManager::_detect_classes() { l += c; used_classes.insert(c); } + l += "::"; + for (int i = 0; i < E.value.build_deps.size(); i++) { + String c = E.value.build_deps[i]; + if (i > 0) { + l += ","; + } + l += c; + used_build_deps.push_back(c); + } f->store_line(l); } f.unref(); - // Add forced ones. + // Add classes that are either necessary for the engine to work properly, or there isn't a way to infer their use. - Vector force_detect = edited->get_force_detect_classes().split(","); - for (int i = 0; i < force_detect.size(); i++) { - String c = force_detect[i].strip_edges(); - if (c.is_empty()) { - continue; + const LocalVector hardcoded_classes = { "InputEvent", "MainLoop", "StyleBox" }; + for (const String &hc_class : hardcoded_classes) { + used_classes.insert(hc_class); + + LocalVector inheriters; + ClassDB::get_inheriters_from_class(hc_class, inheriters); + for (const StringName &inheriter : inheriters) { + used_classes.insert(inheriter); + } + } + + // Add forced classes typed by the user. + + const Vector force_detect = edited->get_force_detect_classes().split(","); + for (const String &class_name : force_detect) { + const String class_stripped = class_name.strip_edges(); + if (!class_stripped.is_empty()) { + used_classes.insert(class_stripped); } - used_classes.insert(c); } // Filter all classes to discard inherited ones. @@ -532,13 +919,23 @@ void EditorBuildProfileManager::_detect_classes() { for (const StringName &E : used_classes) { StringName c = E; if (!ClassDB::class_exists(c)) { - // Maybe this is an old class that got replaced? try getting compat class. + // Maybe this is an old class that got replaced? Try getting compat class. c = ClassDB::get_compatibility_class(c); if (!c) { // No luck, skip. continue; } } + + List dependencies; + ClassDB::get_class_dependencies(E, &dependencies); + for (const StringName &dep : dependencies) { + if (!all_used_classes.has(dep)) { + // Add classes which this class depends upon. + all_used_classes.insert(dep); + } + } + while (c) { all_used_classes.insert(c); c = ClassDB::get_parent_class(c); @@ -551,8 +948,8 @@ void EditorBuildProfileManager::_detect_classes() { ClassDB::get_class_list(&all_classes); for (const StringName &E : all_classes) { - if (all_used_classes.has(E)) { - // This class is valid, do nothing. + if (String(E).begins_with("Editor") || ClassDB::get_api_type(E) != ClassDB::API_CORE || all_used_classes.has(E)) { + // This class is valid or editor-only, do nothing. continue; } @@ -563,6 +960,88 @@ void EditorBuildProfileManager::_detect_classes() { edited->set_disable_class(E, true); } } + + edited->reset_build_options(); + + for (int i = 0; i < EditorBuildProfile::BUILD_OPTION_MAX; i++) { + // Check if the build option requires other options that are currently disabled. + LocalVector dependencies = EditorBuildProfile::get_build_option_dependencies(EditorBuildProfile::BuildOption(i)); + if (!dependencies.is_empty()) { + bool disable = true; + for (EditorBuildProfile::BuildOption dependency : dependencies) { + if (!edited->is_build_option_disabled(dependency)) { + disable = false; + break; + } + } + + if (disable) { + edited->set_disable_build_option(EditorBuildProfile::BuildOption(i), true); + continue; + } + } + + bool skip = false; + bool ignore = true; + + // Check if the build option has enabled classes using it. + const LocalVector classes = EditorBuildProfile::get_build_option_classes(EditorBuildProfile::BuildOption(i)); + if (!classes.is_empty()) { + for (StringName class_name : classes) { + if (!edited->is_class_disabled(class_name)) { + skip = true; + break; + } + } + + if (skip) { + continue; + } + + ignore = false; + } + + // Check if there's project settings requiring it. + const HashMap> settings_list = EditorBuildProfile::get_build_option_settings(EditorBuildProfile::BuildOption(i)); + if (!settings_list.is_empty()) { + for (KeyValue> KV : settings_list) { + Variant proj_value = GLOBAL_GET(KV.key); + for (Variant value : KV.value) { + if (proj_value == value) { + skip = true; + break; + } + } + + if (skip) { + break; + } + } + + if (skip) { + continue; + } + + ignore = false; + } + + // Check if a resource setting depends on it. + if (used_build_deps.has(EditorBuildProfile::get_build_option_identifier(EditorBuildProfile::BuildOption(i)))) { + continue; + } else if (EditorBuildProfile::get_build_option_explicit_use(EditorBuildProfile::BuildOption(i))) { + ignore = false; + } + + if (!skip && !ignore) { + edited->set_disable_build_option(EditorBuildProfile::BuildOption(i), true); + } + } + + if (edited->is_build_option_disabled(EditorBuildProfile::BUILD_OPTION_TEXT_SERVER_ADVANCED)) { + edited->set_disable_build_option(EditorBuildProfile::BUILD_OPTION_TEXT_SERVER_FALLBACK, false); + } + + EditorNode::get_singleton()->progress_end_task("detect_classes_from_project"); } void EditorBuildProfileManager::_action_confirm() { @@ -583,7 +1062,7 @@ void EditorBuildProfileManager::_action_confirm() { _update_edited_profile(); } break; case ACTION_DETECT: { - _detect_classes(); + _detect_from_project(); _update_edited_profile(); } break; case ACTION_MAX: { @@ -869,7 +1348,7 @@ EditorBuildProfileManager::EditorBuildProfileManager() { add_child(import_profile); import_profile->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE); import_profile->add_filter("*.gdbuild,*.build", TTR("Engine Compilation Profile")); - import_profile->connect("files_selected", callable_mp(this, &EditorBuildProfileManager::_import_profile)); + import_profile->connect("file_selected", callable_mp(this, &EditorBuildProfileManager::_import_profile)); import_profile->set_title(TTR("Load Profile")); import_profile->set_access(EditorFileDialog::ACCESS_FILESYSTEM); diff --git a/editor/editor_build_profile.h b/editor/editor_build_profile.h index 3131650ae3f..07c7f85db1d 100644 --- a/editor/editor_build_profile.h +++ b/editor/editor_build_profile.h @@ -41,13 +41,24 @@ class EditorBuildProfile : public RefCounted { public: enum BuildOption { BUILD_OPTION_3D, - BUILD_OPTION_PHYSICS_2D, - BUILD_OPTION_PHYSICS_3D, - BUILD_OPTION_NAVIGATION, + BUILD_OPTION_NAVIGATION_2D, + BUILD_OPTION_NAVIGATION_3D, BUILD_OPTION_XR, + BUILD_OPTION_OPENXR, + BUILD_OPTION_WAYLAND, + BUILD_OPTION_X11, BUILD_OPTION_RENDERING_DEVICE, - BUILD_OPTION_OPENGL, + BUILD_OPTION_FORWARD_RENDERER, + BUILD_OPTION_MOBILE_RENDERER, BUILD_OPTION_VULKAN, + BUILD_OPTION_D3D12, + BUILD_OPTION_METAL, + BUILD_OPTION_OPENGL, + BUILD_OPTION_PHYSICS_2D, + BUILD_OPTION_PHYSICS_GODOT_2D, + BUILD_OPTION_PHYSICS_3D, + BUILD_OPTION_PHYSICS_GODOT_3D, + BUILD_OPTION_PHYSICS_JOLT, BUILD_OPTION_TEXT_SERVER_FALLBACK, BUILD_OPTION_TEXT_SERVER_ADVANCED, BUILD_OPTION_DYNAMIC_FONTS, @@ -59,6 +70,8 @@ public: enum BuildOptionCategory { BUILD_OPTION_CATEGORY_GENERAL, + BUILD_OPTION_CATEGORY_GRAPHICS, + BUILD_OPTION_CATEGORY_PHYSICS, BUILD_OPTION_CATEGORY_TEXT_SERVER, BUILD_OPTION_CATEGORY_MAX, }; @@ -74,7 +87,11 @@ private: static const char *build_option_identifiers[BUILD_OPTION_MAX]; static const bool build_option_disabled_by_default[BUILD_OPTION_MAX]; static const bool build_option_disable_values[BUILD_OPTION_MAX]; + static const bool build_option_explicit_use[BUILD_OPTION_MAX]; static const BuildOptionCategory build_option_category[BUILD_OPTION_MAX]; + static const HashMap> build_option_dependencies; + static HashMap>> build_option_settings; + static const HashMap> build_option_classes; String _get_build_option_name(BuildOption p_build_option) { return get_build_option_name(p_build_option); } @@ -91,6 +108,8 @@ public: void set_disable_build_option(BuildOption p_build_option, bool p_disable); bool is_build_option_disabled(BuildOption p_build_option) const; + void reset_build_options(); + void set_force_detect_classes(const String &p_classes); String get_force_detect_classes() const; @@ -101,8 +120,13 @@ public: static String get_build_option_name(BuildOption p_build_option); static String get_build_option_description(BuildOption p_build_option); + static String get_build_option_identifier(BuildOption p_build_option); static bool get_build_option_disable_value(BuildOption p_build_option); + static bool get_build_option_explicit_use(BuildOption p_build_option); static BuildOptionCategory get_build_option_category(BuildOption p_build_option); + static LocalVector get_build_option_dependencies(BuildOption p_build_option); + static HashMap> get_build_option_settings(BuildOption p_build_option); + static LocalVector get_build_option_classes(BuildOption p_build_option); static String get_build_option_category_name(BuildOptionCategory p_build_option_category); @@ -160,7 +184,10 @@ class EditorBuildProfileManager : public AcceptDialog { void _class_list_item_selected(); void _class_list_item_edited(); void _class_list_item_collapsed(Object *p_item); - void _detect_classes(); + + bool project_scan_canceled = false; + + void _detect_from_project(); void _force_detect_classes_changed(const String &p_text); @@ -168,6 +195,7 @@ class EditorBuildProfileManager : public AcceptDialog { uint32_t timestamp = 0; String md5; Vector classes; + Vector build_deps; }; void _find_files(EditorFileSystemDirectory *p_dir, const HashMap &p_cache, HashMap &r_detected); diff --git a/editor/import/resource_importer_dynamic_font.cpp b/editor/import/resource_importer_dynamic_font.cpp index 49c9b1fed91..0020916f31a 100644 --- a/editor/import/resource_importer_dynamic_font.cpp +++ b/editor/import/resource_importer_dynamic_font.cpp @@ -65,6 +65,13 @@ String ResourceImporterDynamicFont::get_resource_type() const { return "FontFile"; } +void ResourceImporterDynamicFont::get_build_dependencies(const String &p_path, HashSet *r_dependencies) { + Ref font = ResourceLoader::load(p_path); + if (font.is_valid() && font->is_multichannel_signed_distance_field()) { + r_dependencies->insert("module_msdfgen_enabled"); + } +} + bool ResourceImporterDynamicFont::get_option_visibility(const String &p_path, const String &p_option, const HashMap &p_options) const { if (p_option == "msdf_pixel_range" && !bool(p_options["multichannel_signed_distance_field"])) { return false; diff --git a/editor/import/resource_importer_dynamic_font.h b/editor/import/resource_importer_dynamic_font.h index f41eb4b705f..62ce04048a5 100644 --- a/editor/import/resource_importer_dynamic_font.h +++ b/editor/import/resource_importer_dynamic_font.h @@ -47,6 +47,7 @@ public: virtual void get_recognized_extensions(List *p_extensions) const override; virtual String get_save_extension() const override; virtual String get_resource_type() const override; + virtual void get_build_dependencies(const String &p_path, HashSet *r_build_dependencies) override; virtual int get_preset_count() const override; virtual String get_preset_name(int p_idx) const override; diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index 16421c848b4..0096d4d0fe9 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -2114,6 +2114,10 @@ void ColorPicker::_bind_methods() { BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_STYLEBOX, ColorPicker, mode_button_normal, "tab_unselected", "TabContainer"); BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_STYLEBOX, ColorPicker, mode_button_pressed, "tab_selected", "TabContainer"); BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_STYLEBOX, ColorPicker, mode_button_hover, "tab_selected", "TabContainer"); + + ADD_CLASS_DEPENDENCY("LineEdit"); + ADD_CLASS_DEPENDENCY("MenuButton"); + ADD_CLASS_DEPENDENCY("PopupMenu"); } ColorPicker::ColorPicker() { diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index 31912aedf3c..8cdea4f667a 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -443,6 +443,8 @@ void AcceptDialog::_bind_methods() { BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, AcceptDialog, buttons_separation); BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, AcceptDialog, buttons_min_width); BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, AcceptDialog, buttons_min_height); + + ADD_CLASS_DEPENDENCY("Button"); } void AcceptDialog::_validate_property(PropertyInfo &p_property) const { @@ -510,6 +512,8 @@ void ConfirmationDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("get_cancel_button_text"), &ConfirmationDialog::get_cancel_button_text); ADD_PROPERTY(PropertyInfo(Variant::STRING, "cancel_button_text"), "set_cancel_button_text", "get_cancel_button_text"); + + ADD_CLASS_DEPENDENCY("Button"); } Button *ConfirmationDialog::get_cancel_button() { diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index e0c28206dc8..87e375e00ab 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -1900,6 +1900,12 @@ void FileDialog::_bind_methods() { base_property_helper.register_property(PropertyInfo(Variant::PACKED_STRING_ARRAY, "values"), defaults.values, &FileDialog::set_option_values, &FileDialog::get_option_values); base_property_helper.register_property(PropertyInfo(Variant::INT, "default"), defaults.default_idx, &FileDialog::set_option_default, &FileDialog::get_option_default); PropertyListHelper::register_base_helper(&base_property_helper); + + ADD_CLASS_DEPENDENCY("Button"); + ADD_CLASS_DEPENDENCY("ConfirmationDialog"); + ADD_CLASS_DEPENDENCY("LineEdit"); + ADD_CLASS_DEPENDENCY("OptionButton"); + ADD_CLASS_DEPENDENCY("Tree"); } void FileDialog::set_show_hidden_files(bool p_show) { diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index 9318794e607..00229a433a5 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -3129,6 +3129,13 @@ void GraphEdit::_bind_methods() { BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, GraphEdit, port_hotzone_inner_extent); BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, GraphEdit, port_hotzone_outer_extent); + + ADD_CLASS_DEPENDENCY("Button"); + ADD_CLASS_DEPENDENCY("GraphFrame"); + ADD_CLASS_DEPENDENCY("GraphNode"); + ADD_CLASS_DEPENDENCY("HScrollBar"); + ADD_CLASS_DEPENDENCY("SpinBox"); + ADD_CLASS_DEPENDENCY("VScrollBar"); } GraphEdit::GraphEdit() { diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 7210af1bfd1..0ebe6a45a9a 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -3305,6 +3305,8 @@ void LineEdit::_bind_methods() { BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, LineEdit, clear_icon, "clear"); BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, LineEdit, clear_button_color); BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, LineEdit, clear_button_color_pressed); + + ADD_CLASS_DEPENDENCY("PopupMenu"); } LineEdit::LineEdit(const String &p_placeholder) { diff --git a/scene/gui/menu_bar.cpp b/scene/gui/menu_bar.cpp index 54a5f3bfd0c..1cb772ab5ab 100644 --- a/scene/gui/menu_bar.cpp +++ b/scene/gui/menu_bar.cpp @@ -763,6 +763,8 @@ void MenuBar::_bind_methods() { BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, MenuBar, font_focus_color); BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, MenuBar, h_separation); + + ADD_CLASS_DEPENDENCY("PopupMenu"); } void MenuBar::set_switch_on_hover(bool p_enabled) { diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp index d9f35f44d37..72ddddc9bdf 100644 --- a/scene/gui/menu_button.cpp +++ b/scene/gui/menu_button.cpp @@ -194,6 +194,8 @@ void MenuButton::_bind_methods() { ADD_SIGNAL(MethodInfo("about_to_popup")); + ADD_CLASS_DEPENDENCY("PopupMenu"); + PopupMenu::Item defaults(true); base_property_helper.set_prefix("popup/item_"); diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index 607cbddab4e..d1a1d21a416 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -625,6 +625,8 @@ void OptionButton::_bind_methods() { base_property_helper.register_property(PropertyInfo(Variant::BOOL, "disabled"), defaults.disabled, &OptionButton::_dummy_setter, &OptionButton::is_item_disabled); base_property_helper.register_property(PropertyInfo(Variant::BOOL, "separator"), defaults.separator, &OptionButton::_dummy_setter, &OptionButton::is_item_separator); PropertyListHelper::register_base_helper(&base_property_helper); + + ADD_CLASS_DEPENDENCY("PopupMenu"); } void OptionButton::set_disable_shortcuts(bool p_disabled) { diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 705a1d414ef..5137a277c17 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -7416,6 +7416,8 @@ void RichTextLabel::_bind_methods() { BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, RichTextLabel, table_odd_row_bg); BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, RichTextLabel, table_even_row_bg); BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, RichTextLabel, table_border); + + ADD_CLASS_DEPENDENCY("PopupMenu"); } TextServer::VisibleCharactersBehavior RichTextLabel::get_visible_characters_behavior() const { diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index 744b77d3d03..9a0c86502ea 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -691,6 +691,8 @@ void SpinBox::_bind_methods() { BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, SpinBox, field_and_buttons_separator, "field_and_buttons_separator"); BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, SpinBox, up_down_buttons_separator, "up_down_buttons_separator"); + + ADD_CLASS_DEPENDENCY("LineEdit"); } SpinBox::SpinBox() { diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index eb8218e6540..cdfa6b48219 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -1128,6 +1128,8 @@ void TabContainer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_focus_mode", PROPERTY_HINT_ENUM, "None,Click,All"), "set_tab_focus_mode", "get_tab_focus_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deselect_enabled"), "set_deselect_enabled", "get_deselect_enabled"); + ADD_CLASS_DEPENDENCY("TabBar"); + BIND_ENUM_CONSTANT(POSITION_TOP); BIND_ENUM_CONSTANT(POSITION_BOTTOM); BIND_ENUM_CONSTANT(POSITION_MAX); diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 80a563de759..38d2a851b6e 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -7629,6 +7629,12 @@ void TextEdit::_bind_methods() { /* Settings. */ GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "gui/timers/text_edit_idle_detect_sec", PROPERTY_HINT_RANGE, "0,10,0.01,or_greater"), 3); GLOBAL_DEF(PropertyInfo(Variant::INT, "gui/common/text_edit_undo_stack_max_size", PROPERTY_HINT_RANGE, "0,10000,1,or_greater"), 1024); + + /* Dependencies */ + ADD_CLASS_DEPENDENCY("HScrollBar"); + ADD_CLASS_DEPENDENCY("PopupMenu"); + ADD_CLASS_DEPENDENCY("Timer"); + ADD_CLASS_DEPENDENCY("VScrollBar"); } /* Internal API for CodeEdit. */ diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 91510bd825a..d0b2eeec00b 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -6655,6 +6655,14 @@ void Tree::_bind_methods() { BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Tree, title_button_pressed); BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Tree, title_button_hover); BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Tree, title_button_color); + + ADD_CLASS_DEPENDENCY("HScrollBar"); + ADD_CLASS_DEPENDENCY("HSlider"); + ADD_CLASS_DEPENDENCY("LineEdit"); + ADD_CLASS_DEPENDENCY("Popup"); + ADD_CLASS_DEPENDENCY("TextEdit"); + ADD_CLASS_DEPENDENCY("Timer"); + ADD_CLASS_DEPENDENCY("VScrollBar"); } Tree::Tree() { diff --git a/scene/resources/3d/world_3d.cpp b/scene/resources/3d/world_3d.cpp index c6e21421862..649bc78ee82 100644 --- a/scene/resources/3d/world_3d.cpp +++ b/scene/resources/3d/world_3d.cpp @@ -177,18 +177,26 @@ World3D::World3D() { World3D::~World3D() { ERR_FAIL_NULL(RenderingServer::get_singleton()); + #ifndef PHYSICS_3D_DISABLED ERR_FAIL_NULL(PhysicsServer3D::get_singleton()); #endif // PHYSICS_3D_DISABLED + +#ifndef NAVIGATION_3D_DISABLED ERR_FAIL_NULL(NavigationServer3D::get_singleton()); +#endif // NAVIGATION_3D_DISABLED RenderingServer::get_singleton()->free(scenario); + #ifndef PHYSICS_3D_DISABLED if (space.is_valid()) { PhysicsServer3D::get_singleton()->free(space); } #endif // PHYSICS_3D_DISABLED + +#ifndef NAVIGATION_3D_DISABLED if (navigation_map.is_valid()) { NavigationServer3D::get_singleton()->free(navigation_map); } +#endif // NAVIGATION_3D_DISABLED } diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index 938321449a3..03e9b40d205 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -1223,15 +1223,10 @@ Error ResourceLoaderText::get_classes_used(HashSet *r_classes) { return error; } - if (!next_tag.fields.has("type")) { - error = ERR_FILE_CORRUPT; - error_text = "Missing 'type' in external resource tag"; - _printerr(); - return error; + if (next_tag.fields.has("type")) { + r_classes->insert(next_tag.fields["type"]); } - r_classes->insert(next_tag.fields["type"]); - while (true) { String assign; Variant value; @@ -1447,9 +1442,9 @@ bool ResourceFormatLoaderText::handles_type(const String &p_type) const { } void ResourceFormatLoaderText::get_classes_used(const String &p_path, HashSet *r_classes) { - String ext = p_path.get_extension().to_lower(); - if (ext == "tscn") { - r_classes->insert("PackedScene"); + const String type = get_resource_type(p_path); + if (!type.is_empty()) { + r_classes->insert(type); } // ...for anything else must test...