diff options
Diffstat (limited to 'core')
34 files changed, 521 insertions, 380 deletions
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index 93934f2320..4e3196dec3 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -95,7 +95,7 @@ const PackedStringArray ProjectSettings::_get_supported_features() { features.append(VERSION_FULL_CONFIG); features.append(VERSION_FULL_BUILD); -#ifdef VULKAN_ENABLED +#if defined(VULKAN_ENABLED) || defined(D3D12_ENABLED) features.append("Forward Plus"); features.append("Mobile"); #endif @@ -1387,7 +1387,7 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/occlusion_culling/bvh_build_quality", PROPERTY_HINT_ENUM, "Low,Medium,High"), 2); GLOBAL_DEF(PropertyInfo(Variant::INT, "memory/limits/multithreaded_server/rid_pool_prealloc", PROPERTY_HINT_RANGE, "0,500,1"), 60); // No negative and limit to 500 due to crashes. GLOBAL_DEF_RST("internationalization/rendering/force_right_to_left_layout_direction", false); - GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "internationalization/rendering/root_node_layout_direction", PROPERTY_HINT_ENUM, "Based on Locale,Left-to-Right,Right-to-Left"), 0); + GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "internationalization/rendering/root_node_layout_direction", PROPERTY_HINT_ENUM, "Based on Application Locale,Left-to-Right,Right-to-Left,Based on System Locale"), 0); GLOBAL_DEF(PropertyInfo(Variant::INT, "gui/timers/incremental_search_max_interval_msec", PROPERTY_HINT_RANGE, "0,10000,1,or_greater"), 2000); @@ -1399,6 +1399,12 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF("rendering/rendering_device/staging_buffer/texture_upload_region_size_px", 64); GLOBAL_DEF("rendering/rendering_device/pipeline_cache/save_chunk_size_mb", 3.0); GLOBAL_DEF("rendering/rendering_device/vulkan/max_descriptors_per_pool", 64); + GLOBAL_DEF_RST("rendering/rendering_device/d3d12/max_resource_descriptors_per_frame", 16384); + custom_prop_info["rendering/rendering_device/d3d12/max_resource_descriptors_per_frame"] = PropertyInfo(Variant::INT, "rendering/rendering_device/d3d12/max_resource_descriptors_per_frame", PROPERTY_HINT_RANGE, "512,262144"); + GLOBAL_DEF_RST("rendering/rendering_device/d3d12/max_sampler_descriptors_per_frame", 1024); + custom_prop_info["rendering/rendering_device/d3d12/max_sampler_descriptors_per_frame"] = PropertyInfo(Variant::INT, "rendering/rendering_device/d3d12/max_sampler_descriptors_per_frame", PROPERTY_HINT_RANGE, "256,2048"); + GLOBAL_DEF_RST("rendering/rendering_device/d3d12/max_misc_descriptors_per_frame", 512); + custom_prop_info["rendering/rendering_device/d3d12/max_misc_descriptors_per_frame"] = PropertyInfo(Variant::INT, "rendering/rendering_device/d3d12/max_misc_descriptors_per_frame", PROPERTY_HINT_RANGE, "32,4096"); GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "rendering/textures/canvas_textures/default_texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,Linear Mipmap,Nearest Mipmap"), 1); GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "rendering/textures/canvas_textures/default_texture_repeat", PROPERTY_HINT_ENUM, "Disable,Enable,Mirror"), 0); diff --git a/core/core_bind.cpp b/core/core_bind.cpp index 981d9b0025..d91c659d1e 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -662,6 +662,7 @@ void OS::_bind_methods() { BIND_ENUM_CONSTANT(RENDERING_DRIVER_VULKAN); BIND_ENUM_CONSTANT(RENDERING_DRIVER_OPENGL3); + BIND_ENUM_CONSTANT(RENDERING_DRIVER_D3D12); BIND_ENUM_CONSTANT(SYSTEM_DIR_DESKTOP); BIND_ENUM_CONSTANT(SYSTEM_DIR_DCIM); diff --git a/core/core_bind.h b/core/core_bind.h index 5f51b64eb7..715e26cf23 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -129,6 +129,7 @@ public: enum RenderingDriver { RENDERING_DRIVER_VULKAN, RENDERING_DRIVER_OPENGL3, + RENDERING_DRIVER_D3D12, }; virtual PackedStringArray get_connected_midi_inputs(); diff --git a/core/extension/extension_api_dump.cpp b/core/extension/extension_api_dump.cpp index f3e988633c..543dabfb16 100644 --- a/core/extension/extension_api_dump.cpp +++ b/core/extension/extension_api_dump.cpp @@ -742,14 +742,19 @@ Dictionary GDExtensionAPIDump::generate_extension_api(bool p_include_docs) { Dictionary d2; String operator_name = Variant::get_operator_name(Variant::Operator(k)); d2["name"] = operator_name; - if (k != Variant::OP_NEGATE && k != Variant::OP_POSITIVE && k != Variant::OP_NOT && k != Variant::OP_BIT_NEGATE) { - d2["right_type"] = get_builtin_or_variant_type_name(Variant::Type(j)); + + String right_type_name = get_builtin_or_variant_type_name(Variant::Type(j)); + bool is_unary = k == Variant::OP_NEGATE || k == Variant::OP_POSITIVE || k == Variant::OP_NOT || k == Variant::OP_BIT_NEGATE; + if (!is_unary) { + d2["right_type"] = right_type_name; } + d2["return_type"] = get_builtin_or_variant_type_name(Variant::get_operator_return_type(Variant::Operator(k), type, Variant::Type(j))); if (p_include_docs && builtin_doc != nullptr) { for (const DocData::MethodDoc &operator_doc : builtin_doc->operators) { - if (operator_doc.name == "operator " + operator_name) { + if (operator_doc.name == "operator " + operator_name && + (is_unary || operator_doc.arguments[0].type == right_type_name)) { d2["description"] = fix_doc_description(operator_doc.description); break; } diff --git a/core/input/input.cpp b/core/input/input.cpp index 257452b3d8..8f976cbaa3 100644 --- a/core/input/input.cpp +++ b/core/input/input.cpp @@ -143,9 +143,15 @@ void Input::_bind_methods() { ClassDB::bind_method(D_METHOD("set_use_accumulated_input", "enable"), &Input::set_use_accumulated_input); ClassDB::bind_method(D_METHOD("is_using_accumulated_input"), &Input::is_using_accumulated_input); ClassDB::bind_method(D_METHOD("flush_buffered_events"), &Input::flush_buffered_events); + ClassDB::bind_method(D_METHOD("set_emulate_mouse_from_touch", "enable"), &Input::set_emulate_mouse_from_touch); + ClassDB::bind_method(D_METHOD("is_emulating_mouse_from_touch"), &Input::is_emulating_mouse_from_touch); + ClassDB::bind_method(D_METHOD("set_emulate_touch_from_mouse", "enable"), &Input::set_emulate_touch_from_mouse); + ClassDB::bind_method(D_METHOD("is_emulating_touch_from_mouse"), &Input::is_emulating_touch_from_mouse); ADD_PROPERTY(PropertyInfo(Variant::INT, "mouse_mode"), "set_mouse_mode", "get_mouse_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_accumulated_input"), "set_use_accumulated_input", "is_using_accumulated_input"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emulate_mouse_from_touch"), "set_emulate_mouse_from_touch", "is_emulating_mouse_from_touch"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emulate_touch_from_mouse"), "set_emulate_touch_from_mouse", "is_emulating_touch_from_mouse"); BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE); BIND_ENUM_CONSTANT(MOUSE_MODE_HIDDEN); @@ -241,8 +247,8 @@ bool Input::is_anything_pressed() const { return true; } - for (const KeyValue<StringName, Input::Action> &E : action_state) { - if (E.value.pressed) { + for (const KeyValue<StringName, Input::ActionState> &E : action_states) { + if (E.value.cache.pressed) { return true; } } @@ -285,12 +291,17 @@ bool Input::is_joy_button_pressed(int p_device, JoyButton p_button) const { bool Input::is_action_pressed(const StringName &p_action, bool p_exact) const { ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action)); - return action_state.has(p_action) && action_state[p_action].pressed > 0 && (p_exact ? action_state[p_action].exact : true); + HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action); + if (!E) { + return false; + } + + return E->value.cache.pressed && (p_exact ? E->value.exact : true); } bool Input::is_action_just_pressed(const StringName &p_action, bool p_exact) const { ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action)); - HashMap<StringName, Action>::ConstIterator E = action_state.find(p_action); + HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action); if (!E) { return false; } @@ -300,7 +311,7 @@ bool Input::is_action_just_pressed(const StringName &p_action, bool p_exact) con } // Backward compatibility for legacy behavior, only return true if currently pressed. - bool pressed_requirement = legacy_just_pressed_behavior ? E->value.pressed : true; + bool pressed_requirement = legacy_just_pressed_behavior ? E->value.cache.pressed : true; if (Engine::get_singleton()->is_in_physics_frame()) { return pressed_requirement && E->value.pressed_physics_frame == Engine::get_singleton()->get_physics_frames(); @@ -311,7 +322,7 @@ bool Input::is_action_just_pressed(const StringName &p_action, bool p_exact) con bool Input::is_action_just_released(const StringName &p_action, bool p_exact) const { ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action)); - HashMap<StringName, Action>::ConstIterator E = action_state.find(p_action); + HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action); if (!E) { return false; } @@ -321,7 +332,7 @@ bool Input::is_action_just_released(const StringName &p_action, bool p_exact) co } // Backward compatibility for legacy behavior, only return true if currently released. - bool released_requirement = legacy_just_pressed_behavior ? !E->value.pressed : true; + bool released_requirement = legacy_just_pressed_behavior ? !E->value.cache.pressed : true; if (Engine::get_singleton()->is_in_physics_frame()) { return released_requirement && E->value.released_physics_frame == Engine::get_singleton()->get_physics_frames(); @@ -332,7 +343,7 @@ bool Input::is_action_just_released(const StringName &p_action, bool p_exact) co float Input::get_action_strength(const StringName &p_action, bool p_exact) const { ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), 0.0, InputMap::get_singleton()->suggest_actions(p_action)); - HashMap<StringName, Action>::ConstIterator E = action_state.find(p_action); + HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action); if (!E) { return 0.0f; } @@ -341,12 +352,12 @@ float Input::get_action_strength(const StringName &p_action, bool p_exact) const return 0.0f; } - return E->value.strength; + return E->value.cache.strength; } float Input::get_action_raw_strength(const StringName &p_action, bool p_exact) const { ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), 0.0, InputMap::get_singleton()->suggest_actions(p_action)); - HashMap<StringName, Action>::ConstIterator E = action_state.find(p_action); + HashMap<StringName, ActionState>::ConstIterator E = action_states.find(p_action); if (!E) { return 0.0f; } @@ -355,7 +366,7 @@ float Input::get_action_raw_strength(const StringName &p_action, bool p_exact) c return 0.0f; } - return E->value.raw_strength; + return E->value.cache.raw_strength; } float Input::get_axis(const StringName &p_negative_action, const StringName &p_positive_action) const { @@ -440,6 +451,18 @@ static String _hex_str(uint8_t p_byte) { void Input::joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid, Dictionary p_joypad_info) { _THREAD_SAFE_METHOD_ + + // Clear the pressed status if a Joypad gets disconnected. + if (!p_connected) { + for (KeyValue<StringName, ActionState> &E : action_states) { + HashMap<int, ActionState::DeviceState>::Iterator it = E.value.device_states.find(p_idx); + if (it) { + E.value.device_states.remove(it); + _update_action_cache(E.key, E.value); + } + } + } + Joypad js; js.name = p_connected ? p_name : ""; js.uid = p_connected ? p_guid : ""; @@ -699,30 +722,35 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em if (event_index == -1) { continue; } + ERR_FAIL_COND_MSG(event_index >= (int)MAX_EVENT, vformat("Input singleton does not support more than %d events assigned to an action.", MAX_EVENT)); + + int device_id = p_event->get_device(); + bool is_pressed = p_event->is_action_pressed(E.key, true); + ActionState &action_state = action_states[E.key]; + + // Update the action's per-device state. + ActionState::DeviceState &device_state = action_state.device_states[device_id]; + device_state.pressed[event_index] = is_pressed; + device_state.strength[event_index] = p_event->get_action_strength(E.key); + device_state.raw_strength[event_index] = p_event->get_action_raw_strength(E.key); + + // Update the action's global state and cache. + if (!is_pressed) { + action_state.api_pressed = false; // Always release the event from action_press() method. + action_state.api_strength = 0.0; + } + action_state.exact = InputMap::get_singleton()->event_is_action(p_event, E.key, true); - 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.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 (!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); + bool was_pressed = action_state.cache.pressed; + _update_action_cache(E.key, action_state); + if (action_state.cache.pressed && !was_pressed) { + action_state.pressed_physics_frame = Engine::get_singleton()->get_physics_frames(); + action_state.pressed_process_frame = Engine::get_singleton()->get_process_frames(); + } + if (!action_state.cache.pressed && was_pressed) { + action_state.released_physics_frame = Engine::get_singleton()->get_physics_frames(); + action_state.released_process_frame = Engine::get_singleton()->get_process_frames(); } - _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) { @@ -837,32 +865,30 @@ Point2i Input::warp_mouse_motion(const Ref<InputEventMouseMotion> &p_motion, con void Input::action_press(const StringName &p_action, float p_strength) { // Create or retrieve existing action. - Action &action = action_state[p_action]; + ActionState &action_state = action_states[p_action]; - if (!action.pressed) { - action.pressed_physics_frame = Engine::get_singleton()->get_physics_frames(); - action.pressed_process_frame = Engine::get_singleton()->get_process_frames(); + if (!action_state.cache.pressed) { + action_state.pressed_physics_frame = Engine::get_singleton()->get_physics_frames(); + action_state.pressed_process_frame = Engine::get_singleton()->get_process_frames(); } - 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; + action_state.exact = true; + action_state.api_pressed = true; + action_state.api_strength = p_strength; + _update_action_cache(p_action, action_state); } void Input::action_release(const StringName &p_action) { // Create or retrieve existing action. - Action &action = action_state[p_action]; - - 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.exact = true; + ActionState &action_state = action_states[p_action]; + action_state.cache.pressed = 0; + action_state.cache.strength = 0.0; + action_state.cache.raw_strength = 0.0; + action_state.released_physics_frame = Engine::get_singleton()->get_physics_frames(); + action_state.released_process_frame = Engine::get_singleton()->get_process_frames(); + action_state.device_states.clear(); + action_state.exact = true; + action_state.api_pressed = false; + action_state.api_strength = 0.0; } void Input::set_emulate_touch_from_mouse(bool p_emulate) { @@ -1020,10 +1046,8 @@ void Input::release_pressed_events() { joy_buttons_pressed.clear(); _joy_axis.clear(); - for (KeyValue<StringName, Input::Action> &E : action_state) { - if (E.value.pressed > 0) { - // Make sure the action is really released. - E.value.pressed = 1; + for (KeyValue<StringName, Input::ActionState> &E : action_states) { + if (E.value.cache.pressed) { action_release(E.key); } } @@ -1190,35 +1214,26 @@ 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); +void Input::_update_action_cache(const StringName &p_action_name, ActionState &r_action_state) { + // Update the action cache, computed from the per-device and per-event states. + r_action_state.cache.pressed = false; + r_action_state.cache.strength = 0.0; + r_action_state.cache.raw_strength = 0.0; - 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]); + int max_event = InputMap::get_singleton()->action_get_events(p_action_name)->size(); + for (const KeyValue<int, ActionState::DeviceState> &kv : r_action_state.device_states) { + const ActionState::DeviceState &device_state = kv.value; + for (int i = 0; i < max_event; i++) { + r_action_state.cache.pressed = r_action_state.cache.pressed || device_state.pressed[i]; + r_action_state.cache.strength = MAX(r_action_state.cache.strength, device_state.strength[i]); + r_action_state.cache.raw_strength = MAX(r_action_state.cache.raw_strength, device_state.raw_strength[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]); - } + if (r_action_state.api_pressed) { + r_action_state.cache.pressed = true; + r_action_state.cache.strength = MAX(r_action_state.cache.strength, r_action_state.api_strength); + r_action_state.cache.raw_strength = MAX(r_action_state.cache.raw_strength, r_action_state.api_strength); // Use the strength as raw_strength for API-pressed states. } } diff --git a/core/input/input.h b/core/input/input.h index dd613c4877..b98406e884 100644 --- a/core/input/input.h +++ b/core/input/input.h @@ -44,7 +44,7 @@ class Input : public Object { static Input *singleton; - static constexpr uint64_t MAX_EVENT = 31; + static constexpr uint64_t MAX_EVENT = 32; public: enum MouseMode { @@ -100,30 +100,31 @@ private: int64_t mouse_window = 0; bool legacy_just_pressed_behavior = false; - struct Action { + struct ActionState { uint64_t pressed_physics_frame = UINT64_MAX; uint64_t pressed_process_frame = UINT64_MAX; uint64_t released_physics_frame = UINT64_MAX; uint64_t released_process_frame = UINT64_MAX; - 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; - } - } + + struct DeviceState { + bool pressed[MAX_EVENT] = { false }; + float strength[MAX_EVENT] = { 0.0 }; + float raw_strength[MAX_EVENT] = { 0.0 }; + }; + bool api_pressed = false; + float api_strength = 0.0; + HashMap<int, DeviceState> device_states; + + // Cache. + struct ActionStateCache { + bool pressed = false; + float strength = false; + float raw_strength = false; + } cache; }; - HashMap<StringName, Action> action_state; + HashMap<StringName, ActionState> action_states; bool emulate_touch_from_mouse = false; bool emulate_mouse_from_touch = false; @@ -240,8 +241,7 @@ 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 _update_action_cache(const StringName &p_action_name, ActionState &r_action_state); void _parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated); diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp index 74c5c1c191..265d9ef56c 100644 --- a/core/io/file_access_pack.cpp +++ b/core/io/file_access_pack.cpp @@ -327,7 +327,7 @@ uint64_t FileAccessPack::get_buffer(uint8_t *p_dst, uint64_t p_length) const { to_read = (int64_t)pf.size - (int64_t)pos; } - pos += p_length; + pos += to_read; if (to_read <= 0) { return 0; diff --git a/core/io/image.cpp b/core/io/image.cpp index ce08b417a8..c72064e4f7 100644 --- a/core/io/image.cpp +++ b/core/io/image.cpp @@ -509,6 +509,7 @@ static void _convert(int p_width, int p_height, const uint8_t *p_src, uint8_t *p } void Image::convert(Format p_new_format) { + ERR_FAIL_INDEX_MSG(p_new_format, FORMAT_MAX, "The Image format specified (" + itos(p_new_format) + ") is out of range. See Image's Format enum."); if (data.size() == 0) { return; } diff --git a/core/io/resource.cpp b/core/io/resource.cpp index 64fa597a67..04ecabaf27 100644 --- a/core/io/resource.cpp +++ b/core/io/resource.cpp @@ -489,12 +489,14 @@ RWLock ResourceCache::path_cache_lock; #endif void ResourceCache::clear() { - if (resources.size()) { - ERR_PRINT("Resources still in use at exit (run with --verbose for details)."); + if (!resources.is_empty()) { if (OS::get_singleton()->is_stdout_verbose()) { + ERR_PRINT(vformat("%d resources still in use at exit.", resources.size())); for (const KeyValue<String, Resource *> &E : resources) { print_line(vformat("Resource still in use: %s (%s)", E.key, E.value->get_class())); } + } else { + ERR_PRINT(vformat("%d resources still in use at exit (run with --verbose for details).", resources.size())); } } diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index 2a33f723dc..20c494516b 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -1454,8 +1454,10 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons fw.unref(); Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); - da->remove(p_path); - da->rename(p_path + ".depren", p_path); + if (da->exists(p_path + ".depren")) { + da->remove(p_path); + da->rename(p_path + ".depren", p_path); + } return OK; } diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index 529128b9a2..0c7764392a 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -340,7 +340,7 @@ 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); + load_task.resource->set_path(load_task.local_path, load_task.cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE); } else if (!load_task.local_path.is_resource_file()) { load_task.resource->set_path_cache(load_task.local_path); } @@ -361,6 +361,17 @@ void ResourceLoader::_thread_load_function(void *p_userdata) { if (_loaded_callback) { _loaded_callback(load_task.resource, load_task.local_path); } + } else if (load_task.cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) { + Ref<Resource> existing = ResourceCache::get_ref(load_task.local_path); + if (existing.is_valid()) { + load_task.resource = existing; + load_task.status = THREAD_LOAD_LOADED; + load_task.progress = 1.0; + + if (_loaded_callback) { + _loaded_callback(load_task.resource, load_task.local_path); + } + } } thread_load_mutex.unlock(); @@ -463,7 +474,7 @@ Ref<ResourceLoader::LoadToken> ResourceLoader::_load_start(const String &p_path, load_task.type_hint = p_type_hint; load_task.cache_mode = p_cache_mode; load_task.use_sub_threads = p_thread_mode == LOAD_THREAD_DISTRIBUTE; - if (p_cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) { + if (p_cache_mode == ResourceFormatLoader::CACHE_MODE_REUSE) { Ref<Resource> existing = ResourceCache::get_ref(local_path); if (existing.is_valid()) { //referencing is fine @@ -1113,11 +1124,10 @@ bool ResourceLoader::add_custom_resource_format_loader(String script_path) { Ref<Script> s = res; StringName ibt = s->get_instance_base_type(); bool valid_type = ClassDB::is_parent_class(ibt, "ResourceFormatLoader"); - ERR_FAIL_COND_V_MSG(!valid_type, false, "Script does not inherit a CustomResourceLoader: " + script_path + "."); + ERR_FAIL_COND_V_MSG(!valid_type, false, vformat("Failed to add a custom resource loader, script '%s' does not inherit 'ResourceFormatLoader'.", script_path)); Object *obj = ClassDB::instantiate(ibt); - - ERR_FAIL_NULL_V_MSG(obj, false, "Cannot instance script as custom resource loader, expected 'ResourceFormatLoader' inheritance, got: " + String(ibt) + "."); + ERR_FAIL_NULL_V_MSG(obj, false, vformat("Failed to add a custom resource loader, cannot instantiate '%s'.", ibt)); Ref<ResourceFormatLoader> crl = Object::cast_to<ResourceFormatLoader>(obj); crl->set_script(s); diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp index 564a54b913..1c6c18b015 100644 --- a/core/io/resource_saver.cpp +++ b/core/io/resource_saver.cpp @@ -237,11 +237,10 @@ bool ResourceSaver::add_custom_resource_format_saver(String script_path) { Ref<Script> s = res; StringName ibt = s->get_instance_base_type(); bool valid_type = ClassDB::is_parent_class(ibt, "ResourceFormatSaver"); - ERR_FAIL_COND_V_MSG(!valid_type, false, "Script does not inherit a CustomResourceSaver: " + script_path + "."); + ERR_FAIL_COND_V_MSG(!valid_type, false, vformat("Failed to add a custom resource saver, script '%s' does not inherit 'ResourceFormatSaver'.", script_path)); Object *obj = ClassDB::instantiate(ibt); - - ERR_FAIL_NULL_V_MSG(obj, false, "Cannot instance script as custom resource saver, expected 'ResourceFormatSaver' inheritance, got: " + String(ibt) + "."); + ERR_FAIL_NULL_V_MSG(obj, false, vformat("Failed to add a custom resource saver, cannot instantiate '%s'.", ibt)); Ref<ResourceFormatSaver> crl = Object::cast_to<ResourceFormatSaver>(obj); crl->set_script(s); diff --git a/core/math/basis.cpp b/core/math/basis.cpp index 9796ac59c2..cd8c87b158 100644 --- a/core/math/basis.cpp +++ b/core/math/basis.cpp @@ -89,13 +89,26 @@ Basis Basis::orthogonalized() const { return c; } +// Returns true if the basis vectors are orthogonal (perpendicular), so it has no skew or shear, and can be decomposed into rotation and scale. +// See https://en.wikipedia.org/wiki/Orthogonal_basis bool Basis::is_orthogonal() const { - Basis identity; - Basis m = (*this) * transposed(); + const Vector3 x = get_column(0); + const Vector3 y = get_column(1); + const Vector3 z = get_column(2); + return Math::is_zero_approx(x.dot(y)) && Math::is_zero_approx(x.dot(z)) && Math::is_zero_approx(y.dot(z)); +} - return m.is_equal_approx(identity); +// Returns true if the basis vectors are orthonormal (orthogonal and normalized), so it has no scale, skew, or shear. +// See https://en.wikipedia.org/wiki/Orthonormal_basis +bool Basis::is_orthonormal() const { + const Vector3 x = get_column(0); + const Vector3 y = get_column(1); + const Vector3 z = get_column(2); + return Math::is_equal_approx(x.length_squared(), 1) && Math::is_equal_approx(y.length_squared(), 1) && Math::is_equal_approx(z.length_squared(), 1) && Math::is_zero_approx(x.dot(y)) && Math::is_zero_approx(x.dot(z)) && Math::is_zero_approx(y.dot(z)); } +// Returns true if the basis is conformal (orthogonal, uniform scale, preserves angles and distance ratios). +// See https://en.wikipedia.org/wiki/Conformal_linear_transformation bool Basis::is_conformal() const { const Vector3 x = get_column(0); const Vector3 y = get_column(1); @@ -104,6 +117,7 @@ bool Basis::is_conformal() const { return Math::is_equal_approx(x_len_sq, y.length_squared()) && Math::is_equal_approx(x_len_sq, z.length_squared()) && Math::is_zero_approx(x.dot(y)) && Math::is_zero_approx(x.dot(z)) && Math::is_zero_approx(y.dot(z)); } +// Returns true if the basis only has diagonal elements, so it may only have scale or flip, but no rotation, skew, or shear. bool Basis::is_diagonal() const { return ( Math::is_zero_approx(rows[0][1]) && Math::is_zero_approx(rows[0][2]) && @@ -111,8 +125,9 @@ bool Basis::is_diagonal() const { Math::is_zero_approx(rows[2][0]) && Math::is_zero_approx(rows[2][1])); } +// Returns true if the basis is a pure rotation matrix, so it has no scale, skew, shear, or flip. bool Basis::is_rotation() const { - return Math::is_equal_approx(determinant(), 1, (real_t)UNIT_EPSILON) && is_orthogonal(); + return is_conformal() && Math::is_equal_approx(determinant(), 1, (real_t)UNIT_EPSILON); } #ifdef MATH_CHECKS diff --git a/core/math/basis.h b/core/math/basis.h index adacd1c216..b4d971464e 100644 --- a/core/math/basis.h +++ b/core/math/basis.h @@ -138,6 +138,7 @@ struct _NO_DISCARD_ Basis { _FORCE_INLINE_ Basis operator*(const real_t p_val) const; bool is_orthogonal() const; + bool is_orthonormal() const; bool is_conformal() const; bool is_diagonal() const; bool is_rotation() const; diff --git a/core/math/dynamic_bvh.h b/core/math/dynamic_bvh.h index dbc1cb31de..9b49fcc3c8 100644 --- a/core/math/dynamic_bvh.h +++ b/core/math/dynamic_bvh.h @@ -328,7 +328,8 @@ void DynamicBVH::aabb_query(const AABB &p_box, QueryResult &r_result) { volume.min = p_box.position; volume.max = p_box.position + p_box.size; - const Node **stack = (const Node **)alloca(ALLOCA_STACK_SIZE * sizeof(const Node *)); + const Node **alloca_stack = (const Node **)alloca(ALLOCA_STACK_SIZE * sizeof(const Node *)); + const Node **stack = alloca_stack; stack[0] = bvh_root; int32_t depth = 1; int32_t threshold = ALLOCA_STACK_SIZE - 2; @@ -343,7 +344,8 @@ void DynamicBVH::aabb_query(const AABB &p_box, QueryResult &r_result) { if (depth > threshold) { if (aux_stack.is_empty()) { aux_stack.resize(ALLOCA_STACK_SIZE * 2); - memcpy(aux_stack.ptr(), stack, ALLOCA_STACK_SIZE * sizeof(const Node *)); + memcpy(aux_stack.ptr(), alloca_stack, ALLOCA_STACK_SIZE * sizeof(const Node *)); + alloca_stack = nullptr; } else { aux_stack.resize(aux_stack.size() * 2); } @@ -384,7 +386,8 @@ void DynamicBVH::convex_query(const Plane *p_planes, int p_plane_count, const Ve } } - const Node **stack = (const Node **)alloca(ALLOCA_STACK_SIZE * sizeof(const Node *)); + const Node **alloca_stack = (const Node **)alloca(ALLOCA_STACK_SIZE * sizeof(const Node *)); + const Node **stack = alloca_stack; stack[0] = bvh_root; int32_t depth = 1; int32_t threshold = ALLOCA_STACK_SIZE - 2; @@ -399,7 +402,8 @@ void DynamicBVH::convex_query(const Plane *p_planes, int p_plane_count, const Ve if (depth > threshold) { if (aux_stack.is_empty()) { aux_stack.resize(ALLOCA_STACK_SIZE * 2); - memcpy(aux_stack.ptr(), stack, ALLOCA_STACK_SIZE * sizeof(const Node *)); + memcpy(aux_stack.ptr(), alloca_stack, ALLOCA_STACK_SIZE * sizeof(const Node *)); + alloca_stack = nullptr; } else { aux_stack.resize(aux_stack.size() * 2); } @@ -436,7 +440,8 @@ void DynamicBVH::ray_query(const Vector3 &p_from, const Vector3 &p_to, QueryResu Vector3 bounds[2]; - const Node **stack = (const Node **)alloca(ALLOCA_STACK_SIZE * sizeof(const Node *)); + const Node **alloca_stack = (const Node **)alloca(ALLOCA_STACK_SIZE * sizeof(const Node *)); + const Node **stack = alloca_stack; stack[0] = bvh_root; int32_t depth = 1; int32_t threshold = ALLOCA_STACK_SIZE - 2; @@ -456,7 +461,8 @@ void DynamicBVH::ray_query(const Vector3 &p_from, const Vector3 &p_to, QueryResu if (depth > threshold) { if (aux_stack.is_empty()) { aux_stack.resize(ALLOCA_STACK_SIZE * 2); - memcpy(aux_stack.ptr(), stack, ALLOCA_STACK_SIZE * sizeof(const Node *)); + memcpy(aux_stack.ptr(), alloca_stack, ALLOCA_STACK_SIZE * sizeof(const Node *)); + alloca_stack = nullptr; } else { aux_stack.resize(aux_stack.size() * 2); } diff --git a/core/object/make_virtuals.py b/core/object/make_virtuals.py index 79a8df6c8a..ae70981f72 100644 --- a/core/object/make_virtuals.py +++ b/core/object/make_virtuals.py @@ -1,78 +1,74 @@ -proto = """ -#define GDVIRTUAL$VER($RET m_name $ARG) \\ -StringName _gdvirtual_##m_name##_sn = #m_name;\\ -mutable bool _gdvirtual_##m_name##_initialized = false;\\ -mutable void* _gdvirtual_##m_name = nullptr;\\ -template<bool required>\\ -_FORCE_INLINE_ bool _gdvirtual_##m_name##_call($CALLARGS) $CONST { \\ - ScriptInstance *_script_instance = ((Object*)(this))->get_script_instance();\\ - if (_script_instance) {\\ - Callable::CallError ce; \\ - $CALLSIARGS\\ - $CALLSIBEGIN_script_instance->callp(_gdvirtual_##m_name##_sn, $CALLSIARGPASS, ce);\\ - if (ce.error == Callable::CallError::CALL_OK) {\\ - $CALLSIRET\\ +proto = """#define GDVIRTUAL$VER($RET m_name $ARG)\\ + StringName _gdvirtual_##m_name##_sn = #m_name;\\ + mutable bool _gdvirtual_##m_name##_initialized = false;\\ + mutable void *_gdvirtual_##m_name = nullptr;\\ + template <bool required>\\ + _FORCE_INLINE_ bool _gdvirtual_##m_name##_call($CALLARGS) $CONST {\\ + ScriptInstance *_script_instance = ((Object *)(this))->get_script_instance();\\ + if (_script_instance) {\\ + Callable::CallError ce;\\ + $CALLSIARGS\\ + $CALLSIBEGIN_script_instance->callp(_gdvirtual_##m_name##_sn, $CALLSIARGPASS, ce);\\ + if (ce.error == Callable::CallError::CALL_OK) {\\ + $CALLSIRET\\ + return true;\\ + }\\ + }\\ + if (unlikely(_get_extension() && !_gdvirtual_##m_name##_initialized)) {\\ + _gdvirtual_##m_name = nullptr;\\ + if (_get_extension()->get_virtual_call_data && _get_extension()->call_virtual_with_data) {\\ + _gdvirtual_##m_name = _get_extension()->get_virtual_call_data(_get_extension()->class_userdata, &_gdvirtual_##m_name##_sn);\\ + } else if (_get_extension()->get_virtual) {\\ + _gdvirtual_##m_name = (void *)_get_extension()->get_virtual(_get_extension()->class_userdata, &_gdvirtual_##m_name##_sn);\\ + }\\ + GDVIRTUAL_TRACK(_gdvirtual_##m_name, _gdvirtual_##m_name##_initialized);\\ + _gdvirtual_##m_name##_initialized = true;\\ + }\\ + if (_gdvirtual_##m_name) {\\ + $CALLPTRARGS\\ + $CALLPTRRETDEF\\ + if (_get_extension()->get_virtual_call_data && _get_extension()->call_virtual_with_data) {\\ + _get_extension()->call_virtual_with_data(_get_extension_instance(), &_gdvirtual_##m_name##_sn, _gdvirtual_##m_name, $CALLPTRARGPASS, $CALLPTRRETPASS);\\ + $CALLPTRRET\\ + } else {\\ + ((GDExtensionClassCallVirtual)_gdvirtual_##m_name)(_get_extension_instance(), $CALLPTRARGPASS, $CALLPTRRETPASS);\\ + $CALLPTRRET\\ + }\\ return true;\\ - } \\ + }\\ + if (required) {\\ + ERR_PRINT_ONCE("Required virtual method " + get_class() + "::" + #m_name + " must be overridden before calling.");\\ + $RVOID\\ + }\\ + return false;\\ }\\ - if (unlikely(_get_extension() && !_gdvirtual_##m_name##_initialized)) {\\ - _gdvirtual_##m_name = nullptr;\\ - if (_get_extension()->get_virtual_call_data && _get_extension()->call_virtual_with_data) {\\ - _gdvirtual_##m_name = _get_extension()->get_virtual_call_data(_get_extension()->class_userdata, &_gdvirtual_##m_name##_sn);\\ - } else if (_get_extension()->get_virtual) {\\ - _gdvirtual_##m_name = (void *)_get_extension()->get_virtual(_get_extension()->class_userdata, &_gdvirtual_##m_name##_sn);\\ - }\\ - GDVIRTUAL_TRACK(_gdvirtual_##m_name, _gdvirtual_##m_name##_initialized); \\ - _gdvirtual_##m_name##_initialized = true;\\ - }\\ - if (_gdvirtual_##m_name) {\\ - $CALLPTRARGS\\ - $CALLPTRRETDEF\\ - if (_get_extension()->get_virtual_call_data && _get_extension()->call_virtual_with_data) {\\ - _get_extension()->call_virtual_with_data(_get_extension_instance(), &_gdvirtual_##m_name##_sn, _gdvirtual_##m_name, $CALLPTRARGPASS,$CALLPTRRETPASS);\\ - $CALLPTRRET\\ - } else {\\ - ((GDExtensionClassCallVirtual)_gdvirtual_##m_name)(_get_extension_instance(),$CALLPTRARGPASS,$CALLPTRRETPASS);\\ - $CALLPTRRET\\ - }\\ - return true;\\ - }\\ - \\ - if (required) {\\ - ERR_PRINT_ONCE("Required virtual method " + get_class() + "::" + #m_name + " must be overridden before calling.");\\ - $RVOID\\ - }\\ -\\ - return false;\\ -}\\ -_FORCE_INLINE_ bool _gdvirtual_##m_name##_overridden() const { \\ - ScriptInstance *_script_instance = ((Object*)(this))->get_script_instance();\\ - if (_script_instance && _script_instance->has_method(_gdvirtual_##m_name##_sn)) {\\ - return true;\\ - }\\ - if (unlikely(_get_extension() && !_gdvirtual_##m_name##_initialized)) {\\ - _gdvirtual_##m_name = nullptr;\\ - if (_get_extension()->get_virtual_call_data && _get_extension()->call_virtual_with_data) {\\ - _gdvirtual_##m_name = _get_extension()->get_virtual_call_data(_get_extension()->class_userdata, &_gdvirtual_##m_name##_sn);\\ - } else if (_get_extension()->get_virtual) {\\ - _gdvirtual_##m_name = (void *)_get_extension()->get_virtual(_get_extension()->class_userdata, &_gdvirtual_##m_name##_sn);\\ - }\\ - GDVIRTUAL_TRACK(_gdvirtual_##m_name, _gdvirtual_##m_name##_initialized); \\ - _gdvirtual_##m_name##_initialized = true;\\ - }\\ - if (_gdvirtual_##m_name) {\\ - return true;\\ + _FORCE_INLINE_ bool _gdvirtual_##m_name##_overridden() const {\\ + ScriptInstance *_script_instance = ((Object *)(this))->get_script_instance();\\ + if (_script_instance && _script_instance->has_method(_gdvirtual_##m_name##_sn)) {\\ + return true;\\ + }\\ + if (unlikely(_get_extension() && !_gdvirtual_##m_name##_initialized)) {\\ + _gdvirtual_##m_name = nullptr;\\ + if (_get_extension()->get_virtual_call_data && _get_extension()->call_virtual_with_data) {\\ + _gdvirtual_##m_name = _get_extension()->get_virtual_call_data(_get_extension()->class_userdata, &_gdvirtual_##m_name##_sn);\\ + } else if (_get_extension()->get_virtual) {\\ + _gdvirtual_##m_name = (void *)_get_extension()->get_virtual(_get_extension()->class_userdata, &_gdvirtual_##m_name##_sn);\\ + }\\ + GDVIRTUAL_TRACK(_gdvirtual_##m_name, _gdvirtual_##m_name##_initialized);\\ + _gdvirtual_##m_name##_initialized = true;\\ + }\\ + if (_gdvirtual_##m_name) {\\ + return true;\\ + }\\ + return false;\\ }\\ - return false;\\ -}\\ -\\ -_FORCE_INLINE_ static MethodInfo _gdvirtual_##m_name##_get_method_info() { \\ - MethodInfo method_info;\\ - method_info.name = #m_name;\\ - method_info.flags = METHOD_FLAG_VIRTUAL;\\ - $FILL_METHOD_INFO\\ - return method_info;\\ -} + _FORCE_INLINE_ static MethodInfo _gdvirtual_##m_name##_get_method_info() {\\ + MethodInfo method_info;\\ + method_info.name = #m_name;\\ + method_info.flags = $METHOD_FLAGS;\\ + $FILL_METHOD_INFO\\ + return method_info;\\ + } """ @@ -83,22 +79,23 @@ def generate_version(argcount, const=False, returns=False): method_info = "" if returns: sproto += "R" - s = s.replace("$RET", "m_ret, ") + s = s.replace("$RET", "m_ret,") s = s.replace("$RVOID", "(void)r_ret;") # If required, may lead to uninitialized errors s = s.replace("$CALLPTRRETDEF", "PtrToArg<m_ret>::EncodeT ret;") - method_info += "\tmethod_info.return_val = GetTypeInfo<m_ret>::get_class_info();\\\n" - method_info += "\tmethod_info.return_val_metadata = GetTypeInfo<m_ret>::METADATA;\\\n" + method_info += "method_info.return_val = GetTypeInfo<m_ret>::get_class_info();\\\n" + method_info += "\t\tmethod_info.return_val_metadata = GetTypeInfo<m_ret>::METADATA;" else: - s = s.replace("$RET", "") - s = s.replace("$RVOID", "") - s = s.replace("$CALLPTRRETDEF", "") + s = s.replace("$RET ", "") + s = s.replace("\t\t\t$RVOID\\\n", "") + s = s.replace("\t\t\t$CALLPTRRETDEF\\\n", "") if const: sproto += "C" s = s.replace("$CONST", "const") - method_info += "\tmethod_info.flags|=METHOD_FLAG_CONST;\\\n" + s = s.replace("$METHOD_FLAGS", "METHOD_FLAG_VIRTUAL | METHOD_FLAG_CONST") else: - s = s.replace("$CONST", "") + s = s.replace("$CONST ", "") + s = s.replace("$METHOD_FLAGS", "METHOD_FLAG_VIRTUAL") s = s.replace("$VER", sproto) argtext = "" @@ -108,9 +105,9 @@ def generate_version(argcount, const=False, returns=False): callptrargsptr = "" if argcount > 0: argtext += ", " - callsiargs = "Variant vargs[" + str(argcount) + "]={" - callsiargptrs = "\t\tconst Variant *vargptrs[" + str(argcount) + "]={" - callptrargsptr = "\t\tGDExtensionConstTypePtr argptrs[" + str(argcount) + "]={" + callsiargs = f"Variant vargs[{argcount}] = {{ " + callsiargptrs = f"\t\t\tconst Variant *vargptrs[{argcount}] = {{ " + callptrargsptr = f"\t\t\tGDExtensionConstTypePtr argptrs[{argcount}] = {{ " callptrargs = "" for i in range(argcount): if i > 0: @@ -118,52 +115,55 @@ def generate_version(argcount, const=False, returns=False): callargtext += ", " callsiargs += ", " callsiargptrs += ", " - callptrargs += "\t\t" + callptrargs += "\t\t\t" callptrargsptr += ", " - argtext += "m_type" + str(i + 1) - callargtext += "m_type" + str(i + 1) + " arg" + str(i + 1) - callsiargs += "Variant(arg" + str(i + 1) + ")" - callsiargptrs += "&vargs[" + str(i) + "]" + argtext += f"m_type{i + 1}" + callargtext += f"m_type{i + 1} arg{i + 1}" + callsiargs += f"Variant(arg{i + 1})" + callsiargptrs += f"&vargs[{i}]" callptrargs += ( - "PtrToArg<m_type" + str(i + 1) + ">::EncodeT argval" + str(i + 1) + " = arg" + str(i + 1) + ";\\\n" - ) - callptrargsptr += "&argval" + str(i + 1) - method_info += "\tmethod_info.arguments.push_back(GetTypeInfo<m_type" + str(i + 1) + ">::get_class_info());\\\n" - method_info += ( - "\tmethod_info.arguments_metadata.push_back(GetTypeInfo<m_type" + str(i + 1) + ">::METADATA);\\\n" + f"PtrToArg<m_type{i + 1}>::EncodeT argval{i + 1} = (PtrToArg<m_type{i + 1}>::EncodeT)arg{i + 1};\\\n" ) + callptrargsptr += f"&argval{i + 1}" + if method_info: + method_info += "\\\n\t\t" + method_info += f"method_info.arguments.push_back(GetTypeInfo<m_type{i + 1}>::get_class_info());\\\n" + method_info += f"\t\tmethod_info.arguments_metadata.push_back(GetTypeInfo<m_type{i + 1}>::METADATA);" if argcount: - callsiargs += "};\\\n" - callsiargptrs += "};\\\n" + callsiargs += " };\\\n" + callsiargptrs += " };" s = s.replace("$CALLSIARGS", callsiargs + callsiargptrs) - s = s.replace("$CALLSIARGPASS", "(const Variant **)vargptrs," + str(argcount)) - callptrargsptr += "};\\\n" + s = s.replace("$CALLSIARGPASS", f"(const Variant **)vargptrs, {argcount}") + callptrargsptr += " };" s = s.replace("$CALLPTRARGS", callptrargs + callptrargsptr) - s = s.replace("$CALLPTRARGPASS", "reinterpret_cast<GDExtensionConstTypePtr*>(argptrs)") + s = s.replace("$CALLPTRARGPASS", "reinterpret_cast<GDExtensionConstTypePtr *>(argptrs)") else: - s = s.replace("$CALLSIARGS", "") + s = s.replace("\t\t\t$CALLSIARGS\\\n", "") s = s.replace("$CALLSIARGPASS", "nullptr, 0") - s = s.replace("$CALLPTRARGS", "") + s = s.replace("\t\t\t$CALLPTRARGS\\\n", "") s = s.replace("$CALLPTRARGPASS", "nullptr") if returns: if argcount > 0: - callargtext += "," - callargtext += " m_ret& r_ret" + callargtext += ", " + callargtext += "m_ret &r_ret" s = s.replace("$CALLSIBEGIN", "Variant ret = ") s = s.replace("$CALLSIRET", "r_ret = VariantCaster<m_ret>::cast(ret);") s = s.replace("$CALLPTRRETPASS", "&ret") s = s.replace("$CALLPTRRET", "r_ret = (m_ret)ret;") else: s = s.replace("$CALLSIBEGIN", "") - s = s.replace("$CALLSIRET", "") + s = s.replace("\t\t\t\t$CALLSIRET\\\n", "") s = s.replace("$CALLPTRRETPASS", "nullptr") - s = s.replace("$CALLPTRRET", "") + s = s.replace("\t\t\t\t$CALLPTRRET\\\n", "") - s = s.replace("$ARG", argtext) + s = s.replace(" $ARG", argtext) s = s.replace("$CALLARGS", callargtext) - s = s.replace("$FILL_METHOD_INFO", method_info) + if method_info: + s = s.replace("$FILL_METHOD_INFO", method_info) + else: + s = s.replace("\t\t$FILL_METHOD_INFO\\\n", method_info) return s @@ -171,21 +171,21 @@ def generate_version(argcount, const=False, returns=False): def run(target, source, env): max_versions = 12 - txt = """ + txt = """/* THIS FILE IS GENERATED DO NOT EDIT */ #ifndef GDVIRTUAL_GEN_H #define GDVIRTUAL_GEN_H #include "core/object/script_instance.h" #ifdef TOOLS_ENABLED -#define GDVIRTUAL_TRACK(m_virtual, m_initialized) \\ - if (_get_extension()->reloadable) {\\ - VirtualMethodTracker *tracker = memnew(VirtualMethodTracker);\\ - tracker->method = (void **)&m_virtual;\\ - tracker->initialized = &m_initialized;\\ - tracker->next = virtual_method_list;\\ - virtual_method_list = tracker;\\ - } +#define GDVIRTUAL_TRACK(m_virtual, m_initialized)\\ + if (_get_extension()->reloadable) {\\ + VirtualMethodTracker *tracker = memnew(VirtualMethodTracker);\\ + tracker->method = (void **)&m_virtual;\\ + tracker->initialized = &m_initialized;\\ + tracker->next = virtual_method_list;\\ + virtual_method_list = tracker;\\ + } #else #define GDVIRTUAL_TRACK(m_virtual, m_initialized) #endif @@ -193,13 +193,13 @@ def run(target, source, env): """ for i in range(max_versions + 1): - txt += "/* " + str(i) + " Arguments */\n\n" + txt += f"/* {i} Arguments */\n\n" txt += generate_version(i, False, False) txt += generate_version(i, False, True) txt += generate_version(i, True, False) txt += generate_version(i, True, True) - txt += "#endif" + txt += "#endif // GDVIRTUAL_GEN_H\n" with open(target[0], "w") as f: f.write(txt) diff --git a/core/object/message_queue.cpp b/core/object/message_queue.cpp index de71295ee5..a394c957d0 100644 --- a/core/object/message_queue.cpp +++ b/core/object/message_queue.cpp @@ -35,6 +35,8 @@ #include "core/object/class_db.h" #include "core/object/script_language.h" +#include <stdio.h> + #ifdef DEV_ENABLED // Includes safety checks to ensure that a queue set as a thread singleton override // is only ever called from the thread it was set for. @@ -93,7 +95,7 @@ Error CallQueue::push_callablep(const Callable &p_callable, const Variant **p_ar if ((page_bytes[pages_used - 1] + room_needed) > uint32_t(PAGE_SIZE_BYTES)) { if (pages_used == max_pages) { - ERR_PRINT("Failed method: " + p_callable + ". Message queue out of memory. " + error_text); + fprintf(stderr, "Failed method: %s. Message queue out of memory. %s\n", String(p_callable).utf8().get_data(), error_text.utf8().get_data()); statistics(); UNLOCK_MUTEX; return ERR_OUT_OF_MEMORY; @@ -144,7 +146,7 @@ Error CallQueue::push_set(ObjectID p_id, const StringName &p_prop, const Variant if (ObjectDB::get_instance(p_id)) { type = ObjectDB::get_instance(p_id)->get_class(); } - ERR_PRINT("Failed set: " + type + ":" + p_prop + " target ID: " + itos(p_id) + ". Message queue out of memory. " + error_text); + fprintf(stderr, "Failed set: %s: %s target ID: %s. Message queue out of memory. %s\n", type.utf8().get_data(), String(p_prop).utf8().get_data(), itos(p_id).utf8().get_data(), error_text.utf8().get_data()); statistics(); UNLOCK_MUTEX; @@ -181,7 +183,7 @@ Error CallQueue::push_notification(ObjectID p_id, int p_notification) { if ((page_bytes[pages_used - 1] + room_needed) > uint32_t(PAGE_SIZE_BYTES)) { if (pages_used == max_pages) { - ERR_PRINT("Failed notification: " + itos(p_notification) + " target ID: " + itos(p_id) + ". Message queue out of memory. " + error_text); + fprintf(stderr, "Failed notification: %s target ID: %s. Message queue out of memory. %s\n", itos(p_notification).utf8().get_data(), itos(p_id).utf8().get_data(), error_text.utf8().get_data()); statistics(); UNLOCK_MUTEX; return ERR_OUT_OF_MEMORY; diff --git a/core/object/object.cpp b/core/object/object.cpp index 40df13849b..5a776e2106 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -1347,12 +1347,10 @@ Error Object::connect(const StringName &p_signal, const Callable &p_callable, ui s = &signal_map[p_signal]; } - Callable target = p_callable; - //compare with the base callable, so binds can be ignored - if (s->slot_map.has(*target.get_base_comparator())) { + if (s->slot_map.has(*p_callable.get_base_comparator())) { if (p_flags & CONNECT_REFERENCE_COUNTED) { - s->slot_map[*target.get_base_comparator()].reference_count++; + s->slot_map[*p_callable.get_base_comparator()].reference_count++; return OK; } else { ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Signal '" + p_signal + "' is already connected to given callable '" + p_callable + "' in that object."); @@ -1364,7 +1362,7 @@ Error Object::connect(const StringName &p_signal, const Callable &p_callable, ui SignalData::Slot slot; Connection conn; - conn.callable = target; + conn.callable = p_callable; conn.signal = ::Signal(this, p_signal); conn.flags = p_flags; slot.conn = conn; @@ -1376,7 +1374,7 @@ Error Object::connect(const StringName &p_signal, const Callable &p_callable, ui } //use callable version as key, so binds can be ignored - s->slot_map[*target.get_base_comparator()] = slot; + s->slot_map[*p_callable.get_base_comparator()] = slot; return OK; } @@ -1397,9 +1395,7 @@ bool Object::is_connected(const StringName &p_signal, const Callable &p_callable ERR_FAIL_V_MSG(false, "Nonexistent signal: " + p_signal + "."); } - Callable target = p_callable; - - return s->slot_map.has(*target.get_base_comparator()); + return s->slot_map.has(*p_callable.get_base_comparator()); } void Object::disconnect(const StringName &p_signal, const Callable &p_callable) { diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp index 086f8a666e..0b2d5e41cf 100644 --- a/core/object/script_language.cpp +++ b/core/object/script_language.cpp @@ -138,6 +138,8 @@ void Script::_bind_methods() { ClassDB::bind_method(D_METHOD("get_base_script"), &Script::get_base_script); ClassDB::bind_method(D_METHOD("get_instance_base_type"), &Script::get_instance_base_type); + ClassDB::bind_method(D_METHOD("get_global_name"), &Script::get_global_name); + ClassDB::bind_method(D_METHOD("has_script_signal", "signal_name"), &Script::has_script_signal); ClassDB::bind_method(D_METHOD("get_script_property_list"), &Script::_get_script_property_list); @@ -631,6 +633,10 @@ bool PlaceHolderScriptInstance::has_method(const StringName &p_method) const { void PlaceHolderScriptInstance::update(const List<PropertyInfo> &p_properties, const HashMap<StringName, Variant> &p_values) { HashSet<StringName> new_values; for (const PropertyInfo &E : p_properties) { + if (E.usage & (PROPERTY_USAGE_GROUP | PROPERTY_USAGE_SUBGROUP | PROPERTY_USAGE_CATEGORY)) { + continue; + } + StringName n = E.name; new_values.insert(n); diff --git a/core/object/worker_thread_pool.cpp b/core/object/worker_thread_pool.cpp index 784acadab4..631767219f 100644 --- a/core/object/worker_thread_pool.cpp +++ b/core/object/worker_thread_pool.cpp @@ -535,6 +535,11 @@ void WorkerThreadPool::wait_for_group_task_completion(GroupID p_group) { task_mutex.unlock(); } +int WorkerThreadPool::get_thread_index() { + Thread::ID tid = Thread::get_caller_id(); + return singleton->thread_ids.has(tid) ? singleton->thread_ids[tid] : -1; +} + void WorkerThreadPool::init(int p_thread_count, bool p_use_native_threads_low_priority, float p_low_priority_task_ratio) { ERR_FAIL_COND(threads.size() > 0); if (p_thread_count < 0) { diff --git a/core/object/worker_thread_pool.h b/core/object/worker_thread_pool.h index f323a979f7..dd56f95cae 100644 --- a/core/object/worker_thread_pool.h +++ b/core/object/worker_thread_pool.h @@ -197,6 +197,8 @@ public: _FORCE_INLINE_ int get_thread_count() const { return threads.size(); } static WorkerThreadPool *get_singleton() { return singleton; } + static int get_thread_index(); + void init(int p_thread_count = -1, bool p_use_native_threads_low_priority = true, float p_low_priority_task_ratio = 0.3); void finish(); WorkerThreadPool(); diff --git a/core/os/os.cpp b/core/os/os.cpp index f5d55ca107..26ae286979 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -626,17 +626,22 @@ String OS::get_benchmark_file() { return benchmark_file; } -void OS::benchmark_begin_measure(const String &p_what) { +void OS::benchmark_begin_measure(const String &p_context, const String &p_what) { #ifdef TOOLS_ENABLED - start_benchmark_from[p_what] = OS::get_singleton()->get_ticks_usec(); + Pair<String, String> mark_key(p_context, p_what); + ERR_FAIL_COND_MSG(benchmark_marks_from.has(mark_key), vformat("Benchmark key '%s:%s' already exists.", p_context, p_what)); + + benchmark_marks_from[mark_key] = OS::get_singleton()->get_ticks_usec(); #endif } -void OS::benchmark_end_measure(const String &p_what) { +void OS::benchmark_end_measure(const String &p_context, const String &p_what) { #ifdef TOOLS_ENABLED - uint64_t total = OS::get_singleton()->get_ticks_usec() - start_benchmark_from[p_what]; - double total_f = double(total) / double(1000000); + Pair<String, String> mark_key(p_context, p_what); + ERR_FAIL_COND_MSG(!benchmark_marks_from.has(mark_key), vformat("Benchmark key '%s:%s' doesn't exist.", p_context, p_what)); - startup_benchmark_json[p_what] = total_f; + uint64_t total = OS::get_singleton()->get_ticks_usec() - benchmark_marks_from[mark_key]; + double total_f = double(total) / double(1000000); + benchmark_marks_final[mark_key] = total_f; #endif } @@ -645,19 +650,33 @@ void OS::benchmark_dump() { if (!use_benchmark) { return; } + if (!benchmark_file.is_empty()) { Ref<FileAccess> f = FileAccess::open(benchmark_file, FileAccess::WRITE); if (f.is_valid()) { + Dictionary benchmark_marks; + for (const KeyValue<Pair<String, String>, double> &E : benchmark_marks_final) { + const String mark_key = vformat("[%s] %s", E.key.first, E.key.second); + benchmark_marks[mark_key] = E.value; + } + Ref<JSON> json; json.instantiate(); - f->store_string(json->stringify(startup_benchmark_json, "\t", false, true)); + f->store_string(json->stringify(benchmark_marks, "\t", false, true)); } } else { - List<Variant> keys; - startup_benchmark_json.get_key_list(&keys); + HashMap<String, String> results; + for (const KeyValue<Pair<String, String>, double> &E : benchmark_marks_final) { + if (E.key.first == "Startup" && !results.has(E.key.first)) { + results.insert(E.key.first, "", true); // Hack to make sure "Startup" always comes first. + } + + results[E.key.first] += vformat("\t\t- %s: %.3f msec.\n", E.key.second, (E.value * 1000)); + } + print_line("BENCHMARK:"); - for (const Variant &K : keys) { - print_line("\t-", K, ": ", startup_benchmark_json[K], +" sec."); + for (const KeyValue<String, String> &E : results) { + print_line(vformat("\t[%s]\n%s", E.key, E.value)); } } #endif diff --git a/core/os/os.h b/core/os/os.h index cc5ebe1bc8..e22514dce3 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -79,8 +79,8 @@ class OS { // For tracking benchmark data bool use_benchmark = false; String benchmark_file; - HashMap<String, uint64_t> start_benchmark_from; - Dictionary startup_benchmark_json; + HashMap<Pair<String, String>, uint64_t, PairHash<String, String>> benchmark_marks_from; + HashMap<Pair<String, String>, double, PairHash<String, String>> benchmark_marks_final; protected: void _set_logger(CompositeLogger *p_logger); @@ -313,8 +313,8 @@ public: bool is_use_benchmark_set(); void set_benchmark_file(const String &p_benchmark_file); String get_benchmark_file(); - virtual void benchmark_begin_measure(const String &p_what); - virtual void benchmark_end_measure(const String &p_what); + virtual void benchmark_begin_measure(const String &p_context, const String &p_what); + virtual void benchmark_end_measure(const String &p_context, const String &p_what); virtual void benchmark_dump(); virtual void process_and_drop_events() {} diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp index 4ad9dd43c4..2785d1daa5 100644 --- a/core/register_core_types.cpp +++ b/core/register_core_types.cpp @@ -120,7 +120,8 @@ static ResourceUID *resource_uid = nullptr; static bool _is_core_extensions_registered = false; void register_core_types() { - OS::get_singleton()->benchmark_begin_measure("register_core_types"); + OS::get_singleton()->benchmark_begin_measure("Core", "Register Types"); + //consistency check static_assert(sizeof(Callable) <= 16); @@ -296,7 +297,7 @@ void register_core_types() { worker_thread_pool = memnew(WorkerThreadPool); - OS::get_singleton()->benchmark_end_measure("register_core_types"); + OS::get_singleton()->benchmark_end_measure("Core", "Register Types"); } void register_core_settings() { @@ -311,6 +312,8 @@ void register_core_settings() { } void register_core_singletons() { + OS::get_singleton()->benchmark_begin_measure("Core", "Register Singletons"); + GDREGISTER_CLASS(ProjectSettings); GDREGISTER_ABSTRACT_CLASS(IP); GDREGISTER_CLASS(core_bind::Geometry2D); @@ -346,25 +349,35 @@ void register_core_singletons() { Engine::get_singleton()->add_singleton(Engine::Singleton("GDExtensionManager", GDExtensionManager::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("ResourceUID", ResourceUID::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("WorkerThreadPool", worker_thread_pool)); + + OS::get_singleton()->benchmark_end_measure("Core", "Register Singletons"); } void register_core_extensions() { + OS::get_singleton()->benchmark_begin_measure("Core", "Register Extensions"); + // Hardcoded for now. GDExtension::initialize_gdextensions(); gdextension_manager->load_extensions(); gdextension_manager->initialize_extensions(GDExtension::INITIALIZATION_LEVEL_CORE); _is_core_extensions_registered = true; + + OS::get_singleton()->benchmark_end_measure("Core", "Register Extensions"); } void unregister_core_extensions() { + OS::get_singleton()->benchmark_begin_measure("Core", "Unregister Extensions"); + if (_is_core_extensions_registered) { gdextension_manager->deinitialize_extensions(GDExtension::INITIALIZATION_LEVEL_CORE); } GDExtension::finalize_gdextensions(); + + OS::get_singleton()->benchmark_end_measure("Core", "Unregister Extensions"); } void unregister_core_types() { - OS::get_singleton()->benchmark_begin_measure("unregister_core_types"); + OS::get_singleton()->benchmark_begin_measure("Core", "Unregister Types"); // Destroy singletons in reverse order to ensure dependencies are not broken. @@ -435,5 +448,5 @@ void unregister_core_types() { CoreStringNames::free(); StringName::cleanup(); - OS::get_singleton()->benchmark_end_measure("unregister_core_types"); + OS::get_singleton()->benchmark_end_measure("Core", "Unregister Types"); } diff --git a/core/string/translation.cpp b/core/string/translation.cpp index a443ed308d..8fcf2b24b5 100644 --- a/core/string/translation.cpp +++ b/core/string/translation.cpp @@ -518,8 +518,12 @@ String TranslationServer::get_country_name(const String &p_country) const { } void TranslationServer::set_locale(const String &p_locale) { - locale = standardize_locale(p_locale); + String new_locale = standardize_locale(p_locale); + if (locale == new_locale) { + return; + } + locale = new_locale; ResourceLoader::reload_translation_remaps(); if (OS::get_singleton()->get_main_loop()) { diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp index be829502ef..a24cff4f11 100644 --- a/core/string/ustring.cpp +++ b/core/string/ustring.cpp @@ -4842,6 +4842,7 @@ String String::sprintf(const Array &values, bool *error) const { bool pad_with_zeros = false; bool left_justified = false; bool show_sign = false; + bool as_unsigned = false; if (error) { *error = true; @@ -4882,16 +4883,27 @@ String String::sprintf(const Array &values, bool *error) const { case 'x': break; case 'X': - base = 16; capitalize = true; break; } // Get basic number. - String str = String::num_int64(ABS(value), base, capitalize); + String str; + if (!as_unsigned) { + str = String::num_int64(ABS(value), base, capitalize); + } else { + uint64_t uvalue = *((uint64_t *)&value); + // In unsigned hex, if the value fits in 32 bits, trim it down to that. + if (base == 16 && value < 0 && value >= INT32_MIN) { + uvalue &= 0xffffffff; + } + str = String::num_uint64(uvalue, base, capitalize); + } int number_len = str.length(); + bool negative = value < 0 && !as_unsigned; + // Padding. - int pad_chars_count = (value < 0 || show_sign) ? min_chars - 1 : min_chars; + int pad_chars_count = (negative || show_sign) ? min_chars - 1 : min_chars; String pad_char = pad_with_zeros ? String("0") : String(" "); if (left_justified) { str = str.rpad(pad_chars_count, pad_char); @@ -4900,8 +4912,8 @@ String String::sprintf(const Array &values, bool *error) const { } // Sign. - if (show_sign || value < 0) { - String sign_char = value < 0 ? "-" : "+"; + if (show_sign || negative) { + String sign_char = negative ? "-" : "+"; if (left_justified) { str = str.insert(0, sign_char); } else { @@ -5094,6 +5106,10 @@ String String::sprintf(const Array &values, bool *error) const { show_sign = true; break; } + case 'u': { // Treat as unsigned (for int/hex). + as_unsigned = true; + break; + } case '0': case '1': case '2': diff --git a/core/templates/hashfuncs.h b/core/templates/hashfuncs.h index 2a212f3dcb..05960292f5 100644 --- a/core/templates/hashfuncs.h +++ b/core/templates/hashfuncs.h @@ -310,7 +310,7 @@ struct HashMapHasherDefault { static _FORCE_INLINE_ uint32_t hash(const char16_t p_uchar) { return hash_fmix32(p_uchar); } static _FORCE_INLINE_ uint32_t hash(const char32_t p_uchar) { return hash_fmix32(p_uchar); } static _FORCE_INLINE_ uint32_t hash(const RID &p_rid) { return hash_one_uint64(p_rid.get_id()); } - static _FORCE_INLINE_ uint32_t hash(const CharString &p_char_string) { return hash_djb2(p_char_string.ptr()); } + static _FORCE_INLINE_ uint32_t hash(const CharString &p_char_string) { return hash_djb2(p_char_string.get_data()); } static _FORCE_INLINE_ uint32_t hash(const StringName &p_string_name) { return p_string_name.hash(); } static _FORCE_INLINE_ uint32_t hash(const NodePath &p_path) { return p_path.hash(); } static _FORCE_INLINE_ uint32_t hash(const ObjectID &p_id) { return hash_one_uint64(p_id); } diff --git a/core/variant/dictionary.cpp b/core/variant/dictionary.cpp index 141ce25fa6..8b61a8993a 100644 --- a/core/variant/dictionary.cpp +++ b/core/variant/dictionary.cpp @@ -150,6 +150,15 @@ Variant Dictionary::get(const Variant &p_key, const Variant &p_default) const { return *result; } +Variant Dictionary::get_or_add(const Variant &p_key, const Variant &p_default) { + const Variant *result = getptr(p_key); + if (!result) { + operator[](p_key) = p_default; + return p_default; + } + return *result; +} + int Dictionary::size() const { return _p->variant_map.size(); } diff --git a/core/variant/dictionary.h b/core/variant/dictionary.h index 8935d35ed9..f94a0da80a 100644 --- a/core/variant/dictionary.h +++ b/core/variant/dictionary.h @@ -58,6 +58,7 @@ public: Variant get_valid(const Variant &p_key) const; Variant get(const Variant &p_key, const Variant &p_default) const; + Variant get_or_add(const Variant &p_key, const Variant &p_default); int size() const; bool is_empty() const; diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp index 4c0212075b..c352d800f9 100644 --- a/core/variant/variant.cpp +++ b/core/variant/variant.cpp @@ -931,7 +931,7 @@ bool Variant::is_zero() const { return *reinterpret_cast<const ::RID *>(_data._mem) == ::RID(); } case OBJECT: { - return _get_obj().obj == nullptr; + return get_validated_object() == nullptr; } case CALLABLE: { return reinterpret_cast<const Callable *>(_data._mem)->is_null(); diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index f041d2c95e..7121b4da96 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -2195,6 +2195,7 @@ static void _register_variant_builtin_methods() { bind_method(Dictionary, values, sarray(), varray()); bind_method(Dictionary, duplicate, sarray("deep"), varray(false)); bind_method(Dictionary, get, sarray("key", "default"), varray(Variant())); + bind_method(Dictionary, get_or_add, sarray("key", "default"), varray(Variant())); bind_method(Dictionary, make_read_only, sarray(), varray()); bind_method(Dictionary, is_read_only, sarray(), varray()); diff --git a/core/variant/variant_internal.h b/core/variant/variant_internal.h index 116210e8de..171074188f 100644 --- a/core/variant/variant_internal.h +++ b/core/variant/variant_internal.h @@ -1302,192 +1302,192 @@ struct VariantInitializer<Object *> { }; template <class T> -struct VariantZeroAssigner { +struct VariantDefaultInitializer { }; template <> -struct VariantZeroAssigner<bool> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_bool(v) = false; } +struct VariantDefaultInitializer<bool> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_bool(v) = false; } }; template <> -struct VariantZeroAssigner<int64_t> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_int(v) = 0; } +struct VariantDefaultInitializer<int64_t> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_int(v) = 0; } }; template <> -struct VariantZeroAssigner<double> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_float(v) = 0.0; } +struct VariantDefaultInitializer<double> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_float(v) = 0.0; } }; template <> -struct VariantZeroAssigner<float> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_float(v) = 0.0; } +struct VariantDefaultInitializer<float> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_float(v) = 0.0; } }; template <> -struct VariantZeroAssigner<String> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_string(v) = String(); } +struct VariantDefaultInitializer<String> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_string(v) = String(); } }; template <> -struct VariantZeroAssigner<Vector2> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_vector2(v) = Vector2(); } +struct VariantDefaultInitializer<Vector2> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_vector2(v) = Vector2(); } }; template <> -struct VariantZeroAssigner<Vector2i> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_vector2i(v) = Vector2i(); } +struct VariantDefaultInitializer<Vector2i> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_vector2i(v) = Vector2i(); } }; template <> -struct VariantZeroAssigner<Rect2> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_rect2(v) = Rect2(); } +struct VariantDefaultInitializer<Rect2> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_rect2(v) = Rect2(); } }; template <> -struct VariantZeroAssigner<Rect2i> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_rect2i(v) = Rect2i(); } +struct VariantDefaultInitializer<Rect2i> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_rect2i(v) = Rect2i(); } }; template <> -struct VariantZeroAssigner<Vector3> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_vector3(v) = Vector3(); } +struct VariantDefaultInitializer<Vector3> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_vector3(v) = Vector3(); } }; template <> -struct VariantZeroAssigner<Vector3i> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_vector3i(v) = Vector3i(); } +struct VariantDefaultInitializer<Vector3i> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_vector3i(v) = Vector3i(); } }; template <> -struct VariantZeroAssigner<Vector4> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_vector4(v) = Vector4(); } +struct VariantDefaultInitializer<Vector4> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_vector4(v) = Vector4(); } }; template <> -struct VariantZeroAssigner<Vector4i> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_vector4i(v) = Vector4i(); } +struct VariantDefaultInitializer<Vector4i> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_vector4i(v) = Vector4i(); } }; template <> -struct VariantZeroAssigner<Transform2D> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_transform2d(v) = Transform2D(); } +struct VariantDefaultInitializer<Transform2D> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_transform2d(v) = Transform2D(); } }; template <> -struct VariantZeroAssigner<Plane> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_plane(v) = Plane(); } +struct VariantDefaultInitializer<Plane> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_plane(v) = Plane(); } }; template <> -struct VariantZeroAssigner<Quaternion> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_quaternion(v) = Quaternion(); } +struct VariantDefaultInitializer<Quaternion> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_quaternion(v) = Quaternion(); } }; template <> -struct VariantZeroAssigner<AABB> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_aabb(v) = AABB(); } +struct VariantDefaultInitializer<AABB> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_aabb(v) = AABB(); } }; template <> -struct VariantZeroAssigner<Basis> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_basis(v) = Basis(); } +struct VariantDefaultInitializer<Basis> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_basis(v) = Basis(); } }; template <> -struct VariantZeroAssigner<Transform3D> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_transform(v) = Transform3D(); } +struct VariantDefaultInitializer<Transform3D> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_transform(v) = Transform3D(); } }; template <> -struct VariantZeroAssigner<Projection> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_projection(v) = Projection(); } +struct VariantDefaultInitializer<Projection> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_projection(v) = Projection(); } }; template <> -struct VariantZeroAssigner<Color> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_color(v) = Color(); } +struct VariantDefaultInitializer<Color> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_color(v) = Color(); } }; template <> -struct VariantZeroAssigner<StringName> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_string_name(v) = StringName(); } +struct VariantDefaultInitializer<StringName> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_string_name(v) = StringName(); } }; template <> -struct VariantZeroAssigner<NodePath> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_node_path(v) = NodePath(); } +struct VariantDefaultInitializer<NodePath> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_node_path(v) = NodePath(); } }; template <> -struct VariantZeroAssigner<::RID> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_rid(v) = RID(); } +struct VariantDefaultInitializer<::RID> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_rid(v) = RID(); } }; template <> -struct VariantZeroAssigner<Callable> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_callable(v) = Callable(); } +struct VariantDefaultInitializer<Callable> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_callable(v) = Callable(); } }; template <> -struct VariantZeroAssigner<Signal> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_signal(v) = Signal(); } +struct VariantDefaultInitializer<Signal> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_signal(v) = Signal(); } }; template <> -struct VariantZeroAssigner<Dictionary> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_dictionary(v) = Dictionary(); } +struct VariantDefaultInitializer<Dictionary> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_dictionary(v) = Dictionary(); } }; template <> -struct VariantZeroAssigner<Array> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_array(v) = Array(); } +struct VariantDefaultInitializer<Array> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_array(v) = Array(); } }; template <> -struct VariantZeroAssigner<PackedByteArray> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_byte_array(v) = PackedByteArray(); } +struct VariantDefaultInitializer<PackedByteArray> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_byte_array(v) = PackedByteArray(); } }; template <> -struct VariantZeroAssigner<PackedInt32Array> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_int32_array(v) = PackedInt32Array(); } +struct VariantDefaultInitializer<PackedInt32Array> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_int32_array(v) = PackedInt32Array(); } }; template <> -struct VariantZeroAssigner<PackedInt64Array> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_int64_array(v) = PackedInt64Array(); } +struct VariantDefaultInitializer<PackedInt64Array> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_int64_array(v) = PackedInt64Array(); } }; template <> -struct VariantZeroAssigner<PackedFloat32Array> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_float32_array(v) = PackedFloat32Array(); } +struct VariantDefaultInitializer<PackedFloat32Array> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_float32_array(v) = PackedFloat32Array(); } }; template <> -struct VariantZeroAssigner<PackedFloat64Array> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_float64_array(v) = PackedFloat64Array(); } +struct VariantDefaultInitializer<PackedFloat64Array> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_float64_array(v) = PackedFloat64Array(); } }; template <> -struct VariantZeroAssigner<PackedStringArray> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_string_array(v) = PackedStringArray(); } +struct VariantDefaultInitializer<PackedStringArray> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_string_array(v) = PackedStringArray(); } }; template <> -struct VariantZeroAssigner<PackedVector2Array> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_vector2_array(v) = PackedVector2Array(); } +struct VariantDefaultInitializer<PackedVector2Array> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_vector2_array(v) = PackedVector2Array(); } }; template <> -struct VariantZeroAssigner<PackedVector3Array> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_vector3_array(v) = PackedVector3Array(); } +struct VariantDefaultInitializer<PackedVector3Array> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_vector3_array(v) = PackedVector3Array(); } }; template <> -struct VariantZeroAssigner<PackedColorArray> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_color_array(v) = PackedColorArray(); } +struct VariantDefaultInitializer<PackedColorArray> { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_color_array(v) = PackedColorArray(); } }; template <class T> @@ -1504,7 +1504,7 @@ struct VariantTypeChanger { VariantInitializer<T>::init(v); } - VariantZeroAssigner<T>::zero(v); + VariantDefaultInitializer<T>::init(v); } }; diff --git a/core/variant/variant_op.h b/core/variant/variant_op.h index 9e6367ab6d..17ad126891 100644 --- a/core/variant/variant_op.h +++ b/core/variant/variant_op.h @@ -549,14 +549,14 @@ public: class OperatorEvaluatorEqualObject { public: static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const Object *a = p_left.get_validated_object(); - const Object *b = p_right.get_validated_object(); + const ObjectID &a = VariantInternal::get_object_id(&p_left); + const ObjectID &b = VariantInternal::get_object_id(&p_right); *r_ret = a == b; r_valid = true; } static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - const Object *a = left->get_validated_object(); - const Object *b = right->get_validated_object(); + const ObjectID &a = VariantInternal::get_object_id(left); + const ObjectID &b = VariantInternal::get_object_id(right); *VariantGetInternalPtr<bool>::get_ptr(r_ret) = a == b; } static void ptr_evaluate(const void *left, const void *right, void *r_ret) { @@ -568,12 +568,12 @@ public: class OperatorEvaluatorEqualObjectNil { public: static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const Object *a = p_left.get_validated_object(); + const Object *a = p_left.operator Object *(); *r_ret = a == nullptr; r_valid = true; } static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - const Object *a = left->get_validated_object(); + const Object *a = left->operator Object *(); *VariantGetInternalPtr<bool>::get_ptr(r_ret) = a == nullptr; } static void ptr_evaluate(const void *left, const void *right, void *r_ret) { @@ -585,12 +585,12 @@ public: class OperatorEvaluatorEqualNilObject { public: static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const Object *b = p_right.get_validated_object(); + const Object *b = p_right.operator Object *(); *r_ret = nullptr == b; r_valid = true; } static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - const Object *b = right->get_validated_object(); + const Object *b = right->operator Object *(); *VariantGetInternalPtr<bool>::get_ptr(r_ret) = nullptr == b; } static void ptr_evaluate(const void *left, const void *right, void *r_ret) { @@ -620,14 +620,14 @@ public: class OperatorEvaluatorNotEqualObject { public: static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - Object *a = p_left.get_validated_object(); - Object *b = p_right.get_validated_object(); + const ObjectID &a = VariantInternal::get_object_id(&p_left); + const ObjectID &b = VariantInternal::get_object_id(&p_right); *r_ret = a != b; r_valid = true; } static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - Object *a = left->get_validated_object(); - Object *b = right->get_validated_object(); + const ObjectID &a = VariantInternal::get_object_id(left); + const ObjectID &b = VariantInternal::get_object_id(right); *VariantGetInternalPtr<bool>::get_ptr(r_ret) = a != b; } static void ptr_evaluate(const void *left, const void *right, void *r_ret) { @@ -639,12 +639,12 @@ public: class OperatorEvaluatorNotEqualObjectNil { public: static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - Object *a = p_left.get_validated_object(); + Object *a = p_left.operator Object *(); *r_ret = a != nullptr; r_valid = true; } static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - Object *a = left->get_validated_object(); + Object *a = left->operator Object *(); *VariantGetInternalPtr<bool>::get_ptr(r_ret) = a != nullptr; } static void ptr_evaluate(const void *left, const void *right, void *r_ret) { @@ -656,12 +656,12 @@ public: class OperatorEvaluatorNotEqualNilObject { public: static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - Object *b = p_right.get_validated_object(); + Object *b = p_right.operator Object *(); *r_ret = nullptr != b; r_valid = true; } static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - Object *b = right->get_validated_object(); + Object *b = right->operator Object *(); *VariantGetInternalPtr<bool>::get_ptr(r_ret) = nullptr != b; } static void ptr_evaluate(const void *left, const void *right, void *r_ret) { diff --git a/core/variant/variant_parser.cpp b/core/variant/variant_parser.cpp index 86e7654090..e35751fd61 100644 --- a/core/variant/variant_parser.cpp +++ b/core/variant/variant_parser.cpp @@ -1026,7 +1026,10 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, Ref<Resource> res; Error err = p_res_parser->ext_func(p_res_parser->userdata, p_stream, res, line, r_err_str); if (err) { - return err; + // If the file is missing, the error can be ignored. + if (err != ERR_FILE_NOT_FOUND && err != ERR_CANT_OPEN) { + return err; + } } value = res; |