瀏覽代碼

Merge pull request #34887 from akien-mga/cli-export-usability

Export: Improve usability of command line interface
Rémi Verschelde 5 年之前
父節點
當前提交
6fa716c67b

+ 17 - 29
editor/editor_export.cpp

@@ -1485,41 +1485,29 @@ Ref<Texture> EditorExportPlatformPC::get_logo() const {
 bool EditorExportPlatformPC::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
 
 	String err;
-	bool valid = true;
-	bool use64 = p_preset->get("binary_format/64_bits");
-
-	if (use64 && (!exists_export_template(debug_file_64, &err) || !exists_export_template(release_file_64, &err))) {
-		valid = false;
-	}
+	bool valid = false;
 
-	if (!use64 && (!exists_export_template(debug_file_32, &err) || !exists_export_template(release_file_32, &err))) {
-		valid = false;
-	}
-
-	String custom_debug_binary = p_preset->get("custom_template/debug");
-	String custom_release_binary = p_preset->get("custom_template/release");
+	// Look for export templates (first official, and if defined custom templates).
 
-	if (custom_debug_binary == "" && custom_release_binary == "") {
-		if (!err.empty())
-			r_error = err;
-		r_missing_templates = !valid;
-		return valid;
-	}
-
-	bool dvalid = true;
-	bool rvalid = true;
+	bool use64 = p_preset->get("binary_format/64_bits");
+	bool dvalid = exists_export_template(use64 ? debug_file_64 : debug_file_32, &err);
+	bool rvalid = exists_export_template(use64 ? release_file_64 : release_file_32, &err);
 
-	if (!FileAccess::exists(custom_debug_binary)) {
-		dvalid = false;
-		err += TTR("Custom debug template not found.") + "\n";
+	if (p_preset->get("custom_template/debug") != "") {
+		dvalid = FileAccess::exists(p_preset->get("custom_template/debug"));
+		if (!dvalid) {
+			err += TTR("Custom debug template not found.") + "\n";
+		}
 	}
-
-	if (!FileAccess::exists(custom_release_binary)) {
-		rvalid = false;
-		err += TTR("Custom release template not found.") + "\n";
+	if (p_preset->get("custom_template/release") != "") {
+		rvalid = FileAccess::exists(p_preset->get("custom_template/release"));
+		if (!rvalid) {
+			err += TTR("Custom release template not found.") + "\n";
+		}
 	}
 
 	valid = dvalid || rvalid;
+	r_missing_templates = !valid;
 
 	if (!err.empty())
 		r_error = err;
@@ -1600,7 +1588,7 @@ Error EditorExportPlatformPC::export_project(const Ref<EditorExportPreset> &p_pr
 
 			if (embedded_size >= 0x100000000 && !p_preset->get("binary_format/64_bits")) {
 				EditorNode::get_singleton()->show_warning(TTR("On 32-bit exports the embedded PCK cannot be bigger than 4 GiB."));
-				return ERR_UNAVAILABLE;
+				return ERR_INVALID_PARAMETER;
 			}
 
 			FixUpEmbeddedPckFunc fixup_func = get_fixup_embedded_pck_func();

+ 38 - 28
editor/editor_node.cpp

@@ -562,46 +562,68 @@ void EditorNode::_fs_changed() {
 
 	_mark_unsaved_scenes();
 
+	// FIXME: Move this to a cleaner location, it's hacky to do this is _fs_changed.
+	String export_error;
 	if (export_defer.preset != "" && !EditorFileSystem::get_singleton()->is_scanning()) {
+		String preset_name = export_defer.preset;
+		// Ensures export_project does not loop infinitely, because notifications may
+		// come during the export.
+		export_defer.preset = "";
 		Ref<EditorExportPreset> preset;
 		for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); ++i) {
 			preset = EditorExport::get_singleton()->get_export_preset(i);
-			if (preset->get_name() == export_defer.preset) {
+			if (preset->get_name() == preset_name) {
 				break;
 			}
 			preset.unref();
 		}
 		if (preset.is_null()) {
-			String errstr = "Unknown export preset: " + export_defer.preset;
-			ERR_PRINTS(errstr);
-			OS::get_singleton()->set_exit_code(EXIT_FAILURE);
+			export_error = vformat("Invalid export preset name: %s.", preset_name);
 		} else {
 			Ref<EditorExportPlatform> platform = preset->get_platform();
 			if (platform.is_null()) {
-				String errstr = "Preset \"" + export_defer.preset + "\" doesn't have a platform.";
-				ERR_PRINTS(errstr);
-				OS::get_singleton()->set_exit_code(EXIT_FAILURE);
+				export_error = vformat("Export preset '%s' doesn't have a matching platform.", preset_name);
 			} else {
-				// ensures export_project does not loop infinitely, because notifications may
-				// come during the export
-				export_defer.preset = "";
 				Error err = OK;
+				// FIXME: This way to export only resources .pck or .zip is pretty hacky
+				// and undocumented, and might be problematic for platforms where .zip is
+				// a valid project export format (e.g. macOS).
 				if (export_defer.path.ends_with(".pck") || export_defer.path.ends_with(".zip")) {
 					if (export_defer.path.ends_with(".zip")) {
 						err = platform->export_zip(preset, export_defer.debug, export_defer.path);
 					} else if (export_defer.path.ends_with(".pck")) {
 						err = platform->export_pack(preset, export_defer.debug, export_defer.path);
 					}
-				} else {
-					err = platform->export_project(preset, export_defer.debug, export_defer.path);
+				} else { // Normal project export.
+					String config_error;
+					bool missing_templates;
+					if (!platform->can_export(preset, config_error, missing_templates)) {
+						ERR_PRINT(vformat("Cannot export project with preset '%s' due to configuration errors:\n%s", preset_name, config_error));
+						err = missing_templates ? ERR_FILE_NOT_FOUND : ERR_UNCONFIGURED;
+					} else {
+						err = platform->export_project(preset, export_defer.debug, export_defer.path);
+					}
 				}
-				if (err != OK) {
-					ERR_PRINTS(vformat(TTR("Project export failed with error code %d."), (int)err));
-					OS::get_singleton()->set_exit_code(EXIT_FAILURE);
+				switch (err) {
+					case OK:
+						break;
+					case ERR_FILE_NOT_FOUND:
+						export_error = vformat("Project export failed for preset '%s', the export template appears to be missing.", preset_name);
+						break;
+					case ERR_FILE_BAD_PATH:
+						export_error = vformat("Project export failed for preset '%s', the target path '%s' appears to be invalid.", preset_name, export_defer.path);
+						break;
+					default:
+						export_error = vformat("Project export failed with error code %d for preset '%s'.", (int)err, preset_name);
+						break;
 				}
 			}
 		}
 
+		if (!export_error.empty()) {
+			ERR_PRINT(export_error);
+			OS::get_singleton()->set_exit_code(EXIT_FAILURE);
+		}
 		_exit_editor();
 	}
 }
@@ -3920,12 +3942,11 @@ void EditorNode::_editor_file_dialog_unregister(EditorFileDialog *p_dialog) {
 
 Vector<EditorNodeInitCallback> EditorNode::_init_callbacks;
 
-Error EditorNode::export_preset(const String &p_preset, const String &p_path, bool p_debug, const String &p_password, bool p_quit_after) {
+Error EditorNode::export_preset(const String &p_preset, const String &p_path, bool p_debug) {
 
 	export_defer.preset = p_preset;
 	export_defer.path = p_path;
 	export_defer.debug = p_debug;
-	export_defer.password = p_password;
 	disable_progress_dialog = true;
 	return OK;
 }
@@ -6531,12 +6552,6 @@ EditorNode::EditorNode() {
 	gui_base->add_child(file);
 	file->set_current_dir("res://");
 
-	file_export = memnew(EditorFileDialog);
-	file_export->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
-	gui_base->add_child(file_export);
-	file_export->set_title(TTR("Export Project"));
-	file_export->connect("file_selected", this, "_dialog_action");
-
 	file_export_lib = memnew(EditorFileDialog);
 	file_export_lib->set_title(TTR("Export Library"));
 	file_export_lib->set_mode(EditorFileDialog::MODE_SAVE_FILE);
@@ -6547,11 +6562,6 @@ EditorNode::EditorNode() {
 	file_export_lib->get_vbox()->add_child(file_export_lib_merge);
 	gui_base->add_child(file_export_lib);
 
-	file_export_password = memnew(LineEdit);
-	file_export_password->set_secret(true);
-	file_export_password->set_editable(false);
-	file_export->get_vbox()->add_margin_child(TTR("Password:"), file_export_password);
-
 	file_script = memnew(EditorFileDialog);
 	file_script->set_title(TTR("Open & Run a Script"));
 	file_script->set_access(EditorFileDialog::ACCESS_FILESYSTEM);

+ 1 - 8
editor/editor_node.h

@@ -325,18 +325,13 @@ private:
 	ExportTemplateManager *export_template_manager;
 	EditorFeatureProfileManager *feature_profile_manager;
 	EditorFileDialog *file_templates;
-	EditorFileDialog *file_export;
 	EditorFileDialog *file_export_lib;
 	EditorFileDialog *file_script;
 	CheckBox *file_export_lib_merge;
-	LineEdit *file_export_password;
 	String current_path;
 	MenuButton *update_spinner;
 
 	String defer_load_scene;
-	String defer_export;
-	String defer_export_platform;
-	bool defer_export_debug;
 	Node *_last_instanced_scene;
 
 	EditorLog *log;
@@ -563,8 +558,6 @@ private:
 		String preset;
 		String path;
 		bool debug;
-		String password;
-
 	} export_defer;
 
 	bool disable_progress_dialog;
@@ -786,7 +779,7 @@ public:
 
 	void _copy_warning(const String &p_str);
 
-	Error export_preset(const String &p_preset, const String &p_path, bool p_debug, const String &p_password, bool p_quit_after = false);
+	Error export_preset(const String &p_preset, const String &p_path, bool p_debug);
 
 	static void register_editor_types();
 	static void unregister_editor_types();

+ 8 - 12
main/main.cpp

@@ -286,8 +286,10 @@ void Main::print_help(const char *p_binary) {
 	OS::get_singleton()->print("  -s, --script <script>            Run a script.\n");
 	OS::get_singleton()->print("  --check-only                     Only parse for errors and quit (use with --script).\n");
 #ifdef TOOLS_ENABLED
-	OS::get_singleton()->print("  --export <target> <path>         Export the project using the given export target. Export only main pack if path ends with .pck or .zip. <path> is relative to the project directory.\n");
-	OS::get_singleton()->print("  --export-debug <target> <path>   Like --export, but use debug template.\n");
+	OS::get_singleton()->print("  --export <preset> <path>         Export the project using the given preset and matching release template. The preset name should match one defined in export_presets.cfg.\n");
+	OS::get_singleton()->print("                                   <path> should be absolute or relative to the project directory, and include the filename for the binary (e.g. 'builds/game.exe').\n");
+	OS::get_singleton()->print("                                   The target directory should exist. Only the data pack is exported if <path> ends with .pck or .zip.\n");
+	OS::get_singleton()->print("  --export-debug <preset> <path>   Same as --export, but using the debug template.\n");
 	OS::get_singleton()->print("  --doctool <path>                 Dump the engine API reference to the given <path> in XML format, merging if existing files are found.\n");
 	OS::get_singleton()->print("  --no-docbase                     Disallow dumping the base types (used with --doctool).\n");
 	OS::get_singleton()->print("  --build-solutions                Build the scripting solutions (e.g. for C# projects).\n");
@@ -1513,11 +1515,11 @@ bool Main::start() {
 
 	if (_export_preset != "") {
 		if (game_path == "") {
-			String err = "Command line param ";
+			String err = "Command line parameter ";
 			err += export_debug ? "--export-debug" : "--export";
 			err += " passed but no destination path given.\n";
 			err += "Please specify the binary's file path to export to. Aborting export.";
-			ERR_PRINT(err.utf8().get_data());
+			ERR_PRINT(err);
 			return false;
 		}
 	}
@@ -1698,20 +1700,14 @@ bool Main::start() {
 		}
 
 #ifdef TOOLS_ENABLED
-
 		EditorNode *editor_node = NULL;
 		if (editor) {
-
 			editor_node = memnew(EditorNode);
 			sml->get_root()->add_child(editor_node);
 
-			//root_node->set_editor(editor);
-			//startup editor
-
 			if (_export_preset != "") {
-
-				editor_node->export_preset(_export_preset, game_path, export_debug, "", true);
-				game_path = ""; //no load anything
+				editor_node->export_preset(_export_preset, game_path, export_debug);
+				game_path = ""; // Do not load anything.
 			}
 		}
 #endif

+ 24 - 19
platform/android/export/export.cpp

@@ -1299,9 +1299,9 @@ public:
 		r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "graphics/degrees_of_freedom", PROPERTY_HINT_ENUM, "None,3DOF and 6DOF,6DOF"), 0));
 		r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "graphics/32_bits_framebuffer"), true));
 		r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "one_click_deploy/clear_previous_install"), false));
