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