editor_build_profile.cpp 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371
  1. /**************************************************************************/
  2. /* editor_build_profile.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /**************************************************************************/
  30. #include "editor_build_profile.h"
  31. #include "core/config/project_settings.h"
  32. #include "core/io/json.h"
  33. #include "editor/editor_node.h"
  34. #include "editor/editor_string_names.h"
  35. #include "editor/file_system/editor_file_system.h"
  36. #include "editor/file_system/editor_paths.h"
  37. #include "editor/gui/editor_file_dialog.h"
  38. #include "editor/settings/editor_settings.h"
  39. #include "editor/themes/editor_scale.h"
  40. #include "scene/gui/line_edit.h"
  41. #include "scene/gui/separator.h"
  42. #include "modules/modules_enabled.gen.h" // For mono.
  43. const char *EditorBuildProfile::build_option_identifiers[BUILD_OPTION_MAX] = {
  44. // This maps to SCons build options.
  45. "disable_3d",
  46. "disable_navigation_2d",
  47. "disable_navigation_3d",
  48. "disable_xr",
  49. "module_openxr_enabled",
  50. "wayland",
  51. "x11",
  52. "rendering_device", // FIXME: There's no scons option to disable rendering device.
  53. "forward_plus_renderer",
  54. "forward_mobile_renderer",
  55. "vulkan",
  56. "d3d12",
  57. "metal",
  58. "opengl3",
  59. "disable_physics_2d",
  60. "module_godot_physics_2d_enabled",
  61. "disable_physics_3d",
  62. "module_godot_physics_3d_enabled",
  63. "module_jolt_physics_enabled",
  64. "module_text_server_fb_enabled",
  65. "module_text_server_adv_enabled",
  66. "module_freetype_enabled",
  67. "brotli",
  68. "graphite",
  69. "module_msdfgen_enabled",
  70. };
  71. const bool EditorBuildProfile::build_option_disabled_by_default[BUILD_OPTION_MAX] = {
  72. // This maps to SCons build options.
  73. false, // 3D
  74. false, // NAVIGATION_2D
  75. false, // NAVIGATION_3D
  76. false, // XR
  77. false, // OPENXR
  78. false, // WAYLAND
  79. false, // X11
  80. false, // RENDERING_DEVICE
  81. false, // FORWARD_RENDERER
  82. false, // MOBILE_RENDERER
  83. false, // VULKAN
  84. false, // D3D12
  85. false, // METAL
  86. false, // OPENGL
  87. false, // PHYSICS_2D
  88. false, // PHYSICS_GODOT_2D
  89. false, // PHYSICS_3D
  90. false, // PHYSICS_GODOT_3D
  91. false, // PHYSICS_JOLT
  92. true, // TEXT_SERVER_FALLBACK
  93. false, // TEXT_SERVER_ADVANCED
  94. false, // DYNAMIC_FONTS
  95. false, // WOFF2_FONTS
  96. false, // GRAPHITE_FONTS
  97. false, // MSDFGEN
  98. };
  99. const bool EditorBuildProfile::build_option_disable_values[BUILD_OPTION_MAX] = {
  100. // This maps to SCons build options.
  101. true, // 3D
  102. true, // NAVIGATION_2D
  103. true, // NAVIGATION_3D
  104. true, // XR
  105. false, // OPENXR
  106. false, // WAYLAND
  107. false, // X11
  108. false, // RENDERING_DEVICE
  109. false, // FORWARD_RENDERER
  110. false, // MOBILE_RENDERER
  111. false, // VULKAN
  112. false, // D3D12
  113. false, // METAL
  114. false, // OPENGL
  115. true, // PHYSICS_2D
  116. false, // PHYSICS_GODOT_2D
  117. true, // PHYSICS_3D
  118. false, // PHYSICS_GODOT_3D
  119. false, // PHYSICS_JOLT
  120. false, // TEXT_SERVER_FALLBACK
  121. false, // TEXT_SERVER_ADVANCED
  122. false, // DYNAMIC_FONTS
  123. false, // WOFF2_FONTS
  124. false, // GRAPHITE_FONTS
  125. false, // MSDFGEN
  126. };
  127. // Options that require some resource explicitly asking for them when detecting from the project.
  128. const bool EditorBuildProfile::build_option_explicit_use[BUILD_OPTION_MAX] = {
  129. false, // 3D
  130. false, // NAVIGATION_2D
  131. false, // NAVIGATION_3D
  132. false, // XR
  133. false, // OPENXR
  134. false, // WAYLAND
  135. false, // X11
  136. false, // RENDERING_DEVICE
  137. false, // FORWARD_RENDERER
  138. false, // MOBILE_RENDERER
  139. false, // VULKAN
  140. false, // D3D12
  141. false, // METAL
  142. false, // OPENGL
  143. false, // PHYSICS_2D
  144. false, // PHYSICS_GODOT_2D
  145. false, // PHYSICS_3D
  146. false, // PHYSICS_GODOT_3D
  147. false, // PHYSICS_JOLT
  148. false, // TEXT_SERVER_FALLBACK
  149. false, // TEXT_SERVER_ADVANCED
  150. false, // DYNAMIC_FONTS
  151. false, // WOFF2_FONTS
  152. false, // GRAPHITE_FONTS
  153. true, // MSDFGEN
  154. };
  155. const EditorBuildProfile::BuildOptionCategory EditorBuildProfile::build_option_category[BUILD_OPTION_MAX] = {
  156. BUILD_OPTION_CATEGORY_GENERAL, // 3D
  157. BUILD_OPTION_CATEGORY_GENERAL, // NAVIGATION_2D
  158. BUILD_OPTION_CATEGORY_GENERAL, // NAVIGATION_3D
  159. BUILD_OPTION_CATEGORY_GENERAL, // XR
  160. BUILD_OPTION_CATEGORY_GENERAL, // OPENXR
  161. BUILD_OPTION_CATEGORY_GENERAL, // WAYLAND
  162. BUILD_OPTION_CATEGORY_GENERAL, // X11
  163. BUILD_OPTION_CATEGORY_GRAPHICS, // RENDERING_DEVICE
  164. BUILD_OPTION_CATEGORY_GRAPHICS, // FORWARD_RENDERER
  165. BUILD_OPTION_CATEGORY_GRAPHICS, // MOBILE_RENDERER
  166. BUILD_OPTION_CATEGORY_GRAPHICS, // VULKAN
  167. BUILD_OPTION_CATEGORY_GRAPHICS, // D3D12
  168. BUILD_OPTION_CATEGORY_GRAPHICS, // METAL
  169. BUILD_OPTION_CATEGORY_GRAPHICS, // OPENGL
  170. BUILD_OPTION_CATEGORY_PHYSICS, // PHYSICS_2D
  171. BUILD_OPTION_CATEGORY_PHYSICS, // PHYSICS_GODOT_2D
  172. BUILD_OPTION_CATEGORY_PHYSICS, // PHYSICS_3D
  173. BUILD_OPTION_CATEGORY_PHYSICS, // PHYSICS_GODOT_3D
  174. BUILD_OPTION_CATEGORY_PHYSICS, // PHYSICS_JOLT
  175. BUILD_OPTION_CATEGORY_TEXT_SERVER, // TEXT_SERVER_FALLBACK
  176. BUILD_OPTION_CATEGORY_TEXT_SERVER, // TEXT_SERVER_ADVANCED
  177. BUILD_OPTION_CATEGORY_TEXT_SERVER, // DYNAMIC_FONTS
  178. BUILD_OPTION_CATEGORY_TEXT_SERVER, // WOFF2_FONTS
  179. BUILD_OPTION_CATEGORY_TEXT_SERVER, // GRAPHITE_FONTS
  180. BUILD_OPTION_CATEGORY_TEXT_SERVER, // MSDFGEN
  181. };
  182. // Can't assign HashMaps to a HashMap at declaration, so do it in the class' constructor.
  183. HashMap<EditorBuildProfile::BuildOption, HashMap<String, LocalVector<Variant>>> EditorBuildProfile::build_option_settings = {};
  184. /* clang-format off */
  185. const HashMap<EditorBuildProfile::BuildOption, LocalVector<EditorBuildProfile::BuildOption>> EditorBuildProfile::build_option_dependencies = {
  186. { BUILD_OPTION_OPENXR, {
  187. BUILD_OPTION_XR,
  188. } },
  189. { BUILD_OPTION_FORWARD_RENDERER, {
  190. BUILD_OPTION_RENDERING_DEVICE,
  191. } },
  192. { BUILD_OPTION_MOBILE_RENDERER, {
  193. BUILD_OPTION_RENDERING_DEVICE,
  194. } },
  195. { BUILD_OPTION_VULKAN, {
  196. BUILD_OPTION_FORWARD_RENDERER,
  197. BUILD_OPTION_MOBILE_RENDERER,
  198. } },
  199. { BUILD_OPTION_D3D12, {
  200. BUILD_OPTION_FORWARD_RENDERER,
  201. BUILD_OPTION_MOBILE_RENDERER,
  202. } },
  203. { BUILD_OPTION_METAL, {
  204. BUILD_OPTION_FORWARD_RENDERER,
  205. BUILD_OPTION_MOBILE_RENDERER,
  206. } },
  207. { BUILD_OPTION_PHYSICS_GODOT_2D, {
  208. BUILD_OPTION_PHYSICS_2D,
  209. } },
  210. { BUILD_OPTION_PHYSICS_GODOT_3D, {
  211. BUILD_OPTION_PHYSICS_3D,
  212. } },
  213. { BUILD_OPTION_PHYSICS_JOLT, {
  214. BUILD_OPTION_PHYSICS_3D,
  215. } },
  216. { BUILD_OPTION_DYNAMIC_FONTS, {
  217. BUILD_OPTION_TEXT_SERVER_ADVANCED,
  218. } },
  219. { BUILD_OPTION_WOFF2_FONTS, {
  220. BUILD_OPTION_TEXT_SERVER_ADVANCED,
  221. } },
  222. { BUILD_OPTION_GRAPHITE_FONTS, {
  223. BUILD_OPTION_TEXT_SERVER_ADVANCED,
  224. } },
  225. };
  226. const HashMap<EditorBuildProfile::BuildOption, LocalVector<String>> EditorBuildProfile::build_option_classes = {
  227. { BUILD_OPTION_3D, {
  228. "Node3D",
  229. } },
  230. { BUILD_OPTION_NAVIGATION_2D, {
  231. "NavigationAgent2D",
  232. "NavigationLink2D",
  233. "NavigationMeshSourceGeometryData2D",
  234. "NavigationObstacle2D"
  235. "NavigationPolygon",
  236. "NavigationRegion2D",
  237. } },
  238. { BUILD_OPTION_NAVIGATION_3D, {
  239. "NavigationAgent3D",
  240. "NavigationLink3D",
  241. "NavigationMeshSourceGeometryData3D",
  242. "NavigationObstacle3D",
  243. "NavigationRegion3D",
  244. } },
  245. { BUILD_OPTION_XR, {
  246. "XRBodyModifier3D",
  247. "XRBodyTracker",
  248. "XRControllerTracker",
  249. "XRFaceModifier3D",
  250. "XRFaceTracker",
  251. "XRHandModifier3D",
  252. "XRHandTracker",
  253. "XRInterface",
  254. "XRInterfaceExtension",
  255. "XRNode3D",
  256. "XROrigin3D",
  257. "XRPose",
  258. "XRPositionalTracker",
  259. "XRServer",
  260. "XRTracker",
  261. "XRVRS",
  262. } },
  263. { BUILD_OPTION_RENDERING_DEVICE, {
  264. "RenderingDevice",
  265. } },
  266. { BUILD_OPTION_PHYSICS_2D, {
  267. "CollisionObject2D",
  268. "CollisionPolygon2D",
  269. "CollisionShape2D",
  270. "Joint2D",
  271. "PhysicsServer2D",
  272. "PhysicsServer2DManager",
  273. "ShapeCast2D",
  274. "RayCast2D",
  275. "TouchScreenButton",
  276. } },
  277. { BUILD_OPTION_PHYSICS_3D, {
  278. "CollisionObject3D",
  279. "CollisionPolygon3D",
  280. "CollisionShape3D",
  281. "CSGShape3D",
  282. "GPUParticlesAttractor3D",
  283. "GPUParticlesCollision3D",
  284. "Joint3D",
  285. "PhysicalBoneSimulator3D",
  286. "PhysicsServer3D",
  287. "PhysicsServer3DManager",
  288. "PhysicsServer3DRenderingServerHandler",
  289. "RayCast3D",
  290. "SoftBody3D",
  291. "SpringArm3D",
  292. "SpringBoneCollision3D",
  293. "SpringBoneSimulator3D",
  294. "VehicleWheel3D",
  295. } },
  296. { BUILD_OPTION_TEXT_SERVER_ADVANCED, {
  297. "CanvasItem",
  298. "Label3D",
  299. "TextServerAdvanced",
  300. } },
  301. };
  302. /* clang-format on */
  303. void EditorBuildProfile::set_disable_class(const StringName &p_class, bool p_disabled) {
  304. if (p_disabled) {
  305. disabled_classes.insert(p_class);
  306. } else {
  307. disabled_classes.erase(p_class);
  308. }
  309. }
  310. bool EditorBuildProfile::is_class_disabled(const StringName &p_class) const {
  311. if (p_class == StringName()) {
  312. return false;
  313. }
  314. return disabled_classes.has(p_class) || is_class_disabled(ClassDB::get_parent_class_nocheck(p_class));
  315. }
  316. void EditorBuildProfile::set_item_collapsed(const StringName &p_class, bool p_collapsed) {
  317. if (p_collapsed) {
  318. collapsed_classes.insert(p_class);
  319. } else {
  320. collapsed_classes.erase(p_class);
  321. }
  322. }
  323. bool EditorBuildProfile::is_item_collapsed(const StringName &p_class) const {
  324. return collapsed_classes.has(p_class);
  325. }
  326. void EditorBuildProfile::set_disable_build_option(BuildOption p_build_option, bool p_disable) {
  327. ERR_FAIL_INDEX(p_build_option, BUILD_OPTION_MAX);
  328. build_options_disabled[p_build_option] = p_disable;
  329. }
  330. void EditorBuildProfile::clear_disabled_classes() {
  331. disabled_classes.clear();
  332. collapsed_classes.clear();
  333. }
  334. bool EditorBuildProfile::is_build_option_disabled(BuildOption p_build_option) const {
  335. ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, false);
  336. return build_options_disabled[p_build_option];
  337. }
  338. bool EditorBuildProfile::get_build_option_disable_value(BuildOption p_build_option) {
  339. ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, false);
  340. return build_option_disable_values[p_build_option];
  341. }
  342. bool EditorBuildProfile::get_build_option_explicit_use(BuildOption p_build_option) {
  343. ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, false);
  344. return build_option_explicit_use[p_build_option];
  345. }
  346. void EditorBuildProfile::reset_build_options() {
  347. for (int i = 0; i < EditorBuildProfile::BUILD_OPTION_MAX; i++) {
  348. build_options_disabled[i] = build_option_disabled_by_default[i];
  349. }
  350. }
  351. void EditorBuildProfile::set_force_detect_classes(const String &p_classes) {
  352. force_detect_classes = p_classes;
  353. }
  354. String EditorBuildProfile::get_force_detect_classes() const {
  355. return force_detect_classes;
  356. }
  357. String EditorBuildProfile::get_build_option_name(BuildOption p_build_option) {
  358. ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, String());
  359. const char *build_option_names[BUILD_OPTION_MAX] = {
  360. TTRC("3D Engine"),
  361. TTRC("Navigation (2D)"),
  362. TTRC("Navigation (3D)"),
  363. TTRC("XR"),
  364. TTRC("OpenXR"),
  365. TTRC("Wayland"),
  366. TTRC("X11"),
  367. TTRC("RenderingDevice"),
  368. TTRC("Forward+ Renderer"),
  369. TTRC("Mobile Renderer"),
  370. TTRC("Vulkan"),
  371. TTRC("D3D12"),
  372. TTRC("Metal"),
  373. TTRC("OpenGL"),
  374. TTRC("Physics Server (2D)"),
  375. TTRC("Godot Physics (2D)"),
  376. TTRC("Physics Server (3D)"),
  377. TTRC("Godot Physics (3D)"),
  378. TTRC("Jolt Physics"),
  379. TTRC("Text Server: Fallback"),
  380. TTRC("Text Server: Advanced"),
  381. TTRC("TTF, OTF, Type 1, WOFF1 Fonts"),
  382. TTRC("WOFF2 Fonts"),
  383. TTRC("SIL Graphite Fonts"),
  384. TTRC("Multi-channel Signed Distance Field Font Rendering"),
  385. };
  386. return TTRGET(build_option_names[p_build_option]);
  387. }
  388. String EditorBuildProfile::get_build_option_description(BuildOption p_build_option) {
  389. ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, String());
  390. const char *build_option_descriptions[BUILD_OPTION_MAX] = {
  391. TTRC("3D Nodes as well as RenderingServer access to 3D features."),
  392. TTRC("Navigation Server and capabilities for 2D."),
  393. TTRC("Navigation Server and capabilities for 3D."),
  394. TTRC("XR (AR and VR)."),
  395. TTRC("OpenXR standard implementation (requires XR to be enabled)."),
  396. TTRC("Wayland display (Linux only)."),
  397. TTRC("X11 display (Linux only)."),
  398. TTRC("RenderingDevice based rendering (if disabled, the OpenGL backend is required)."),
  399. TTRC("Forward+ renderer for advanced 3D graphics."),
  400. TTRC("Mobile renderer for less advanced 3D graphics."),
  401. TTRC("Vulkan backend of RenderingDevice."),
  402. TTRC("Direct3D 12 backend of RenderingDevice."),
  403. TTRC("Metal backend of RenderingDevice (Apple arm64 only)."),
  404. TTRC("OpenGL backend (if disabled, the RenderingDevice backend is required)."),
  405. TTRC("Physics Server and capabilities for 2D."),
  406. TTRC("Godot Physics backend (2D)."),
  407. TTRC("Physics Server and capabilities for 3D."),
  408. TTRC("Godot Physics backend (3D)."),
  409. TTRC("Jolt Physics backend (3D only)."),
  410. TTRC("Fallback implementation of Text Server\nSupports basic text layouts."),
  411. TTRC("Text Server implementation powered by ICU and HarfBuzz libraries.\nSupports complex text layouts, BiDi, and contextual OpenType font features."),
  412. TTRC("TrueType, OpenType, Type 1, and WOFF1 font format support using FreeType library (if disabled, WOFF2 support is also disabled)."),
  413. TTRC("WOFF2 font format support using FreeType and Brotli libraries."),
  414. TTRC("SIL Graphite smart font technology support (supported by Advanced Text Server only)."),
  415. TTRC("Multi-channel signed distance field font rendering support using msdfgen library (pre-rendered MSDF fonts can be used even if this option disabled)."),
  416. };
  417. return TTRGET(build_option_descriptions[p_build_option]);
  418. }
  419. String EditorBuildProfile::get_build_option_identifier(BuildOption p_build_option) {
  420. ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, String());
  421. return build_option_identifiers[p_build_option];
  422. }
  423. EditorBuildProfile::BuildOptionCategory EditorBuildProfile::get_build_option_category(BuildOption p_build_option) {
  424. ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, BUILD_OPTION_CATEGORY_GENERAL);
  425. return build_option_category[p_build_option];
  426. }
  427. LocalVector<EditorBuildProfile::BuildOption> EditorBuildProfile::get_build_option_dependencies(BuildOption p_build_option) {
  428. ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, LocalVector<EditorBuildProfile::BuildOption>());
  429. return build_option_dependencies.has(p_build_option) ? build_option_dependencies[p_build_option] : LocalVector<EditorBuildProfile::BuildOption>();
  430. }
  431. HashMap<String, LocalVector<Variant>> EditorBuildProfile::get_build_option_settings(BuildOption p_build_option) {
  432. ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, (HashMap<String, LocalVector<Variant>>()));
  433. return build_option_settings.has(p_build_option) ? build_option_settings[p_build_option] : HashMap<String, LocalVector<Variant>>();
  434. }
  435. LocalVector<String> EditorBuildProfile::get_build_option_classes(BuildOption p_build_option) {
  436. ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, LocalVector<String>());
  437. return build_option_classes.has(p_build_option) ? build_option_classes[p_build_option] : LocalVector<String>();
  438. }
  439. String EditorBuildProfile::get_build_option_category_name(BuildOptionCategory p_build_option_category) {
  440. ERR_FAIL_INDEX_V(p_build_option_category, BUILD_OPTION_CATEGORY_MAX, String());
  441. const char *build_option_subcategories[BUILD_OPTION_CATEGORY_MAX]{
  442. TTRC("General Features:"),
  443. TTRC("Graphics and Rendering:"),
  444. TTRC("Physics Systems:"),
  445. TTRC("Text Rendering and Font Options:"),
  446. };
  447. return TTRGET(build_option_subcategories[p_build_option_category]);
  448. }
  449. Error EditorBuildProfile::save_to_file(const String &p_path) {
  450. Dictionary data;
  451. data["type"] = "build_profile";
  452. Array dis_classes;
  453. for (const StringName &E : disabled_classes) {
  454. dis_classes.push_back(String(E));
  455. }
  456. dis_classes.sort();
  457. data["disabled_classes"] = dis_classes;
  458. Dictionary dis_build_options;
  459. for (int i = 0; i < BUILD_OPTION_MAX; i++) {
  460. if (build_options_disabled[i] != build_option_disabled_by_default[i]) {
  461. if (build_options_disabled[i]) {
  462. dis_build_options[build_option_identifiers[i]] = build_option_disable_values[i];
  463. } else {
  464. dis_build_options[build_option_identifiers[i]] = !build_option_disable_values[i];
  465. }
  466. }
  467. }
  468. data["disabled_build_options"] = dis_build_options;
  469. if (!force_detect_classes.is_empty()) {
  470. data["force_detect_classes"] = force_detect_classes;
  471. }
  472. Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE);
  473. ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_CREATE, "Cannot create file '" + p_path + "'.");
  474. String text = JSON::stringify(data, "\t");
  475. f->store_string(text);
  476. return OK;
  477. }
  478. Error EditorBuildProfile::load_from_file(const String &p_path) {
  479. Error err;
  480. String text = FileAccess::get_file_as_string(p_path, &err);
  481. if (err != OK) {
  482. return err;
  483. }
  484. JSON json;
  485. err = json.parse(text);
  486. if (err != OK) {
  487. ERR_PRINT("Error parsing '" + p_path + "' on line " + itos(json.get_error_line()) + ": " + json.get_error_message());
  488. return ERR_PARSE_ERROR;
  489. }
  490. Dictionary data = json.get_data();
  491. if (!data.has("type") || String(data["type"]) != "build_profile") {
  492. ERR_PRINT("Error parsing '" + p_path + "', it's not a build profile.");
  493. return ERR_PARSE_ERROR;
  494. }
  495. disabled_classes.clear();
  496. if (data.has("disabled_classes")) {
  497. Array disabled_classes_arr = data["disabled_classes"];
  498. for (int i = 0; i < disabled_classes_arr.size(); i++) {
  499. disabled_classes.insert(disabled_classes_arr[i]);
  500. }
  501. }
  502. for (int i = 0; i < BUILD_OPTION_MAX; i++) {
  503. build_options_disabled[i] = build_option_disabled_by_default[i];
  504. }
  505. if (data.has("disabled_build_options")) {
  506. Dictionary disabled_build_options_arr = data["disabled_build_options"];
  507. for (const KeyValue<Variant, Variant> &kv : disabled_build_options_arr) {
  508. String key = kv.key;
  509. for (int i = 0; i < BUILD_OPTION_MAX; i++) {
  510. String f = build_option_identifiers[i];
  511. if (f == key) {
  512. build_options_disabled[i] = true;
  513. break;
  514. }
  515. }
  516. }
  517. }
  518. if (data.has("force_detect_classes")) {
  519. force_detect_classes = data["force_detect_classes"];
  520. }
  521. return OK;
  522. }
  523. void EditorBuildProfile::_bind_methods() {
  524. ClassDB::bind_method(D_METHOD("set_disable_class", "class_name", "disable"), &EditorBuildProfile::set_disable_class);
  525. ClassDB::bind_method(D_METHOD("is_class_disabled", "class_name"), &EditorBuildProfile::is_class_disabled);
  526. ClassDB::bind_method(D_METHOD("set_disable_build_option", "build_option", "disable"), &EditorBuildProfile::set_disable_build_option);
  527. ClassDB::bind_method(D_METHOD("is_build_option_disabled", "build_option"), &EditorBuildProfile::is_build_option_disabled);
  528. ClassDB::bind_method(D_METHOD("get_build_option_name", "build_option"), &EditorBuildProfile::_get_build_option_name);
  529. ClassDB::bind_method(D_METHOD("save_to_file", "path"), &EditorBuildProfile::save_to_file);
  530. ClassDB::bind_method(D_METHOD("load_from_file", "path"), &EditorBuildProfile::load_from_file);
  531. BIND_ENUM_CONSTANT(BUILD_OPTION_3D);
  532. BIND_ENUM_CONSTANT(BUILD_OPTION_NAVIGATION_2D);
  533. BIND_ENUM_CONSTANT(BUILD_OPTION_NAVIGATION_3D);
  534. BIND_ENUM_CONSTANT(BUILD_OPTION_XR);
  535. BIND_ENUM_CONSTANT(BUILD_OPTION_OPENXR);
  536. BIND_ENUM_CONSTANT(BUILD_OPTION_WAYLAND);
  537. BIND_ENUM_CONSTANT(BUILD_OPTION_X11);
  538. BIND_ENUM_CONSTANT(BUILD_OPTION_RENDERING_DEVICE);
  539. BIND_ENUM_CONSTANT(BUILD_OPTION_FORWARD_RENDERER);
  540. BIND_ENUM_CONSTANT(BUILD_OPTION_MOBILE_RENDERER);
  541. BIND_ENUM_CONSTANT(BUILD_OPTION_VULKAN);
  542. BIND_ENUM_CONSTANT(BUILD_OPTION_D3D12);
  543. BIND_ENUM_CONSTANT(BUILD_OPTION_METAL);
  544. BIND_ENUM_CONSTANT(BUILD_OPTION_OPENGL);
  545. BIND_ENUM_CONSTANT(BUILD_OPTION_PHYSICS_2D);
  546. BIND_ENUM_CONSTANT(BUILD_OPTION_PHYSICS_GODOT_2D);
  547. BIND_ENUM_CONSTANT(BUILD_OPTION_PHYSICS_3D);
  548. BIND_ENUM_CONSTANT(BUILD_OPTION_PHYSICS_GODOT_3D);
  549. BIND_ENUM_CONSTANT(BUILD_OPTION_PHYSICS_JOLT);
  550. BIND_ENUM_CONSTANT(BUILD_OPTION_TEXT_SERVER_FALLBACK);
  551. BIND_ENUM_CONSTANT(BUILD_OPTION_TEXT_SERVER_ADVANCED);
  552. BIND_ENUM_CONSTANT(BUILD_OPTION_DYNAMIC_FONTS);
  553. BIND_ENUM_CONSTANT(BUILD_OPTION_WOFF2_FONTS);
  554. BIND_ENUM_CONSTANT(BUILD_OPTION_GRAPHITE_FONTS);
  555. BIND_ENUM_CONSTANT(BUILD_OPTION_MSDFGEN);
  556. BIND_ENUM_CONSTANT(BUILD_OPTION_MAX);
  557. BIND_ENUM_CONSTANT(BUILD_OPTION_CATEGORY_GENERAL);
  558. BIND_ENUM_CONSTANT(BUILD_OPTION_CATEGORY_GRAPHICS);
  559. BIND_ENUM_CONSTANT(BUILD_OPTION_CATEGORY_PHYSICS);
  560. BIND_ENUM_CONSTANT(BUILD_OPTION_CATEGORY_TEXT_SERVER);
  561. BIND_ENUM_CONSTANT(BUILD_OPTION_CATEGORY_MAX);
  562. }
  563. EditorBuildProfile::EditorBuildProfile() {
  564. reset_build_options();
  565. HashMap<String, LocalVector<Variant>> settings_openxr = {
  566. { "xr/openxr/enabled", { true } },
  567. };
  568. build_option_settings.insert(BUILD_OPTION_OPENXR, settings_openxr);
  569. HashMap<String, LocalVector<Variant>> settings_wayland = {
  570. { "display/display_server/driver.linuxbsd", { "default", "wayland" } },
  571. };
  572. build_option_settings.insert(BUILD_OPTION_OPENXR, settings_wayland);
  573. HashMap<String, LocalVector<Variant>> settings_x11 = {
  574. { "display/display_server/driver.linuxbsd", { "default", "x11" } },
  575. };
  576. build_option_settings.insert(BUILD_OPTION_OPENXR, settings_x11);
  577. HashMap<String, LocalVector<Variant>> settings_rd = {
  578. { "rendering/renderer/rendering_method", { "forward_plus", "mobile" } },
  579. { "rendering/renderer/rendering_method.mobile", { "forward_plus", "mobile" } },
  580. { "rendering/renderer/rendering_method.web", { "forward_plus", "mobile" } },
  581. };
  582. build_option_settings.insert(BUILD_OPTION_RENDERING_DEVICE, settings_rd);
  583. HashMap<String, LocalVector<Variant>> settings_vulkan = {
  584. { "rendering/rendering_device/driver", { "vulkan" } },
  585. { "rendering/rendering_device/driver.windows", { "vulkan" } },
  586. { "rendering/rendering_device/driver.linuxbsd", { "vulkan" } },
  587. { "rendering/rendering_device/driver.android", { "vulkan" } },
  588. { "rendering/rendering_device/driver.ios", { "vulkan" } },
  589. { "rendering/rendering_device/driver.macos", { "vulkan" } },
  590. { "rendering/rendering_device/fallback_to_vulkan", { true } },
  591. };
  592. build_option_settings.insert(BUILD_OPTION_VULKAN, settings_vulkan);
  593. HashMap<String, LocalVector<Variant>> settings_d3d12 = {
  594. { "rendering/rendering_device/driver", { "d3d12" } },
  595. { "rendering/rendering_device/driver.windows", { "d3d12" } },
  596. { "rendering/rendering_device/driver.linuxbsd", { "d3d12" } },
  597. { "rendering/rendering_device/driver.android", { "d3d12" } },
  598. { "rendering/rendering_device/driver.ios", { "d3d12" } },
  599. { "rendering/rendering_device/driver.macos", { "d3d12" } },
  600. { "rendering/rendering_device/fallback_to_d3d12", { true } },
  601. };
  602. build_option_settings.insert(BUILD_OPTION_VULKAN, settings_vulkan);
  603. HashMap<String, LocalVector<Variant>> settings_metal = {
  604. { "rendering/rendering_device/driver", { "metal" } },
  605. { "rendering/rendering_device/driver.ios", { "metal" } },
  606. { "rendering/rendering_device/driver.macos", { "metal" } },
  607. };
  608. build_option_settings.insert(BUILD_OPTION_METAL, settings_metal);
  609. HashMap<String, LocalVector<Variant>> settings_opengl = {
  610. { "rendering/renderer/rendering_method", { "gl_compatibility" } },
  611. { "rendering/renderer/rendering_method.mobile", { "gl_compatibility" } },
  612. { "rendering/renderer/rendering_method.web", { "gl_compatibility" } },
  613. { "rendering/rendering_device/fallback_to_opengl3", { true } },
  614. };
  615. build_option_settings.insert(BUILD_OPTION_OPENGL, settings_opengl);
  616. HashMap<String, LocalVector<Variant>> settings_phy_godot_3d = {
  617. { "physics/3d/physics_engine", { "DEFAULT", "GodotPhysics3D" } },
  618. };
  619. build_option_settings.insert(BUILD_OPTION_PHYSICS_GODOT_3D, settings_phy_godot_3d);
  620. HashMap<String, LocalVector<Variant>> settings_jolt = {
  621. { "physics/3d/physics_engine", { "Jolt Physics" } },
  622. };
  623. build_option_settings.insert(BUILD_OPTION_PHYSICS_JOLT, settings_jolt);
  624. HashMap<String, LocalVector<Variant>> settings_msdfgen = {
  625. { "gui/theme/default_font_multichannel_signed_distance_field", { true } },
  626. };
  627. build_option_settings.insert(BUILD_OPTION_MSDFGEN, settings_msdfgen);
  628. }
  629. //////////////////////////
  630. void EditorBuildProfileManager::_notification(int p_what) {
  631. switch (p_what) {
  632. case NOTIFICATION_READY: {
  633. String last_file = EditorSettings::get_singleton()->get_project_metadata("build_profile", "last_file_path", "");
  634. if (!last_file.is_empty()) {
  635. _import_profile(last_file);
  636. }
  637. if (edited.is_null()) {
  638. edited.instantiate();
  639. _update_edited_profile();
  640. }
  641. } break;
  642. }
  643. }
  644. void EditorBuildProfileManager::_profile_action(int p_action) {
  645. last_action = Action(p_action);
  646. switch (p_action) {
  647. case ACTION_RESET: {
  648. confirm_dialog->set_text(TTR("Reset the edited profile?"));
  649. confirm_dialog->popup_centered();
  650. } break;
  651. case ACTION_LOAD: {
  652. import_profile->popup_file_dialog();
  653. } break;
  654. case ACTION_SAVE: {
  655. if (!profile_path->get_text().is_empty()) {
  656. Error err = edited->save_to_file(profile_path->get_text());
  657. if (err != OK) {
  658. EditorNode::get_singleton()->show_warning(TTR("File saving failed."));
  659. }
  660. break;
  661. }
  662. [[fallthrough]];
  663. }
  664. case ACTION_SAVE_AS: {
  665. export_profile->popup_file_dialog();
  666. export_profile->set_current_file(profile_path->get_text());
  667. } break;
  668. case ACTION_NEW: {
  669. confirm_dialog->set_text(TTR("Create a new profile?"));
  670. confirm_dialog->popup_centered();
  671. } break;
  672. case ACTION_DETECT: {
  673. 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.");
  674. #ifdef MODULE_MONO_ENABLED
  675. text += "\n\n" + TTR("Warning: Class detection for C# scripts is not currently available, and such files will be ignored.");
  676. #endif // MODULE_MONO_ENABLED
  677. confirm_dialog->set_text(text);
  678. confirm_dialog->popup_centered();
  679. } break;
  680. case ACTION_MAX: {
  681. } break;
  682. }
  683. }
  684. void EditorBuildProfileManager::_find_files(EditorFileSystemDirectory *p_dir, const HashMap<String, DetectedFile> &p_cache, HashMap<String, DetectedFile> &r_detected) {
  685. if (p_dir == nullptr || p_dir->get_path().get_file().begins_with(".")) {
  686. return;
  687. }
  688. for (int i = 0; i < p_dir->get_file_count(); i++) {
  689. String p = p_dir->get_file_path(i);
  690. if (EditorNode::get_singleton()->progress_task_step("detect_classes_from_project", p, 1)) {
  691. project_scan_canceled = true;
  692. return;
  693. }
  694. String p_check = p;
  695. // Make so that the import file is the one checked if available,
  696. // so the cache can be updated when it changes.
  697. if (ResourceFormatImporter::get_singleton()->exists(p_check)) {
  698. p_check += ".import";
  699. }
  700. uint64_t timestamp = 0;
  701. String md5;
  702. if (p_cache.has(p)) {
  703. const DetectedFile &cache = p_cache[p];
  704. // Check if timestamp and MD5 match.
  705. timestamp = FileAccess::get_modified_time(p_check);
  706. bool cache_valid = true;
  707. if (cache.timestamp != timestamp) {
  708. md5 = FileAccess::get_md5(p_check);
  709. if (md5 != cache.md5) {
  710. cache_valid = false;
  711. }
  712. }
  713. if (cache_valid) {
  714. r_detected.insert(p, cache);
  715. continue;
  716. }
  717. }
  718. // Not cached, or cache invalid.
  719. DetectedFile cache;
  720. HashSet<StringName> classes;
  721. ResourceLoader::get_classes_used(p, &classes);
  722. for (const StringName &E : classes) {
  723. cache.classes.push_back(E);
  724. }
  725. HashSet<String> build_deps;
  726. ResourceFormatImporter::get_singleton()->get_build_dependencies(p, &build_deps);
  727. for (const String &E : build_deps) {
  728. cache.build_deps.push_back(E);
  729. }
  730. if (md5.is_empty()) {
  731. cache.timestamp = FileAccess::get_modified_time(p_check);
  732. cache.md5 = FileAccess::get_md5(p_check);
  733. } else {
  734. cache.timestamp = timestamp;
  735. cache.md5 = md5;
  736. }
  737. r_detected.insert(p, cache);
  738. }
  739. for (int i = 0; i < p_dir->get_subdir_count(); i++) {
  740. _find_files(p_dir->get_subdir(i), p_cache, r_detected);
  741. }
  742. }
  743. void EditorBuildProfileManager::_detect_from_project() {
  744. EditorNode::get_singleton()->progress_add_task("detect_classes_from_project", TTRC("Scanning Project for Used Classes"), 3, true);
  745. HashMap<String, DetectedFile> previous_file_cache;
  746. Ref<FileAccess> f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().path_join("used_class_cache"), FileAccess::READ);
  747. if (f.is_valid()) {
  748. while (!f->eof_reached()) {
  749. String l = f->get_line();
  750. Vector<String> fields = l.split("::");
  751. if (fields.size() == 5) {
  752. const String &path = fields[0];
  753. DetectedFile df;
  754. df.timestamp = fields[1].to_int();
  755. df.md5 = fields[2];
  756. df.classes = fields[3].split(",", false);
  757. df.build_deps = fields[4].split(",", false);
  758. previous_file_cache.insert(path, df);
  759. }
  760. }
  761. f.unref();
  762. }
  763. HashMap<String, DetectedFile> updated_file_cache;
  764. _find_files(EditorFileSystem::get_singleton()->get_filesystem(), previous_file_cache, updated_file_cache);
  765. if (project_scan_canceled) {
  766. project_scan_canceled = false;
  767. EditorNode::get_singleton()->progress_end_task("detect_classes_from_project");
  768. return;
  769. }
  770. EditorNode::get_singleton()->progress_task_step("detect_classes_from_project", TTRC("Processing Classes Found"), 2);
  771. HashSet<StringName> used_classes;
  772. LocalVector<String> used_build_deps;
  773. // Find classes and update the disk cache in the process.
  774. f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().path_join("used_class_cache"), FileAccess::WRITE);
  775. for (const KeyValue<String, DetectedFile> &E : updated_file_cache) {
  776. String l = E.key + "::" + itos(E.value.timestamp) + "::" + E.value.md5 + "::";
  777. for (int i = 0; i < E.value.classes.size(); i++) {
  778. String c = E.value.classes[i];
  779. if (i > 0) {
  780. l += ",";
  781. }
  782. l += c;
  783. used_classes.insert(c);
  784. }
  785. l += "::";
  786. for (int i = 0; i < E.value.build_deps.size(); i++) {
  787. String c = E.value.build_deps[i];
  788. if (i > 0) {
  789. l += ",";
  790. }
  791. l += c;
  792. used_build_deps.push_back(c);
  793. }
  794. f->store_line(l);
  795. }
  796. f.unref();
  797. // Add classes that are either necessary for the engine to work properly, or there isn't a way to infer their use.
  798. const LocalVector<String> hardcoded_classes = { "InputEvent", "MainLoop", "StyleBox" };
  799. for (const String &hc_class : hardcoded_classes) {
  800. used_classes.insert(hc_class);
  801. LocalVector<StringName> inheriters;
  802. ClassDB::get_inheriters_from_class(hc_class, inheriters);
  803. for (const StringName &inheriter : inheriters) {
  804. used_classes.insert(inheriter);
  805. }
  806. }
  807. // Add forced classes typed by the user.
  808. const Vector<String> force_detect = edited->get_force_detect_classes().split(",");
  809. for (const String &class_name : force_detect) {
  810. const String class_stripped = class_name.strip_edges();
  811. if (!class_stripped.is_empty()) {
  812. used_classes.insert(class_stripped);
  813. }
  814. }
  815. // Filter all classes to discard inherited ones.
  816. HashSet<StringName> all_used_classes;
  817. for (const StringName &E : used_classes) {
  818. StringName c = E;
  819. if (!ClassDB::class_exists(c)) {
  820. // Maybe this is an old class that got replaced? Try getting compat class.
  821. c = ClassDB::get_compatibility_class(c);
  822. if (!c) {
  823. // No luck, skip.
  824. continue;
  825. }
  826. }
  827. List<StringName> dependencies;
  828. ClassDB::get_class_dependencies(E, &dependencies);
  829. for (const StringName &dep : dependencies) {
  830. if (!all_used_classes.has(dep)) {
  831. // Add classes which this class depends upon.
  832. all_used_classes.insert(dep);
  833. }
  834. }
  835. while (c) {
  836. all_used_classes.insert(c);
  837. c = ClassDB::get_parent_class(c);
  838. }
  839. }
  840. edited->clear_disabled_classes();
  841. List<StringName> all_classes;
  842. ClassDB::get_class_list(&all_classes);
  843. for (const StringName &E : all_classes) {
  844. if (String(E).begins_with("Editor") || ClassDB::get_api_type(E) != ClassDB::API_CORE || all_used_classes.has(E)) {
  845. // This class is valid or editor-only, do nothing.
  846. continue;
  847. }
  848. StringName p = ClassDB::get_parent_class(E);
  849. if (!p || all_used_classes.has(p)) {
  850. // If no parent, or if the parent is enabled, then add to disabled classes.
  851. // This way we avoid disabling redundant classes.
  852. edited->set_disable_class(E, true);
  853. }
  854. }
  855. edited->reset_build_options();
  856. for (int i = 0; i < EditorBuildProfile::BUILD_OPTION_MAX; i++) {
  857. // Check if the build option requires other options that are currently disabled.
  858. LocalVector<EditorBuildProfile::BuildOption> dependencies = EditorBuildProfile::get_build_option_dependencies(EditorBuildProfile::BuildOption(i));
  859. if (!dependencies.is_empty()) {
  860. bool disable = true;
  861. for (EditorBuildProfile::BuildOption dependency : dependencies) {
  862. if (!edited->is_build_option_disabled(dependency)) {
  863. disable = false;
  864. break;
  865. }
  866. }
  867. if (disable) {
  868. edited->set_disable_build_option(EditorBuildProfile::BuildOption(i), true);
  869. continue;
  870. }
  871. }
  872. bool skip = false;
  873. bool ignore = true;
  874. // Check if the build option has enabled classes using it.
  875. const LocalVector<String> classes = EditorBuildProfile::get_build_option_classes(EditorBuildProfile::BuildOption(i));
  876. if (!classes.is_empty()) {
  877. for (StringName class_name : classes) {
  878. if (!edited->is_class_disabled(class_name)) {
  879. skip = true;
  880. break;
  881. }
  882. }
  883. if (skip) {
  884. continue;
  885. }
  886. ignore = false;
  887. }
  888. // Check if there's project settings requiring it.
  889. const HashMap<String, LocalVector<Variant>> settings_list = EditorBuildProfile::get_build_option_settings(EditorBuildProfile::BuildOption(i));
  890. if (!settings_list.is_empty()) {
  891. for (KeyValue<String, LocalVector<Variant>> KV : settings_list) {
  892. Variant proj_value = GLOBAL_GET(KV.key);
  893. for (Variant value : KV.value) {
  894. if (proj_value == value) {
  895. skip = true;
  896. break;
  897. }
  898. }
  899. if (skip) {
  900. break;
  901. }
  902. }
  903. if (skip) {
  904. continue;
  905. }
  906. ignore = false;
  907. }
  908. // Check if a resource setting depends on it.
  909. if (used_build_deps.has(EditorBuildProfile::get_build_option_identifier(EditorBuildProfile::BuildOption(i)))) {
  910. continue;
  911. } else if (EditorBuildProfile::get_build_option_explicit_use(EditorBuildProfile::BuildOption(i))) {
  912. ignore = false;
  913. }
  914. if (!skip && !ignore) {
  915. edited->set_disable_build_option(EditorBuildProfile::BuildOption(i), true);
  916. }
  917. }
  918. if (edited->is_build_option_disabled(EditorBuildProfile::BUILD_OPTION_TEXT_SERVER_ADVANCED)) {
  919. edited->set_disable_build_option(EditorBuildProfile::BUILD_OPTION_TEXT_SERVER_FALLBACK, false);
  920. }
  921. EditorNode::get_singleton()->progress_end_task("detect_classes_from_project");
  922. }
  923. void EditorBuildProfileManager::_action_confirm() {
  924. switch (last_action) {
  925. case ACTION_RESET: {
  926. edited.instantiate();
  927. _update_edited_profile();
  928. } break;
  929. case ACTION_LOAD: {
  930. } break;
  931. case ACTION_SAVE: {
  932. } break;
  933. case ACTION_SAVE_AS: {
  934. } break;
  935. case ACTION_NEW: {
  936. profile_path->set_text("");
  937. edited.instantiate();
  938. _update_edited_profile();
  939. } break;
  940. case ACTION_DETECT: {
  941. _detect_from_project();
  942. _update_edited_profile();
  943. } break;
  944. case ACTION_MAX: {
  945. } break;
  946. }
  947. }
  948. void EditorBuildProfileManager::_hide_requested() {
  949. _cancel_pressed(); // From AcceptDialog.
  950. }
  951. void EditorBuildProfileManager::_fill_classes_from(TreeItem *p_parent, const String &p_class, const String &p_selected) {
  952. TreeItem *class_item = class_list->create_item(p_parent);
  953. class_item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
  954. class_item->set_icon(0, EditorNode::get_singleton()->get_class_icon(p_class));
  955. const String &text = p_class;
  956. bool disabled = edited->is_class_disabled(p_class);
  957. if (disabled) {
  958. class_item->set_custom_color(0, class_list->get_theme_color(SNAME("font_disabled_color"), EditorStringName(Editor)));
  959. }
  960. class_item->set_text(0, text);
  961. class_item->set_editable(0, true);
  962. class_item->set_selectable(0, true);
  963. class_item->set_metadata(0, p_class);
  964. bool collapsed = edited->is_item_collapsed(p_class);
  965. class_item->set_collapsed(collapsed);
  966. if (p_class == p_selected) {
  967. class_item->select(0);
  968. }
  969. if (disabled) {
  970. // Class disabled, do nothing else (do not show further).
  971. return;
  972. }
  973. class_item->set_checked(0, true); // If it's not disabled, its checked.
  974. List<StringName> child_classes;
  975. ClassDB::get_direct_inheriters_from_class(p_class, &child_classes);
  976. child_classes.sort_custom<StringName::AlphCompare>();
  977. for (const StringName &name : child_classes) {
  978. if (String(name).begins_with("Editor") || ClassDB::get_api_type(name) != ClassDB::API_CORE) {
  979. continue;
  980. }
  981. _fill_classes_from(class_item, name, p_selected);
  982. }
  983. }
  984. void EditorBuildProfileManager::_class_list_item_selected() {
  985. if (updating_build_options) {
  986. return;
  987. }
  988. TreeItem *item = class_list->get_selected();
  989. if (!item) {
  990. return;
  991. }
  992. Variant md = item->get_metadata(0);
  993. if (md.is_string()) {
  994. description_bit->parse_symbol("class|" + md.operator String() + "|");
  995. } else if (md.get_type() == Variant::INT) {
  996. String build_option_description = EditorBuildProfile::get_build_option_description(EditorBuildProfile::BuildOption((int)md));
  997. description_bit->set_custom_text(TTR(item->get_text(0)), String(), TTRGET(build_option_description));
  998. }
  999. }
  1000. void EditorBuildProfileManager::_class_list_item_edited() {
  1001. if (updating_build_options) {
  1002. return;
  1003. }
  1004. TreeItem *item = class_list->get_edited();
  1005. if (!item) {
  1006. return;
  1007. }
  1008. bool checked = item->is_checked(0);
  1009. Variant md = item->get_metadata(0);
  1010. if (md.is_string()) {
  1011. String class_selected = md;
  1012. edited->set_disable_class(class_selected, !checked);
  1013. _update_edited_profile();
  1014. } else if (md.get_type() == Variant::INT) {
  1015. int build_option_selected = md;
  1016. edited->set_disable_build_option(EditorBuildProfile::BuildOption(build_option_selected), !checked);
  1017. }
  1018. }
  1019. void EditorBuildProfileManager::_class_list_item_collapsed(Object *p_item) {
  1020. if (updating_build_options) {
  1021. return;
  1022. }
  1023. TreeItem *item = Object::cast_to<TreeItem>(p_item);
  1024. if (!item) {
  1025. return;
  1026. }
  1027. Variant md = item->get_metadata(0);
  1028. if (!md.is_string()) {
  1029. return;
  1030. }
  1031. String class_name = md;
  1032. bool collapsed = item->is_collapsed();
  1033. edited->set_item_collapsed(class_name, collapsed);
  1034. }
  1035. void EditorBuildProfileManager::_update_edited_profile() {
  1036. String class_selected;
  1037. int build_option_selected = -1;
  1038. if (class_list->get_selected()) {
  1039. Variant md = class_list->get_selected()->get_metadata(0);
  1040. if (md.is_string()) {
  1041. class_selected = md;
  1042. } else if (md.get_type() == Variant::INT) {
  1043. build_option_selected = md;
  1044. }
  1045. }
  1046. class_list->clear();
  1047. updating_build_options = true;
  1048. TreeItem *root = class_list->create_item();
  1049. HashMap<EditorBuildProfile::BuildOptionCategory, TreeItem *> subcats;
  1050. for (int i = 0; i < EditorBuildProfile::BUILD_OPTION_CATEGORY_MAX; i++) {
  1051. TreeItem *build_cat;
  1052. build_cat = class_list->create_item(root);
  1053. build_cat->set_text(0, EditorBuildProfile::get_build_option_category_name(EditorBuildProfile::BuildOptionCategory(i)));
  1054. subcats[EditorBuildProfile::BuildOptionCategory(i)] = build_cat;
  1055. }
  1056. for (int i = 0; i < EditorBuildProfile::BUILD_OPTION_MAX; i++) {
  1057. TreeItem *build_option;
  1058. build_option = class_list->create_item(subcats[EditorBuildProfile::get_build_option_category(EditorBuildProfile::BuildOption(i))]);
  1059. build_option->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
  1060. build_option->set_text(0, EditorBuildProfile::get_build_option_name(EditorBuildProfile::BuildOption(i)));
  1061. build_option->set_selectable(0, true);
  1062. build_option->set_editable(0, true);
  1063. build_option->set_metadata(0, i);
  1064. if (!edited->is_build_option_disabled(EditorBuildProfile::BuildOption(i))) {
  1065. build_option->set_checked(0, true);
  1066. }
  1067. if (i == build_option_selected) {
  1068. build_option->select(0);
  1069. }
  1070. }
  1071. TreeItem *classes = class_list->create_item(root);
  1072. classes->set_text(0, TTR("Nodes and Classes:"));
  1073. _fill_classes_from(classes, "Node", class_selected);
  1074. _fill_classes_from(classes, "Resource", class_selected);
  1075. force_detect_classes->set_text(edited->get_force_detect_classes());
  1076. updating_build_options = false;
  1077. _class_list_item_selected();
  1078. }
  1079. void EditorBuildProfileManager::_force_detect_classes_changed(const String &p_text) {
  1080. if (updating_build_options) {
  1081. return;
  1082. }
  1083. edited->set_force_detect_classes(force_detect_classes->get_text());
  1084. }
  1085. void EditorBuildProfileManager::_import_profile(const String &p_path) {
  1086. Ref<EditorBuildProfile> profile;
  1087. profile.instantiate();
  1088. Error err = profile->load_from_file(p_path);
  1089. String basefile = p_path.get_file();
  1090. if (err != OK) {
  1091. EditorNode::get_singleton()->show_warning(vformat(TTR("File '%s' format is invalid, import aborted."), basefile));
  1092. return;
  1093. }
  1094. profile_path->set_text(p_path);
  1095. EditorSettings::get_singleton()->set_project_metadata("build_profile", "last_file_path", p_path);
  1096. edited = profile;
  1097. _update_edited_profile();
  1098. }
  1099. void EditorBuildProfileManager::_export_profile(const String &p_path) {
  1100. ERR_FAIL_COND(edited.is_null());
  1101. Error err = edited->save_to_file(p_path);
  1102. if (err != OK) {
  1103. EditorNode::get_singleton()->show_warning(vformat(TTR("Error saving profile to path: '%s'."), p_path));
  1104. } else {
  1105. profile_path->set_text(p_path);
  1106. EditorSettings::get_singleton()->set_project_metadata("build_profile", "last_file_path", p_path);
  1107. }
  1108. }
  1109. Ref<EditorBuildProfile> EditorBuildProfileManager::get_current_profile() {
  1110. return edited;
  1111. }
  1112. EditorBuildProfileManager *EditorBuildProfileManager::singleton = nullptr;
  1113. void EditorBuildProfileManager::_bind_methods() {
  1114. ClassDB::bind_method("_update_selected_profile", &EditorBuildProfileManager::_update_edited_profile);
  1115. }
  1116. EditorBuildProfileManager::EditorBuildProfileManager() {
  1117. VBoxContainer *main_vbc = memnew(VBoxContainer);
  1118. add_child(main_vbc);
  1119. HBoxContainer *path_hbc = memnew(HBoxContainer);
  1120. profile_path = memnew(LineEdit);
  1121. path_hbc->add_child(profile_path);
  1122. profile_path->set_accessibility_name(TTRC("Profile Path"));
  1123. profile_path->set_editable(true);
  1124. profile_path->set_h_size_flags(Control::SIZE_EXPAND_FILL);
  1125. profile_actions[ACTION_NEW] = memnew(Button(TTR("New")));
  1126. path_hbc->add_child(profile_actions[ACTION_NEW]);
  1127. profile_actions[ACTION_NEW]->connect(SceneStringName(pressed), callable_mp(this, &EditorBuildProfileManager::_profile_action).bind(ACTION_NEW));
  1128. profile_actions[ACTION_LOAD] = memnew(Button(TTR("Load")));
  1129. path_hbc->add_child(profile_actions[ACTION_LOAD]);
  1130. profile_actions[ACTION_LOAD]->connect(SceneStringName(pressed), callable_mp(this, &EditorBuildProfileManager::_profile_action).bind(ACTION_LOAD));
  1131. profile_actions[ACTION_SAVE] = memnew(Button(TTR("Save")));
  1132. path_hbc->add_child(profile_actions[ACTION_SAVE]);
  1133. profile_actions[ACTION_SAVE]->connect(SceneStringName(pressed), callable_mp(this, &EditorBuildProfileManager::_profile_action).bind(ACTION_SAVE));
  1134. profile_actions[ACTION_SAVE_AS] = memnew(Button(TTR("Save As")));
  1135. path_hbc->add_child(profile_actions[ACTION_SAVE_AS]);
  1136. profile_actions[ACTION_SAVE_AS]->connect(SceneStringName(pressed), callable_mp(this, &EditorBuildProfileManager::_profile_action).bind(ACTION_SAVE_AS));
  1137. main_vbc->add_margin_child(TTR("Profile:"), path_hbc);
  1138. main_vbc->add_child(memnew(HSeparator));
  1139. HBoxContainer *profiles_hbc = memnew(HBoxContainer);
  1140. profile_actions[ACTION_RESET] = memnew(Button(TTR("Reset to Defaults")));
  1141. profiles_hbc->add_child(profile_actions[ACTION_RESET]);
  1142. profile_actions[ACTION_RESET]->connect(SceneStringName(pressed), callable_mp(this, &EditorBuildProfileManager::_profile_action).bind(ACTION_RESET));
  1143. profile_actions[ACTION_DETECT] = memnew(Button(TTR("Detect from Project")));
  1144. profiles_hbc->add_child(profile_actions[ACTION_DETECT]);
  1145. profile_actions[ACTION_DETECT]->connect(SceneStringName(pressed), callable_mp(this, &EditorBuildProfileManager::_profile_action).bind(ACTION_DETECT));
  1146. main_vbc->add_margin_child(TTR("Actions:"), profiles_hbc);
  1147. class_list = memnew(Tree);
  1148. class_list->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
  1149. class_list->set_hide_root(true);
  1150. class_list->set_edit_checkbox_cell_only_when_checkbox_is_pressed(true);
  1151. class_list->connect("cell_selected", callable_mp(this, &EditorBuildProfileManager::_class_list_item_selected));
  1152. class_list->connect("item_edited", callable_mp(this, &EditorBuildProfileManager::_class_list_item_edited), CONNECT_DEFERRED);
  1153. class_list->connect("item_collapsed", callable_mp(this, &EditorBuildProfileManager::_class_list_item_collapsed));
  1154. // It will be displayed once the user creates or chooses a profile.
  1155. main_vbc->add_margin_child(TTR("Configure Engine Compilation Profile:"), class_list, true);
  1156. description_bit = memnew(EditorHelpBit);
  1157. description_bit->set_content_height_limits(80 * EDSCALE, 80 * EDSCALE);
  1158. description_bit->connect("request_hide", callable_mp(this, &EditorBuildProfileManager::_hide_requested));
  1159. main_vbc->add_margin_child(TTR("Description:"), description_bit, false);
  1160. confirm_dialog = memnew(ConfirmationDialog);
  1161. add_child(confirm_dialog);
  1162. confirm_dialog->set_title(TTR("Please Confirm:"));
  1163. confirm_dialog->connect(SceneStringName(confirmed), callable_mp(this, &EditorBuildProfileManager::_action_confirm));
  1164. import_profile = memnew(EditorFileDialog);
  1165. add_child(import_profile);
  1166. import_profile->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
  1167. import_profile->add_filter("*.gdbuild,*.build", TTR("Engine Compilation Profile"));
  1168. import_profile->connect("file_selected", callable_mp(this, &EditorBuildProfileManager::_import_profile));
  1169. import_profile->set_title(TTR("Load Profile"));
  1170. import_profile->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
  1171. export_profile = memnew(EditorFileDialog);
  1172. add_child(export_profile);
  1173. export_profile->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
  1174. export_profile->add_filter("*.gdbuild,*.build", TTR("Engine Compilation Profile"));
  1175. export_profile->connect("file_selected", callable_mp(this, &EditorBuildProfileManager::_export_profile));
  1176. export_profile->set_title(TTR("Export Profile"));
  1177. export_profile->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
  1178. force_detect_classes = memnew(LineEdit);
  1179. force_detect_classes->set_accessibility_name(TTRC("Forced Classes on Detect:"));
  1180. main_vbc->add_margin_child(TTR("Forced Classes on Detect:"), force_detect_classes);
  1181. force_detect_classes->connect(SceneStringName(text_changed), callable_mp(this, &EditorBuildProfileManager::_force_detect_classes_changed));
  1182. set_title(TTR("Edit Compilation Configuration Profile"));
  1183. singleton = this;
  1184. }