diff options
Diffstat (limited to 'modules')
49 files changed, 440 insertions, 173 deletions
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index 0656f8224c..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()); @@ -573,6 +575,11 @@ void CSGShape3D::_notification(int p_what) { // Update this node's parent only if its own visibility has changed, not the visibility of parent nodes parent_shape->_make_dirty(); } + if (is_visible()) { + _update_debug_collision_shape(); + } else { + _clear_debug_collision_shape(); + } last_visible = is_visible(); } break; diff --git a/modules/csg/icons/CSGBox3D.svg b/modules/csg/icons/CSGBox3D.svg index bb3a1f357a..d425180cf5 100644 --- a/modules/csg/icons/CSGBox3D.svg +++ b/modules/csg/icons/CSGBox3D.svg @@ -1 +1 @@ -<svg height="16" width="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><mask id="a"><path d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z" fill="#fff"/></mask><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/><path d="m8 2 6 3v6l-6 3-6-3V5zm0 12V8l6-3M8 8 2 5" fill="none" stroke-width="2" stroke="#fc7f7f" mask="url(#a)"/></svg> +<svg height="16" width="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><mask id="a"><path d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z" fill="#fefefe"/></mask><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/><path d="m8 2 6 3v6l-6 3-6-3V5zm0 12V8l6-3M8 8 2 5" fill="none" stroke-width="2" stroke="#fc7f7f" mask="url(#a)"/></svg> diff --git a/modules/csg/icons/CSGCapsule3D.svg b/modules/csg/icons/CSGCapsule3D.svg index 33a2d4a115..3c2657999c 100644 --- a/modules/csg/icons/CSGCapsule3D.svg +++ b/modules/csg/icons/CSGCapsule3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><mask id="a"><path d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z" fill="#fff"/></mask><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/><path d="M4 6a4 4 0 0 1 8 0v4a4 4 0 0 1-8 0zm0 1.25a2.5 1 0 0 0 8 0m-4-5v12" fill="none" stroke-width="2" stroke="#fc7f7f" mask="url(#a)"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><mask id="a"><path d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z" fill="#fefefe"/></mask><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/><path d="M4 6a4 4 0 0 1 8 0v4a4 4 0 0 1-8 0zm0 1.25a2.5 1 0 0 0 8 0m-4-5v12" fill="none" stroke-width="2" stroke="#fc7f7f" mask="url(#a)"/></svg> diff --git a/modules/csg/icons/CSGCylinder3D.svg b/modules/csg/icons/CSGCylinder3D.svg index 29d658dc46..19e48b4dba 100644 --- a/modules/csg/icons/CSGCylinder3D.svg +++ b/modules/csg/icons/CSGCylinder3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><mask id="a"><path d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z" fill="#fff"/></mask><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/><path d="M2 4v8a6 2 0 0 0 12 0V4A6 2 0 0 0 2 4a6 2 0 0 0 12 0" stroke-width="2" fill="none" stroke="#fc7f7f" mask="url(#a)"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><mask id="a"><path d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z" fill="#fefefe"/></mask><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/><path d="M2 4v8a6 2 0 0 0 12 0V4A6 2 0 0 0 2 4a6 2 0 0 0 12 0" stroke-width="2" fill="none" stroke="#fc7f7f" mask="url(#a)"/></svg> diff --git a/modules/csg/icons/CSGPolygon3D.svg b/modules/csg/icons/CSGPolygon3D.svg index 8d4b61e039..090047248b 100644 --- a/modules/csg/icons/CSGPolygon3D.svg +++ b/modules/csg/icons/CSGPolygon3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><mask id="a"><path d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z" fill="#fff"/></mask><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/><path d="m8 2 6 3.5v5L8 14l-6-3.5v-5h6zm6 3.5L8 9 2 5.5M8 9v5" fill="none" stroke-linejoin="round" stroke-width="2" stroke="#fc7f7f" mask="url(#a)"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><mask id="a"><path d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z" fill="#fefefe"/></mask><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/><path d="m8 2 6 3.5v5L8 14l-6-3.5v-5h6zm6 3.5L8 9 2 5.5M8 9v5" fill="none" stroke-linejoin="round" stroke-width="2" stroke="#fc7f7f" mask="url(#a)"/></svg> diff --git a/modules/csg/icons/CSGSphere3D.svg b/modules/csg/icons/CSGSphere3D.svg index 16d45b3c99..a677ffaf5c 100644 --- a/modules/csg/icons/CSGSphere3D.svg +++ b/modules/csg/icons/CSGSphere3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><mask id="a"><path d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z" fill="#fff"/></mask><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/><path d="M8 2a6 6 0 0 0 0 12A6 6 0 0 0 8 2v12M2.05 7.4a6 2 0 0 0 11.9 0" fill="none" stroke-width="2" stroke="#fc7f7f" mask="url(#a)"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><mask id="a"><path d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z" fill="#fefefe"/></mask><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/><path d="M8 2a6 6 0 0 0 0 12A6 6 0 0 0 8 2v12M2.05 7.4a6 2 0 0 0 11.9 0" fill="none" stroke-width="2" stroke="#fc7f7f" mask="url(#a)"/></svg> diff --git a/modules/csg/icons/CSGTorus3D.svg b/modules/csg/icons/CSGTorus3D.svg index 27a6b422f9..60c56bd1ca 100644 --- a/modules/csg/icons/CSGTorus3D.svg +++ b/modules/csg/icons/CSGTorus3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><mask id="a"><path d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z" fill="#fff"/></mask><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/><g fill="none" stroke="#fc7f7f" mask="url(#a)"><path d="M2.5 10a6 4 0 0 0 11 0 4 4 0 0 0 0-4 6 4 0 0 0-11 0 4 4 0 0 0 0 4z" stroke-width="2"/><path d="M6.2 7.2a2 1 0 1 0 3.6 0" stroke-width="1.75" stroke-linecap="round"/></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><mask id="a"><path d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z" fill="#fefefe"/></mask><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/><g fill="none" stroke="#fc7f7f" mask="url(#a)"><path d="M2.5 10a6 4 0 0 0 11 0 4 4 0 0 0 0-4 6 4 0 0 0-11 0 4 4 0 0 0 0 4z" stroke-width="2"/><path d="M6.2 7.2a2 1 0 1 0 3.6 0" stroke-width="1.75" stroke-linecap="round"/></g></svg> diff --git a/modules/gdscript/SCsub b/modules/gdscript/SCsub index 1dc4768186..61accd4fc9 100644 --- a/modules/gdscript/SCsub +++ b/modules/gdscript/SCsub @@ -19,6 +19,8 @@ if env.editor_build: # Using a define in the disabled case, to avoid having an extra define # in regular builds where all modules are enabled. env_gdscript.Append(CPPDEFINES=["GDSCRIPT_NO_LSP"]) + # Also needed in main env to unexpose --lsp-port option. + env.Append(CPPDEFINES=["GDSCRIPT_NO_LSP"]) if env["tests"]: diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp index becc2876f9..9128f104b8 100644 --- a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp +++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp @@ -40,7 +40,7 @@ void GDScriptEditorTranslationParserPlugin::get_recognized_extensions(List<Strin } Error GDScriptEditorTranslationParserPlugin::parse_file(const String &p_path, Vector<String> *r_ids, Vector<Vector<String>> *r_ids_ctx_plural) { - // Extract all translatable strings using the parsed tree from GDSriptParser. + // Extract all translatable strings using the parsed tree from GDScriptParser. // The strategy is to find all ExpressionNode and AssignmentNode from the tree and extract strings if relevant, i.e // Search strings in ExpressionNode -> CallNode -> tr(), set_text(), set_placeholder() etc. // Search strings in AssignmentNode -> text = "__", tooltip_text = "__" etc. diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 6245cc85a0..4accdb4d21 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -992,6 +992,7 @@ void GDScript::set_path(const String &p_path, bool p_take_over) { String old_path = path; path = p_path; + path_valid = true; GDScriptCache::move_script(old_path, p_path); for (KeyValue<StringName, Ref<GDScript>> &kv : subclasses) { @@ -1000,6 +1001,9 @@ void GDScript::set_path(const String &p_path, bool p_take_over) { } String GDScript::get_script_path() const { + if (!path_valid && !get_path().is_empty()) { + return get_path(); + } return path; } @@ -1035,6 +1039,7 @@ Error GDScript::load_source_code(const String &p_path) { source = s; path = p_path; + path_valid = true; #ifdef TOOLS_ENABLED source_changed_cache = true; set_edited(false); @@ -1387,33 +1392,106 @@ String GDScript::debug_get_script_name(const Ref<Script> &p_script) { #endif thread_local GDScript::UpdatableFuncPtr GDScript::func_ptrs_to_update_thread_local; +GDScript::UpdatableFuncPtr *GDScript::func_ptrs_to_update_main_thread = &func_ptrs_to_update_thread_local; + +GDScript::UpdatableFuncPtrElement *GDScript::_add_func_ptr_to_update(GDScriptFunction **p_func_ptr_ptr) { + MutexLock lock(func_ptrs_to_update_mutex); -GDScript::UpdatableFuncPtrElement GDScript::_add_func_ptr_to_update(GDScriptFunction **p_func_ptr_ptr) { - UpdatableFuncPtrElement result = {}; + List<UpdatableFuncPtrElement>::Element *result = func_ptrs_to_update_elems.push_back(UpdatableFuncPtrElement()); { - MutexLock lock(func_ptrs_to_update_thread_local.mutex); - result.element = func_ptrs_to_update_thread_local.ptrs.push_back(p_func_ptr_ptr); - result.mutex = &func_ptrs_to_update_thread_local.mutex; + MutexLock lock2(func_ptrs_to_update_thread_local.mutex); + result->get().element = func_ptrs_to_update_thread_local.ptrs.push_back(p_func_ptr_ptr); + result->get().mutex = &func_ptrs_to_update_thread_local.mutex; if (likely(func_ptrs_to_update_thread_local.initialized)) { - return result; + return &result->get(); } func_ptrs_to_update_thread_local.initialized = true; } - MutexLock lock(func_ptrs_to_update_mutex); func_ptrs_to_update.push_back(&func_ptrs_to_update_thread_local); - return result; + return &result->get(); +} + +void GDScript::_remove_func_ptr_to_update(const UpdatableFuncPtrElement *p_func_ptr_element) { + // None of these checks should ever fail, unless there's a bug. + // They can be removed once we are sure they never catch anything. + // Left here now due to extra safety needs late in the release cycle. + ERR_FAIL_NULL(p_func_ptr_element); + MutexLock lock(*p_func_ptr_element->mutex); + ERR_FAIL_NULL(p_func_ptr_element->element); + ERR_FAIL_NULL(p_func_ptr_element->mutex); + p_func_ptr_element->element->erase(); } -void GDScript::_remove_func_ptr_to_update(const UpdatableFuncPtrElement p_func_ptr_element) { - ERR_FAIL_NULL(p_func_ptr_element.element); - ERR_FAIL_NULL(p_func_ptr_element.mutex); - MutexLock lock(*p_func_ptr_element.mutex); - p_func_ptr_element.element->erase(); +void GDScript::_fixup_thread_function_bookkeeping() { + // Transfer the ownership of these update items to the main thread, + // because the current one is dying, leaving theirs orphan, dangling. + + HashSet<GDScript *> scripts; + + DEV_ASSERT(!Thread::is_main_thread()); + MutexLock lock(func_ptrs_to_update_main_thread->mutex); + + { + MutexLock lock2(func_ptrs_to_update_thread_local.mutex); + + while (!func_ptrs_to_update_thread_local.ptrs.is_empty()) { + // Transfer the thread-to-script records from the dying thread to the main one. + + List<GDScriptFunction **>::Element *E = func_ptrs_to_update_thread_local.ptrs.front(); + List<GDScriptFunction **>::Element *new_E = func_ptrs_to_update_main_thread->ptrs.push_front(E->get()); + + GDScript *script = (*E->get())->get_script(); + if (!scripts.has(script)) { + scripts.insert(script); + + // Replace dying thread by the main thread in the script-to-thread records. + + MutexLock lock3(script->func_ptrs_to_update_mutex); + DEV_ASSERT(script->func_ptrs_to_update.find(&func_ptrs_to_update_thread_local)); + { + for (List<UpdatableFuncPtrElement>::Element *F = script->func_ptrs_to_update_elems.front(); F; F = F->next()) { + bool is_dying_thread_entry = F->get().mutex == &func_ptrs_to_update_thread_local.mutex; + if (is_dying_thread_entry) { + // This may lead to multiple main-thread entries, but that's not a problem + // and allows to reuse the element, which is needed, since it's tracked by pointer. + F->get().element = new_E; + F->get().mutex = &func_ptrs_to_update_main_thread->mutex; + } + } + } + } + + E->erase(); + } + } + func_ptrs_to_update_main_thread->initialized = true; + + { + // Remove orphan thread-to-script entries from every script. + // FIXME: This involves iterating through every script whenever a thread dies. + // While it's OK that thread creation/destruction are heavy operations, + // additional bookkeeping can be used to outperform this brute-force approach. + + GDScriptLanguage *gd_lang = GDScriptLanguage::get_singleton(); + + MutexLock lock2(gd_lang->mutex); + + for (SelfList<GDScript> *s = gd_lang->script_list.first(); s; s = s->next()) { + GDScript *script = s->self(); + for (List<UpdatableFuncPtr *>::Element *E = script->func_ptrs_to_update.front(); E; E = E->next()) { + bool is_dying_thread_entry = &E->get()->mutex == &func_ptrs_to_update_thread_local.mutex; + if (is_dying_thread_entry) { + E->erase(); + break; + } + } + } + } } void GDScript::clear(ClearData *p_clear_data) { @@ -1441,6 +1519,7 @@ void GDScript::clear(ClearData *p_clear_data) { *func_ptr_ptr = nullptr; } } + func_ptrs_to_update_elems.clear(); } RBSet<GDScript *> must_clear_dependencies = get_must_clear_dependencies(); @@ -2060,6 +2139,10 @@ void GDScriptLanguage::remove_named_global_constant(const StringName &p_name) { named_globals.erase(p_name); } +void GDScriptLanguage::thread_exit() { + GDScript::_fixup_thread_function_bookkeeping(); +} + void GDScriptLanguage::init() { //populate global constants int gcc = CoreConstants::get_global_constant_count(); diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 04b0a1d786..9b99f5ca0b 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -128,11 +128,16 @@ class GDScript : public Script { Mutex *mutex = nullptr; }; static thread_local UpdatableFuncPtr func_ptrs_to_update_thread_local; + static thread_local LocalVector<List<UpdatableFuncPtr *>::Element> func_ptrs_to_update_entries_thread_local; + static UpdatableFuncPtr *func_ptrs_to_update_main_thread; List<UpdatableFuncPtr *> func_ptrs_to_update; + List<UpdatableFuncPtrElement> func_ptrs_to_update_elems; Mutex func_ptrs_to_update_mutex; - UpdatableFuncPtrElement _add_func_ptr_to_update(GDScriptFunction **p_func_ptr_ptr); - static void _remove_func_ptr_to_update(const UpdatableFuncPtrElement p_func_ptr_element); + UpdatableFuncPtrElement *_add_func_ptr_to_update(GDScriptFunction **p_func_ptr_ptr); + static void _remove_func_ptr_to_update(const UpdatableFuncPtrElement *p_func_ptr_element); + + static void _fixup_thread_function_bookkeeping(); #ifdef TOOLS_ENABLED // For static data storage during hot-reloading. @@ -171,6 +176,7 @@ class GDScript : public Script { //exported members String source; String path; + bool path_valid = false; // False if using default path. StringName local_name; // Inner class identifier or `class_name`. StringName global_name; // `class_name`. String fully_qualified_name; @@ -553,6 +559,10 @@ public: virtual void add_named_global_constant(const StringName &p_name, const Variant &p_value) override; virtual void remove_named_global_constant(const StringName &p_name) override; + /* MULTITHREAD FUNCTIONS */ + + virtual void thread_exit() override; + /* DEBUGGER FUNCTIONS */ virtual String debug_get_error() const override; diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp index 26f01ec218..76f4e69ab9 100644 --- a/modules/gdscript/gdscript_cache.cpp +++ b/modules/gdscript/gdscript_cache.cpp @@ -364,28 +364,33 @@ void GDScriptCache::remove_static_script(const String &p_fqcn) { Ref<PackedScene> GDScriptCache::get_packed_scene(const String &p_path, Error &r_error, const String &p_owner) { MutexLock lock(singleton->mutex); - if (singleton->packed_scene_cache.has(p_path)) { - singleton->packed_scene_dependencies[p_path].insert(p_owner); - return singleton->packed_scene_cache[p_path]; + String path = p_path; + if (path.begins_with("uid://")) { + path = ResourceUID::get_singleton()->get_id_path(ResourceUID::get_singleton()->text_to_id(path)); } - Ref<PackedScene> scene = ResourceCache::get_ref(p_path); + if (singleton->packed_scene_cache.has(path)) { + singleton->packed_scene_dependencies[path].insert(p_owner); + return singleton->packed_scene_cache[path]; + } + + Ref<PackedScene> scene = ResourceCache::get_ref(path); if (scene.is_valid()) { - singleton->packed_scene_cache[p_path] = scene; - singleton->packed_scene_dependencies[p_path].insert(p_owner); + singleton->packed_scene_cache[path] = scene; + singleton->packed_scene_dependencies[path].insert(p_owner); return scene; } scene.instantiate(); r_error = OK; - if (p_path.is_empty()) { + if (path.is_empty()) { r_error = ERR_FILE_BAD_PATH; return scene; } - scene->set_path(p_path); - singleton->packed_scene_cache[p_path] = scene; - singleton->packed_scene_dependencies[p_path].insert(p_owner); + scene->set_path(path); + singleton->packed_scene_cache[path] = scene; + singleton->packed_scene_dependencies[path].insert(p_owner); scene->reload_from_file(); return scene; diff --git a/modules/gdscript/gdscript_lambda_callable.cpp b/modules/gdscript/gdscript_lambda_callable.cpp index 547f5607d3..339d1ac08e 100644 --- a/modules/gdscript/gdscript_lambda_callable.cpp +++ b/modules/gdscript/gdscript_lambda_callable.cpp @@ -296,5 +296,7 @@ GDScriptLambdaSelfCallable::GDScriptLambdaSelfCallable(Object *p_self, GDScriptF } GDScriptLambdaSelfCallable::~GDScriptLambdaSelfCallable() { - GDScript::_remove_func_ptr_to_update(updatable_func_ptr_element); + if (updatable_func_ptr_element) { + GDScript::_remove_func_ptr_to_update(updatable_func_ptr_element); + } } diff --git a/modules/gdscript/gdscript_lambda_callable.h b/modules/gdscript/gdscript_lambda_callable.h index ee7d547544..d961f18852 100644 --- a/modules/gdscript/gdscript_lambda_callable.h +++ b/modules/gdscript/gdscript_lambda_callable.h @@ -45,7 +45,7 @@ class GDScriptLambdaCallable : public CallableCustom { GDScriptFunction *function = nullptr; Ref<GDScript> script; uint32_t h; - GDScript::UpdatableFuncPtrElement updatable_func_ptr_element; + GDScript::UpdatableFuncPtrElement *updatable_func_ptr_element = nullptr; Vector<Variant> captures; @@ -72,7 +72,7 @@ class GDScriptLambdaSelfCallable : public CallableCustom { Ref<RefCounted> reference; // For objects that are RefCounted, keep a reference. Object *object = nullptr; // For non RefCounted objects, use a direct pointer. uint32_t h; - GDScript::UpdatableFuncPtrElement updatable_func_ptr_element; + GDScript::UpdatableFuncPtrElement *updatable_func_ptr_element = nullptr; Vector<Variant> captures; diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index 9067864dfe..4b46b98baa 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -178,11 +178,11 @@ public: bool operator==(const DataType &p_other) const { if (type_source == UNDETECTED || p_other.type_source == UNDETECTED) { - return true; // Can be consireded equal for parsing purposes. + return true; // Can be considered equal for parsing purposes. } if (type_source == INFERRED || p_other.type_source == INFERRED) { - return true; // Can be consireded equal for parsing purposes. + return true; // Can be considered equal for parsing purposes. } if (kind != p_other.kind) { diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index b723ecc185..d31411b26b 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -662,6 +662,14 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a uint32_t op_signature = _code_ptr[ip + 5]; uint32_t actual_signature = (a->get_type() << 8) | (b->get_type()); +#ifdef DEBUG_ENABLED + if (op == Variant::OP_DIVIDE || op == Variant::OP_MODULE) { + // Don't optimize division and modulo since there's not check for division by zero with validated calls. + op_signature = 0xFFFF; + _code_ptr[ip + 5] = op_signature; + } +#endif + // Check if this is the first run. If so, store the current signature for the optimized path. if (unlikely(op_signature == 0)) { static Mutex initializer_mutex; diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp index cb45a6589e..2fad475e92 100644 --- a/modules/gltf/editor/editor_scene_importer_blend.cpp +++ b/modules/gltf/editor/editor_scene_importer_blend.cpp @@ -130,8 +130,9 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_ // Get global paths for source and sink. // Escape paths to be valid Python strings to embed in the script. const String source_global = ProjectSettings::get_singleton()->globalize_path(p_path).c_escape(); + const String blend_basename = p_path.get_file().get_basename(); const String sink = ProjectSettings::get_singleton()->get_imported_files_path().path_join( - vformat("%s-%s.gltf", p_path.get_file().get_basename(), p_path.md5_text())); + vformat("%s-%s.gltf", blend_basename, p_path.md5_text())); const String sink_global = ProjectSettings::get_singleton()->globalize_path(sink).c_escape(); // Handle configuration options. @@ -282,6 +283,7 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_ if (p_options.has(SNAME("blender/materials/unpack_enabled")) && p_options[SNAME("blender/materials/unpack_enabled")]) { base_dir = sink.get_base_dir(); } + state->set_scene_name(blend_basename); err = gltf->append_from_file(sink.get_basename() + ".gltf", state, p_flags, base_dir); if (err != OK) { if (r_err) { diff --git a/modules/gltf/editor/editor_scene_importer_gltf.cpp b/modules/gltf/editor/editor_scene_importer_gltf.cpp index b63a938e64..e35c0e9b9b 100644 --- a/modules/gltf/editor/editor_scene_importer_gltf.cpp +++ b/modules/gltf/editor/editor_scene_importer_gltf.cpp @@ -51,6 +51,10 @@ Node *EditorSceneFormatImporterGLTF::import_scene(const String &p_path, uint32_t gltf.instantiate(); Ref<GLTFState> state; state.instantiate(); + if (p_options.has("gltf/naming_version")) { + int naming_version = p_options["gltf/naming_version"]; + gltf->set_naming_version(naming_version); + } if (p_options.has("gltf/embedded_image_handling")) { int32_t enum_option = p_options["gltf/embedded_image_handling"]; state->set_handle_binary_image(enum_option); @@ -77,7 +81,16 @@ Node *EditorSceneFormatImporterGLTF::import_scene(const String &p_path, uint32_t void EditorSceneFormatImporterGLTF::get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options) { - r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "gltf/embedded_image_handling", PROPERTY_HINT_ENUM, "Discard All Textures,Extract Textures,Embed As Basis Universal,Embed as Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), GLTFState::HANDLE_BINARY_EXTRACT_TEXTURES)); + r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "gltf/naming_version", PROPERTY_HINT_ENUM, "Godot 4.1 or 4.0,Godot 4.2 or later"), 1)); + r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "gltf/embedded_image_handling", PROPERTY_HINT_ENUM, "Discard All Textures,Extract Textures,Embed as Basis Universal,Embed as Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), GLTFState::HANDLE_BINARY_EXTRACT_TEXTURES)); +} + +void EditorSceneFormatImporterGLTF::handle_compatibility_options(HashMap<StringName, Variant> &p_import_params) const { + if (!p_import_params.has("gltf/naming_version")) { + // If an existing import file is missing the glTF + // compatibility version, we need to use version 0. + p_import_params["gltf/naming_version"] = 0; + } } #endif // TOOLS_ENABLED diff --git a/modules/gltf/editor/editor_scene_importer_gltf.h b/modules/gltf/editor/editor_scene_importer_gltf.h index ed57ec8cdb..7726c845bf 100644 --- a/modules/gltf/editor/editor_scene_importer_gltf.h +++ b/modules/gltf/editor/editor_scene_importer_gltf.h @@ -49,6 +49,7 @@ public: List<String> *r_missing_deps, Error *r_err = nullptr) override; virtual void get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options) override; + virtual void handle_compatibility_options(HashMap<StringName, Variant> &p_import_params) const override; }; #endif // TOOLS_ENABLED diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index 47fc58fe43..4060f7f626 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -573,9 +573,12 @@ Error GLTFDocument::_parse_scenes(Ref<GLTFState> p_state) { // Determine what to use for the scene name. if (scene_dict.has("name") && !String(scene_dict["name"]).is_empty() && !((String)scene_dict["name"]).begins_with("Scene")) { p_state->scene_name = scene_dict["name"]; - } else { + } else if (p_state->scene_name.is_empty()) { p_state->scene_name = p_state->filename; } + if (_naming_version == 0) { + p_state->scene_name = _gen_unique_name(p_state, p_state->scene_name); + } } return OK; @@ -2797,9 +2800,26 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) { array[Mesh::ARRAY_INDEX] = indices; } - bool generate_tangents = p_state->force_generate_tangents && (primitive == Mesh::PRIMITIVE_TRIANGLES && !a.has("TANGENT") && a.has("TEXCOORD_0") && a.has("NORMAL")); + bool generate_tangents = p_state->force_generate_tangents && (primitive == Mesh::PRIMITIVE_TRIANGLES && !a.has("TANGENT") && a.has("NORMAL")); + + if (generate_tangents && !a.has("TEXCOORD_0")) { + // If we don't have UVs we provide a dummy tangent array. + Vector<float> tangents; + tangents.resize(vertex_num * 4); + float *tangentsw = tangents.ptrw(); + + Vector<Vector3> normals = array[Mesh::ARRAY_NORMAL]; + for (int k = 0; k < vertex_num; k++) { + Vector3 tan = Vector3(0.0, 1.0, 0.0).cross(normals[k]); + tangentsw[k * 4 + 0] = tan.x; + tangentsw[k * 4 + 1] = tan.y; + tangentsw[k * 4 + 2] = tan.z; + tangentsw[k * 4 + 3] = 1.0; + } + array[Mesh::ARRAY_TANGENT] = tangents; + } - if (p_state->force_disable_compression || !a.has("POSITION") || !a.has("NORMAL") || !(a.has("TANGENT") || generate_tangents) || p.has("targets") || (a.has("JOINTS_0") || a.has("JOINTS_1"))) { + if (p_state->force_disable_compression || !a.has("POSITION") || !a.has("NORMAL") || p.has("targets") || (a.has("JOINTS_0") || a.has("JOINTS_1"))) { flags &= ~RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES; } @@ -2810,7 +2830,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) { mesh_surface_tool->set_skin_weight_count(SurfaceTool::SKIN_8_WEIGHTS); } mesh_surface_tool->index(); - if (generate_tangents) { + if (generate_tangents && a.has("TEXCOORD_0")) { //must generate mikktspace tangents.. ergh.. mesh_surface_tool->generate_tangents(); } @@ -3006,6 +3026,14 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) { return OK; } +void GLTFDocument::set_naming_version(int p_version) { + _naming_version = p_version; +} + +int GLTFDocument::get_naming_version() const { + return _naming_version; +} + void GLTFDocument::set_image_format(const String &p_image_format) { _image_format = p_image_format; } @@ -5341,12 +5369,22 @@ void GLTFDocument::_assign_node_names(Ref<GLTFState> p_state) { } String gltf_node_name = gltf_node->get_name(); if (gltf_node_name.is_empty()) { - if (gltf_node->mesh >= 0) { - gltf_node_name = "Mesh"; - } else if (gltf_node->camera >= 0) { - gltf_node_name = "Camera"; + if (_naming_version == 0) { + if (gltf_node->mesh >= 0) { + gltf_node_name = _gen_unique_name(p_state, "Mesh"); + } else if (gltf_node->camera >= 0) { + gltf_node_name = _gen_unique_name(p_state, "Camera3D"); + } else { + gltf_node_name = _gen_unique_name(p_state, "Node"); + } } else { - gltf_node_name = "Node"; + if (gltf_node->mesh >= 0) { + gltf_node_name = "Mesh"; + } else if (gltf_node->camera >= 0) { + gltf_node_name = "Camera"; + } else { + gltf_node_name = "Node"; + } } } gltf_node->set_name(_gen_unique_name(p_state, gltf_node_name)); @@ -5846,6 +5884,10 @@ void GLTFDocument::_generate_scene_node(Ref<GLTFState> p_state, const GLTFNodeIn BoneAttachment3D *bone_attachment = _generate_bone_attachment(p_state, active_skeleton, p_node_index, gltf_node->parent); p_scene_parent->add_child(bone_attachment, true); + + // Find the correct bone_idx so we can properly serialize it. + bone_attachment->set_bone_idx(active_skeleton->find_bone(gltf_node->get_name())); + bone_attachment->set_owner(p_scene_root); // There is no gltf_node that represent this, so just directly create a unique name @@ -5949,6 +5991,10 @@ void GLTFDocument::_generate_skeleton_bone_node(Ref<GLTFState> p_state, const GL BoneAttachment3D *bone_attachment = _generate_bone_attachment(p_state, active_skeleton, p_node_index, p_node_index); p_scene_parent->add_child(bone_attachment, true); + + // Find the correct bone_idx so we can properly serialize it. + bone_attachment->set_bone_idx(active_skeleton->find_bone(gltf_node->get_name())); + bone_attachment->set_owner(p_scene_root); // There is no gltf_node that represent this, so just directly create a unique name @@ -7380,7 +7426,11 @@ Node *GLTFDocument::_generate_scene_node_tree(Ref<GLTFState> p_state) { if (unlikely(p_state->scene_name.is_empty())) { p_state->scene_name = single_root->get_name(); } else if (single_root->get_name() == StringName()) { - single_root->set_name(_gen_unique_name(p_state, p_state->scene_name)); + if (_naming_version == 0) { + single_root->set_name(p_state->scene_name); + } else { + single_root->set_name(_gen_unique_name(p_state, p_state->scene_name)); + } } return single_root; } diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h index 828d650cff..7e378fe94d 100644 --- a/modules/gltf/gltf_document.h +++ b/modules/gltf/gltf_document.h @@ -73,6 +73,7 @@ public: private: const float BAKE_FPS = 30.0f; + int _naming_version = 1; String _image_format = "PNG"; float _lossy_quality = 0.75f; Ref<GLTFDocumentExtension> _image_save_extension; @@ -86,6 +87,8 @@ public: static void unregister_gltf_document_extension(Ref<GLTFDocumentExtension> p_extension); static void unregister_all_gltf_document_extensions(); + void set_naming_version(int p_version); + int get_naming_version() const; void set_image_format(const String &p_image_format); String get_image_format() const; void set_lossy_quality(float p_lossy_quality); diff --git a/modules/gltf/gltf_state.cpp b/modules/gltf/gltf_state.cpp index c0ec004fd6..766fe41257 100644 --- a/modules/gltf/gltf_state.cpp +++ b/modules/gltf/gltf_state.cpp @@ -124,7 +124,7 @@ void GLTFState::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "skeletons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_skeletons", "get_skeletons"); // Vector<Ref<GLTFSkeleton>> ADD_PROPERTY(PropertyInfo(Variant::BOOL, "create_animations"), "set_create_animations", "get_create_animations"); // bool ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_animations", "get_animations"); // Vector<Ref<GLTFAnimation>> - ADD_PROPERTY(PropertyInfo(Variant::INT, "handle_binary_image", PROPERTY_HINT_ENUM, "Discard All Textures,Extract Textures,Embed As Basis Universal,Embed as Uncompressed", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_handle_binary_image", "get_handle_binary_image"); // enum + ADD_PROPERTY(PropertyInfo(Variant::INT, "handle_binary_image", PROPERTY_HINT_ENUM, "Discard All Textures,Extract Textures,Embed as Basis Universal,Embed as Uncompressed", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_handle_binary_image", "get_handle_binary_image"); // enum BIND_CONSTANT(HANDLE_BINARY_DISCARD_TEXTURES); BIND_CONSTANT(HANDLE_BINARY_EXTRACT_TEXTURES); diff --git a/modules/jpg/image_loader_jpegd.cpp b/modules/jpg/image_loader_jpegd.cpp index 0b9fcf4455..e7fa909706 100644 --- a/modules/jpg/image_loader_jpegd.cpp +++ b/modules/jpg/image_loader_jpegd.cpp @@ -156,7 +156,11 @@ public: static Error _jpgd_save_to_output_stream(jpge::output_stream *p_output_stream, const Ref<Image> &p_img, float p_quality) { ERR_FAIL_COND_V(p_img.is_null() || p_img->is_empty(), ERR_INVALID_PARAMETER); - Ref<Image> image = p_img; + Ref<Image> image = p_img->duplicate(); + if (image->is_compressed()) { + Error error = image->decompress(); + ERR_FAIL_COND_V_MSG(error != OK, error, "Couldn't decompress image."); + } if (image->get_format() != Image::FORMAT_RGB8) { image->convert(Image::FORMAT_RGB8); } diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp index fe919953c1..a4ecb767a7 100644 --- a/modules/lightmapper_rd/lightmapper_rd.cpp +++ b/modules/lightmapper_rd/lightmapper_rd.cpp @@ -877,7 +877,7 @@ LightmapperRD::BakeError LightmapperRD::_denoise_oidn(RenderingDevice *p_rd, RID if (err != OK || exitcode != 0) { da->remove(fname_out); print_verbose(str); - ERR_FAIL_V_MSG(BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES, vformat(TTR("OIDN denoiser failed, return code: %d"), exitcode)); + ERR_FAIL_V_MSG(BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES, vformat("OIDN denoiser failed, return code: %d", exitcode)); } Ref<Image> img = _read_pfm(fname_out); @@ -988,7 +988,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d oidn_path = oidn_path.path_join("oidnDenoise"); } } - ERR_FAIL_COND_V_MSG(oidn_path.is_empty() || !da->file_exists(oidn_path), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES, TTR("OIDN denoiser is selected in the project settings, but no or invalid OIDN executable path is configured in the editor settings.")); + ERR_FAIL_COND_V_MSG(oidn_path.is_empty() || !da->file_exists(oidn_path), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES, "OIDN denoiser is selected in the project settings, but no or invalid OIDN executable path is configured in the editor settings."); } if (p_step_function) { diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 44bcd4cfe4..56e4fa53d0 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -142,6 +142,10 @@ void CSharpLanguage::finalize() { return; } + if (gdmono && gdmono->is_runtime_initialized() && GDMonoCache::godot_api_cache_updated) { + GDMonoCache::managed_callbacks.DisposablesTracker_OnGodotShuttingDown(); + } + finalizing = true; // Make sure all script binding gchandles are released before finalizing GDMono @@ -1985,24 +1989,31 @@ const Variant CSharpInstance::get_rpc_config() const { void CSharpInstance::notification(int p_notification, bool p_reversed) { if (p_notification == Object::NOTIFICATION_PREDELETE) { - // When NOTIFICATION_PREDELETE is sent, we also take the chance to call Dispose(). - // It's safe to call Dispose() multiple times and NOTIFICATION_PREDELETE is guaranteed + if (base_ref_counted) { + // At this point, Dispose() was already called (manually or from the finalizer). + // The RefCounted wouldn't have reached 0 otherwise, since the managed side + // references it and Dispose() needs to be called to release it. + // However, this means C# RefCounted scripts can't receive NOTIFICATION_PREDELETE, but + // this is likely the case with GDScript as well: https://github.com/godotengine/godot/issues/6784 + return; + } + } else if (p_notification == Object::NOTIFICATION_PREDELETE_CLEANUP) { + // When NOTIFICATION_PREDELETE_CLEANUP is sent, we also take the chance to call Dispose(). + // It's safe to call Dispose() multiple times and NOTIFICATION_PREDELETE_CLEANUP is guaranteed // to be sent at least once, which happens right before the call to the destructor. predelete_notified = true; if (base_ref_counted) { - // It's not safe to proceed if the owner derives RefCounted and the refcount reached 0. - // At this point, Dispose() was already called (manually or from the finalizer) so - // that's not a problem. The refcount wouldn't have reached 0 otherwise, since the - // managed side references it and Dispose() needs to be called to release it. - // However, this means C# RefCounted scripts can't receive NOTIFICATION_PREDELETE, but - // this is likely the case with GDScript as well: https://github.com/godotengine/godot/issues/6784 + // At this point, Dispose() was already called (manually or from the finalizer). + // The RefCounted wouldn't have reached 0 otherwise, since the managed side + // references it and Dispose() needs to be called to release it. return; } - _call_notification(p_notification, p_reversed); - + // NOTIFICATION_PREDELETE_CLEANUP is not sent to scripts. + // After calling Dispose() the C# instance can no longer be used, + // so it should be the last thing we do. GDMonoCache::managed_callbacks.CSharpInstanceBridge_CallDispose( gchandle.get_intptr(), /* okIfNull */ false); diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs index df35091596..147ef852b3 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs @@ -230,6 +230,31 @@ namespace Godot.SourceGenerators location?.SourceTree?.FilePath)); } + public static void ReportOnlyNodesShouldExportNodes( + GeneratorExecutionContext context, + ISymbol exportedMemberSymbol + ) + { + var locations = exportedMemberSymbol.Locations; + var location = locations.FirstOrDefault(l => l.SourceTree != null) ?? locations.FirstOrDefault(); + bool isField = exportedMemberSymbol is IFieldSymbol; + + string message = $"Types not derived from Node should not export Node {(isField ? "fields" : "properties")}"; + + string description = $"{message}. Node export is only supported in Node-derived classes."; + + context.ReportDiagnostic(Diagnostic.Create( + new DiagnosticDescriptor(id: "GD0107", + title: message, + messageFormat: message, + category: "Usage", + DiagnosticSeverity.Error, + isEnabledByDefault: true, + description), + location, + location?.SourceTree?.FilePath)); + } + public static void ReportSignalDelegateMissingSuffix( GeneratorExecutionContext context, INamedTypeSymbol delegateSymbol) diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs index 5866db5144..c7fd45238d 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs @@ -32,7 +32,7 @@ namespace Godot.SourceGenerators disabledGenerators != null && disabledGenerators.Split(';').Contains(generatorName)); - public static bool InheritsFrom(this INamedTypeSymbol? symbol, string assemblyName, string typeFullName) + public static bool InheritsFrom(this ITypeSymbol? symbol, string assemblyName, string typeFullName) { while (symbol != null) { diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs index fc0bfbf084..253e24f092 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs @@ -170,6 +170,15 @@ namespace Godot.SourceGenerators continue; } + if (marshalType == MarshalType.GodotObjectOrDerived) + { + if (!symbol.InheritsFrom("GodotSharp", "Godot.Node") && + propertyType.InheritsFrom("GodotSharp", "Godot.Node")) + { + Common.ReportOnlyNodesShouldExportNodes(context, property); + } + } + var propertyDeclarationSyntax = property.DeclaringSyntaxReferences .Select(r => r.GetSyntax() as PropertyDeclarationSyntax).FirstOrDefault(); @@ -265,6 +274,15 @@ namespace Godot.SourceGenerators continue; } + if (marshalType == MarshalType.GodotObjectOrDerived) + { + if (!symbol.InheritsFrom("GodotSharp", "Godot.Node") && + fieldType.InheritsFrom("GodotSharp", "Godot.Node")) + { + Common.ReportOnlyNodesShouldExportNodes(context, field); + } + } + EqualsValueClauseSyntax? initializer = field.DeclaringSyntaxReferences .Select(r => r.GetSyntax()) .OfType<VariableDeclaratorSyntax>() diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs index 7b1d5c228a..1d17f3d4f5 100644 --- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs +++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs @@ -1,5 +1,7 @@ using System; +using System.Linq; using Microsoft.Build.Construction; +using Microsoft.Build.Locator; namespace GodotTools.ProjectEditor { @@ -19,15 +21,18 @@ namespace GodotTools.ProjectEditor public static class ProjectUtils { - public static void MSBuildLocatorRegisterDefaults(out Version version, out string path) + public static void MSBuildLocatorRegisterLatest(out Version version, out string path) { - var instance = Microsoft.Build.Locator.MSBuildLocator.RegisterDefaults(); + var instance = MSBuildLocator.QueryVisualStudioInstances() + .OrderByDescending(x => x.Version) + .First(); + MSBuildLocator.RegisterInstance(instance); version = instance.Version; path = instance.MSBuildPath; } public static void MSBuildLocatorRegisterMSBuildPath(string msbuildPath) - => Microsoft.Build.Locator.MSBuildLocator.RegisterMSBuildPath(msbuildPath); + => MSBuildLocator.RegisterMSBuildPath(msbuildPath); public static MSBuildProject Open(string path) { diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs index a00c812c79..650afb4cdf 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs +++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs @@ -456,7 +456,7 @@ namespace GodotTools var dotNetSdkSearchVersion = Environment.Version; // First we try to find the .NET Sdk ourselves to make sure we get the - // correct version first (`RegisterDefaults` always picks the latest). + // correct version first, otherwise pick the latest. if (DotNetFinder.TryFindDotNetSdk(dotNetSdkSearchVersion, out var sdkVersion, out string sdkPath)) { if (Godot.OS.IsStdOutVerbose()) @@ -468,7 +468,7 @@ namespace GodotTools { try { - ProjectUtils.MSBuildLocatorRegisterDefaults(out sdkVersion, out sdkPath); + ProjectUtils.MSBuildLocatorRegisterLatest(out sdkVersion, out sdkPath); if (Godot.OS.IsStdOutVerbose()) Console.WriteLine($"Found .NET Sdk version '{sdkVersion}': {sdkPath}"); } @@ -497,7 +497,10 @@ namespace GodotTools AddChild(new HotReloadAssemblyWatcher { Name = "HotReloadAssemblyWatcher" }); - _menuPopup = new PopupMenu(); + _menuPopup = new PopupMenu + { + Name = "CSharpTools", + }; _menuPopup.Hide(); AddToolSubmenuItem("C#", _menuPopup); @@ -626,6 +629,12 @@ namespace GodotTools _editorSettings.SettingsChanged -= OnSettingsChanged; } + public override void _ExitTree() + { + _errorDialog?.QueueFree(); + _confirmCreateSlnDialog?.QueueFree(); + } + private void OnSettingsChanged() { // We want to force NoConsoleLogging to true when the VerbosityLevel is at Detailed or above. diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs index 93a83b701b..0cc89d78af 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs @@ -259,7 +259,7 @@ namespace Godot.NativeInterop } return new godot_callable(method /* Takes ownership of disposable */, - p_managed_callable.Target.GetInstanceId()); + p_managed_callable.Target?.GetInstanceId() ?? 0); } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs index 4ee452455e..215bb4df8c 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs @@ -182,8 +182,8 @@ namespace Godot } // Constants - private static readonly Vector2I _min = new Vector2I(int.MinValue, int.MinValue); - private static readonly Vector2I _max = new Vector2I(int.MaxValue, int.MaxValue); + private static readonly Vector2I _minValue = new Vector2I(int.MinValue, int.MinValue); + private static readonly Vector2I _maxValue = new Vector2I(int.MaxValue, int.MaxValue); private static readonly Vector2I _zero = new Vector2I(0, 0); private static readonly Vector2I _one = new Vector2I(1, 1); @@ -197,12 +197,12 @@ namespace Godot /// Min vector, a vector with all components equal to <see cref="int.MinValue"/>. Can be used as a negative integer equivalent of <see cref="Vector2.Inf"/>. /// </summary> /// <value>Equivalent to <c>new Vector2I(int.MinValue, int.MinValue)</c>.</value> - public static Vector2I Min { get { return _min; } } + public static Vector2I MinValue { get { return _minValue; } } /// <summary> /// Max vector, a vector with all components equal to <see cref="int.MaxValue"/>. Can be used as an integer equivalent of <see cref="Vector2.Inf"/>. /// </summary> /// <value>Equivalent to <c>new Vector2I(int.MaxValue, int.MaxValue)</c>.</value> - public static Vector2I Max { get { return _max; } } + public static Vector2I MaxValue { get { return _maxValue; } } /// <summary> /// Zero vector, a vector with all components set to <c>0</c>. diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs index db8ceb30e9..fe74ec8884 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs @@ -193,8 +193,8 @@ namespace Godot } // Constants - private static readonly Vector3I _min = new Vector3I(int.MinValue, int.MinValue, int.MinValue); - private static readonly Vector3I _max = new Vector3I(int.MaxValue, int.MaxValue, int.MaxValue); + private static readonly Vector3I _minValue = new Vector3I(int.MinValue, int.MinValue, int.MinValue); + private static readonly Vector3I _maxValue = new Vector3I(int.MaxValue, int.MaxValue, int.MaxValue); private static readonly Vector3I _zero = new Vector3I(0, 0, 0); private static readonly Vector3I _one = new Vector3I(1, 1, 1); @@ -210,12 +210,12 @@ namespace Godot /// Min vector, a vector with all components equal to <see cref="int.MinValue"/>. Can be used as a negative integer equivalent of <see cref="Vector3.Inf"/>. /// </summary> /// <value>Equivalent to <c>new Vector3I(int.MinValue, int.MinValue, int.MinValue)</c>.</value> - public static Vector3I Min { get { return _min; } } + public static Vector3I MinValue { get { return _minValue; } } /// <summary> /// Max vector, a vector with all components equal to <see cref="int.MaxValue"/>. Can be used as an integer equivalent of <see cref="Vector3.Inf"/>. /// </summary> /// <value>Equivalent to <c>new Vector3I(int.MaxValue, int.MaxValue, int.MaxValue)</c>.</value> - public static Vector3I Max { get { return _max; } } + public static Vector3I MaxValue { get { return _maxValue; } } /// <summary> /// Zero vector, a vector with all components set to <c>0</c>. diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs index e75e996b04..a0a4393523 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs @@ -228,8 +228,8 @@ namespace Godot } // Constants - private static readonly Vector4I _min = new Vector4I(int.MinValue, int.MinValue, int.MinValue, int.MinValue); - private static readonly Vector4I _max = new Vector4I(int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue); + private static readonly Vector4I _minValue = new Vector4I(int.MinValue, int.MinValue, int.MinValue, int.MinValue); + private static readonly Vector4I _maxValue = new Vector4I(int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue); private static readonly Vector4I _zero = new Vector4I(0, 0, 0, 0); private static readonly Vector4I _one = new Vector4I(1, 1, 1, 1); @@ -238,12 +238,12 @@ namespace Godot /// Min vector, a vector with all components equal to <see cref="int.MinValue"/>. Can be used as a negative integer equivalent of <see cref="Vector4.Inf"/>. /// </summary> /// <value>Equivalent to <c>new Vector4I(int.MinValue, int.MinValue, int.MinValue, int.MinValue)</c>.</value> - public static Vector4I Min { get { return _min; } } + public static Vector4I MinValue { get { return _minValue; } } /// <summary> /// Max vector, a vector with all components equal to <see cref="int.MaxValue"/>. Can be used as an integer equivalent of <see cref="Vector4.Inf"/>. /// </summary> /// <value>Equivalent to <c>new Vector4I(int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue)</c>.</value> - public static Vector4I Max { get { return _max; } } + public static Vector4I MaxValue { get { return _maxValue; } } /// <summary> /// Zero vector, a vector with all components set to <c>0</c>. diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index ca2ad315a7..3eb746677d 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -556,12 +556,6 @@ GDMono::GDMono() { GDMono::~GDMono() { finalizing_scripts_domain = true; - if (is_runtime_initialized()) { - if (GDMonoCache::godot_api_cache_updated) { - GDMonoCache::managed_callbacks.DisposablesTracker_OnGodotShuttingDown(); - } - } - if (hostfxr_dll_handle) { OS::get_singleton()->close_dynamic_library(hostfxr_dll_handle); } diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp index 5ef0298eb4..ca1034dcc0 100644 --- a/modules/navigation/nav_map.cpp +++ b/modules/navigation/nav_map.cpp @@ -1125,6 +1125,7 @@ void NavMap::_update_rvo_obstacles_tree_2d() { rvo_2d_vertices.reserve(_obstacle_vertices.size()); uint32_t _obstacle_avoidance_layers = obstacle->get_avoidance_layers(); + real_t _obstacle_height = obstacle->get_height(); for (const Vector3 &_obstacle_vertex : _obstacle_vertices) { rvo_2d_vertices.push_back(RVO2D::Vector2(_obstacle_vertex.x + _obstacle_position.x, _obstacle_vertex.z + _obstacle_position.z)); @@ -1135,6 +1136,9 @@ void NavMap::_update_rvo_obstacles_tree_2d() { for (size_t i = 0; i < rvo_2d_vertices.size(); i++) { RVO2D::Obstacle2D *rvo_2d_obstacle = new RVO2D::Obstacle2D(); rvo_2d_obstacle->point_ = rvo_2d_vertices[i]; + rvo_2d_obstacle->height_ = _obstacle_height; + rvo_2d_obstacle->elevation_ = _obstacle_position.y; + rvo_2d_obstacle->avoidance_layers_ = _obstacle_avoidance_layers; if (i != 0) { diff --git a/modules/navigation/nav_mesh_generator_2d.cpp b/modules/navigation/nav_mesh_generator_2d.cpp index 089744c8bd..f8c12935b4 100644 --- a/modules/navigation/nav_mesh_generator_2d.cpp +++ b/modules/navigation/nav_mesh_generator_2d.cpp @@ -587,6 +587,9 @@ void NavMeshGenerator2D::generator_parse_tilemap_node(const Ref<NavigationPolygo const Vector2i &cell = used_cells[used_cell_index]; const TileData *tile_data = tilemap->get_cell_tile_data(tilemap_layer, cell, false); + if (tile_data == nullptr) { + continue; + } Transform2D tile_transform; tile_transform.set_origin(tilemap->map_to_local(cell)); @@ -597,10 +600,19 @@ void NavMeshGenerator2D::generator_parse_tilemap_node(const Ref<NavigationPolygo Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(tilemap_layer); if (navigation_polygon.is_valid()) { for (int outline_index = 0; outline_index < navigation_polygon->get_outline_count(); outline_index++) { - Vector<Vector2> traversable_outline = navigation_polygon->get_outline(outline_index); + const Vector<Vector2> &navigation_polygon_outline = navigation_polygon->get_outline(outline_index); + if (navigation_polygon_outline.size() == 0) { + continue; + } + + Vector<Vector2> traversable_outline; + traversable_outline.resize(navigation_polygon_outline.size()); + + const Vector2 *navigation_polygon_outline_ptr = navigation_polygon_outline.ptr(); + Vector2 *traversable_outline_ptrw = traversable_outline.ptrw(); for (int traversable_outline_index = 0; traversable_outline_index < traversable_outline.size(); traversable_outline_index++) { - traversable_outline.write[traversable_outline_index] = tile_transform_offset.xform(traversable_outline[traversable_outline_index]); + traversable_outline_ptrw[traversable_outline_index] = tile_transform_offset.xform(navigation_polygon_outline_ptr[traversable_outline_index]); } p_source_geometry_data->_add_traversable_outline(traversable_outline); @@ -610,10 +622,19 @@ void NavMeshGenerator2D::generator_parse_tilemap_node(const Ref<NavigationPolygo if (physics_layers_count > 0 && (parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_STATIC_COLLIDERS || parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_BOTH) && (tile_set->get_physics_layer_collision_layer(tilemap_layer) & parsed_collision_mask)) { for (int collision_polygon_index = 0; collision_polygon_index < tile_data->get_collision_polygons_count(tilemap_layer); collision_polygon_index++) { - Vector<Vector2> obstruction_outline = tile_data->get_collision_polygon_points(tilemap_layer, collision_polygon_index); + const Vector<Vector2> &collision_polygon_points = tile_data->get_collision_polygon_points(tilemap_layer, collision_polygon_index); + if (collision_polygon_points.size() == 0) { + continue; + } + + Vector<Vector2> obstruction_outline; + obstruction_outline.resize(collision_polygon_points.size()); + + const Vector2 *collision_polygon_points_ptr = collision_polygon_points.ptr(); + Vector2 *obstruction_outline_ptrw = obstruction_outline.ptrw(); for (int obstruction_outline_index = 0; obstruction_outline_index < obstruction_outline.size(); obstruction_outline_index++) { - obstruction_outline.write[obstruction_outline_index] = tile_transform_offset.xform(obstruction_outline[obstruction_outline_index]); + obstruction_outline_ptrw[obstruction_outline_index] = tile_transform_offset.xform(collision_polygon_points_ptr[obstruction_outline_index]); } p_source_geometry_data->_add_obstruction_outline(obstruction_outline); diff --git a/modules/navigation/nav_mesh_generator_3d.cpp b/modules/navigation/nav_mesh_generator_3d.cpp index 5de1c4cba9..8719801c72 100644 --- a/modules/navigation/nav_mesh_generator_3d.cpp +++ b/modules/navigation/nav_mesh_generator_3d.cpp @@ -384,33 +384,23 @@ void NavMeshGenerator3D::generator_parse_staticbody3d_node(const Ref<NavigationM const Vector<real_t> &map_data = heightmap_shape->get_map_data(); Vector2 heightmap_gridsize(heightmap_width - 1, heightmap_depth - 1); - Vector2 start = heightmap_gridsize * -0.5; + Vector3 start = Vector3(heightmap_gridsize.x, 0, heightmap_gridsize.y) * -0.5; Vector<Vector3> vertex_array; vertex_array.resize((heightmap_depth - 1) * (heightmap_width - 1) * 6); - int map_data_current_index = 0; - - for (int d = 0; d < heightmap_depth; d++) { - for (int w = 0; w < heightmap_width; w++) { - if (map_data_current_index + 1 + heightmap_depth < map_data.size()) { - float top_left_height = map_data[map_data_current_index]; - float top_right_height = map_data[map_data_current_index + 1]; - float bottom_left_height = map_data[map_data_current_index + heightmap_depth]; - float bottom_right_height = map_data[map_data_current_index + 1 + heightmap_depth]; - - Vector3 top_left = Vector3(start.x + w, top_left_height, start.y + d); - Vector3 top_right = Vector3(start.x + w + 1.0, top_right_height, start.y + d); - Vector3 bottom_left = Vector3(start.x + w, bottom_left_height, start.y + d + 1.0); - Vector3 bottom_right = Vector3(start.x + w + 1.0, bottom_right_height, start.y + d + 1.0); - - vertex_array.push_back(top_right); - vertex_array.push_back(bottom_left); - vertex_array.push_back(top_left); - vertex_array.push_back(top_right); - vertex_array.push_back(bottom_right); - vertex_array.push_back(bottom_left); - } - map_data_current_index += 1; + Vector3 *vertex_array_ptrw = vertex_array.ptrw(); + const real_t *map_data_ptr = map_data.ptr(); + int vertex_index = 0; + + for (int d = 0; d < heightmap_depth - 1; d++) { + for (int w = 0; w < heightmap_width - 1; w++) { + vertex_array_ptrw[vertex_index] = start + Vector3(w, map_data_ptr[(heightmap_width * d) + w], d); + vertex_array_ptrw[vertex_index + 1] = start + Vector3(w + 1, map_data_ptr[(heightmap_width * d) + w + 1], d); + vertex_array_ptrw[vertex_index + 2] = start + Vector3(w, map_data_ptr[(heightmap_width * d) + heightmap_width + w], d + 1); + vertex_array_ptrw[vertex_index + 3] = start + Vector3(w + 1, map_data_ptr[(heightmap_width * d) + w + 1], d); + vertex_array_ptrw[vertex_index + 4] = start + Vector3(w + 1, map_data_ptr[(heightmap_width * d) + heightmap_width + w + 1], d + 1); + vertex_array_ptrw[vertex_index + 5] = start + Vector3(w, map_data_ptr[(heightmap_width * d) + heightmap_width + w], d + 1); + vertex_index += 6; } } if (vertex_array.size() > 0) { @@ -540,33 +530,23 @@ void NavMeshGenerator3D::generator_parse_gridmap_node(const Ref<NavigationMesh> const Vector<real_t> &map_data = dict["heights"]; Vector2 heightmap_gridsize(heightmap_width - 1, heightmap_depth - 1); - Vector2 start = heightmap_gridsize * -0.5; + Vector3 start = Vector3(heightmap_gridsize.x, 0, heightmap_gridsize.y) * -0.5; Vector<Vector3> vertex_array; vertex_array.resize((heightmap_depth - 1) * (heightmap_width - 1) * 6); - int map_data_current_index = 0; - - for (int d = 0; d < heightmap_depth; d++) { - for (int w = 0; w < heightmap_width; w++) { - if (map_data_current_index + 1 + heightmap_depth < map_data.size()) { - float top_left_height = map_data[map_data_current_index]; - float top_right_height = map_data[map_data_current_index + 1]; - float bottom_left_height = map_data[map_data_current_index + heightmap_depth]; - float bottom_right_height = map_data[map_data_current_index + 1 + heightmap_depth]; - - Vector3 top_left = Vector3(start.x + w, top_left_height, start.y + d); - Vector3 top_right = Vector3(start.x + w + 1.0, top_right_height, start.y + d); - Vector3 bottom_left = Vector3(start.x + w, bottom_left_height, start.y + d + 1.0); - Vector3 bottom_right = Vector3(start.x + w + 1.0, bottom_right_height, start.y + d + 1.0); - - vertex_array.push_back(top_right); - vertex_array.push_back(bottom_left); - vertex_array.push_back(top_left); - vertex_array.push_back(top_right); - vertex_array.push_back(bottom_right); - vertex_array.push_back(bottom_left); - } - map_data_current_index += 1; + Vector3 *vertex_array_ptrw = vertex_array.ptrw(); + const real_t *map_data_ptr = map_data.ptr(); + int vertex_index = 0; + + for (int d = 0; d < heightmap_depth - 1; d++) { + for (int w = 0; w < heightmap_width - 1; w++) { + vertex_array_ptrw[vertex_index] = start + Vector3(w, map_data_ptr[(heightmap_width * d) + w], d); + vertex_array_ptrw[vertex_index + 1] = start + Vector3(w + 1, map_data_ptr[(heightmap_width * d) + w + 1], d); + vertex_array_ptrw[vertex_index + 2] = start + Vector3(w, map_data_ptr[(heightmap_width * d) + heightmap_width + w], d + 1); + vertex_array_ptrw[vertex_index + 3] = start + Vector3(w + 1, map_data_ptr[(heightmap_width * d) + w + 1], d); + vertex_array_ptrw[vertex_index + 4] = start + Vector3(w + 1, map_data_ptr[(heightmap_width * d) + heightmap_width + w + 1], d + 1); + vertex_array_ptrw[vertex_index + 5] = start + Vector3(w, map_data_ptr[(heightmap_width * d) + heightmap_width + w], d + 1); + vertex_index += 6; } } if (vertex_array.size() > 0) { diff --git a/modules/noise/fastnoise_lite.cpp b/modules/noise/fastnoise_lite.cpp index 4aea98c4de..1b0ef6506b 100644 --- a/modules/noise/fastnoise_lite.cpp +++ b/modules/noise/fastnoise_lite.cpp @@ -416,8 +416,8 @@ void FastNoiseLite::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "noise_type", PROPERTY_HINT_ENUM, "Simplex,Simplex Smooth,Cellular,Perlin,Value Cubic,Value"), "set_noise_type", "get_noise_type"); ADD_PROPERTY(PropertyInfo(Variant::INT, "seed"), "set_seed", "get_seed"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frequency", PROPERTY_HINT_RANGE, ".0001,1,.0001"), "set_frequency", "get_frequency"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "offset", PROPERTY_HINT_RANGE, "-999999999,999999999,0.01"), "set_offset", "get_offset"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frequency", PROPERTY_HINT_RANGE, ".0001,1,.0001,exp"), "set_frequency", "get_frequency"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "offset", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_less,or_greater"), "set_offset", "get_offset"); ADD_GROUP("Fractal", "fractal_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "fractal_type", PROPERTY_HINT_ENUM, "None,FBM,Ridged,Ping-Pong"), "set_fractal_type", "get_fractal_type"); diff --git a/modules/noise/noise.cpp b/modules/noise/noise.cpp index 1115d92f58..9b9fd640f4 100644 --- a/modules/noise/noise.cpp +++ b/modules/noise/noise.cpp @@ -54,6 +54,9 @@ Vector<Ref<Image>> Noise::_get_seamless_image(int p_width, int p_height, int p_d Ref<Image> Noise::get_seamless_image(int p_width, int p_height, bool p_invert, bool p_in_3d_space, real_t p_blend_skirt, bool p_normalize) const { Vector<Ref<Image>> images = _get_seamless_image(p_width, p_height, 1, p_invert, p_in_3d_space, p_blend_skirt, p_normalize); + if (images.size() == 0) { + return Ref<Image>(); + } return images[0]; } @@ -163,6 +166,9 @@ Vector<Ref<Image>> Noise::_get_image(int p_width, int p_height, int p_depth, boo Ref<Image> Noise::get_image(int p_width, int p_height, bool p_invert, bool p_in_3d_space, bool p_normalize) const { Vector<Ref<Image>> images = _get_image(p_width, p_height, 1, p_invert, p_in_3d_space, p_normalize); + if (images.is_empty()) { + return Ref<Image>(); + } return images[0]; } diff --git a/modules/openxr/SCsub b/modules/openxr/SCsub index 2ccfe46062..c64b6de78c 100644 --- a/modules/openxr/SCsub +++ b/modules/openxr/SCsub @@ -70,7 +70,6 @@ if env["builtin_openxr"]: # On Android the openxr_loader is provided by separate plugins for each device # Build the engine using object files khrloader_obj = [] - env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/xr_generated_dispatch_table.c") env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/xr_generated_dispatch_table_core.c") env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/common/filesystem_utils.cpp") diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp index d0e958164d..3c606de670 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -289,7 +289,7 @@ bool OpenXRAPI::create_instance() { for (KeyValue<String, bool *> &requested_extension : requested_extensions) { if (!is_extension_supported(requested_extension.key)) { if (requested_extension.value == nullptr) { - // Null means this is a manditory extension so we fail. + // Null means this is a mandatory extension so we fail. ERR_FAIL_V_MSG(false, String("OpenXR: OpenXR Runtime does not support ") + requested_extension.key + String(" extension!")); } else { // Set this extension as not supported. @@ -804,6 +804,7 @@ bool OpenXRAPI::create_swapchains() { */ Size2 recommended_size = get_recommended_target_size(); + uint32_t sample_count = 1; // We start with our color swapchain... { @@ -827,7 +828,7 @@ bool OpenXRAPI::create_swapchains() { print_verbose(String("Using color swap chain format:") + get_swapchain_format_name(swapchain_format_to_use)); } - if (!create_swapchain(XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT | XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT, swapchain_format_to_use, recommended_size.width, recommended_size.height, view_configuration_views[0].recommendedSwapchainSampleCount, view_count, swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain, &swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain_graphics_data)) { + if (!create_swapchain(XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT | XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT, swapchain_format_to_use, recommended_size.width, recommended_size.height, sample_count, view_count, swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain, &swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain_graphics_data)) { return false; } } @@ -863,7 +864,7 @@ bool OpenXRAPI::create_swapchains() { // Note, if VK_FORMAT_D32_SFLOAT is used here but we're using the forward+ renderer, we should probably output a warning. - if (!create_swapchain(XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, swapchain_format_to_use, recommended_size.width, recommended_size.height, view_configuration_views[0].recommendedSwapchainSampleCount, view_count, swapchains[OPENXR_SWAPCHAIN_DEPTH].swapchain, &swapchains[OPENXR_SWAPCHAIN_DEPTH].swapchain_graphics_data)) { + if (!create_swapchain(XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, swapchain_format_to_use, recommended_size.width, recommended_size.height, sample_count, view_count, swapchains[OPENXR_SWAPCHAIN_DEPTH].swapchain, &swapchains[OPENXR_SWAPCHAIN_DEPTH].swapchain_graphics_data)) { return false; } diff --git a/modules/text_server_adv/gdextension_build/methods.py b/modules/text_server_adv/gdextension_build/methods.py index 3c5229462c..e58bc3abec 100644 --- a/modules/text_server_adv/gdextension_build/methods.py +++ b/modules/text_server_adv/gdextension_build/methods.py @@ -99,8 +99,8 @@ def make_icu_data(target, source, env): def write_macos_plist(target, binary_name, identifier, name): - os.makedirs(f"{target}/Resourece/", exist_ok=True) - f = open(f"{target}/Resourece/Info.plist", "w") + os.makedirs(f"{target}/Resource/", exist_ok=True) + f = open(f"{target}/Resource/Info.plist", "w") f.write(f'<?xml version="1.0" encoding="UTF-8"?>\n') f.write(f'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n') diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index 16046ef053..6d0a398218 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -338,6 +338,7 @@ _FORCE_INLINE_ bool is_connected_to_prev(char32_t p_chr, char32_t p_pchr) { /*************************************************************************/ bool TextServerAdvanced::icu_data_loaded = false; +PackedByteArray TextServerAdvanced::icu_data; bool TextServerAdvanced::_has_feature(Feature p_feature) const { switch (p_feature) { @@ -438,7 +439,7 @@ bool TextServerAdvanced::_load_support_data(const String &p_filename) { return false; } uint64_t len = f->get_length(); - PackedByteArray icu_data = f->get_buffer(len); + icu_data = f->get_buffer(len); UErrorCode err = U_ZERO_ERROR; udata_setCommonData(icu_data.ptr(), &err); @@ -476,10 +477,10 @@ bool TextServerAdvanced::_save_support_data(const String &p_filename) const { return false; } - PackedByteArray icu_data; - icu_data.resize(U_ICUDATA_SIZE); - memcpy(icu_data.ptrw(), U_ICUDATA_ENTRY_POINT, U_ICUDATA_SIZE); - f->store_buffer(icu_data); + PackedByteArray icu_data_static; + icu_data_static.resize(U_ICUDATA_SIZE); + memcpy(icu_data_static.ptrw(), U_ICUDATA_ENTRY_POINT, U_ICUDATA_SIZE); + f->store_buffer(icu_data_static); return true; #else @@ -1112,14 +1113,14 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma case FT_PIXEL_MODE_LCD: { int ofs_color = i * bitmap.pitch + (j * 3); if (p_bgra) { - wr[ofs + 0] = bitmap.buffer[ofs_color + 0]; + wr[ofs + 0] = bitmap.buffer[ofs_color + 2]; wr[ofs + 1] = bitmap.buffer[ofs_color + 1]; - wr[ofs + 2] = bitmap.buffer[ofs_color + 2]; + wr[ofs + 2] = bitmap.buffer[ofs_color + 0]; wr[ofs + 3] = 255; } else { - wr[ofs + 0] = bitmap.buffer[ofs_color + 2]; + wr[ofs + 0] = bitmap.buffer[ofs_color + 0]; wr[ofs + 1] = bitmap.buffer[ofs_color + 1]; - wr[ofs + 2] = bitmap.buffer[ofs_color + 0]; + wr[ofs + 2] = bitmap.buffer[ofs_color + 2]; wr[ofs + 3] = 255; } } break; @@ -4311,6 +4312,8 @@ bool TextServerAdvanced::_shaped_text_resize_object(const RID &p_shaped, const V sd->width += gl.advance * gl.repeat; } } + sd->sort_valid = false; + sd->glyphs_logical.clear(); _realign(sd); } return true; diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index f1932d9c50..cbd2911aaf 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -158,6 +158,7 @@ class TextServerAdvanced : public TextServerExtension { // ICU support data. static bool icu_data_loaded; + static PackedByteArray icu_data; mutable USet *allowed = nullptr; mutable USpoofChecker *sc_spoof = nullptr; mutable USpoofChecker *sc_conf = nullptr; @@ -680,11 +681,7 @@ class TextServerAdvanced : public TextServerExtension { _FORCE_INLINE_ bool operator()(const Glyph &l, const Glyph &r) const { if (l.start == r.start) { if (l.count == r.count) { - if ((l.flags & TextServer::GRAPHEME_IS_VIRTUAL) == TextServer::GRAPHEME_IS_VIRTUAL) { - return false; - } else { - return true; - } + return (l.flags & TextServer::GRAPHEME_IS_VIRTUAL) < (r.flags & TextServer::GRAPHEME_IS_VIRTUAL); } return l.count > r.count; // Sort first glyph with count & flags, order of the rest are irrelevant. } else { diff --git a/modules/text_server_fb/gdextension_build/methods.py b/modules/text_server_fb/gdextension_build/methods.py index 3c5229462c..e58bc3abec 100644 --- a/modules/text_server_fb/gdextension_build/methods.py +++ b/modules/text_server_fb/gdextension_build/methods.py @@ -99,8 +99,8 @@ def make_icu_data(target, source, env): def write_macos_plist(target, binary_name, identifier, name): - os.makedirs(f"{target}/Resourece/", exist_ok=True) - f = open(f"{target}/Resourece/Info.plist", "w") + os.makedirs(f"{target}/Resource/", exist_ok=True) + f = open(f"{target}/Resource/Info.plist", "w") f.write(f'<?xml version="1.0" encoding="UTF-8"?>\n') f.write(f'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n') diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index eb247cdcbe..f12275d10c 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -548,14 +548,14 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma case FT_PIXEL_MODE_LCD: { int ofs_color = i * bitmap.pitch + (j * 3); if (p_bgra) { - wr[ofs + 0] = bitmap.buffer[ofs_color + 0]; + wr[ofs + 0] = bitmap.buffer[ofs_color + 2]; wr[ofs + 1] = bitmap.buffer[ofs_color + 1]; - wr[ofs + 2] = bitmap.buffer[ofs_color + 2]; + wr[ofs + 2] = bitmap.buffer[ofs_color + 0]; wr[ofs + 3] = 255; } else { - wr[ofs + 0] = bitmap.buffer[ofs_color + 2]; + wr[ofs + 0] = bitmap.buffer[ofs_color + 0]; wr[ofs + 1] = bitmap.buffer[ofs_color + 1]; - wr[ofs + 2] = bitmap.buffer[ofs_color + 0]; + wr[ofs + 2] = bitmap.buffer[ofs_color + 2]; wr[ofs + 3] = 255; } } break; diff --git a/modules/vorbis/audio_stream_ogg_vorbis.cpp b/modules/vorbis/audio_stream_ogg_vorbis.cpp index 8a265ffaf3..7ec0b697bf 100644 --- a/modules/vorbis/audio_stream_ogg_vorbis.cpp +++ b/modules/vorbis/audio_stream_ogg_vorbis.cpp @@ -144,7 +144,7 @@ int AudioStreamPlaybackOggVorbis::_mix_internal(AudioFrame *p_buffer, int p_fram } int AudioStreamPlaybackOggVorbis::_mix_frames_vorbis(AudioFrame *p_buffer, int p_frames) { - ERR_FAIL_COND_V(!ready, 0); + ERR_FAIL_COND_V(!ready, p_frames); if (!have_samples_left) { ogg_packet *packet = nullptr; int err; @@ -156,10 +156,10 @@ int AudioStreamPlaybackOggVorbis::_mix_frames_vorbis(AudioFrame *p_buffer, int p } err = vorbis_synthesis(&block, packet); - ERR_FAIL_COND_V_MSG(err != 0, 0, "Error during vorbis synthesis " + itos(err)); + ERR_FAIL_COND_V_MSG(err != 0, p_frames, "Error during vorbis synthesis " + itos(err)); err = vorbis_synthesis_blockin(&dsp_state, &block); - ERR_FAIL_COND_V_MSG(err != 0, 0, "Error during vorbis block processing " + itos(err)); + ERR_FAIL_COND_V_MSG(err != 0, p_frames, "Error during vorbis block processing " + itos(err)); have_packets_left = !packet->e_o_s; } diff --git a/modules/webp/webp_common.cpp b/modules/webp/webp_common.cpp index bc34a25733..3a2ac5a90e 100644 --- a/modules/webp/webp_common.cpp +++ b/modules/webp/webp_common.cpp @@ -59,6 +59,10 @@ Vector<uint8_t> _webp_packer(const Ref<Image> &p_image, float p_quality, bool p_ compression_method = CLAMP(compression_method, 0, 6); Ref<Image> img = p_image->duplicate(); + if (img->is_compressed()) { + Error error = img->decompress(); + ERR_FAIL_COND_V_MSG(error != OK, Vector<uint8_t>(), "Couldn't decompress image."); + } if (img->detect_alpha()) { img->convert(Image::FORMAT_RGBA8); } else { |
