1/**************************************************************************/
2/* editor_export_preset.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_export.h"
32
33#include "core/config/project_settings.h"
34
35bool EditorExportPreset::_set(const StringName &p_name, const Variant &p_value) {
36 values[p_name] = p_value;
37 EditorExport::singleton->save_presets();
38 if (update_visibility.has(p_name)) {
39 if (update_visibility[p_name]) {
40 notify_property_list_changed();
41 }
42 return true;
43 }
44
45 return false;
46}
47
48bool EditorExportPreset::_get(const StringName &p_name, Variant &r_ret) const {
49 if (values.has(p_name)) {
50 r_ret = values[p_name];
51 return true;
52 }
53
54 return false;
55}
56
57void EditorExportPreset::_bind_methods() {
58 ClassDB::bind_method(D_METHOD("_get_property_warning", "name"), &EditorExportPreset::_get_property_warning);
59}
60
61String EditorExportPreset::_get_property_warning(const StringName &p_name) const {
62 String warning = platform->get_export_option_warning(this, p_name);
63 if (!warning.is_empty()) {
64 warning += "\n";
65 }
66
67 // Get property warning from editor export plugins.
68 Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
69 for (int i = 0; i < export_plugins.size(); i++) {
70 if (!export_plugins[i]->supports_platform(platform)) {
71 continue;
72 }
73
74 export_plugins.write[i]->set_export_preset(Ref<EditorExportPreset>(this));
75 String plugin_warning = export_plugins[i]->_get_export_option_warning(platform, p_name);
76 if (!plugin_warning.is_empty()) {
77 warning += plugin_warning + "\n";
78 }
79 }
80
81 return warning;
82}
83
84void EditorExportPreset::_get_property_list(List<PropertyInfo> *p_list) const {
85 for (const KeyValue<StringName, PropertyInfo> &E : properties) {
86 if (platform->get_export_option_visibility(this, E.key)) {
87 p_list->push_back(E.value);
88 }
89 }
90}
91
92Ref<EditorExportPlatform> EditorExportPreset::get_platform() const {
93 return platform;
94}
95
96void EditorExportPreset::update_files() {
97 {
98 Vector<String> to_remove;
99 for (const String &E : selected_files) {
100 if (!FileAccess::exists(E)) {
101 to_remove.push_back(E);
102 }
103 }
104 for (int i = 0; i < to_remove.size(); ++i) {
105 selected_files.erase(to_remove[i]);
106 }
107 }
108
109 {
110 Vector<String> to_remove;
111 for (const KeyValue<String, FileExportMode> &E : customized_files) {
112 if (!FileAccess::exists(E.key) && !DirAccess::exists(E.key)) {
113 to_remove.push_back(E.key);
114 }
115 }
116 for (int i = 0; i < to_remove.size(); ++i) {
117 customized_files.erase(to_remove[i]);
118 }
119 }
120}
121
122Vector<String> EditorExportPreset::get_files_to_export() const {
123 Vector<String> files;
124 for (const String &E : selected_files) {
125 files.push_back(E);
126 }
127 return files;
128}
129
130Dictionary EditorExportPreset::get_customized_files() const {
131 Dictionary files;
132 for (const KeyValue<String, FileExportMode> &E : customized_files) {
133 String mode;
134 switch (E.value) {
135 case MODE_FILE_NOT_CUSTOMIZED: {
136 continue;
137 } break;
138 case MODE_FILE_STRIP: {
139 mode = "strip";
140 } break;
141 case MODE_FILE_KEEP: {
142 mode = "keep";
143 } break;
144 case MODE_FILE_REMOVE: {
145 mode = "remove";
146 }
147 }
148 files[E.key] = mode;
149 }
150 return files;
151}
152
153int EditorExportPreset::get_customized_files_count() const {
154 return customized_files.size();
155}
156
157void EditorExportPreset::set_customized_files(const Dictionary &p_files) {
158 for (const Variant *key = p_files.next(nullptr); key; key = p_files.next(key)) {
159 EditorExportPreset::FileExportMode mode = EditorExportPreset::MODE_FILE_NOT_CUSTOMIZED;
160 String value = p_files[*key];
161 if (value == "strip") {
162 mode = EditorExportPreset::MODE_FILE_STRIP;
163 } else if (value == "keep") {
164 mode = EditorExportPreset::MODE_FILE_KEEP;
165 } else if (value == "remove") {
166 mode = EditorExportPreset::MODE_FILE_REMOVE;
167 }
168 set_file_export_mode(*key, mode);
169 }
170}
171
172void EditorExportPreset::set_name(const String &p_name) {
173 name = p_name;
174 EditorExport::singleton->save_presets();
175}
176
177String EditorExportPreset::get_name() const {
178 return name;
179}
180
181void EditorExportPreset::set_runnable(bool p_enable) {
182 runnable = p_enable;
183 EditorExport::singleton->save_presets();
184}
185
186bool EditorExportPreset::is_runnable() const {
187 return runnable;
188}
189
190void EditorExportPreset::set_dedicated_server(bool p_enable) {
191 dedicated_server = p_enable;
192 EditorExport::singleton->save_presets();
193}
194
195bool EditorExportPreset::is_dedicated_server() const {
196 return dedicated_server;
197}
198
199void EditorExportPreset::set_export_filter(ExportFilter p_filter) {
200 export_filter = p_filter;
201 EditorExport::singleton->save_presets();
202}
203
204EditorExportPreset::ExportFilter EditorExportPreset::get_export_filter() const {
205 return export_filter;
206}
207
208void EditorExportPreset::set_include_filter(const String &p_include) {
209 include_filter = p_include;
210 EditorExport::singleton->save_presets();
211}
212
213String EditorExportPreset::get_include_filter() const {
214 return include_filter;
215}
216
217void EditorExportPreset::set_export_path(const String &p_path) {
218 export_path = p_path;
219 /* NOTE(SonerSound): if there is a need to implement a PropertyHint that specifically indicates a relative path,
220 * this should be removed. */
221 if (export_path.is_absolute_path()) {
222 String res_path = OS::get_singleton()->get_resource_dir();
223 export_path = res_path.path_to_file(export_path);
224 }
225 EditorExport::singleton->save_presets();
226}
227
228String EditorExportPreset::get_export_path() const {
229 return export_path;
230}
231
232void EditorExportPreset::set_exclude_filter(const String &p_exclude) {
233 exclude_filter = p_exclude;
234 EditorExport::singleton->save_presets();
235}
236
237String EditorExportPreset::get_exclude_filter() const {
238 return exclude_filter;
239}
240
241void EditorExportPreset::add_export_file(const String &p_path) {
242 selected_files.insert(p_path);
243 EditorExport::singleton->save_presets();
244}
245
246void EditorExportPreset::remove_export_file(const String &p_path) {
247 selected_files.erase(p_path);
248 EditorExport::singleton->save_presets();
249}
250
251bool EditorExportPreset::has_export_file(const String &p_path) {
252 return selected_files.has(p_path);
253}
254
255void EditorExportPreset::set_file_export_mode(const String &p_path, EditorExportPreset::FileExportMode p_mode) {
256 if (p_mode == FileExportMode::MODE_FILE_NOT_CUSTOMIZED) {
257 customized_files.erase(p_path);
258 } else {
259 customized_files.insert(p_path, p_mode);
260 }
261 EditorExport::singleton->save_presets();
262}
263
264EditorExportPreset::FileExportMode EditorExportPreset::get_file_export_mode(const String &p_path, EditorExportPreset::FileExportMode p_default) const {
265 HashMap<String, FileExportMode>::ConstIterator i = customized_files.find(p_path);
266 if (i) {
267 return i->value;
268 }
269 return p_default;
270}
271
272void EditorExportPreset::set_custom_features(const String &p_custom_features) {
273 custom_features = p_custom_features;
274 EditorExport::singleton->save_presets();
275}
276
277String EditorExportPreset::get_custom_features() const {
278 return custom_features;
279}
280
281void EditorExportPreset::set_enc_in_filter(const String &p_filter) {
282 enc_in_filters = p_filter;
283 EditorExport::singleton->save_presets();
284}
285
286String EditorExportPreset::get_enc_in_filter() const {
287 return enc_in_filters;
288}
289
290void EditorExportPreset::set_enc_ex_filter(const String &p_filter) {
291 enc_ex_filters = p_filter;
292 EditorExport::singleton->save_presets();
293}
294
295String EditorExportPreset::get_enc_ex_filter() const {
296 return enc_ex_filters;
297}
298
299void EditorExportPreset::set_enc_pck(bool p_enabled) {
300 enc_pck = p_enabled;
301 EditorExport::singleton->save_presets();
302}
303
304bool EditorExportPreset::get_enc_pck() const {
305 return enc_pck;
306}
307
308void EditorExportPreset::set_enc_directory(bool p_enabled) {
309 enc_directory = p_enabled;
310 EditorExport::singleton->save_presets();
311}
312
313bool EditorExportPreset::get_enc_directory() const {
314 return enc_directory;
315}
316
317void EditorExportPreset::set_script_encryption_key(const String &p_key) {
318 script_key = p_key;
319 EditorExport::singleton->save_presets();
320}
321
322String EditorExportPreset::get_script_encryption_key() const {
323 return script_key;
324}
325
326Variant EditorExportPreset::get_or_env(const StringName &p_name, const String &p_env_var, bool *r_valid) const {
327 const String from_env = OS::get_singleton()->get_environment(p_env_var);
328 if (!from_env.is_empty()) {
329 if (r_valid) {
330 *r_valid = true;
331 }
332 return from_env;
333 }
334 return get(p_name, r_valid);
335}
336
337String EditorExportPreset::get_version(const StringName &p_preset_string, bool p_windows_version) const {
338 String result = get(p_preset_string);
339 if (result.is_empty()) {
340 result = GLOBAL_GET("application/config/version");
341
342 if (p_windows_version) {
343 // Modify version number to match Windows constraints (version numbers must have 4 components).
344 const PackedStringArray result_split = result.split(".");
345 String windows_version;
346 if (result_split.is_empty()) {
347 // Use a valid fallback if the version string is empty, as a version number must be specified.
348 result = "1.0.0.0";
349 } else if (result_split.size() == 1) {
350 result = result + ".0.0.0";
351 } else if (result_split.size() == 2) {
352 result = result + ".0.0";
353 } else if (result_split.size() == 3) {
354 result = result + ".0";
355 } else {
356 // 4 components or more in the version string. Trim to contain only the first 4 components.
357 result = vformat("%s.%s.%s.%s", result_split[0] + result_split[1] + result_split[2] + result_split[3]);
358 }
359 } else if (result.is_empty()) {
360 // Use a valid fallback if the version string is empty, as a version number must be specified.
361 result = "1.0.0";
362 }
363 }
364
365 return result;
366}
367
368EditorExportPreset::EditorExportPreset() {}
369