summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/extension/gdextension.cpp13
-rw-r--r--core/extension/gdextension.h8
-rw-r--r--core/object/class_db.cpp17
-rw-r--r--core/object/class_db.h3
-rw-r--r--doc/classes/AudioStreamGeneratorPlayback.xml1
-rw-r--r--doc/classes/PopupMenu.xml2
-rw-r--r--editor/doc_tools.cpp28
-rw-r--r--editor/doc_tools.h6
-rw-r--r--editor/editor_help.cpp55
-rw-r--r--editor/editor_help.h5
-rw-r--r--editor/filesystem_dock.cpp19
-rw-r--r--editor/import/resource_importer_scene.cpp60
-rw-r--r--editor/scene_tree_dock.cpp168
-rw-r--r--main/main.cpp6
-rw-r--r--modules/csg/csg_shape.cpp4
-rw-r--r--platform/macos/export/export_plugin.cpp99
-rw-r--r--scene/2d/tile_map.cpp6
17 files changed, 239 insertions, 261 deletions
diff --git a/core/extension/gdextension.cpp b/core/extension/gdextension.cpp
index 136a5bfbb2..6c3d0a6148 100644
--- a/core/extension/gdextension.cpp
+++ b/core/extension/gdextension.cpp
@@ -915,9 +915,9 @@ Error GDExtensionResourceLoader::load_gdextension_resource(const String &p_path,
#ifdef TOOLS_ENABLED
p_extension->set_reloadable(config->get_value("configuration", "reloadable", false) && Engine::get_singleton()->is_extension_reloading_enabled());
- p_extension->update_last_modified_time(MAX(
- FileAccess::get_modified_time(library_path),
- FileAccess::get_modified_time(p_path)));
+ p_extension->update_last_modified_time(
+ FileAccess::get_modified_time(p_path),
+ FileAccess::get_modified_time(library_path));
#endif
err = p_extension->open_library(library_path, entry_symbol);
@@ -990,10 +990,13 @@ String GDExtensionResourceLoader::get_resource_type(const String &p_path) const
#ifdef TOOLS_ENABLED
bool GDExtension::has_library_changed() const {
- if (FileAccess::get_modified_time(get_path()) > last_modified_time) {
+ // Check only that the last modified time is different (rather than checking
+ // that it's newer) since some OS's (namely Windows) will preserve the modified
+ // time by default when copying files.
+ if (FileAccess::get_modified_time(get_path()) != resource_last_modified_time) {
return true;
}
- if (FileAccess::get_modified_time(library_path) > last_modified_time) {
+ if (FileAccess::get_modified_time(library_path) != library_last_modified_time) {
return true;
}
return false;
diff --git a/core/extension/gdextension.h b/core/extension/gdextension.h
index bab3bcd198..0d20b8e50c 100644
--- a/core/extension/gdextension.h
+++ b/core/extension/gdextension.h
@@ -90,7 +90,8 @@ class GDExtension : public Resource {
int32_t level_initialized = -1;
#ifdef TOOLS_ENABLED
- uint64_t last_modified_time = 0;
+ uint64_t resource_last_modified_time = 0;
+ uint64_t library_last_modified_time = 0;
bool is_reloading = false;
Vector<GDExtensionMethodBind *> invalid_methods;
Vector<ObjectID> instance_bindings;
@@ -140,8 +141,9 @@ public:
void set_reloadable(bool p_reloadable) { reloadable = p_reloadable; }
bool has_library_changed() const;
- void update_last_modified_time(uint64_t p_last_modified_time) {
- last_modified_time = MAX(last_modified_time, p_last_modified_time);
+ void update_last_modified_time(uint64_t p_resource_last_modified_time, uint64_t p_library_last_modified_time) {
+ resource_last_modified_time = p_resource_last_modified_time;
+ library_last_modified_time = p_library_last_modified_time;
}
void track_instance_binding(Object *p_object);
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp
index 8c54db3c2c..bf1bd0de93 100644
--- a/core/object/class_db.cpp
+++ b/core/object/class_db.cpp
@@ -98,9 +98,24 @@ void ClassDB::get_class_list(List<StringName> *p_classes) {
p_classes->push_back(E.key);
}
- p_classes->sort();
+ p_classes->sort_custom<StringName::AlphCompare>();
}
+#ifdef TOOLS_ENABLED
+void ClassDB::get_extensions_class_list(List<StringName> *p_classes) {
+ OBJTYPE_RLOCK;
+
+ for (const KeyValue<StringName, ClassInfo> &E : classes) {
+ if (E.value.api != API_EXTENSION && E.value.api != API_EDITOR_EXTENSION) {
+ continue;
+ }
+ p_classes->push_back(E.key);
+ }
+
+ p_classes->sort_custom<StringName::AlphCompare>();
+}
+#endif
+
void ClassDB::get_inheriters_from_class(const StringName &p_class, List<StringName> *p_classes) {
OBJTYPE_RLOCK;
diff --git a/core/object/class_db.h b/core/object/class_db.h
index 5c2c59d508..7a4ee1afa4 100644
--- a/core/object/class_db.h
+++ b/core/object/class_db.h
@@ -251,6 +251,9 @@ public:
}
static void get_class_list(List<StringName> *p_classes);
+#ifdef TOOLS_ENABLED
+ static void get_extensions_class_list(List<StringName> *p_classes);
+#endif
static void get_inheriters_from_class(const StringName &p_class, List<StringName> *p_classes);
static void get_direct_inheriters_from_class(const StringName &p_class, List<StringName> *p_classes);
static StringName get_parent_class_nocheck(const StringName &p_class);
diff --git a/doc/classes/AudioStreamGeneratorPlayback.xml b/doc/classes/AudioStreamGeneratorPlayback.xml
index 185b89d760..88c5cf6dbe 100644
--- a/doc/classes/AudioStreamGeneratorPlayback.xml
+++ b/doc/classes/AudioStreamGeneratorPlayback.xml
@@ -33,6 +33,7 @@
<method name="get_skips" qualifiers="const">
<return type="int" />
<description>
+ Returns the number of times the playback skipped due to a buffer underrun in the audio sample data. This value is reset at the start of the playback.
</description>
</method>
<method name="push_buffer">
diff --git a/doc/classes/PopupMenu.xml b/doc/classes/PopupMenu.xml
index 6293fcb309..3f4ec1b677 100644
--- a/doc/classes/PopupMenu.xml
+++ b/doc/classes/PopupMenu.xml
@@ -186,7 +186,7 @@
<param index="1" name="submenu" type="String" />
<param index="2" name="id" type="int" default="-1" />
<description>
- Adds an item that will act as a submenu of the parent [PopupMenu] node when clicked. The [param submenu] argument is the name of the child [PopupMenu] node that will be shown when the item is clicked.
+ Adds an item that will act as a submenu of the parent [PopupMenu] node when clicked. The [param submenu] argument must be the name of an existing [PopupMenu] that has been added as a child to this node. This submenu will be shown when the item is clicked, hovered for long enough, or activated using the [code]ui_select[/code] or [code]ui_right[/code] input actions.
An [param id] can optionally be provided. If no [param id] is provided, one will be created from the index.
</description>
</method>
diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp
index ef3981fd3f..a7e3c03250 100644
--- a/editor/doc_tools.cpp
+++ b/editor/doc_tools.cpp
@@ -355,20 +355,27 @@ static Variant get_documentation_default_value(const StringName &p_class_name, c
return default_value;
}
-void DocTools::generate(bool p_basic_types) {
+void DocTools::generate(BitField<GenerateFlags> p_flags) {
+ // This may involve instantiating classes that are only usable from the main thread
+ // (which is in fact the case of the core API).
+ ERR_FAIL_COND(!Thread::is_main_thread());
+
// Add ClassDB-exposed classes.
{
List<StringName> classes;
- ClassDB::get_class_list(&classes);
- classes.sort_custom<StringName::AlphCompare>();
- // Move ProjectSettings, so that other classes can register properties there.
- classes.move_to_back(classes.find("ProjectSettings"));
+ if (p_flags.has_flag(GENERATE_FLAG_EXTENSION_CLASSES_ONLY)) {
+ ClassDB::get_extensions_class_list(&classes);
+ } else {
+ ClassDB::get_class_list(&classes);
+ // Move ProjectSettings, so that other classes can register properties there.
+ classes.move_to_back(classes.find("ProjectSettings"));
+ }
bool skip_setter_getter_methods = true;
// Populate documentation data for each exposed class.
while (classes.size()) {
- String name = classes.front()->get();
+ const String &name = classes.front()->get();
if (!ClassDB::is_class_exposed(name)) {
print_verbose(vformat("Class '%s' is not exposed, skipping.", name));
classes.pop_front();
@@ -675,6 +682,10 @@ void DocTools::generate(bool p_basic_types) {
}
}
+ if (p_flags.has_flag(GENERATE_FLAG_SKIP_BASIC_TYPES)) {
+ return;
+ }
+
// Add a dummy Variant entry.
{
// This allows us to document the concept of Variant even though
@@ -683,11 +694,6 @@ void DocTools::generate(bool p_basic_types) {
class_list["Variant"].name = "Variant";
}
- // If we don't want to populate basic types, break here.
- if (!p_basic_types) {
- return;
- }
-
// Add Variant data types.
for (int i = 0; i < Variant::VARIANT_MAX; i++) {
if (i == Variant::NIL) {
diff --git a/editor/doc_tools.h b/editor/doc_tools.h
index 2d4a45bda0..5fffb6be38 100644
--- a/editor/doc_tools.h
+++ b/editor/doc_tools.h
@@ -45,7 +45,11 @@ public:
void add_doc(const DocData::ClassDoc &p_class_doc);
void remove_doc(const String &p_class_name);
bool has_doc(const String &p_class_name);
- void generate(bool p_basic_types = false);
+ enum GenerateFlags {
+ GENERATE_FLAG_SKIP_BASIC_TYPES = (1 << 0),
+ GENERATE_FLAG_EXTENSION_CLASSES_ONLY = (1 << 1),
+ };
+ void generate(BitField<GenerateFlags> p_flags = {});
Error load_classes(const String &p_dir);
Error save_classes(const String &p_default_path, const HashMap<String, String> &p_class_path, bool p_include_xml_schema = true);
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index 0ab6e20b01..10ab733c2b 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -2361,13 +2361,11 @@ void EditorHelp::_add_text(const String &p_bbcode) {
}
String EditorHelp::doc_version_hash;
-bool EditorHelp::doc_gen_first_attempt = true;
-bool EditorHelp::doc_gen_use_threads = true;
-Thread EditorHelp::gen_thread;
+Thread EditorHelp::worker_thread;
void EditorHelp::_wait_for_thread() {
- if (gen_thread.is_started()) {
- gen_thread.wait_to_finish();
+ if (worker_thread.is_started()) {
+ worker_thread.wait_to_finish();
}
}
@@ -2381,18 +2379,18 @@ String EditorHelp::get_cache_full_path() {
}
void EditorHelp::_load_doc_thread(void *p_udata) {
- DEV_ASSERT(doc_gen_first_attempt);
-
Ref<Resource> cache_res = ResourceLoader::load(get_cache_full_path());
if (cache_res.is_valid() && cache_res->get_meta("version_hash", "") == doc_version_hash) {
Array classes = cache_res->get_meta("classes", Array());
for (int i = 0; i < classes.size(); i++) {
doc->add_doc(DocData::ClassDoc::from_dict(classes[i]));
}
+
+ // Extensions' docs are not cached. Generate them now (on the main thread).
+ callable_mp_static(&EditorHelp::_gen_extensions_docs).call_deferred();
} else {
- // We have to go back to the main thread to start from scratch.
- doc_gen_first_attempt = false;
- callable_mp_static(&EditorHelp::generate_doc).bind(true).call_deferred();
+ // We have to go back to the main thread to start from scratch, bypassing any possibly existing cache.
+ callable_mp_static(&EditorHelp::generate_doc).bind(false).call_deferred();
}
}
@@ -2406,6 +2404,12 @@ void EditorHelp::_gen_doc_thread(void *p_udata) {
cache_res->set_meta("version_hash", doc_version_hash);
Array classes;
for (const KeyValue<String, DocData::ClassDoc> &E : doc->class_list) {
+ if (ClassDB::class_exists(E.value.name)) {
+ ClassDB::APIType api = ClassDB::get_api_type(E.value.name);
+ if (api == ClassDB::API_EXTENSION || api == ClassDB::API_EDITOR_EXTENSION) {
+ continue;
+ }
+ }
classes.push_back(DocData::ClassDoc::to_dict(E.value));
}
cache_res->set_meta("classes", classes);
@@ -2415,14 +2419,15 @@ void EditorHelp::_gen_doc_thread(void *p_udata) {
}
}
+void EditorHelp::_gen_extensions_docs() {
+ doc->generate((DocTools::GENERATE_FLAG_SKIP_BASIC_TYPES | DocTools::GENERATE_FLAG_EXTENSION_CLASSES_ONLY));
+}
+
void EditorHelp::generate_doc(bool p_use_cache) {
OS::get_singleton()->benchmark_begin_measure("EditorHelp::generate_doc");
- if (doc_gen_use_threads) {
- // In case not the first attempt.
- _wait_for_thread();
- }
- DEV_ASSERT(doc_gen_first_attempt == (doc == nullptr));
+ // In case not the first attempt.
+ _wait_for_thread();
if (!doc) {
doc = memnew(DocTools);
@@ -2432,24 +2437,14 @@ void EditorHelp::generate_doc(bool p_use_cache) {
_compute_doc_version_hash();
}
- if (p_use_cache && doc_gen_first_attempt && FileAccess::exists(get_cache_full_path())) {
- if (doc_gen_use_threads) {
- gen_thread.start(_load_doc_thread, nullptr);
- } else {
- _load_doc_thread(nullptr);
- }
+ if (p_use_cache && FileAccess::exists(get_cache_full_path())) {
+ worker_thread.start(_load_doc_thread, nullptr);
} else {
print_verbose("Regenerating editor help cache");
-
- // Not doable on threads unfortunately, since it instantiates all sorts of classes to get default values.
- doc->generate(true);
-
- if (doc_gen_use_threads) {
- gen_thread.start(_gen_doc_thread, nullptr);
- } else {
- _gen_doc_thread(nullptr);
- }
+ doc->generate();
+ worker_thread.start(_gen_doc_thread, nullptr);
}
+
OS::get_singleton()->benchmark_end_measure("EditorHelp::generate_doc");
}
diff --git a/editor/editor_help.h b/editor/editor_help.h
index 1f813f930c..d2d05a8603 100644
--- a/editor/editor_help.h
+++ b/editor/editor_help.h
@@ -188,13 +188,12 @@ class EditorHelp : public VBoxContainer {
void _toggle_scripts_pressed();
static String doc_version_hash;
- static bool doc_gen_first_attempt;
- static bool doc_gen_use_threads;
- static Thread gen_thread;
+ static Thread worker_thread;
static void _wait_for_thread();
static void _load_doc_thread(void *p_udata);
static void _gen_doc_thread(void *p_udata);
+ static void _gen_extensions_docs();
static void _compute_doc_version_hash();
protected:
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 0aa8ef66e7..944da47242 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -88,6 +88,7 @@ void FileSystemList::_line_editor_submit(String p_text) {
bool FileSystemList::edit_selected() {
ERR_FAIL_COND_V_MSG(!is_anything_selected(), false, "No item selected.");
int s = get_current();
+ ERR_FAIL_COND_V_MSG(s < 0, false, "No current item selected.");
ensure_current_is_visible();
Rect2 rect;
@@ -907,12 +908,13 @@ void FileSystemDock::_sort_file_info_list(List<FileSystemDock::FileInfo> &r_file
}
void FileSystemDock::_update_file_list(bool p_keep_selection) {
- // Register the previously selected items.
- HashSet<String> cselection;
+ // Register the previously current and selected items.
+ HashSet<String> previous_selection;
+ HashSet<int> valid_selection;
if (p_keep_selection) {
for (int i = 0; i < files->get_item_count(); i++) {
if (files->is_selected(i)) {
- cselection.insert(files->get_item_text(i));
+ previous_selection.insert(files->get_item_text(i));
}
}
}
@@ -1068,8 +1070,9 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
Color this_folder_color = has_custom_color ? folder_colors[assigned_folder_colors[dpath]] : inherited_folder_color;
files->set_item_icon_modulate(-1, editor_is_dark_theme ? this_folder_color : this_folder_color * 1.75);
- if (cselection.has(dname)) {
+ if (previous_selection.has(dname)) {
files->select(files->get_item_count() - 1, false);
+ valid_selection.insert(files->get_item_count() - 1);
}
}
}
@@ -1142,8 +1145,9 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
}
// Select the items.
- if (cselection.has(fname)) {
+ if (previous_selection.has(fname)) {
files->select(item_index, false);
+ valid_selection.insert(item_index);
}
if (!p_keep_selection && !file.is_empty() && fname == file) {
@@ -1159,6 +1163,11 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
}
files->set_item_tooltip(item_index, tooltip);
}
+
+ // If we only have any selected items retained, we need to update the current idx.
+ if (!valid_selection.is_empty()) {
+ files->set_current(*valid_selection.begin());
+ }
}
void FileSystemDock::_select_file(const String &p_path, bool p_select_in_favorites) {
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index e3c575c127..8e277a8b6c 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -965,38 +965,6 @@ Node *ResourceImporterScene::_pre_fix_animations(Node *p_node, Node *p_root, con
List<StringName> anims;
ap->get_animation_list(&anims);
- for (const StringName &name : anims) {
- Ref<Animation> anim = ap->get_animation(name);
- Array animation_slices;
-
- if (p_animation_data.has(name)) {
- Dictionary anim_settings = p_animation_data[name];
- int slices_count = anim_settings["slices/amount"];
-
- for (int i = 0; i < slices_count; i++) {
- String slice_name = anim_settings["slice_" + itos(i + 1) + "/name"];
- int from_frame = anim_settings["slice_" + itos(i + 1) + "/start_frame"];
- int end_frame = anim_settings["slice_" + itos(i + 1) + "/end_frame"];
- Animation::LoopMode loop_mode = static_cast<Animation::LoopMode>((int)anim_settings["slice_" + itos(i + 1) + "/loop_mode"]);
- bool save_to_file = anim_settings["slice_" + itos(i + 1) + "/save_to_file/enabled"];
- bool save_to_path = anim_settings["slice_" + itos(i + 1) + "/save_to_file/path"];
- bool save_to_file_keep_custom = anim_settings["slice_" + itos(i + 1) + "/save_to_file/keep_custom_tracks"];
-
- animation_slices.push_back(slice_name);
- animation_slices.push_back(from_frame / p_animation_fps);
- animation_slices.push_back(end_frame / p_animation_fps);
- animation_slices.push_back(loop_mode);
- animation_slices.push_back(save_to_file);
- animation_slices.push_back(save_to_path);
- animation_slices.push_back(save_to_file_keep_custom);
- }
- }
-
- if (animation_slices.size() > 0) {
- _create_slices(ap, anim, animation_slices, true);
- }
- }
-
AnimationImportTracks import_tracks_mode[TRACK_CHANNEL_MAX] = {
AnimationImportTracks(int(node_settings["import_tracks/position"])),
AnimationImportTracks(int(node_settings["import_tracks/rotation"])),
@@ -1063,8 +1031,36 @@ Node *ResourceImporterScene::_post_fix_animations(Node *p_node, Node *p_root, co
ap->get_animation_list(&anims);
for (const StringName &name : anims) {
Ref<Animation> anim = ap->get_animation(name);
+ Array animation_slices;
+
if (p_animation_data.has(name)) {
Dictionary anim_settings = p_animation_data[name];
+
+ {
+ int slices_count = anim_settings["slices/amount"];
+
+ for (int i = 0; i < slices_count; i++) {
+ String slice_name = anim_settings["slice_" + itos(i + 1) + "/name"];
+ int from_frame = anim_settings["slice_" + itos(i + 1) + "/start_frame"];
+ int end_frame = anim_settings["slice_" + itos(i + 1) + "/end_frame"];
+ Animation::LoopMode loop_mode = static_cast<Animation::LoopMode>((int)anim_settings["slice_" + itos(i + 1) + "/loop_mode"]);
+ bool save_to_file = anim_settings["slice_" + itos(i + 1) + "/save_to_file/enabled"];
+ String save_to_path = anim_settings["slice_" + itos(i + 1) + "/save_to_file/path"];
+ bool save_to_file_keep_custom = anim_settings["slice_" + itos(i + 1) + "/save_to_file/keep_custom_tracks"];
+
+ animation_slices.push_back(slice_name);
+ animation_slices.push_back(from_frame / p_animation_fps);
+ animation_slices.push_back(end_frame / p_animation_fps);
+ animation_slices.push_back(loop_mode);
+ animation_slices.push_back(save_to_file);
+ animation_slices.push_back(save_to_path);
+ animation_slices.push_back(save_to_file_keep_custom);
+ }
+
+ if (animation_slices.size() > 0) {
+ _create_slices(ap, anim, animation_slices, true);
+ }
+ }
{
//fill with default values
List<ImportOption> iopts;
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 0cd3d4dddf..5f55591b57 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -55,6 +55,7 @@
#include "editor/plugins/script_editor_plugin.h"
#include "editor/reparent_dialog.h"
#include "editor/shader_create_dialog.h"
+#include "scene/animation/animation_tree.h"
#include "scene/gui/check_box.h"
#include "scene/main/window.h"
#include "scene/property_utils.h"
@@ -1810,95 +1811,93 @@ void SceneTreeDock::perform_node_renames(Node *p_base, HashMap<Node *, NodePath>
return;
}
- // Renaming node paths used in node properties.
- List<PropertyInfo> properties;
- p_base->get_property_list(&properties);
-
- for (const PropertyInfo &E : properties) {
- if (!(E.usage & (PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR))) {
- continue;
- }
- String propertyname = E.name;
- Variant old_variant = p_base->get(propertyname);
- Variant updated_variant = old_variant;
- if (_check_node_path_recursive(p_base, updated_variant, p_renames)) {
- EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->add_do_property(p_base, propertyname, updated_variant);
- undo_redo->add_undo_property(p_base, propertyname, old_variant);
- p_base->set(propertyname, updated_variant);
- }
- }
-
bool autorename_animation_tracks = bool(EDITOR_GET("editors/animation/autorename_animation_tracks"));
- if (autorename_animation_tracks && Object::cast_to<AnimationPlayer>(p_base)) {
- AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_base);
- List<StringName> anims;
- ap->get_animation_list(&anims);
- Node *root = ap->get_node(ap->get_root_node());
+ AnimationMixer *mixer = Object::cast_to<AnimationMixer>(p_base);
+ if (autorename_animation_tracks && mixer) {
+ // Don't rename if we're an AnimationTree pointing to an AnimationPlayer
+ bool points_to_other_animation_player = false;
+ AnimationTree *at = Object::cast_to<AnimationTree>(mixer);
+ if (at) {
+ AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(at->get_node_or_null(at->get_animation_player()));
+ if (ap) {
+ points_to_other_animation_player = true;
+ }
+ }
- if (root) {
- HashMap<Node *, NodePath>::Iterator found_root_path = p_renames->find(root);
- NodePath new_root_path = found_root_path ? found_root_path->value : root->get_path();
- if (!new_root_path.is_empty()) { // No renaming if root node is deleted.
- for (const StringName &E : anims) {
- Ref<Animation> anim = ap->get_animation(E);
- if (!r_rem_anims->has(anim)) {
- r_rem_anims->insert(anim, HashSet<int>());
- HashSet<int> &ran = r_rem_anims->find(anim)->value;
- for (int i = 0; i < anim->get_track_count(); i++) {
- ran.insert(i);
+ if (!points_to_other_animation_player) {
+ List<StringName> anims;
+ mixer->get_animation_list(&anims);
+ Node *root = mixer->get_node(mixer->get_root_node());
+
+ if (root) {
+ HashMap<Node *, NodePath>::Iterator found_root_path = p_renames->find(root);
+ NodePath new_root_path = found_root_path ? found_root_path->value : root->get_path();
+ if (!new_root_path.is_empty()) { // No renaming if root node is deleted.
+ for (const StringName &E : anims) {
+ Ref<Animation> anim = mixer->get_animation(E);
+ if (!r_rem_anims->has(anim)) {
+ r_rem_anims->insert(anim, HashSet<int>());
+ HashSet<int> &ran = r_rem_anims->find(anim)->value;
+ for (int i = 0; i < anim->get_track_count(); i++) {
+ ran.insert(i);
+ }
}
- }
-
- HashSet<int> &ran = r_rem_anims->find(anim)->value;
-
- if (anim.is_null()) {
- continue;
- }
- int tracks_removed = 0;
+ HashSet<int> &ran = r_rem_anims->find(anim)->value;
- for (int i = 0; i < anim->get_track_count(); i++) {
- NodePath track_np = anim->track_get_path(i);
- Node *n = root->get_node_or_null(track_np);
- if (!n) {
+ if (anim.is_null() || EditorNode::get_singleton()->is_resource_read_only(anim)) {
continue;
}
- if (!ran.has(i)) {
- continue; //channel was removed
- }
+ int tracks_removed = 0;
- HashMap<Node *, NodePath>::Iterator found_path = p_renames->find(n);
- EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- if (found_path) {
- if (found_path->value.is_empty()) {
- //will be erased
-
- int idx = i - tracks_removed;
- tracks_removed++;
-
- undo_redo->add_do_method(anim.ptr(), "remove_track", idx);
- undo_redo->add_undo_method(anim.ptr(), "add_track", anim->track_get_type(i), idx);
- undo_redo->add_undo_method(anim.ptr(), "track_set_path", idx, track_np);
- undo_redo->add_undo_method(anim.ptr(), "track_set_interpolation_type", idx, anim->track_get_interpolation_type(i));
- for (int j = 0; j < anim->track_get_key_count(i); j++) {
- undo_redo->add_undo_method(anim.ptr(), "track_insert_key", idx, anim->track_get_key_time(i, j), anim->track_get_key_value(i, j), anim->track_get_key_transition(i, j));
- }
+ for (int i = 0; i < anim->get_track_count(); i++) {
+ if (anim->track_is_imported(i)) {
+ continue;
+ }
- ran.erase(i); //byebye channel
+ NodePath track_np = anim->track_get_path(i);
- } else {
- //will be renamed
- NodePath rel_path = new_root_path.rel_path_to(found_path->value);
+ Node *n = root->get_node_or_null(track_np);
+ if (!n) {
+ continue;
+ }
- NodePath new_path = NodePath(rel_path.get_names(), track_np.get_subnames(), false);
- if (new_path == track_np) {
- continue; //bleh
+ if (!ran.has(i)) {
+ continue; //channel was removed
+ }
+
+ HashMap<Node *, NodePath>::Iterator found_path = p_renames->find(n);
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
+ if (found_path) {
+ if (found_path->value.is_empty()) {
+ //will be erased
+
+ int idx = i - tracks_removed;
+ tracks_removed++;
+
+ undo_redo->add_do_method(anim.ptr(), "remove_track", idx);
+ undo_redo->add_undo_method(anim.ptr(), "add_track", anim->track_get_type(i), idx);
+ undo_redo->add_undo_method(anim.ptr(), "track_set_path", idx, track_np);
+ undo_redo->add_undo_method(anim.ptr(), "track_set_interpolation_type", idx, anim->track_get_interpolation_type(i));
+ for (int j = 0; j < anim->track_get_key_count(i); j++) {
+ undo_redo->add_undo_method(anim.ptr(), "track_insert_key", idx, anim->track_get_key_time(i, j), anim->track_get_key_value(i, j), anim->track_get_key_transition(i, j));
+ }
+
+ ran.erase(i); //byebye channel
+
+ } else {
+ //will be renamed
+ NodePath rel_path = new_root_path.rel_path_to(found_path->value);
+
+ NodePath new_path = NodePath(rel_path.get_names(), track_np.get_subnames(), false);
+ if (new_path == track_np) {
+ continue; //bleh
+ }
+ undo_redo->add_do_method(anim.ptr(), "track_set_path", i, new_path);
+ undo_redo->add_undo_method(anim.ptr(), "track_set_path", i, track_np);
}
- undo_redo->add_do_method(anim.ptr(), "track_set_path", i, new_path);
- undo_redo->add_undo_method(anim.ptr(), "track_set_path", i, track_np);
}
}
}
@@ -1907,6 +1906,25 @@ void SceneTreeDock::perform_node_renames(Node *p_base, HashMap<Node *, NodePath>
}
}
+ // Renaming node paths used in node properties.
+ List<PropertyInfo> properties;
+ p_base->get_property_list(&properties);
+
+ for (const PropertyInfo &E : properties) {
+ if (!(E.usage & (PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR))) {
+ continue;
+ }
+ String propertyname = E.name;
+ Variant old_variant = p_base->get(propertyname);
+ Variant updated_variant = old_variant;
+ if (_check_node_path_recursive(p_base, updated_variant, p_renames)) {
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
+ undo_redo->add_do_property(p_base, propertyname, updated_variant);
+ undo_redo->add_undo_property(p_base, propertyname, old_variant);
+ p_base->set(propertyname, updated_variant);
+ }
+ }
+
for (int i = 0; i < p_base->get_child_count(); i++) {
perform_node_renames(p_base->get_child(i), p_renames, r_rem_anims);
}
diff --git a/main/main.cpp b/main/main.cpp
index 7b46957904..900f9b2714 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -2768,7 +2768,7 @@ bool Main::start() {
#ifdef TOOLS_ENABLED
String doc_tool_path;
- bool doc_base = true;
+ BitField<DocTools::GenerateFlags> gen_flags;
String _export_preset;
bool export_debug = false;
bool export_pack_only = false;
@@ -2793,7 +2793,7 @@ bool Main::start() {
check_only = true;
#ifdef TOOLS_ENABLED
} else if (args[i] == "--no-docbase") {
- doc_base = false;
+ gen_flags.set_flag(DocTools::GENERATE_FLAG_SKIP_BASIC_TYPES);
#ifndef DISABLE_DEPRECATED
} else if (args[i] == "--convert-3to4") {
converting_project = true;
@@ -2904,7 +2904,7 @@ bool Main::start() {
Error err;
DocTools doc;
- doc.generate(doc_base);
+ doc.generate(gen_flags);
DocTools docsrc;
HashMap<String, String> doc_data_classes;
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp
index 0fc61dfe92..9c178997c5 100644
--- a/modules/csg/csg_shape.cpp
+++ b/modules/csg/csg_shape.cpp
@@ -488,7 +488,9 @@ bool CSGShape3D::_is_debug_collision_shape_visible() {
}
void CSGShape3D::_update_debug_collision_shape() {
- // NOTE: This is called only for the root shape with collision, when root_collision_shape is valid.
+ if (!use_collision || !is_root_shape() || !root_collision_shape.is_valid() || !_is_debug_collision_shape_visible()) {
+ return;
+ }
ERR_FAIL_NULL(RenderingServer::get_singleton());
diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp
index eb78edd2e7..31564d6c20 100644
--- a/platform/macos/export/export_plugin.cpp
+++ b/platform/macos/export/export_plugin.cpp
@@ -139,6 +139,9 @@ String EditorExportPlatformMacOS::get_export_option_warning(const EditorExportPr
if (p_name == "codesign/codesign") {
if (dist_type == 2) {
+ if (codesign_tool == 2 && Engine::get_singleton()->has_singleton("GodotSharp")) {
+ return TTR("'rcodesign' doesn't support signing applications with embedded dynamic libraries (GDExtension or .NET).");
+ }
if (codesign_tool == 0) {
return TTR("Code signing is required for App Store distribution.");
}
@@ -314,9 +317,6 @@ bool EditorExportPlatformMacOS::get_export_option_visibility(const EditorExportP
case 2: { // "notarytool"
// All options are visible.
} break;
- case 3: { // "altool"
- // All options are visible.
- } break;
default: { // disabled
if (p_option == "notarization/apple_id_name" || p_option == "notarization/apple_id_password" || p_option == "notarization/api_uuid" || p_option == "notarization/api_key" || p_option == "notarization/api_key_id") {
return false;
@@ -436,14 +436,14 @@ void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options
r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "codesign/custom_options"), PackedStringArray()));
#ifdef MACOS_ENABLED
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "notarization/notarization", PROPERTY_HINT_ENUM, "Disabled,rcodesign,Xcode notarytool,Xcode altool (deprecated)"), 0, true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "notarization/notarization", PROPERTY_HINT_ENUM, "Disabled,rcodesign,Xcode notarytool"), 0, true));
#else
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "notarization/notarization", PROPERTY_HINT_ENUM, "Disabled,rcodesign"), 0, true));
#endif
- // "altool" and "notarytool" only options:
+ // "notarytool" only options:
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_id_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Apple ID email", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_id_password", PROPERTY_HINT_PASSWORD, "Enable two-factor authentication and provide app-specific password", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "", false, true));
- // "altool", "notarytool" and "rcodesign" only options:
+ // "notarytool" and "rcodesign" only options:
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/api_uuid", PROPERTY_HINT_PLACEHOLDER_TEXT, "App Store Connect issuer ID UUID", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/api_key", PROPERTY_HINT_GLOBAL_FILE, "*.p8", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/api_key_id", PROPERTY_HINT_PLACEHOLDER_TEXT, "App Store Connect API key ID", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "", false, true));
@@ -916,89 +916,6 @@ Error EditorExportPlatformMacOS::_notarize(const Ref<EditorExportPreset> &p_pres
add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t\t\"xcrun stapler staple <app path>\"");
}
} break;
- case 3: { // "altool"
- print_verbose("using altool notarization...");
-
- if (!FileAccess::exists("/usr/bin/xcrun") && !FileAccess::exists("/bin/xcrun")) {
- add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("Xcode command line tools are not installed."));
- return Error::FAILED;
- }
-
- List<String> args;
-
- args.push_back("altool");
- args.push_back("--notarize-app");
-
- args.push_back("--primary-bundle-id");
- args.push_back(p_preset->get("application/bundle_identifier"));
-
- if (p_preset->get_or_env("notarization/apple_id_name", ENV_MAC_NOTARIZATION_APPLE_ID) == "" && p_preset->get_or_env("notarization/api_uuid", ENV_MAC_NOTARIZATION_UUID) == "") {
- add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("Neither Apple ID name nor App Store Connect issuer ID name not specified."));
- return Error::FAILED;
- }
- if (p_preset->get_or_env("notarization/apple_id_name", ENV_MAC_NOTARIZATION_APPLE_ID) != "" && p_preset->get_or_env("notarization/api_uuid", ENV_MAC_NOTARIZATION_UUID) != "") {
- add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("Both Apple ID name and App Store Connect issuer ID name are specified, only one should be set at the same time."));
- return Error::FAILED;
- }
-
- if (p_preset->get_or_env("notarization/apple_id_name", ENV_MAC_NOTARIZATION_APPLE_ID) != "") {
- if (p_preset->get_or_env("notarization/apple_id_password", ENV_MAC_NOTARIZATION_APPLE_PASS) == "") {
- add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("Apple ID password not specified."));
- return Error::FAILED;
- }
- args.push_back("--username");
- args.push_back(p_preset->get_or_env("notarization/apple_id_name", ENV_MAC_NOTARIZATION_APPLE_ID));
-
- args.push_back("--password");
- args.push_back(p_preset->get_or_env("notarization/apple_id_password", ENV_MAC_NOTARIZATION_APPLE_PASS));
- } else {
- if (p_preset->get_or_env("notarization/api_key", ENV_MAC_NOTARIZATION_KEY) == "") {
- add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("App Store Connect API key ID not specified."));
- return Error::FAILED;
- }
- args.push_back("--apiIssuer");
- args.push_back(p_preset->get_or_env("notarization/api_uuid", ENV_MAC_NOTARIZATION_UUID));
-
- args.push_back("--apiKey");
- args.push_back(p_preset->get_or_env("notarization/api_key_id", ENV_MAC_NOTARIZATION_KEY_ID));
- }
-
- args.push_back("--type");
- args.push_back("osx");
-
- if (p_preset->get("codesign/apple_team_id")) {
- args.push_back("--asc-provider");
- args.push_back(p_preset->get("codesign/apple_team_id"));
- }
-
- args.push_back("--file");
- args.push_back(p_path);
-
- String str;
- int exitcode = 0;
- Error err = OS::get_singleton()->execute("xcrun", args, &str, &exitcode, true);
- if (err != OK) {
- add_message(EXPORT_MESSAGE_WARNING, TTR("Notarization"), TTR("Could not start xcrun executable."));
- return err;
- }
-
- int rq_offset = str.find("RequestUUID:");
- if (exitcode != 0 || rq_offset == -1) {
- print_line("xcrun altool (" + p_path + "):\n" + str);
- add_message(EXPORT_MESSAGE_WARNING, TTR("Notarization"), TTR("Notarization failed, see editor log for details."));
- return Error::FAILED;
- } else {
- print_verbose("xcrun altool (" + p_path + "):\n" + str);
- int next_nl = str.find("\n", rq_offset);
- String request_uuid = (next_nl == -1) ? str.substr(rq_offset + 13, -1) : str.substr(rq_offset + 13, next_nl - rq_offset - 13);
- 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>\"");
- }
- } break;
#endif
default: {
};
@@ -1815,6 +1732,10 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
lib_validation = true;
}
+ if (!shared_objects.is_empty() && sign_enabled && codesign_tool == 2) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("'rcodesign' doesn't support signing applications with embedded dynamic libraries."));
+ }
+
String ent_path = p_preset->get("codesign/entitlements/custom_file");
String hlp_ent_path = EditorPaths::get_singleton()->get_cache_dir().path_join(pkg_name + "_helper.entitlements");
if (sign_enabled && (ent_path.is_empty())) {
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 3b19cb5566..1f70d4b558 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -3072,8 +3072,12 @@ void TileMap::_internal_update() {
return;
}
+ // FIXME: This should only clear polygons that are no longer going to be used, but since it's difficult to determine,
+ // the cache is never cleared at runtime to prevent invalidating used polygons.
+ if (Engine::get_singleton()->is_editor_hint()) {
+ polygon_cache.clear();
+ }
// Update dirty quadrants on layers.
- polygon_cache.clear();
for (Ref<TileMapLayer> &layer : layers) {
layer->internal_update();
}