diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/config/project_settings.cpp | 5 | ||||
-rw-r--r-- | core/extension/gdextension.cpp | 18 | ||||
-rw-r--r-- | core/input/input.cpp | 119 | ||||
-rw-r--r-- | core/input/input.h | 19 | ||||
-rw-r--r-- | core/input/input_map.cpp | 18 | ||||
-rw-r--r-- | core/input/input_map.h | 5 | ||||
-rw-r--r-- | core/io/resource.cpp | 4 | ||||
-rw-r--r-- | core/io/resource.h | 1 | ||||
-rw-r--r-- | core/io/resource_format_binary.cpp | 2 | ||||
-rw-r--r-- | core/io/resource_importer.h | 1 | ||||
-rw-r--r-- | core/io/resource_loader.cpp | 4 | ||||
-rw-r--r-- | core/object/object.cpp | 1 | ||||
-rw-r--r-- | core/object/object.h | 10 | ||||
-rw-r--r-- | core/object/script_language.cpp | 37 | ||||
-rw-r--r-- | core/object/script_language.h | 7 | ||||
-rw-r--r-- | core/object/undo_redo.cpp | 8 | ||||
-rw-r--r-- | core/object/undo_redo.h | 2 | ||||
-rw-r--r-- | core/object/worker_thread_pool.cpp | 9 | ||||
-rw-r--r-- | core/object/worker_thread_pool.h | 1 | ||||
-rw-r--r-- | core/os/os.cpp | 6 | ||||
-rw-r--r-- | core/string/string_name.cpp | 2 | ||||
-rw-r--r-- | core/string/translation.cpp | 10 | ||||
-rw-r--r-- | core/string/ustring.cpp | 7 | ||||
-rw-r--r-- | core/string/ustring.h | 2 | ||||
-rw-r--r-- | core/variant/variant.cpp | 6 |
25 files changed, 213 insertions, 91 deletions
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index cbbfe3de75..93934f2320 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -852,8 +852,8 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const RBMap<S } if (!p_custom_features.is_empty()) { + // Store how many properties are saved, add one for custom features, which must always go first. file->store_32(count + 1); - //store how many properties are saved, add one for custom featuers, which must always go first String key = CoreStringNames::get_singleton()->_custom_features; file->store_pascal_string(key); @@ -870,7 +870,8 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const RBMap<S file->store_buffer(buff.ptr(), buff.size()); } else { - file->store_32(count); //store how many properties are saved + // Store how many properties are saved. + file->store_32(count); } for (const KeyValue<String, List<String>> &E : p_props) { diff --git a/core/extension/gdextension.cpp b/core/extension/gdextension.cpp index 6c3d0a6148..2bac1f6592 100644 --- a/core/extension/gdextension.cpp +++ b/core/extension/gdextension.cpp @@ -678,12 +678,11 @@ GDExtensionInterfaceFunctionPtr GDExtension::get_interface_function(StringName p } Error GDExtension::open_library(const String &p_path, const String &p_entry_symbol) { - library_path = p_path; - String abs_path = ProjectSettings::get_singleton()->globalize_path(p_path); #if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED) // If running on the editor on Windows, we copy the library and open the copy. // This is so the original file isn't locked and can be updated by a compiler. + bool library_copied = false; if (Engine::get_singleton()->is_editor_hint()) { if (!FileAccess::exists(abs_path)) { ERR_PRINT("GDExtension library not found: " + library_path); @@ -705,6 +704,7 @@ Error GDExtension::open_library(const String &p_path, const String &p_entry_symb return ERR_CANT_CREATE; } FileAccess::set_hidden_attribute(copy_path, true); + library_copied = true; // Save the copied path so it can be deleted later. temp_lib_path = copy_path; @@ -714,12 +714,20 @@ Error GDExtension::open_library(const String &p_path, const String &p_entry_symb } #endif - Error err = OS::get_singleton()->open_dynamic_library(abs_path, library, true); + Error err = OS::get_singleton()->open_dynamic_library(abs_path, library, true, &library_path); if (err != OK) { ERR_PRINT("GDExtension dynamic library not found: " + abs_path); return err; } +#if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED) + // If we copied the file, let's change the library path to point at the original, + // because that's what we want to check to see if it's changed. + if (library_copied) { + library_path = library_path.get_base_dir() + "\\" + p_path.get_file(); + } +#endif + void *entry_funcptr = nullptr; err = OS::get_singleton()->get_dynamic_library_symbol_handle(library, p_entry_symbol, entry_funcptr, false); @@ -904,6 +912,8 @@ Error GDExtensionResourceLoader::load_gdextension_resource(const String &p_path, return ERR_FILE_NOT_FOUND; } + bool is_static_library = library_path.ends_with(".a") || library_path.ends_with(".xcframework"); + if (!library_path.is_resource_file() && !library_path.is_absolute_path()) { library_path = p_path.get_base_dir().path_join(library_path); } @@ -920,7 +930,7 @@ Error GDExtensionResourceLoader::load_gdextension_resource(const String &p_path, FileAccess::get_modified_time(library_path)); #endif - err = p_extension->open_library(library_path, entry_symbol); + err = p_extension->open_library(is_static_library ? String() : library_path, entry_symbol); if (err != OK) { #if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED) // If the DLL fails to load, make sure that temporary DLL copies are cleaned up. diff --git a/core/input/input.cpp b/core/input/input.cpp index 2d48bdd4cf..257452b3d8 100644 --- a/core/input/input.cpp +++ b/core/input/input.cpp @@ -695,53 +695,34 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em } for (const KeyValue<StringName, InputMap::Action> &E : InputMap::get_singleton()->get_action_map()) { - if (InputMap::get_singleton()->event_is_action(p_event, E.key)) { - Action &action = action_state[E.key]; - bool is_joypad_axis = jm.is_valid(); - bool is_pressed = false; - if (!p_event->is_echo()) { - if (p_event->is_action_pressed(E.key)) { - bool is_joypad_axis_valid_zone_enter = false; - if (is_joypad_axis) { - if (!action.axis_pressed) { - is_joypad_axis_valid_zone_enter = true; - action.pressed++; - action.axis_pressed = true; - } - } else { - action.pressed++; - } - if (action.pressed == 1 && (is_joypad_axis_valid_zone_enter || !is_joypad_axis)) { - action.pressed_physics_frame = Engine::get_singleton()->get_physics_frames(); - action.pressed_process_frame = Engine::get_singleton()->get_process_frames(); - } - is_pressed = true; - } else { - bool is_released = true; - if (is_joypad_axis) { - if (action.axis_pressed) { - action.axis_pressed = false; - } else { - is_released = false; - } - } + const int event_index = InputMap::get_singleton()->event_get_index(p_event, E.key); + if (event_index == -1) { + continue; + } - if (is_released) { - if (action.pressed == 1) { - action.released_physics_frame = Engine::get_singleton()->get_physics_frames(); - action.released_process_frame = Engine::get_singleton()->get_process_frames(); - } - action.pressed = MAX(action.pressed - 1, 0); - } + Action &action = action_state[E.key]; + if (!p_event->is_echo()) { + if (p_event->is_action_pressed(E.key)) { + if (!action.pressed) { + action.pressed_physics_frame = Engine::get_singleton()->get_physics_frames(); + action.pressed_process_frame = Engine::get_singleton()->get_process_frames(); } - action.exact = InputMap::get_singleton()->event_is_action(p_event, E.key, true); - } + action.pressed |= ((uint64_t)1 << event_index); + } else { + action.pressed &= ~((uint64_t)1 << event_index); + action.pressed &= ~(1 << MAX_EVENT); // Always release the event from action_press() method. - if (is_pressed || action.pressed == 0) { - action.strength = p_event->get_action_strength(E.key); - action.raw_strength = p_event->get_action_raw_strength(E.key); + if (!action.pressed) { + action.released_physics_frame = Engine::get_singleton()->get_physics_frames(); + action.released_process_frame = Engine::get_singleton()->get_process_frames(); + } + _update_action_strength(action, MAX_EVENT, 0.0); + _update_action_raw_strength(action, MAX_EVENT, 0.0); } + action.exact = InputMap::get_singleton()->event_is_action(p_event, E.key, true); } + _update_action_strength(action, event_index, p_event->get_action_strength(E.key)); + _update_action_raw_strength(action, event_index, p_event->get_action_raw_strength(E.key)); } if (event_dispatch_function) { @@ -858,13 +839,13 @@ void Input::action_press(const StringName &p_action, float p_strength) { // Create or retrieve existing action. Action &action = action_state[p_action]; - action.pressed++; - if (action.pressed == 1) { + if (!action.pressed) { action.pressed_physics_frame = Engine::get_singleton()->get_physics_frames(); action.pressed_process_frame = Engine::get_singleton()->get_process_frames(); } - action.strength = p_strength; - action.raw_strength = p_strength; + action.pressed |= 1 << MAX_EVENT; + _update_action_strength(action, MAX_EVENT, p_strength); + _update_action_raw_strength(action, MAX_EVENT, p_strength); action.exact = true; } @@ -872,13 +853,15 @@ void Input::action_release(const StringName &p_action) { // Create or retrieve existing action. Action &action = action_state[p_action]; - action.pressed--; - if (action.pressed == 0) { - action.released_physics_frame = Engine::get_singleton()->get_physics_frames(); - action.released_process_frame = Engine::get_singleton()->get_process_frames(); + action.pressed = 0; + action.strength = 0.0; + action.raw_strength = 0.0; + action.released_physics_frame = Engine::get_singleton()->get_physics_frames(); + action.released_process_frame = Engine::get_singleton()->get_process_frames(); + for (uint64_t i = 0; i <= MAX_EVENT; i++) { + action.strengths[i] = 0.0; + action.raw_strengths[i] = 0.0; } - action.strength = 0.0f; - action.raw_strength = 0.0f; action.exact = true; } @@ -1207,6 +1190,38 @@ void Input::_axis_event(int p_device, JoyAxis p_axis, float p_value) { parse_input_event(ievent); } +void Input::_update_action_strength(Action &p_action, int p_event_index, float p_strength) { + ERR_FAIL_INDEX(p_event_index, (int)MAX_EVENT + 1); + + float old_strength = p_action.strengths[p_event_index]; + p_action.strengths[p_event_index] = p_strength; + + if (p_strength > p_action.strength) { + p_action.strength = p_strength; + } else if (Math::is_equal_approx(old_strength, p_action.strength)) { + p_action.strength = p_strength; + for (uint64_t i = 0; i <= MAX_EVENT; i++) { + p_action.strength = MAX(p_action.strength, p_action.strengths[i]); + } + } +} + +void Input::_update_action_raw_strength(Action &p_action, int p_event_index, float p_strength) { + ERR_FAIL_INDEX(p_event_index, (int)MAX_EVENT + 1); + + float old_strength = p_action.raw_strengths[p_event_index]; + p_action.raw_strengths[p_event_index] = p_strength; + + if (p_strength > p_action.raw_strength) { + p_action.raw_strength = p_strength; + } else if (Math::is_equal_approx(old_strength, p_action.raw_strength)) { + p_action.raw_strength = p_strength; + for (uint64_t i = 0; i <= MAX_EVENT; i++) { + p_action.raw_strength = MAX(p_action.raw_strength, p_action.raw_strengths[i]); + } + } +} + Input::JoyEvent Input::_get_mapped_button_event(const JoyDeviceMapping &mapping, JoyButton p_button) { JoyEvent event; diff --git a/core/input/input.h b/core/input/input.h index bedc3fa0e3..dd613c4877 100644 --- a/core/input/input.h +++ b/core/input/input.h @@ -44,6 +44,8 @@ class Input : public Object { static Input *singleton; + static constexpr uint64_t MAX_EVENT = 31; + public: enum MouseMode { MOUSE_MODE_VISIBLE, @@ -103,11 +105,22 @@ private: uint64_t pressed_process_frame = UINT64_MAX; uint64_t released_physics_frame = UINT64_MAX; uint64_t released_process_frame = UINT64_MAX; - int pressed = 0; - bool axis_pressed = false; + uint64_t pressed = 0; bool exact = true; float strength = 0.0f; float raw_strength = 0.0f; + LocalVector<float> strengths; + LocalVector<float> raw_strengths; + + Action() { + strengths.resize(MAX_EVENT + 1); + raw_strengths.resize(MAX_EVENT + 1); + + for (uint64_t i = 0; i <= MAX_EVENT; i++) { + strengths[i] = 0.0; + raw_strengths[i] = 0.0; + } + } }; HashMap<StringName, Action> action_state; @@ -227,6 +240,8 @@ private: JoyAxis _get_output_axis(String output); void _button_event(int p_device, JoyButton p_index, bool p_pressed); void _axis_event(int p_device, JoyAxis p_axis, float p_value); + void _update_action_strength(Action &p_action, int p_event_index, float p_strength); + void _update_action_raw_strength(Action &p_action, int p_event_index, float p_strength); void _parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated); diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp index ddfde0e7cd..78b9ada884 100644 --- a/core/input/input_map.cpp +++ b/core/input/input_map.cpp @@ -127,16 +127,21 @@ List<StringName> InputMap::get_actions() const { return actions; } -List<Ref<InputEvent>>::Element *InputMap::_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool p_exact_match, bool *r_pressed, float *r_strength, float *r_raw_strength) const { +List<Ref<InputEvent>>::Element *InputMap::_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool p_exact_match, bool *r_pressed, float *r_strength, float *r_raw_strength, int *r_event_index) const { ERR_FAIL_COND_V(!p_event.is_valid(), nullptr); + int i = 0; for (List<Ref<InputEvent>>::Element *E = p_action.inputs.front(); E; E = E->next()) { int device = E->get()->get_device(); if (device == ALL_DEVICES || device == p_event->get_device()) { if (E->get()->action_match(p_event, p_exact_match, p_action.deadzone, r_pressed, r_strength, r_raw_strength)) { + if (r_event_index) { + *r_event_index = i; + } return E; } } + i++; } return nullptr; @@ -179,6 +184,7 @@ void InputMap::action_erase_event(const StringName &p_action, const Ref<InputEve List<Ref<InputEvent>>::Element *E = _find_event(input_map[p_action], p_event, true); if (E) { input_map[p_action].inputs.erase(E); + if (Input::get_singleton()->is_action_pressed(p_action)) { Input::get_singleton()->action_release(p_action); } @@ -216,7 +222,13 @@ bool InputMap::event_is_action(const Ref<InputEvent> &p_event, const StringName return event_get_action_status(p_event, p_action, p_exact_match); } -bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match, bool *r_pressed, float *r_strength, float *r_raw_strength) const { +int InputMap::event_get_index(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match) const { + int index = -1; + event_get_action_status(p_event, p_action, p_exact_match, nullptr, nullptr, nullptr, &index); + return index; +} + +bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match, bool *r_pressed, float *r_strength, float *r_raw_strength, int *r_event_index) const { HashMap<StringName, Action>::Iterator E = input_map.find(p_action); ERR_FAIL_COND_V_MSG(!E, false, suggest_actions(p_action)); @@ -236,7 +248,7 @@ bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const Str return input_event_action->get_action() == p_action; } - List<Ref<InputEvent>>::Element *event = _find_event(E->value, p_event, p_exact_match, r_pressed, r_strength, r_raw_strength); + List<Ref<InputEvent>>::Element *event = _find_event(E->value, p_event, p_exact_match, r_pressed, r_strength, r_raw_strength, r_event_index); return event != nullptr; } diff --git a/core/input/input_map.h b/core/input/input_map.h index b4d5beacb3..6407ea489e 100644 --- a/core/input/input_map.h +++ b/core/input/input_map.h @@ -61,7 +61,7 @@ private: HashMap<String, List<Ref<InputEvent>>> default_builtin_cache; HashMap<String, List<Ref<InputEvent>>> default_builtin_with_overrides_cache; - List<Ref<InputEvent>>::Element *_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool p_exact_match = false, bool *r_pressed = nullptr, float *r_strength = nullptr, float *r_raw_strength = nullptr) const; + List<Ref<InputEvent>>::Element *_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool p_exact_match = false, bool *r_pressed = nullptr, float *r_strength = nullptr, float *r_raw_strength = nullptr, int *r_event_index = nullptr) const; TypedArray<InputEvent> _action_get_events(const StringName &p_action); TypedArray<StringName> _get_actions(); @@ -86,7 +86,8 @@ public: const List<Ref<InputEvent>> *action_get_events(const StringName &p_action); bool event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match = false) const; - bool event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match = false, bool *r_pressed = nullptr, float *r_strength = nullptr, float *r_raw_strength = nullptr) const; + int event_get_index(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match = false) const; + bool event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match = false, bool *r_pressed = nullptr, float *r_strength = nullptr, float *r_raw_strength = nullptr, int *r_event_index = nullptr) const; const HashMap<StringName, Action> &get_action_map() const; void load_from_project_settings(); diff --git a/core/io/resource.cpp b/core/io/resource.cpp index e0d42a274a..64fa597a67 100644 --- a/core/io/resource.cpp +++ b/core/io/resource.cpp @@ -90,6 +90,10 @@ String Resource::get_path() const { return path_cache; } +void Resource::set_path_cache(const String &p_path) { + path_cache = p_path; +} + String Resource::generate_scene_unique_id() { // Generate a unique enough hash, but still user-readable. // If it's not unique it does not matter because the saver will try again. diff --git a/core/io/resource.h b/core/io/resource.h index a9b1a88f6b..610c2150db 100644 --- a/core/io/resource.h +++ b/core/io/resource.h @@ -103,6 +103,7 @@ public: virtual void set_path(const String &p_path, bool p_take_over = false); String get_path() const; + void set_path_cache(const String &p_path); // Set raw path without involving resource cache. _FORCE_INLINE_ bool is_built_in() const { return path_cache.is_empty() || path_cache.contains("::") || path_cache.begins_with("local://"); } static String generate_scene_unique_id(); diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index ea97e5ecce..2a33f723dc 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -774,6 +774,8 @@ Error ResourceLoaderBinary::load() { res = Ref<Resource>(r); if (!path.is_empty() && cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) { r->set_path(path, cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE); //if got here because the resource with same path has different type, replace it + } else if (!path.is_resource_file()) { + r->set_path_cache(path); } r->set_scene_unique_id(id); } diff --git a/core/io/resource_importer.h b/core/io/resource_importer.h index 0089544caa..e17644058a 100644 --- a/core/io/resource_importer.h +++ b/core/io/resource_importer.h @@ -136,6 +136,7 @@ public: virtual void get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset = 0) const = 0; virtual bool get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const = 0; + virtual void handle_compatibility_options(HashMap<StringName, Variant> &p_import_params) const {} virtual String get_option_group_file() const { return String(); } virtual Error import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = nullptr, Variant *r_metadata = nullptr) = 0; diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index 6721ec0953..529128b9a2 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -341,6 +341,8 @@ void ResourceLoader::_thread_load_function(void *p_userdata) { if (load_task.resource.is_valid()) { if (load_task.cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) { load_task.resource->set_path(load_task.local_path); + } else if (!load_task.local_path.is_resource_file()) { + load_task.resource->set_path_cache(load_task.local_path); } if (load_task.xl_remapped) { @@ -918,7 +920,7 @@ String ResourceLoader::_path_remap(const String &p_path, bool *r_translation_rem } // Fallback to p_path if new_path does not exist. - if (!FileAccess::exists(new_path)) { + if (!FileAccess::exists(new_path + ".import") && !FileAccess::exists(new_path)) { WARN_PRINT(vformat("Translation remap '%s' does not exist. Falling back to '%s'.", new_path, p_path)); new_path = p_path; } diff --git a/core/object/object.cpp b/core/object/object.cpp index 2e5b897bce..40df13849b 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -198,6 +198,7 @@ bool Object::_predelete() { notification(NOTIFICATION_PREDELETE, true); if (_predelete_ok) { _class_name_ptr = nullptr; // Must restore, so constructors/destructors have proper class name access at each stage. + notification(NOTIFICATION_PREDELETE_CLEANUP, true); } return _predelete_ok; } diff --git a/core/object/object.h b/core/object/object.h index a444db0f70..7b53fcaa41 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -72,12 +72,12 @@ enum PropertyHint { PROPERTY_HINT_COLOR_NO_ALPHA, ///< used for ignoring alpha component when editing a color PROPERTY_HINT_OBJECT_ID, PROPERTY_HINT_TYPE_STRING, ///< a type string, the hint is the base type to choose - PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE, ///< so something else can provide this (used in scripts) + PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE, // Deprecated. PROPERTY_HINT_OBJECT_TOO_BIG, ///< object is too big to send PROPERTY_HINT_NODE_PATH_VALID_TYPES, PROPERTY_HINT_SAVE_FILE, ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc,". This opens a save dialog PROPERTY_HINT_GLOBAL_SAVE_FILE, ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc,". This opens a save dialog - PROPERTY_HINT_INT_IS_OBJECTID, + PROPERTY_HINT_INT_IS_OBJECTID, // Deprecated. PROPERTY_HINT_INT_IS_POINTER, PROPERTY_HINT_ARRAY_TYPE, PROPERTY_HINT_LOCALE_ID, @@ -105,7 +105,7 @@ enum PropertyUsageFlags { PROPERTY_USAGE_SCRIPT_VARIABLE = 1 << 12, PROPERTY_USAGE_STORE_IF_NULL = 1 << 13, PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED = 1 << 14, - PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE = 1 << 15, + PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE = 1 << 15, // Deprecated. PROPERTY_USAGE_CLASS_IS_ENUM = 1 << 16, PROPERTY_USAGE_NIL_IS_VARIANT = 1 << 17, PROPERTY_USAGE_ARRAY = 1 << 18, // Used in the inspector to group properties as elements of an array. @@ -115,7 +115,7 @@ enum PropertyUsageFlags { PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT = 1 << 22, PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT = 1 << 23, PROPERTY_USAGE_KEYING_INCREMENTS = 1 << 24, // Used in inspector to increment property when keyed in animation player. - PROPERTY_USAGE_DEFERRED_SET_RESOURCE = 1 << 25, // when loading, the resource for this property can be set at the end of loading. + PROPERTY_USAGE_DEFERRED_SET_RESOURCE = 1 << 25, // Deprecated. PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT = 1 << 26, // For Object properties, instantiate them when creating in editor. PROPERTY_USAGE_EDITOR_BASIC_SETTING = 1 << 27, //for project or editor settings, show when basic settings are selected. PROPERTY_USAGE_READ_ONLY = 1 << 28, // Mark a property as read-only in the inspector. @@ -801,6 +801,8 @@ public: NOTIFICATION_POSTINITIALIZE = 0, NOTIFICATION_PREDELETE = 1, NOTIFICATION_EXTENSION_RELOADED = 2, + // Internal notification to send after NOTIFICATION_PREDELETE, not bound to scripting. + NOTIFICATION_PREDELETE_CLEANUP = 3, }; /* TYPE API */ diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp index 011f4203ea..5f53975bf6 100644 --- a/core/object/script_language.cpp +++ b/core/object/script_language.cpp @@ -39,10 +39,11 @@ ScriptLanguage *ScriptServer::_languages[MAX_LANGUAGES]; int ScriptServer::_language_count = 0; +bool ScriptServer::languages_ready = false; +Mutex ScriptServer::languages_mutex; bool ScriptServer::scripting_enabled = true; bool ScriptServer::reload_scripts_on_save = false; -SafeFlag ScriptServer::languages_finished; // Used until GH-76581 is fixed properly. ScriptEditRequestFunction ScriptServer::edit_request_func = nullptr; void Script::_notification(int p_what) { @@ -160,12 +161,13 @@ bool ScriptServer::is_scripting_enabled() { } ScriptLanguage *ScriptServer::get_language(int p_idx) { + MutexLock lock(languages_mutex); ERR_FAIL_INDEX_V(p_idx, _language_count, nullptr); - return _languages[p_idx]; } Error ScriptServer::register_language(ScriptLanguage *p_language) { + MutexLock lock(languages_mutex); ERR_FAIL_NULL_V(p_language, ERR_INVALID_PARAMETER); ERR_FAIL_COND_V_MSG(_language_count >= MAX_LANGUAGES, ERR_UNAVAILABLE, "Script languages limit has been reach, cannot register more."); for (int i = 0; i < _language_count; i++) { @@ -179,6 +181,8 @@ Error ScriptServer::register_language(ScriptLanguage *p_language) { } Error ScriptServer::unregister_language(const ScriptLanguage *p_language) { + MutexLock lock(languages_mutex); + for (int i = 0; i < _language_count; i++) { if (_languages[i] == p_language) { _language_count--; @@ -219,17 +223,31 @@ void ScriptServer::init_languages() { } } - for (int i = 0; i < _language_count; i++) { - _languages[i]->init(); + { + MutexLock lock(languages_mutex); + + for (int i = 0; i < _language_count; i++) { + _languages[i]->init(); + } + + languages_ready = true; } } void ScriptServer::finish_languages() { + MutexLock lock(languages_mutex); + for (int i = 0; i < _language_count; i++) { _languages[i]->finish(); } global_classes_clear(); - languages_finished.set(); + + languages_ready = false; +} + +bool ScriptServer::are_languages_initialized() { + MutexLock lock(languages_mutex); + return languages_ready; } void ScriptServer::set_reload_scripts_on_save(bool p_enable) { @@ -241,7 +259,8 @@ bool ScriptServer::is_reload_scripts_on_save_enabled() { } void ScriptServer::thread_enter() { - if (!languages_finished.is_set()) { + MutexLock lock(languages_mutex); + if (!languages_ready) { return; } for (int i = 0; i < _language_count; i++) { @@ -250,7 +269,8 @@ void ScriptServer::thread_enter() { } void ScriptServer::thread_exit() { - if (!languages_finished.is_set()) { + MutexLock lock(languages_mutex); + if (!languages_ready) { return; } for (int i = 0; i < _language_count; i++) { @@ -538,9 +558,6 @@ void PlaceHolderScriptInstance::get_property_list(List<PropertyInfo> *p_properti } else { for (const PropertyInfo &E : properties) { PropertyInfo pinfo = E; - if (!values.has(pinfo.name)) { - pinfo.usage |= PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE; - } p_properties->push_back(E); } } diff --git a/core/object/script_language.h b/core/object/script_language.h index 3e4041d173..85e64c8d62 100644 --- a/core/object/script_language.h +++ b/core/object/script_language.h @@ -52,9 +52,11 @@ class ScriptServer { static ScriptLanguage *_languages[MAX_LANGUAGES]; static int _language_count; + static bool languages_ready; + static Mutex languages_mutex; + static bool scripting_enabled; static bool reload_scripts_on_save; - static SafeFlag languages_finished; // Used until GH-76581 is fixed properly. struct GlobalScriptClass { StringName language; @@ -98,8 +100,7 @@ public: static void init_languages(); static void finish_languages(); - - static bool are_languages_finished() { return languages_finished.is_set(); } + static bool are_languages_initialized(); }; class PlaceHolderScriptInstance; diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp index a8f2ac5bfe..3c1d4ef95e 100644 --- a/core/object/undo_redo.cpp +++ b/core/object/undo_redo.cpp @@ -301,6 +301,8 @@ void UndoRedo::commit_action(bool p_execute) { return; //still nested } + bool add_message = !merging; + if (merging) { version--; merging = false; @@ -314,7 +316,7 @@ void UndoRedo::commit_action(bool p_execute) { _redo(p_execute); // perform action committing--; - if (callback && actions.size() > 0) { + if (add_message && callback && actions.size() > 0) { callback(callback_ud, actions[actions.size() - 1].name); } } @@ -463,6 +465,10 @@ bool UndoRedo::has_redo() const { return (current_action + 1) < actions.size(); } +bool UndoRedo::is_merging() const { + return merging; +} + uint64_t UndoRedo::get_version() const { return version; } diff --git a/core/object/undo_redo.h b/core/object/undo_redo.h index 74a6bea732..b3a3322e4b 100644 --- a/core/object/undo_redo.h +++ b/core/object/undo_redo.h @@ -131,6 +131,8 @@ public: bool has_undo() const; bool has_redo() const; + bool is_merging() const; + uint64_t get_version() const; void set_commit_notify_callback(CommitNotifyCallback p_callback, void *p_ud); diff --git a/core/object/worker_thread_pool.cpp b/core/object/worker_thread_pool.cpp index 2fcd0867e6..784acadab4 100644 --- a/core/object/worker_thread_pool.cpp +++ b/core/object/worker_thread_pool.cpp @@ -30,6 +30,7 @@ #include "worker_thread_pool.h" +#include "core/object/script_language.h" #include "core/os/os.h" #include "core/os/thread_safe.h" @@ -60,6 +61,14 @@ void WorkerThreadPool::_process_task(Task *p_task) { set_current_thread_safe_for_nodes(false); pool_thread_index = thread_ids[Thread::get_caller_id()]; ThreadData &curr_thread = threads[pool_thread_index]; + // Since the WorkerThreadPool is started before the script server, + // its pre-created threads can't have ScriptServer::thread_enter() called on them early. + // Therefore, we do it late at the first opportunity, so in case the task + // about to be run uses scripting, guarantees are held. + if (!curr_thread.ready_for_scripting && ScriptServer::are_languages_initialized()) { + ScriptServer::thread_enter(); + curr_thread.ready_for_scripting = true; + } task_mutex.lock(); p_task->pool_thread_index = pool_thread_index; if (low_priority) { diff --git a/core/object/worker_thread_pool.h b/core/object/worker_thread_pool.h index d4d9387765..f323a979f7 100644 --- a/core/object/worker_thread_pool.h +++ b/core/object/worker_thread_pool.h @@ -106,6 +106,7 @@ private: uint32_t index; Thread thread; Task *current_low_prio_task = nullptr; + bool ready_for_scripting = false; }; TightLocalVector<ThreadData> threads; diff --git a/core/os/os.cpp b/core/os/os.cpp index 991b179e1f..c7390f14ff 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -490,6 +490,12 @@ bool OS::has_feature(const String &p_feature) { } #endif +#if defined(IOS_SIMULATOR) + if (p_feature == "simulator") { + return true; + } +#endif + if (_check_internal_feature_support(p_feature)) { return true; } diff --git a/core/string/string_name.cpp b/core/string/string_name.cpp index 5a8df07410..658297d805 100644 --- a/core/string/string_name.cpp +++ b/core/string/string_name.cpp @@ -122,7 +122,7 @@ void StringName::unref() { if (_data && _data->refcount.unref()) { MutexLock lock(mutex); - if (_data->static_count.get() > 0) { + if (CoreGlobals::leak_reporting_enabled && _data->static_count.get() > 0) { if (_data->cname) { ERR_PRINT("BUG: Unreferenced static string to 0: " + String(_data->cname)); } else { diff --git a/core/string/translation.cpp b/core/string/translation.cpp index 02380c92bb..a443ed308d 100644 --- a/core/string/translation.cpp +++ b/core/string/translation.cpp @@ -520,11 +520,11 @@ String TranslationServer::get_country_name(const String &p_country) const { void TranslationServer::set_locale(const String &p_locale) { locale = standardize_locale(p_locale); + ResourceLoader::reload_translation_remaps(); + if (OS::get_singleton()->get_main_loop()) { OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_TRANSLATION_CHANGED); } - - ResourceLoader::reload_translation_remaps(); } String TranslationServer::get_locale() const { @@ -816,10 +816,11 @@ bool TranslationServer::is_pseudolocalization_enabled() const { void TranslationServer::set_pseudolocalization_enabled(bool p_enabled) { pseudolocalization_enabled = p_enabled; + ResourceLoader::reload_translation_remaps(); + if (OS::get_singleton()->get_main_loop()) { OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_TRANSLATION_CHANGED); } - ResourceLoader::reload_translation_remaps(); } void TranslationServer::set_editor_pseudolocalization(bool p_enabled) { @@ -836,10 +837,11 @@ void TranslationServer::reload_pseudolocalization() { pseudolocalization_suffix = GLOBAL_GET("internationalization/pseudolocalization/suffix"); pseudolocalization_skip_placeholders_enabled = GLOBAL_GET("internationalization/pseudolocalization/skip_placeholders"); + ResourceLoader::reload_translation_remaps(); + if (OS::get_singleton()->get_main_loop()) { OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_TRANSLATION_CHANGED); } - ResourceLoader::reload_translation_remaps(); } StringName TranslationServer::pseudolocalize(const StringName &p_message) const { diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp index 9be7c04158..60e2d539f8 100644 --- a/core/string/ustring.cpp +++ b/core/string/ustring.cpp @@ -4699,11 +4699,16 @@ String String::property_name_encode() const { static const char32_t invalid_node_name_characters[] = { '.', ':', '@', '/', '\"', UNIQUE_NODE_PREFIX[0], 0 }; -String String::get_invalid_node_name_characters() { +String String::get_invalid_node_name_characters(bool p_allow_internal) { // Do not use this function for critical validation. String r; const char32_t *c = invalid_node_name_characters; while (*c) { + if (p_allow_internal && *c == '@') { + c++; + continue; + } + if (c != invalid_node_name_characters) { r += " "; } diff --git a/core/string/ustring.h b/core/string/ustring.h index f45392eee1..897b06fc6d 100644 --- a/core/string/ustring.h +++ b/core/string/ustring.h @@ -437,7 +437,7 @@ public: String property_name_encode() const; // node functions - static String get_invalid_node_name_characters(); + static String get_invalid_node_name_characters(bool p_allow_internal = false); String validate_node_name() const; String validate_identifier() const; String validate_filename() const; diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp index 09fb34e7c1..4c0212075b 100644 --- a/core/variant/variant.cpp +++ b/core/variant/variant.cpp @@ -1291,7 +1291,13 @@ void Variant::zero() { break; default: + Type prev_type = type; this->clear(); + if (type != prev_type) { + // clear() changes type to NIL, so it needs to be restored. + Callable::CallError ce; + Variant::construct(prev_type, *this, nullptr, 0, ce); + } break; } } |