diff options
-rw-r--r-- | core/extension/gdextension.cpp | 13 | ||||
-rw-r--r-- | core/extension/gdextension.h | 8 | ||||
-rw-r--r-- | core/object/class_db.cpp | 17 | ||||
-rw-r--r-- | core/object/class_db.h | 3 | ||||
-rw-r--r-- | doc/classes/AudioStreamGeneratorPlayback.xml | 1 | ||||
-rw-r--r-- | doc/classes/PopupMenu.xml | 2 | ||||
-rw-r--r-- | editor/doc_tools.cpp | 28 | ||||
-rw-r--r-- | editor/doc_tools.h | 6 | ||||
-rw-r--r-- | editor/editor_help.cpp | 55 | ||||
-rw-r--r-- | editor/editor_help.h | 5 | ||||
-rw-r--r-- | editor/filesystem_dock.cpp | 19 | ||||
-rw-r--r-- | editor/import/resource_importer_scene.cpp | 60 | ||||
-rw-r--r-- | editor/scene_tree_dock.cpp | 168 | ||||
-rw-r--r-- | main/main.cpp | 6 | ||||
-rw-r--r-- | modules/csg/csg_shape.cpp | 4 | ||||
-rw-r--r-- | platform/macos/export/export_plugin.cpp | 99 | ||||
-rw-r--r-- | scene/2d/tile_map.cpp | 6 |
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(); } |