Path: blob/master/editor/settings/editor_build_profile.cpp
20850 views
/**************************************************************************/1/* editor_build_profile.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "editor_build_profile.h"3132#include "core/config/project_settings.h"33#include "core/io/json.h"34#include "editor/editor_node.h"35#include "editor/editor_string_names.h"36#include "editor/file_system/editor_file_system.h"37#include "editor/file_system/editor_paths.h"38#include "editor/gui/editor_file_dialog.h"39#include "editor/settings/editor_settings.h"40#include "editor/themes/editor_scale.h"41#include "scene/gui/line_edit.h"42#include "scene/gui/margin_container.h"43#include "scene/gui/separator.h"4445#include "modules/modules_enabled.gen.h" // For mono.4647const char *EditorBuildProfile::build_option_identifiers[BUILD_OPTION_MAX] = {48// This maps to SCons build options.49"disable_3d",50"disable_navigation_2d",51"disable_navigation_3d",52"accesskit",53"sdl",54"disable_xr",55"module_openxr_enabled",56"wayland",57"x11",58"pulseaudio",59"alsa",60"rendering_device", // FIXME: There's no scons option to disable rendering device.61"forward_plus_renderer",62"forward_mobile_renderer",63"vulkan",64"d3d12",65"metal",66"opengl3",67"disable_physics_2d",68"module_godot_physics_2d_enabled",69"disable_physics_3d",70"module_godot_physics_3d_enabled",71"module_jolt_physics_enabled",72"module_text_server_fb_enabled",73"module_text_server_adv_enabled",74"module_freetype_enabled",75"brotli",76"graphite",77"module_msdfgen_enabled",78};7980const bool EditorBuildProfile::build_option_disabled_by_default[BUILD_OPTION_MAX] = {81// This maps to SCons build options.82false, // 3D83false, // NAVIGATION_2D84false, // NAVIGATION_3D85false, // ACCESSKIT86false, // SDL87false, // XR88false, // OPENXR89false, // WAYLAND90false, // X1191false, // PULSEAUDIO92false, // ALSA93false, // RENDERING_DEVICE94false, // FORWARD_RENDERER95false, // MOBILE_RENDERER96false, // VULKAN97false, // D3D1298false, // METAL99false, // OPENGL100false, // PHYSICS_2D101false, // PHYSICS_GODOT_2D102false, // PHYSICS_3D103false, // PHYSICS_GODOT_3D104false, // PHYSICS_JOLT105true, // TEXT_SERVER_FALLBACK106false, // TEXT_SERVER_ADVANCED107false, // DYNAMIC_FONTS108false, // WOFF2_FONTS109false, // GRAPHITE_FONTS110false, // MSDFGEN111};112113const bool EditorBuildProfile::build_option_disable_values[BUILD_OPTION_MAX] = {114// This maps to SCons build options.115true, // 3D116true, // NAVIGATION_2D117true, // NAVIGATION_3D118false, // ACCESSKIT119false, // SDL120true, // XR121false, // OPENXR122false, // WAYLAND123false, // X11124false, // PULSEAUDIO125false, // ALSA126false, // RENDERING_DEVICE127false, // FORWARD_RENDERER128false, // MOBILE_RENDERER129false, // VULKAN130false, // D3D12131false, // METAL132false, // OPENGL133true, // PHYSICS_2D134false, // PHYSICS_GODOT_2D135true, // PHYSICS_3D136false, // PHYSICS_GODOT_3D137false, // PHYSICS_JOLT138false, // TEXT_SERVER_FALLBACK139false, // TEXT_SERVER_ADVANCED140false, // DYNAMIC_FONTS141false, // WOFF2_FONTS142false, // GRAPHITE_FONTS143false, // MSDFGEN144};145146// Options that require some resource explicitly asking for them when detecting from the project.147const bool EditorBuildProfile::build_option_explicit_use[BUILD_OPTION_MAX] = {148false, // 3D149false, // NAVIGATION_2D150false, // NAVIGATION_3D151false, // ACCESSKIT152false, // SDL153false, // XR154false, // OPENXR155false, // WAYLAND156false, // X11157false, // PULSEAUDIO158false, // ALSA159false, // RENDERING_DEVICE160false, // FORWARD_RENDERER161false, // MOBILE_RENDERER162false, // VULKAN163false, // D3D12164false, // METAL165false, // OPENGL166false, // PHYSICS_2D167false, // PHYSICS_GODOT_2D168false, // PHYSICS_3D169false, // PHYSICS_GODOT_3D170false, // PHYSICS_JOLT171false, // TEXT_SERVER_FALLBACK172false, // TEXT_SERVER_ADVANCED173false, // DYNAMIC_FONTS174false, // WOFF2_FONTS175false, // GRAPHITE_FONTS176true, // MSDFGEN177};178179const EditorBuildProfile::BuildOptionCategory EditorBuildProfile::build_option_category[BUILD_OPTION_MAX] = {180BUILD_OPTION_CATEGORY_GENERAL, // 3D181BUILD_OPTION_CATEGORY_GENERAL, // NAVIGATION_2D182BUILD_OPTION_CATEGORY_GENERAL, // NAVIGATION_3D183BUILD_OPTION_CATEGORY_GENERAL, // ACCESSKIT184BUILD_OPTION_CATEGORY_GENERAL, // SDL185BUILD_OPTION_CATEGORY_GENERAL, // XR186BUILD_OPTION_CATEGORY_GENERAL, // OPENXR187BUILD_OPTION_CATEGORY_GENERAL, // WAYLAND188BUILD_OPTION_CATEGORY_GENERAL, // X11189BUILD_OPTION_CATEGORY_GENERAL, // PULSEAUDIO190BUILD_OPTION_CATEGORY_GENERAL, // ALSA191BUILD_OPTION_CATEGORY_GRAPHICS, // RENDERING_DEVICE192BUILD_OPTION_CATEGORY_GRAPHICS, // FORWARD_RENDERER193BUILD_OPTION_CATEGORY_GRAPHICS, // MOBILE_RENDERER194BUILD_OPTION_CATEGORY_GRAPHICS, // VULKAN195BUILD_OPTION_CATEGORY_GRAPHICS, // D3D12196BUILD_OPTION_CATEGORY_GRAPHICS, // METAL197BUILD_OPTION_CATEGORY_GRAPHICS, // OPENGL198BUILD_OPTION_CATEGORY_PHYSICS, // PHYSICS_2D199BUILD_OPTION_CATEGORY_PHYSICS, // PHYSICS_GODOT_2D200BUILD_OPTION_CATEGORY_PHYSICS, // PHYSICS_3D201BUILD_OPTION_CATEGORY_PHYSICS, // PHYSICS_GODOT_3D202BUILD_OPTION_CATEGORY_PHYSICS, // PHYSICS_JOLT203BUILD_OPTION_CATEGORY_TEXT_SERVER, // TEXT_SERVER_FALLBACK204BUILD_OPTION_CATEGORY_TEXT_SERVER, // TEXT_SERVER_ADVANCED205BUILD_OPTION_CATEGORY_TEXT_SERVER, // DYNAMIC_FONTS206BUILD_OPTION_CATEGORY_TEXT_SERVER, // WOFF2_FONTS207BUILD_OPTION_CATEGORY_TEXT_SERVER, // GRAPHITE_FONTS208BUILD_OPTION_CATEGORY_TEXT_SERVER, // MSDFGEN209};210211// Can't assign HashMaps to a HashMap at declaration, so do it in the class' constructor.212HashMap<EditorBuildProfile::BuildOption, HashMap<String, LocalVector<Variant>>> EditorBuildProfile::build_option_settings = {};213214/* clang-format off */215216const HashMap<EditorBuildProfile::BuildOption, LocalVector<EditorBuildProfile::BuildOption>> EditorBuildProfile::build_option_dependencies = {217{ BUILD_OPTION_OPENXR, {218BUILD_OPTION_XR,219} },220{ BUILD_OPTION_FORWARD_RENDERER, {221BUILD_OPTION_RENDERING_DEVICE,222} },223{ BUILD_OPTION_MOBILE_RENDERER, {224BUILD_OPTION_RENDERING_DEVICE,225} },226{ BUILD_OPTION_VULKAN, {227BUILD_OPTION_FORWARD_RENDERER,228BUILD_OPTION_MOBILE_RENDERER,229} },230{ BUILD_OPTION_D3D12, {231BUILD_OPTION_FORWARD_RENDERER,232BUILD_OPTION_MOBILE_RENDERER,233} },234{ BUILD_OPTION_METAL, {235BUILD_OPTION_FORWARD_RENDERER,236BUILD_OPTION_MOBILE_RENDERER,237} },238{ BUILD_OPTION_PHYSICS_GODOT_2D, {239BUILD_OPTION_PHYSICS_2D,240} },241{ BUILD_OPTION_PHYSICS_GODOT_3D, {242BUILD_OPTION_PHYSICS_3D,243} },244{ BUILD_OPTION_PHYSICS_JOLT, {245BUILD_OPTION_PHYSICS_3D,246} },247{ BUILD_OPTION_DYNAMIC_FONTS, {248BUILD_OPTION_TEXT_SERVER_ADVANCED,249} },250{ BUILD_OPTION_WOFF2_FONTS, {251BUILD_OPTION_TEXT_SERVER_ADVANCED,252} },253{ BUILD_OPTION_GRAPHITE_FONTS, {254BUILD_OPTION_TEXT_SERVER_ADVANCED,255} },256};257258const HashMap<EditorBuildProfile::BuildOption, LocalVector<String>> EditorBuildProfile::build_option_classes = {259{ BUILD_OPTION_3D, {260"Node3D",261} },262{ BUILD_OPTION_NAVIGATION_2D, {263"NavigationAgent2D",264"NavigationLink2D",265"NavigationMeshSourceGeometryData2D",266"NavigationObstacle2D",267"NavigationPolygon",268"NavigationRegion2D",269} },270{ BUILD_OPTION_NAVIGATION_3D, {271"NavigationAgent3D",272"NavigationLink3D",273"NavigationMeshSourceGeometryData3D",274"NavigationObstacle3D",275"NavigationRegion3D",276} },277{ BUILD_OPTION_XR, {278"XRBodyModifier3D",279"XRBodyTracker",280"XRControllerTracker",281"XRFaceModifier3D",282"XRFaceTracker",283"XRHandModifier3D",284"XRHandTracker",285"XRInterface",286"XRInterfaceExtension",287"XRNode3D",288"XROrigin3D",289"XRPose",290"XRPositionalTracker",291"XRServer",292"XRTracker",293"XRVRS",294} },295{ BUILD_OPTION_RENDERING_DEVICE, {296"RenderingDevice",297} },298{ BUILD_OPTION_PHYSICS_2D, {299"CollisionObject2D",300"CollisionPolygon2D",301"CollisionShape2D",302"Joint2D",303"PhysicsServer2D",304"PhysicsServer2DManager",305"ShapeCast2D",306"RayCast2D",307"TouchScreenButton",308} },309{ BUILD_OPTION_PHYSICS_3D, {310"CollisionObject3D",311"CollisionPolygon3D",312"CollisionShape3D",313"CSGShape3D",314"GPUParticlesAttractor3D",315"GPUParticlesCollision3D",316"Joint3D",317"PhysicalBoneSimulator3D",318"PhysicsServer3D",319"PhysicsServer3DManager",320"PhysicsServer3DRenderingServerHandler",321"RayCast3D",322"SoftBody3D",323"SpringArm3D",324"VehicleWheel3D",325} },326{ BUILD_OPTION_TEXT_SERVER_ADVANCED, {327"CanvasItem",328"Label3D",329"TextServerAdvanced",330} },331};332333/* clang-format on */334335void EditorBuildProfile::set_disable_class(const StringName &p_class, bool p_disabled) {336if (p_disabled) {337disabled_classes.insert(p_class);338} else {339disabled_classes.erase(p_class);340}341}342343bool EditorBuildProfile::is_class_disabled(const StringName &p_class) const {344if (p_class == StringName()) {345return false;346}347return disabled_classes.has(p_class) || is_class_disabled(ClassDB::get_parent_class_nocheck(p_class));348}349350void EditorBuildProfile::set_item_collapsed(const StringName &p_class, bool p_collapsed) {351if (p_collapsed) {352collapsed_classes.insert(p_class);353} else {354collapsed_classes.erase(p_class);355}356}357358bool EditorBuildProfile::is_item_collapsed(const StringName &p_class) const {359return collapsed_classes.has(p_class);360}361362void EditorBuildProfile::set_disable_build_option(BuildOption p_build_option, bool p_disable) {363ERR_FAIL_INDEX(p_build_option, BUILD_OPTION_MAX);364build_options_disabled[p_build_option] = p_disable;365}366367void EditorBuildProfile::clear_disabled_classes() {368disabled_classes.clear();369collapsed_classes.clear();370}371372bool EditorBuildProfile::is_build_option_disabled(BuildOption p_build_option) const {373ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, false);374return build_options_disabled[p_build_option];375}376377bool EditorBuildProfile::get_build_option_disable_value(BuildOption p_build_option) {378ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, false);379return build_option_disable_values[p_build_option];380}381382bool EditorBuildProfile::get_build_option_explicit_use(BuildOption p_build_option) {383ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, false);384return build_option_explicit_use[p_build_option];385}386387void EditorBuildProfile::reset_build_options() {388for (int i = 0; i < EditorBuildProfile::BUILD_OPTION_MAX; i++) {389build_options_disabled[i] = build_option_disabled_by_default[i];390}391}392393void EditorBuildProfile::set_force_detect_classes(const String &p_classes) {394force_detect_classes = p_classes;395}396397String EditorBuildProfile::get_force_detect_classes() const {398return force_detect_classes;399}400401String EditorBuildProfile::get_build_option_name(BuildOption p_build_option) {402ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, String());403const char *build_option_names[BUILD_OPTION_MAX] = {404TTRC("3D Engine"),405TTRC("Navigation (2D)"),406TTRC("Navigation (3D)"),407TTRC("Accessibility Support (AccessKit)"),408TTRC("Improved Gamepad Support (SDL)"),409TTRC("XR"),410TTRC("OpenXR"),411TTRC("Wayland"),412TTRC("X11"),413TTRC("PulseAudio"),414TTRC("ALSA"),415TTRC("RenderingDevice"),416TTRC("Forward+ Renderer"),417TTRC("Mobile Renderer"),418TTRC("Vulkan"),419TTRC("D3D12"),420TTRC("Metal"),421TTRC("OpenGL"),422TTRC("Physics Server (2D)"),423TTRC("Godot Physics (2D)"),424TTRC("Physics Server (3D)"),425TTRC("Godot Physics (3D)"),426TTRC("Jolt Physics"),427TTRC("Text Server: Fallback"),428TTRC("Text Server: Advanced"),429TTRC("TTF, OTF, Type 1, WOFF1 Fonts"),430TTRC("WOFF2 Fonts"),431TTRC("SIL Graphite Fonts"),432TTRC("Multi-channel Signed Distance Field Font Rendering"),433};434return TTRGET(build_option_names[p_build_option]);435}436437String EditorBuildProfile::get_build_option_description(BuildOption p_build_option) {438ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, String());439440const char *build_option_descriptions[BUILD_OPTION_MAX] = {441TTRC("3D Nodes as well as RenderingServer access to 3D features.\nNote that the Geometry3D singleton remains available even with this item disabled."),442TTRC("NavigationServer and capabilities for 2D."),443TTRC("NavigationServer and capabilities for 3D."),444TTRC("Support for screen readers using the AccessKit library."),445TTRC("Improved gamepad support on Windows, macOS, and Linux using the SDL library.\nIf disabled, built-in custom code is used for gamepad support instead, which may be less reliable for certain controller models."),446TTRC("XR (AR and VR)."),447TTRC("OpenXR standard implementation (requires XR to be enabled)."),448TTRC("Wayland display server support (Linux only)."),449TTRC("X11 display server support (Linux only)."),450TTRC("PulseAudio audio driver (Linux only)."),451TTRC("ALSA audio driver (Linux only)."),452TTRC("RenderingDevice-based rendering (if disabled, the OpenGL backend is required)."),453TTRC("Forward+ renderer for advanced 3D graphics."),454TTRC("Mobile renderer for less advanced 3D graphics."),455TTRC("Vulkan backend of RenderingDevice."),456TTRC("Direct3D 12 backend of RenderingDevice."),457TTRC("Metal backend of RenderingDevice (Apple arm64 only)."),458TTRC("OpenGL backend (if disabled, the RenderingDevice backend is required)."),459TTRC("PhysicsServer and capabilities for 2D."),460TTRC("Godot Physics backend (2D)."),461TTRC("PhysicsServer and capabilities for 3D."),462TTRC("Godot Physics backend (3D)."),463TTRC("Jolt Physics backend (3D only)."),464TTRC("Fallback implementation of Text Server\nSupports basic text layouts."),465TTRC("Text Server implementation powered by ICU and HarfBuzz libraries.\nSupports complex text layouts, BiDi, and contextual OpenType font features."),466TTRC("TrueType, OpenType, Type 1, and WOFF1 font format support using FreeType library (if disabled, WOFF2 support is also disabled)."),467TTRC("WOFF2 font format support using FreeType and Brotli libraries."),468TTRC("SIL Graphite smart font technology support (supported by Advanced Text Server only)."),469TTRC("Multi-channel signed distance field font rendering support using msdfgen library (pre-rendered MSDF fonts can be used even if this option is disabled)."),470};471472return TTRGET(build_option_descriptions[p_build_option]);473}474475String EditorBuildProfile::get_build_option_identifier(BuildOption p_build_option) {476ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, String());477return build_option_identifiers[p_build_option];478}479480EditorBuildProfile::BuildOptionCategory EditorBuildProfile::get_build_option_category(BuildOption p_build_option) {481ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, BUILD_OPTION_CATEGORY_GENERAL);482return build_option_category[p_build_option];483}484485LocalVector<EditorBuildProfile::BuildOption> EditorBuildProfile::get_build_option_dependencies(BuildOption p_build_option) {486ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, LocalVector<EditorBuildProfile::BuildOption>());487return build_option_dependencies.has(p_build_option) ? LocalVector<EditorBuildProfile::BuildOption>(build_option_dependencies[p_build_option]) : LocalVector<EditorBuildProfile::BuildOption>();488}489490HashMap<String, LocalVector<Variant>> EditorBuildProfile::get_build_option_settings(BuildOption p_build_option) {491ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, (HashMap<String, LocalVector<Variant>>()));492return build_option_settings.has(p_build_option) ? HashMap<String, LocalVector<Variant>>(build_option_settings[p_build_option]) : HashMap<String, LocalVector<Variant>>();493}494495LocalVector<String> EditorBuildProfile::get_build_option_classes(BuildOption p_build_option) {496ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, LocalVector<String>());497return build_option_classes.has(p_build_option) ? LocalVector<String>(build_option_classes[p_build_option]) : LocalVector<String>();498}499500String EditorBuildProfile::get_build_option_category_name(BuildOptionCategory p_build_option_category) {501ERR_FAIL_INDEX_V(p_build_option_category, BUILD_OPTION_CATEGORY_MAX, String());502503const char *build_option_subcategories[BUILD_OPTION_CATEGORY_MAX]{504TTRC("General Features:"),505TTRC("Graphics and Rendering:"),506TTRC("Physics Systems:"),507TTRC("Text Rendering and Font Options:"),508};509510return TTRGET(build_option_subcategories[p_build_option_category]);511}512513Error EditorBuildProfile::save_to_file(const String &p_path) {514Dictionary data;515data["type"] = "build_profile";516Array dis_classes;517for (const StringName &E : disabled_classes) {518dis_classes.push_back(String(E));519}520dis_classes.sort();521data["disabled_classes"] = dis_classes;522523Dictionary dis_build_options;524for (int i = 0; i < BUILD_OPTION_MAX; i++) {525if (build_options_disabled[i] != build_option_disabled_by_default[i]) {526if (build_options_disabled[i]) {527dis_build_options[build_option_identifiers[i]] = build_option_disable_values[i];528} else {529dis_build_options[build_option_identifiers[i]] = !build_option_disable_values[i];530}531}532}533534data["disabled_build_options"] = dis_build_options;535536if (!force_detect_classes.is_empty()) {537data["force_detect_classes"] = force_detect_classes;538}539540Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE);541ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_CREATE, "Cannot create file '" + p_path + "'.");542543String text = JSON::stringify(data, "\t");544f->store_string(text);545return OK;546}547548Error EditorBuildProfile::load_from_file(const String &p_path) {549Error err;550String text = FileAccess::get_file_as_string(p_path, &err);551if (err != OK) {552return err;553}554555JSON json;556err = json.parse(text);557if (err != OK) {558ERR_PRINT("Error parsing '" + p_path + "' on line " + itos(json.get_error_line()) + ": " + json.get_error_message());559return ERR_PARSE_ERROR;560}561562Dictionary data = json.get_data();563564if (!data.has("type") || String(data["type"]) != "build_profile") {565ERR_PRINT("Error parsing '" + p_path + "', it's not a build profile.");566return ERR_PARSE_ERROR;567}568569disabled_classes.clear();570571if (data.has("disabled_classes")) {572Array disabled_classes_arr = data["disabled_classes"];573for (int i = 0; i < disabled_classes_arr.size(); i++) {574disabled_classes.insert(disabled_classes_arr[i]);575}576}577578for (int i = 0; i < BUILD_OPTION_MAX; i++) {579build_options_disabled[i] = build_option_disabled_by_default[i];580}581582if (data.has("disabled_build_options")) {583Dictionary disabled_build_options_arr = data["disabled_build_options"];584585for (const KeyValue<Variant, Variant> &kv : disabled_build_options_arr) {586String key = kv.key;587588for (int i = 0; i < BUILD_OPTION_MAX; i++) {589String f = build_option_identifiers[i];590if (f == key) {591build_options_disabled[i] = true;592break;593}594}595}596}597598if (data.has("force_detect_classes")) {599force_detect_classes = data["force_detect_classes"];600}601602return OK;603}604605void EditorBuildProfile::_bind_methods() {606ClassDB::bind_method(D_METHOD("set_disable_class", "class_name", "disable"), &EditorBuildProfile::set_disable_class);607ClassDB::bind_method(D_METHOD("is_class_disabled", "class_name"), &EditorBuildProfile::is_class_disabled);608609ClassDB::bind_method(D_METHOD("set_disable_build_option", "build_option", "disable"), &EditorBuildProfile::set_disable_build_option);610ClassDB::bind_method(D_METHOD("is_build_option_disabled", "build_option"), &EditorBuildProfile::is_build_option_disabled);611612ClassDB::bind_method(D_METHOD("get_build_option_name", "build_option"), &EditorBuildProfile::_get_build_option_name);613614ClassDB::bind_method(D_METHOD("save_to_file", "path"), &EditorBuildProfile::save_to_file);615ClassDB::bind_method(D_METHOD("load_from_file", "path"), &EditorBuildProfile::load_from_file);616617BIND_ENUM_CONSTANT(BUILD_OPTION_3D);618BIND_ENUM_CONSTANT(BUILD_OPTION_NAVIGATION_2D);619BIND_ENUM_CONSTANT(BUILD_OPTION_NAVIGATION_3D);620BIND_ENUM_CONSTANT(BUILD_OPTION_XR);621BIND_ENUM_CONSTANT(BUILD_OPTION_OPENXR);622BIND_ENUM_CONSTANT(BUILD_OPTION_WAYLAND);623BIND_ENUM_CONSTANT(BUILD_OPTION_X11);624BIND_ENUM_CONSTANT(BUILD_OPTION_RENDERING_DEVICE);625BIND_ENUM_CONSTANT(BUILD_OPTION_FORWARD_RENDERER);626BIND_ENUM_CONSTANT(BUILD_OPTION_MOBILE_RENDERER);627BIND_ENUM_CONSTANT(BUILD_OPTION_VULKAN);628BIND_ENUM_CONSTANT(BUILD_OPTION_D3D12);629BIND_ENUM_CONSTANT(BUILD_OPTION_METAL);630BIND_ENUM_CONSTANT(BUILD_OPTION_OPENGL);631BIND_ENUM_CONSTANT(BUILD_OPTION_PHYSICS_2D);632BIND_ENUM_CONSTANT(BUILD_OPTION_PHYSICS_GODOT_2D);633BIND_ENUM_CONSTANT(BUILD_OPTION_PHYSICS_3D);634BIND_ENUM_CONSTANT(BUILD_OPTION_PHYSICS_GODOT_3D);635BIND_ENUM_CONSTANT(BUILD_OPTION_PHYSICS_JOLT);636BIND_ENUM_CONSTANT(BUILD_OPTION_TEXT_SERVER_FALLBACK);637BIND_ENUM_CONSTANT(BUILD_OPTION_TEXT_SERVER_ADVANCED);638BIND_ENUM_CONSTANT(BUILD_OPTION_DYNAMIC_FONTS);639BIND_ENUM_CONSTANT(BUILD_OPTION_WOFF2_FONTS);640BIND_ENUM_CONSTANT(BUILD_OPTION_GRAPHITE_FONTS);641BIND_ENUM_CONSTANT(BUILD_OPTION_MSDFGEN);642BIND_ENUM_CONSTANT(BUILD_OPTION_MAX);643644BIND_ENUM_CONSTANT(BUILD_OPTION_CATEGORY_GENERAL);645BIND_ENUM_CONSTANT(BUILD_OPTION_CATEGORY_GRAPHICS);646BIND_ENUM_CONSTANT(BUILD_OPTION_CATEGORY_PHYSICS);647BIND_ENUM_CONSTANT(BUILD_OPTION_CATEGORY_TEXT_SERVER);648BIND_ENUM_CONSTANT(BUILD_OPTION_CATEGORY_MAX);649}650651EditorBuildProfile::EditorBuildProfile() {652reset_build_options();653654HashMap<String, LocalVector<Variant>> settings_openxr = {655{ "xr/openxr/enabled", { true } },656};657build_option_settings.insert(BUILD_OPTION_OPENXR, settings_openxr);658659HashMap<String, LocalVector<Variant>> settings_wayland = {660{ "display/display_server/driver.linuxbsd", { "default", "wayland" } },661};662build_option_settings.insert(BUILD_OPTION_WAYLAND, settings_wayland);663664HashMap<String, LocalVector<Variant>> settings_x11 = {665{ "display/display_server/driver.linuxbsd", { "default", "x11" } },666};667build_option_settings.insert(BUILD_OPTION_X11, settings_x11);668669HashMap<String, LocalVector<Variant>> settings_rd = {670{ "rendering/renderer/rendering_method", { "forward_plus", "mobile" } },671{ "rendering/renderer/rendering_method.mobile", { "forward_plus", "mobile" } },672{ "rendering/renderer/rendering_method.web", { "forward_plus", "mobile" } },673};674build_option_settings.insert(BUILD_OPTION_RENDERING_DEVICE, settings_rd);675676HashMap<String, LocalVector<Variant>> settings_vulkan = {677{ "rendering/rendering_device/driver", { "vulkan" } },678{ "rendering/rendering_device/driver.windows", { "vulkan" } },679{ "rendering/rendering_device/driver.linuxbsd", { "vulkan" } },680{ "rendering/rendering_device/driver.android", { "vulkan" } },681{ "rendering/rendering_device/driver.ios", { "vulkan" } },682{ "rendering/rendering_device/driver.macos", { "vulkan" } },683{ "rendering/rendering_device/fallback_to_vulkan", { true } },684};685build_option_settings.insert(BUILD_OPTION_VULKAN, settings_vulkan);686687HashMap<String, LocalVector<Variant>> settings_d3d12 = {688{ "rendering/rendering_device/driver", { "d3d12" } },689{ "rendering/rendering_device/driver.windows", { "d3d12" } },690{ "rendering/rendering_device/driver.linuxbsd", { "d3d12" } },691{ "rendering/rendering_device/driver.android", { "d3d12" } },692{ "rendering/rendering_device/driver.ios", { "d3d12" } },693{ "rendering/rendering_device/driver.macos", { "d3d12" } },694{ "rendering/rendering_device/fallback_to_d3d12", { true } },695};696build_option_settings.insert(BUILD_OPTION_D3D12, settings_d3d12);697698HashMap<String, LocalVector<Variant>> settings_metal = {699{ "rendering/rendering_device/driver", { "metal" } },700{ "rendering/rendering_device/driver.ios", { "metal" } },701{ "rendering/rendering_device/driver.macos", { "metal" } },702};703build_option_settings.insert(BUILD_OPTION_METAL, settings_metal);704705HashMap<String, LocalVector<Variant>> settings_opengl = {706{ "rendering/renderer/rendering_method", { "gl_compatibility" } },707{ "rendering/renderer/rendering_method.mobile", { "gl_compatibility" } },708{ "rendering/renderer/rendering_method.web", { "gl_compatibility" } },709{ "rendering/rendering_device/fallback_to_opengl3", { true } },710};711build_option_settings.insert(BUILD_OPTION_OPENGL, settings_opengl);712713HashMap<String, LocalVector<Variant>> settings_phy_godot_3d = {714{ "physics/3d/physics_engine", { "DEFAULT", "GodotPhysics3D" } },715};716build_option_settings.insert(BUILD_OPTION_PHYSICS_GODOT_3D, settings_phy_godot_3d);717718HashMap<String, LocalVector<Variant>> settings_jolt = {719{ "physics/3d/physics_engine", { "Jolt Physics" } },720};721build_option_settings.insert(BUILD_OPTION_PHYSICS_JOLT, settings_jolt);722723HashMap<String, LocalVector<Variant>> settings_msdfgen = {724{ "gui/theme/default_font_multichannel_signed_distance_field", { true } },725};726build_option_settings.insert(BUILD_OPTION_MSDFGEN, settings_msdfgen);727}728729//////////////////////////730731void EditorBuildProfileManager::_notification(int p_what) {732switch (p_what) {733case NOTIFICATION_READY: {734String last_file = EditorSettings::get_singleton()->get_project_metadata("build_profile", "last_file_path", "");735if (!last_file.is_empty()) {736_import_profile(last_file);737}738if (edited.is_null()) {739edited.instantiate();740_update_edited_profile();741}742743} break;744}745}746747void EditorBuildProfileManager::_profile_action(int p_action) {748last_action = Action(p_action);749750switch (p_action) {751case ACTION_RESET: {752confirm_dialog->set_text(TTR("Reset the edited profile?"));753confirm_dialog->popup_centered();754} break;755case ACTION_LOAD: {756import_profile->popup_file_dialog();757} break;758case ACTION_SAVE: {759if (!profile_path->get_text().is_empty()) {760Error err = edited->save_to_file(profile_path->get_text());761if (err != OK) {762EditorNode::get_singleton()->show_warning(TTR("File saving failed."));763}764break;765}766[[fallthrough]];767}768case ACTION_SAVE_AS: {769export_profile->popup_file_dialog();770export_profile->set_current_file(profile_path->get_text());771} break;772case ACTION_NEW: {773confirm_dialog->set_text(TTR("Create a new profile?"));774confirm_dialog->popup_centered();775} break;776case ACTION_DETECT: {777String 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.");778#ifdef MODULE_MONO_ENABLED779text += "\n\n" + TTR("Warning: Class detection for C# scripts is not currently available, and such files will be ignored.");780#endif // MODULE_MONO_ENABLED781confirm_dialog->set_text(text);782confirm_dialog->popup_centered();783} break;784case ACTION_MAX: {785} break;786}787}788789void EditorBuildProfileManager::_find_files(EditorFileSystemDirectory *p_dir, const HashMap<String, DetectedFile> &p_cache, HashMap<String, DetectedFile> &r_detected) {790if (p_dir == nullptr || p_dir->get_path().get_file().begins_with(".")) {791return;792}793794for (int i = 0; i < p_dir->get_file_count(); i++) {795String p = p_dir->get_file_path(i);796797if (EditorNode::get_singleton()->progress_task_step("detect_classes_from_project", p, 1)) {798project_scan_canceled = true;799return;800}801802String p_check = p;803// Make so that the import file is the one checked if available,804// so the cache can be updated when it changes.805if (ResourceFormatImporter::get_singleton()->exists(p_check)) {806p_check += ".import";807}808809uint64_t timestamp = 0;810String md5;811812if (p_cache.has(p)) {813const DetectedFile &cache = p_cache[p];814// Check if timestamp and MD5 match.815timestamp = FileAccess::get_modified_time(p_check);816bool cache_valid = true;817if (cache.timestamp != timestamp) {818md5 = FileAccess::get_md5(p_check);819if (md5 != cache.md5) {820cache_valid = false;821}822}823824if (cache_valid) {825r_detected.insert(p, cache);826continue;827}828}829830// Not cached, or cache invalid.831832DetectedFile cache;833834HashSet<StringName> classes;835ResourceLoader::get_classes_used(p, &classes);836for (const StringName &E : classes) {837cache.classes.push_back(E);838}839840HashSet<String> build_deps;841ResourceFormatImporter::get_singleton()->get_build_dependencies(p, &build_deps);842for (const String &E : build_deps) {843cache.build_deps.push_back(E);844}845846if (md5.is_empty()) {847cache.timestamp = FileAccess::get_modified_time(p_check);848cache.md5 = FileAccess::get_md5(p_check);849} else {850cache.timestamp = timestamp;851cache.md5 = md5;852}853854r_detected.insert(p, cache);855}856857for (int i = 0; i < p_dir->get_subdir_count(); i++) {858_find_files(p_dir->get_subdir(i), p_cache, r_detected);859}860}861862void EditorBuildProfileManager::_detect_from_project() {863EditorNode::get_singleton()->progress_add_task("detect_classes_from_project", TTRC("Scanning Project for Used Classes"), 3, true);864865HashMap<String, DetectedFile> previous_file_cache;866867Ref<FileAccess> f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().path_join("used_class_cache"), FileAccess::READ);868if (f.is_valid()) {869while (!f->eof_reached()) {870String l = f->get_line();871Vector<String> fields = l.split("::");872if (fields.size() == 5) {873const String &path = fields[0];874DetectedFile df;875df.timestamp = fields[1].to_int();876df.md5 = fields[2];877df.classes = fields[3].split(",", false);878df.build_deps = fields[4].split(",", false);879previous_file_cache.insert(path, df);880}881}882f.unref();883}884885HashMap<String, DetectedFile> updated_file_cache;886887_find_files(EditorFileSystem::get_singleton()->get_filesystem(), previous_file_cache, updated_file_cache);888889if (project_scan_canceled) {890project_scan_canceled = false;891EditorNode::get_singleton()->progress_end_task("detect_classes_from_project");892893return;894}895896EditorNode::get_singleton()->progress_task_step("detect_classes_from_project", TTRC("Processing Classes Found"), 2);897898HashSet<StringName> used_classes;899LocalVector<String> used_build_deps;900901// Find classes and update the disk cache in the process.902f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().path_join("used_class_cache"), FileAccess::WRITE);903904for (const KeyValue<String, DetectedFile> &E : updated_file_cache) {905String l = E.key + "::" + itos(E.value.timestamp) + "::" + E.value.md5 + "::";906for (int i = 0; i < E.value.classes.size(); i++) {907String c = E.value.classes[i];908if (i > 0) {909l += ",";910}911l += c;912used_classes.insert(c);913}914l += "::";915for (int i = 0; i < E.value.build_deps.size(); i++) {916String c = E.value.build_deps[i];917if (i > 0) {918l += ",";919}920l += c;921used_build_deps.push_back(c);922}923f->store_line(l);924}925926f.unref();927928// Add classes that are either necessary for the engine to work properly, or there isn't a way to infer their use.929930// HACK: Some classes are included due to creating clashes with unrelated when disabled.931// Until that is fixed, they need to always be enabled.932const LocalVector<String> hardcoded_classes = {933"Font",934"InputEvent",935"MainLoop",936"Mutex",937"ShaderInclude",938"ShaderIncludeDB",939"StyleBox",940"Time",941"Window",942};943944for (const String &hc_class : hardcoded_classes) {945used_classes.insert(hc_class);946947LocalVector<StringName> inheriters;948ClassDB::get_inheriters_from_class(hc_class, inheriters);949for (const StringName &inheriter : inheriters) {950used_classes.insert(inheriter);951}952}953954// Add forced classes typed by the user.955956const Vector<String> force_detect = edited->get_force_detect_classes().split(",");957for (const String &class_name : force_detect) {958const String class_stripped = class_name.strip_edges();959if (!class_stripped.is_empty()) {960used_classes.insert(class_stripped);961}962}963964// Filter all classes to discard inherited ones.965966HashSet<StringName> all_used_classes;967968for (const StringName &E : used_classes) {969StringName c = E;970if (!ClassDB::class_exists(c)) {971// Maybe this is an old class that got replaced? Try getting compat class.972c = ClassDB::get_compatibility_class(c);973if (!c) {974// No luck, skip.975continue;976}977}978979List<StringName> dependencies;980ClassDB::get_class_dependencies(E, &dependencies);981for (const StringName &dep : dependencies) {982if (!all_used_classes.has(dep)) {983// Add classes which this class depends upon.984all_used_classes.insert(dep);985}986}987988while (c) {989all_used_classes.insert(c);990c = ClassDB::get_parent_class(c);991}992}993994edited->clear_disabled_classes();995996LocalVector<StringName> all_classes;997ClassDB::get_class_list(all_classes);998999for (const StringName &class_name : all_classes) {1000if (String(class_name).begins_with("Editor") || ClassDB::get_api_type(class_name) != ClassDB::API_CORE || all_used_classes.has(class_name)) {1001// This class is valid or editor-only, do nothing.1002continue;1003}10041005StringName p = ClassDB::get_parent_class(class_name);1006if (!p || all_used_classes.has(p)) {1007// If no parent, or if the parent is enabled, then add to disabled classes.1008// This way we avoid disabling redundant classes.1009edited->set_disable_class(class_name, true);1010}1011}10121013edited->reset_build_options();10141015for (int i = 0; i < EditorBuildProfile::BUILD_OPTION_MAX; i++) {1016// Check if the build option requires other options that are currently disabled.1017LocalVector<EditorBuildProfile::BuildOption> dependencies = EditorBuildProfile::get_build_option_dependencies(EditorBuildProfile::BuildOption(i));1018if (!dependencies.is_empty()) {1019bool disable = true;1020for (EditorBuildProfile::BuildOption dependency : dependencies) {1021if (!edited->is_build_option_disabled(dependency)) {1022disable = false;1023break;1024}1025}10261027if (disable) {1028edited->set_disable_build_option(EditorBuildProfile::BuildOption(i), true);1029continue;1030}1031}10321033bool skip = false;1034bool ignore = true;10351036// Check if the build option has enabled classes using it.1037const LocalVector<String> classes = EditorBuildProfile::get_build_option_classes(EditorBuildProfile::BuildOption(i));1038if (!classes.is_empty()) {1039for (StringName class_name : classes) {1040if (!edited->is_class_disabled(class_name)) {1041skip = true;1042break;1043}1044}10451046if (skip) {1047continue;1048}10491050ignore = false;1051}10521053// Check if there's project settings requiring it.1054const HashMap<String, LocalVector<Variant>> settings_list = EditorBuildProfile::get_build_option_settings(EditorBuildProfile::BuildOption(i));1055if (!settings_list.is_empty()) {1056for (KeyValue<String, LocalVector<Variant>> KV : settings_list) {1057Variant proj_value = GLOBAL_GET(KV.key);1058for (Variant value : KV.value) {1059if (proj_value == value) {1060skip = true;1061break;1062}1063}10641065if (skip) {1066break;1067}1068}10691070if (skip) {1071continue;1072}10731074ignore = false;1075}10761077// Check if a resource setting depends on it.1078if (used_build_deps.has(EditorBuildProfile::get_build_option_identifier(EditorBuildProfile::BuildOption(i)))) {1079continue;1080} else if (EditorBuildProfile::get_build_option_explicit_use(EditorBuildProfile::BuildOption(i))) {1081ignore = false;1082}10831084if (!skip && !ignore) {1085edited->set_disable_build_option(EditorBuildProfile::BuildOption(i), true);1086}1087}10881089if (edited->is_build_option_disabled(EditorBuildProfile::BUILD_OPTION_TEXT_SERVER_ADVANCED)) {1090edited->set_disable_build_option(EditorBuildProfile::BUILD_OPTION_TEXT_SERVER_FALLBACK, false);1091}10921093EditorNode::get_singleton()->progress_end_task("detect_classes_from_project");1094}10951096void EditorBuildProfileManager::_action_confirm() {1097switch (last_action) {1098case ACTION_RESET: {1099edited.instantiate();1100_update_edited_profile();1101} break;1102case ACTION_LOAD: {1103} break;1104case ACTION_SAVE: {1105} break;1106case ACTION_SAVE_AS: {1107} break;1108case ACTION_NEW: {1109profile_path->set_text("");1110edited.instantiate();1111_update_edited_profile();1112} break;1113case ACTION_DETECT: {1114_detect_from_project();1115_update_edited_profile();1116} break;1117case ACTION_MAX: {1118} break;1119}1120}11211122void EditorBuildProfileManager::_hide_requested() {1123_cancel_pressed(); // From AcceptDialog.1124}11251126void EditorBuildProfileManager::_fill_classes_from(TreeItem *p_parent, const String &p_class, const String &p_selected) {1127TreeItem *class_item = class_list->create_item(p_parent);1128class_item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);1129class_item->set_icon(0, EditorNode::get_singleton()->get_class_icon(p_class));1130const String &text = p_class;11311132bool disabled = edited->is_class_disabled(p_class);1133if (disabled) {1134class_item->set_custom_color(0, class_list->get_theme_color(SNAME("font_disabled_color"), EditorStringName(Editor)));1135}11361137class_item->set_text(0, text);1138class_item->set_editable(0, true);1139class_item->set_selectable(0, true);1140class_item->set_metadata(0, p_class);11411142bool collapsed = edited->is_item_collapsed(p_class);1143class_item->set_collapsed(collapsed);11441145if (p_class == p_selected) {1146class_item->select(0);1147}1148if (disabled) {1149// Class disabled, do nothing else (do not show further).1150return;1151}11521153class_item->set_checked(0, true); // If it's not disabled, its checked.11541155List<StringName> child_classes;1156ClassDB::get_direct_inheriters_from_class(p_class, &child_classes);1157child_classes.sort_custom<StringName::AlphCompare>();11581159for (const StringName &name : child_classes) {1160if (String(name).begins_with("Editor") || ClassDB::get_api_type(name) != ClassDB::API_CORE) {1161continue;1162}1163_fill_classes_from(class_item, name, p_selected);1164}1165}11661167void EditorBuildProfileManager::_class_list_item_selected() {1168if (updating_build_options) {1169return;1170}11711172TreeItem *item = class_list->get_selected();1173if (!item) {1174return;1175}11761177Variant md = item->get_metadata(0);1178if (md.is_string()) {1179description_bit->parse_symbol("class|" + md.operator String() + "|");1180} else if (md.get_type() == Variant::INT) {1181String build_option_description = EditorBuildProfile::get_build_option_description(EditorBuildProfile::BuildOption((int)md));1182description_bit->set_custom_text(TTR(item->get_text(0)), String(), TTRGET(build_option_description));1183}1184}11851186void EditorBuildProfileManager::_class_list_item_edited() {1187if (updating_build_options) {1188return;1189}11901191TreeItem *item = class_list->get_edited();1192if (!item) {1193return;1194}11951196bool checked = item->is_checked(0);11971198Variant md = item->get_metadata(0);1199if (md.is_string()) {1200String class_selected = md;1201edited->set_disable_class(class_selected, !checked);1202_update_edited_profile();1203} else if (md.get_type() == Variant::INT) {1204int build_option_selected = md;1205edited->set_disable_build_option(EditorBuildProfile::BuildOption(build_option_selected), !checked);1206}1207}12081209void EditorBuildProfileManager::_class_list_item_collapsed(Object *p_item) {1210if (updating_build_options) {1211return;1212}12131214TreeItem *item = Object::cast_to<TreeItem>(p_item);1215if (!item) {1216return;1217}12181219Variant md = item->get_metadata(0);1220if (!md.is_string()) {1221return;1222}12231224String class_name = md;1225bool collapsed = item->is_collapsed();1226edited->set_item_collapsed(class_name, collapsed);1227}12281229void EditorBuildProfileManager::_update_edited_profile() {1230String class_selected;1231int build_option_selected = -1;12321233if (class_list->get_selected()) {1234Variant md = class_list->get_selected()->get_metadata(0);1235if (md.is_string()) {1236class_selected = md;1237} else if (md.get_type() == Variant::INT) {1238build_option_selected = md;1239}1240}12411242class_list->clear();12431244updating_build_options = true;12451246TreeItem *root = class_list->create_item();12471248HashMap<EditorBuildProfile::BuildOptionCategory, TreeItem *> subcats;1249for (int i = 0; i < EditorBuildProfile::BUILD_OPTION_CATEGORY_MAX; i++) {1250TreeItem *build_cat;1251build_cat = class_list->create_item(root);12521253build_cat->set_text(0, EditorBuildProfile::get_build_option_category_name(EditorBuildProfile::BuildOptionCategory(i)));1254subcats[EditorBuildProfile::BuildOptionCategory(i)] = build_cat;1255}12561257for (int i = 0; i < EditorBuildProfile::BUILD_OPTION_MAX; i++) {1258TreeItem *build_option;1259build_option = class_list->create_item(subcats[EditorBuildProfile::get_build_option_category(EditorBuildProfile::BuildOption(i))]);12601261build_option->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);1262build_option->set_text(0, EditorBuildProfile::get_build_option_name(EditorBuildProfile::BuildOption(i)));1263build_option->set_selectable(0, true);1264build_option->set_editable(0, true);1265build_option->set_metadata(0, i);1266if (!edited->is_build_option_disabled(EditorBuildProfile::BuildOption(i))) {1267build_option->set_checked(0, true);1268}12691270if (i == build_option_selected) {1271build_option->select(0);1272}1273}12741275TreeItem *classes = class_list->create_item(root);1276classes->set_text(0, TTR("Nodes and Classes:"));12771278_fill_classes_from(classes, "Node", class_selected);1279_fill_classes_from(classes, "Resource", class_selected);12801281force_detect_classes->set_text(edited->get_force_detect_classes());12821283updating_build_options = false;12841285_class_list_item_selected();1286}12871288void EditorBuildProfileManager::_force_detect_classes_changed(const String &p_text) {1289if (updating_build_options) {1290return;1291}1292edited->set_force_detect_classes(force_detect_classes->get_text());1293}12941295void EditorBuildProfileManager::_import_profile(const String &p_path) {1296Ref<EditorBuildProfile> profile;1297profile.instantiate();1298Error err = profile->load_from_file(p_path);1299String basefile = p_path.get_file();1300if (err != OK) {1301EditorNode::get_singleton()->show_warning(vformat(TTR("File '%s' format is invalid, import aborted."), basefile));1302return;1303}13041305profile_path->set_text(p_path);1306EditorSettings::get_singleton()->set_project_metadata("build_profile", "last_file_path", p_path);13071308edited = profile;1309_update_edited_profile();1310}13111312void EditorBuildProfileManager::_export_profile(const String &p_path) {1313ERR_FAIL_COND(edited.is_null());1314Error err = edited->save_to_file(p_path);1315if (err != OK) {1316EditorNode::get_singleton()->show_warning(vformat(TTR("Error saving profile to path: '%s'."), p_path));1317} else {1318profile_path->set_text(p_path);1319EditorSettings::get_singleton()->set_project_metadata("build_profile", "last_file_path", p_path);1320}1321}13221323Ref<EditorBuildProfile> EditorBuildProfileManager::get_current_profile() {1324return edited;1325}13261327EditorBuildProfileManager *EditorBuildProfileManager::singleton = nullptr;13281329void EditorBuildProfileManager::_bind_methods() {1330ClassDB::bind_method("_update_selected_profile", &EditorBuildProfileManager::_update_edited_profile);1331}13321333EditorBuildProfileManager::EditorBuildProfileManager() {1334VBoxContainer *main_vbc = memnew(VBoxContainer);1335add_child(main_vbc);13361337HBoxContainer *path_hbc = memnew(HBoxContainer);1338profile_path = memnew(LineEdit);1339path_hbc->add_child(profile_path);1340profile_path->set_accessibility_name(TTRC("Profile Path"));1341profile_path->set_editable(true);1342profile_path->set_h_size_flags(Control::SIZE_EXPAND_FILL);13431344profile_actions[ACTION_NEW] = memnew(Button(TTR("New")));1345path_hbc->add_child(profile_actions[ACTION_NEW]);1346profile_actions[ACTION_NEW]->connect(SceneStringName(pressed), callable_mp(this, &EditorBuildProfileManager::_profile_action).bind(ACTION_NEW));13471348profile_actions[ACTION_LOAD] = memnew(Button(TTR("Load")));1349path_hbc->add_child(profile_actions[ACTION_LOAD]);1350profile_actions[ACTION_LOAD]->connect(SceneStringName(pressed), callable_mp(this, &EditorBuildProfileManager::_profile_action).bind(ACTION_LOAD));13511352profile_actions[ACTION_SAVE] = memnew(Button(TTR("Save")));1353path_hbc->add_child(profile_actions[ACTION_SAVE]);1354profile_actions[ACTION_SAVE]->connect(SceneStringName(pressed), callable_mp(this, &EditorBuildProfileManager::_profile_action).bind(ACTION_SAVE));13551356profile_actions[ACTION_SAVE_AS] = memnew(Button(TTR("Save As")));1357path_hbc->add_child(profile_actions[ACTION_SAVE_AS]);1358profile_actions[ACTION_SAVE_AS]->connect(SceneStringName(pressed), callable_mp(this, &EditorBuildProfileManager::_profile_action).bind(ACTION_SAVE_AS));13591360main_vbc->add_margin_child(TTR("Profile:"), path_hbc);13611362main_vbc->add_child(memnew(HSeparator));13631364HBoxContainer *profiles_hbc = memnew(HBoxContainer);13651366profile_actions[ACTION_RESET] = memnew(Button(TTR("Reset to Defaults")));1367profiles_hbc->add_child(profile_actions[ACTION_RESET]);1368profile_actions[ACTION_RESET]->connect(SceneStringName(pressed), callable_mp(this, &EditorBuildProfileManager::_profile_action).bind(ACTION_RESET));13691370profile_actions[ACTION_DETECT] = memnew(Button(TTR("Detect from Project")));1371profiles_hbc->add_child(profile_actions[ACTION_DETECT]);1372profile_actions[ACTION_DETECT]->connect(SceneStringName(pressed), callable_mp(this, &EditorBuildProfileManager::_profile_action).bind(ACTION_DETECT));13731374main_vbc->add_margin_child(TTR("Actions:"), profiles_hbc);13751376class_list = memnew(Tree);1377class_list->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);1378class_list->set_hide_root(true);1379class_list->set_edit_checkbox_cell_only_when_checkbox_is_pressed(true);1380class_list->set_scroll_hint_mode(Tree::SCROLL_HINT_MODE_BOTH);1381class_list->connect("cell_selected", callable_mp(this, &EditorBuildProfileManager::_class_list_item_selected));1382class_list->connect("item_edited", callable_mp(this, &EditorBuildProfileManager::_class_list_item_edited), CONNECT_DEFERRED);1383class_list->connect("item_collapsed", callable_mp(this, &EditorBuildProfileManager::_class_list_item_collapsed));13841385// It will be displayed once the user creates or chooses a profile.1386MarginContainer *mc = main_vbc->add_margin_child(TTRC("Configure Engine Compilation Profile:"), class_list, true);1387mc->set_theme_type_variation("NoBorderHorizontalWindow");1388mc->set_v_size_flags(Control::SIZE_EXPAND_FILL);13891390description_bit = memnew(EditorHelpBit);1391description_bit->set_content_height_limits(80 * EDSCALE, 80 * EDSCALE);1392description_bit->connect("request_hide", callable_mp(this, &EditorBuildProfileManager::_hide_requested));1393main_vbc->add_margin_child(TTR("Description:"), description_bit, false);13941395confirm_dialog = memnew(ConfirmationDialog);1396add_child(confirm_dialog);1397confirm_dialog->set_title(TTR("Please Confirm:"));1398confirm_dialog->connect(SceneStringName(confirmed), callable_mp(this, &EditorBuildProfileManager::_action_confirm));13991400import_profile = memnew(EditorFileDialog);1401add_child(import_profile);1402import_profile->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);1403import_profile->add_filter("*.gdbuild,*.build", TTR("Engine Compilation Profile"));1404import_profile->connect("file_selected", callable_mp(this, &EditorBuildProfileManager::_import_profile));1405import_profile->set_title(TTR("Load Profile"));1406import_profile->set_access(EditorFileDialog::ACCESS_FILESYSTEM);14071408export_profile = memnew(EditorFileDialog);1409add_child(export_profile);1410export_profile->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);1411export_profile->add_filter("*.gdbuild,*.build", TTR("Engine Compilation Profile"));1412export_profile->connect("file_selected", callable_mp(this, &EditorBuildProfileManager::_export_profile));1413export_profile->set_title(TTR("Export Profile"));1414export_profile->set_access(EditorFileDialog::ACCESS_FILESYSTEM);14151416force_detect_classes = memnew(LineEdit);1417force_detect_classes->set_accessibility_name(TTRC("Forced Classes on Detect:"));1418main_vbc->add_margin_child(TTR("Forced Classes on Detect:"), force_detect_classes);1419force_detect_classes->connect(SceneStringName(text_changed), callable_mp(this, &EditorBuildProfileManager::_force_detect_classes_changed));14201421set_title(TTR("Edit Compilation Configuration Profile"));14221423singleton = this;1424}142514261427