summaryrefslogtreecommitdiff
path: root/platform/windows/export
diff options
context:
space:
mode:
Diffstat (limited to 'platform/windows/export')
-rw-r--r--platform/windows/export/export.cpp59
-rw-r--r--platform/windows/export/export.h58
-rw-r--r--platform/windows/export/export_plugin.cpp519
-rw-r--r--platform/windows/export/export_plugin.h97
4 files changed, 606 insertions, 127 deletions
diff --git a/platform/windows/export/export.cpp b/platform/windows/export/export.cpp
index 8f91756c02..4112bb84b5 100644
--- a/platform/windows/export/export.cpp
+++ b/platform/windows/export/export.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* export.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
+/**************************************************************************/
+/* export.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
#include "export.h"
@@ -51,7 +51,6 @@ void register_windows_exporter() {
Ref<EditorExportPlatformWindows> platform;
platform.instantiate();
- platform->set_logo(ImageTexture::create_from_image(memnew(Image(_windows_logo))));
platform->set_name("Windows Desktop");
platform->set_os_name("Windows");
diff --git a/platform/windows/export/export.h b/platform/windows/export/export.h
index 1054e04b1e..f5bf83bb48 100644
--- a/platform/windows/export/export.h
+++ b/platform/windows/export/export.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* export.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
+/**************************************************************************/
+/* export.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
#ifndef WINDOWS_EXPORT_H
#define WINDOWS_EXPORT_H
diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp
index d15380ac7a..4107a8a17e 100644
--- a/platform/windows/export/export_plugin.cpp
+++ b/platform/windows/export/export_plugin.cpp
@@ -1,37 +1,160 @@
-/*************************************************************************/
-/* export_plugin.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
+/**************************************************************************/
+/* export_plugin.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
#include "export_plugin.h"
#include "core/config/project_settings.h"
+#include "core/io/image_loader.h"
#include "editor/editor_node.h"
+#include "editor/editor_paths.h"
+#include "editor/editor_scale.h"
+#include "platform/windows/logo_svg.gen.h"
+#include "platform/windows/run_icon_svg.gen.h"
+
+#include "modules/modules_enabled.gen.h" // For svg.
+#ifdef MODULE_SVG_ENABLED
+#include "modules/svg/image_loader_svg.h"
+#endif
+
+Error EditorExportPlatformWindows::_process_icon(const Ref<EditorExportPreset> &p_preset, const String &p_src_path, const String &p_dst_path) {
+ static const uint8_t icon_size[] = { 16, 32, 48, 64, 128, 0 /*256*/ };
+
+ struct IconData {
+ Vector<uint8_t> data;
+ uint8_t pal_colors = 0;
+ uint16_t planes = 0;
+ uint16_t bpp = 32;
+ };
+
+ HashMap<uint8_t, IconData> images;
+ Error err;
+
+ if (p_src_path.get_extension() == "ico") {
+ Ref<FileAccess> f = FileAccess::open(p_src_path, FileAccess::READ, &err);
+ if (err != OK) {
+ return err;
+ }
+
+ // Read ICONDIR.
+ f->get_16(); // Reserved.
+ uint16_t icon_type = f->get_16(); // Image type: 1 - ICO.
+ uint16_t icon_count = f->get_16(); // Number of images.
+ ERR_FAIL_COND_V(icon_type != 1, ERR_CANT_OPEN);
+
+ for (uint16_t i = 0; i < icon_count; i++) {
+ // Read ICONDIRENTRY.
+ uint16_t w = f->get_8(); // Width in pixels.
+ uint16_t h = f->get_8(); // Height in pixels.
+ uint8_t pal_colors = f->get_8(); // Number of colors in the palette (0 - no palette).
+ f->get_8(); // Reserved.
+ uint16_t planes = f->get_16(); // Number of color planes.
+ uint16_t bpp = f->get_16(); // Bits per pixel.
+ uint32_t img_size = f->get_32(); // Image data size in bytes.
+ uint32_t img_offset = f->get_32(); // Image data offset.
+ if (w != h) {
+ continue;
+ }
+
+ // Read image data.
+ uint64_t prev_offset = f->get_position();
+ images[w].pal_colors = pal_colors;
+ images[w].planes = planes;
+ images[w].bpp = bpp;
+ images[w].data.resize(img_size);
+ f->seek(img_offset);
+ f->get_buffer(images[w].data.ptrw(), img_size);
+ f->seek(prev_offset);
+ }
+ } else {
+ Ref<Image> src_image;
+ src_image.instantiate();
+ err = ImageLoader::load_image(p_src_path, src_image);
+ ERR_FAIL_COND_V(err != OK || src_image->is_empty(), ERR_CANT_OPEN);
+ for (size_t i = 0; i < sizeof(icon_size) / sizeof(icon_size[0]); ++i) {
+ int size = (icon_size[i] == 0) ? 256 : icon_size[i];
+
+ Ref<Image> res_image = src_image->duplicate();
+ ERR_FAIL_COND_V(res_image.is_null() || res_image->is_empty(), ERR_CANT_OPEN);
+ res_image->resize(size, size, (Image::Interpolation)(p_preset->get("application/icon_interpolation").operator int()));
+ images[icon_size[i]].data = res_image->save_png_to_buffer();
+ }
+ }
+
+ uint16_t valid_icon_count = 0;
+ for (size_t i = 0; i < sizeof(icon_size) / sizeof(icon_size[0]); ++i) {
+ if (images.has(icon_size[i])) {
+ valid_icon_count++;
+ } else {
+ int size = (icon_size[i] == 0) ? 256 : icon_size[i];
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), vformat(TTR("Icon size \"%d\" is missing."), size));
+ }
+ }
+ ERR_FAIL_COND_V(valid_icon_count == 0, ERR_CANT_OPEN);
+
+ Ref<FileAccess> fw = FileAccess::open(p_dst_path, FileAccess::WRITE, &err);
+ if (err != OK) {
+ return err;
+ }
+
+ // Write ICONDIR.
+ fw->store_16(0); // Reserved.
+ fw->store_16(1); // Image type: 1 - ICO.
+ fw->store_16(valid_icon_count); // Number of images.
+
+ // Write ICONDIRENTRY.
+ uint32_t img_offset = 6 + 16 * valid_icon_count;
+ for (size_t i = 0; i < sizeof(icon_size) / sizeof(icon_size[0]); ++i) {
+ if (images.has(icon_size[i])) {
+ const IconData &di = images[icon_size[i]];
+ fw->store_8(icon_size[i]); // Width in pixels.
+ fw->store_8(icon_size[i]); // Height in pixels.
+ fw->store_8(di.pal_colors); // Number of colors in the palette (0 - no palette).
+ fw->store_8(0); // Reserved.
+ fw->store_16(di.planes); // Number of color planes.
+ fw->store_16(di.bpp); // Bits per pixel.
+ fw->store_32(di.data.size()); // Image data size in bytes.
+ fw->store_32(img_offset); // Image data offset.
+
+ img_offset += di.data.size();
+ }
+ }
+
+ // Write image data.
+ for (size_t i = 0; i < sizeof(icon_size) / sizeof(icon_size[0]); ++i) {
+ if (images.has(icon_size[i])) {
+ const IconData &di = images[icon_size[i]];
+ fw->store_buffer(di.data.ptr(), di.data.size());
+ }
+ }
+ return OK;
+}
Error EditorExportPlatformWindows::sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path) {
if (p_preset->get("codesign/enable")) {
@@ -53,9 +176,39 @@ Error EditorExportPlatformWindows::modify_template(const Ref<EditorExportPreset>
}
Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
- String pck_path = p_path;
- if (p_preset->get("binary_format/embed_pck")) {
- pck_path = p_path.get_basename() + ".tmp";
+ bool export_as_zip = p_path.ends_with("zip");
+ bool embedded = p_preset->get("binary_format/embed_pck");
+
+ String pkg_name;
+ if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "") {
+ pkg_name = String(ProjectSettings::get_singleton()->get("application/config/name"));
+ } else {
+ pkg_name = "Unnamed";
+ }
+
+ pkg_name = OS::get_singleton()->get_safe_dir_name(pkg_name);
+
+ // Setup temp folder.
+ String path = p_path;
+ String tmp_dir_path = EditorPaths::get_singleton()->get_cache_dir().path_join(pkg_name);
+ Ref<DirAccess> tmp_app_dir = DirAccess::create_for_path(tmp_dir_path);
+ if (export_as_zip) {
+ if (tmp_app_dir.is_null()) {
+ return ERR_CANT_CREATE;
+ }
+ if (DirAccess::exists(tmp_dir_path)) {
+ if (tmp_app_dir->change_dir(tmp_dir_path) == OK) {
+ tmp_app_dir->erase_contents_recursive();
+ }
+ }
+ tmp_app_dir->make_dir_recursive(tmp_dir_path);
+ path = tmp_dir_path.path_join(p_path.get_file().get_basename() + ".exe");
+ }
+
+ // Export project.
+ String pck_path = path;
+ if (embedded) {
+ pck_path = pck_path.get_basename() + ".tmp";
}
Error err = EditorExportPlatformPC::export_project(p_preset, p_debug, pck_path, p_flags);
if (p_preset->get("codesign/enable") && err == OK) {
@@ -66,7 +219,7 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset>
}
}
- if (p_preset->get("binary_format/embed_pck") && err == OK) {
+ if (embedded && err == OK) {
Ref<DirAccess> tmp_dir = DirAccess::create_for_path(p_path.get_base_dir());
err = tmp_dir->rename(pck_path, p_path);
if (err != OK) {
@@ -74,6 +227,27 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset>
}
}
+ // ZIP project.
+ if (export_as_zip) {
+ if (FileAccess::exists(p_path)) {
+ OS::get_singleton()->move_to_trash(p_path);
+ }
+
+ Ref<FileAccess> io_fa_dst;
+ zlib_filefunc_def io_dst = zipio_create_io(&io_fa_dst);
+ zipFile zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io_dst);
+
+ zip_folder_recursive(zip, tmp_dir_path, "", pkg_name);
+
+ zipClose(zip, nullptr);
+
+ if (tmp_app_dir->change_dir(tmp_dir_path) == OK) {
+ tmp_app_dir->erase_contents_recursive();
+ tmp_app_dir->change_dir("..");
+ tmp_app_dir->remove(pkg_name);
+ }
+ }
+
return err;
}
@@ -84,6 +258,7 @@ String EditorExportPlatformWindows::get_template_file_name(const String &p_targe
List<String> EditorExportPlatformWindows::get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const {
List<String> list;
list.push_back("exe");
+ list.push_back("zip");
return list;
}
@@ -97,6 +272,7 @@ bool EditorExportPlatformWindows::get_export_option_visibility(const EditorExpor
void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_options) {
EditorExportPlatformPC::get_export_options(r_options);
+
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "binary_format/architecture", PROPERTY_HINT_ENUM, "x86_64,x86_32,arm64"), "x86_64"));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/enable"), false));
@@ -110,7 +286,9 @@ void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_optio
r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "codesign/custom_options"), PackedStringArray()));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "application/modify_resources"), true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.ico"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.ico,*.png,*.webp,*.svg"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/console_wrapper_icon", PROPERTY_HINT_FILE, "*.ico,*.png,*.webp,*.svg"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/icon_interpolation", PROPERTY_HINT_ENUM, "Nearest neighbor,Bilinear,Cubic,Trilinear,Lanczos"), 4));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0.0"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/product_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0.0"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/company_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Company Name"), ""));
@@ -118,9 +296,32 @@ void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_optio
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_description"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/trademarks"), ""));
+
+ String run_script = "Expand-Archive -LiteralPath '{temp_dir}\\{archive_name}' -DestinationPath '{temp_dir}'\n"
+ "$action = New-ScheduledTaskAction -Execute '{temp_dir}\\{exe_name}' -Argument '{cmd_args}'\n"
+ "$trigger = New-ScheduledTaskTrigger -Once -At 00:00\n"
+ "$settings = New-ScheduledTaskSettingsSet\n"
+ "$task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings\n"
+ "Register-ScheduledTask godot_remote_debug -InputObject $task -Force:$true\n"
+ "Start-ScheduledTask -TaskName godot_remote_debug\n"
+ "while (Get-ScheduledTask -TaskName godot_remote_debug | ? State -eq running) { Start-Sleep -Milliseconds 100 }\n"
+ "Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue";
+
+ String cleanup_script = "Stop-ScheduledTask -TaskName godot_remote_debug -ErrorAction:SilentlyContinue\n"
+ "Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue\n"
+ "Remove-Item -Recurse -Force '{temp_dir}'";
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "ssh_remote_deploy/enabled"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/host"), "user@host_ip"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/port"), "22"));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/extra_args_ssh", PROPERTY_HINT_MULTILINE_TEXT), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/extra_args_scp", PROPERTY_HINT_MULTILINE_TEXT), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/run_script", PROPERTY_HINT_MULTILINE_TEXT), run_script));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/cleanup_script", PROPERTY_HINT_MULTILINE_TEXT), cleanup_script));
}
-Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path, bool p_set_icon) {
+Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path, bool p_console_icon) {
String rcedit_path = EDITOR_GET("export/windows/rcedit");
if (rcedit_path != String() && !FileAccess::exists(rcedit_path)) {
@@ -147,6 +348,21 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset
#endif
String icon_path = ProjectSettings::get_singleton()->globalize_path(p_preset->get("application/icon"));
+ if (p_console_icon) {
+ String console_icon_path = ProjectSettings::get_singleton()->globalize_path(p_preset->get("application/console_wrapper_icon"));
+ if (!console_icon_path.is_empty() && FileAccess::exists(console_icon_path)) {
+ icon_path = console_icon_path;
+ }
+ }
+
+ String tmp_icon_path = EditorPaths::get_singleton()->get_cache_dir().path_join("_rcedit.ico");
+ if (!icon_path.is_empty()) {
+ if (_process_icon(p_preset, icon_path, tmp_icon_path) != OK) {
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), vformat(TTR("Invalid icon file \"%s\"."), icon_path));
+ icon_path = String();
+ }
+ }
+
String file_verion = p_preset->get("application/file_version");
String product_version = p_preset->get("application/product_version");
String company_name = p_preset->get("application/company_name");
@@ -158,9 +374,9 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset
List<String> args;
args.push_back(p_path);
- if (!icon_path.is_empty() && p_set_icon) {
+ if (!icon_path.is_empty()) {
args.push_back("--set-icon");
- args.push_back(icon_path);
+ args.push_back(tmp_icon_path);
}
if (!file_verion.is_empty()) {
args.push_back("--set-file-version");
@@ -204,6 +420,11 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset
String str;
Error err = OS::get_singleton()->execute(rcedit_path, args, &str, nullptr, true);
+
+ if (FileAccess::exists(tmp_icon_path)) {
+ DirAccess::remove_file_or_error(tmp_icon_path);
+ }
+
if (err != OK || (str.find("not found") != -1) || (str.find("not recognized") != -1)) {
add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), TTR("Could not start rcedit executable. Configure rcedit path in the Editor Settings (Export > Windows > rcedit), or disable \"Application > Modify Resources\" in the export preset."));
return err;
@@ -522,3 +743,227 @@ Error EditorExportPlatformWindows::fixup_embedded_pck(const String &p_path, int6
}
return OK;
}
+
+Ref<Texture2D> EditorExportPlatformWindows::get_run_icon() const {
+ return run_icon;
+}
+
+bool EditorExportPlatformWindows::poll_export() {
+ Ref<EditorExportPreset> preset;
+
+ for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) {
+ Ref<EditorExportPreset> ep = EditorExport::get_singleton()->get_export_preset(i);
+ if (ep->is_runnable() && ep->get_platform() == this) {
+ preset = ep;
+ break;
+ }
+ }
+
+ int prev = menu_options;
+ menu_options = (preset.is_valid() && preset->get("ssh_remote_deploy/enabled").operator bool());
+ if (ssh_pid != 0 || !cleanup_commands.is_empty()) {
+ if (menu_options == 0) {
+ cleanup();
+ } else {
+ menu_options += 1;
+ }
+ }
+ return menu_options != prev;
+}
+
+Ref<ImageTexture> EditorExportPlatformWindows::get_option_icon(int p_index) const {
+ return p_index == 1 ? stop_icon : EditorExportPlatform::get_option_icon(p_index);
+}
+
+int EditorExportPlatformWindows::get_options_count() const {
+ return menu_options;
+}
+
+String EditorExportPlatformWindows::get_option_label(int p_index) const {
+ return (p_index) ? TTR("Stop and uninstall") : TTR("Run on remote Windows system");
+}
+
+String EditorExportPlatformWindows::get_option_tooltip(int p_index) const {
+ return (p_index) ? TTR("Stop and uninstall running project from the remote system") : TTR("Run exported project on remote Windows system");
+}
+
+void EditorExportPlatformWindows::cleanup() {
+ if (ssh_pid != 0 && OS::get_singleton()->is_process_running(ssh_pid)) {
+ print_line("Terminating connection...");
+ OS::get_singleton()->kill(ssh_pid);
+ OS::get_singleton()->delay_usec(1000);
+ }
+
+ if (!cleanup_commands.is_empty()) {
+ print_line("Stopping and deleting previous version...");
+ for (const SSHCleanupCommand &cmd : cleanup_commands) {
+ if (cmd.wait) {
+ ssh_run_on_remote(cmd.host, cmd.port, cmd.ssh_args, cmd.cmd_args);
+ } else {
+ ssh_run_on_remote_no_wait(cmd.host, cmd.port, cmd.ssh_args, cmd.cmd_args);
+ }
+ }
+ }
+ ssh_pid = 0;
+ cleanup_commands.clear();
+}
+
+Error EditorExportPlatformWindows::run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) {
+ cleanup();
+ if (p_device) { // Stop command, cleanup only.
+ return OK;
+ }
+
+ EditorProgress ep("run", TTR("Running..."), 5);
+
+ const String dest = EditorPaths::get_singleton()->get_cache_dir().path_join("windows");
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ if (!da->dir_exists(dest)) {
+ Error err = da->make_dir_recursive(dest);
+ if (err != OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not create temp directory:") + "\n" + dest);
+ return err;
+ }
+ }
+
+ String host = p_preset->get("ssh_remote_deploy/host").operator String();
+ String port = p_preset->get("ssh_remote_deploy/port").operator String();
+ if (port.is_empty()) {
+ port = "22";
+ }
+ Vector<String> extra_args_ssh = p_preset->get("ssh_remote_deploy/extra_args_ssh").operator String().split(" ", false);
+ Vector<String> extra_args_scp = p_preset->get("ssh_remote_deploy/extra_args_scp").operator String().split(" ", false);
+
+ const String basepath = dest.path_join("tmp_windows_export");
+
+#define CLEANUP_AND_RETURN(m_err) \
+ { \
+ if (da->file_exists(basepath + ".zip")) { \
+ da->remove(basepath + ".zip"); \
+ } \
+ if (da->file_exists(basepath + "_start.ps1")) { \
+ da->remove(basepath + "_start.ps1"); \
+ } \
+ if (da->file_exists(basepath + "_clean.ps1")) { \
+ da->remove(basepath + "_clean.ps1"); \
+ } \
+ return m_err; \
+ } \
+ ((void)0)
+
+ if (ep.step(TTR("Exporting project..."), 1)) {
+ return ERR_SKIP;
+ }
+ Error err = export_project(p_preset, true, basepath + ".zip", p_debug_flags);
+ if (err != OK) {
+ DirAccess::remove_file_or_error(basepath + ".zip");
+ return err;
+ }
+
+ String cmd_args;
+ {
+ Vector<String> cmd_args_list;
+ gen_debug_flags(cmd_args_list, p_debug_flags);
+ for (int i = 0; i < cmd_args_list.size(); i++) {
+ if (i != 0) {
+ cmd_args += " ";
+ }
+ cmd_args += cmd_args_list[i];
+ }
+ }
+
+ const bool use_remote = (p_debug_flags & DEBUG_FLAG_REMOTE_DEBUG) || (p_debug_flags & DEBUG_FLAG_DUMB_CLIENT);
+ int dbg_port = EditorSettings::get_singleton()->get("network/debug/remote_port");
+
+ print_line("Creating temporary directory...");
+ ep.step(TTR("Creating temporary directory..."), 2);
+ String temp_dir;
+ err = ssh_run_on_remote(host, port, extra_args_ssh, "powershell -command \\\"\\$tmp = Join-Path \\$Env:Temp \\$(New-Guid); New-Item -Type Directory -Path \\$tmp | Out-Null; Write-Output \\$tmp\\\"", &temp_dir);
+ if (err != OK || temp_dir.is_empty()) {
+ CLEANUP_AND_RETURN(err);
+ }
+
+ print_line("Uploading archive...");
+ ep.step(TTR("Uploading archive..."), 3);
+ err = ssh_push_to_remote(host, port, extra_args_scp, basepath + ".zip", temp_dir);
+ if (err != OK) {
+ CLEANUP_AND_RETURN(err);
+ }
+
+ {
+ String run_script = p_preset->get("ssh_remote_deploy/run_script");
+ run_script = run_script.replace("{temp_dir}", temp_dir);
+ run_script = run_script.replace("{archive_name}", basepath.get_file() + ".zip");
+ run_script = run_script.replace("{exe_name}", basepath.get_file() + ".exe");
+ run_script = run_script.replace("{cmd_args}", cmd_args);
+
+ Ref<FileAccess> f = FileAccess::open(basepath + "_start.ps1", FileAccess::WRITE);
+ if (f.is_null()) {
+ CLEANUP_AND_RETURN(err);
+ }
+
+ f->store_string(run_script);
+ }
+
+ {
+ String clean_script = p_preset->get("ssh_remote_deploy/cleanup_script");
+ clean_script = clean_script.replace("{temp_dir}", temp_dir);
+ clean_script = clean_script.replace("{archive_name}", basepath.get_file() + ".zip");
+ clean_script = clean_script.replace("{exe_name}", basepath.get_file() + ".exe");
+ clean_script = clean_script.replace("{cmd_args}", cmd_args);
+
+ Ref<FileAccess> f = FileAccess::open(basepath + "_clean.ps1", FileAccess::WRITE);
+ if (f.is_null()) {
+ CLEANUP_AND_RETURN(err);
+ }
+
+ f->store_string(clean_script);
+ }
+
+ print_line("Uploading scripts...");
+ ep.step(TTR("Uploading scripts..."), 4);
+ err = ssh_push_to_remote(host, port, extra_args_scp, basepath + "_start.ps1", temp_dir);
+ if (err != OK) {
+ CLEANUP_AND_RETURN(err);
+ }
+ err = ssh_push_to_remote(host, port, extra_args_scp, basepath + "_clean.ps1", temp_dir);
+ if (err != OK) {
+ CLEANUP_AND_RETURN(err);
+ }
+
+ print_line("Starting project...");
+ ep.step(TTR("Starting project..."), 5);
+ err = ssh_run_on_remote_no_wait(host, port, extra_args_ssh, vformat("powershell -file \"%s\\%s\"", temp_dir, basepath.get_file() + "_start.ps1"), &ssh_pid, (use_remote) ? dbg_port : -1);
+ if (err != OK) {
+ CLEANUP_AND_RETURN(err);
+ }
+
+ cleanup_commands.clear();
+ cleanup_commands.push_back(SSHCleanupCommand(host, port, extra_args_ssh, vformat("powershell -file \"%s\\%s\"", temp_dir, basepath.get_file() + "_clean.ps1")));
+
+ print_line("Project started.");
+
+ CLEANUP_AND_RETURN(OK);
+#undef CLEANUP_AND_RETURN
+}
+
+EditorExportPlatformWindows::EditorExportPlatformWindows() {
+#ifdef MODULE_SVG_ENABLED
+ Ref<Image> img = memnew(Image);
+ const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE);
+
+ ImageLoaderSVG img_loader;
+ img_loader.create_image_from_string(img, _windows_logo_svg, EDSCALE, upsample, false);
+ set_logo(ImageTexture::create_from_image(img));
+
+ img_loader.create_image_from_string(img, _windows_run_icon_svg, EDSCALE, upsample, false);
+ run_icon = ImageTexture::create_from_image(img);
+#endif
+
+ Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme();
+ if (theme.is_valid()) {
+ stop_icon = theme->get_icon(SNAME("Stop"), SNAME("EditorIcons"));
+ } else {
+ stop_icon.instantiate();
+ }
+}
diff --git a/platform/windows/export/export_plugin.h b/platform/windows/export/export_plugin.h
index ec3b60aa76..fa75a17a1f 100644
--- a/platform/windows/export/export_plugin.h
+++ b/platform/windows/export/export_plugin.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* export_plugin.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
+/**************************************************************************/
+/* export_plugin.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
#ifndef WINDOWS_EXPORT_PLUGIN_H
#define WINDOWS_EXPORT_PLUGIN_H
@@ -35,10 +35,34 @@
#include "core/os/os.h"
#include "editor/editor_settings.h"
#include "editor/export/editor_export_platform_pc.h"
-#include "platform/windows/logo.gen.h"
class EditorExportPlatformWindows : public EditorExportPlatformPC {
- Error _rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path, bool p_set_icon);
+ struct SSHCleanupCommand {
+ String host;
+ String port;
+ Vector<String> ssh_args;
+ String cmd_args;
+ bool wait = false;
+
+ SSHCleanupCommand(){};
+ SSHCleanupCommand(const String &p_host, const String &p_port, const Vector<String> &p_ssh_arg, const String &p_cmd_args, bool p_wait = false) {
+ host = p_host;
+ port = p_port;
+ ssh_args = p_ssh_arg;
+ cmd_args = p_cmd_args;
+ wait = p_wait;
+ };
+ };
+
+ Ref<ImageTexture> run_icon;
+ Ref<ImageTexture> stop_icon;
+
+ Vector<SSHCleanupCommand> cleanup_commands;
+ OS::ProcessID ssh_pid = 0;
+ int menu_options = 0;
+
+ Error _process_icon(const Ref<EditorExportPreset> &p_preset, const String &p_src_path, const String &p_dst_path);
+ Error _rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path, bool p_console_icon);
Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path);
public:
@@ -52,6 +76,17 @@ public:
virtual bool get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option, const HashMap<StringName, Variant> &p_options) const override;
virtual String get_template_file_name(const String &p_target, const String &p_arch) const override;
virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) override;
+
+ virtual Ref<Texture2D> get_run_icon() const override;
+ virtual bool poll_export() override;
+ virtual Ref<ImageTexture> get_option_icon(int p_index) const override;
+ virtual int get_options_count() const override;
+ virtual String get_option_label(int p_index) const override;
+ virtual String get_option_tooltip(int p_index) const override;
+ virtual Error run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) override;
+ virtual void cleanup() override;
+
+ EditorExportPlatformWindows();
};
#endif // WINDOWS_EXPORT_PLUGIN_H