-		r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_package/debug", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), ""));
-		r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_package/release", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), ""));
-		r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "custom_package/use_custom_build"), false));
+		r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), ""));
+		r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), ""));
+		r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "custom_template/use_custom_build"), false));
 		r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "command_line/extra_args"), ""));
 		r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/code", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 1));
 		r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "version/name"), "1.0"));
@@ -1577,29 +1577,34 @@ public:
 	virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
 
 		String err;
+		bool valid = false;
 
-		if (!bool(p_preset->get("custom_package/use_custom_build"))) {
+		// Look for export templates (first official, and if defined custom templates).
 
-			r_missing_templates = find_export_template("android_debug.apk") == String() || find_export_template("android_release.apk") == String();
+		if (!bool(p_preset->get("custom_template/use_custom_build"))) {
+			bool dvalid = exists_export_template("android_debug.apk", &err);
+			bool rvalid = exists_export_template("android_release.apk", &err);
 
-			if (p_preset->get("custom_package/debug") != "") {
-				if (FileAccess::exists(p_preset->get("custom_package/debug"))) {
-					r_missing_templates = false;
-				} else {
+			if (p_preset->get("custom_template/debug") != "") {
+				dvalid = FileAccess::exists(p_preset->get("custom_template/debug"));
+				if (!dvalid) {
 					err += TTR("Custom debug template not found.") + "\n";
 				}
 			}
-
-			if (p_preset->get("custom_package/release") != "") {
-				if (FileAccess::exists(p_preset->get("custom_package/release"))) {
-					r_missing_templates = false;
-				} else {
+			if (p_preset->get("custom_template/release") != "") {
+				rvalid = FileAccess::exists(p_preset->get("custom_template/release"));
+				if (!rvalid) {
 					err += TTR("Custom release template not found.") + "\n";
 				}
 			}
+
+			valid = dvalid || rvalid;
+		} else {
+			valid = exists_export_template("android_source.zip", &err);
 		}
+		r_missing_templates = !valid;
 
-		bool valid = !r_missing_templates;
+		// Validate the rest of the configuration.
 
 		String adb = EditorSettings::get_singleton()->get("export/android/adb");
 
@@ -1628,7 +1633,7 @@ public:
 			}
 		}
 
-		if (bool(p_preset->get("custom_package/use_custom_build"))) {
+		if (bool(p_preset->get("custom_template/use_custom_build"))) {
 			String sdk_path = EditorSettings::get_singleton()->get("export/android/custom_build_sdk_path");
 			if (sdk_path == "") {
 				err += TTR("Custom build requires a valid Android SDK path in Editor Settings.") + "\n";
@@ -1949,7 +1954,7 @@ public:
 
 		EditorProgress ep("export", "Exporting for Android", 105, true);
 
-		if (bool(p_preset->get("custom_package/use_custom_build"))) { //custom build
+		if (bool(p_preset->get("custom_template/use_custom_build"))) { //custom build
 			//re-generate build.gradle and AndroidManifest.xml
 
 			{ //test that installed build version is alright
@@ -2017,9 +2022,9 @@ public:
 		} else {
 
 			if (p_debug)
-				src_apk = p_preset->get("custom_package/debug");
+				src_apk = p_preset->get("custom_template/debug");
 			else
-				src_apk = p_preset->get("custom_package/release");
+				src_apk = p_preset->get("custom_template/release");
 
 			src_apk = src_apk.strip_edges();
 			if (src_apk == "") {

+ 20 - 15
platform/iphone/export/export.cpp

@@ -206,8 +206,8 @@ static const LoadingScreenInfo loading_screen_infos[] = {
 
 void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options) {
 
-	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_package/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
-	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_package/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
+	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
+	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
 
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/app_store_team_id"), ""));
 
@@ -848,9 +848,9 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
 	ERR_FAIL_COND_V_MSG(team_id.length() == 0, ERR_CANT_OPEN, "App Store Team ID not specified - cannot configure the project.");
 
 	if (p_debug)
-		src_pkg_name = p_preset->get("custom_package/debug");
+		src_pkg_name = p_preset->get("custom_template/debug");
 	else
-		src_pkg_name = p_preset->get("custom_package/release");
+		src_pkg_name = p_preset->get("custom_template/release");
 
 	if (src_pkg_name == "") {
 		String err;
@@ -1156,25 +1156,30 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
 bool EditorExportPlatformIOS::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
 
 	String err;
-	r_missing_templates = find_export_template("iphone.zip") == String();
+	bool valid = false;
 
-	if (p_preset->get("custom_package/debug") != "") {
-		if (FileAccess::exists(p_preset->get("custom_package/debug"))) {
-			r_missing_templates = false;
-		} else {
+	// Look for export templates (first official, and if defined custom templates).
+
+	bool dvalid = exists_export_template("iphone.zip", &err);
+	bool rvalid = dvalid; // Both in the same ZIP.
+
+	if (p_preset->get("custom_template/debug") != "") {
+		dvalid = FileAccess::exists(p_preset->get("custom_template/debug"));
+		if (!dvalid) {
 			err += TTR("Custom debug template not found.") + "\n";
 		}
 	}
-
-	if (p_preset->get("custom_package/release") != "") {
-		if (FileAccess::exists(p_preset->get("custom_package/release"))) {
-			r_missing_templates = false;
-		} else {
+	if (p_preset->get("custom_template/release") != "") {
+		rvalid = FileAccess::exists(p_preset->get("custom_template/release"));
+		if (!rvalid) {
 			err += TTR("Custom release template not found.") + "\n";
 		}
 	}
 
-	bool valid = !r_missing_templates;
+	valid = dvalid || rvalid;
+	r_missing_templates = !valid;
+
+	// Validate the rest of the configuration.
 
 	String team_id = p_preset->get("application/app_store_team_id");
 	if (team_id.length() == 0) {

+ 12 - 12
platform/javascript/export/export.cpp

@@ -288,32 +288,32 @@ Ref<Texture> EditorExportPlatformJavaScript::get_logo() const {
 
 bool EditorExportPlatformJavaScript::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
 
-	bool valid = false;
 	String err;
+	bool valid = false;
 
-	if (find_export_template(EXPORT_TEMPLATE_WEBASSEMBLY_RELEASE) != "")
-		valid = true;
-	else if (find_export_template(EXPORT_TEMPLATE_WEBASSEMBLY_DEBUG) != "")
-		valid = true;
+	// Look for export templates (first official, and if defined custom templates).
+
+	bool dvalid = exists_export_template(EXPORT_TEMPLATE_WEBASSEMBLY_DEBUG, &err);
+	bool rvalid = exists_export_template(EXPORT_TEMPLATE_WEBASSEMBLY_RELEASE, &err);
 
 	if (p_preset->get("custom_template/debug") != "") {
-		if (FileAccess::exists(p_preset->get("custom_template/debug"))) {
-			valid = true;
-		} else {
+		dvalid = FileAccess::exists(p_preset->get("custom_template/debug"));
+		if (!dvalid) {
 			err += TTR("Custom debug template not found.") + "\n";
 		}
 	}
-
 	if (p_preset->get("custom_template/release") != "") {
-		if (FileAccess::exists(p_preset->get("custom_template/release"))) {
-			valid = true;
-		} else {
+		rvalid = FileAccess::exists(p_preset->get("custom_template/release"));
+		if (!rvalid) {
 			err += TTR("Custom release template not found.") + "\n";
 		}
 	}
 
+	valid = dvalid || rvalid;
 	r_missing_templates = !valid;
 
+	// Validate the rest of the configuration.
+
 	if (p_preset->get("vram_texture_compression/for_mobile")) {
 		String etc_error = test_etc2();
 		if (etc_error != String()) {

+ 18 - 19
platform/osx/export/export.cpp

@@ -118,8 +118,8 @@ void EditorExportPlatformOSX::get_preset_features(const Ref<EditorExportPreset>
 
 void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options) {
 
-	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_package/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
-	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_package/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
+	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
+	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
 
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name"), ""));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/info"), "Made with Godot Engine"));
@@ -459,9 +459,9 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
 	EditorProgress ep("export", "Exporting for OSX", 3, true);
 
 	if (p_debug)
-		src_pkg_name = p_preset->get("custom_package/debug");
+		src_pkg_name = p_preset->get("custom_template/debug");
 	else
-		src_pkg_name = p_preset->get("custom_package/release");
+		src_pkg_name = p_preset->get("custom_template/release");
 
 	if (src_pkg_name == "") {
 		String err;
@@ -796,33 +796,32 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
 
 bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
 
-	bool valid = false;
 	String err;
+	bool valid = false;
 
-	if (exists_export_template("osx.zip", &err)) {
-		valid = true;
-	}
+	// Look for export templates (first official, and if defined custom templates).
 
-	if (p_preset->get("custom_package/debug") != "") {
-		if (FileAccess::exists(p_preset->get("custom_package/debug"))) {
-			valid = true;
-		} else {
+	bool dvalid = exists_export_template("osx.zip", &err);
+	bool rvalid = dvalid; // Both in the same ZIP.
+
+	if (p_preset->get("custom_template/debug") != "") {
+		dvalid = FileAccess::exists(p_preset->get("custom_template/debug"));
+		if (!dvalid) {
 			err += TTR("Custom debug template not found.") + "\n";
 		}
 	}
-
-	if (p_preset->get("custom_package/release") != "") {
-		if (FileAccess::exists(p_preset->get("custom_package/release"))) {
-			valid = true;
-		} else {
+	if (p_preset->get("custom_template/release") != "") {
+		rvalid = FileAccess::exists(p_preset->get("custom_template/release"));
+		if (!rvalid) {
 			err += TTR("Custom release template not found.") + "\n";
 		}
 	}
 
+	valid = dvalid || rvalid;
+	r_missing_templates = !valid;
+
 	if (!err.empty())
 		r_error = err;
-
-	r_missing_templates = !valid;
 	return valid;
 }
 

+ 18 - 31
platform/uwp/export/export.cpp

@@ -1090,15 +1090,14 @@ public:
 	}
 
 	virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
+
 		String err;
-		bool valid = true;
-		Platform arch = (Platform)(int)(p_preset->get("architecture/target"));
+		bool valid = false;
 
-		String custom_debug_binary = p_preset->get("custom_template/debug");
-		String custom_release_binary = p_preset->get("custom_template/release");
+		// Look for export templates (first official, and if defined custom templates).
 
+		Platform arch = (Platform)(int)(p_preset->get("architecture/target"));
 		String platform_infix;
-
 		switch (arch) {
 			case EditorExportPlatformUWP::ARM: {
 				platform_infix = "arm";
@@ -1111,38 +1110,26 @@ public:
 			} break;
 		}
 
-		if (!exists_export_template("uwp_" + platform_infix + "_debug.zip", &err) || !exists_export_template("uwp_" + platform_infix + "_release.zip", &err)) {
-			valid = false;
-			r_missing_templates = true;
-		}
+		bool dvalid = exists_export_template("uwp_" + platform_infix + "_debug.zip", &err);
+		bool rvalid = exists_export_template("uwp_" + platform_infix + "_release.zip", &err);
 
-		if (!valid && custom_debug_binary == "" && custom_release_binary == "") {
-			if (!err.empty()) {
-				r_error = err;
+		if (p_preset->get("custom_template/debug") != "") {
+			dvalid = FileAccess::exists(p_preset->get("custom_template/debug"));
+			if (!dvalid) {
+				err += TTR("Custom debug template not found.") + "\n";
 			}
-			return valid;
 		}
-
-		bool dvalid = true;
-		bool rvalid = true;
-
-		if (!FileAccess::exists(custom_debug_binary)) {
-			dvalid = false;
-			err += TTR("Custom debug template not found.") + "\n";
-		}
-
-		if (!FileAccess::exists(custom_release_binary)) {
-			rvalid = false;
-			err += TTR("Custom release template not found.") + "\n";
+		if (p_preset->get("custom_template/release") != "") {
+			rvalid = FileAccess::exists(p_preset->get("custom_template/release"));
+			if (!rvalid) {
+				err += TTR("Custom release template not found.") + "\n";
+			}
 		}
 
-		if (dvalid || rvalid)
-			valid = true;
+		valid = dvalid || rvalid;
+		r_missing_templates = !valid;
 
-		if (!valid) {
-			r_error = err;
-			return valid;
-		}
+		// Validate the rest of the configuration.
 
 		if (!_valid_resource_name(p_preset->get("package/short_name"))) {
 			valid = false;