Merge pull request #61624 from bruvzg/export_errors
This commit is contained in:
commit
49205ccaa6
16 changed files with 485 additions and 235 deletions
|
@ -22,6 +22,7 @@
|
||||||
<argument index="0" name="image" type="Texture" />
|
<argument index="0" name="image" type="Texture" />
|
||||||
<argument index="1" name="width" type="int" default="0" />
|
<argument index="1" name="width" type="int" default="0" />
|
||||||
<argument index="2" name="height" type="int" default="0" />
|
<argument index="2" name="height" type="int" default="0" />
|
||||||
|
<argument index="3" name="align" type="int" enum="RichTextLabel.InlineAlign" default="2" />
|
||||||
<description>
|
<description>
|
||||||
Adds an image's opening and closing tags to the tag stack, optionally providing a [code]width[/code] and [code]height[/code] to resize the image.
|
Adds an image's opening and closing tags to the tag stack, optionally providing a [code]width[/code] and [code]height[/code] to resize the image.
|
||||||
If [code]width[/code] or [code]height[/code] is set to 0, the image size will be adjusted in order to keep the original aspect ratio.
|
If [code]width[/code] or [code]height[/code] is set to 0, the image size will be adjusted in order to keep the original aspect ratio.
|
||||||
|
@ -335,6 +336,18 @@
|
||||||
<constant name="ALIGN_FILL" value="3" enum="Align">
|
<constant name="ALIGN_FILL" value="3" enum="Align">
|
||||||
Makes text fill width.
|
Makes text fill width.
|
||||||
</constant>
|
</constant>
|
||||||
|
<constant name="INLINE_ALIGN_TOP" value="0" enum="InlineAlign">
|
||||||
|
Aligns top of the inline image to the top of the text.
|
||||||
|
</constant>
|
||||||
|
<constant name="INLINE_ALIGN_CENTER" value="1" enum="InlineAlign">
|
||||||
|
Aligns center of the inline image to the center of the text.
|
||||||
|
</constant>
|
||||||
|
<constant name="INLINE_ALIGN_BASELINE" value="2" enum="InlineAlign">
|
||||||
|
Aligns bottom of the inline image to the baseline of the text.
|
||||||
|
</constant>
|
||||||
|
<constant name="INLINE_ALIGN_BOTTOM" value="3" enum="InlineAlign">
|
||||||
|
Aligns bottom of the inline image to the bottom of the text.
|
||||||
|
</constant>
|
||||||
<constant name="LIST_NUMBERS" value="0" enum="ListType">
|
<constant name="LIST_NUMBERS" value="0" enum="ListType">
|
||||||
Each list item has a number marker.
|
Each list item has a number marker.
|
||||||
</constant>
|
</constant>
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include "editor/editor_file_system.h"
|
#include "editor/editor_file_system.h"
|
||||||
#include "editor/plugins/script_editor_plugin.h"
|
#include "editor/plugins/script_editor_plugin.h"
|
||||||
#include "editor_node.h"
|
#include "editor_node.h"
|
||||||
|
#include "editor_scale.h"
|
||||||
#include "editor_settings.h"
|
#include "editor_settings.h"
|
||||||
#include "scene/resources/resource_format_text.h"
|
#include "scene/resources/resource_format_text.h"
|
||||||
|
|
||||||
|
@ -220,6 +221,82 @@ EditorExportPreset::EditorExportPreset() :
|
||||||
|
|
||||||
///////////////////////////////////
|
///////////////////////////////////
|
||||||
|
|
||||||
|
bool EditorExportPlatform::fill_log_messages(RichTextLabel *p_log, Error p_err) {
|
||||||
|
bool has_messages = false;
|
||||||
|
|
||||||
|
int msg_count = get_message_count();
|
||||||
|
|
||||||
|
p_log->add_text(TTR("Project export for platform:") + " ");
|
||||||
|
p_log->add_image(get_logo(), 16 * EDSCALE, 16 * EDSCALE, RichTextLabel::INLINE_ALIGN_CENTER);
|
||||||
|
p_log->add_text(" ");
|
||||||
|
p_log->add_text(get_name());
|
||||||
|
p_log->add_text(" - ");
|
||||||
|
if (p_err == OK) {
|
||||||
|
if (get_worst_message_type() >= EditorExportPlatform::EXPORT_MESSAGE_WARNING) {
|
||||||
|
p_log->add_image(EditorNode::get_singleton()->get_gui_base()->get_icon("StatusWarning", "EditorIcons"), 16 * EDSCALE, 16 * EDSCALE, RichTextLabel::INLINE_ALIGN_CENTER);
|
||||||
|
p_log->add_text(" ");
|
||||||
|
p_log->add_text(TTR("Completed with errors."));
|
||||||
|
has_messages = true;
|
||||||
|
} else {
|
||||||
|
p_log->add_image(EditorNode::get_singleton()->get_gui_base()->get_icon("StatusSuccess", "EditorIcons"), 16 * EDSCALE, 16 * EDSCALE, RichTextLabel::INLINE_ALIGN_CENTER);
|
||||||
|
p_log->add_text(" ");
|
||||||
|
p_log->add_text(TTR("Completed sucessfully."));
|
||||||
|
if (msg_count > 0) {
|
||||||
|
has_messages = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
p_log->add_image(EditorNode::get_singleton()->get_gui_base()->get_icon("StatusError", "EditorIcons"), 16 * EDSCALE, 16 * EDSCALE, RichTextLabel::INLINE_ALIGN_CENTER);
|
||||||
|
p_log->add_text(" ");
|
||||||
|
p_log->add_text(TTR("Failed."));
|
||||||
|
has_messages = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg_count) {
|
||||||
|
p_log->push_table(2);
|
||||||
|
p_log->set_table_column_expand(0, false);
|
||||||
|
p_log->set_table_column_expand(1, true);
|
||||||
|
for (int m = 0; m < msg_count; m++) {
|
||||||
|
EditorExportPlatform::ExportMessage msg = get_message(m);
|
||||||
|
Color color = EditorNode::get_singleton()->get_gui_base()->get_color("font_color", "Label");
|
||||||
|
Ref<Texture> icon;
|
||||||
|
|
||||||
|
switch (msg.msg_type) {
|
||||||
|
case EditorExportPlatform::EXPORT_MESSAGE_INFO: {
|
||||||
|
color = EditorNode::get_singleton()->get_gui_base()->get_color("font_color", "Editor") * Color(1, 1, 1, 0.6);
|
||||||
|
} break;
|
||||||
|
case EditorExportPlatform::EXPORT_MESSAGE_WARNING: {
|
||||||
|
icon = EditorNode::get_singleton()->get_gui_base()->get_icon("Warning", "EditorIcons");
|
||||||
|
color = EditorNode::get_singleton()->get_gui_base()->get_color("warning_color", "Editor");
|
||||||
|
} break;
|
||||||
|
case EditorExportPlatform::EXPORT_MESSAGE_ERROR: {
|
||||||
|
icon = EditorNode::get_singleton()->get_gui_base()->get_icon("Error", "EditorIcons");
|
||||||
|
color = EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor");
|
||||||
|
} break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
p_log->push_cell();
|
||||||
|
p_log->add_text("\t");
|
||||||
|
if (icon.is_valid()) {
|
||||||
|
p_log->add_image(icon);
|
||||||
|
}
|
||||||
|
p_log->pop();
|
||||||
|
|
||||||
|
p_log->push_cell();
|
||||||
|
p_log->push_color(color);
|
||||||
|
p_log->add_text(vformat("[%s]: %s", msg.category, msg.text));
|
||||||
|
p_log->pop();
|
||||||
|
p_log->pop();
|
||||||
|
}
|
||||||
|
p_log->pop();
|
||||||
|
p_log->add_newline();
|
||||||
|
}
|
||||||
|
p_log->add_newline();
|
||||||
|
return has_messages;
|
||||||
|
}
|
||||||
|
|
||||||
void EditorExportPlatform::gen_debug_flags(Vector<String> &r_flags, int p_flags) {
|
void EditorExportPlatform::gen_debug_flags(Vector<String> &r_flags, int p_flags) {
|
||||||
String host = EditorSettings::get_singleton()->get("network/debug/remote_host");
|
String host = EditorSettings::get_singleton()->get("network/debug/remote_host");
|
||||||
int remote_port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port");
|
int remote_port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port");
|
||||||
|
@ -961,7 +1038,10 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, c
|
||||||
|
|
||||||
String tmppath = EditorSettings::get_singleton()->get_cache_dir().plus_file("packtmp");
|
String tmppath = EditorSettings::get_singleton()->get_cache_dir().plus_file("packtmp");
|
||||||
FileAccess *ftmp = FileAccess::open(tmppath, FileAccess::WRITE);
|
FileAccess *ftmp = FileAccess::open(tmppath, FileAccess::WRITE);
|
||||||
ERR_FAIL_COND_V_MSG(!ftmp, ERR_CANT_CREATE, "Cannot create file '" + tmppath + "'.");
|
if (!ftmp) {
|
||||||
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Save PCK"), vformat(TTR("Cannot create file \"%s\"."), tmppath));
|
||||||
|
return ERR_CANT_CREATE;
|
||||||
|
}
|
||||||
|
|
||||||
PackData pd;
|
PackData pd;
|
||||||
pd.ep = &ep;
|
pd.ep = &ep;
|
||||||
|
@ -974,7 +1054,7 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, c
|
||||||
|
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
DirAccess::remove_file_or_error(tmppath);
|
DirAccess::remove_file_or_error(tmppath);
|
||||||
ERR_PRINT("Failed to export project files");
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Save PCK"), TTR("Failed to export project files."));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1066,7 +1146,8 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, c
|
||||||
if (!ftmp) {
|
if (!ftmp) {
|
||||||
memdelete(f);
|
memdelete(f);
|
||||||
DirAccess::remove_file_or_error(tmppath);
|
DirAccess::remove_file_or_error(tmppath);
|
||||||
ERR_FAIL_V_MSG(ERR_CANT_CREATE, "Can't open file to read from path '" + String(tmppath) + "'.");
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Save PCK"), vformat(TTR("Can't open file to read from path \"%s\"."), tmppath));
|
||||||
|
return ERR_CANT_CREATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int bufsize = 16384;
|
const int bufsize = 16384;
|
||||||
|
@ -1117,8 +1198,9 @@ Error EditorExportPlatform::save_zip(const Ref<EditorExportPreset> &p_preset, co
|
||||||
zd.zip = zip;
|
zd.zip = zip;
|
||||||
|
|
||||||
Error err = export_project_files(p_preset, _save_zip_file, &zd);
|
Error err = export_project_files(p_preset, _save_zip_file, &zd);
|
||||||
if (err != OK && err != ERR_SKIP)
|
if (err != OK && err != ERR_SKIP) {
|
||||||
ERR_PRINT("Failed to export project files");
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Save ZIP"), TTR("Failed to export project files."));
|
||||||
|
}
|
||||||
|
|
||||||
zipClose(zip, nullptr);
|
zipClose(zip, nullptr);
|
||||||
|
|
||||||
|
@ -1184,6 +1266,7 @@ void EditorExportPlatform::gen_export_flags(Vector<String> &r_flags, int p_flags
|
||||||
r_flags.push_back("--debug-navigation");
|
r_flags.push_back("--debug-navigation");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorExportPlatform::EditorExportPlatform() {
|
EditorExportPlatform::EditorExportPlatform() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1638,6 +1721,7 @@ Error EditorExportPlatformPC::export_project(const Ref<EditorExportPreset> &p_pr
|
||||||
|
|
||||||
Error EditorExportPlatformPC::prepare_template(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
|
Error EditorExportPlatformPC::prepare_template(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
|
||||||
if (!DirAccess::exists(p_path.get_base_dir())) {
|
if (!DirAccess::exists(p_path.get_base_dir())) {
|
||||||
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Template"), TTR("The given export path doesn't exist."));
|
||||||
return ERR_FILE_BAD_PATH;
|
return ERR_FILE_BAD_PATH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1665,13 +1749,16 @@ Error EditorExportPlatformPC::prepare_template(const Ref<EditorExportPreset> &p_
|
||||||
}
|
}
|
||||||
|
|
||||||
if (template_path != String() && !FileAccess::exists(template_path)) {
|
if (template_path != String() && !FileAccess::exists(template_path)) {
|
||||||
EditorNode::get_singleton()->show_warning(TTR("Template file not found:") + "\n" + template_path);
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Template"), vformat(TTR("Template file not found: \"%s\"."), template_path));
|
||||||
return ERR_FILE_NOT_FOUND;
|
return ERR_FILE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||||
da->make_dir_recursive(p_path.get_base_dir());
|
da->make_dir_recursive(p_path.get_base_dir());
|
||||||
Error err = da->copy(template_path, p_path, get_chmod_flags());
|
Error err = da->copy(template_path, p_path, get_chmod_flags());
|
||||||
|
if (err != OK) {
|
||||||
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Template"), TTR("Failed to copy export template."));
|
||||||
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -1691,14 +1778,11 @@ Error EditorExportPlatformPC::export_project_data(const Ref<EditorExportPreset>
|
||||||
Error err = save_pack(p_preset, pck_path, &so_files, p_preset->get("binary_format/embed_pck"), &embedded_pos, &embedded_size);
|
Error err = save_pack(p_preset, pck_path, &so_files, p_preset->get("binary_format/embed_pck"), &embedded_pos, &embedded_size);
|
||||||
if (err == OK && p_preset->get("binary_format/embed_pck")) {
|
if (err == OK && p_preset->get("binary_format/embed_pck")) {
|
||||||
if (embedded_size >= 0x100000000 && !p_preset->get("binary_format/64_bits")) {
|
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."));
|
add_message(EXPORT_MESSAGE_ERROR, TTR("PCK Embedding"), TTR("On 32-bit exports the embedded PCK cannot be bigger than 4 GiB."));
|
||||||
return ERR_INVALID_PARAMETER;
|
return ERR_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
FixUpEmbeddedPckFunc fixup_func = get_fixup_embedded_pck_func();
|
err = fixup_embedded_pck(p_path, embedded_pos, embedded_size);
|
||||||
if (fixup_func) {
|
|
||||||
err = fixup_func(p_path, embedded_pos, embedded_size);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err == OK && !so_files.empty()) {
|
if (err == OK && !so_files.empty()) {
|
||||||
|
@ -1778,17 +1862,8 @@ void EditorExportPlatformPC::set_chmod_flags(int p_flags) {
|
||||||
chmod_flags = p_flags;
|
chmod_flags = p_flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorExportPlatformPC::FixUpEmbeddedPckFunc EditorExportPlatformPC::get_fixup_embedded_pck_func() const {
|
|
||||||
return fixup_embedded_pck_func;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EditorExportPlatformPC::set_fixup_embedded_pck_func(FixUpEmbeddedPckFunc p_fixup_embedded_pck_func) {
|
|
||||||
fixup_embedded_pck_func = p_fixup_embedded_pck_func;
|
|
||||||
}
|
|
||||||
|
|
||||||
EditorExportPlatformPC::EditorExportPlatformPC() {
|
EditorExportPlatformPC::EditorExportPlatformPC() {
|
||||||
chmod_flags = -1;
|
chmod_flags = -1;
|
||||||
fixup_embedded_pck_func = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////
|
///////////////////////
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
|
|
||||||
#include "core/os/dir_access.h"
|
#include "core/os/dir_access.h"
|
||||||
#include "core/resource.h"
|
#include "core/resource.h"
|
||||||
|
#include "scene/gui/rich_text_label.h"
|
||||||
#include "scene/main/node.h"
|
#include "scene/main/node.h"
|
||||||
#include "scene/main/timer.h"
|
#include "scene/main/timer.h"
|
||||||
#include "scene/resources/texture.h"
|
#include "scene/resources/texture.h"
|
||||||
|
@ -151,6 +152,19 @@ public:
|
||||||
typedef Error (*EditorExportSaveFunction)(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total);
|
typedef Error (*EditorExportSaveFunction)(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total);
|
||||||
typedef Error (*EditorExportSaveSharedObject)(void *p_userdata, const SharedObject &p_so);
|
typedef Error (*EditorExportSaveSharedObject)(void *p_userdata, const SharedObject &p_so);
|
||||||
|
|
||||||
|
enum ExportMessageType {
|
||||||
|
EXPORT_MESSAGE_NONE,
|
||||||
|
EXPORT_MESSAGE_INFO,
|
||||||
|
EXPORT_MESSAGE_WARNING,
|
||||||
|
EXPORT_MESSAGE_ERROR,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ExportMessage {
|
||||||
|
ExportMessageType msg_type;
|
||||||
|
String category;
|
||||||
|
String text;
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct SavedData {
|
struct SavedData {
|
||||||
uint64_t ofs;
|
uint64_t ofs;
|
||||||
|
@ -180,6 +194,8 @@ private:
|
||||||
PoolVector<String> features_pv;
|
PoolVector<String> features_pv;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Vector<ExportMessage> messages;
|
||||||
|
|
||||||
void _export_find_resources(EditorFileSystemDirectory *p_dir, Set<String> &p_paths);
|
void _export_find_resources(EditorFileSystemDirectory *p_dir, Set<String> &p_paths);
|
||||||
void _export_find_dependencies(const String &p_path, Set<String> &p_paths);
|
void _export_find_dependencies(const String &p_path, Set<String> &p_paths);
|
||||||
|
|
||||||
|
@ -220,6 +236,47 @@ public:
|
||||||
|
|
||||||
virtual Ref<EditorExportPreset> create_preset();
|
virtual Ref<EditorExportPreset> create_preset();
|
||||||
|
|
||||||
|
virtual void clear_messages() { messages.clear(); }
|
||||||
|
virtual void add_message(ExportMessageType p_type, const String &p_category, const String &p_message) {
|
||||||
|
ExportMessage msg;
|
||||||
|
msg.category = p_category;
|
||||||
|
msg.text = p_message;
|
||||||
|
msg.msg_type = p_type;
|
||||||
|
messages.push_back(msg);
|
||||||
|
switch (p_type) {
|
||||||
|
case EXPORT_MESSAGE_INFO: {
|
||||||
|
print_line(vformat("%s: %s\n", msg.category, msg.text));
|
||||||
|
} break;
|
||||||
|
case EXPORT_MESSAGE_WARNING: {
|
||||||
|
WARN_PRINT(vformat("%s: %s\n", msg.category, msg.text));
|
||||||
|
} break;
|
||||||
|
case EXPORT_MESSAGE_ERROR: {
|
||||||
|
ERR_PRINT(vformat("%s: %s\n", msg.category, msg.text));
|
||||||
|
} break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int get_message_count() const {
|
||||||
|
return messages.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ExportMessage get_message(int p_index) const {
|
||||||
|
ERR_FAIL_INDEX_V(p_index, messages.size(), ExportMessage());
|
||||||
|
return messages[p_index];
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ExportMessageType get_worst_message_type() const {
|
||||||
|
ExportMessageType worst_type = EXPORT_MESSAGE_NONE;
|
||||||
|
for (int i = 0; i < messages.size(); i++) {
|
||||||
|
worst_type = MAX(worst_type, messages[i].msg_type);
|
||||||
|
}
|
||||||
|
return worst_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool fill_log_messages(RichTextLabel *p_log, Error p_err);
|
||||||
|
|
||||||
virtual void get_export_options(List<ExportOption> *r_options) = 0;
|
virtual void get_export_options(List<ExportOption> *r_options) = 0;
|
||||||
virtual bool should_update_export_options() { return false; }
|
virtual bool should_update_export_options() { return false; }
|
||||||
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const { return true; }
|
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const { return true; }
|
||||||
|
@ -400,9 +457,6 @@ public:
|
||||||
class EditorExportPlatformPC : public EditorExportPlatform {
|
class EditorExportPlatformPC : public EditorExportPlatform {
|
||||||
GDCLASS(EditorExportPlatformPC, EditorExportPlatform);
|
GDCLASS(EditorExportPlatformPC, EditorExportPlatform);
|
||||||
|
|
||||||
public:
|
|
||||||
typedef Error (*FixUpEmbeddedPckFunc)(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ref<ImageTexture> logo;
|
Ref<ImageTexture> logo;
|
||||||
String name;
|
String name;
|
||||||
|
@ -418,8 +472,6 @@ private:
|
||||||
|
|
||||||
int chmod_flags;
|
int chmod_flags;
|
||||||
|
|
||||||
FixUpEmbeddedPckFunc fixup_embedded_pck_func;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features);
|
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features);
|
||||||
|
|
||||||
|
@ -437,6 +489,7 @@ public:
|
||||||
virtual Error prepare_template(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags);
|
virtual Error prepare_template(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags);
|
||||||
virtual Error modify_template(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { return OK; }
|
virtual Error modify_template(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { return OK; }
|
||||||
virtual Error export_project_data(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags);
|
virtual Error export_project_data(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags);
|
||||||
|
virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) { return OK; }
|
||||||
|
|
||||||
void set_extension(const String &p_extension, const String &p_feature_key = "default");
|
void set_extension(const String &p_extension, const String &p_feature_key = "default");
|
||||||
void set_name(const String &p_name);
|
void set_name(const String &p_name);
|
||||||
|
@ -456,9 +509,6 @@ public:
|
||||||
int get_chmod_flags() const;
|
int get_chmod_flags() const;
|
||||||
void set_chmod_flags(int p_flags);
|
void set_chmod_flags(int p_flags);
|
||||||
|
|
||||||
FixUpEmbeddedPckFunc get_fixup_embedded_pck_func() const;
|
|
||||||
void set_fixup_embedded_pck_func(FixUpEmbeddedPckFunc p_fixup_embedded_pck_func);
|
|
||||||
|
|
||||||
EditorExportPlatformPC();
|
EditorExportPlatformPC();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -798,21 +798,14 @@ void EditorNode::_fs_changed() {
|
||||||
ERR_PRINT(vformat("Cannot export project with preset \"%s\" due to configuration errors:\n%s", preset_name, config_error));
|
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;
|
err = missing_templates ? ERR_FILE_NOT_FOUND : ERR_UNCONFIGURED;
|
||||||
} else {
|
} else {
|
||||||
|
platform->clear_messages();
|
||||||
err = platform->export_project(preset, export_defer.debug, export_path);
|
err = platform->export_project(preset, export_defer.debug, export_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch (err) {
|
if (err != OK) {
|
||||||
case OK:
|
export_error = vformat("Project export for preset \"%s\" failed.", preset_name);
|
||||||
break;
|
} else if (platform->get_worst_message_type() >= EditorExportPlatform::EXPORT_MESSAGE_WARNING) {
|
||||||
case ERR_FILE_NOT_FOUND:
|
export_error = vformat("Project export for preset \"%s\" completed with errors.", preset_name);
|
||||||
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_path);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
export_error = vformat("Project export failed with error code %d for preset \"%s\".", (int)err, preset_name);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,7 +146,12 @@ void EditorRunNative::_run_native(int p_idx, int p_platform) {
|
||||||
flags |= EditorExportPlatform::DEBUG_FLAG_SHADER_FALLBACKS;
|
flags |= EditorExportPlatform::DEBUG_FLAG_SHADER_FALLBACKS;
|
||||||
}
|
}
|
||||||
|
|
||||||
eep->run(preset, p_idx, flags);
|
eep->clear_messages();
|
||||||
|
Error err = eep->run(preset, p_idx, flags);
|
||||||
|
result_dialog_log->clear();
|
||||||
|
if (eep->fill_log_messages(result_dialog_log, err)) {
|
||||||
|
result_dialog->popup_centered_ratio(0.5);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorRunNative::resume_run_native() {
|
void EditorRunNative::resume_run_native() {
|
||||||
|
@ -200,6 +205,15 @@ bool EditorRunNative::get_debug_shader_fallbacks() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorRunNative::EditorRunNative() {
|
EditorRunNative::EditorRunNative() {
|
||||||
|
result_dialog = memnew(AcceptDialog);
|
||||||
|
result_dialog->set_title(TTR("Project Run"));
|
||||||
|
result_dialog_log = memnew(RichTextLabel);
|
||||||
|
result_dialog_log->set_custom_minimum_size(Size2(300, 80) * EDSCALE);
|
||||||
|
result_dialog->add_child(result_dialog_log);
|
||||||
|
|
||||||
|
add_child(result_dialog);
|
||||||
|
result_dialog->hide();
|
||||||
|
|
||||||
set_process(true);
|
set_process(true);
|
||||||
first = true;
|
first = true;
|
||||||
deploy_dumb = false;
|
deploy_dumb = false;
|
||||||
|
|
|
@ -32,11 +32,16 @@
|
||||||
#define EDITOR_RUN_NATIVE_H
|
#define EDITOR_RUN_NATIVE_H
|
||||||
|
|
||||||
#include "scene/gui/box_container.h"
|
#include "scene/gui/box_container.h"
|
||||||
|
#include "scene/gui/dialogs.h"
|
||||||
#include "scene/gui/menu_button.h"
|
#include "scene/gui/menu_button.h"
|
||||||
|
#include "scene/gui/rich_text_label.h"
|
||||||
|
|
||||||
class EditorRunNative : public HBoxContainer {
|
class EditorRunNative : public HBoxContainer {
|
||||||
GDCLASS(EditorRunNative, HBoxContainer);
|
GDCLASS(EditorRunNative, HBoxContainer);
|
||||||
|
|
||||||
|
RichTextLabel *result_dialog_log;
|
||||||
|
AcceptDialog *result_dialog;
|
||||||
|
|
||||||
Map<int, MenuButton *> menus;
|
Map<int, MenuButton *> menus;
|
||||||
bool first;
|
bool first;
|
||||||
bool deploy_dumb;
|
bool deploy_dumb;
|
||||||
|
|
|
@ -883,17 +883,14 @@ void ProjectExportDialog::_export_project_to_path(const String &p_path) {
|
||||||
ERR_FAIL_COND(platform.is_null());
|
ERR_FAIL_COND(platform.is_null());
|
||||||
current->set_export_path(p_path);
|
current->set_export_path(p_path);
|
||||||
|
|
||||||
|
platform->clear_messages();
|
||||||
Error err = platform->export_project(current, export_debug->is_pressed(), p_path, 0);
|
Error err = platform->export_project(current, export_debug->is_pressed(), p_path, 0);
|
||||||
if (err != OK && err != ERR_SKIP) {
|
result_dialog_log->clear();
|
||||||
if (err == ERR_FILE_NOT_FOUND) {
|
|
||||||
error_dialog->set_text(vformat(TTR("Failed to export the project for platform '%s'.\nExport templates seem to be missing or invalid."), platform->get_name()));
|
|
||||||
} else { // Assume misconfiguration. FIXME: Improve error handling and preset config validation.
|
|
||||||
error_dialog->set_text(vformat(TTR("Failed to export the project for platform '%s'.\nThis might be due to a configuration issue in the export preset or your export settings."), platform->get_name()));
|
|
||||||
}
|
|
||||||
|
|
||||||
ERR_PRINT(vformat("Failed to export the project for platform '%s'.", platform->get_name()));
|
if (err != ERR_SKIP) {
|
||||||
error_dialog->show();
|
if (platform->fill_log_messages(result_dialog_log, err)) {
|
||||||
error_dialog->popup_centered_minsize(Size2(300, 80));
|
result_dialog->popup_centered_ratio(0.5);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -912,6 +909,8 @@ void ProjectExportDialog::_export_all(bool p_debug) {
|
||||||
String mode = p_debug ? TTR("Debug") : TTR("Release");
|
String mode = p_debug ? TTR("Debug") : TTR("Release");
|
||||||
EditorProgress ep("exportall", TTR("Exporting All") + " " + mode, EditorExport::get_singleton()->get_export_preset_count(), true);
|
EditorProgress ep("exportall", TTR("Exporting All") + " " + mode, EditorExport::get_singleton()->get_export_preset_count(), true);
|
||||||
|
|
||||||
|
bool show_dialog = false;
|
||||||
|
result_dialog_log->clear();
|
||||||
for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) {
|
for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) {
|
||||||
Ref<EditorExportPreset> preset = EditorExport::get_singleton()->get_export_preset(i);
|
Ref<EditorExportPreset> preset = EditorExport::get_singleton()->get_export_preset(i);
|
||||||
ERR_FAIL_COND(preset.is_null());
|
ERR_FAIL_COND(preset.is_null());
|
||||||
|
@ -920,17 +919,16 @@ void ProjectExportDialog::_export_all(bool p_debug) {
|
||||||
|
|
||||||
ep.step(preset->get_name(), i);
|
ep.step(preset->get_name(), i);
|
||||||
|
|
||||||
|
platform->clear_messages();
|
||||||
Error err = platform->export_project(preset, p_debug, preset->get_export_path(), 0);
|
Error err = platform->export_project(preset, p_debug, preset->get_export_path(), 0);
|
||||||
if (err != OK && err != ERR_SKIP) {
|
if (err == ERR_SKIP) {
|
||||||
if (err == ERR_FILE_BAD_PATH) {
|
return;
|
||||||
error_dialog->set_text(TTR("The given export path doesn't exist:") + "\n" + preset->get_export_path().get_base_dir());
|
|
||||||
} else {
|
|
||||||
error_dialog->set_text(TTR("Export templates for this platform are missing/corrupted:") + " " + platform->get_name());
|
|
||||||
}
|
|
||||||
error_dialog->show();
|
|
||||||
error_dialog->popup_centered_minsize(Size2(300, 80));
|
|
||||||
ERR_PRINT("Failed to export project");
|
|
||||||
}
|
}
|
||||||
|
bool has_messages = platform->fill_log_messages(result_dialog_log, err);
|
||||||
|
show_dialog = show_dialog || has_messages;
|
||||||
|
}
|
||||||
|
if (show_dialog) {
|
||||||
|
result_dialog->popup_centered_ratio(0.5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1200,11 +1198,14 @@ ProjectExportDialog::ProjectExportDialog() {
|
||||||
export_error2->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor"));
|
export_error2->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor"));
|
||||||
export_error2->set_text(" - " + TTR("Export templates for this platform are missing:") + " ");
|
export_error2->set_text(" - " + TTR("Export templates for this platform are missing:") + " ");
|
||||||
|
|
||||||
error_dialog = memnew(AcceptDialog);
|
result_dialog = memnew(AcceptDialog);
|
||||||
error_dialog->set_title("Error");
|
result_dialog->set_title(TTR("Project Export"));
|
||||||
error_dialog->set_text(TTR("Export templates for this platform are missing/corrupted:") + " ");
|
result_dialog_log = memnew(RichTextLabel);
|
||||||
main_vb->add_child(error_dialog);
|
result_dialog_log->set_custom_minimum_size(Size2(300, 80) * EDSCALE);
|
||||||
error_dialog->hide();
|
result_dialog->add_child(result_dialog_log);
|
||||||
|
|
||||||
|
main_vb->add_child(result_dialog);
|
||||||
|
result_dialog->hide();
|
||||||
|
|
||||||
LinkButton *download_templates = memnew(LinkButton);
|
LinkButton *download_templates = memnew(LinkButton);
|
||||||
download_templates->set_text(TTR("Manage Export Templates"));
|
download_templates->set_text(TTR("Manage Export Templates"));
|
||||||
|
|
|
@ -74,7 +74,8 @@ private:
|
||||||
Button *button_export;
|
Button *button_export;
|
||||||
bool updating;
|
bool updating;
|
||||||
|
|
||||||
AcceptDialog *error_dialog;
|
RichTextLabel *result_dialog_log;
|
||||||
|
AcceptDialog *result_dialog;
|
||||||
ConfirmationDialog *delete_confirm;
|
ConfirmationDialog *delete_confirm;
|
||||||
|
|
||||||
OptionButton *export_filter;
|
OptionButton *export_filter;
|
||||||
|
|
|
@ -1828,7 +1828,7 @@ Error EditorExportPlatformAndroid::run(const Ref<EditorExportPreset> &p_preset,
|
||||||
String can_export_error;
|
String can_export_error;
|
||||||
bool can_export_missing_templates;
|
bool can_export_missing_templates;
|
||||||
if (!can_export(p_preset, can_export_error, can_export_missing_templates)) {
|
if (!can_export(p_preset, can_export_error, can_export_missing_templates)) {
|
||||||
EditorNode::add_io_error(can_export_error);
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Run"), can_export_error);
|
||||||
return ERR_UNCONFIGURED;
|
return ERR_UNCONFIGURED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1909,7 +1909,7 @@ Error EditorExportPlatformAndroid::run(const Ref<EditorExportPreset> &p_preset,
|
||||||
err = OS::get_singleton()->execute(adb, args, true, nullptr, &output, &rv, true);
|
err = OS::get_singleton()->execute(adb, args, true, nullptr, &output, &rv, true);
|
||||||
print_verbose(output);
|
print_verbose(output);
|
||||||
if (err || rv != 0) {
|
if (err || rv != 0) {
|
||||||
EditorNode::add_io_error(vformat(TTR("Could not install to device: %s"), output));
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Run"), vformat(TTR("Could not install to device: %s"), output));
|
||||||
CLEANUP_AND_RETURN(ERR_CANT_CREATE);
|
CLEANUP_AND_RETURN(ERR_CANT_CREATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1987,7 +1987,7 @@ Error EditorExportPlatformAndroid::run(const Ref<EditorExportPreset> &p_preset,
|
||||||
err = OS::get_singleton()->execute(adb, args, true, nullptr, &output, &rv, true);
|
err = OS::get_singleton()->execute(adb, args, true, nullptr, &output, &rv, true);
|
||||||
print_verbose(output);
|
print_verbose(output);
|
||||||
if (err || rv != 0) {
|
if (err || rv != 0) {
|
||||||
EditorNode::add_io_error(TTR("Could not execute on device."));
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Run"), TTR("Could not execute on device."));
|
||||||
CLEANUP_AND_RETURN(ERR_CANT_CREATE);
|
CLEANUP_AND_RETURN(ERR_CANT_CREATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2042,7 +2042,7 @@ String EditorExportPlatformAndroid::get_apksigner_path() {
|
||||||
da->list_dir_end();
|
da->list_dir_end();
|
||||||
|
|
||||||
if (apksigner_path.empty()) {
|
if (apksigner_path.empty()) {
|
||||||
EditorNode::get_singleton()->show_warning(TTR("Unable to find the 'apksigner' tool."));
|
print_error("Unable to find the 'apksigner' tool.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return apksigner_path;
|
return apksigner_path;
|
||||||
|
@ -2643,7 +2643,7 @@ Error EditorExportPlatformAndroid::sign_apk(const Ref<EditorExportPreset> &p_pre
|
||||||
String apksigner = get_apksigner_path();
|
String apksigner = get_apksigner_path();
|
||||||
print_verbose("Starting signing of the " + export_label + " binary using " + apksigner);
|
print_verbose("Starting signing of the " + export_label + " binary using " + apksigner);
|
||||||
if (!FileAccess::exists(apksigner)) {
|
if (!FileAccess::exists(apksigner)) {
|
||||||
EditorNode::add_io_error(vformat(TTR("'apksigner' could not be found.\nPlease check the command is available in the Android SDK build-tools directory.\nThe resulting %s is unsigned."), export_label));
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("'apksigner' could not be found. Please check that the command is available in the Android SDK build-tools directory. The resulting %s is unsigned."), export_label));
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2676,7 +2676,7 @@ Error EditorExportPlatformAndroid::sign_apk(const Ref<EditorExportPreset> &p_pre
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!FileAccess::exists(keystore)) {
|
if (!FileAccess::exists(keystore)) {
|
||||||
EditorNode::add_io_error(TTR("Could not find keystore, unable to export."));
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not find keystore, unable to export."));
|
||||||
return ERR_FILE_CANT_OPEN;
|
return ERR_FILE_CANT_OPEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2697,10 +2697,14 @@ Error EditorExportPlatformAndroid::sign_apk(const Ref<EditorExportPreset> &p_pre
|
||||||
}
|
}
|
||||||
int retval;
|
int retval;
|
||||||
output.clear();
|
output.clear();
|
||||||
OS::get_singleton()->execute(apksigner, args, true, nullptr, &output, &retval, true);
|
Error err = OS::get_singleton()->execute(apksigner, args, true, nullptr, &output, &retval, true);
|
||||||
|
if (err != OK) {
|
||||||
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start apksigner executable."));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
print_verbose(output);
|
print_verbose(output);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
EditorNode::add_io_error(vformat(TTR("'apksigner' returned with error #%d"), retval));
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("'apksigner' returned with error #%d"), retval));
|
||||||
return ERR_CANT_CREATE;
|
return ERR_CANT_CREATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2717,10 +2721,14 @@ Error EditorExportPlatformAndroid::sign_apk(const Ref<EditorExportPreset> &p_pre
|
||||||
}
|
}
|
||||||
|
|
||||||
output.clear();
|
output.clear();
|
||||||
OS::get_singleton()->execute(apksigner, args, true, nullptr, &output, &retval, true);
|
err = OS::get_singleton()->execute(apksigner, args, true, nullptr, &output, &retval, true);
|
||||||
|
if (err != OK) {
|
||||||
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start apksigner executable."));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
print_verbose(output);
|
print_verbose(output);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
EditorNode::add_io_error(vformat(TTR("'apksigner' verification of %s failed."), export_label));
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("'apksigner' verification of %s failed."), export_label));
|
||||||
return ERR_CANT_CREATE;
|
return ERR_CANT_CREATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2830,22 +2838,21 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
|
||||||
|
|
||||||
if (export_format == EXPORT_FORMAT_AAB) {
|
if (export_format == EXPORT_FORMAT_AAB) {
|
||||||
if (!p_path.ends_with(".aab")) {
|
if (!p_path.ends_with(".aab")) {
|
||||||
EditorNode::get_singleton()->show_warning(TTR("Invalid filename! Android App Bundle requires the *.aab extension."));
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Invalid filename! Android App Bundle requires the *.aab extension."));
|
||||||
return ERR_UNCONFIGURED;
|
return ERR_UNCONFIGURED;
|
||||||
}
|
}
|
||||||
if (apk_expansion) {
|
if (apk_expansion) {
|
||||||
EditorNode::get_singleton()->show_warning(TTR("APK Expansion not compatible with Android App Bundle."));
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("APK Expansion not compatible with Android App Bundle."));
|
||||||
return ERR_UNCONFIGURED;
|
return ERR_UNCONFIGURED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (export_format == EXPORT_FORMAT_APK && !p_path.ends_with(".apk")) {
|
if (export_format == EXPORT_FORMAT_APK && !p_path.ends_with(".apk")) {
|
||||||
EditorNode::get_singleton()->show_warning(
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Invalid filename! Android APK requires the *.apk extension."));
|
||||||
TTR("Invalid filename! Android APK requires the *.apk extension."));
|
|
||||||
return ERR_UNCONFIGURED;
|
return ERR_UNCONFIGURED;
|
||||||
}
|
}
|
||||||
if (export_format > EXPORT_FORMAT_AAB || export_format < EXPORT_FORMAT_APK) {
|
if (export_format > EXPORT_FORMAT_AAB || export_format < EXPORT_FORMAT_APK) {
|
||||||
EditorNode::add_io_error(TTR("Unsupported export format!\n"));
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Unsupported export format!"));
|
||||||
return ERR_UNCONFIGURED; //TODO: is this the right error?
|
return ERR_UNCONFIGURED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (use_custom_build) {
|
if (use_custom_build) {
|
||||||
|
@ -2855,14 +2862,14 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
|
||||||
print_verbose("Checking build version..");
|
print_verbose("Checking build version..");
|
||||||
FileAccessRef f = FileAccess::open("res://android/.build_version", FileAccess::READ);
|
FileAccessRef f = FileAccess::open("res://android/.build_version", FileAccess::READ);
|
||||||
if (!f) {
|
if (!f) {
|
||||||
EditorNode::get_singleton()->show_warning(TTR("Trying to build from a custom built template, but no version info for it exists. Please reinstall from the 'Project' menu."));
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Trying to build from a custom built template, but no version info for it exists. Please reinstall from the 'Project' menu."));
|
||||||
return ERR_UNCONFIGURED;
|
return ERR_UNCONFIGURED;
|
||||||
}
|
}
|
||||||
String version = f->get_line().strip_edges();
|
String version = f->get_line().strip_edges();
|
||||||
print_verbose("- build version: " + version);
|
print_verbose("- build version: " + version);
|
||||||
f->close();
|
f->close();
|
||||||
if (version != VERSION_FULL_CONFIG) {
|
if (version != VERSION_FULL_CONFIG) {
|
||||||
EditorNode::get_singleton()->show_warning(vformat(TTR("Android build version mismatch:\n Template installed: %s\n Godot Version: %s\nPlease reinstall Android build template from 'Project' menu."), version, VERSION_FULL_CONFIG));
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Android build version mismatch: Template installed: %s, Godot version: %s. Please reinstall Android build template from 'Project' menu."), version, VERSION_FULL_CONFIG));
|
||||||
return ERR_UNCONFIGURED;
|
return ERR_UNCONFIGURED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2875,7 +2882,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
|
||||||
String project_name = get_project_name(p_preset->get("package/name"));
|
String project_name = get_project_name(p_preset->get("package/name"));
|
||||||
err = _create_project_name_strings_files(p_preset, project_name); //project name localization.
|
err = _create_project_name_strings_files(p_preset, project_name); //project name localization.
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
EditorNode::add_io_error(TTR("Unable to overwrite res://android/build/res/*.xml files with project name"));
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Unable to overwrite res://android/build/res/*.xml files with project name."));
|
||||||
}
|
}
|
||||||
// Copies the project icon files into the appropriate Gradle project directory.
|
// Copies the project icon files into the appropriate Gradle project directory.
|
||||||
_copy_icons_to_gradle_project(p_preset, processed_splash_config_xml, splash_image, splash_bg_color_image, main_image, foreground, background);
|
_copy_icons_to_gradle_project(p_preset, processed_splash_config_xml, splash_image, splash_bg_color_image, main_image, foreground, background);
|
||||||
|
@ -2892,7 +2899,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
|
||||||
user_data.debug = p_debug;
|
user_data.debug = p_debug;
|
||||||
err = export_project_files(p_preset, rename_and_store_file_in_gradle_project, &user_data, copy_gradle_so);
|
err = export_project_files(p_preset, rename_and_store_file_in_gradle_project, &user_data, copy_gradle_so);
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
EditorNode::add_io_error(TTR("Could not export project files to gradle project\n"));
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Could not export project files to gradle project."));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
if (user_data.libs.size() > 0) {
|
if (user_data.libs.size() > 0) {
|
||||||
|
@ -2904,7 +2911,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
|
||||||
print_verbose("Saving apk expansion file..");
|
print_verbose("Saving apk expansion file..");
|
||||||
err = save_apk_expansion_file(p_preset, p_path);
|
err = save_apk_expansion_file(p_preset, p_path);
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
EditorNode::add_io_error(TTR("Could not write expansion package file!"));
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Could not write expansion package file!"));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2989,7 +2996,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
|
||||||
debug_keystore = OS::get_singleton()->get_resource_dir().plus_file(debug_keystore).simplify_path();
|
debug_keystore = OS::get_singleton()->get_resource_dir().plus_file(debug_keystore).simplify_path();
|
||||||
}
|
}
|
||||||
if (!FileAccess::exists(debug_keystore)) {
|
if (!FileAccess::exists(debug_keystore)) {
|
||||||
EditorNode::add_io_error(TTR("Could not find keystore, unable to export."));
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("Could not find keystore, unable to export."));
|
||||||
return ERR_FILE_CANT_OPEN;
|
return ERR_FILE_CANT_OPEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3005,7 +3012,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
|
||||||
release_keystore = OS::get_singleton()->get_resource_dir().plus_file(release_keystore).simplify_path();
|
release_keystore = OS::get_singleton()->get_resource_dir().plus_file(release_keystore).simplify_path();
|
||||||
}
|
}
|
||||||
if (!FileAccess::exists(release_keystore)) {
|
if (!FileAccess::exists(release_keystore)) {
|
||||||
EditorNode::add_io_error(TTR("Could not find keystore, unable to export."));
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("Could not find keystore, unable to export."));
|
||||||
return ERR_FILE_CANT_OPEN;
|
return ERR_FILE_CANT_OPEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3017,7 +3024,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
|
||||||
|
|
||||||
int result = EditorNode::get_singleton()->execute_and_show_output(TTR("Building Android Project (gradle)"), build_command, cmdline);
|
int result = EditorNode::get_singleton()->execute_and_show_output(TTR("Building Android Project (gradle)"), build_command, cmdline);
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
EditorNode::get_singleton()->show_warning(TTR("Building of Android project failed, check output for the error.\nAlternatively visit docs.godotengine.org for Android build documentation."));
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Building of Android project failed, check output for the error. Alternatively visit docs.godotengine.org for Android build documentation."));
|
||||||
return ERR_CANT_CREATE;
|
return ERR_CANT_CREATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3047,7 +3054,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
|
||||||
print_verbose("Copying Android binary using gradle command: " + String("\n") + build_command + " " + join_list(copy_args, String(" ")));
|
print_verbose("Copying Android binary using gradle command: " + String("\n") + build_command + " " + join_list(copy_args, String(" ")));
|
||||||
int copy_result = EditorNode::get_singleton()->execute_and_show_output(TTR("Moving output"), build_command, copy_args);
|
int copy_result = EditorNode::get_singleton()->execute_and_show_output(TTR("Moving output"), build_command, copy_args);
|
||||||
if (copy_result != 0) {
|
if (copy_result != 0) {
|
||||||
EditorNode::get_singleton()->show_warning(TTR("Unable to copy and rename export file, check gradle project directory for outputs."));
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Unable to copy and rename export file, check gradle project directory for outputs."));
|
||||||
return ERR_CANT_CREATE;
|
return ERR_CANT_CREATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3070,7 +3077,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
|
||||||
src_apk = find_export_template("android_release.apk");
|
src_apk = find_export_template("android_release.apk");
|
||||||
}
|
}
|
||||||
if (src_apk == "") {
|
if (src_apk == "") {
|
||||||
EditorNode::add_io_error(vformat(TTR("Package not found: %s"), src_apk));
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Package not found: \"%s\"."), src_apk));
|
||||||
return ERR_FILE_NOT_FOUND;
|
return ERR_FILE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3088,7 +3095,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
|
||||||
|
|
||||||
unzFile pkg = unzOpen2(src_apk.utf8().get_data(), &io);
|
unzFile pkg = unzOpen2(src_apk.utf8().get_data(), &io);
|
||||||
if (!pkg) {
|
if (!pkg) {
|
||||||
EditorNode::add_io_error(vformat(TTR("Could not find template APK to export:\n%s"), src_apk));
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not find template APK to export: \"%s\"."), src_apk));
|
||||||
return ERR_FILE_NOT_FOUND;
|
return ERR_FILE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3217,7 +3224,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
|
||||||
|
|
||||||
if (!invalid_abis.empty()) {
|
if (!invalid_abis.empty()) {
|
||||||
String unsupported_arch = String(", ").join(invalid_abis);
|
String unsupported_arch = String(", ").join(invalid_abis);
|
||||||
EditorNode::add_io_error(vformat(TTR("Missing libraries in the export template for the selected architectures: %s.\nPlease build a template with all required libraries, or uncheck the missing architectures in the export preset."), unsupported_arch));
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Missing libraries in the export template for the selected architectures: %s. Please build a template with all required libraries, or uncheck the missing architectures in the export preset."), unsupported_arch));
|
||||||
CLEANUP_AND_RETURN(ERR_FILE_NOT_FOUND);
|
CLEANUP_AND_RETURN(ERR_FILE_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3235,7 +3242,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
|
||||||
if (apk_expansion) {
|
if (apk_expansion) {
|
||||||
err = save_apk_expansion_file(p_preset, p_path);
|
err = save_apk_expansion_file(p_preset, p_path);
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
EditorNode::add_io_error(TTR("Could not write expansion package file!"));
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Could not write expansion package file!"));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -3248,7 +3255,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
|
||||||
|
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
unzClose(pkg);
|
unzClose(pkg);
|
||||||
EditorNode::add_io_error(TTR("Could not export project files"));
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not export project files.")));
|
||||||
CLEANUP_AND_RETURN(ERR_SKIP);
|
CLEANUP_AND_RETURN(ERR_SKIP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3285,7 +3292,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
|
||||||
|
|
||||||
unzFile tmp_unaligned = unzOpen2(tmp_unaligned_path.utf8().get_data(), &io);
|
unzFile tmp_unaligned = unzOpen2(tmp_unaligned_path.utf8().get_data(), &io);
|
||||||
if (!tmp_unaligned) {
|
if (!tmp_unaligned) {
|
||||||
EditorNode::add_io_error(TTR("Could not unzip temporary unaligned APK."));
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not unzip temporary unaligned APK.")));
|
||||||
CLEANUP_AND_RETURN(ERR_FILE_NOT_FOUND);
|
CLEANUP_AND_RETURN(ERR_FILE_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1098,7 +1098,12 @@ Error EditorExportPlatformIOS::_codesign(String p_file, void *p_userdata) {
|
||||||
codesign_args.push_back("-s");
|
codesign_args.push_back("-s");
|
||||||
codesign_args.push_back(sign_id);
|
codesign_args.push_back(sign_id);
|
||||||
codesign_args.push_back(p_file);
|
codesign_args.push_back(p_file);
|
||||||
return OS::get_singleton()->execute("codesign", codesign_args, true);
|
|
||||||
|
String str;
|
||||||
|
Error err = OS::get_singleton()->execute("codesign", codesign_args, true, NULL, &str, NULL, true);
|
||||||
|
print_verbose("codesign (" + p_file + "):\n" + str);
|
||||||
|
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
@ -1686,7 +1691,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
|
||||||
String err;
|
String err;
|
||||||
src_pkg_name = find_export_template("iphone.zip", &err);
|
src_pkg_name = find_export_template("iphone.zip", &err);
|
||||||
if (src_pkg_name == "") {
|
if (src_pkg_name == "") {
|
||||||
EditorNode::add_io_error(err);
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Templates"), TTR("Export template not found."));
|
||||||
return ERR_FILE_NOT_FOUND;
|
return ERR_FILE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1783,7 +1788,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
|
||||||
zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
|
zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
|
||||||
unzFile src_pkg_zip = unzOpen2(src_pkg_name.utf8().get_data(), &io);
|
unzFile src_pkg_zip = unzOpen2(src_pkg_name.utf8().get_data(), &io);
|
||||||
if (!src_pkg_zip) {
|
if (!src_pkg_zip) {
|
||||||
EditorNode::add_io_error("Could not open export template (not a zip file?):\n" + src_pkg_name);
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Templates"), TTR("Could not open export template (not a zip file?): \"%s\".", src_pkg_name));
|
||||||
return ERR_CANT_OPEN;
|
return ERR_CANT_OPEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -361,12 +361,12 @@ Error EditorExportPlatformJavaScript::_extract_template(const String &p_template
|
||||||
unzFile pkg = unzOpen2(p_template.utf8().get_data(), &io);
|
unzFile pkg = unzOpen2(p_template.utf8().get_data(), &io);
|
||||||
|
|
||||||
if (!pkg) {
|
if (!pkg) {
|
||||||
EditorNode::get_singleton()->show_warning(TTR("Could not open template for export:") + "\n" + p_template);
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Templates"), vformat(TTR("Could not open template for export: \"%s\"."), p_template));
|
||||||
return ERR_FILE_NOT_FOUND;
|
return ERR_FILE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unzGoToFirstFile(pkg) != UNZ_OK) {
|
if (unzGoToFirstFile(pkg) != UNZ_OK) {
|
||||||
EditorNode::get_singleton()->show_warning(TTR("Invalid export template:") + "\n" + p_template);
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Templates"), vformat(TTR("Invalid export template: \"%s\"."), p_template));
|
||||||
unzClose(pkg);
|
unzClose(pkg);
|
||||||
return ERR_FILE_CORRUPT;
|
return ERR_FILE_CORRUPT;
|
||||||
}
|
}
|
||||||
|
@ -379,6 +379,11 @@ Error EditorExportPlatformJavaScript::_extract_template(const String &p_template
|
||||||
|
|
||||||
String file = String::utf8(fname);
|
String file = String::utf8(fname);
|
||||||
|
|
||||||
|
// Skip folders.
|
||||||
|
if (file.ends_with("/")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Skip service worker and offline page if not exporting pwa.
|
// Skip service worker and offline page if not exporting pwa.
|
||||||
if (!pwa && (file == "godot.service.worker.js" || file == "godot.offline.html")) {
|
if (!pwa && (file == "godot.service.worker.js" || file == "godot.offline.html")) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -395,7 +400,7 @@ Error EditorExportPlatformJavaScript::_extract_template(const String &p_template
|
||||||
String dst = p_dir.plus_file(file.replace("godot", p_name));
|
String dst = p_dir.plus_file(file.replace("godot", p_name));
|
||||||
FileAccess *f = FileAccess::open(dst, FileAccess::WRITE);
|
FileAccess *f = FileAccess::open(dst, FileAccess::WRITE);
|
||||||
if (!f) {
|
if (!f) {
|
||||||
EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + dst);
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Templates"), vformat(TTR("Could not write file: \"%s\"."), dst));
|
||||||
unzClose(pkg);
|
unzClose(pkg);
|
||||||
return ERR_FILE_CANT_WRITE;
|
return ERR_FILE_CANT_WRITE;
|
||||||
}
|
}
|
||||||
|
@ -410,7 +415,7 @@ Error EditorExportPlatformJavaScript::_extract_template(const String &p_template
|
||||||
Error EditorExportPlatformJavaScript::_write_or_error(const uint8_t *p_content, int p_size, String p_path) {
|
Error EditorExportPlatformJavaScript::_write_or_error(const uint8_t *p_content, int p_size, String p_path) {
|
||||||
FileAccess *f = FileAccess::open(p_path, FileAccess::WRITE);
|
FileAccess *f = FileAccess::open(p_path, FileAccess::WRITE);
|
||||||
if (!f) {
|
if (!f) {
|
||||||
EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + p_path);
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not write file: \"%s\"."), p_path));
|
||||||
return ERR_FILE_CANT_WRITE;
|
return ERR_FILE_CANT_WRITE;
|
||||||
}
|
}
|
||||||
f->store_buffer(p_content, p_size);
|
f->store_buffer(p_content, p_size);
|
||||||
|
@ -488,7 +493,7 @@ Error EditorExportPlatformJavaScript::_add_manifest_icon(const String &p_path, c
|
||||||
icon.instance();
|
icon.instance();
|
||||||
const Error err = ImageLoader::load_image(p_icon, icon);
|
const Error err = ImageLoader::load_image(p_icon, icon);
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
EditorNode::get_singleton()->show_warning(TTR("Could not read file:") + "\n" + p_icon);
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Icon Creation"), vformat(TTR("Could not read file: \"%s\"."), p_icon));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
if (icon->get_width() != p_size || icon->get_height() != p_size) {
|
if (icon->get_width() != p_size || icon->get_height() != p_size) {
|
||||||
|
@ -500,7 +505,7 @@ Error EditorExportPlatformJavaScript::_add_manifest_icon(const String &p_path, c
|
||||||
}
|
}
|
||||||
const Error err = icon->save_png(icon_dest);
|
const Error err = icon->save_png(icon_dest);
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + icon_dest);
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Icon Creation"), vformat(TTR("Could not write file: \"%s\"."), icon_dest));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
Dictionary icon_dict;
|
Dictionary icon_dict;
|
||||||
|
@ -558,7 +563,7 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> &
|
||||||
{
|
{
|
||||||
FileAccess *f = FileAccess::open(sw_path, FileAccess::READ);
|
FileAccess *f = FileAccess::open(sw_path, FileAccess::READ);
|
||||||
if (!f) {
|
if (!f) {
|
||||||
EditorNode::get_singleton()->show_warning(TTR("Could not read file:") + "\n" + sw_path);
|
add_message(EXPORT_MESSAGE_ERROR, TTR("PWA"), vformat(TTR("Could not read file: \"%s\"."), sw_path));
|
||||||
return ERR_FILE_CANT_READ;
|
return ERR_FILE_CANT_READ;
|
||||||
}
|
}
|
||||||
sw.resize(f->get_len());
|
sw.resize(f->get_len());
|
||||||
|
@ -579,7 +584,7 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> &
|
||||||
const String offline_dest = dir.plus_file(name + ".offline.html");
|
const String offline_dest = dir.plus_file(name + ".offline.html");
|
||||||
err = da->copy(ProjectSettings::get_singleton()->globalize_path(offline_page), offline_dest);
|
err = da->copy(ProjectSettings::get_singleton()->globalize_path(offline_page), offline_dest);
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
EditorNode::get_singleton()->show_warning(TTR("Could not read file:") + "\n" + offline_dest);
|
add_message(EXPORT_MESSAGE_ERROR, TTR("PWA"), vformat(TTR("Could not read file: \"%s\"."), offline_dest));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -758,7 +763,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
|
||||||
}
|
}
|
||||||
|
|
||||||
if (template_path != String() && !FileAccess::exists(template_path)) {
|
if (template_path != String() && !FileAccess::exists(template_path)) {
|
||||||
EditorNode::get_singleton()->show_warning(TTR("Template file not found:") + "\n" + template_path);
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Templates"), vformat(TTR("Template file not found: \"%s\"."), template_path));
|
||||||
return ERR_FILE_NOT_FOUND;
|
return ERR_FILE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -767,7 +772,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
|
||||||
String pck_path = base_path + ".pck";
|
String pck_path = base_path + ".pck";
|
||||||
Error error = save_pack(p_preset, pck_path, &shared_objects);
|
Error error = save_pack(p_preset, pck_path, &shared_objects);
|
||||||
if (error != OK) {
|
if (error != OK) {
|
||||||
EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + pck_path);
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not write file: \"%s\"."), pck_path));
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||||
|
@ -775,7 +780,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
|
||||||
String dst = base_dir.plus_file(shared_objects[i].path.get_file());
|
String dst = base_dir.plus_file(shared_objects[i].path.get_file());
|
||||||
error = da->copy(shared_objects[i].path, dst);
|
error = da->copy(shared_objects[i].path, dst);
|
||||||
if (error != OK) {
|
if (error != OK) {
|
||||||
EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + shared_objects[i].path.get_file());
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not write file: \"%s\"."), shared_objects[i].path.get_file()));
|
||||||
memdelete(da);
|
memdelete(da);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
@ -810,7 +815,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
|
||||||
Vector<uint8_t> html;
|
Vector<uint8_t> html;
|
||||||
f = FileAccess::open(html_path, FileAccess::READ);
|
f = FileAccess::open(html_path, FileAccess::READ);
|
||||||
if (!f) {
|
if (!f) {
|
||||||
EditorNode::get_singleton()->show_warning(TTR("Could not read HTML shell:") + "\n" + html_path);
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not read HTML shell: \"%s\"."), html_path));
|
||||||
return ERR_FILE_CANT_READ;
|
return ERR_FILE_CANT_READ;
|
||||||
}
|
}
|
||||||
html.resize(f->get_len());
|
html.resize(f->get_len());
|
||||||
|
@ -830,7 +835,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
|
||||||
Ref<Image> splash = _get_project_splash();
|
Ref<Image> splash = _get_project_splash();
|
||||||
const String splash_png_path = base_path + ".png";
|
const String splash_png_path = base_path + ".png";
|
||||||
if (splash->save_png(splash_png_path) != OK) {
|
if (splash->save_png(splash_png_path) != OK) {
|
||||||
EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + splash_png_path);
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not write file: \"%s\"."), splash_png_path));
|
||||||
return ERR_FILE_CANT_WRITE;
|
return ERR_FILE_CANT_WRITE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -840,13 +845,13 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
|
||||||
Ref<Image> favicon = _get_project_icon();
|
Ref<Image> favicon = _get_project_icon();
|
||||||
const String favicon_png_path = base_path + ".icon.png";
|
const String favicon_png_path = base_path + ".icon.png";
|
||||||
if (favicon->save_png(favicon_png_path) != OK) {
|
if (favicon->save_png(favicon_png_path) != OK) {
|
||||||
EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + favicon_png_path);
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not write file: \"%s\"."), favicon_png_path));
|
||||||
return ERR_FILE_CANT_WRITE;
|
return ERR_FILE_CANT_WRITE;
|
||||||
}
|
}
|
||||||
favicon->resize(180, 180);
|
favicon->resize(180, 180);
|
||||||
const String apple_icon_png_path = base_path + ".apple-touch-icon.png";
|
const String apple_icon_png_path = base_path + ".apple-touch-icon.png";
|
||||||
if (favicon->save_png(apple_icon_png_path) != OK) {
|
if (favicon->save_png(apple_icon_png_path) != OK) {
|
||||||
EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + apple_icon_png_path);
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not write file: \"%s\"."), apple_icon_png_path));
|
||||||
return ERR_FILE_CANT_WRITE;
|
return ERR_FILE_CANT_WRITE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -906,10 +911,11 @@ Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_prese
|
||||||
if (!da->dir_exists(dest)) {
|
if (!da->dir_exists(dest)) {
|
||||||
Error err = da->make_dir_recursive(dest);
|
Error err = da->make_dir_recursive(dest);
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
EditorNode::get_singleton()->show_warning(TTR("Could not create HTTP server directory:") + "\n" + dest);
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Run"), vformat(TTR("Could not create HTTP server directory: %s."), dest));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const String basepath = dest.plus_file("tmp_js_export");
|
const String basepath = dest.plus_file("tmp_js_export");
|
||||||
Error err = export_project(p_preset, true, basepath + ".html", p_debug_flags);
|
Error err = export_project(p_preset, true, basepath + ".html", p_debug_flags);
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
|
@ -952,7 +958,7 @@ Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_prese
|
||||||
err = server->listen(bind_port, bind_ip, use_ssl, ssl_key, ssl_cert);
|
err = server->listen(bind_port, bind_ip, use_ssl, ssl_key, ssl_cert);
|
||||||
}
|
}
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
EditorNode::get_singleton()->show_warning(TTR("Error starting HTTP server:") + "\n" + itos(err));
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Run"), vformat(TTR("Error starting HTTP server: %d."), err));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -346,7 +346,8 @@ void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_
|
||||||
if (!f) {
|
if (!f) {
|
||||||
// Clean up generated file.
|
// Clean up generated file.
|
||||||
DirAccess::remove_file_or_error(path);
|
DirAccess::remove_file_or_error(path);
|
||||||
ERR_FAIL();
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Icon Creation"), vformat(TTR("Could not open icon file \"%s\"."), path));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ofs = data.size();
|
int ofs = data.size();
|
||||||
|
@ -528,18 +529,25 @@ Error EditorExportPlatformOSX::_notarize(const Ref<EditorExportPreset> &p_preset
|
||||||
|
|
||||||
String str;
|
String str;
|
||||||
Error err = OS::get_singleton()->execute("xcrun", args, true, NULL, &str, NULL, true);
|
Error err = OS::get_singleton()->execute("xcrun", args, true, NULL, &str, NULL, true);
|
||||||
ERR_FAIL_COND_V(err != OK, err);
|
if (err != OK || (str.find("not found") != -1) || (str.find("not recognized") != -1)) {
|
||||||
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Notarization"), TTR("Could not start xcrun executable."));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
print_verbose("altool (" + p_path + "):\n" + str);
|
print_verbose("altool (" + p_path + "):\n" + str);
|
||||||
if (str.find("RequestUUID") == -1) {
|
int rq_offset = str.find("RequestUUID");
|
||||||
EditorNode::add_io_error("altool: " + str);
|
if (rq_offset == -1) {
|
||||||
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Notarization"), TTR("Notarization failed."));
|
||||||
return FAILED;
|
return FAILED;
|
||||||
} else {
|
} else {
|
||||||
print_line(TTR("Note: The notarization process generally takes less than an hour. When the process is completed, you'll receive an email."));
|
int next_nl = str.find("\n", rq_offset);
|
||||||
print_line(" " + TTR("You can check progress manually by opening a Terminal and running the following command:"));
|
String request_uuid = (next_nl == -1) ? str.substr(rq_offset + 14, -1) : str.substr(rq_offset + 14, next_nl - rq_offset - 14);
|
||||||
print_line(" \"xcrun altool --notarization-history 0 -u <your email> -p <app-specific pwd>\"");
|
add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), vformat(TTR("Notarization request UUID: \"%s\""), request_uuid));
|
||||||
print_line(" " + TTR("Run the following command to staple the notarization ticket to the exported application (optional):"));
|
add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), TTR("The notarization process generally takes less than an hour. When the process is completed, you'll receive an email."));
|
||||||
print_line(" \"xcrun stapler staple <app path>\"");
|
add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t" + TTR("You can check progress manually by opening a Terminal and running the following command:"));
|
||||||
|
add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t\t\"xcrun altool --notarization-history 0 -u <your email> -p <app-specific pwd>\"");
|
||||||
|
add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t" + TTR("Run the following command to staple the notarization ticket to the exported application (optional):"));
|
||||||
|
add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t\t\"xcrun stapler staple <app path>\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -556,21 +564,21 @@ Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_prese
|
||||||
#ifdef MODULE_REGEX_ENABLED
|
#ifdef MODULE_REGEX_ENABLED
|
||||||
#ifdef OSX_ENABLED
|
#ifdef OSX_ENABLED
|
||||||
if (p_preset->get("codesign/timestamp")) {
|
if (p_preset->get("codesign/timestamp")) {
|
||||||
WARN_PRINT("Timestamping is not compatible with ad-hoc signature, and was disabled!");
|
add_message(EXPORT_MESSAGE_INFO, TTR("Code Signing"), TTR("Timestamping is not compatible with ad-hoc signature, and was disabled!"));
|
||||||
}
|
}
|
||||||
if (p_preset->get("codesign/hardened_runtime")) {
|
if (p_preset->get("codesign/hardened_runtime")) {
|
||||||
WARN_PRINT("Hardened Runtime is not compatible with ad-hoc signature, and was disabled!");
|
add_message(EXPORT_MESSAGE_INFO, TTR("Code Signing"), TTR("Hardened Runtime is not compatible with ad-hoc signature, and was disabled!"));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
String error_msg;
|
String error_msg;
|
||||||
Error err = CodeSign::codesign(false, p_preset->get("codesign/replace_existing_signature"), p_path, p_ent_path, error_msg);
|
Error err = CodeSign::codesign(false, p_preset->get("codesign/replace_existing_signature"), p_path, p_ent_path, error_msg);
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
EditorNode::add_io_error("Built-in CodeSign: " + error_msg);
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Built-in CodeSign failed with error \"%s\"."), error_msg));
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
ERR_FAIL_V_MSG(FAILED, "Built-in CodeSign require regex module");
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Built-in CodeSign require regex module."));
|
||||||
#endif
|
#endif
|
||||||
return OK;
|
return OK;
|
||||||
} else {
|
} else {
|
||||||
|
@ -578,14 +586,14 @@ Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_prese
|
||||||
List<String> args;
|
List<String> args;
|
||||||
if (p_preset->get("codesign/timestamp")) {
|
if (p_preset->get("codesign/timestamp")) {
|
||||||
if (ad_hoc) {
|
if (ad_hoc) {
|
||||||
WARN_PRINT("Timestamping is not compatible with ad-hoc signature, and was disabled!");
|
add_message(EXPORT_MESSAGE_INFO, TTR("Code Signing"), TTR("Timestamping is not compatible with ad-hoc signature, and was disabled!"));
|
||||||
} else {
|
} else {
|
||||||
args.push_back("--timestamp");
|
args.push_back("--timestamp");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (p_preset->get("codesign/hardened_runtime")) {
|
if (p_preset->get("codesign/hardened_runtime")) {
|
||||||
if (ad_hoc) {
|
if (ad_hoc) {
|
||||||
WARN_PRINT("Hardened Runtime is not compatible with ad-hoc signature, and was disabled!");
|
add_message(EXPORT_MESSAGE_INFO, TTR("Code Signing"), TTR("Hardened Runtime is not compatible with ad-hoc signature, and was disabled!"));
|
||||||
} else {
|
} else {
|
||||||
args.push_back("--options");
|
args.push_back("--options");
|
||||||
args.push_back("runtime");
|
args.push_back("runtime");
|
||||||
|
@ -622,15 +630,18 @@ Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_prese
|
||||||
|
|
||||||
String str;
|
String str;
|
||||||
Error err = OS::get_singleton()->execute("codesign", args, true, NULL, &str, NULL, true);
|
Error err = OS::get_singleton()->execute("codesign", args, true, NULL, &str, NULL, true);
|
||||||
ERR_FAIL_COND_V(err != OK, err);
|
if (err != OK || (str.find("not found") != -1) || (str.find("not recognized") != -1)) {
|
||||||
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start codesign executable, make sure Xcode command line tools are installed."));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
print_verbose("codesign (" + p_path + "):\n" + str);
|
print_verbose("codesign (" + p_path + "):\n" + str);
|
||||||
if (str.find("no identity found") != -1) {
|
if (str.find("no identity found") != -1) {
|
||||||
EditorNode::add_io_error("CodeSign: " + TTR("No identity found."));
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("No identity found."));
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
if ((str.find("unrecognized blob type") != -1) || (str.find("cannot read entitlement data") != -1)) {
|
if ((str.find("unrecognized blob type") != -1) || (str.find("cannot read entitlement data") != -1)) {
|
||||||
EditorNode::add_io_error("CodeSign: " + TTR("Invalid entitlements file."));
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Invalid entitlements file."));
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
return OK;
|
return OK;
|
||||||
|
@ -675,7 +686,7 @@ Error EditorExportPlatformOSX::_code_sign_directory(const Ref<EditorExportPreset
|
||||||
return code_sign_error;
|
return code_sign_error;
|
||||||
}
|
}
|
||||||
} else if (p_should_error_on_non_code) {
|
} else if (p_should_error_on_non_code) {
|
||||||
ERR_PRINT(vformat("Cannot sign file %s.", current_file));
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Cannot sign file %s."), current_file));
|
||||||
return Error::FAILED;
|
return Error::FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -693,7 +704,7 @@ Error EditorExportPlatformOSX::_copy_and_sign_files(DirAccessRef &dir_access, co
|
||||||
Error err{ OK };
|
Error err{ OK };
|
||||||
if (dir_access->dir_exists(p_src_path)) {
|
if (dir_access->dir_exists(p_src_path)) {
|
||||||
#ifndef UNIX_ENABLED
|
#ifndef UNIX_ENABLED
|
||||||
WARN_PRINT("Relative symlinks are not supported, exported " + p_src_path.get_file() + " might be broken!");
|
add_message(EXPORT_MESSAGE_INFO, TTR("Export"), vformat(TTR("Relative symlinks are not supported, exported \"%s\" might be broken!"), p_src_path.get_file()));
|
||||||
#endif
|
#endif
|
||||||
print_verbose("export framework: " + p_src_path + " -> " + p_in_app_path);
|
print_verbose("export framework: " + p_src_path + " -> " + p_in_app_path);
|
||||||
err = dir_access->make_dir_recursive(p_in_app_path);
|
err = dir_access->make_dir_recursive(p_in_app_path);
|
||||||
|
@ -750,14 +761,17 @@ Error EditorExportPlatformOSX::_create_dmg(const String &p_dmg_path, const Strin
|
||||||
|
|
||||||
String str;
|
String str;
|
||||||
Error err = OS::get_singleton()->execute("hdiutil", args, true, nullptr, &str, nullptr, true);
|
Error err = OS::get_singleton()->execute("hdiutil", args, true, nullptr, &str, nullptr, true);
|
||||||
ERR_FAIL_COND_V(err != OK, err);
|
if (err != OK) {
|
||||||
|
add_message(EXPORT_MESSAGE_ERROR, TTR("DMG Creation"), TTR("Could not start hdiutil executable."));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
print_line("hdiutil returned: " + str);
|
print_line("hdiutil returned: " + str);
|
||||||
if (str.find("create failed") != -1) {
|
if (str.find("create failed") != -1) {
|
||||||
if (str.find("File exists") != -1) {
|
if (str.find("File exists") != -1) {
|
||||||
EditorNode::add_io_error("hdiutil: create failed - file exists");
|
add_message(EXPORT_MESSAGE_ERROR, TTR("DMG Creation"), TTR("`hdiutil create` failed - file exists."));
|
||||||
} else {
|
} else {
|
||||||
EditorNode::add_io_error("hdiutil: create failed");
|
add_message(EXPORT_MESSAGE_ERROR, TTR("DMG Creation"), TTR("`hdiutil create` failed."));
|
||||||
}
|
}
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
|
@ -782,12 +796,13 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
|
||||||
String err;
|
String err;
|
||||||
src_pkg_name = find_export_template("osx.zip", &err);
|
src_pkg_name = find_export_template("osx.zip", &err);
|
||||||
if (src_pkg_name == "") {
|
if (src_pkg_name == "") {
|
||||||
EditorNode::add_io_error(err);
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Templates"), TTR("Export template not found."));
|
||||||
return ERR_FILE_NOT_FOUND;
|
return ERR_FILE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!DirAccess::exists(p_path.get_base_dir())) {
|
if (!DirAccess::exists(p_path.get_base_dir())) {
|
||||||
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Templates"), TTR("The given export path doesn't exist."));
|
||||||
return ERR_FILE_BAD_PATH;
|
return ERR_FILE_BAD_PATH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -800,7 +815,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
|
||||||
|
|
||||||
unzFile src_pkg_zip = unzOpen2(src_pkg_name.utf8().get_data(), &io);
|
unzFile src_pkg_zip = unzOpen2(src_pkg_name.utf8().get_data(), &io);
|
||||||
if (!src_pkg_zip) {
|
if (!src_pkg_zip) {
|
||||||
EditorNode::add_io_error(TTR("Could not find template app to export:") + "\n" + src_pkg_name);
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Templates"), vformat(TTR("Could not find template app to export: \"%s\"."), src_pkg_name));
|
||||||
return ERR_FILE_NOT_FOUND;
|
return ERR_FILE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -827,7 +842,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
|
||||||
} else if (p_path.ends_with("app")) {
|
} else if (p_path.ends_with("app")) {
|
||||||
export_format = "app";
|
export_format = "app";
|
||||||
} else {
|
} else {
|
||||||
EditorNode::add_io_error("Invalid export format");
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Invalid export format."));
|
||||||
return ERR_CANT_CREATE;
|
return ERR_CANT_CREATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -849,8 +864,10 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DirAccess::exists(tmp_app_dir_name)) {
|
if (DirAccess::exists(tmp_app_dir_name)) {
|
||||||
|
String old_dir = tmp_app_dir->get_current_dir();
|
||||||
if (tmp_app_dir->change_dir(tmp_app_path_name) == OK) {
|
if (tmp_app_dir->change_dir(tmp_app_path_name) == OK) {
|
||||||
tmp_app_dir->erase_contents_recursive();
|
tmp_app_dir->erase_contents_recursive();
|
||||||
|
tmp_app_dir->change_dir(old_dir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -920,7 +937,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
|
||||||
|
|
||||||
if (((info.external_fa >> 16L) & 0120000) == 0120000) {
|
if (((info.external_fa >> 16L) & 0120000) == 0120000) {
|
||||||
#ifndef UNIX_ENABLED
|
#ifndef UNIX_ENABLED
|
||||||
WARN_PRINT(vformat(TTR("Relative symlinks are not supported on this OS, the exported project might be broken!")));
|
add_message(EXPORT_MESSAGE_INFO, TTR("Export"), TTR("Relative symlinks are not supported on this OS, the exported project might be broken!"));
|
||||||
#endif
|
#endif
|
||||||
// Handle symlinks in the archive.
|
// Handle symlinks in the archive.
|
||||||
file = tmp_app_path_name.plus_file(file);
|
file = tmp_app_path_name.plus_file(file);
|
||||||
|
@ -1030,7 +1047,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
|
||||||
unzClose(src_pkg_zip);
|
unzClose(src_pkg_zip);
|
||||||
|
|
||||||
if (!found_binary) {
|
if (!found_binary) {
|
||||||
ERR_PRINT(vformat(TTR("Requested template binary '%s' not found. It might be missing from your template archive."), binary_to_use));
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Requested template binary \"%s\" not found. It might be missing from your template archive."), binary_to_use));
|
||||||
err = ERR_FILE_NOT_FOUND;
|
err = ERR_FILE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1190,7 +1207,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
|
||||||
ad_hoc = (sign_identity == "" || sign_identity == "-");
|
ad_hoc = (sign_identity == "" || sign_identity == "-");
|
||||||
bool lib_validation = p_preset->get("codesign/entitlements/disable_library_validation");
|
bool lib_validation = p_preset->get("codesign/entitlements/disable_library_validation");
|
||||||
if ((!dylibs_found.empty() || !shared_objects.empty()) && sign_enabled && ad_hoc && !lib_validation) {
|
if ((!dylibs_found.empty() || !shared_objects.empty()) && sign_enabled && ad_hoc && !lib_validation) {
|
||||||
ERR_PRINT(TTR("Ad-hoc signed applications require the 'Disable Library Validation' entitlement to load dynamic libraries."));
|
add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("Ad-hoc signed applications require the 'Disable Library Validation' entitlement to load dynamic libraries."));
|
||||||
err = ERR_CANT_CREATE;
|
err = ERR_CANT_CREATE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1269,7 +1286,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
|
||||||
bool noto_enabled = p_preset->get("notarization/enable");
|
bool noto_enabled = p_preset->get("notarization/enable");
|
||||||
if (err == OK && noto_enabled) {
|
if (err == OK && noto_enabled) {
|
||||||
if (export_format == "app") {
|
if (export_format == "app") {
|
||||||
WARN_PRINT(TTR("Notarization requires the app to be archived first, select the DMG or ZIP export format instead."));
|
add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), TTR("Notarization requires the app to be archived first, select the DMG or ZIP export format instead."));
|
||||||
} else {
|
} else {
|
||||||
if (ep.step(TTR("Sending archive for notarization"), 4)) {
|
if (ep.step(TTR("Sending archive for notarization"), 4)) {
|
||||||
return ERR_SKIP;
|
return ERR_SKIP;
|
||||||
|
@ -1390,7 +1407,8 @@ void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String
|
||||||
|
|
||||||
FileAccessRef fa = FileAccess::open(dir.plus_file(f), FileAccess::READ);
|
FileAccessRef fa = FileAccess::open(dir.plus_file(f), FileAccess::READ);
|
||||||
if (!fa) {
|
if (!fa) {
|
||||||
ERR_FAIL_MSG("Can't open file to read from path '" + String(dir.plus_file(f)) + "'.");
|
add_message(EXPORT_MESSAGE_ERROR, TTR("ZIP Creation"), vformat(TTR("Could not open file to read from path \"%s\"."), dir.plus_file(f)));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
const int bufsize = 16384;
|
const int bufsize = 16384;
|
||||||
uint8_t buf[bufsize];
|
uint8_t buf[bufsize];
|
||||||
|
|
|
@ -37,8 +37,6 @@
|
||||||
#include "editor/editor_settings.h"
|
#include "editor/editor_settings.h"
|
||||||
#include "platform/windows/logo.gen.h"
|
#include "platform/windows/logo.gen.h"
|
||||||
|
|
||||||
static Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size);
|
|
||||||
|
|
||||||
class EditorExportPlatformWindows : public EditorExportPlatformPC {
|
class EditorExportPlatformWindows : public EditorExportPlatformPC {
|
||||||
Error _rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path);
|
Error _rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path);
|
||||||
Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path);
|
Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path);
|
||||||
|
@ -47,6 +45,7 @@ public:
|
||||||
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0);
|
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0);
|
||||||
virtual Error sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path);
|
virtual Error sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path);
|
||||||
virtual Error modify_template(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags);
|
virtual Error modify_template(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags);
|
||||||
|
virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size);
|
||||||
virtual void get_export_options(List<ExportOption> *r_options);
|
virtual void get_export_options(List<ExportOption> *r_options);
|
||||||
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const;
|
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const;
|
||||||
virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const;
|
virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const;
|
||||||
|
@ -62,10 +61,9 @@ Error EditorExportPlatformWindows::sign_shared_object(const Ref<EditorExportPres
|
||||||
|
|
||||||
Error EditorExportPlatformWindows::modify_template(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
|
Error EditorExportPlatformWindows::modify_template(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
|
||||||
if (p_preset->get("application/modify_resources")) {
|
if (p_preset->get("application/modify_resources")) {
|
||||||
return _rcedit_add_data(p_preset, p_path);
|
_rcedit_add_data(p_preset, p_path);
|
||||||
} else {
|
|
||||||
return OK;
|
|
||||||
}
|
}
|
||||||
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
|
Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
|
||||||
|
@ -76,12 +74,15 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset>
|
||||||
|
|
||||||
Error err = EditorExportPlatformPC::export_project(p_preset, p_debug, pck_path, p_flags);
|
Error err = EditorExportPlatformPC::export_project(p_preset, p_debug, pck_path, p_flags);
|
||||||
if (p_preset->get("codesign/enable") && err == OK) {
|
if (p_preset->get("codesign/enable") && err == OK) {
|
||||||
err = _code_sign(p_preset, pck_path);
|
_code_sign(p_preset, pck_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_preset->get("binary_format/embed_pck") && err == OK) {
|
if (p_preset->get("binary_format/embed_pck") && err == OK) {
|
||||||
DirAccessRef tmp_dir = DirAccess::create_for_path(p_path.get_base_dir());
|
DirAccessRef tmp_dir = DirAccess::create_for_path(p_path.get_base_dir());
|
||||||
err = tmp_dir->rename(pck_path, p_path);
|
err = tmp_dir->rename(pck_path, p_path);
|
||||||
|
if (err != OK) {
|
||||||
|
add_message(EXPORT_MESSAGE_ERROR, TTR("PCK Embedding"), vformat(TTR("Failed to rename temporary file \"%s\"."), pck_path));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
@ -123,7 +124,7 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset
|
||||||
String rcedit_path = EditorSettings::get_singleton()->get("export/windows/rcedit");
|
String rcedit_path = EditorSettings::get_singleton()->get("export/windows/rcedit");
|
||||||
|
|
||||||
if (rcedit_path != String() && !FileAccess::exists(rcedit_path)) {
|
if (rcedit_path != String() && !FileAccess::exists(rcedit_path)) {
|
||||||
ERR_PRINT("Could not find rcedit executable at " + rcedit_path + ", aborting.");
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), vformat(TTR("Could not find rcedit executable at \"%s\"."), rcedit_path));
|
||||||
return ERR_FILE_NOT_FOUND;
|
return ERR_FILE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,7 +137,7 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset
|
||||||
String wine_path = EditorSettings::get_singleton()->get("export/windows/wine");
|
String wine_path = EditorSettings::get_singleton()->get("export/windows/wine");
|
||||||
|
|
||||||
if (wine_path != String() && !FileAccess::exists(wine_path)) {
|
if (wine_path != String() && !FileAccess::exists(wine_path)) {
|
||||||
ERR_PRINT("Could not find wine executable at " + wine_path + ", aborting.");
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), vformat(TTR("Could not find wine executable at \"%s\"."), wine_path));
|
||||||
return ERR_FILE_NOT_FOUND;
|
return ERR_FILE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,10 +204,14 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset
|
||||||
|
|
||||||
String str;
|
String str;
|
||||||
Error err = OS::get_singleton()->execute(rcedit_path, args, true, nullptr, &str, nullptr, true);
|
Error err = OS::get_singleton()->execute(rcedit_path, args, true, nullptr, &str, nullptr, true);
|
||||||
ERR_FAIL_COND_V_MSG(err != OK, err, "Could not start rcedit executable, configure rcedit path in the Editor Settings (Export > Windows > Rcedit).");
|
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)."));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
print_line("rcedit (" + p_path + "): " + str);
|
print_line("rcedit (" + p_path + "): " + str);
|
||||||
|
|
||||||
if (str.find("Fatal error") != -1) {
|
if (str.find("Fatal error") != -1) {
|
||||||
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), vformat(TTR("rcedit failed to modify executable:\n%s"), str));
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,7 +224,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
|
||||||
#ifdef WINDOWS_ENABLED
|
#ifdef WINDOWS_ENABLED
|
||||||
String signtool_path = EditorSettings::get_singleton()->get("export/windows/signtool");
|
String signtool_path = EditorSettings::get_singleton()->get("export/windows/signtool");
|
||||||
if (signtool_path != String() && !FileAccess::exists(signtool_path)) {
|
if (signtool_path != String() && !FileAccess::exists(signtool_path)) {
|
||||||
ERR_PRINT("Could not find signtool executable at " + signtool_path + ", aborting.");
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Could not find signtool executable at \"%s\"."), signtool_path));
|
||||||
return ERR_FILE_NOT_FOUND;
|
return ERR_FILE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
if (signtool_path == String()) {
|
if (signtool_path == String()) {
|
||||||
|
@ -228,7 +233,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
|
||||||
#else
|
#else
|
||||||
String signtool_path = EditorSettings::get_singleton()->get("export/windows/osslsigncode");
|
String signtool_path = EditorSettings::get_singleton()->get("export/windows/osslsigncode");
|
||||||
if (signtool_path != String() && !FileAccess::exists(signtool_path)) {
|
if (signtool_path != String() && !FileAccess::exists(signtool_path)) {
|
||||||
ERR_PRINT("Could not find osslsigncode executable at " + signtool_path + ", aborting.");
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Could not find osslsigncode executable at \"%s\"."), signtool_path));
|
||||||
return ERR_FILE_NOT_FOUND;
|
return ERR_FILE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
if (signtool_path == String()) {
|
if (signtool_path == String()) {
|
||||||
|
@ -248,7 +253,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
|
||||||
args.push_back("/f");
|
args.push_back("/f");
|
||||||
args.push_back(p_preset->get("codesign/identity"));
|
args.push_back(p_preset->get("codesign/identity"));
|
||||||
} else {
|
} else {
|
||||||
EditorNode::add_io_error("codesign: no identity found");
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("No identity found."));
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
} else if (id_type == 2) { //Windows certificate store
|
} else if (id_type == 2) { //Windows certificate store
|
||||||
|
@ -256,11 +261,11 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
|
||||||
args.push_back("/sha1");
|
args.push_back("/sha1");
|
||||||
args.push_back(p_preset->get("codesign/identity"));
|
args.push_back(p_preset->get("codesign/identity"));
|
||||||
} else {
|
} else {
|
||||||
EditorNode::add_io_error("codesign: no identity found");
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("No identity found."));
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
EditorNode::add_io_error("codesign: invalid identity type");
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Invalid identity type."));
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
@ -268,7 +273,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
|
||||||
args.push_back("-pkcs12");
|
args.push_back("-pkcs12");
|
||||||
args.push_back(p_preset->get("codesign/identity"));
|
args.push_back(p_preset->get("codesign/identity"));
|
||||||
} else {
|
} else {
|
||||||
EditorNode::add_io_error("codesign: no identity found");
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("No identity found."));
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -300,7 +305,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
|
||||||
args.push_back(p_preset->get("codesign/timestamp_server_url"));
|
args.push_back(p_preset->get("codesign/timestamp_server_url"));
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
EditorNode::add_io_error("codesign: invalid timestamp server");
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Invalid timestamp server."));
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -347,7 +352,10 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
|
||||||
|
|
||||||
String str;
|
String str;
|
||||||
Error err = OS::get_singleton()->execute(signtool_path, args, true, nullptr, &str, nullptr, true);
|
Error err = OS::get_singleton()->execute(signtool_path, args, true, nullptr, &str, nullptr, true);
|
||||||
ERR_FAIL_COND_V_MSG(err != OK, err, "Could not start signtool executable, configure signtool path in the Editor Settings (Export > Windows > Signtool).");
|
if (err != OK || (str.find("not found") != -1) || (str.find("not recognized") != -1)) {
|
||||||
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start signtool executable, configure signtool path in the Editor Settings (Export > Windows > Signtool)."));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
print_line("codesign (" + p_path + "): " + str);
|
print_line("codesign (" + p_path + "): " + str);
|
||||||
#ifndef WINDOWS_ENABLED
|
#ifndef WINDOWS_ENABLED
|
||||||
|
@ -355,6 +363,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
|
||||||
#else
|
#else
|
||||||
if (str.find("Failed") != -1) {
|
if (str.find("Failed") != -1) {
|
||||||
#endif
|
#endif
|
||||||
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Signtool failed to sign executable:\n%s"), str));
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -362,10 +371,16 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
|
||||||
DirAccessRef tmp_dir = DirAccess::create_for_path(p_path.get_base_dir());
|
DirAccessRef tmp_dir = DirAccess::create_for_path(p_path.get_base_dir());
|
||||||
|
|
||||||
err = tmp_dir->remove(p_path);
|
err = tmp_dir->remove(p_path);
|
||||||
ERR_FAIL_COND_V(err != OK, err);
|
if (err != OK) {
|
||||||
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Failed to remove temporary file \"%s\"."), p_path));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
err = tmp_dir->rename(p_path + "_signed", p_path);
|
err = tmp_dir->rename(p_path + "_signed", p_path);
|
||||||
ERR_FAIL_COND_V(err != OK, err);
|
if (err != OK) {
|
||||||
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Failed to rename temporary file \"%s\"."), p_path + "_signed"));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
|
@ -414,49 +429,17 @@ bool EditorExportPlatformWindows::can_export(const Ref<EditorExportPreset> &p_pr
|
||||||
return valid;
|
return valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
void register_windows_exporter() {
|
Error EditorExportPlatformWindows::fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) {
|
||||||
EDITOR_DEF("export/windows/rcedit", "");
|
|
||||||
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/windows/rcedit", PROPERTY_HINT_GLOBAL_FILE, "*.exe"));
|
|
||||||
#ifdef WINDOWS_ENABLED
|
|
||||||
EDITOR_DEF("export/windows/signtool", "");
|
|
||||||
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/windows/signtool", PROPERTY_HINT_GLOBAL_FILE, "*.exe"));
|
|
||||||
#else
|
|
||||||
EDITOR_DEF("export/windows/osslsigncode", "");
|
|
||||||
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/windows/osslsigncode", PROPERTY_HINT_GLOBAL_FILE));
|
|
||||||
// On non-Windows we need WINE to run rcedit
|
|
||||||
EDITOR_DEF("export/windows/wine", "");
|
|
||||||
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/windows/wine", PROPERTY_HINT_GLOBAL_FILE));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Ref<EditorExportPlatformWindows> platform;
|
|
||||||
platform.instance();
|
|
||||||
|
|
||||||
Ref<Image> img = memnew(Image(_windows_logo));
|
|
||||||
Ref<ImageTexture> logo;
|
|
||||||
logo.instance();
|
|
||||||
logo->create_from_image(img);
|
|
||||||
platform->set_logo(logo);
|
|
||||||
platform->set_name("Windows Desktop");
|
|
||||||
platform->set_extension("exe");
|
|
||||||
platform->set_release_32("windows_32_release.exe");
|
|
||||||
platform->set_debug_32("windows_32_debug.exe");
|
|
||||||
platform->set_release_64("windows_64_release.exe");
|
|
||||||
platform->set_debug_64("windows_64_debug.exe");
|
|
||||||
platform->set_os_name("Windows");
|
|
||||||
platform->set_fixup_embedded_pck_func(&fixup_embedded_pck);
|
|
||||||
|
|
||||||
EditorExport::get_singleton()->add_export_platform(platform);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) {
|
|
||||||
// Patch the header of the "pck" section in the PE file so that it corresponds to the embedded data
|
// Patch the header of the "pck" section in the PE file so that it corresponds to the embedded data
|
||||||
|
|
||||||
if (p_embedded_size + p_embedded_start >= 0x100000000) { // Check for total executable size
|
if (p_embedded_size + p_embedded_start >= 0x100000000) { // Check for total executable size
|
||||||
ERR_FAIL_V_MSG(ERR_INVALID_DATA, "Windows executables cannot be >= 4 GiB.");
|
add_message(EXPORT_MESSAGE_ERROR, TTR("PCK Embedding"), TTR("Windows executables cannot be >= 4 GiB."));
|
||||||
|
return ERR_INVALID_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileAccess *f = FileAccess::open(p_path, FileAccess::READ_WRITE);
|
FileAccess *f = FileAccess::open(p_path, FileAccess::READ_WRITE);
|
||||||
if (!f) {
|
if (!f) {
|
||||||
|
add_message(EXPORT_MESSAGE_ERROR, TTR("PCK Embedding"), vformat(TTR("Failed to open executable file \"%s\"."), p_path));
|
||||||
return ERR_CANT_OPEN;
|
return ERR_CANT_OPEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -469,6 +452,7 @@ static Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start,
|
||||||
uint32_t magic = f->get_32();
|
uint32_t magic = f->get_32();
|
||||||
if (magic != 0x00004550) {
|
if (magic != 0x00004550) {
|
||||||
f->close();
|
f->close();
|
||||||
|
add_message(EXPORT_MESSAGE_ERROR, TTR("PCK Embedding"), TTR("Executable file header corrupted."));
|
||||||
return ERR_FILE_CORRUPT;
|
return ERR_FILE_CORRUPT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -520,5 +504,42 @@ static Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start,
|
||||||
|
|
||||||
f->close();
|
f->close();
|
||||||
|
|
||||||
return found ? OK : ERR_FILE_CORRUPT;
|
if (!found) {
|
||||||
|
add_message(EXPORT_MESSAGE_ERROR, TTR("PCK Embedding"), TTR("Executable \"pck\" section not found."));
|
||||||
|
return ERR_FILE_CORRUPT;
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void register_windows_exporter() {
|
||||||
|
EDITOR_DEF("export/windows/rcedit", "");
|
||||||
|
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/windows/rcedit", PROPERTY_HINT_GLOBAL_FILE, "*.exe"));
|
||||||
|
#ifdef WINDOWS_ENABLED
|
||||||
|
EDITOR_DEF("export/windows/signtool", "");
|
||||||
|
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/windows/signtool", PROPERTY_HINT_GLOBAL_FILE, "*.exe"));
|
||||||
|
#else
|
||||||
|
EDITOR_DEF("export/windows/osslsigncode", "");
|
||||||
|
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/windows/osslsigncode", PROPERTY_HINT_GLOBAL_FILE));
|
||||||
|
// On non-Windows we need WINE to run rcedit
|
||||||
|
EDITOR_DEF("export/windows/wine", "");
|
||||||
|
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/windows/wine", PROPERTY_HINT_GLOBAL_FILE));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Ref<EditorExportPlatformWindows> platform;
|
||||||
|
platform.instance();
|
||||||
|
|
||||||
|
Ref<Image> img = memnew(Image(_windows_logo));
|
||||||
|
Ref<ImageTexture> logo;
|
||||||
|
logo.instance();
|
||||||
|
logo->create_from_image(img);
|
||||||
|
platform->set_logo(logo);
|
||||||
|
platform->set_name("Windows Desktop");
|
||||||
|
platform->set_extension("exe");
|
||||||
|
platform->set_release_32("windows_32_release.exe");
|
||||||
|
platform->set_debug_32("windows_32_debug.exe");
|
||||||
|
platform->set_release_64("windows_64_release.exe");
|
||||||
|
platform->set_debug_64("windows_64_debug.exe");
|
||||||
|
platform->set_os_name("Windows");
|
||||||
|
|
||||||
|
EditorExport::get_singleton()->add_export_platform(platform);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,36 +35,17 @@
|
||||||
#include "platform/x11/logo.gen.h"
|
#include "platform/x11/logo.gen.h"
|
||||||
#include "scene/resources/texture.h"
|
#include "scene/resources/texture.h"
|
||||||
|
|
||||||
static Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size);
|
class EditorExportPlatformX11 : public EditorExportPlatformPC {
|
||||||
|
public:
|
||||||
|
virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size);
|
||||||
|
};
|
||||||
|
|
||||||
void register_x11_exporter() {
|
Error EditorExportPlatformX11::fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) {
|
||||||
Ref<EditorExportPlatformPC> platform;
|
|
||||||
platform.instance();
|
|
||||||
|
|
||||||
Ref<Image> img = memnew(Image(_x11_logo));
|
|
||||||
Ref<ImageTexture> logo;
|
|
||||||
logo.instance();
|
|
||||||
logo->create_from_image(img);
|
|
||||||
platform->set_logo(logo);
|
|
||||||
platform->set_name("Linux/X11");
|
|
||||||
platform->set_extension("x86");
|
|
||||||
platform->set_extension("x86_64", "binary_format/64_bits");
|
|
||||||
platform->set_release_32("linux_x11_32_release");
|
|
||||||
platform->set_debug_32("linux_x11_32_debug");
|
|
||||||
platform->set_release_64("linux_x11_64_release");
|
|
||||||
platform->set_debug_64("linux_x11_64_debug");
|
|
||||||
platform->set_os_name("X11");
|
|
||||||
platform->set_chmod_flags(0755);
|
|
||||||
platform->set_fixup_embedded_pck_func(&fixup_embedded_pck);
|
|
||||||
|
|
||||||
EditorExport::get_singleton()->add_export_platform(platform);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) {
|
|
||||||
// Patch the header of the "pck" section in the ELF file so that it corresponds to the embedded data
|
// Patch the header of the "pck" section in the ELF file so that it corresponds to the embedded data
|
||||||
|
|
||||||
FileAccess *f = FileAccess::open(p_path, FileAccess::READ_WRITE);
|
FileAccess *f = FileAccess::open(p_path, FileAccess::READ_WRITE);
|
||||||
if (!f) {
|
if (!f) {
|
||||||
|
add_message(EXPORT_MESSAGE_ERROR, TTR("PCK Embedding"), vformat(TTR("Failed to open executable file \"%s\"."), p_path));
|
||||||
return ERR_CANT_OPEN;
|
return ERR_CANT_OPEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,6 +54,7 @@ static Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start,
|
||||||
uint32_t magic = f->get_32();
|
uint32_t magic = f->get_32();
|
||||||
if (magic != 0x464c457f) { // 0x7F + "ELF"
|
if (magic != 0x464c457f) { // 0x7F + "ELF"
|
||||||
f->close();
|
f->close();
|
||||||
|
add_message(EXPORT_MESSAGE_ERROR, TTR("PCK Embedding"), TTR("Executable file header corrupted."));
|
||||||
return ERR_FILE_CORRUPT;
|
return ERR_FILE_CORRUPT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,7 +65,8 @@ static Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start,
|
||||||
|
|
||||||
if (bits == 32 && p_embedded_size >= 0x100000000) {
|
if (bits == 32 && p_embedded_size >= 0x100000000) {
|
||||||
f->close();
|
f->close();
|
||||||
ERR_FAIL_V_MSG(ERR_INVALID_DATA, "32-bit executables cannot have embedded data >= 4 GiB.");
|
add_message(EXPORT_MESSAGE_ERROR, TTR("PCK Embedding"), TTR("32-bit executables cannot have embedded data >= 4 GiB."));
|
||||||
|
return ERR_INVALID_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get info about the section header table
|
// Get info about the section header table
|
||||||
|
@ -162,5 +145,31 @@ static Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start,
|
||||||
memfree(strings);
|
memfree(strings);
|
||||||
f->close();
|
f->close();
|
||||||
|
|
||||||
return found ? OK : ERR_FILE_CORRUPT;
|
if (!found) {
|
||||||
|
add_message(EXPORT_MESSAGE_ERROR, TTR("PCK Embedding"), TTR("Executable \"pck\" section not found."));
|
||||||
|
return ERR_FILE_CORRUPT;
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void register_x11_exporter() {
|
||||||
|
Ref<EditorExportPlatformX11> platform;
|
||||||
|
platform.instance();
|
||||||
|
|
||||||
|
Ref<Image> img = memnew(Image(_x11_logo));
|
||||||
|
Ref<ImageTexture> logo;
|
||||||
|
logo.instance();
|
||||||
|
logo->create_from_image(img);
|
||||||
|
platform->set_logo(logo);
|
||||||
|
platform->set_name("Linux/X11");
|
||||||
|
platform->set_extension("x86");
|
||||||
|
platform->set_extension("x86_64", "binary_format/64_bits");
|
||||||
|
platform->set_release_32("linux_x11_32_release");
|
||||||
|
platform->set_debug_32("linux_x11_32_debug");
|
||||||
|
platform->set_release_64("linux_x11_64_release");
|
||||||
|
platform->set_debug_64("linux_x11_64_debug");
|
||||||
|
platform->set_os_name("X11");
|
||||||
|
platform->set_chmod_flags(0755);
|
||||||
|
|
||||||
|
EditorExport::get_singleton()->add_export_platform(platform);
|
||||||
}
|
}
|
||||||
|
|
|
@ -686,7 +686,20 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_mode == PROCESS_DRAW && visible) {
|
if (p_mode == PROCESS_DRAW && visible) {
|
||||||
img->image->draw_rect(ci, Rect2(p_ofs + Point2(align_ofs + wofs, y + lh - font->get_descent() - img->size.height), img->size));
|
switch (img->align) {
|
||||||
|
case INLINE_ALIGN_TOP: {
|
||||||
|
img->image->draw_rect(ci, Rect2(p_ofs + Point2(align_ofs + wofs, y + lh - (font->get_descent() + font->get_ascent())), img->size));
|
||||||
|
} break;
|
||||||
|
case INLINE_ALIGN_CENTER: {
|
||||||
|
img->image->draw_rect(ci, Rect2(p_ofs + Point2(align_ofs + wofs, y + lh - (font->get_descent() + font->get_ascent() + img->size.height) / 2), img->size));
|
||||||
|
} break;
|
||||||
|
case INLINE_ALIGN_BASELINE: {
|
||||||
|
img->image->draw_rect(ci, Rect2(p_ofs + Point2(align_ofs + wofs, y + lh - (font->get_descent() + img->size.height)), img->size));
|
||||||
|
} break;
|
||||||
|
case INLINE_ALIGN_BOTTOM: {
|
||||||
|
img->image->draw_rect(ci, Rect2(p_ofs + Point2(align_ofs + wofs, y + lh - img->size.height), img->size));
|
||||||
|
} break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
p_char_count++;
|
p_char_count++;
|
||||||
|
|
||||||
|
@ -1720,7 +1733,7 @@ void RichTextLabel::_remove_item(Item *p_item, const int p_line, const int p_sub
|
||||||
memdelete(p_item);
|
memdelete(p_item);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RichTextLabel::add_image(const Ref<Texture> &p_image, const int p_width, const int p_height) {
|
void RichTextLabel::add_image(const Ref<Texture> &p_image, const int p_width, const int p_height, RichTextLabel::InlineAlign p_align) {
|
||||||
if (current->type == ITEM_TABLE) {
|
if (current->type == ITEM_TABLE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1731,6 +1744,7 @@ void RichTextLabel::add_image(const Ref<Texture> &p_image, const int p_width, co
|
||||||
ItemImage *item = memnew(ItemImage);
|
ItemImage *item = memnew(ItemImage);
|
||||||
|
|
||||||
item->image = p_image;
|
item->image = p_image;
|
||||||
|
item->align = p_align;
|
||||||
|
|
||||||
if (p_width > 0) {
|
if (p_width > 0) {
|
||||||
// custom width
|
// custom width
|
||||||
|
@ -2801,7 +2815,7 @@ void RichTextLabel::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("get_text"), &RichTextLabel::get_text);
|
ClassDB::bind_method(D_METHOD("get_text"), &RichTextLabel::get_text);
|
||||||
ClassDB::bind_method(D_METHOD("add_text", "text"), &RichTextLabel::add_text);
|
ClassDB::bind_method(D_METHOD("add_text", "text"), &RichTextLabel::add_text);
|
||||||
ClassDB::bind_method(D_METHOD("set_text", "text"), &RichTextLabel::set_text);
|
ClassDB::bind_method(D_METHOD("set_text", "text"), &RichTextLabel::set_text);
|
||||||
ClassDB::bind_method(D_METHOD("add_image", "image", "width", "height"), &RichTextLabel::add_image, DEFVAL(0), DEFVAL(0));
|
ClassDB::bind_method(D_METHOD("add_image", "image", "width", "height", "align"), &RichTextLabel::add_image, DEFVAL(0), DEFVAL(0), DEFVAL(INLINE_ALIGN_BASELINE));
|
||||||
ClassDB::bind_method(D_METHOD("newline"), &RichTextLabel::add_newline);
|
ClassDB::bind_method(D_METHOD("newline"), &RichTextLabel::add_newline);
|
||||||
ClassDB::bind_method(D_METHOD("remove_line", "line"), &RichTextLabel::remove_line);
|
ClassDB::bind_method(D_METHOD("remove_line", "line"), &RichTextLabel::remove_line);
|
||||||
ClassDB::bind_method(D_METHOD("push_font", "font"), &RichTextLabel::push_font);
|
ClassDB::bind_method(D_METHOD("push_font", "font"), &RichTextLabel::push_font);
|
||||||
|
@ -2914,6 +2928,11 @@ void RichTextLabel::_bind_methods() {
|
||||||
BIND_ENUM_CONSTANT(ALIGN_RIGHT);
|
BIND_ENUM_CONSTANT(ALIGN_RIGHT);
|
||||||
BIND_ENUM_CONSTANT(ALIGN_FILL);
|
BIND_ENUM_CONSTANT(ALIGN_FILL);
|
||||||
|
|
||||||
|
BIND_ENUM_CONSTANT(INLINE_ALIGN_TOP);
|
||||||
|
BIND_ENUM_CONSTANT(INLINE_ALIGN_CENTER);
|
||||||
|
BIND_ENUM_CONSTANT(INLINE_ALIGN_BASELINE);
|
||||||
|
BIND_ENUM_CONSTANT(INLINE_ALIGN_BOTTOM);
|
||||||
|
|
||||||
BIND_ENUM_CONSTANT(LIST_NUMBERS);
|
BIND_ENUM_CONSTANT(LIST_NUMBERS);
|
||||||
BIND_ENUM_CONSTANT(LIST_LETTERS);
|
BIND_ENUM_CONSTANT(LIST_LETTERS);
|
||||||
BIND_ENUM_CONSTANT(LIST_DOTS);
|
BIND_ENUM_CONSTANT(LIST_DOTS);
|
||||||
|
|
|
@ -46,6 +46,14 @@ public:
|
||||||
ALIGN_FILL
|
ALIGN_FILL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum InlineAlign {
|
||||||
|
|
||||||
|
INLINE_ALIGN_TOP,
|
||||||
|
INLINE_ALIGN_CENTER,
|
||||||
|
INLINE_ALIGN_BASELINE,
|
||||||
|
INLINE_ALIGN_BOTTOM
|
||||||
|
};
|
||||||
|
|
||||||
enum ListType {
|
enum ListType {
|
||||||
|
|
||||||
LIST_NUMBERS,
|
LIST_NUMBERS,
|
||||||
|
@ -147,7 +155,11 @@ private:
|
||||||
struct ItemImage : public Item {
|
struct ItemImage : public Item {
|
||||||
Ref<Texture> image;
|
Ref<Texture> image;
|
||||||
Size2 size;
|
Size2 size;
|
||||||
ItemImage() { type = ITEM_IMAGE; }
|
InlineAlign align;
|
||||||
|
ItemImage() {
|
||||||
|
type = ITEM_IMAGE;
|
||||||
|
align = INLINE_ALIGN_BASELINE;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ItemFont : public Item {
|
struct ItemFont : public Item {
|
||||||
|
@ -407,7 +419,7 @@ protected:
|
||||||
public:
|
public:
|
||||||
String get_text();
|
String get_text();
|
||||||
void add_text(const String &p_text);
|
void add_text(const String &p_text);
|
||||||
void add_image(const Ref<Texture> &p_image, const int p_width = 0, const int p_height = 0);
|
void add_image(const Ref<Texture> &p_image, const int p_width = 0, const int p_height = 0, RichTextLabel::InlineAlign p_align = INLINE_ALIGN_BASELINE);
|
||||||
void add_newline();
|
void add_newline();
|
||||||
bool remove_line(const int p_line);
|
bool remove_line(const int p_line);
|
||||||
void push_font(const Ref<Font> &p_font);
|
void push_font(const Ref<Font> &p_font);
|
||||||
|
@ -509,6 +521,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
VARIANT_ENUM_CAST(RichTextLabel::Align);
|
VARIANT_ENUM_CAST(RichTextLabel::Align);
|
||||||
|
VARIANT_ENUM_CAST(RichTextLabel::InlineAlign);
|
||||||
VARIANT_ENUM_CAST(RichTextLabel::ListType);
|
VARIANT_ENUM_CAST(RichTextLabel::ListType);
|
||||||
VARIANT_ENUM_CAST(RichTextLabel::ItemType);
|
VARIANT_ENUM_CAST(RichTextLabel::ItemType);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue