summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--COPYRIGHT.txt2
-rw-r--r--core/io/resource_format_binary.cpp19
-rw-r--r--doc/classes/NavigationRegion2D.xml9
-rw-r--r--doc/classes/NavigationRegion3D.xml10
-rw-r--r--doc/classes/NavigationServer2D.xml30
-rw-r--r--doc/classes/NavigationServer3D.xml30
-rw-r--r--doc/classes/ProjectSettings.xml4
-rw-r--r--editor/editor_export.cpp114
-rw-r--r--editor/editor_export.h59
-rw-r--r--editor/editor_node.cpp17
-rw-r--r--editor/editor_run_native.cpp17
-rw-r--r--editor/editor_run_native.h5
-rw-r--r--editor/project_export.cpp46
-rw-r--r--editor/project_export.h3
-rw-r--r--modules/gridmap/grid_map.cpp41
-rw-r--r--modules/gridmap/grid_map.h1
-rw-r--r--modules/navigation/godot_navigation_server.cpp30
-rw-r--r--modules/navigation/godot_navigation_server.h6
-rw-r--r--modules/navigation/nav_map.cpp16
-rw-r--r--modules/navigation/nav_map.h4
-rw-r--r--modules/navigation/nav_region.h8
-rw-r--r--modules/navigation/navigation_mesh_generator.cpp25
-rw-r--r--platform/android/export/export_plugin.cpp69
-rw-r--r--platform/iphone/export/export_plugin.cpp10
-rw-r--r--platform/javascript/export/export_plugin.cpp40
-rw-r--r--platform/linuxbsd/export/export_plugin.cpp20
-rw-r--r--platform/linuxbsd/export/export_plugin.h2
-rw-r--r--platform/osx/export/export_plugin.cpp113
-rw-r--r--platform/windows/export/export_plugin.cpp72
-rw-r--r--platform/windows/export/export_plugin.h2
-rw-r--r--scene/2d/navigation_region_2d.cpp30
-rw-r--r--scene/2d/navigation_region_2d.h9
-rw-r--r--scene/3d/navigation_region_3d.cpp30
-rw-r--r--scene/3d/navigation_region_3d.h9
-rw-r--r--scene/resources/world_3d.cpp4
-rw-r--r--servers/navigation_server_2d.cpp10
-rw-r--r--servers/navigation_server_2d.h8
-rw-r--r--servers/navigation_server_3d.cpp4
-rw-r--r--servers/navigation_server_3d.h8
-rw-r--r--thirdparty/README.md5
-rw-r--r--thirdparty/freetype/patches/fix_gcc_lto_build.diff34
-rw-r--r--thirdparty/freetype/src/smooth/ftgrays.c9
42 files changed, 805 insertions, 179 deletions
diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt
index 14c61c187f..60fda8f971 100644
--- a/COPYRIGHT.txt
+++ b/COPYRIGHT.txt
@@ -132,7 +132,7 @@ Copyright: 2016, Intel Corporation
License: Expat
Files: ./servers/rendering/renderer_rd/shaders/taa_resolve.glsl
-Comment: Temporal Anti-Aliasing reslove implementation
+Comment: Temporal Anti-Aliasing resolve implementation
Copyright: 2016, Panos Karabelas
License: Expat
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index 24458f20b4..2469e1a4be 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -1547,10 +1547,11 @@ void ResourceFormatSaverBinaryInstance::write_variant(Ref<FileAccess> f, const V
case Variant::COLOR: {
f->store_32(VARIANT_COLOR);
Color val = p_property;
- f->store_real(val.r);
- f->store_real(val.g);
- f->store_real(val.b);
- f->store_real(val.a);
+ // Color are always floats
+ f->store_float(val.r);
+ f->store_float(val.g);
+ f->store_float(val.b);
+ f->store_float(val.a);
} break;
case Variant::STRING_NAME: {
@@ -1685,7 +1686,7 @@ void ResourceFormatSaverBinaryInstance::write_variant(Ref<FileAccess> f, const V
f->store_32(len);
const float *r = arr.ptr();
for (int i = 0; i < len; i++) {
- f->store_real(r[i]);
+ f->store_float(r[i]);
}
} break;
@@ -1743,10 +1744,10 @@ void ResourceFormatSaverBinaryInstance::write_variant(Ref<FileAccess> f, const V
f->store_32(len);
const Color *r = arr.ptr();
for (int i = 0; i < len; i++) {
- f->store_real(r[i].r);
- f->store_real(r[i].g);
- f->store_real(r[i].b);
- f->store_real(r[i].a);
+ f->store_float(r[i].r);
+ f->store_float(r[i].g);
+ f->store_float(r[i].b);
+ f->store_float(r[i].a);
}
} break;
diff --git a/doc/classes/NavigationRegion2D.xml b/doc/classes/NavigationRegion2D.xml
index 5cd2e035b6..542aa8f619 100644
--- a/doc/classes/NavigationRegion2D.xml
+++ b/doc/classes/NavigationRegion2D.xml
@@ -7,6 +7,9 @@
A region of the navigation map. It tells the [NavigationServer2D] what can be navigated and what cannot, based on its [NavigationPolygon] resource.
Two regions can be connected to each other if they share a similar edge. You can set the minimum distance between two vertices required to connect two edges by using [method NavigationServer2D.map_set_edge_connection_margin].
[b]Note:[/b] Overlapping two regions' polygons is not enough for connecting two regions. They must share a similar edge.
+ The pathfinding cost of entering this region from another region can be controlled with the [member enter_cost] value.
+ [b]Note[/b]: This value is not added to the path cost when the start position is already inside this region.
+ The pathfinding cost of traveling distances inside this region can be controlled with the [member travel_cost] multiplier.
</description>
<tutorials>
</tutorials>
@@ -22,11 +25,17 @@
<member name="enabled" type="bool" setter="set_enabled" getter="is_enabled" default="true">
Determines if the [NavigationRegion2D] is enabled or disabled.
</member>
+ <member name="enter_cost" type="float" setter="set_enter_cost" getter="get_enter_cost" default="0.0">
+ When pathfinding enters this regions navmesh from another regions navmesh the [code]enter_cost[/code] value is added to the path distance for determining the shortest path.
+ </member>
<member name="layers" type="int" setter="set_layers" getter="get_layers" default="1">
A bitfield determining all layers the region belongs to. These layers can be checked upon when requesting a path with [method NavigationServer2D.map_get_path].
</member>
<member name="navpoly" type="NavigationPolygon" setter="set_navigation_polygon" getter="get_navigation_polygon">
The [NavigationPolygon] resource to use.
</member>
+ <member name="travel_cost" type="float" setter="set_travel_cost" getter="get_travel_cost" default="1.0">
+ When pathfinding moves inside this regions navmesh the traveled distances are multiplied with [code]travel_cost[/code] for determining the shortest path.
+ </member>
</members>
</class>
diff --git a/doc/classes/NavigationRegion3D.xml b/doc/classes/NavigationRegion3D.xml
index 42f0e0c5d9..e45bca7f8b 100644
--- a/doc/classes/NavigationRegion3D.xml
+++ b/doc/classes/NavigationRegion3D.xml
@@ -6,6 +6,10 @@
<description>
A region of the navigation map. It tells the [NavigationServer3D] what can be navigated and what cannot, based on its [NavigationMesh] resource.
Two regions can be connected to each other if they share a similar edge. You can set the minimum distance between two vertices required to connect two edges by using [method NavigationServer3D.map_set_edge_connection_margin].
+ [b]Note:[/b] Overlapping two regions' navmeshes is not enough for connecting two regions. They must share a similar edge.
+ The cost of entering this region from another region can be controlled with the [member enter_cost] value.
+ [b]Note[/b]: This value is not added to the path cost when the start position is already inside this region.
+ The cost of traveling distances inside this region can be controlled with the [member travel_cost] multiplier.
</description>
<tutorials>
</tutorials>
@@ -28,12 +32,18 @@
<member name="enabled" type="bool" setter="set_enabled" getter="is_enabled" default="true">
Determines if the [NavigationRegion3D] is enabled or disabled.
</member>
+ <member name="enter_cost" type="float" setter="set_enter_cost" getter="get_enter_cost" default="0.0">
+ When pathfinding enters this regions navmesh from another regions navmesh the [code]enter_cost[/code] value is added to the path distance for determining the shortest path.
+ </member>
<member name="layers" type="int" setter="set_layers" getter="get_layers" default="1">
A bitfield determining all layers the region belongs to. These layers can be checked upon when requesting a path with [method NavigationServer3D.map_get_path].
</member>
<member name="navmesh" type="NavigationMesh" setter="set_navigation_mesh" getter="get_navigation_mesh">
The [NavigationMesh] resource to use.
</member>
+ <member name="travel_cost" type="float" setter="set_travel_cost" getter="get_travel_cost" default="1.0">
+ When pathfinding moves inside this regions navmesh the traveled distances are multiplied with [code]travel_cost[/code] for determining the shortest path.
+ </member>
</members>
<signals>
<signal name="bake_finished">
diff --git a/doc/classes/NavigationServer2D.xml b/doc/classes/NavigationServer2D.xml
index 1994a7a4c4..7b0dac99c3 100644
--- a/doc/classes/NavigationServer2D.xml
+++ b/doc/classes/NavigationServer2D.xml
@@ -247,6 +247,13 @@
Returns how many connections this [code]region[/code] has with other regions in the map.
</description>
</method>
+ <method name="region_get_enter_cost" qualifiers="const">
+ <return type="float" />
+ <argument index="0" name="region" type="RID" />
+ <description>
+ Returns the [code]enter_cost[/code] of this [code]region[/code].
+ </description>
+ </method>
<method name="region_get_layers" qualifiers="const">
<return type="int" />
<argument index="0" name="region" type="RID" />
@@ -261,6 +268,21 @@
Returns the navigation map [RID] the requested [code]region[/code] is currently assigned to.
</description>
</method>
+ <method name="region_get_travel_cost" qualifiers="const">
+ <return type="float" />
+ <argument index="0" name="region" type="RID" />
+ <description>
+ Returns the [code]travel_cost[/code] of this [code]region[/code].
+ </description>
+ </method>
+ <method name="region_set_enter_cost" qualifiers="const">
+ <return type="void" />
+ <argument index="0" name="region" type="RID" />
+ <argument index="1" name="enter_cost" type="float" />
+ <description>
+ Sets the [code]enter_cost[/code] for this [code]region[/code].
+ </description>
+ </method>
<method name="region_set_layers" qualifiers="const">
<return type="void" />
<argument index="0" name="region" type="RID" />
@@ -293,6 +315,14 @@
Sets the global transformation for the region.
</description>
</method>
+ <method name="region_set_travel_cost" qualifiers="const">
+ <return type="void" />
+ <argument index="0" name="region" type="RID" />
+ <argument index="1" name="travel_cost" type="float" />
+ <description>
+ Sets the [code]travel_cost[/code] for this [code]region[/code].
+ </description>
+ </method>
</methods>
<signals>
<signal name="map_changed">
diff --git a/doc/classes/NavigationServer3D.xml b/doc/classes/NavigationServer3D.xml
index 2a729e7108..d6574dd69a 100644
--- a/doc/classes/NavigationServer3D.xml
+++ b/doc/classes/NavigationServer3D.xml
@@ -297,6 +297,13 @@
Returns how many connections this [code]region[/code] has with other regions in the map.
</description>
</method>
+ <method name="region_get_enter_cost" qualifiers="const">
+ <return type="float" />
+ <argument index="0" name="region" type="RID" />
+ <description>
+ Returns the [code]enter_cost[/code] of this [code]region[/code].
+ </description>
+ </method>
<method name="region_get_layers" qualifiers="const">
<return type="int" />
<argument index="0" name="region" type="RID" />
@@ -311,6 +318,21 @@
Returns the navigation map [RID] the requested [code]region[/code] is currently assigned to.
</description>
</method>
+ <method name="region_get_travel_cost" qualifiers="const">
+ <return type="float" />
+ <argument index="0" name="region" type="RID" />
+ <description>
+ Returns the [code]travel_cost[/code] of this [code]region[/code].
+ </description>
+ </method>
+ <method name="region_set_enter_cost" qualifiers="const">
+ <return type="void" />
+ <argument index="0" name="region" type="RID" />
+ <argument index="1" name="enter_cost" type="float" />
+ <description>
+ Sets the [code]enter_cost[/code] for this [code]region[/code].
+ </description>
+ </method>
<method name="region_set_layers" qualifiers="const">
<return type="void" />
<argument index="0" name="region" type="RID" />
@@ -343,6 +365,14 @@
Sets the global transformation for the region.
</description>
</method>
+ <method name="region_set_travel_cost" qualifiers="const">
+ <return type="void" />
+ <argument index="0" name="region" type="RID" />
+ <argument index="1" name="travel_cost" type="float" />
+ <description>
+ Sets the [code]travel_cost[/code] for this [code]region[/code].
+ </description>
+ </method>
<method name="set_active" qualifiers="const">
<return type="void" />
<argument index="0" name="active" type="bool" />
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index a5ac8f3601..8a3677c0b4 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -1384,10 +1384,10 @@
<member name="navigation/2d/default_edge_connection_margin" type="int" setter="" getter="" default="1">
Default edge connection margin for 2D navigation maps. See [method NavigationServer2D.map_set_edge_connection_margin].
</member>
- <member name="navigation/3d/default_cell_size" type="float" setter="" getter="" default="0.3">
+ <member name="navigation/3d/default_cell_size" type="float" setter="" getter="" default="0.25">
Default cell size for 3D navigation maps. See [method NavigationServer3D.map_set_cell_size].
</member>
- <member name="navigation/3d/default_edge_connection_margin" type="float" setter="" getter="" default="0.3">
+ <member name="navigation/3d/default_edge_connection_margin" type="float" setter="" getter="" default="0.25">
Default edge connection margin for 3D navigation maps. See [method NavigationServer3D.map_set_edge_connection_margin].
</member>
<member name="network/limits/debugger/max_chars_per_second" type="int" setter="" getter="" default="32768">
diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp
index f4a81521df..bb9d930cf5 100644
--- a/editor/editor_export.cpp
+++ b/editor/editor_export.cpp
@@ -46,6 +46,7 @@
#include "editor/editor_file_system.h"
#include "editor/editor_node.h"
#include "editor/editor_paths.h"
+#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "editor/plugins/script_editor_plugin.h"
#include "scene/resources/resource_format_text.h"
@@ -252,6 +253,83 @@ String EditorExportPreset::get_script_encryption_key() const {
///////////////////////////////////
+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, Color(1.0, 1.0, 1.0), INLINE_ALIGNMENT_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_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons")), 16 * EDSCALE, 16 * EDSCALE, Color(1.0, 1.0, 1.0), INLINE_ALIGNMENT_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_theme_icon(SNAME("StatusSuccess"), SNAME("EditorIcons")), 16 * EDSCALE, 16 * EDSCALE, Color(1.0, 1.0, 1.0), INLINE_ALIGNMENT_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_theme_icon(SNAME("StatusError"), SNAME("EditorIcons")), 16 * EDSCALE, 16 * EDSCALE, Color(1.0, 1.0, 1.0), INLINE_ALIGNMENT_CENTER);
+ p_log->add_text(" ");
+ p_log->add_text(TTR("Failed."));
+ has_messages = true;
+ }
+ p_log->add_newline();
+
+ 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_theme_color(SNAME("font_color"), SNAME("Label"));
+ Ref<Texture> icon;
+
+ switch (msg.msg_type) {
+ case EditorExportPlatform::EXPORT_MESSAGE_INFO: {
+ color = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("font_color"), SNAME("Editor")) * Color(1, 1, 1, 0.6);
+ } break;
+ case EditorExportPlatform::EXPORT_MESSAGE_WARNING: {
+ icon = EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Warning"), SNAME("EditorIcons"));
+ color = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("warning_color"), SNAME("Editor"));
+ } break;
+ case EditorExportPlatform::EXPORT_MESSAGE_ERROR: {
+ icon = EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Error"), SNAME("EditorIcons"));
+ color = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("error_color"), SNAME("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) {
String host = EditorSettings::get_singleton()->get("network/debug/remote_host");
int remote_port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port");
@@ -1134,7 +1212,10 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b
String tmppath = EditorPaths::get_singleton()->get_cache_dir().plus_file("packtmp");
Ref<FileAccess> ftmp = FileAccess::open(tmppath, FileAccess::WRITE);
- ERR_FAIL_COND_V_MSG(ftmp.is_null(), ERR_CANT_CREATE, "Cannot create file '" + tmppath + "'.");
+ if (ftmp.is_null()) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Save PCK"), vformat(TTR("Cannot create file \"%s\"."), tmppath));
+ return ERR_CANT_CREATE;
+ }
PackData pd;
pd.ep = &ep;
@@ -1149,7 +1230,7 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b
if (err != OK) {
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;
}
@@ -1162,14 +1243,16 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b
f = FileAccess::open(p_path, FileAccess::WRITE);
if (f.is_null()) {
DirAccess::remove_file_or_error(tmppath);
- ERR_FAIL_V(ERR_CANT_CREATE);
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Save PCK"), vformat(TTR("Can't open file to read from path \"%s\"."), tmppath));
+ return ERR_CANT_CREATE;
}
} else {
// Append to executable
f = FileAccess::open(p_path, FileAccess::READ_WRITE);
if (f.is_null()) {
DirAccess::remove_file_or_error(tmppath);
- ERR_FAIL_V(ERR_FILE_CANT_OPEN);
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Save PCK"), vformat(TTR("Can't open executable file from path \"%s\"."), tmppath));
+ return ERR_FILE_CANT_OPEN;
}
f->seek_end();
@@ -1245,10 +1328,16 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b
}
}
fae.instantiate();
- ERR_FAIL_COND_V(fae.is_null(), ERR_SKIP);
+ if (fae.is_null()) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Save PCK"), TTR("Can't create encrypted file."));
+ return ERR_CANT_CREATE;
+ }
err = fae->open_and_parse(f, key, FileAccessEncrypted::MODE_WRITE_AES256, false);
- ERR_FAIL_COND_V(err != OK, ERR_SKIP);
+ if (err != OK) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Save PCK"), TTR("Can't open encrypted file to write."));
+ return ERR_CANT_CREATE;
+ }
fhead = fae;
}
@@ -1293,7 +1382,8 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b
ftmp = FileAccess::open(tmppath, FileAccess::READ);
if (ftmp.is_null()) {
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;
@@ -1344,7 +1434,7 @@ Error EditorExportPlatform::save_zip(const Ref<EditorExportPreset> &p_preset, bo
Error err = export_project_files(p_preset, p_debug, _save_zip_file, &zd);
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);
@@ -1835,6 +1925,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) {
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;
}
@@ -1850,13 +1941,16 @@ Error EditorExportPlatformPC::prepare_template(const Ref<EditorExportPreset> &p_
}
if (!template_path.is_empty() && !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;
}
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
da->make_dir_recursive(p_path.get_base_dir());
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;
}
@@ -1876,7 +1970,7 @@ Error EditorExportPlatformPC::export_project_data(const Ref<EditorExportPreset>
Error err = save_pack(p_preset, p_debug, 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 (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;
}
diff --git a/editor/editor_export.h b/editor/editor_export.h
index daf6d8ef23..6f41736d2d 100644
--- a/editor/editor_export.h
+++ b/editor/editor_export.h
@@ -33,6 +33,7 @@
#include "core/io/dir_access.h"
#include "core/io/resource.h"
+#include "scene/gui/rich_text_label.h"
#include "scene/main/node.h"
#include "scene/main/timer.h"
#include "scene/resources/texture.h"
@@ -170,6 +171,19 @@ public:
typedef Error (*EditorExportSaveFunction)(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
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:
struct SavedData {
uint64_t ofs = 0;
@@ -200,6 +214,8 @@ private:
Vector<String> features_pv;
};
+ Vector<ExportMessage> messages;
+
void _export_find_resources(EditorFileSystemDirectory *p_dir, HashSet<String> &p_paths);
void _export_find_dependencies(const String &p_path, HashSet<String> &p_paths);
@@ -240,6 +256,47 @@ public:
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 bool should_update_export_options() { return false; }
virtual bool get_export_option_visibility(const String &p_option, const HashMap<StringName, Variant> &p_options) const { return true; }
@@ -459,7 +516,7 @@ public:
int get_chmod_flags() const;
void set_chmod_flags(int p_flags);
- virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) const {
+ virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) {
return Error::OK;
}
};
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index e23c36c1d4..61f8ab1936 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -968,21 +968,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 = missing_templates ? ERR_FILE_NOT_FOUND : ERR_UNCONFIGURED;
} else {
+ platform->clear_messages();
err = platform->export_project(export_preset, export_defer.debug, export_path);
}
}
- switch (err) {
- case OK:
- break;
- case ERR_FILE_NOT_FOUND:
- export_error = vformat("Project export failed for preset \"%s\". The export template appears to be missing.", preset_name);
- break;
- case ERR_FILE_BAD_PATH:
- export_error = vformat("Project export failed for preset \"%s\". The target path \"%s\" appears to be invalid.", preset_name, export_path);
- break;
- default:
- export_error = vformat("Project export failed with error code %d for preset \"%s\".", (int)err, preset_name);
- break;
+ if (err != OK) {
+ export_error = vformat("Project export for preset \"%s\" failed.", preset_name);
+ } else if (platform->get_worst_message_type() >= EditorExportPlatform::EXPORT_MESSAGE_WARNING) {
+ export_error = vformat("Project export for preset \"%s\" completed with errors.", preset_name);
}
}
}
diff --git a/editor/editor_run_native.cpp b/editor/editor_run_native.cpp
index 5db7b8673f..6ce9e5fa6f 100644
--- a/editor/editor_run_native.cpp
+++ b/editor/editor_run_native.cpp
@@ -151,7 +151,13 @@ Error EditorRunNative::run_native(int p_idx, int p_platform) {
flags |= EditorExportPlatform::DEBUG_FLAG_VIEW_NAVIGATION;
}
- return 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);
+ }
+ return err;
}
void EditorRunNative::resume_run_native() {
@@ -167,6 +173,15 @@ bool EditorRunNative::is_deploy_debug_remote_enabled() const {
}
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);
resume_idx = 0;
resume_platform = 0;
diff --git a/editor/editor_run_native.h b/editor/editor_run_native.h
index 798a0371a4..66d9b0402a 100644
--- a/editor/editor_run_native.h
+++ b/editor/editor_run_native.h
@@ -32,11 +32,16 @@
#define EDITOR_RUN_NATIVE_H
#include "scene/gui/box_container.h"
+#include "scene/gui/dialogs.h"
#include "scene/gui/menu_button.h"
+#include "scene/gui/rich_text_label.h"
class EditorRunNative : public HBoxContainer {
GDCLASS(EditorRunNative, HBoxContainer);
+ RichTextLabel *result_dialog_log = nullptr;
+ AcceptDialog *result_dialog = nullptr;
+
HashMap<int, MenuButton *> menus;
bool first = true;
diff --git a/editor/project_export.cpp b/editor/project_export.cpp
index 70627d5e82..b77ab179fb 100644
--- a/editor/project_export.cpp
+++ b/editor/project_export.cpp
@@ -928,17 +928,13 @@ void ProjectExportDialog::_export_project_to_path(const String &p_path) {
ERR_FAIL_COND(platform.is_null());
current->set_export_path(p_path);
+ platform->clear_messages();
Error err = platform->export_project(current, export_debug->is_pressed(), p_path, 0);
- if (err != OK && err != ERR_SKIP) {
- 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()));
+ result_dialog_log->clear();
+ if (err != ERR_SKIP) {
+ if (platform->fill_log_messages(result_dialog_log, err)) {
+ result_dialog->popup_centered_ratio(0.5);
}
-
- ERR_PRINT(vformat("Failed to export the project for platform '%s'.", platform->get_name()));
- error_dialog->show();
- error_dialog->popup_centered(Size2(300, 80));
}
}
@@ -957,6 +953,8 @@ void ProjectExportDialog::_export_all(bool p_debug) {
String mode = p_debug ? TTR("Debug") : TTR("Release");
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++) {
Ref<EditorExportPreset> preset = EditorExport::get_singleton()->get_export_preset(i);
ERR_FAIL_COND(preset.is_null());
@@ -965,17 +963,16 @@ void ProjectExportDialog::_export_all(bool p_debug) {
ep.step(preset->get_name(), i);
+ platform->clear_messages();
Error err = platform->export_project(preset, p_debug, preset->get_export_path(), 0);
- if (err != OK && err != ERR_SKIP) {
- if (err == ERR_FILE_BAD_PATH) {
- 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(Size2(300, 80));
- ERR_PRINT("Failed to export project");
+ if (err == ERR_SKIP) {
+ return;
}
+ 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);
}
}
@@ -1248,11 +1245,14 @@ ProjectExportDialog::ProjectExportDialog() {
export_error2->add_theme_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("error_color"), SNAME("Editor")));
export_error2->set_text(String::utf8("• ") + TTR("Export templates for this platform are missing:") + " ");
- error_dialog = memnew(AcceptDialog);
- error_dialog->set_title(TTR("Error"));
- error_dialog->set_text(TTR("Export templates for this platform are missing/corrupted:") + " ");
- main_vb->add_child(error_dialog);
- error_dialog->hide();
+ result_dialog = memnew(AcceptDialog);
+ result_dialog->set_title(TTR("Project Export"));
+ result_dialog_log = memnew(RichTextLabel);
+ result_dialog_log->set_custom_minimum_size(Size2(300, 80) * EDSCALE);
+ result_dialog->add_child(result_dialog_log);
+
+ main_vb->add_child(result_dialog);
+ result_dialog->hide();
LinkButton *download_templates = memnew(LinkButton);
download_templates->set_text(TTR("Manage Export Templates"));
diff --git a/editor/project_export.h b/editor/project_export.h
index 4d1719d6eb..6b10642495 100644
--- a/editor/project_export.h
+++ b/editor/project_export.h
@@ -73,7 +73,8 @@ private:
Button *button_export = nullptr;
bool updating = false;
- AcceptDialog *error_dialog = nullptr;
+ RichTextLabel *result_dialog_log = nullptr;
+ AcceptDialog *result_dialog = nullptr;
ConfirmationDialog *delete_confirm = nullptr;
OptionButton *export_filter = nullptr;
diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp
index bd2c72f64d..84dd731195 100644
--- a/modules/gridmap/grid_map.cpp
+++ b/modules/gridmap/grid_map.cpp
@@ -433,6 +433,18 @@ void GridMap::_octant_transform(const OctantKey &p_key) {
RS::get_singleton()->instance_set_transform(g.collision_debug_instance, get_global_transform());
}
+ // update transform for NavigationServer regions and navigation debugmesh instances
+ for (const KeyValue<IndexKey, Octant::NavMesh> &E : g.navmesh_ids) {
+ if (bake_navigation) {
+ if (E.value.region.is_valid()) {
+ NavigationServer3D::get_singleton()->region_set_transform(E.value.region, get_global_transform() * E.value.xform);
+ }
+ if (E.value.navmesh_debug_instance.is_valid()) {
+ RS::get_singleton()->instance_set_transform(E.value.navmesh_debug_instance, get_global_transform() * E.value.xform);
+ }
+ }
+ }
+
for (int i = 0; i < g.multimesh_instances.size(); i++) {
RS::get_singleton()->instance_set_transform(g.multimesh_instances[i].instance, get_global_transform());
}
@@ -456,6 +468,9 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
//erase navigation
for (const KeyValue<IndexKey, Octant::NavMesh> &E : g.navmesh_ids) {
NavigationServer3D::get_singleton()->free(E.value.region);
+ if (E.value.navmesh_debug_instance.is_valid()) {
+ RS::get_singleton()->free(E.value.navmesh_debug_instance);
+ }
}
g.navmesh_ids.clear();
@@ -538,6 +553,21 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
NavigationServer3D::get_singleton()->region_set_transform(region, get_global_transform() * nm.xform);
NavigationServer3D::get_singleton()->region_set_map(region, get_world_3d()->get_navigation_map());
nm.region = region;
+
+ // add navigation debugmesh visual instances if debug is enabled
+ SceneTree *st = SceneTree::get_singleton();
+ if (st && st->is_debugging_navigation_hint()) {
+ if (!nm.navmesh_debug_instance.is_valid()) {
+ RID navmesh_debug_rid = navmesh->get_debug_mesh()->get_rid();
+ nm.navmesh_debug_instance = RS::get_singleton()->instance_create();
+ RS::get_singleton()->instance_set_base(nm.navmesh_debug_instance, navmesh_debug_rid);
+ RS::get_singleton()->mesh_surface_set_material(navmesh_debug_rid, 0, st->get_debug_navigation_material()->get_rid());
+ }
+ if (is_inside_tree()) {
+ RS::get_singleton()->instance_set_scenario(nm.navmesh_debug_instance, get_world_3d()->get_scenario());
+ RS::get_singleton()->instance_set_transform(nm.navmesh_debug_instance, get_global_transform() * nm.xform);
+ }
+ }
}
g.navmesh_ids[E] = nm;
@@ -660,6 +690,10 @@ void GridMap::_octant_exit_world(const OctantKey &p_key) {
NavigationServer3D::get_singleton()->free(F.value.region);
F.value.region = RID();
}
+ if (F.value.navmesh_debug_instance.is_valid()) {
+ RS::get_singleton()->free(F.value.navmesh_debug_instance);
+ F.value.navmesh_debug_instance = RID();
+ }
}
}
@@ -678,7 +712,12 @@ void GridMap::_octant_clean_up(const OctantKey &p_key) {
// Erase navigation
for (const KeyValue<IndexKey, Octant::NavMesh> &E : g.navmesh_ids) {
- NavigationServer3D::get_singleton()->free(E.value.region);
+ if (E.value.region.is_valid()) {
+ NavigationServer3D::get_singleton()->free(E.value.region);
+ }
+ if (E.value.navmesh_debug_instance.is_valid()) {
+ RS::get_singleton()->free(E.value.navmesh_debug_instance);
+ }
}
g.navmesh_ids.clear();
diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h
index d0872a839b..c79557afea 100644
--- a/modules/gridmap/grid_map.h
+++ b/modules/gridmap/grid_map.h
@@ -98,6 +98,7 @@ class GridMap : public Node3D {
struct NavMesh {
RID region;
Transform3D xform;
+ RID navmesh_debug_instance;
};
struct MultimeshInstance {
diff --git a/modules/navigation/godot_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp
index cc9d05da47..f4e719b0c1 100644
--- a/modules/navigation/godot_navigation_server.cpp
+++ b/modules/navigation/godot_navigation_server.cpp
@@ -309,6 +309,36 @@ COMMAND_2(region_set_transform, RID, p_region, Transform3D, p_transform) {
region->set_transform(p_transform);
}
+COMMAND_2(region_set_enter_cost, RID, p_region, real_t, p_enter_cost) {
+ NavRegion *region = region_owner.get_or_null(p_region);
+ ERR_FAIL_COND(region == nullptr);
+ ERR_FAIL_COND(p_enter_cost < 0.0);
+
+ region->set_enter_cost(p_enter_cost);
+}
+
+real_t GodotNavigationServer::region_get_enter_cost(RID p_region) const {
+ NavRegion *region = region_owner.get_or_null(p_region);
+ ERR_FAIL_COND_V(region == nullptr, 0);
+
+ return region->get_enter_cost();
+}
+
+COMMAND_2(region_set_travel_cost, RID, p_region, real_t, p_travel_cost) {
+ NavRegion *region = region_owner.get_or_null(p_region);
+ ERR_FAIL_COND(region == nullptr);
+ ERR_FAIL_COND(p_travel_cost < 0.0);
+
+ region->set_travel_cost(p_travel_cost);
+}
+
+real_t GodotNavigationServer::region_get_travel_cost(RID p_region) const {
+ NavRegion *region = region_owner.get_or_null(p_region);
+ ERR_FAIL_COND_V(region == nullptr, 0);
+
+ return region->get_travel_cost();
+}
+
COMMAND_2(region_set_layers, RID, p_region, uint32_t, p_layers) {
NavRegion *region = region_owner.get_or_null(p_region);
ERR_FAIL_COND(region == nullptr);
diff --git a/modules/navigation/godot_navigation_server.h b/modules/navigation/godot_navigation_server.h
index 89e7311e51..1a7fddb7e6 100644
--- a/modules/navigation/godot_navigation_server.h
+++ b/modules/navigation/godot_navigation_server.h
@@ -109,6 +109,12 @@ public:
virtual Array map_get_agents(RID p_map) const override;
virtual RID region_create() const override;
+
+ COMMAND_2(region_set_enter_cost, RID, p_region, real_t, p_enter_cost);
+ virtual real_t region_get_enter_cost(RID p_region) const override;
+ COMMAND_2(region_set_travel_cost, RID, p_region, real_t, p_travel_cost);
+ virtual real_t region_get_travel_cost(RID p_region) const override;
+
COMMAND_2(region_set_map, RID, p_region, RID, p_map);
virtual RID region_get_map(RID p_region) const override;
COMMAND_2(region_set_layers, RID, p_region, uint32_t, p_layers);
diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp
index 344475fb37..059dc989a8 100644
--- a/modules/navigation/nav_map.cpp
+++ b/modules/navigation/nav_map.cpp
@@ -140,6 +140,8 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
float reachable_d = 1e30;
bool is_reachable = true;
+ gd::NavigationPoly *prev_least_cost_poly = nullptr;
+
while (true) {
// Takes the current least_cost_poly neighbors (iterating over its edges) and compute the traveled_distance.
for (size_t i = 0; i < navigation_polys[least_cost_id].poly->edges.size(); i++) {
@@ -156,9 +158,17 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
continue;
}
+ float region_enter_cost = 0.0;
+ float region_travel_cost = least_cost_poly->poly->owner->get_travel_cost();
+
+ if (prev_least_cost_poly != nullptr && !(prev_least_cost_poly->poly->owner->get_self() == least_cost_poly->poly->owner->get_self())) {
+ region_enter_cost = least_cost_poly->poly->owner->get_enter_cost();
+ }
+ prev_least_cost_poly = least_cost_poly;
+
Vector3 pathway[2] = { connection.pathway_start, connection.pathway_end };
const Vector3 new_entry = Geometry3D::get_closest_point_to_segment(least_cost_poly->entry, pathway);
- const float new_distance = least_cost_poly->entry.distance_to(new_entry) + least_cost_poly->traveled_distance;
+ const float new_distance = (least_cost_poly->entry.distance_to(new_entry) * region_travel_cost) + region_enter_cost + least_cost_poly->traveled_distance;
const std::vector<gd::NavigationPoly>::iterator it = std::find(
navigation_polys.begin(),
@@ -238,7 +248,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
for (List<uint32_t>::Element *element = to_visit.front(); element != nullptr; element = element->next()) {
gd::NavigationPoly *np = &navigation_polys[element->get()];
float cost = np->traveled_distance;
- cost += np->entry.distance_to(end_point);
+ cost += (np->entry.distance_to(end_point) * np->poly->owner->get_travel_cost());
if (cost < least_cost) {
least_cost_id = np->self_id;
least_cost = cost;
@@ -249,7 +259,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
// Stores the further reachable end polygon, in case our goal is not reachable.
if (is_reachable) {
- float d = navigation_polys[least_cost_id].entry.distance_to(p_destination);
+ float d = navigation_polys[least_cost_id].entry.distance_to(p_destination) * navigation_polys[least_cost_id].poly->owner->get_travel_cost();
if (reachable_d > d) {
reachable_d = d;
reachable_end = navigation_polys[least_cost_id].poly;
diff --git a/modules/navigation/nav_map.h b/modules/navigation/nav_map.h
index f58a78d4ca..20115dd1b4 100644
--- a/modules/navigation/nav_map.h
+++ b/modules/navigation/nav_map.h
@@ -50,10 +50,10 @@ class NavMap : public NavRid {
/// To find the polygons edges the vertices are displaced in a grid where
/// each cell has the following cell_size.
- real_t cell_size = 0.3;
+ real_t cell_size = 0.25;
/// This value is used to detect the near edges to connect.
- real_t edge_connection_margin = 5.0;
+ real_t edge_connection_margin = 0.25;
bool regenerate_polygons = true;
bool regenerate_links = true;
diff --git a/modules/navigation/nav_region.h b/modules/navigation/nav_region.h
index 7a6da281c0..acde5de834 100644
--- a/modules/navigation/nav_region.h
+++ b/modules/navigation/nav_region.h
@@ -46,6 +46,8 @@ class NavRegion : public NavRid {
Transform3D transform;
Ref<NavigationMesh> mesh;
uint32_t layers = 1;
+ float enter_cost = 0.0;
+ float travel_cost = 1.0;
Vector<gd::Edge::Connection> connections;
bool polygons_dirty = true;
@@ -65,6 +67,12 @@ public:
return map;
}
+ void set_enter_cost(float p_enter_cost) { enter_cost = MAX(p_enter_cost, 0.0); }
+ float get_enter_cost() const { return enter_cost; }
+
+ void set_travel_cost(float p_travel_cost) { travel_cost = MAX(p_travel_cost, 0.0); }
+ float get_travel_cost() const { return travel_cost; }
+
void set_layers(uint32_t p_layers);
uint32_t get_layers() const;
diff --git a/modules/navigation/navigation_mesh_generator.cpp b/modules/navigation/navigation_mesh_generator.cpp
index 1bc7cd7cdc..e430f5fd59 100644
--- a/modules/navigation/navigation_mesh_generator.cpp
+++ b/modules/navigation/navigation_mesh_generator.cpp
@@ -450,6 +450,31 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh(
cfg.detailSampleDist = MAX(p_nav_mesh->get_cell_size() * p_nav_mesh->get_detail_sample_distance(), 0.1f);
cfg.detailSampleMaxError = p_nav_mesh->get_cell_height() * p_nav_mesh->get_detail_sample_max_error();
+ if (!Math::is_equal_approx((float)cfg.walkableHeight * cfg.ch, p_nav_mesh->get_agent_height())) {
+ WARN_PRINT("Property agent_height is ceiled to cell_height voxel units and loses precision.");
+ }
+ if (!Math::is_equal_approx((float)cfg.walkableClimb * cfg.ch, p_nav_mesh->get_agent_max_climb())) {
+ WARN_PRINT("Property agent_max_climb is floored to cell_height voxel units and loses precision.");
+ }
+ if (!Math::is_equal_approx((float)cfg.walkableRadius * cfg.cs, p_nav_mesh->get_agent_radius())) {
+ WARN_PRINT("Property agent_radius is ceiled to cell_size voxel units and loses precision.");
+ }
+ if (!Math::is_equal_approx((float)cfg.maxEdgeLen * cfg.cs, p_nav_mesh->get_edge_max_length())) {
+ WARN_PRINT("Property edge_max_length is rounded to cell_size voxel units and loses precision.");
+ }
+ if (!Math::is_equal_approx((float)cfg.minRegionArea, p_nav_mesh->get_region_min_size() * p_nav_mesh->get_region_min_size())) {
+ WARN_PRINT("Property region_min_size is converted to int and loses precision.");
+ }
+ if (!Math::is_equal_approx((float)cfg.mergeRegionArea, p_nav_mesh->get_region_merge_size() * p_nav_mesh->get_region_merge_size())) {
+ WARN_PRINT("Property region_merge_size is converted to int and loses precision.");
+ }
+ if (!Math::is_equal_approx((float)cfg.maxVertsPerPoly, p_nav_mesh->get_verts_per_poly())) {
+ WARN_PRINT("Property verts_per_poly is converted to int and loses precision.");
+ }
+ if (p_nav_mesh->get_cell_size() * p_nav_mesh->get_detail_sample_distance() < 0.1f) {
+ WARN_PRINT("Property detail_sample_distance is clamped to 0.1 world units as the resulting value from multiplying with cell_size is too low.");
+ }
+
cfg.bmin[0] = bmin[0];
cfg.bmin[1] = bmin[1];
cfg.bmin[2] = bmin[2];
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index c692f10fd1..73c6fcc7e8 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -1818,7 +1818,7 @@ Error EditorExportPlatformAndroid::run(const Ref<EditorExportPreset> &p_preset,
String can_export_error;
bool 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;
}
@@ -1897,7 +1897,7 @@ Error EditorExportPlatformAndroid::run(const Ref<EditorExportPreset> &p_preset,
err = OS::get_singleton()->execute(adb, args, &output, &rv, true);
print_verbose(output);
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);
}
@@ -1975,7 +1975,7 @@ Error EditorExportPlatformAndroid::run(const Ref<EditorExportPreset> &p_preset,
err = OS::get_singleton()->execute(adb, args, &output, &rv, true);
print_verbose(output);
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);
}
@@ -2030,7 +2030,7 @@ String EditorExportPlatformAndroid::get_apksigner_path() {
da->list_dir_end();
if (apksigner_path.is_empty()) {
- EditorNode::get_singleton()->show_warning(TTR("Unable to find the 'apksigner' tool."));
+ print_error("Unable to find the 'apksigner' tool.");
}
return apksigner_path;
@@ -2335,7 +2335,7 @@ Error EditorExportPlatformAndroid::sign_apk(const Ref<EditorExportPreset> &p_pre
String apksigner = get_apksigner_path();
print_verbose("Starting signing of the " + export_label + " binary using " + 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;
}
@@ -2368,7 +2368,7 @@ Error EditorExportPlatformAndroid::sign_apk(const Ref<EditorExportPreset> &p_pre
}
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;
}
@@ -2389,10 +2389,14 @@ Error EditorExportPlatformAndroid::sign_apk(const Ref<EditorExportPreset> &p_pre
}
int retval;
output.clear();
- OS::get_singleton()->execute(apksigner, args, &output, &retval, true);
+ Error err = OS::get_singleton()->execute(apksigner, args, &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);
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;
}
@@ -2409,10 +2413,14 @@ Error EditorExportPlatformAndroid::sign_apk(const Ref<EditorExportPreset> &p_pre
}
output.clear();
- OS::get_singleton()->execute(apksigner, args, &output, &retval, true);
+ err = OS::get_singleton()->execute(apksigner, args, &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);
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;
}
@@ -2520,22 +2528,21 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
if (export_format == EXPORT_FORMAT_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;
}
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;
}
}
if (export_format == EXPORT_FORMAT_APK && !p_path.ends_with(".apk")) {
- EditorNode::get_singleton()->show_warning(
- TTR("Invalid filename! Android APK requires the *.apk extension."));
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Invalid filename! Android APK requires the *.apk extension."));
return ERR_UNCONFIGURED;
}
if (export_format > EXPORT_FORMAT_AAB || export_format < EXPORT_FORMAT_APK) {
- EditorNode::add_io_error(TTR("Unsupported export format!\n"));
- return ERR_UNCONFIGURED; //TODO: is this the right error?
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Unsupported export format!"));
+ return ERR_UNCONFIGURED;
}
if (use_custom_build) {
@@ -2545,13 +2552,13 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
print_verbose("Checking build version..");
Ref<FileAccess> f = FileAccess::open("res://android/.build_version", FileAccess::READ);
if (f.is_null()) {
- 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;
}
String version = f->get_line().strip_edges();
print_verbose("- build version: " + version);
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;
}
}
@@ -2564,7 +2571,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
String project_name = get_project_name(p_preset->get("package/name"));
err = _create_project_name_strings_files(p_preset, project_name); //project name localization.
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.
_copy_icons_to_gradle_project(p_preset, processed_splash_config_xml, splash_image, splash_bg_color_image, main_image, foreground, background);
@@ -2581,7 +2588,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
user_data.debug = p_debug;
err = export_project_files(p_preset, p_debug, rename_and_store_file_in_gradle_project, &user_data, copy_gradle_so);
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;
}
if (user_data.libs.size() > 0) {
@@ -2593,7 +2600,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
print_verbose("Saving apk expansion file..");
err = save_apk_expansion_file(p_preset, p_debug, p_path);
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;
}
}
@@ -2678,7 +2685,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
debug_keystore = OS::get_singleton()->get_resource_dir().plus_file(debug_keystore).simplify_path();
}
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;
}
@@ -2694,7 +2701,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
release_keystore = OS::get_singleton()->get_resource_dir().plus_file(release_keystore).simplify_path();
}
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;
}
@@ -2706,7 +2713,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);
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;
}
@@ -2736,7 +2743,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(" ")));
int copy_result = EditorNode::get_singleton()->execute_and_show_output(TTR("Moving output"), build_command, copy_args);
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;
}
@@ -2758,7 +2765,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
src_apk = find_export_template("android_release.apk");
}
if (src_apk.is_empty()) {
- 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;
}
}
@@ -2776,7 +2783,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
unzFile pkg = unzOpen2(src_apk.utf8().get_data(), &io);
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;
}
@@ -2907,7 +2914,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
if (!invalid_abis.is_empty()) {
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);
}
@@ -2925,7 +2932,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
if (apk_expansion) {
err = save_apk_expansion_file(p_preset, p_debug, p_path);
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;
}
} else {
@@ -2938,7 +2945,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
if (err != OK) {
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);
}
@@ -2974,7 +2981,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
unzFile tmp_unaligned = unzOpen2(tmp_unaligned_path.utf8().get_data(), &io);
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);
}
diff --git a/platform/iphone/export/export_plugin.cpp b/platform/iphone/export/export_plugin.cpp
index 1f5e378098..4cf1c279eb 100644
--- a/platform/iphone/export/export_plugin.cpp
+++ b/platform/iphone/export/export_plugin.cpp
@@ -817,7 +817,11 @@ Error EditorExportPlatformIOS::_codesign(String p_file, void *p_userdata) {
codesign_args.push_back("-s");
codesign_args.push_back(sign_id);
codesign_args.push_back(p_file);
- return OS::get_singleton()->execute("codesign", codesign_args);
+ String str;
+ Error err = OS::get_singleton()->execute("codesign", codesign_args, &str, nullptr, true);
+ print_verbose("codesign (" + p_file + "):\n" + str);
+
+ return err;
}
return OK;
}
@@ -1392,7 +1396,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
String err;
src_pkg_name = find_export_template("iphone.zip", &err);
if (src_pkg_name.is_empty()) {
- EditorNode::add_io_error(err);
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Templates"), TTR("Export template not found."));
return ERR_FILE_NOT_FOUND;
}
}
@@ -1487,7 +1491,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
zlib_filefunc_def io = zipio_create_io(&io_fa);
unzFile src_pkg_zip = unzOpen2(src_pkg_name.utf8().get_data(), &io);
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;
}
diff --git a/platform/javascript/export/export_plugin.cpp b/platform/javascript/export/export_plugin.cpp
index 3334e7394b..128834c90f 100644
--- a/platform/javascript/export/export_plugin.cpp
+++ b/platform/javascript/export/export_plugin.cpp
@@ -38,12 +38,12 @@ Error EditorExportPlatformJavaScript::_extract_template(const String &p_template
unzFile pkg = unzOpen2(p_template.utf8().get_data(), &io);
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;
}
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);
return ERR_FILE_CORRUPT;
}
@@ -56,6 +56,11 @@ Error EditorExportPlatformJavaScript::_extract_template(const String &p_template
String file = String::utf8(fname);
+ // Skip folders.
+ if (file.ends_with("/")) {
+ continue;
+ }
+
// Skip service worker and offline page if not exporting pwa.
if (!pwa && (file == "godot.service.worker.js" || file == "godot.offline.html")) {
continue;
@@ -72,7 +77,7 @@ Error EditorExportPlatformJavaScript::_extract_template(const String &p_template
String dst = p_dir.plus_file(file.replace("godot", p_name));
Ref<FileAccess> f = FileAccess::open(dst, FileAccess::WRITE);
if (f.is_null()) {
- 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);
return ERR_FILE_CANT_WRITE;
}
@@ -86,7 +91,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) {
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE);
if (f.is_null()) {
- 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;
}
f->store_buffer(p_content, p_size);
@@ -163,7 +168,7 @@ Error EditorExportPlatformJavaScript::_add_manifest_icon(const String &p_path, c
icon.instantiate();
const Error err = ImageLoader::load_image(p_icon, icon);
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;
}
if (icon->get_width() != p_size || icon->get_height() != p_size) {
@@ -175,7 +180,7 @@ Error EditorExportPlatformJavaScript::_add_manifest_icon(const String &p_path, c
}
const Error err = icon->save_png(icon_dest);
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;
}
Dictionary icon_dict;
@@ -233,7 +238,7 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> &
{
Ref<FileAccess> f = FileAccess::open(sw_path, FileAccess::READ);
if (f.is_null()) {
- 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;
}
sw.resize(f->get_length());
@@ -252,7 +257,7 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> &
const String offline_dest = dir.plus_file(name + ".offline.html");
err = da->copy(ProjectSettings::get_singleton()->globalize_path(offline_page), offline_dest);
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;
}
}
@@ -438,7 +443,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
}
if (!template_path.is_empty() && !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;
}
@@ -447,7 +452,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
String pck_path = base_path + ".pck";
Error error = save_pack(p_preset, p_debug, pck_path, &shared_objects);
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;
}
@@ -457,7 +462,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
String dst = base_dir.plus_file(shared_objects[i].path.get_file());
error = da->copy(shared_objects[i].path, dst);
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()));
return error;
}
}
@@ -485,7 +490,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
Vector<uint8_t> html;
f = FileAccess::open(html_path, FileAccess::READ);
if (f.is_null()) {
- 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;
}
html.resize(f->get_length());
@@ -503,7 +508,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
Ref<Image> splash = _get_project_splash();
const String splash_png_path = base_path + ".png";
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;
}
@@ -513,13 +518,13 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
Ref<Image> favicon = _get_project_icon();
const String favicon_png_path = base_path + ".icon.png";
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;
}
favicon->resize(180, 180);
const String apple_icon_png_path = base_path + ".apple-touch-icon.png";
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;
}
}
@@ -579,10 +584,11 @@ Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_prese
if (!da->dir_exists(dest)) {
Error err = da->make_dir_recursive(dest);
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;
}
}
+
const String basepath = dest.plus_file("tmp_js_export");
Error err = export_project(p_preset, true, basepath + ".html", p_debug_flags);
if (err != OK) {
@@ -625,7 +631,7 @@ Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_prese
err = server->listen(bind_port, bind_ip, use_ssl, ssl_key, ssl_cert);
}
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;
}
diff --git a/platform/linuxbsd/export/export_plugin.cpp b/platform/linuxbsd/export/export_plugin.cpp
index 9f7fab6ee8..4e14920e79 100644
--- a/platform/linuxbsd/export/export_plugin.cpp
+++ b/platform/linuxbsd/export/export_plugin.cpp
@@ -35,7 +35,10 @@
Error EditorExportPlatformLinuxBSD::_export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path) {
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE);
- ERR_FAIL_COND_V(f.is_null(), ERR_CANT_CREATE);
+ if (f.is_null()) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Debug Script Export"), vformat(TTR("Could not open file \"%s\"."), p_path));
+ return ERR_CANT_CREATE;
+ }
f->store_line("#!/bin/sh");
f->store_line("echo -ne '\\033c\\033]0;" + p_app_name + "\\a'");
@@ -67,6 +70,9 @@ Error EditorExportPlatformLinuxBSD::export_project(const Ref<EditorExportPreset>
String scr_path = p_path.get_basename() + ".sh";
err = _export_debug_script(p_preset, app_name, p_path.get_file(), scr_path);
FileAccess::set_unix_permissions(scr_path, 0755);
+ if (err != OK) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Debug Script Export"), TTR("Could not create console script."));
+ }
}
}
@@ -98,11 +104,12 @@ List<String> EditorExportPlatformLinuxBSD::get_binary_extensions(const Ref<Edito
return list;
}
-Error EditorExportPlatformLinuxBSD::fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) const {
+Error EditorExportPlatformLinuxBSD::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
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ_WRITE);
if (f.is_null()) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("PCK Embedding"), vformat(TTR("Failed to open executable file \"%s\"."), p_path));
return ERR_CANT_OPEN;
}
@@ -110,6 +117,7 @@ Error EditorExportPlatformLinuxBSD::fixup_embedded_pck(const String &p_path, int
{
uint32_t magic = f->get_32();
if (magic != 0x464c457f) { // 0x7F + "ELF"
+ add_message(EXPORT_MESSAGE_ERROR, TTR("PCK Embedding"), TTR("Executable file header corrupted."));
return ERR_FILE_CORRUPT;
}
}
@@ -119,7 +127,7 @@ Error EditorExportPlatformLinuxBSD::fixup_embedded_pck(const String &p_path, int
int bits = f->get_8() * 32;
if (bits == 32 && p_embedded_size >= 0x100000000) {
- 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."));
}
// Get info about the section header table
@@ -196,5 +204,9 @@ Error EditorExportPlatformLinuxBSD::fixup_embedded_pck(const String &p_path, int
memfree(strings);
- 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;
}
diff --git a/platform/linuxbsd/export/export_plugin.h b/platform/linuxbsd/export/export_plugin.h
index 9ae5cf827a..e04bcc20f9 100644
--- a/platform/linuxbsd/export/export_plugin.h
+++ b/platform/linuxbsd/export/export_plugin.h
@@ -46,7 +46,7 @@ public:
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override;
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
virtual String get_template_file_name(const String &p_target, const String &p_arch) const override;
- virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) const override;
+ virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) override;
};
#endif
diff --git a/platform/osx/export/export_plugin.cpp b/platform/osx/export/export_plugin.cpp
index 9309b9f89b..7010709123 100644
--- a/platform/osx/export/export_plugin.cpp
+++ b/platform/osx/export/export_plugin.cpp
@@ -261,7 +261,8 @@ void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_
if (f.is_null()) {
// Clean up generated file.
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();
@@ -441,18 +442,25 @@ Error EditorExportPlatformOSX::_notarize(const Ref<EditorExportPreset> &p_preset
String str;
Error err = OS::get_singleton()->execute("xcrun", args, &str, nullptr, 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);
- if (str.find("RequestUUID") == -1) {
- EditorNode::add_io_error("altool: " + str);
+ int rq_offset = str.find("RequestUUID");
+ if (rq_offset == -1) {
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Notarization"), TTR("Notarization failed."));
return FAILED;
} else {
- print_line(TTR("Note: The notarization process generally takes less than an hour. When the process is completed, you'll receive an email."));
- print_line(" " + TTR("You can check progress manually by opening a Terminal and running the following command:"));
- print_line(" \"xcrun altool --notarization-history 0 -u <your email> -p <app-specific pwd>\"");
- print_line(" " + TTR("Run the following command to staple the notarization ticket to the exported application (optional):"));
- print_line(" \"xcrun stapler staple <app path>\"");
+ int next_nl = str.find("\n", rq_offset);
+ String request_uuid = (next_nl == -1) ? str.substr(rq_offset + 14, -1) : str.substr(rq_offset + 14, next_nl - rq_offset - 14);
+ add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), vformat(TTR("Notarization request UUID: \"%s\""), request_uuid));
+ 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."));
+ 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
@@ -470,21 +478,21 @@ Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_prese
#ifdef OSX_ENABLED
if (p_preset->get("codesign/timestamp") && p_warn) {
- 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") && p_warn) {
- 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
String error_msg;
Error err = CodeSign::codesign(false, p_preset->get("codesign/replace_existing_signature"), p_path, p_ent_path, error_msg);
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;
}
#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
return OK;
} else {
@@ -493,7 +501,7 @@ Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_prese
if (p_preset->get("codesign/timestamp")) {
if (ad_hoc) {
if (p_warn) {
- 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 {
args.push_back("--timestamp");
@@ -502,7 +510,7 @@ Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_prese
if (p_preset->get("codesign/hardened_runtime")) {
if (ad_hoc) {
if (p_warn) {
- 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 {
args.push_back("--options");
@@ -540,15 +548,18 @@ Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_prese
String str;
Error err = OS::get_singleton()->execute("codesign", args, &str, nullptr, 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);
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;
}
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 OK;
@@ -593,7 +604,7 @@ Error EditorExportPlatformOSX::_code_sign_directory(const Ref<EditorExportPreset
return code_sign_error;
}
} 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;
}
@@ -611,7 +622,7 @@ Error EditorExportPlatformOSX::_copy_and_sign_files(Ref<DirAccess> &dir_access,
Error err{ OK };
if (dir_access->dir_exists(p_src_path)) {
#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
print_verbose("export framework: " + p_src_path + " -> " + p_in_app_path);
err = dir_access->make_dir_recursive(p_in_app_path);
@@ -668,14 +679,17 @@ Error EditorExportPlatformOSX::_create_dmg(const String &p_dmg_path, const Strin
String str;
Error err = OS::get_singleton()->execute("hdiutil", args, &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_verbose("hdiutil returned: " + str);
if (str.find("create failed") != -1) {
if (str.find("File exists") != -1) {
- EditorNode::add_io_error("hdiutil: " + TTR("DMG creation failed, file already exists."));
+ add_message(EXPORT_MESSAGE_ERROR, TTR("DMG Creation"), TTR("`hdiutil create` failed - file exists."));
} else {
- EditorNode::add_io_error("hdiutil: " + TTR("DMG create failed."));
+ add_message(EXPORT_MESSAGE_ERROR, TTR("DMG Creation"), TTR("`hdiutil create` failed."));
}
return FAILED;
}
@@ -685,7 +699,10 @@ Error EditorExportPlatformOSX::_create_dmg(const String &p_dmg_path, const Strin
Error EditorExportPlatformOSX::_export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path) {
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE);
- ERR_FAIL_COND_V(f.is_null(), ERR_CANT_CREATE);
+ if (f.is_null()) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Debug Script Export"), vformat(TTR("Could not open file \"%s\"."), p_path));
+ return ERR_CANT_CREATE;
+ }
f->store_line("#!/bin/sh");
f->store_line("echo -ne '\\033c\\033]0;" + p_app_name + "\\a'");
@@ -713,12 +730,13 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
String err;
src_pkg_name = find_export_template("osx.zip", &err);
if (src_pkg_name.is_empty()) {
- EditorNode::add_io_error(err);
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Templates"), TTR("Export template not found."));
return ERR_FILE_NOT_FOUND;
}
}
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;
}
@@ -731,7 +749,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
unzFile src_pkg_zip = unzOpen2(src_pkg_name.utf8().get_data(), &io);
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;
}
@@ -756,7 +774,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
} else if (p_path.ends_with("app")) {
export_format = "app";
} else {
- EditorNode::add_io_error("Invalid export format");
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Invalid export format."));
return ERR_CANT_CREATE;
}
@@ -781,13 +799,16 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
Ref<DirAccess> tmp_app_dir = DirAccess::create_for_path(tmp_base_path_name);
if (tmp_app_dir.is_null()) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not create directory: \"%s\"."), tmp_base_path_name));
err = ERR_CANT_CREATE;
}
DirAccess::remove_file_or_error(scr_path);
if (DirAccess::exists(tmp_app_path_name)) {
+ String old_dir = tmp_app_dir->get_current_dir();
if (tmp_app_dir->change_dir(tmp_app_path_name) == OK) {
tmp_app_dir->erase_contents_recursive();
+ tmp_app_dir->change_dir(old_dir);
}
}
@@ -797,21 +818,33 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
if (err == OK) {
print_verbose("Creating " + tmp_app_path_name + "/Contents/MacOS");
err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/MacOS");
+ if (err != OK) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not create directory \"%s\"."), tmp_app_path_name + "/Contents/MacOS"));
+ }
}
if (err == OK) {
print_verbose("Creating " + tmp_app_path_name + "/Contents/Frameworks");
err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/Frameworks");
+ if (err != OK) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not create directory \"%s\"."), tmp_app_path_name + "/Contents/Frameworks"));
+ }
}
if ((err == OK) && helpers.size() > 0) {
print_line("Creating " + tmp_app_path_name + "/Contents/Helpers");
err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/Helpers");
+ if (err != OK) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not create directory \"%s\"."), tmp_app_path_name + "/Contents/Helpers"));
+ }
}
if (err == OK) {
print_verbose("Creating " + tmp_app_path_name + "/Contents/Resources");
err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/Resources");
+ if (err != OK) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not create directory \"%s\"."), tmp_app_path_name + "/Contents/Resources"));
+ }
}
Dictionary appnames = ProjectSettings::get_singleton()->get("application/config/name_localized");
@@ -955,16 +988,22 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
if (((info.external_fa >> 16L) & 0120000) == 0120000) {
#ifndef UNIX_ENABLED
- WARN_PRINT(vformat("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
// Handle symlinks in the archive.
file = tmp_app_path_name.plus_file(file);
if (err == OK) {
err = tmp_app_dir->make_dir_recursive(file.get_base_dir());
+ if (err != OK) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not create directory \"%s\"."), file.get_base_dir()));
+ }
}
if (err == OK) {
String lnk_data = String::utf8((const char *)data.ptr(), data.size());
err = tmp_app_dir->create_link(lnk_data, file);
+ if (err != OK) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not created symlink \"%s\" -> \"%s\"."), lnk_data, file));
+ }
print_verbose(vformat("ADDING SYMLINK %s => %s\n", file, lnk_data));
}
@@ -1039,6 +1078,9 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
file = tmp_app_path_name.plus_file(file);
if (err == OK) {
err = tmp_app_dir->make_dir_recursive(file.get_base_dir());
+ if (err != OK) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not create directory \"%s\"."), file.get_base_dir()));
+ }
}
if (err == OK) {
Ref<FileAccess> f = FileAccess::open(file, FileAccess::WRITE);
@@ -1049,6 +1091,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
FileAccess::set_unix_permissions(file, 0755);
}
} else {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not open \"%s\"."), file));
err = ERR_CANT_CREATE;
}
}
@@ -1061,7 +1104,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
unzClose(src_pkg_zip);
if (!found_binary) {
- ERR_PRINT(vformat("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;
}
@@ -1071,6 +1114,9 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
if ((con_scr == 1 && p_debug) || (con_scr == 2)) {
err = _export_debug_script(p_preset, pkg_name, tmp_app_path_name.get_file() + "/Contents/MacOS/" + pkg_name, scr_path);
FileAccess::set_unix_permissions(scr_path, 0755);
+ if (err != OK) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Could not create console script."));
+ }
}
}
@@ -1214,6 +1260,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
ent_f->store_line("</dict>");
ent_f->store_line("</plist>");
} else {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("Could not create entitlements file."));
err = ERR_CANT_CREATE;
}
@@ -1231,6 +1278,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
ent_f->store_line("</dict>");
ent_f->store_line("</plist>");
} else {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("Could not create helper entitlements file."));
err = ERR_CANT_CREATE;
}
}
@@ -1258,7 +1306,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
ad_hoc = (sign_identity == "" || sign_identity == "-");
bool lib_validation = p_preset->get("codesign/entitlements/disable_library_validation");
if ((!dylibs_found.is_empty() || !shared_objects.is_empty()) && sign_enabled && ad_hoc && !lib_validation) {
- ERR_PRINT("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;
}
}
@@ -1342,7 +1390,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
bool noto_enabled = p_preset->get("notarization/enable");
if (err == OK && noto_enabled) {
if (export_format == "app") {
- WARN_PRINT("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 {
if (ep.step(TTR("Sending archive for notarization"), 4)) {
return ERR_SKIP;
@@ -1467,7 +1515,8 @@ void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String
Ref<FileAccess> fa = FileAccess::open(dir.plus_file(f), FileAccess::READ);
if (fa.is_null()) {
- ERR_FAIL_MSG(vformat("Can't open file to read from path \"%s\".", 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;
uint8_t buf[bufsize];
diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp
index 45281f037c..16c67345e0 100644
--- a/platform/windows/export/export_plugin.cpp
+++ b/platform/windows/export/export_plugin.cpp
@@ -43,7 +43,10 @@ Error EditorExportPlatformWindows::sign_shared_object(const Ref<EditorExportPres
Error EditorExportPlatformWindows::_export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path) {
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE);
- ERR_FAIL_COND_V(f.is_null(), ERR_CANT_CREATE);
+ if (f.is_null()) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Debug Script Export"), vformat(TTR("Could not open file \"%s\"."), p_path));
+ return ERR_CANT_CREATE;
+ }
f->store_line("@echo off");
f->store_line("title \"" + p_app_name + "\"");
@@ -55,10 +58,9 @@ Error EditorExportPlatformWindows::_export_debug_script(const Ref<EditorExportPr
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")) {
- return _rcedit_add_data(p_preset, p_path);
- } else {
- return OK;
+ _rcedit_add_data(p_preset, p_path);
}
+ return OK;
}
Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
@@ -68,12 +70,15 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset>
}
Error err = EditorExportPlatformPC::export_project(p_preset, p_debug, pck_path, p_flags);
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) {
Ref<DirAccess> tmp_dir = DirAccess::create_for_path(p_path.get_base_dir());
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));
+ }
}
String app_name;
@@ -89,7 +94,9 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset>
int con_scr = p_preset->get("debug/export_console_script");
if ((con_scr == 1 && p_debug) || (con_scr == 2)) {
String scr_path = p_path.get_basename() + ".cmd";
- err = _export_debug_script(p_preset, app_name, p_path.get_file(), scr_path);
+ if (_export_debug_script(p_preset, app_name, p_path.get_file(), scr_path) != OK) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Debug Script Export"), TTR("Could not create console script."));
+ }
}
}
@@ -142,7 +149,7 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset
String rcedit_path = EditorSettings::get_singleton()->get("export/windows/rcedit");
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;
}
@@ -155,7 +162,7 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset
String wine_path = EditorSettings::get_singleton()->get("export/windows/wine");
if (!wine_path.is_empty() && !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;
}
@@ -222,10 +229,14 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset
String str;
Error err = OS::get_singleton()->execute(rcedit_path, args, &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);
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;
}
@@ -238,7 +249,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
#ifdef WINDOWS_ENABLED
String signtool_path = EditorSettings::get_singleton()->get("export/windows/signtool");
if (!signtool_path.is_empty() && !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;
}
if (signtool_path.is_empty()) {
@@ -247,7 +258,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
#else
String signtool_path = EditorSettings::get_singleton()->get("export/windows/osslsigncode");
if (!signtool_path.is_empty() && !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;
}
if (signtool_path.is_empty()) {
@@ -267,7 +278,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
args.push_back("/f");
args.push_back(p_preset->get("codesign/identity"));
} else {
- EditorNode::add_io_error("codesign: no identity found");
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("No identity found."));
return FAILED;
}
} else if (id_type == 2) { //Windows certificate store
@@ -275,11 +286,11 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
args.push_back("/sha1");
args.push_back(p_preset->get("codesign/identity"));
} else {
- EditorNode::add_io_error("codesign: no identity found");
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("No identity found."));
return FAILED;
}
} else {
- EditorNode::add_io_error("codesign: invalid identity type");
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Invalid identity type."));
return FAILED;
}
#else
@@ -287,7 +298,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
args.push_back("-pkcs12");
args.push_back(p_preset->get("codesign/identity"));
} else {
- EditorNode::add_io_error("codesign: no identity found");
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("No identity found."));
return FAILED;
}
#endif
@@ -319,7 +330,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
args.push_back(p_preset->get("codesign/timestamp_server_url"));
#endif
} else {
- EditorNode::add_io_error("codesign: invalid timestamp server");
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Invalid timestamp server."));
return FAILED;
}
}
@@ -366,7 +377,10 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
String str;
Error err = OS::get_singleton()->execute(signtool_path, args, &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);
#ifndef WINDOWS_ENABLED
@@ -374,6 +388,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
#else
if (str.find("Failed") != -1) {
#endif
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Signtool failed to sign executable:\n%s"), str));
return FAILED;
}
@@ -381,10 +396,16 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
Ref<DirAccess> tmp_dir = DirAccess::create_for_path(p_path.get_base_dir());
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_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
return OK;
@@ -433,15 +454,17 @@ bool EditorExportPlatformWindows::can_export(const Ref<EditorExportPreset> &p_pr
return valid;
}
-Error EditorExportPlatformWindows::fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) const {
+Error EditorExportPlatformWindows::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
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;
}
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ_WRITE);
if (f.is_null()) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("PCK Embedding"), vformat(TTR("Failed to open executable file \"%s\"."), p_path));
return ERR_CANT_OPEN;
}
@@ -453,6 +476,7 @@ Error EditorExportPlatformWindows::fixup_embedded_pck(const String &p_path, int6
f->seek(pe_pos);
uint32_t magic = f->get_32();
if (magic != 0x00004550) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("PCK Embedding"), TTR("Executable file header corrupted."));
return ERR_FILE_CORRUPT;
}
}
@@ -502,5 +526,9 @@ Error EditorExportPlatformWindows::fixup_embedded_pck(const String &p_path, int6
}
}
- 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;
}
diff --git a/platform/windows/export/export_plugin.h b/platform/windows/export/export_plugin.h
index 61184a8987..51f98365a9 100644
--- a/platform/windows/export/export_plugin.h
+++ b/platform/windows/export/export_plugin.h
@@ -51,7 +51,7 @@ public:
virtual bool get_export_option_visibility(const String &p_option, const HashMap<StringName, Variant> &p_options) const override;
virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
virtual String get_template_file_name(const String &p_target, const String &p_arch) const override;
- virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) const override;
+ virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) override;
};
#endif
diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp
index 41773d81c5..6f3222f27e 100644
--- a/scene/2d/navigation_region_2d.cpp
+++ b/scene/2d/navigation_region_2d.cpp
@@ -388,6 +388,26 @@ uint32_t NavigationRegion2D::get_layers() const {
return NavigationServer2D::get_singleton()->region_get_layers(region);
}
+void NavigationRegion2D::set_enter_cost(real_t p_enter_cost) {
+ ERR_FAIL_COND_MSG(p_enter_cost < 0.0, "The enter_cost must be positive.");
+ enter_cost = MAX(p_enter_cost, 0.0);
+ NavigationServer2D::get_singleton()->region_set_enter_cost(region, p_enter_cost);
+}
+
+real_t NavigationRegion2D::get_enter_cost() const {
+ return enter_cost;
+}
+
+void NavigationRegion2D::set_travel_cost(real_t p_travel_cost) {
+ ERR_FAIL_COND_MSG(p_travel_cost < 0.0, "The travel_cost must be positive.");
+ travel_cost = MAX(p_travel_cost, 0.0);
+ NavigationServer2D::get_singleton()->region_set_enter_cost(region, travel_cost);
+}
+
+real_t NavigationRegion2D::get_travel_cost() const {
+ return travel_cost;
+}
+
RID NavigationRegion2D::get_region_rid() const {
return region;
}
@@ -544,16 +564,26 @@ void NavigationRegion2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_region_rid"), &NavigationRegion2D::get_region_rid);
+ ClassDB::bind_method(D_METHOD("set_enter_cost", "enter_cost"), &NavigationRegion2D::set_enter_cost);
+ ClassDB::bind_method(D_METHOD("get_enter_cost"), &NavigationRegion2D::get_enter_cost);
+
+ ClassDB::bind_method(D_METHOD("set_travel_cost", "travel_cost"), &NavigationRegion2D::set_travel_cost);
+ ClassDB::bind_method(D_METHOD("get_travel_cost"), &NavigationRegion2D::get_travel_cost);
+
ClassDB::bind_method(D_METHOD("_navpoly_changed"), &NavigationRegion2D::_navpoly_changed);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navpoly", PROPERTY_HINT_RESOURCE_TYPE, "NavigationPolygon"), "set_navigation_polygon", "get_navigation_polygon");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "layers", PROPERTY_HINT_LAYERS_2D_NAVIGATION), "set_layers", "get_layers");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "enter_cost"), "set_enter_cost", "get_enter_cost");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "travel_cost"), "set_travel_cost", "get_travel_cost");
}
NavigationRegion2D::NavigationRegion2D() {
set_notify_transform(true);
region = NavigationServer2D::get_singleton()->region_create();
+ NavigationServer2D::get_singleton()->region_set_enter_cost(region, get_enter_cost());
+ NavigationServer2D::get_singleton()->region_set_travel_cost(region, get_travel_cost());
}
NavigationRegion2D::~NavigationRegion2D() {
diff --git a/scene/2d/navigation_region_2d.h b/scene/2d/navigation_region_2d.h
index 3c4a4e81d9..31574749f7 100644
--- a/scene/2d/navigation_region_2d.h
+++ b/scene/2d/navigation_region_2d.h
@@ -98,6 +98,9 @@ class NavigationRegion2D : public Node2D {
RID region;
Ref<NavigationPolygon> navpoly;
+ real_t enter_cost = 0.0;
+ real_t travel_cost = 1.0;
+
void _navpoly_changed();
void _map_changed(RID p_RID);
@@ -119,6 +122,12 @@ public:
RID get_region_rid() const;
+ void set_enter_cost(real_t p_enter_cost);
+ real_t get_enter_cost() const;
+
+ void set_travel_cost(real_t p_travel_cost);
+ real_t get_travel_cost() const;
+
void set_navigation_polygon(const Ref<NavigationPolygon> &p_navpoly);
Ref<NavigationPolygon> get_navigation_polygon() const;
diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp
index cb8da182ee..dda1382814 100644
--- a/scene/3d/navigation_region_3d.cpp
+++ b/scene/3d/navigation_region_3d.cpp
@@ -73,6 +73,26 @@ uint32_t NavigationRegion3D::get_layers() const {
return NavigationServer3D::get_singleton()->region_get_layers(region);
}
+void NavigationRegion3D::set_enter_cost(real_t p_enter_cost) {
+ ERR_FAIL_COND_MSG(p_enter_cost < 0.0, "The enter_cost must be positive.");
+ enter_cost = MAX(p_enter_cost, 0.0);
+ NavigationServer3D::get_singleton()->region_set_enter_cost(region, p_enter_cost);
+}
+
+real_t NavigationRegion3D::get_enter_cost() const {
+ return enter_cost;
+}
+
+void NavigationRegion3D::set_travel_cost(real_t p_travel_cost) {
+ ERR_FAIL_COND_MSG(p_travel_cost < 0.0, "The travel_cost must be positive.");
+ travel_cost = MAX(p_travel_cost, 0.0);
+ NavigationServer3D::get_singleton()->region_set_enter_cost(region, travel_cost);
+}
+
+real_t NavigationRegion3D::get_travel_cost() const {
+ return travel_cost;
+}
+
RID NavigationRegion3D::get_region_rid() const {
return region;
}
@@ -224,12 +244,20 @@ void NavigationRegion3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_region_rid"), &NavigationRegion3D::get_region_rid);
+ ClassDB::bind_method(D_METHOD("set_enter_cost", "enter_cost"), &NavigationRegion3D::set_enter_cost);
+ ClassDB::bind_method(D_METHOD("get_enter_cost"), &NavigationRegion3D::get_enter_cost);
+
+ ClassDB::bind_method(D_METHOD("set_travel_cost", "travel_cost"), &NavigationRegion3D::set_travel_cost);
+ ClassDB::bind_method(D_METHOD("get_travel_cost"), &NavigationRegion3D::get_travel_cost);
+
ClassDB::bind_method(D_METHOD("bake_navigation_mesh", "on_thread"), &NavigationRegion3D::bake_navigation_mesh, DEFVAL(true));
ClassDB::bind_method(D_METHOD("_bake_finished", "nav_mesh"), &NavigationRegion3D::_bake_finished);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navmesh", PROPERTY_HINT_RESOURCE_TYPE, "NavigationMesh"), "set_navigation_mesh", "get_navigation_mesh");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "layers", PROPERTY_HINT_LAYERS_3D_NAVIGATION), "set_layers", "get_layers");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "enter_cost"), "set_enter_cost", "get_enter_cost");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "travel_cost"), "set_travel_cost", "get_travel_cost");
ADD_SIGNAL(MethodInfo("navigation_mesh_changed"));
ADD_SIGNAL(MethodInfo("bake_finished"));
@@ -243,6 +271,8 @@ void NavigationRegion3D::_navigation_changed() {
NavigationRegion3D::NavigationRegion3D() {
set_notify_transform(true);
region = NavigationServer3D::get_singleton()->region_create();
+ NavigationServer3D::get_singleton()->region_set_enter_cost(region, get_enter_cost());
+ NavigationServer3D::get_singleton()->region_set_travel_cost(region, get_travel_cost());
}
NavigationRegion3D::~NavigationRegion3D() {
diff --git a/scene/3d/navigation_region_3d.h b/scene/3d/navigation_region_3d.h
index 140dfebf6a..042684c5b7 100644
--- a/scene/3d/navigation_region_3d.h
+++ b/scene/3d/navigation_region_3d.h
@@ -41,6 +41,9 @@ class NavigationRegion3D : public Node3D {
RID region;
Ref<NavigationMesh> navmesh;
+ real_t enter_cost = 0.0;
+ real_t travel_cost = 1.0;
+
Node *debug_view = nullptr;
Thread bake_thread;
@@ -59,6 +62,12 @@ public:
RID get_region_rid() const;
+ void set_enter_cost(real_t p_enter_cost);
+ real_t get_enter_cost() const;
+
+ void set_travel_cost(real_t p_travel_cost);
+ real_t get_travel_cost() const;
+
void set_navigation_mesh(const Ref<NavigationMesh> &p_navmesh);
Ref<NavigationMesh> get_navigation_mesh() const;
diff --git a/scene/resources/world_3d.cpp b/scene/resources/world_3d.cpp
index 0088236112..eb0af63975 100644
--- a/scene/resources/world_3d.cpp
+++ b/scene/resources/world_3d.cpp
@@ -150,8 +150,8 @@ World3D::World3D() {
navigation_map = NavigationServer3D::get_singleton()->map_create();
NavigationServer3D::get_singleton()->map_set_active(navigation_map, true);
- NavigationServer3D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_DEF("navigation/3d/default_cell_size", 0.3));
- NavigationServer3D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/3d/default_edge_connection_margin", 0.3));
+ NavigationServer3D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_DEF("navigation/3d/default_cell_size", 0.25));
+ NavigationServer3D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/3d/default_edge_connection_margin", 0.25));
}
World3D::~World3D() {
diff --git a/servers/navigation_server_2d.cpp b/servers/navigation_server_2d.cpp
index 901d335017..ab323e76e8 100644
--- a/servers/navigation_server_2d.cpp
+++ b/servers/navigation_server_2d.cpp
@@ -174,6 +174,10 @@ void NavigationServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("map_get_agents", "map"), &NavigationServer2D::map_get_agents);
ClassDB::bind_method(D_METHOD("region_create"), &NavigationServer2D::region_create);
+ ClassDB::bind_method(D_METHOD("region_set_enter_cost", "region", "enter_cost"), &NavigationServer2D::region_set_enter_cost);
+ ClassDB::bind_method(D_METHOD("region_get_enter_cost", "region"), &NavigationServer2D::region_get_enter_cost);
+ ClassDB::bind_method(D_METHOD("region_set_travel_cost", "region", "travel_cost"), &NavigationServer2D::region_set_travel_cost);
+ ClassDB::bind_method(D_METHOD("region_get_travel_cost", "region"), &NavigationServer2D::region_get_travel_cost);
ClassDB::bind_method(D_METHOD("region_set_map", "region", "map"), &NavigationServer2D::region_set_map);
ClassDB::bind_method(D_METHOD("region_get_map", "region"), &NavigationServer2D::region_get_map);
ClassDB::bind_method(D_METHOD("region_set_layers", "region", "layers"), &NavigationServer2D::region_set_layers);
@@ -239,6 +243,12 @@ Vector2 FORWARD_2_R_C(v3_to_v2, map_get_closest_point, RID, p_map, const Vector2
RID FORWARD_2_C(map_get_closest_point_owner, RID, p_map, const Vector2 &, p_point, rid_to_rid, v2_to_v3);
RID FORWARD_0_C(region_create);
+
+void FORWARD_2_C(region_set_enter_cost, RID, p_region, real_t, p_enter_cost, rid_to_rid, real_to_real);
+real_t FORWARD_1_C(region_get_enter_cost, RID, p_region, rid_to_rid);
+void FORWARD_2_C(region_set_travel_cost, RID, p_region, real_t, p_travel_cost, rid_to_rid, real_to_real);
+real_t FORWARD_1_C(region_get_travel_cost, RID, p_region, rid_to_rid);
+
void FORWARD_2_C(region_set_map, RID, p_region, RID, p_map, rid_to_rid, rid_to_rid);
void FORWARD_2_C(region_set_layers, RID, p_region, uint32_t, p_layers, rid_to_rid, uint32_to_uint32);
uint32_t FORWARD_1_C(region_get_layers, RID, p_region, rid_to_rid);
diff --git a/servers/navigation_server_2d.h b/servers/navigation_server_2d.h
index dfdcf5fca8..8e285147b1 100644
--- a/servers/navigation_server_2d.h
+++ b/servers/navigation_server_2d.h
@@ -86,6 +86,14 @@ public:
/// Creates a new region.
virtual RID region_create() const;
+ /// Set the enter_cost of a region
+ virtual void region_set_enter_cost(RID p_region, real_t p_enter_cost) const;
+ virtual real_t region_get_enter_cost(RID p_region) const;
+
+ /// Set the travel_cost of a region
+ virtual void region_set_travel_cost(RID p_region, real_t p_travel_cost) const;
+ virtual real_t region_get_travel_cost(RID p_region) const;
+
/// Set the map of this region.
virtual void region_set_map(RID p_region, RID p_map) const;
virtual RID region_get_map(RID p_region) const;
diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp
index 0ce869ad1a..6d99f6dfbb 100644
--- a/servers/navigation_server_3d.cpp
+++ b/servers/navigation_server_3d.cpp
@@ -52,6 +52,10 @@ void NavigationServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("map_get_agents", "map"), &NavigationServer3D::map_get_agents);
ClassDB::bind_method(D_METHOD("region_create"), &NavigationServer3D::region_create);
+ ClassDB::bind_method(D_METHOD("region_set_enter_cost", "region", "enter_cost"), &NavigationServer3D::region_set_enter_cost);
+ ClassDB::bind_method(D_METHOD("region_get_enter_cost", "region"), &NavigationServer3D::region_get_enter_cost);
+ ClassDB::bind_method(D_METHOD("region_set_travel_cost", "region", "travel_cost"), &NavigationServer3D::region_set_travel_cost);
+ ClassDB::bind_method(D_METHOD("region_get_travel_cost", "region"), &NavigationServer3D::region_get_travel_cost);
ClassDB::bind_method(D_METHOD("region_set_map", "region", "map"), &NavigationServer3D::region_set_map);
ClassDB::bind_method(D_METHOD("region_get_map", "region"), &NavigationServer3D::region_get_map);
ClassDB::bind_method(D_METHOD("region_set_layers", "region", "layers"), &NavigationServer3D::region_set_layers);
diff --git a/servers/navigation_server_3d.h b/servers/navigation_server_3d.h
index c3d3a589a9..9b7e48e8d1 100644
--- a/servers/navigation_server_3d.h
+++ b/servers/navigation_server_3d.h
@@ -97,6 +97,14 @@ public:
/// Creates a new region.
virtual RID region_create() const = 0;
+ /// Set the enter_cost of a region
+ virtual void region_set_enter_cost(RID p_region, real_t p_enter_cost) const = 0;
+ virtual real_t region_get_enter_cost(RID p_region) const = 0;
+
+ /// Set the travel_cost of a region
+ virtual void region_set_travel_cost(RID p_region, real_t p_travel_cost) const = 0;
+ virtual real_t region_get_travel_cost(RID p_region) const = 0;
+
/// Set the map of this region.
virtual void region_set_map(RID p_region, RID p_map) const = 0;
virtual RID region_get_map(RID p_region) const = 0;
diff --git a/thirdparty/README.md b/thirdparty/README.md
index 97ba4bdca4..93499d1358 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -167,6 +167,11 @@ Files extracted from upstream source:
- `include/` folder, minus the `dlg` subfolder
- `LICENSE.TXT` and `docs/FTL.TXT`
+Some changes have been made in order to prevent LTO from removing code.
+They are marked with `// -- GODOT start --` and `// -- GODOT end --`
+comments. Apply the patches in the `patches/` folder when syncing on newer upstream
+commits.
+
## glslang
diff --git a/thirdparty/freetype/patches/fix_gcc_lto_build.diff b/thirdparty/freetype/patches/fix_gcc_lto_build.diff
new file mode 100644
index 0000000000..3c22b464c2
--- /dev/null
+++ b/thirdparty/freetype/patches/fix_gcc_lto_build.diff
@@ -0,0 +1,34 @@
+diff --git a/thirdparty/freetype/src/smooth/ftgrays.c b/thirdparty/freetype/src/smooth/ftgrays.c
+index 622035aa79..5d9e1600b7 100644
+--- a/thirdparty/freetype/src/smooth/ftgrays.c
++++ b/thirdparty/freetype/src/smooth/ftgrays.c
+@@ -1907,6 +1907,9 @@ typedef ptrdiff_t FT_PtrDist;
+ 0 /* delta */
+ )
+
++// -- GODOT start --
++ static volatile int _lto_dummy = 0;
++// -- GODOT end --
+
+ static int
+ gray_convert_glyph_inner( RAS_ARG,
+@@ -1928,6 +1931,9 @@ typedef ptrdiff_t FT_PtrDist;
+ ras.max_ey,
+ ras.cell_null - ras.cell_free,
+ ras.cell_null - ras.cell_free == 1 ? "" : "s" ));
++// -- GODOT start --
++ _lto_dummy = error; // Prevents LTO from removing this branch.
++// -- GODOT end --
+ }
+ else
+ {
+@@ -1935,6 +1941,9 @@ typedef ptrdiff_t FT_PtrDist;
+
+ FT_TRACE7(( "band [%d..%d]: to be bisected\n",
+ ras.min_ey, ras.max_ey ));
++// -- GODOT start --
++ _lto_dummy = error; // Prevents LTO from removing this branch.
++// -- GODOT end --
+ }
+
+ return error;
diff --git a/thirdparty/freetype/src/smooth/ftgrays.c b/thirdparty/freetype/src/smooth/ftgrays.c
index 622035aa79..5d9e1600b7 100644
--- a/thirdparty/freetype/src/smooth/ftgrays.c
+++ b/thirdparty/freetype/src/smooth/ftgrays.c
@@ -1907,6 +1907,9 @@ typedef ptrdiff_t FT_PtrDist;
0 /* delta */
)
+// -- GODOT start --
+ static volatile int _lto_dummy = 0;
+// -- GODOT end --
static int
gray_convert_glyph_inner( RAS_ARG,
@@ -1928,6 +1931,9 @@ typedef ptrdiff_t FT_PtrDist;
ras.max_ey,
ras.cell_null - ras.cell_free,
ras.cell_null - ras.cell_free == 1 ? "" : "s" ));
+// -- GODOT start --
+ _lto_dummy = error; // Prevents LTO from removing this branch.
+// -- GODOT end --
}
else
{
@@ -1935,6 +1941,9 @@ typedef ptrdiff_t FT_PtrDist;
FT_TRACE7(( "band [%d..%d]: to be bisected\n",
ras.min_ey, ras.max_ey ));
+// -- GODOT start --
+ _lto_dummy = error; // Prevents LTO from removing this branch.
+// -- GODOT end --
}
return error;