Path: blob/master/editor/export/editor_export_preset.cpp
20803 views
/**************************************************************************/1/* editor_export_preset.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "editor_export_preset.h"31#include "editor_export_preset.compat.inc"3233#include "core/config/project_settings.h"34#include "core/io/dir_access.h"35#include "editor/export/editor_export.h"36#include "editor/settings/editor_settings.h"3738bool EditorExportPreset::_set(const StringName &p_name, const Variant &p_value) {39values[p_name] = p_value;40EditorExport::singleton->save_presets();41if (update_visibility.has(p_name)) {42if (update_visibility[p_name]) {43update_value_overrides();44notify_property_list_changed();45}46return true;47}4849return false;50}5152bool EditorExportPreset::_get(const StringName &p_name, Variant &r_ret) const {53if (value_overrides.has(p_name)) {54r_ret = value_overrides[p_name];55return true;56}5758if (values.has(p_name)) {59r_ret = values[p_name];60return true;61}6263return false;64}6566Variant EditorExportPreset::get_project_setting(const StringName &p_name) {67List<String> ftr_list;68platform->get_platform_features(&ftr_list);69platform->get_preset_features(this, &ftr_list);7071Vector<String> features;72for (const String &E : ftr_list) {73features.push_back(E);74}7576if (!get_custom_features().is_empty()) {77Vector<String> tmp_custom_list = get_custom_features().split(",");7879for (int i = 0; i < tmp_custom_list.size(); i++) {80String f = tmp_custom_list[i].strip_edges();81if (!f.is_empty()) {82features.push_back(f);83}84}85}86return ProjectSettings::get_singleton()->get_setting_with_override_and_custom_features(p_name, features);87}8889void EditorExportPreset::_bind_methods() {90ClassDB::bind_method(D_METHOD("_get_property_warning", "name"), &EditorExportPreset::_get_property_warning);9192ClassDB::bind_method(D_METHOD("has", "property"), &EditorExportPreset::has);9394ClassDB::bind_method(D_METHOD("get_files_to_export"), &EditorExportPreset::get_files_to_export);95ClassDB::bind_method(D_METHOD("get_customized_files"), &EditorExportPreset::get_customized_files);96ClassDB::bind_method(D_METHOD("get_customized_files_count"), &EditorExportPreset::get_customized_files_count);97ClassDB::bind_method(D_METHOD("has_export_file", "path"), &EditorExportPreset::has_export_file);98ClassDB::bind_method(D_METHOD("get_file_export_mode", "path", "default"), &EditorExportPreset::get_file_export_mode, DEFVAL(MODE_FILE_NOT_CUSTOMIZED));99ClassDB::bind_method(D_METHOD("get_project_setting", "name"), &EditorExportPreset::get_project_setting);100101ClassDB::bind_method(D_METHOD("get_preset_name"), &EditorExportPreset::get_name);102ClassDB::bind_method(D_METHOD("is_runnable"), &EditorExportPreset::is_runnable);103ClassDB::bind_method(D_METHOD("are_advanced_options_enabled"), &EditorExportPreset::are_advanced_options_enabled);104ClassDB::bind_method(D_METHOD("is_dedicated_server"), &EditorExportPreset::is_dedicated_server);105ClassDB::bind_method(D_METHOD("get_export_filter"), &EditorExportPreset::get_export_filter);106ClassDB::bind_method(D_METHOD("get_include_filter"), &EditorExportPreset::get_include_filter);107ClassDB::bind_method(D_METHOD("get_exclude_filter"), &EditorExportPreset::get_exclude_filter);108ClassDB::bind_method(D_METHOD("get_custom_features"), &EditorExportPreset::get_custom_features);109ClassDB::bind_method(D_METHOD("get_patches"), &EditorExportPreset::get_patches);110ClassDB::bind_method(D_METHOD("get_export_path"), &EditorExportPreset::get_export_path);111ClassDB::bind_method(D_METHOD("get_encryption_in_filter"), &EditorExportPreset::get_enc_in_filter);112ClassDB::bind_method(D_METHOD("get_encryption_ex_filter"), &EditorExportPreset::get_enc_ex_filter);113ClassDB::bind_method(D_METHOD("get_encrypt_pck"), &EditorExportPreset::get_enc_pck);114ClassDB::bind_method(D_METHOD("get_encrypt_directory"), &EditorExportPreset::get_enc_directory);115ClassDB::bind_method(D_METHOD("get_encryption_key"), &EditorExportPreset::get_script_encryption_key);116ClassDB::bind_method(D_METHOD("get_script_export_mode"), &EditorExportPreset::get_script_export_mode);117118ClassDB::bind_method(D_METHOD("get_or_env", "name", "env_var"), &EditorExportPreset::_get_or_env);119ClassDB::bind_method(D_METHOD("get_version", "name", "windows_version"), &EditorExportPreset::get_version);120121BIND_ENUM_CONSTANT(EXPORT_ALL_RESOURCES);122BIND_ENUM_CONSTANT(EXPORT_SELECTED_SCENES);123BIND_ENUM_CONSTANT(EXPORT_SELECTED_RESOURCES);124BIND_ENUM_CONSTANT(EXCLUDE_SELECTED_RESOURCES);125BIND_ENUM_CONSTANT(EXPORT_CUSTOMIZED);126127BIND_ENUM_CONSTANT(MODE_FILE_NOT_CUSTOMIZED);128BIND_ENUM_CONSTANT(MODE_FILE_STRIP);129BIND_ENUM_CONSTANT(MODE_FILE_KEEP);130BIND_ENUM_CONSTANT(MODE_FILE_REMOVE);131132BIND_ENUM_CONSTANT(MODE_SCRIPT_TEXT);133BIND_ENUM_CONSTANT(MODE_SCRIPT_BINARY_TOKENS);134BIND_ENUM_CONSTANT(MODE_SCRIPT_BINARY_TOKENS_COMPRESSED);135}136137String EditorExportPreset::_get_property_warning(const StringName &p_name) const {138if (value_overrides.has(p_name)) {139return String();140}141142String warning = platform->get_export_option_warning(this, p_name);143if (!warning.is_empty()) {144warning += "\n";145}146147// Get property warning from editor export plugins.148Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();149for (int i = 0; i < export_plugins.size(); i++) {150if (!export_plugins[i]->supports_platform(platform)) {151continue;152}153154export_plugins.write[i]->set_export_preset(Ref<EditorExportPreset>(this));155String plugin_warning = export_plugins[i]->_get_export_option_warning(platform, p_name);156if (!plugin_warning.is_empty()) {157warning += plugin_warning + "\n";158}159}160161return warning;162}163164void EditorExportPreset::_get_property_list(List<PropertyInfo> *p_list) const {165for (const KeyValue<StringName, PropertyInfo> &E : properties) {166if (!value_overrides.has(E.key)) {167bool property_visible = platform->get_export_option_visibility(this, E.key);168if (!property_visible) {169continue;170}171172// Get option visibility from editor export plugins.173Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();174for (int i = 0; i < export_plugins.size(); i++) {175if (!export_plugins[i]->supports_platform(platform)) {176continue;177}178179export_plugins.write[i]->set_export_preset(Ref<EditorExportPreset>(this));180property_visible = export_plugins[i]->_get_export_option_visibility(platform, E.key);181if (!property_visible) {182break;183}184}185186if (property_visible) {187p_list->push_back(E.value);188}189}190}191}192193Ref<EditorExportPlatform> EditorExportPreset::get_platform() const {194return platform;195}196197void EditorExportPreset::update_files() {198{199Vector<String> to_remove;200for (const String &E : selected_files) {201if (!FileAccess::exists(E)) {202to_remove.push_back(E);203}204}205for (int i = 0; i < to_remove.size(); ++i) {206selected_files.erase(to_remove[i]);207}208}209210{211Vector<String> to_remove;212for (const KeyValue<String, FileExportMode> &E : customized_files) {213if (!FileAccess::exists(E.key) && !DirAccess::exists(E.key)) {214to_remove.push_back(E.key);215}216}217for (int i = 0; i < to_remove.size(); ++i) {218customized_files.erase(to_remove[i]);219}220}221}222223void EditorExportPreset::update_value_overrides() {224Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();225HashMap<StringName, Variant> new_value_overrides;226227value_overrides.clear();228229for (int i = 0; i < export_plugins.size(); i++) {230if (!export_plugins[i]->supports_platform(platform)) {231continue;232}233234export_plugins.write[i]->set_export_preset(Ref<EditorExportPreset>(this));235236Dictionary plugin_overrides = export_plugins[i]->_get_export_options_overrides(platform);237if (!plugin_overrides.is_empty()) {238for (const KeyValue<Variant, Variant> &kv : plugin_overrides) {239const StringName &key = kv.key;240const Variant &value = kv.value;241if (new_value_overrides.has(key) && new_value_overrides[key] != value) {242WARN_PRINT_ED(vformat("Editor export plugin '%s' overrides pre-existing export option override '%s' with new value.", export_plugins[i]->get_name(), key));243}244new_value_overrides[key] = value;245}246}247}248249value_overrides = new_value_overrides;250notify_property_list_changed();251}252253Vector<String> EditorExportPreset::get_files_to_export() const {254Vector<String> files;255for (const String &E : selected_files) {256files.push_back(E);257}258return files;259}260261HashSet<String> EditorExportPreset::get_selected_files() const {262return selected_files;263}264265void EditorExportPreset::set_selected_files(const HashSet<String> &p_files) {266selected_files = p_files;267}268269Dictionary EditorExportPreset::get_customized_files() const {270Dictionary files;271for (const KeyValue<String, FileExportMode> &E : customized_files) {272String mode;273switch (E.value) {274case MODE_FILE_NOT_CUSTOMIZED: {275continue;276} break;277case MODE_FILE_STRIP: {278mode = "strip";279} break;280case MODE_FILE_KEEP: {281mode = "keep";282} break;283case MODE_FILE_REMOVE: {284mode = "remove";285}286}287files[E.key] = mode;288}289return files;290}291292int EditorExportPreset::get_customized_files_count() const {293return customized_files.size();294}295296void EditorExportPreset::set_customized_files(const Dictionary &p_files) {297for (const Variant *key = p_files.next(nullptr); key; key = p_files.next(key)) {298EditorExportPreset::FileExportMode mode = EditorExportPreset::MODE_FILE_NOT_CUSTOMIZED;299String value = p_files[*key];300if (value == "strip") {301mode = EditorExportPreset::MODE_FILE_STRIP;302} else if (value == "keep") {303mode = EditorExportPreset::MODE_FILE_KEEP;304} else if (value == "remove") {305mode = EditorExportPreset::MODE_FILE_REMOVE;306}307set_file_export_mode(*key, mode);308}309}310311void EditorExportPreset::set_name(const String &p_name) {312name = p_name;313EditorExport::singleton->save_presets();314}315316String EditorExportPreset::get_name() const {317return name;318}319320void EditorExportPreset::set_runnable(bool p_enable) {321if (p_enable) {322EditorExport::singleton->set_runnable_preset(this);323} else {324EditorExport::singleton->unset_runnable_preset(this);325}326}327328bool EditorExportPreset::is_runnable() const {329return EditorExport::singleton->get_runnable_preset_for_platform(platform).ptr() == this;330}331332bool EditorExportPreset::are_advanced_options_enabled() const {333return EDITOR_GET("_export_preset_advanced_mode");334}335336void EditorExportPreset::set_dedicated_server(bool p_enable) {337dedicated_server = p_enable;338EditorExport::singleton->save_presets();339}340341bool EditorExportPreset::is_dedicated_server() const {342return dedicated_server;343}344345void EditorExportPreset::set_export_filter(ExportFilter p_filter) {346export_filter = p_filter;347EditorExport::singleton->save_presets();348}349350EditorExportPreset::ExportFilter EditorExportPreset::get_export_filter() const {351return export_filter;352}353354void EditorExportPreset::set_include_filter(const String &p_include) {355include_filter = p_include;356EditorExport::singleton->save_presets();357}358359String EditorExportPreset::get_include_filter() const {360return include_filter;361}362363void EditorExportPreset::set_export_path(const String &p_path) {364export_path = p_path;365/* NOTE(SonerSound): if there is a need to implement a PropertyHint that specifically indicates a relative path,366* this should be removed. */367if (export_path.is_absolute_path()) {368String res_path = OS::get_singleton()->get_resource_dir();369export_path = res_path.path_to_file(export_path);370}371EditorExport::singleton->save_presets();372}373374String EditorExportPreset::get_export_path() const {375return export_path;376}377378void EditorExportPreset::set_exclude_filter(const String &p_exclude) {379exclude_filter = p_exclude;380EditorExport::singleton->save_presets();381}382383String EditorExportPreset::get_exclude_filter() const {384return exclude_filter;385}386387void EditorExportPreset::add_export_file(const String &p_path) {388selected_files.insert(p_path);389EditorExport::singleton->save_presets();390}391392void EditorExportPreset::remove_export_file(const String &p_path) {393selected_files.erase(p_path);394EditorExport::singleton->save_presets();395}396397bool EditorExportPreset::has_export_file(const String &p_path) {398return selected_files.has(p_path);399}400401void EditorExportPreset::set_file_export_mode(const String &p_path, EditorExportPreset::FileExportMode p_mode) {402if (p_mode == FileExportMode::MODE_FILE_NOT_CUSTOMIZED) {403customized_files.erase(p_path);404} else {405customized_files.insert(p_path, p_mode);406}407EditorExport::singleton->save_presets();408}409410EditorExportPreset::FileExportMode EditorExportPreset::get_file_export_mode(const String &p_path, EditorExportPreset::FileExportMode p_default) const {411HashMap<String, FileExportMode>::ConstIterator i = customized_files.find(p_path);412if (i) {413return i->value;414}415return p_default;416}417418void EditorExportPreset::add_patch(const String &p_path, int p_at_pos) {419ERR_FAIL_COND_EDMSG(patches.has(p_path), vformat("Failed to add patch \"%s\". Patches must be unique.", p_path));420421if (p_at_pos < 0) {422patches.push_back(p_path);423} else {424patches.insert(p_at_pos, p_path);425}426427EditorExport::singleton->save_presets();428}429430void EditorExportPreset::set_patch(int p_index, const String &p_path) {431remove_patch(p_index);432add_patch(p_path, p_index);433}434435String EditorExportPreset::get_patch(int p_index) {436ERR_FAIL_INDEX_V(p_index, patches.size(), String());437return patches[p_index];438}439440void EditorExportPreset::remove_patch(int p_index) {441ERR_FAIL_INDEX(p_index, patches.size());442patches.remove_at(p_index);443EditorExport::singleton->save_presets();444}445446void EditorExportPreset::set_patches(const Vector<String> &p_patches) {447patches = p_patches;448}449450Vector<String> EditorExportPreset::get_patches() const {451return patches;452}453454void EditorExportPreset::set_patch_delta_encoding_enabled(bool p_enable) {455patch_delta_encoding_enabled = p_enable;456EditorExport::singleton->save_presets();457}458459bool EditorExportPreset::is_patch_delta_encoding_enabled() const {460return patch_delta_encoding_enabled;461}462463void EditorExportPreset::set_patch_delta_zstd_level(int p_level) {464patch_delta_zstd_level = p_level;465EditorExport::singleton->save_presets();466}467468int EditorExportPreset::get_patch_delta_zstd_level() const {469return patch_delta_zstd_level;470}471472void EditorExportPreset::set_patch_delta_min_reduction(double p_ratio) {473patch_delta_min_reduction = p_ratio;474EditorExport::singleton->save_presets();475}476477double EditorExportPreset::get_patch_delta_min_reduction() const {478return patch_delta_min_reduction;479}480481void EditorExportPreset::set_patch_delta_include_filter(const String &p_filter) {482patch_delta_include_filter = p_filter;483EditorExport::singleton->save_presets();484}485486String EditorExportPreset::get_patch_delta_include_filter() const {487return patch_delta_include_filter;488}489490void EditorExportPreset::set_patch_delta_exclude_filter(const String &p_filter) {491patch_delta_exclude_filter = p_filter;492EditorExport::singleton->save_presets();493}494495String EditorExportPreset::get_patch_delta_exclude_filter() const {496return patch_delta_exclude_filter;497}498499void EditorExportPreset::set_custom_features(const String &p_custom_features) {500custom_features = p_custom_features;501EditorExport::singleton->save_presets();502}503504String EditorExportPreset::get_custom_features() const {505return custom_features;506}507508void EditorExportPreset::set_enc_in_filter(const String &p_filter) {509enc_in_filters = p_filter;510EditorExport::singleton->save_presets();511}512513String EditorExportPreset::get_enc_in_filter() const {514return enc_in_filters;515}516517void EditorExportPreset::set_enc_ex_filter(const String &p_filter) {518enc_ex_filters = p_filter;519EditorExport::singleton->save_presets();520}521522String EditorExportPreset::get_enc_ex_filter() const {523return enc_ex_filters;524}525526void EditorExportPreset::set_seed(uint64_t p_seed) {527seed = p_seed;528EditorExport::singleton->save_presets();529}530531uint64_t EditorExportPreset::get_seed() const {532return seed;533}534535void EditorExportPreset::set_enc_pck(bool p_enabled) {536enc_pck = p_enabled;537EditorExport::singleton->save_presets();538}539540bool EditorExportPreset::get_enc_pck() const {541return enc_pck;542}543544void EditorExportPreset::set_enc_directory(bool p_enabled) {545enc_directory = p_enabled;546EditorExport::singleton->save_presets();547}548549bool EditorExportPreset::get_enc_directory() const {550return enc_directory;551}552553void EditorExportPreset::set_script_encryption_key(const String &p_key) {554script_key = p_key;555EditorExport::singleton->save_presets();556}557558String EditorExportPreset::get_script_encryption_key() const {559return script_key;560}561562void EditorExportPreset::set_script_export_mode(ScriptExportMode p_mode) {563script_mode = p_mode;564EditorExport::singleton->save_presets();565}566567EditorExportPreset::ScriptExportMode EditorExportPreset::get_script_export_mode() const {568return script_mode;569}570571Variant EditorExportPreset::get_or_env(const StringName &p_name, const String &p_env_var, bool *r_valid) const {572const String from_env = OS::get_singleton()->get_environment(p_env_var);573if (!from_env.is_empty()) {574if (r_valid) {575*r_valid = true;576}577return from_env;578}579return get(p_name, r_valid);580}581582_FORCE_INLINE_ bool _check_digits(const String &p_str) {583for (int i = 0; i < p_str.length(); i++) {584char32_t c = p_str.operator[](i);585if (!is_digit(c)) {586return false;587}588}589return true;590}591592String EditorExportPreset::get_version(const StringName &p_preset_string, bool p_windows_version) const {593String result = get(p_preset_string);594if (result.is_empty()) {595result = GLOBAL_GET("application/config/version");596597// Split and validate version number components.598const PackedStringArray result_split = result.split(".", false);599bool valid_version = !result_split.is_empty();600for (const String &E : result_split) {601if (!_check_digits(E)) {602valid_version = false;603break;604}605}606607if (valid_version) {608if (p_windows_version) {609// Modify version number to match Windows constraints (version numbers must have 4 components).610if (result_split.size() == 1) {611result = result + ".0.0.0";612} else if (result_split.size() == 2) {613result = result + ".0.0";614} else if (result_split.size() == 3) {615result = result + ".0";616} else {617result = vformat("%s.%s.%s.%s", result_split[0], result_split[1], result_split[2], result_split[3]);618}619} else {620result = String(".").join(result_split);621}622} else {623if (!result.is_empty()) {624WARN_PRINT(vformat("Invalid version number \"%s\". The version number can only contain numeric characters (0-9) and non-consecutive periods (.).", result));625}626if (p_windows_version) {627result = "1.0.0.0";628} else {629result = "1.0.0";630}631}632}633634return result;635}636637638