From 341ca31be884cc6aa24534c3784d135215cf9662 Mon Sep 17 00:00:00 2001 From: Hugo Locurcio Date: Fri, 26 Jan 2024 18:02:46 +0100 Subject: [PATCH 01/23] Change scene drag-and-drop modifier behavior in the 2D and 3D editors Behavior is now consistent across 2D and 3D editors. - By default, drag-and-dropping adds the scene as a child of the selected node. Hold Alt when releasing the mouse to add the scene as a child of the root node, or Shift to add the scene as a sibling of the selected node. - To choose a different node type in the 2D editor when drag-and-dropping a texture resource, hold Alt + Shift (instead of just Alt). - If multiple nodes are selected, only the first one is taken into account. This was previously the behavior in 2D, but not in 3D (an error dialog appeared instead). This makes the UI more forgiving. --- editor/plugins/canvas_item_editor_plugin.cpp | 13 +++++----- editor/plugins/node_3d_editor_plugin.cpp | 27 ++++++++------------ 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 30e0dc95c7..626da0e3b3 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -5659,7 +5659,7 @@ void CanvasItemEditorViewport::_create_preview(const Vector &files) cons Ref scene = Ref(Object::cast_to(*res)); if (texture != nullptr || scene != nullptr) { bool root_node_selected = EditorNode::get_singleton()->get_editor_selection()->is_selected(EditorNode::get_singleton()->get_edited_scene()); - String desc = TTR("Drag and drop to add as child of current scene's root node.") + "\n" + vformat(TTR("Hold %s when dropping to add as child of selected node."), keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL)); + String desc = TTR("Drag and drop to add as child of selected node.") + "\n" + TTR("Hold Alt when dropping to add as child of root node."); if (!root_node_selected) { desc += "\n" + TTR("Hold Shift when dropping to add as sibling of selected node."); } @@ -5670,7 +5670,7 @@ void CanvasItemEditorViewport::_create_preview(const Vector &files) cons preview_node->add_child(sprite); label->show(); label_desc->show(); - desc += "\n" + TTR("Hold Alt when dropping to add as a different node type."); + desc += "\n" + TTR("Hold Alt + Shift when dropping to add as a different node type."); label_desc->set_text(desc); } else { if (scene.is_valid()) { @@ -5963,7 +5963,6 @@ bool CanvasItemEditorViewport::_only_packed_scenes_selected() const { void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p_data) { bool is_shift = Input::get_singleton()->is_key_pressed(Key::SHIFT); - bool is_ctrl = Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL); bool is_alt = Input::get_singleton()->is_key_pressed(Key::ALT); selected_files.clear(); @@ -5979,9 +5978,9 @@ void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p Node *root_node = EditorNode::get_singleton()->get_edited_scene(); if (selected_nodes.size() > 0) { Node *selected_node = selected_nodes[0]; - target_node = root_node; - if (is_ctrl) { - target_node = selected_node; + target_node = selected_node; + if (is_alt) { + target_node = root_node; } else if (is_shift && selected_node != root_node) { target_node = selected_node->get_parent(); } @@ -5995,7 +5994,7 @@ void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p drop_pos = p_point; - if (is_alt && !_only_packed_scenes_selected()) { + if (is_alt && is_shift && !_only_packed_scenes_selected()) { _show_resource_type_selector(); } else { _perform_drop_data(); diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index e4d24832bf..c57265166d 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -4530,7 +4530,7 @@ void Node3DEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p_ } bool is_shift = Input::get_singleton()->is_key_pressed(Key::SHIFT); - bool is_ctrl = Input::get_singleton()->is_key_pressed(Key::CTRL); + bool is_alt = Input::get_singleton()->is_key_pressed(Key::ALT); selected_files.clear(); Dictionary d = p_data; @@ -4540,15 +4540,15 @@ void Node3DEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p_ List selected_nodes = EditorNode::get_singleton()->get_editor_selection()->get_selected_node_list(); Node *root_node = EditorNode::get_singleton()->get_edited_scene(); - if (selected_nodes.size() == 1) { + if (selected_nodes.size() > 0) { Node *selected_node = selected_nodes[0]; - target_node = root_node; - if (is_ctrl) { - target_node = selected_node; + target_node = selected_node; + if (is_alt) { + target_node = root_node; } else if (is_shift && selected_node != root_node) { target_node = selected_node->get_parent(); } - } else if (selected_nodes.size() == 0) { + } else { if (root_node) { target_node = root_node; } else { @@ -4556,11 +4556,6 @@ void Node3DEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p_ SceneTreeDock::get_singleton()->add_root_node(memnew(Node3D)); target_node = get_tree()->get_edited_scene_root(); } - } else { - accept->set_text(TTR("Cannot drag and drop into multiple selected nodes.")); - accept->popup_centered(); - _remove_preview_node(); - return; } drop_pos = p_point; @@ -6500,20 +6495,20 @@ void vertex() { // Points are already in world space, so no need for MODEL_MATRIX anymore. vec4 clip_a = PROJECTION_MATRIX * (VIEW_MATRIX * vec4(point_a, 1.0)); vec4 clip_b = PROJECTION_MATRIX * (VIEW_MATRIX * vec4(point_b, 1.0)); - + vec2 screen_a = VIEWPORT_SIZE * (0.5 * clip_a.xy / clip_a.w + 0.5); vec2 screen_b = VIEWPORT_SIZE * (0.5 * clip_b.xy / clip_b.w + 0.5); - + vec2 x_basis = normalize(screen_b - screen_a); vec2 y_basis = vec2(-x_basis.y, x_basis.x); - + float width = 3.0; vec2 screen_point_a = screen_a + width * (VERTEX.x * x_basis + VERTEX.y * y_basis); vec2 screen_point_b = screen_b + width * (VERTEX.x * x_basis + VERTEX.y * y_basis); vec2 screen_point_final = mix(screen_point_a, screen_point_b, VERTEX.z); - + vec4 clip_final = mix(clip_a, clip_b, VERTEX.z); - + POSITION = vec4(clip_final.w * ((2.0 * screen_point_final) / VIEWPORT_SIZE - 1.0), clip_final.z, clip_final.w); UV = VERTEX.yz * clip_final.w; From aed5ea946036e6c2c8a0165265bb6b038b3db8cb Mon Sep 17 00:00:00 2001 From: Aaron Franke Date: Wed, 8 Nov 2023 16:56:19 -0600 Subject: [PATCH 02/23] Expose a method to get gravity for any physics body --- doc/classes/PhysicsBody2D.xml | 6 ++++++ doc/classes/PhysicsBody3D.xml | 6 ++++++ .../script_templates/CharacterBody2D/basic_movement.gd | 5 +---- .../script_templates/CharacterBody3D/basic_movement.gd | 5 +---- .../script_templates/CharacterBody2D/basic_movement.cs | 9 +++++---- .../script_templates/CharacterBody3D/basic_movement.cs | 9 +++++---- scene/2d/physics_body_2d.cpp | 5 +++++ scene/2d/physics_body_2d.h | 1 + scene/3d/physics_body_3d.cpp | 5 +++++ scene/3d/physics_body_3d.h | 1 + 10 files changed, 36 insertions(+), 16 deletions(-) diff --git a/doc/classes/PhysicsBody2D.xml b/doc/classes/PhysicsBody2D.xml index adfdfdc445..eef159d44d 100644 --- a/doc/classes/PhysicsBody2D.xml +++ b/doc/classes/PhysicsBody2D.xml @@ -23,6 +23,12 @@ Returns an array of nodes that were added as collision exceptions for this body. + + + + Returns the gravity vector computed from all sources that can affect the body, including all gravity overrides from [Area2D] nodes and the global world gravity. + + diff --git a/doc/classes/PhysicsBody3D.xml b/doc/classes/PhysicsBody3D.xml index ff994fe6c5..866b3e298c 100644 --- a/doc/classes/PhysicsBody3D.xml +++ b/doc/classes/PhysicsBody3D.xml @@ -31,6 +31,12 @@ Returns an array of nodes that were added as collision exceptions for this body. + + + + Returns the gravity vector computed from all sources that can affect the body, including all gravity overrides from [Area3D] nodes and the global world gravity. + + diff --git a/modules/gdscript/editor/script_templates/CharacterBody2D/basic_movement.gd b/modules/gdscript/editor/script_templates/CharacterBody2D/basic_movement.gd index 28ab080dd2..bd4816827f 100644 --- a/modules/gdscript/editor/script_templates/CharacterBody2D/basic_movement.gd +++ b/modules/gdscript/editor/script_templates/CharacterBody2D/basic_movement.gd @@ -6,14 +6,11 @@ extends _BASE_ const SPEED = 300.0 const JUMP_VELOCITY = -400.0 -# Get the gravity from the project settings to be synced with RigidBody nodes. -var gravity: int = ProjectSettings.get_setting("physics/2d/default_gravity") - func _physics_process(delta: float) -> void: # Add the gravity. if not is_on_floor(): - velocity.y += gravity * delta + velocity += get_gravity() * delta # Handle jump. if Input.is_action_just_pressed("ui_accept") and is_on_floor(): diff --git a/modules/gdscript/editor/script_templates/CharacterBody3D/basic_movement.gd b/modules/gdscript/editor/script_templates/CharacterBody3D/basic_movement.gd index 9b0e4be4ed..f9c4f70a24 100644 --- a/modules/gdscript/editor/script_templates/CharacterBody3D/basic_movement.gd +++ b/modules/gdscript/editor/script_templates/CharacterBody3D/basic_movement.gd @@ -6,14 +6,11 @@ extends _BASE_ const SPEED = 5.0 const JUMP_VELOCITY = 4.5 -# Get the gravity from the project settings to be synced with RigidBody nodes. -var gravity: float = ProjectSettings.get_setting("physics/3d/default_gravity") - func _physics_process(delta: float) -> void: # Add the gravity. if not is_on_floor(): - velocity.y -= gravity * delta + velocity += get_gravity() * delta # Handle jump. if Input.is_action_just_pressed("ui_accept") and is_on_floor(): diff --git a/modules/mono/editor/script_templates/CharacterBody2D/basic_movement.cs b/modules/mono/editor/script_templates/CharacterBody2D/basic_movement.cs index 87468fb433..698157c6b4 100644 --- a/modules/mono/editor/script_templates/CharacterBody2D/basic_movement.cs +++ b/modules/mono/editor/script_templates/CharacterBody2D/basic_movement.cs @@ -8,20 +8,21 @@ public partial class _CLASS_ : _BASE_ public const float Speed = 300.0f; public const float JumpVelocity = -400.0f; - // Get the gravity from the project settings to be synced with RigidBody nodes. - public float gravity = ProjectSettings.GetSetting("physics/2d/default_gravity").AsSingle(); - public override void _PhysicsProcess(double delta) { Vector2 velocity = Velocity; // Add the gravity. if (!IsOnFloor()) - velocity.Y += gravity * (float)delta; + { + velocity += GetGravity() * (float)delta; + } // Handle Jump. if (Input.IsActionJustPressed("ui_accept") && IsOnFloor()) + { velocity.Y = JumpVelocity; + } // Get the input direction and handle the movement/deceleration. // As good practice, you should replace UI actions with custom gameplay actions. diff --git a/modules/mono/editor/script_templates/CharacterBody3D/basic_movement.cs b/modules/mono/editor/script_templates/CharacterBody3D/basic_movement.cs index ddeb9d7e00..30dabd31d9 100644 --- a/modules/mono/editor/script_templates/CharacterBody3D/basic_movement.cs +++ b/modules/mono/editor/script_templates/CharacterBody3D/basic_movement.cs @@ -8,20 +8,21 @@ public partial class _CLASS_ : _BASE_ public const float Speed = 5.0f; public const float JumpVelocity = 4.5f; - // Get the gravity from the project settings to be synced with RigidBody nodes. - public float gravity = ProjectSettings.GetSetting("physics/3d/default_gravity").AsSingle(); - public override void _PhysicsProcess(double delta) { Vector3 velocity = Velocity; // Add the gravity. if (!IsOnFloor()) - velocity.Y -= gravity * (float)delta; + { + velocity += GetGravity() * (float)delta; + } // Handle Jump. if (Input.IsActionJustPressed("ui_accept") && IsOnFloor()) + { velocity.Y = JumpVelocity; + } // Get the input direction and handle the movement/deceleration. // As good practice, you should replace UI actions with custom gameplay actions. diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index 6af5a8dd80..7a131916e8 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -35,6 +35,7 @@ void PhysicsBody2D::_bind_methods() { ClassDB::bind_method(D_METHOD("move_and_collide", "motion", "test_only", "safe_margin", "recovery_as_collision"), &PhysicsBody2D::_move, DEFVAL(false), DEFVAL(0.08), DEFVAL(false)); ClassDB::bind_method(D_METHOD("test_move", "from", "motion", "collision", "safe_margin", "recovery_as_collision"), &PhysicsBody2D::test_move, DEFVAL(Variant()), DEFVAL(0.08), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_gravity"), &PhysicsBody2D::get_gravity); ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody2D::get_collision_exceptions); ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody2D::add_collision_exception_with); @@ -145,6 +146,10 @@ bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), parameters, r); } +Vector2 PhysicsBody2D::get_gravity() const { + return PhysicsServer2D::get_singleton()->body_get_direct_state(get_rid())->get_total_gravity(); +} + TypedArray PhysicsBody2D::get_collision_exceptions() { List exceptions; PhysicsServer2D::get_singleton()->body_get_collision_exceptions(get_rid(), &exceptions); diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h index 208e72c40f..62636b02f4 100644 --- a/scene/2d/physics_body_2d.h +++ b/scene/2d/physics_body_2d.h @@ -52,6 +52,7 @@ protected: public: bool move_and_collide(const PhysicsServer2D::MotionParameters &p_parameters, PhysicsServer2D::MotionResult &r_result, bool p_test_only = false, bool p_cancel_sliding = true); bool test_move(const Transform2D &p_from, const Vector2 &p_motion, const Ref &r_collision = Ref(), real_t p_margin = 0.08, bool p_recovery_as_collision = false); + Vector2 get_gravity() const; TypedArray get_collision_exceptions(); void add_collision_exception_with(Node *p_node); //must be physicsbody diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp index ed64c16564..b11dfec104 100644 --- a/scene/3d/physics_body_3d.cpp +++ b/scene/3d/physics_body_3d.cpp @@ -35,6 +35,7 @@ void PhysicsBody3D::_bind_methods() { ClassDB::bind_method(D_METHOD("move_and_collide", "motion", "test_only", "safe_margin", "recovery_as_collision", "max_collisions"), &PhysicsBody3D::_move, DEFVAL(false), DEFVAL(0.001), DEFVAL(false), DEFVAL(1)); ClassDB::bind_method(D_METHOD("test_move", "from", "motion", "collision", "safe_margin", "recovery_as_collision", "max_collisions"), &PhysicsBody3D::test_move, DEFVAL(Variant()), DEFVAL(0.001), DEFVAL(false), DEFVAL(1)); + ClassDB::bind_method(D_METHOD("get_gravity"), &PhysicsBody3D::get_gravity); ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &PhysicsBody3D::set_axis_lock); ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &PhysicsBody3D::get_axis_lock); @@ -186,6 +187,10 @@ bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_motion return PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), parameters, r); } +Vector3 PhysicsBody3D::get_gravity() const { + return PhysicsServer3D::get_singleton()->body_get_direct_state(get_rid())->get_total_gravity(); +} + void PhysicsBody3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock) { if (p_lock) { locked_axis |= p_axis; diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h index e8d5ef2103..e8373d5907 100644 --- a/scene/3d/physics_body_3d.h +++ b/scene/3d/physics_body_3d.h @@ -55,6 +55,7 @@ protected: public: bool move_and_collide(const PhysicsServer3D::MotionParameters &p_parameters, PhysicsServer3D::MotionResult &r_result, bool p_test_only = false, bool p_cancel_sliding = true); bool test_move(const Transform3D &p_from, const Vector3 &p_motion, const Ref &r_collision = Ref(), real_t p_margin = 0.001, bool p_recovery_as_collision = false, int p_max_collisions = 1); + Vector3 get_gravity() const; void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock); bool get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const; From 55ed34e37c61ae53e676f73a2e4444d7ecb4ce7d Mon Sep 17 00:00:00 2001 From: vittorioromeo Date: Fri, 2 Feb 2024 15:43:21 +0100 Subject: [PATCH 03/23] Use '_v' shorthand for type traits and 'if constexpr' where appropriate --- core/object/class_db.h | 20 +++++++++---------- core/os/memory.h | 8 ++++---- core/templates/cowdata.h | 8 ++++---- core/templates/local_vector.h | 10 +++++----- core/templates/paged_allocator.h | 2 +- core/templates/paged_array.h | 10 +++++----- core/templates/safe_refcount.h | 2 +- core/variant/binder_common.h | 8 ++++---- core/variant/type_info.h | 12 ++++------- .../rendering/storage/variant_converters.h | 6 +++--- 10 files changed, 41 insertions(+), 45 deletions(-) diff --git a/core/object/class_db.h b/core/object/class_db.h index 7a4ee1afa4..21243230de 100644 --- a/core/object/class_db.h +++ b/core/object/class_db.h @@ -188,7 +188,7 @@ public: template static void register_class(bool p_virtual = false) { GLOBAL_LOCK_FUNCTION; - static_assert(TypesAreSame::value, "Class not declared properly, please use GDCLASS."); + static_assert(types_are_same_v, "Class not declared properly, please use GDCLASS."); T::initialize_class(); ClassInfo *t = classes.getptr(T::get_class_static()); ERR_FAIL_NULL(t); @@ -203,7 +203,7 @@ public: template static void register_abstract_class() { GLOBAL_LOCK_FUNCTION; - static_assert(TypesAreSame::value, "Class not declared properly, please use GDCLASS."); + static_assert(types_are_same_v, "Class not declared properly, please use GDCLASS."); T::initialize_class(); ClassInfo *t = classes.getptr(T::get_class_static()); ERR_FAIL_NULL(t); @@ -216,7 +216,7 @@ public: template static void register_internal_class() { GLOBAL_LOCK_FUNCTION; - static_assert(TypesAreSame::value, "Class not declared properly, please use GDCLASS."); + static_assert(types_are_same_v, "Class not declared properly, please use GDCLASS."); T::initialize_class(); ClassInfo *t = classes.getptr(T::get_class_static()); ERR_FAIL_NULL(t); @@ -239,7 +239,7 @@ public: template static void register_custom_instance_class() { GLOBAL_LOCK_FUNCTION; - static_assert(TypesAreSame::value, "Class not declared properly, please use GDCLASS."); + static_assert(types_are_same_v, "Class not declared properly, please use GDCLASS."); T::initialize_class(); ClassInfo *t = classes.getptr(T::get_class_static()); ERR_FAIL_NULL(t); @@ -296,7 +296,7 @@ public: argptrs[i] = &args[i]; } MethodBind *bind = create_method_bind(p_method); - if constexpr (std::is_same::return_type, Object *>::value) { + if constexpr (std::is_same_v::return_type, Object *>) { bind->set_return_type_is_raw_object_ptr(true); } return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, false, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args)); @@ -311,7 +311,7 @@ public: } MethodBind *bind = create_static_method_bind(p_method); bind->set_instance_class(p_class); - if constexpr (std::is_same::return_type, Object *>::value) { + if constexpr (std::is_same_v::return_type, Object *>) { bind->set_return_type_is_raw_object_ptr(true); } return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, false, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args)); @@ -325,7 +325,7 @@ public: argptrs[i] = &args[i]; } MethodBind *bind = create_method_bind(p_method); - if constexpr (std::is_same::return_type, Object *>::value) { + if constexpr (std::is_same_v::return_type, Object *>) { bind->set_return_type_is_raw_object_ptr(true); } return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, true, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args)); @@ -340,7 +340,7 @@ public: } MethodBind *bind = create_static_method_bind(p_method); bind->set_instance_class(p_class); - if constexpr (std::is_same::return_type, Object *>::value) { + if constexpr (std::is_same_v::return_type, Object *>) { bind->set_return_type_is_raw_object_ptr(true); } return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, true, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args)); @@ -353,7 +353,7 @@ public: MethodBind *bind = create_vararg_method_bind(p_method, p_info, p_return_nil_is_variant); ERR_FAIL_NULL_V(bind, nullptr); - if constexpr (std::is_same::return_type, Object *>::value) { + if constexpr (std::is_same_v::return_type, Object *>) { bind->set_return_type_is_raw_object_ptr(true); } return _bind_vararg_method(bind, p_name, p_default_args, false); @@ -366,7 +366,7 @@ public: MethodBind *bind = create_vararg_method_bind(p_method, p_info, p_return_nil_is_variant); ERR_FAIL_NULL_V(bind, nullptr); - if constexpr (std::is_same::return_type, Object *>::value) { + if constexpr (std::is_same_v::return_type, Object *>) { bind->set_return_type_is_raw_object_ptr(true); } return _bind_vararg_method(bind, p_name, p_default_args, true); diff --git a/core/os/memory.h b/core/os/memory.h index a0524b0ea2..a43a15e58f 100644 --- a/core/os/memory.h +++ b/core/os/memory.h @@ -105,7 +105,7 @@ void memdelete(T *p_class) { if (!predelete_handler(p_class)) { return; // doesn't want to be deleted } - if (!std::is_trivially_destructible::value) { + if constexpr (!std::is_trivially_destructible_v) { p_class->~T(); } @@ -117,7 +117,7 @@ void memdelete_allocator(T *p_class) { if (!predelete_handler(p_class)) { return; // doesn't want to be deleted } - if (!std::is_trivially_destructible::value) { + if constexpr (!std::is_trivially_destructible_v) { p_class->~T(); } @@ -147,7 +147,7 @@ T *memnew_arr_template(size_t p_elements) { ERR_FAIL_NULL_V(mem, failptr); *(mem - 1) = p_elements; - if (!std::is_trivially_constructible::value) { + if constexpr (!std::is_trivially_constructible_v) { T *elems = (T *)mem; /* call operator new */ @@ -174,7 +174,7 @@ template void memdelete_arr(T *p_class) { uint64_t *ptr = (uint64_t *)p_class; - if (!std::is_trivially_destructible::value) { + if constexpr (!std::is_trivially_destructible_v) { uint64_t elem_count = *(ptr - 1); for (uint64_t i = 0; i < elem_count; i++) { diff --git a/core/templates/cowdata.h b/core/templates/cowdata.h index d43cf8107f..a0632b2645 100644 --- a/core/templates/cowdata.h +++ b/core/templates/cowdata.h @@ -233,7 +233,7 @@ void CowData::_unref(void *p_data) { } // clean up - if (!std::is_trivially_destructible::value) { + if constexpr (!std::is_trivially_destructible_v) { USize *count = _get_size(); T *data = (T *)(count + 1); @@ -269,7 +269,7 @@ typename CowData::USize CowData::_copy_on_write() { T *_data = (T *)(mem_new); // initialize new elements - if (std::is_trivially_copyable::value) { + if constexpr (std::is_trivially_copyable_v) { memcpy(mem_new, _ptr, current_size * sizeof(T)); } else { @@ -335,7 +335,7 @@ Error CowData::resize(Size p_size) { // construct the newly created elements - if (!std::is_trivially_constructible::value) { + if constexpr (!std::is_trivially_constructible_v) { for (Size i = *_get_size(); i < p_size; i++) { memnew_placement(&_ptr[i], T); } @@ -346,7 +346,7 @@ Error CowData::resize(Size p_size) { *_get_size() = p_size; } else if (p_size < current_size) { - if (!std::is_trivially_destructible::value) { + if constexpr (!std::is_trivially_destructible_v) { // deinitialize no longer needed elements for (USize i = p_size; i < *_get_size(); i++) { T *t = &_ptr[i]; diff --git a/core/templates/local_vector.h b/core/templates/local_vector.h index b454821a8f..17ddbf6161 100644 --- a/core/templates/local_vector.h +++ b/core/templates/local_vector.h @@ -64,7 +64,7 @@ public: CRASH_COND_MSG(!data, "Out of memory"); } - if constexpr (!std::is_trivially_constructible::value && !force_trivial) { + if constexpr (!std::is_trivially_constructible_v && !force_trivial) { memnew_placement(&data[count++], T(p_elem)); } else { data[count++] = p_elem; @@ -77,7 +77,7 @@ public: for (U i = p_index; i < count; i++) { data[i] = data[i + 1]; } - if constexpr (!std::is_trivially_destructible::value && !force_trivial) { + if constexpr (!std::is_trivially_destructible_v && !force_trivial) { data[count].~T(); } } @@ -90,7 +90,7 @@ public: if (count > p_index) { data[p_index] = data[count]; } - if constexpr (!std::is_trivially_destructible::value && !force_trivial) { + if constexpr (!std::is_trivially_destructible_v && !force_trivial) { data[count].~T(); } } @@ -133,7 +133,7 @@ public: _FORCE_INLINE_ U size() const { return count; } void resize(U p_size) { if (p_size < count) { - if constexpr (!std::is_trivially_destructible::value && !force_trivial) { + if constexpr (!std::is_trivially_destructible_v && !force_trivial) { for (U i = p_size; i < count; i++) { data[i].~T(); } @@ -145,7 +145,7 @@ public: data = (T *)memrealloc(data, capacity * sizeof(T)); CRASH_COND_MSG(!data, "Out of memory"); } - if constexpr (!std::is_trivially_constructible::value && !force_trivial) { + if constexpr (!std::is_trivially_constructible_v && !force_trivial) { for (U i = count; i < p_size; i++) { memnew_placement(&data[i], T); } diff --git a/core/templates/paged_allocator.h b/core/templates/paged_allocator.h index d880eae0c3..48110d37e5 100644 --- a/core/templates/paged_allocator.h +++ b/core/templates/paged_allocator.h @@ -101,7 +101,7 @@ public: private: void _reset(bool p_allow_unfreed) { - if (!p_allow_unfreed || !std::is_trivially_destructible::value) { + if (!p_allow_unfreed || !std::is_trivially_destructible_v) { ERR_FAIL_COND(allocs_available < pages_allocated * page_size); } if (pages_allocated) { diff --git a/core/templates/paged_array.h b/core/templates/paged_array.h index 6b7e0cee16..21053dd033 100644 --- a/core/templates/paged_array.h +++ b/core/templates/paged_array.h @@ -202,7 +202,7 @@ public: uint32_t page = count >> page_size_shift; uint32_t offset = count & page_size_mask; - if (!std::is_trivially_constructible::value) { + if constexpr (!std::is_trivially_constructible_v) { memnew_placement(&page_data[page][offset], T(p_value)); } else { page_data[page][offset] = p_value; @@ -214,7 +214,7 @@ public: _FORCE_INLINE_ void pop_back() { ERR_FAIL_COND(count == 0); - if (!std::is_trivially_destructible::value) { + if constexpr (!std::is_trivially_destructible_v) { uint32_t page = (count - 1) >> page_size_shift; uint32_t offset = (count - 1) & page_size_mask; page_data[page][offset].~T(); @@ -237,7 +237,7 @@ public: void clear() { //destruct if needed - if (!std::is_trivially_destructible::value) { + if constexpr (!std::is_trivially_destructible_v) { for (uint64_t i = 0; i < count; i++) { uint32_t page = i >> page_size_shift; uint32_t offset = i & page_size_mask; @@ -318,13 +318,13 @@ public: uint32_t to_copy = MIN(page_size - new_remainder, remainder); for (uint32_t i = 0; i < to_copy; i++) { - if (!std::is_trivially_constructible::value) { + if constexpr (!std::is_trivially_constructible_v) { memnew_placement(&dst_page[i + new_remainder], T(remainder_page[i + remainder - to_copy])); } else { dst_page[i + new_remainder] = remainder_page[i + remainder - to_copy]; } - if (!std::is_trivially_destructible::value) { + if constexpr (!std::is_trivially_destructible_v) { remainder_page[i + remainder - to_copy].~T(); } } diff --git a/core/templates/safe_refcount.h b/core/templates/safe_refcount.h index 20fb0c6501..7bbceadc8d 100644 --- a/core/templates/safe_refcount.h +++ b/core/templates/safe_refcount.h @@ -54,7 +54,7 @@ #define SAFE_NUMERIC_TYPE_PUN_GUARANTEES(m_type) \ static_assert(sizeof(SafeNumeric) == sizeof(m_type)); \ static_assert(alignof(SafeNumeric) == alignof(m_type)); \ - static_assert(std::is_trivially_destructible>::value); + static_assert(std::is_trivially_destructible_v>); #define SAFE_FLAG_TYPE_PUN_GUARANTEES \ static_assert(sizeof(SafeFlag) == sizeof(bool)); \ static_assert(alignof(SafeFlag) == alignof(bool)); diff --git a/core/variant/binder_common.h b/core/variant/binder_common.h index c9f5ae7fc6..a44b938395 100644 --- a/core/variant/binder_common.h +++ b/core/variant/binder_common.h @@ -51,7 +51,7 @@ template struct VariantCaster { static _FORCE_INLINE_ T cast(const Variant &p_variant) { using TStripped = std::remove_pointer_t; - if constexpr (std::is_base_of::value) { + if constexpr (std::is_base_of_v) { return Object::cast_to(p_variant); } else { return p_variant; @@ -63,7 +63,7 @@ template struct VariantCaster { static _FORCE_INLINE_ T cast(const Variant &p_variant) { using TStripped = std::remove_pointer_t; - if constexpr (std::is_base_of::value) { + if constexpr (std::is_base_of_v) { return Object::cast_to(p_variant); } else { return p_variant; @@ -75,7 +75,7 @@ template struct VariantCaster { static _FORCE_INLINE_ T cast(const Variant &p_variant) { using TStripped = std::remove_pointer_t; - if constexpr (std::is_base_of::value) { + if constexpr (std::is_base_of_v) { return Object::cast_to(p_variant); } else { return p_variant; @@ -226,7 +226,7 @@ template struct VariantObjectClassChecker { static _FORCE_INLINE_ bool check(const Variant &p_variant) { using TStripped = std::remove_pointer_t; - if constexpr (std::is_base_of::value) { + if constexpr (std::is_base_of_v) { Object *obj = p_variant; return Object::cast_to(p_variant) || !obj; } else { diff --git a/core/variant/type_info.h b/core/variant/type_info.h index c1f2f86a96..49c4db8229 100644 --- a/core/variant/type_info.h +++ b/core/variant/type_info.h @@ -43,14 +43,10 @@ struct EnableIf { }; template -struct TypesAreSame { - static bool const value = false; -}; +inline constexpr bool types_are_same_v = false; -template -struct TypesAreSame { - static bool const value = true; -}; +template +inline constexpr bool types_are_same_v = true; template struct TypeInherits { @@ -60,7 +56,7 @@ struct TypeInherits { static char (&test(...))[2]; static bool const value = sizeof(test(get_d())) == sizeof(char) && - !TypesAreSame::value; + !types_are_same_v; }; namespace GodotTypeInfo { diff --git a/servers/rendering/storage/variant_converters.h b/servers/rendering/storage/variant_converters.h index ea291ba058..6e3c07237e 100644 --- a/servers/rendering/storage/variant_converters.h +++ b/servers/rendering/storage/variant_converters.h @@ -243,10 +243,10 @@ inline bool is_convertible_array(Variant::Type type) { } template -struct is_vector_type : std::false_type {}; +inline constexpr bool is_vector_type_v = false; template -struct is_vector_type> : std::true_type {}; +inline constexpr bool is_vector_type_v> = true; template void convert_item_std140(const T &p_item, P *p_write, bool p_compact = false) { @@ -274,7 +274,7 @@ Vector

convert_array_std140(const Variant &p_variant, [[maybe_unused]] bool p const Variant &item = array.get(i); P *offset = write + (i * elements); - if constexpr (is_vector_type::value) { + if constexpr (is_vector_type_v) { const T &vec = convert_to_vector(item, p_linear_color); convert_item_std140(vec, offset, true); } else { From 8ddd27ce1ee321f8d307d0593d1045bc23deb6c3 Mon Sep 17 00:00:00 2001 From: kit Date: Fri, 2 Feb 2024 16:45:06 -0500 Subject: [PATCH 04/23] Fix freeze in TextEdit with scroll_past_end_of_file and fit_content_height --- scene/gui/text_edit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 540c999131..e2925920a2 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -7333,7 +7333,7 @@ void TextEdit::_update_scrollbars() { int visible_rows = get_visible_line_count(); int total_rows = draw_placeholder ? placeholder_wraped_rows.size() - 1 : get_total_visible_line_count(); - if (scroll_past_end_of_file_enabled) { + if (scroll_past_end_of_file_enabled && !fit_content_height) { total_rows += visible_rows - 1; } From 87ab959ae05662cddfa83270787be6e8e538ddf2 Mon Sep 17 00:00:00 2001 From: "Silc Lizard (Tokage) Renew" <61938263+TokageItLab@users.noreply.github.com> Date: Fri, 2 Feb 2024 04:45:43 +0900 Subject: [PATCH 05/23] Remove duplicated `set()` methods from SceneTreeDock --- editor/scene_tree_dock.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 4d998118e2..8c6f1f5363 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -1824,7 +1824,6 @@ bool SceneTreeDock::_check_node_path_recursive(Node *p_root_node, Variant &r_var EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->add_do_property(resource, propertyname, updated_variant); undo_redo->add_undo_property(resource, propertyname, old_variant); - resource->set(propertyname, updated_variant); } } break; @@ -1968,7 +1967,6 @@ void SceneTreeDock::perform_node_renames(Node *p_base, HashMap EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->add_do_property(p_base, propertyname, updated_variant); undo_redo->add_undo_property(p_base, propertyname, old_variant); - p_base->set(propertyname, updated_variant); } } @@ -2849,7 +2847,6 @@ void SceneTreeDock::perform_node_replace(Node *p_base, Node *p_node, Node *p_by_ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->add_do_property(p_base, propertyname, updated_variant); undo_redo->add_undo_property(p_base, propertyname, old_variant); - p_base->set(propertyname, updated_variant); if (!warn_message.is_empty()) { String node_path = (String(edited_scene->get_name()) + "/" + String(edited_scene->get_path_to(p_base))).trim_suffix("/."); WARN_PRINT(warn_message + vformat("Removing the node from variable \"%s\" on node \"%s\".", propertyname, node_path)); From 7a2c386e281db72871dda33944502b7a7e7a6df9 Mon Sep 17 00:00:00 2001 From: Robert Yevdokimov Date: Fri, 12 Jan 2024 12:49:10 -0500 Subject: [PATCH 06/23] Clear drag preview nodes on `NOTIFICATION_DRAG_END` --- editor/plugins/canvas_item_editor_plugin.cpp | 4 ++++ editor/plugins/node_3d_editor_plugin.cpp | 2 ++ 2 files changed, 6 insertions(+) diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index f16aff555c..1eb0f783b9 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -6027,6 +6027,10 @@ void CanvasItemEditorViewport::_notification(int p_what) { case NOTIFICATION_EXIT_TREE: { disconnect("mouse_exited", callable_mp(this, &CanvasItemEditorViewport::_on_mouse_exit)); } break; + + case NOTIFICATION_DRAG_END: { + _remove_preview(); + } break; } } diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index e4d24832bf..74bd7e8172 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -3017,6 +3017,8 @@ void Node3DEditorViewport::_notification(int p_what) { // Clear preview material when dropped outside applicable object. if (spatial_editor->get_preview_material().is_valid() && !is_drag_successful()) { _remove_preview_material(); + } else { + _remove_preview_node(); } } break; } From 0a485fc30aae693e942a5984f149c7aa69f397d7 Mon Sep 17 00:00:00 2001 From: smix8 <52464204+smix8@users.noreply.github.com> Date: Fri, 2 Feb 2024 23:07:53 +0100 Subject: [PATCH 07/23] Add HeightMapShape3D functions to get min / max height Adds HeightMapShape3D functions to get min / max height. --- doc/classes/HeightMapShape3D.xml | 16 +++++++++++++++- scene/resources/height_map_shape_3d.cpp | 10 ++++++++++ scene/resources/height_map_shape_3d.h | 3 +++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/doc/classes/HeightMapShape3D.xml b/doc/classes/HeightMapShape3D.xml index ff120fa557..ba79cbc89a 100644 --- a/doc/classes/HeightMapShape3D.xml +++ b/doc/classes/HeightMapShape3D.xml @@ -9,9 +9,23 @@ + + + + + Returns the largest height value found in [member map_data]. Recalculates only when [member map_data] changes. + + + + + + Returns the smallest height value found in [member map_data]. Recalculates only when [member map_data] changes. + + + - Height map data, pool array must be of [member map_width] * [member map_depth] size. + Height map data. The array's size must be equal to [member map_width] multiplied by [member map_depth]. Number of vertices in the depth of the height map. Changing this will resize the [member map_data]. diff --git a/scene/resources/height_map_shape_3d.cpp b/scene/resources/height_map_shape_3d.cpp index 718d701811..35c905bd43 100644 --- a/scene/resources/height_map_shape_3d.cpp +++ b/scene/resources/height_map_shape_3d.cpp @@ -179,6 +179,14 @@ Vector HeightMapShape3D::get_map_data() const { return map_data; } +real_t HeightMapShape3D::get_min_height() const { + return min_height; +} + +real_t HeightMapShape3D::get_max_height() const { + return max_height; +} + void HeightMapShape3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_map_width", "width"), &HeightMapShape3D::set_map_width); ClassDB::bind_method(D_METHOD("get_map_width"), &HeightMapShape3D::get_map_width); @@ -186,6 +194,8 @@ void HeightMapShape3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_map_depth"), &HeightMapShape3D::get_map_depth); ClassDB::bind_method(D_METHOD("set_map_data", "data"), &HeightMapShape3D::set_map_data); ClassDB::bind_method(D_METHOD("get_map_data"), &HeightMapShape3D::get_map_data); + ClassDB::bind_method(D_METHOD("get_min_height"), &HeightMapShape3D::get_min_height); + ClassDB::bind_method(D_METHOD("get_max_height"), &HeightMapShape3D::get_max_height); ADD_PROPERTY(PropertyInfo(Variant::INT, "map_width", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), "set_map_width", "get_map_width"); ADD_PROPERTY(PropertyInfo(Variant::INT, "map_depth", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), "set_map_depth", "get_map_depth"); diff --git a/scene/resources/height_map_shape_3d.h b/scene/resources/height_map_shape_3d.h index 5fe00ec0b1..eff025c816 100644 --- a/scene/resources/height_map_shape_3d.h +++ b/scene/resources/height_map_shape_3d.h @@ -54,6 +54,9 @@ public: void set_map_data(Vector p_new); Vector get_map_data() const; + real_t get_min_height() const; + real_t get_max_height() const; + virtual Vector get_debug_mesh_lines() const override; virtual real_t get_enclosing_radius() const override; From 677bd9783a6dbc40b9202381095b85f4f7b3de0c Mon Sep 17 00:00:00 2001 From: Robert Yevdokimov Date: Sat, 3 Feb 2024 21:45:08 -0500 Subject: [PATCH 08/23] Fix a regression when multiple nodes are selected. and drag transform is attempted w/o gizmo --- editor/plugins/node_3d_editor_plugin.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 5e70354d22..476ca99433 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -1749,8 +1749,7 @@ void Node3DEditorViewport::_sinput(const Ref &p_event) { _edit.mode = TRANSFORM_NONE; _edit.original = spatial_editor->get_gizmo_transform(); // To prevent to break when flipping with scale. - bool node_selected = spatial_editor->get_single_selected_node(); - bool can_select_gizmos = node_selected; + bool can_select_gizmos = spatial_editor->get_single_selected_node(); { int idx = view_menu->get_popup()->get_item_index(VIEW_GIZMOS); @@ -1840,6 +1839,8 @@ void Node3DEditorViewport::_sinput(const Ref &p_event) { clicked = ObjectID(); + bool node_selected = get_selected_count() > 0; + if (node_selected && ((spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT && b->is_command_or_control_pressed()) || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE)) { begin_transform(TRANSFORM_ROTATE, false); break; From d06c526fb06714e16207aa1292146bc283b99e31 Mon Sep 17 00:00:00 2001 From: jsjtxietian Date: Wed, 31 Jan 2024 12:36:23 +0800 Subject: [PATCH 09/23] Fix `TextureRegionEditor::_pan_callback` deferred called with only one arg --- editor/plugins/texture_region_editor_plugin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index 09f6bf884e..56b5930aa3 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -226,8 +226,8 @@ void TextureRegionEditor::_texture_overlay_draw() { hscroll->set_value((hscroll->get_min() + hscroll->get_max() - hscroll->get_page()) / 2); vscroll->set_value((vscroll->get_min() + vscroll->get_max() - vscroll->get_page()) / 2); // This ensures that the view is updated correctly. - callable_mp(this, &TextureRegionEditor::_pan_callback).bind(Vector2(1, 0)).call_deferred(); - callable_mp(this, &TextureRegionEditor::_scroll_changed).bind(0.0).call_deferred(); + callable_mp(this, &TextureRegionEditor::_pan_callback).call_deferred(Vector2(1, 0), Ref()); + callable_mp(this, &TextureRegionEditor::_scroll_changed).call_deferred(0.0); request_center = false; } From 0a9715d6b55dfa28f46de8ff4097dacb2f2032a6 Mon Sep 17 00:00:00 2001 From: 31 <31eee384@gmail.com> Date: Sat, 3 Feb 2024 20:46:56 -0800 Subject: [PATCH 10/23] Add Callable call_deferred() C# example --- doc/classes/Callable.xml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/doc/classes/Callable.xml b/doc/classes/Callable.xml index 3550a6b7bd..8dd0cfa135 100644 --- a/doc/classes/Callable.xml +++ b/doc/classes/Callable.xml @@ -98,10 +98,18 @@ Calls the method represented by this [Callable] in deferred mode, i.e. at the end of the current frame. Arguments can be passed and should match the method's signature. - [codeblock] + [codeblocks] + [gdscript] func _ready(): grab_focus.call_deferred() - [/codeblock] + [/gdscript] + [csharp] + public override void _Ready() + { + Callable.From(GrabFocus).CallDeferred(); + } + [/csharp] + [/codeblocks] See also [method Object.call_deferred]. From 4c8d69f264459a9b8b72fa7ffe8a972e821af1a1 Mon Sep 17 00:00:00 2001 From: Aaron Franke Date: Sun, 4 Feb 2024 02:47:44 -0600 Subject: [PATCH 11/23] Fix crash when importing a GLTF file with a skeleton as the root --- modules/gltf/gltf_document.cpp | 15 ++++++++++----- modules/gltf/gltf_document.h | 2 +- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index f2dccf6d68..73e26fbef5 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -5982,8 +5982,13 @@ void GLTFDocument::_generate_skeleton_bone_node(Ref p_state, const GL p_scene_parent = bone_attachment; } if (skeleton->get_parent() == nullptr) { - p_scene_parent->add_child(skeleton, true); - skeleton->set_owner(p_scene_root); + if (p_scene_root) { + p_scene_parent->add_child(skeleton, true); + skeleton->set_owner(p_scene_root); + } else { + p_scene_parent = skeleton; + p_scene_root = skeleton; + } } } @@ -6582,7 +6587,7 @@ float GLTFDocument::get_max_component(const Color &p_color) { return MAX(MAX(r, g), b); } -void GLTFDocument::_process_mesh_instances(Ref p_state) { +void GLTFDocument::_process_mesh_instances(Ref p_state, Node *p_scene_root) { for (GLTFNodeIndex node_i = 0; node_i < p_state->nodes.size(); ++node_i) { Ref node = p_state->nodes[node_i]; @@ -6607,7 +6612,7 @@ void GLTFDocument::_process_mesh_instances(Ref p_state) { mi->get_parent()->remove_child(mi); skeleton->add_child(mi, true); - mi->set_owner(skeleton->get_owner()); + mi->set_owner(p_scene_root); mi->set_skin(p_state->skins.write[skin_i]->godot_skin); mi->set_skeleton_path(mi->get_path_to(skeleton)); @@ -7461,7 +7466,7 @@ Node *GLTFDocument::generate_scene(Ref p_state, float p_bake_fps, boo Error err = OK; Node *root = _generate_scene_node_tree(p_state); ERR_FAIL_NULL_V(root, nullptr); - _process_mesh_instances(p_state); + _process_mesh_instances(p_state, root); if (p_state->get_create_animations() && p_state->animations.size()) { AnimationPlayer *ap = memnew(AnimationPlayer); root->add_child(ap, true); diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h index f321bb7111..04c85f3b07 100644 --- a/modules/gltf/gltf_document.h +++ b/modules/gltf/gltf_document.h @@ -326,7 +326,7 @@ public: Error _parse_gltf_state(Ref p_state, const String &p_search_path); Error _parse_asset_header(Ref p_state); Error _parse_gltf_extensions(Ref p_state); - void _process_mesh_instances(Ref p_state); + void _process_mesh_instances(Ref p_state, Node *p_scene_root); Node *_generate_scene_node_tree(Ref p_state); void _generate_scene_node(Ref p_state, const GLTFNodeIndex p_node_index, Node *p_scene_parent, Node *p_scene_root); void _generate_skeleton_bone_node(Ref p_state, const GLTFNodeIndex p_node_index, Node *p_scene_parent, Node *p_scene_root); From 43038bbfcb53ccaecc8a258e4d07d0f489292361 Mon Sep 17 00:00:00 2001 From: ACB Date: Sun, 4 Feb 2024 14:21:03 +0100 Subject: [PATCH 12/23] Only recurse depth wise in `Tree::_count_selected_items` --- scene/gui/tree.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 10f4962c48..73a49fd427 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -2587,12 +2587,8 @@ int Tree::_count_selected_items(TreeItem *p_from) const { } } - if (p_from->get_first_child()) { - count += _count_selected_items(p_from->get_first_child()); - } - - if (p_from->get_next()) { - count += _count_selected_items(p_from->get_next()); + for (TreeItem *c = p_from->get_first_child(); c; c = c->get_next()) { + count += _count_selected_items(c); } return count; From 66d55e62f009876b4e71d988a7a1bfb16c8230fa Mon Sep 17 00:00:00 2001 From: A Thousand Ships <96648715+AThousandShips@users.noreply.github.com> Date: Sun, 4 Feb 2024 13:06:34 +0100 Subject: [PATCH 13/23] [GDScript] Prevent running `String` number functions on invalid literal Prevents printing excessive errors. --- modules/gdscript/gdscript_tokenizer.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp index 98a3a1268f..29cf7bc6ca 100644 --- a/modules/gdscript/gdscript_tokenizer.cpp +++ b/modules/gdscript/gdscript_tokenizer.cpp @@ -672,6 +672,7 @@ GDScriptTokenizer::Token GDScriptTokenizer::number() { bool has_decimal = false; bool has_exponent = false; bool has_error = false; + bool need_digits = false; bool (*digit_check_func)(char32_t) = is_digit; // Sign before hexadecimal or binary. @@ -686,11 +687,13 @@ GDScriptTokenizer::Token GDScriptTokenizer::number() { // Hexadecimal. base = 16; digit_check_func = is_hex_digit; + need_digits = true; _advance(); } else if (_peek() == 'b') { // Binary. base = 2; digit_check_func = is_binary_digit; + need_digits = true; _advance(); } } @@ -717,6 +720,7 @@ GDScriptTokenizer::Token GDScriptTokenizer::number() { } previous_was_underscore = true; } else { + need_digits = false; previous_was_underscore = false; } _advance(); @@ -820,6 +824,16 @@ GDScriptTokenizer::Token GDScriptTokenizer::number() { } } + if (need_digits) { + // No digits in hex or bin literal. + Token error = make_error(vformat(R"(Expected %s digit after "0%c".)", (base == 16 ? "hexadecimal" : "binary"), (base == 16 ? 'x' : 'b'))); + error.start_column = column; + error.leftmost_column = column; + error.end_column = column + 1; + error.rightmost_column = column + 1; + return error; + } + // Detect extra decimal point. if (!has_error && has_decimal && _peek() == '.' && _peek(1) != '.') { Token error = make_error("Cannot use a decimal point twice in a number."); From dc4c6cfb9b78bca962121510b01b7a7605bbbd45 Mon Sep 17 00:00:00 2001 From: Mikhail Tishin Date: Sun, 4 Feb 2024 14:41:23 +0300 Subject: [PATCH 14/23] Add null check for gdextension deinitialization --- core/extension/gdextension.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/extension/gdextension.cpp b/core/extension/gdextension.cpp index 2904e54b22..aba96befd6 100644 --- a/core/extension/gdextension.cpp +++ b/core/extension/gdextension.cpp @@ -794,6 +794,9 @@ void GDExtension::deinitialize_library(InitializationLevel p_level) { ERR_FAIL_COND(p_level > int32_t(level_initialized)); level_initialized = int32_t(p_level) - 1; + + ERR_FAIL_NULL(initialization.deinitialize); + initialization.deinitialize(initialization.userdata, GDExtensionInitializationLevel(p_level)); } From 71e0082ab035bdcd6372c6faf96596ce9eac5a3c Mon Sep 17 00:00:00 2001 From: vittorioromeo Date: Sun, 4 Feb 2024 16:59:54 +0100 Subject: [PATCH 15/23] Extract 'SafeBinaryMutex' to separate header This change simply extracts 'SafeBinaryMutex' from 'mutex.h' to 'safe_binary_mutex.h', in an effort to reduce the compilation speed impact of including `mutex.h`. --- core/io/resource_loader.cpp | 1 + core/io/resource_loader.h | 3 + core/os/mutex.h | 80 ----------------------- core/os/safe_binary_mutex.h | 124 ++++++++++++++++++++++++++++++++++++ 4 files changed, 128 insertions(+), 80 deletions(-) create mode 100644 core/os/safe_binary_mutex.h diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index 197c8813a7..2fb3bda87d 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -36,6 +36,7 @@ #include "core/object/script_language.h" #include "core/os/condition_variable.h" #include "core/os/os.h" +#include "core/os/safe_binary_mutex.h" #include "core/string/print_string.h" #include "core/string/translation.h" #include "core/variant/variant_parser.h" diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h index 0ab81cd0a8..3099d9aab3 100644 --- a/core/io/resource_loader.h +++ b/core/io/resource_loader.h @@ -39,6 +39,9 @@ class ConditionVariable; +template +class SafeBinaryMutex; + class ResourceFormatLoader : public RefCounted { GDCLASS(ResourceFormatLoader, RefCounted); diff --git a/core/os/mutex.h b/core/os/mutex.h index 69f494d9cd..a4eab0cd86 100644 --- a/core/os/mutex.h +++ b/core/os/mutex.h @@ -70,56 +70,6 @@ public: } }; -// A very special kind of mutex, used in scenarios where these -// requirements hold at the same time: -// - Must be used with a condition variable (only binary mutexes are suitable). -// - Must have recursive semnantics (or simulate, as this one does). -// The implementation keeps the lock count in TS. Therefore, only -// one object of each version of the template can exists; hence the Tag argument. -// Tags must be unique across the Godot codebase. -// Also, don't forget to declare the thread_local variable on each use. -template -class SafeBinaryMutex { - friend class MutexLock; - - using StdMutexType = THREADING_NAMESPACE::mutex; - - mutable THREADING_NAMESPACE::mutex mutex; - static thread_local uint32_t count; - -public: - _ALWAYS_INLINE_ void lock() const { - if (++count == 1) { - mutex.lock(); - } - } - - _ALWAYS_INLINE_ void unlock() const { - DEV_ASSERT(count); - if (--count == 0) { - mutex.unlock(); - } - } - - _ALWAYS_INLINE_ bool try_lock() const { - if (count) { - count++; - return true; - } else { - if (mutex.try_lock()) { - count++; - return true; - } else { - return false; - } - } - } - - ~SafeBinaryMutex() { - DEV_ASSERT(!count); - } -}; - template class MutexLock { friend class ConditionVariable; @@ -131,24 +81,6 @@ public: lock(p_mutex.mutex) {} }; -// This specialization is needed so manual locking and MutexLock can be used -// at the same time on a SafeBinaryMutex. -template -class MutexLock> { - friend class ConditionVariable; - - THREADING_NAMESPACE::unique_lock lock; - -public: - _ALWAYS_INLINE_ explicit MutexLock(const SafeBinaryMutex &p_mutex) : - lock(p_mutex.mutex) { - SafeBinaryMutex::count++; - }; - _ALWAYS_INLINE_ ~MutexLock() { - SafeBinaryMutex::count--; - }; -}; - using Mutex = MutexImpl; // Recursive, for general use using BinaryMutex = MutexImpl; // Non-recursive, handle with care @@ -168,24 +100,12 @@ public: bool try_lock() const { return true; } }; -template -class SafeBinaryMutex : public MutexImpl { - static thread_local uint32_t count; -}; - template class MutexLock { public: MutexLock(const MutexT &p_mutex) {} }; -template -class MutexLock> { -public: - MutexLock(const SafeBinaryMutex &p_mutex) {} - ~MutexLock() {} -}; - using Mutex = MutexImpl; using BinaryMutex = MutexImpl; diff --git a/core/os/safe_binary_mutex.h b/core/os/safe_binary_mutex.h new file mode 100644 index 0000000000..1e98cc074c --- /dev/null +++ b/core/os/safe_binary_mutex.h @@ -0,0 +1,124 @@ +/**************************************************************************/ +/* safe_binary_mutex.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef SAFE_BINARY_MUTEX_H +#define SAFE_BINARY_MUTEX_H + +#include "core/error/error_macros.h" +#include "core/os/mutex.h" +#include "core/typedefs.h" + +#ifdef THREADS_ENABLED + +// A very special kind of mutex, used in scenarios where these +// requirements hold at the same time: +// - Must be used with a condition variable (only binary mutexes are suitable). +// - Must have recursive semnantics (or simulate, as this one does). +// The implementation keeps the lock count in TS. Therefore, only +// one object of each version of the template can exists; hence the Tag argument. +// Tags must be unique across the Godot codebase. +// Also, don't forget to declare the thread_local variable on each use. +template +class SafeBinaryMutex { + friend class MutexLock; + + using StdMutexType = THREADING_NAMESPACE::mutex; + + mutable THREADING_NAMESPACE::mutex mutex; + static thread_local uint32_t count; + +public: + _ALWAYS_INLINE_ void lock() const { + if (++count == 1) { + mutex.lock(); + } + } + + _ALWAYS_INLINE_ void unlock() const { + DEV_ASSERT(count); + if (--count == 0) { + mutex.unlock(); + } + } + + _ALWAYS_INLINE_ bool try_lock() const { + if (count) { + count++; + return true; + } else { + if (mutex.try_lock()) { + count++; + return true; + } else { + return false; + } + } + } + + ~SafeBinaryMutex() { + DEV_ASSERT(!count); + } +}; + +// This specialization is needed so manual locking and MutexLock can be used +// at the same time on a SafeBinaryMutex. +template +class MutexLock> { + friend class ConditionVariable; + + THREADING_NAMESPACE::unique_lock lock; + +public: + _ALWAYS_INLINE_ explicit MutexLock(const SafeBinaryMutex &p_mutex) : + lock(p_mutex.mutex) { + SafeBinaryMutex::count++; + }; + _ALWAYS_INLINE_ ~MutexLock() { + SafeBinaryMutex::count--; + }; +}; + +#else // No threads. + +template +class SafeBinaryMutex : public MutexImpl { + static thread_local uint32_t count; +}; + +template +class MutexLock> { +public: + MutexLock(const SafeBinaryMutex &p_mutex) {} + ~MutexLock() {} +}; + +#endif // THREADS_ENABLED + +#endif // SAFE_BINARY_MUTEX_H From 17000bf8c3abb2a6f240bf49800ce8e68e7ced70 Mon Sep 17 00:00:00 2001 From: A Thousand Ships <96648715+AThousandShips@users.noreply.github.com> Date: Sun, 4 Feb 2024 18:31:09 +0100 Subject: [PATCH 16/23] Fix inverted link in docs Title and url were swapped --- doc/classes/EditorExportPlatform.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/classes/EditorExportPlatform.xml b/doc/classes/EditorExportPlatform.xml index 6801ac672c..0e5de79b25 100644 --- a/doc/classes/EditorExportPlatform.xml +++ b/doc/classes/EditorExportPlatform.xml @@ -8,7 +8,7 @@ Used in scripting by [EditorExportPlugin] to configure platform-specific customization of scenes and resources. See [method EditorExportPlugin._begin_customize_scenes] and [method EditorExportPlugin._begin_customize_resources] for more details. - Console support in Godot + $DOCS_URL/tutorials/platform/consoles.html From 6718a9e4cfeffd43b1b9493aa0d3cf9537ab395c Mon Sep 17 00:00:00 2001 From: Robert Yevdokimov Date: Sun, 4 Feb 2024 10:17:09 -0500 Subject: [PATCH 17/23] Fix bug that translates node during region select over geometry by always defaulting to region select --- editor/plugins/node_3d_editor_plugin.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 5e70354d22..cd6bbbf88e 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -1985,9 +1985,8 @@ void Node3DEditorViewport::_sinput(const Ref &p_event) { } else { const bool movement_threshold_passed = _edit.original_mouse_pos.distance_to(_edit.mouse_pos) > 8 * EDSCALE; - // enable region-select if nothing has been selected yet or multi-select (shift key) is active - if (selection_in_progress && movement_threshold_passed) { - if (get_selected_count() == 0 || clicked_wants_append) { + if (selection_in_progress && movement_threshold_passed && clicked.is_valid()) { + if (clicked_wants_append || !editor_selection->is_selected(Object::cast_to(ObjectDB::get_instance(clicked)))) { cursor.region_select = true; cursor.region_begin = _edit.original_mouse_pos; clicked = ObjectID(); From 656bc22e283852a55ad1317048649f0991bc7dcd Mon Sep 17 00:00:00 2001 From: Adam Scott Date: Sun, 4 Feb 2024 15:24:24 -0500 Subject: [PATCH 18/23] Add workaround for emscripten >= 3.1.47 LTO build --- platform/web/detect.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/platform/web/detect.py b/platform/web/detect.py index bce03eb79e..a1920acf6f 100644 --- a/platform/web/detect.py +++ b/platform/web/detect.py @@ -229,6 +229,9 @@ def configure(env: "Environment"): # Workaround https://github.com/emscripten-core/emscripten/issues/19781. if cc_semver >= (3, 1, 42) and cc_semver < (3, 1, 46): env.Append(LINKFLAGS=["-Wl,-u,scalbnf"]) + # Workaround https://github.com/emscripten-core/emscripten/issues/16836. + if cc_semver >= (3, 1, 47): + env.Append(LINKFLAGS=["-Wl,-u,_emscripten_run_callback_on_thread"]) if env["dlink_enabled"]: if env["proxy_to_pthread"]: From 70e328385c8c9e11ff2d62906edd5a0706c27b9f Mon Sep 17 00:00:00 2001 From: bruvzg <7645683+bruvzg@users.noreply.github.com> Date: Sun, 4 Feb 2024 23:09:52 +0200 Subject: [PATCH 19/23] [macOS] Check Vulkan SDK version when looking for MoltenVK libs. --- platform/macos/detect.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/macos/detect.py b/platform/macos/detect.py index 4a8e9cd956..0d1e40fb3d 100644 --- a/platform/macos/detect.py +++ b/platform/macos/detect.py @@ -67,13 +67,14 @@ def get_mvk_sdk_path(): if not os.path.exists(dirname): return "" + ver_min = ver_parse("1.3.231.0") ver_num = ver_parse("0.0.0.0") files = os.listdir(dirname) lib_name_out = dirname for file in files: if os.path.isdir(os.path.join(dirname, file)): ver_comp = ver_parse(file) - if ver_comp > ver_num: + if ver_comp > ver_num and ver_comp >= ver_min: # Try new SDK location. lib_name = os.path.join( os.path.join(dirname, file), "macOS/lib/MoltenVK.xcframework/macos-arm64_x86_64/" From 7bcb41914907e17bfd5af934a031f783bb76b969 Mon Sep 17 00:00:00 2001 From: bruvzg <7645683+bruvzg@users.noreply.github.com> Date: Thu, 1 Feb 2024 10:15:08 +0200 Subject: [PATCH 20/23] [Core] Improve `CowData` and `Memory` metadata alignment. --- core/os/memory.cpp | 24 +++++------ core/os/memory.h | 35 ++++++++++----- core/templates/cowdata.h | 92 +++++++++++++++++++++++++++------------- 3 files changed, 99 insertions(+), 52 deletions(-) diff --git a/core/os/memory.cpp b/core/os/memory.cpp index 5f6216a5f1..32c316e58e 100644 --- a/core/os/memory.cpp +++ b/core/os/memory.cpp @@ -72,23 +72,23 @@ void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) { bool prepad = p_pad_align; #endif - void *mem = malloc(p_bytes + (prepad ? PAD_ALIGN : 0)); + void *mem = malloc(p_bytes + (prepad ? DATA_OFFSET : 0)); ERR_FAIL_NULL_V(mem, nullptr); alloc_count.increment(); if (prepad) { - uint64_t *s = (uint64_t *)mem; - *s = p_bytes; - uint8_t *s8 = (uint8_t *)mem; + uint64_t *s = (uint64_t *)(s8 + SIZE_OFFSET); + *s = p_bytes; + #ifdef DEBUG_ENABLED uint64_t new_mem_usage = mem_usage.add(p_bytes); max_usage.exchange_if_greater(new_mem_usage); #endif - return s8 + PAD_ALIGN; + return s8 + DATA_OFFSET; } else { return mem; } @@ -108,8 +108,8 @@ void *Memory::realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align) { #endif if (prepad) { - mem -= PAD_ALIGN; - uint64_t *s = (uint64_t *)mem; + mem -= DATA_OFFSET; + uint64_t *s = (uint64_t *)(mem + SIZE_OFFSET); #ifdef DEBUG_ENABLED if (p_bytes > *s) { @@ -126,14 +126,14 @@ void *Memory::realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align) { } else { *s = p_bytes; - mem = (uint8_t *)realloc(mem, p_bytes + PAD_ALIGN); + mem = (uint8_t *)realloc(mem, p_bytes + DATA_OFFSET); ERR_FAIL_NULL_V(mem, nullptr); - s = (uint64_t *)mem; + s = (uint64_t *)(mem + SIZE_OFFSET); *s = p_bytes; - return mem + PAD_ALIGN; + return mem + DATA_OFFSET; } } else { mem = (uint8_t *)realloc(mem, p_bytes); @@ -158,10 +158,10 @@ void Memory::free_static(void *p_ptr, bool p_pad_align) { alloc_count.decrement(); if (prepad) { - mem -= PAD_ALIGN; + mem -= DATA_OFFSET; #ifdef DEBUG_ENABLED - uint64_t *s = (uint64_t *)mem; + uint64_t *s = (uint64_t *)(mem + SIZE_OFFSET); mem_usage.sub(*s); #endif diff --git a/core/os/memory.h b/core/os/memory.h index a43a15e58f..6f3f6fed39 100644 --- a/core/os/memory.h +++ b/core/os/memory.h @@ -38,10 +38,6 @@ #include #include -#ifndef PAD_ALIGN -#define PAD_ALIGN 16 //must always be greater than this at much -#endif - class Memory { #ifdef DEBUG_ENABLED static SafeNumeric mem_usage; @@ -51,6 +47,17 @@ class Memory { static SafeNumeric alloc_count; public: + // Alignment: ↓ max_align_t ↓ uint64_t ↓ max_align_t + // ┌─────────────────┬──┬────────────────┬──┬───────────... + // │ uint64_t │░░│ uint64_t │░░│ T[] + // │ alloc size │░░│ element count │░░│ data + // └─────────────────┴──┴────────────────┴──┴───────────... + // Offset: ↑ SIZE_OFFSET ↑ ELEMENT_OFFSET ↑ DATA_OFFSET + + static constexpr size_t SIZE_OFFSET = 0; + static constexpr size_t ELEMENT_OFFSET = ((SIZE_OFFSET + sizeof(uint64_t)) % alignof(uint64_t) == 0) ? (SIZE_OFFSET + sizeof(uint64_t)) : ((SIZE_OFFSET + sizeof(uint64_t)) + alignof(uint64_t) - ((SIZE_OFFSET + sizeof(uint64_t)) % alignof(uint64_t))); + static constexpr size_t DATA_OFFSET = ((ELEMENT_OFFSET + sizeof(uint64_t)) % alignof(max_align_t) == 0) ? (ELEMENT_OFFSET + sizeof(uint64_t)) : ((ELEMENT_OFFSET + sizeof(uint64_t)) + alignof(max_align_t) - ((ELEMENT_OFFSET + sizeof(uint64_t)) % alignof(max_align_t))); + static void *alloc_static(size_t p_bytes, bool p_pad_align = false); static void *realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align = false); static void free_static(void *p_ptr, bool p_pad_align = false); @@ -133,6 +140,10 @@ void memdelete_allocator(T *p_class) { #define memnew_arr(m_class, m_count) memnew_arr_template(m_count) +_FORCE_INLINE_ uint64_t *_get_element_count_ptr(uint8_t *p_ptr) { + return (uint64_t *)(p_ptr - Memory::DATA_OFFSET + Memory::ELEMENT_OFFSET); +} + template T *memnew_arr_template(size_t p_elements) { if (p_elements == 0) { @@ -142,10 +153,12 @@ T *memnew_arr_template(size_t p_elements) { same strategy used by std::vector, and the Vector class, so it should be safe.*/ size_t len = sizeof(T) * p_elements; - uint64_t *mem = (uint64_t *)Memory::alloc_static(len, true); + uint8_t *mem = (uint8_t *)Memory::alloc_static(len, true); T *failptr = nullptr; //get rid of a warning ERR_FAIL_NULL_V(mem, failptr); - *(mem - 1) = p_elements; + + uint64_t *_elem_count_ptr = _get_element_count_ptr(mem); + *(_elem_count_ptr) = p_elements; if constexpr (!std::is_trivially_constructible_v) { T *elems = (T *)mem; @@ -166,16 +179,18 @@ T *memnew_arr_template(size_t p_elements) { template size_t memarr_len(const T *p_class) { - uint64_t *ptr = (uint64_t *)p_class; - return *(ptr - 1); + uint8_t *ptr = (uint8_t *)p_class; + uint64_t *_elem_count_ptr = _get_element_count_ptr(ptr); + return *(_elem_count_ptr); } template void memdelete_arr(T *p_class) { - uint64_t *ptr = (uint64_t *)p_class; + uint8_t *ptr = (uint8_t *)p_class; if constexpr (!std::is_trivially_destructible_v) { - uint64_t elem_count = *(ptr - 1); + uint64_t *_elem_count_ptr = _get_element_count_ptr(ptr); + uint64_t elem_count = *(_elem_count_ptr); for (uint64_t i = 0; i < elem_count; i++) { p_class[i].~T(); diff --git a/core/templates/cowdata.h b/core/templates/cowdata.h index a0632b2645..466658951e 100644 --- a/core/templates/cowdata.h +++ b/core/templates/cowdata.h @@ -46,7 +46,7 @@ class CharString; template class VMap; -SAFE_NUMERIC_TYPE_PUN_GUARANTEES(uint64_t) +static_assert(std::is_trivially_destructible_v>); // Silence a false positive warning (see GH-52119). #if defined(__GNUC__) && !defined(__clang__) @@ -89,18 +89,39 @@ private: return ++x; } - static constexpr USize ALLOC_PAD = sizeof(USize) * 2; // For size and atomic refcount. + // Alignment: ↓ max_align_t ↓ USize ↓ max_align_t + // ┌────────────────────┬──┬─────────────┬──┬───────────... + // │ SafeNumeric │░░│ USize │░░│ T[] + // │ ref. count │░░│ data size │░░│ data + // └────────────────────┴──┴─────────────┴──┴───────────... + // Offset: ↑ REF_COUNT_OFFSET ↑ SIZE_OFFSET ↑ DATA_OFFSET + + static constexpr size_t REF_COUNT_OFFSET = 0; + static constexpr size_t SIZE_OFFSET = ((REF_COUNT_OFFSET + sizeof(SafeNumeric)) % alignof(USize) == 0) ? (REF_COUNT_OFFSET + sizeof(SafeNumeric)) : ((REF_COUNT_OFFSET + sizeof(SafeNumeric)) + alignof(USize) - ((REF_COUNT_OFFSET + sizeof(SafeNumeric)) % alignof(USize))); + static constexpr size_t DATA_OFFSET = ((SIZE_OFFSET + sizeof(USize)) % alignof(max_align_t) == 0) ? (SIZE_OFFSET + sizeof(USize)) : ((SIZE_OFFSET + sizeof(USize)) + alignof(max_align_t) - ((SIZE_OFFSET + sizeof(USize)) % alignof(max_align_t))); mutable T *_ptr = nullptr; // internal helpers + static _FORCE_INLINE_ SafeNumeric *_get_refcount_ptr(uint8_t *p_ptr) { + return (SafeNumeric *)(p_ptr + REF_COUNT_OFFSET); + } + + static _FORCE_INLINE_ USize *_get_size_ptr(uint8_t *p_ptr) { + return (USize *)(p_ptr + SIZE_OFFSET); + } + + static _FORCE_INLINE_ T *_get_data_ptr(uint8_t *p_ptr) { + return (T *)(p_ptr + DATA_OFFSET); + } + _FORCE_INLINE_ SafeNumeric *_get_refcount() const { if (!_ptr) { return nullptr; } - return reinterpret_cast *>(_ptr) - 2; + return (SafeNumeric *)((uint8_t *)_ptr - DATA_OFFSET + REF_COUNT_OFFSET); } _FORCE_INLINE_ USize *_get_size() const { @@ -108,7 +129,7 @@ private: return nullptr; } - return reinterpret_cast(_ptr) - 1; + return (USize *)((uint8_t *)_ptr - DATA_OFFSET + SIZE_OFFSET); } _FORCE_INLINE_ USize _get_alloc_size(USize p_elements) const { @@ -244,7 +265,7 @@ void CowData::_unref(void *p_data) { } // free mem - Memory::free_static(((uint8_t *)p_data) - ALLOC_PAD, false); + Memory::free_static(((uint8_t *)p_data) - DATA_OFFSET, false); } template @@ -260,26 +281,27 @@ typename CowData::USize CowData::_copy_on_write() { /* in use by more than me */ USize current_size = *_get_size(); - USize *mem_new = (USize *)Memory::alloc_static(_get_alloc_size(current_size) + ALLOC_PAD, false); - mem_new += 2; + uint8_t *mem_new = (uint8_t *)Memory::alloc_static(_get_alloc_size(current_size) + DATA_OFFSET, false); + ERR_FAIL_NULL_V(mem_new, 0); - new (mem_new - 2) SafeNumeric(1); //refcount - *(mem_new - 1) = current_size; //size + SafeNumeric *_refc_ptr = _get_refcount_ptr(mem_new); + USize *_size_ptr = _get_size_ptr(mem_new); + T *_data_ptr = _get_data_ptr(mem_new); - T *_data = (T *)(mem_new); + new (_refc_ptr) SafeNumeric(1); //refcount + *(_size_ptr) = current_size; //size // initialize new elements if constexpr (std::is_trivially_copyable_v) { - memcpy(mem_new, _ptr, current_size * sizeof(T)); - + memcpy((uint8_t *)_data_ptr, _ptr, current_size * sizeof(T)); } else { for (USize i = 0; i < current_size; i++) { - memnew_placement(&_data[i], T(_ptr[i])); + memnew_placement(&_data_ptr[i], T(_ptr[i])); } } _unref(_ptr); - _ptr = _data; + _ptr = _data_ptr; rc = 1; } @@ -315,21 +337,28 @@ Error CowData::resize(Size p_size) { if (alloc_size != current_alloc_size) { if (current_size == 0) { // alloc from scratch - USize *ptr = (USize *)Memory::alloc_static(alloc_size + ALLOC_PAD, false); - ptr += 2; - ERR_FAIL_NULL_V(ptr, ERR_OUT_OF_MEMORY); - *(ptr - 1) = 0; //size, currently none - new (ptr - 2) SafeNumeric(1); //refcount + uint8_t *mem_new = (uint8_t *)Memory::alloc_static(alloc_size + DATA_OFFSET, false); + ERR_FAIL_NULL_V(mem_new, ERR_OUT_OF_MEMORY); + + SafeNumeric *_refc_ptr = _get_refcount_ptr(mem_new); + USize *_size_ptr = _get_size_ptr(mem_new); + T *_data_ptr = _get_data_ptr(mem_new); - _ptr = (T *)ptr; + new (_refc_ptr) SafeNumeric(1); //refcount + *(_size_ptr) = 0; //size, currently none + + _ptr = _data_ptr; } else { - USize *_ptrnew = (USize *)Memory::realloc_static(((uint8_t *)_ptr) - ALLOC_PAD, alloc_size + ALLOC_PAD, false); - ERR_FAIL_NULL_V(_ptrnew, ERR_OUT_OF_MEMORY); - _ptrnew += 2; - new (_ptrnew - 2) SafeNumeric(rc); //refcount + uint8_t *mem_new = (uint8_t *)Memory::realloc_static(((uint8_t *)_ptr) - DATA_OFFSET, alloc_size + DATA_OFFSET, false); + ERR_FAIL_NULL_V(mem_new, ERR_OUT_OF_MEMORY); + + SafeNumeric *_refc_ptr = _get_refcount_ptr(mem_new); + T *_data_ptr = _get_data_ptr(mem_new); - _ptr = (T *)(_ptrnew); + new (_refc_ptr) SafeNumeric(rc); //refcount + + _ptr = _data_ptr; } } @@ -355,12 +384,15 @@ Error CowData::resize(Size p_size) { } if (alloc_size != current_alloc_size) { - USize *_ptrnew = (USize *)Memory::realloc_static(((uint8_t *)_ptr) - ALLOC_PAD, alloc_size + ALLOC_PAD, false); - ERR_FAIL_NULL_V(_ptrnew, ERR_OUT_OF_MEMORY); - _ptrnew += 2; - new (_ptrnew - 2) SafeNumeric(rc); //refcount + uint8_t *mem_new = (uint8_t *)Memory::realloc_static(((uint8_t *)_ptr) - DATA_OFFSET, alloc_size + DATA_OFFSET, false); + ERR_FAIL_NULL_V(mem_new, ERR_OUT_OF_MEMORY); + + SafeNumeric *_refc_ptr = _get_refcount_ptr(mem_new); + T *_data_ptr = _get_data_ptr(mem_new); + + new (_refc_ptr) SafeNumeric(rc); //refcount - _ptr = (T *)(_ptrnew); + _ptr = _data_ptr; } *_get_size() = p_size; From fb1662b939391cd2af9ce1cc6dba87b364f0ee77 Mon Sep 17 00:00:00 2001 From: A Thousand Ships <96648715+AThousandShips@users.noreply.github.com> Date: Mon, 5 Feb 2024 16:40:49 +0100 Subject: [PATCH 21/23] Fix crash with `PhysicsBody2D/3D::get_gravity` with invalid state --- scene/2d/physics_body_2d.cpp | 4 +++- scene/3d/physics_body_3d.cpp | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index 7a131916e8..af9008f452 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -147,7 +147,9 @@ bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion } Vector2 PhysicsBody2D::get_gravity() const { - return PhysicsServer2D::get_singleton()->body_get_direct_state(get_rid())->get_total_gravity(); + PhysicsDirectBodyState2D *state = PhysicsServer2D::get_singleton()->body_get_direct_state(get_rid()); + ERR_FAIL_NULL_V(state, Vector2()); + return state->get_total_gravity(); } TypedArray PhysicsBody2D::get_collision_exceptions() { diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp index 1f78928b94..7d08d767c7 100644 --- a/scene/3d/physics_body_3d.cpp +++ b/scene/3d/physics_body_3d.cpp @@ -189,7 +189,9 @@ bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_motion } Vector3 PhysicsBody3D::get_gravity() const { - return PhysicsServer3D::get_singleton()->body_get_direct_state(get_rid())->get_total_gravity(); + PhysicsDirectBodyState3D *state = PhysicsServer3D::get_singleton()->body_get_direct_state(get_rid()); + ERR_FAIL_NULL_V(state, Vector3()); + return state->get_total_gravity(); } void PhysicsBody3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock) { From 808f4e8cb9be502060317526f887b1d31cbeb40a Mon Sep 17 00:00:00 2001 From: kobewi Date: Mon, 5 Feb 2024 17:42:37 +0100 Subject: [PATCH 22/23] Check if history exists before discarding --- editor/editor_data.cpp | 4 +++- editor/editor_undo_redo_manager.cpp | 4 ++++ editor/editor_undo_redo_manager.h | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index 786e841c21..b4cf6d8de1 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -649,7 +649,9 @@ void EditorData::remove_scene(int p_idx) { EditorNode::get_singleton()->emit_signal("scene_closed", edited_scene[p_idx].path); } - undo_redo_manager->discard_history(edited_scene[p_idx].history_id); + if (undo_redo_manager->has_history(edited_scene[p_idx].history_id)) { // Might not exist if scene failed to load. + undo_redo_manager->discard_history(edited_scene[p_idx].history_id); + } edited_scene.remove_at(p_idx); } diff --git a/editor/editor_undo_redo_manager.cpp b/editor/editor_undo_redo_manager.cpp index c2491f8611..94f76dbc41 100644 --- a/editor/editor_undo_redo_manager.cpp +++ b/editor/editor_undo_redo_manager.cpp @@ -375,6 +375,10 @@ bool EditorUndoRedoManager::has_redo() { return false; } +bool EditorUndoRedoManager::has_history(int p_idx) const { + return history_map.has(p_idx); +} + void EditorUndoRedoManager::clear_history(bool p_increase_version, int p_idx) { if (p_idx != INVALID_HISTORY) { History &history = get_or_create_history(p_idx); diff --git a/editor/editor_undo_redo_manager.h b/editor/editor_undo_redo_manager.h index effa36a87c..e8c782871c 100644 --- a/editor/editor_undo_redo_manager.h +++ b/editor/editor_undo_redo_manager.h @@ -130,6 +130,7 @@ public: bool is_history_unsaved(int p_idx); bool has_undo(); bool has_redo(); + bool has_history(int p_idx) const; String get_current_action_name(); int get_current_action_history_id(); From 5922ac0fb11105da67d28847b60a521406a77cdb Mon Sep 17 00:00:00 2001 From: Adam Scott Date: Mon, 5 Feb 2024 11:42:28 -0500 Subject: [PATCH 23/23] Fix emscripten 3.1.51 breaking change about `*glGetProcAddress()` --- platform/web/detect.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/platform/web/detect.py b/platform/web/detect.py index bce03eb79e..7deec7b593 100644 --- a/platform/web/detect.py +++ b/platform/web/detect.py @@ -206,6 +206,11 @@ def configure(env: "Environment"): env.Append(LINKFLAGS=["-s", "USE_WEBGL2=1"]) # Allow use to take control of swapping WebGL buffers. env.Append(LINKFLAGS=["-s", "OFFSCREEN_FRAMEBUFFER=1"]) + # Breaking change since emscripten 3.1.51 + # https://github.com/emscripten-core/emscripten/blob/main/ChangeLog.md#3151---121323 + if cc_semver >= (3, 1, 51): + # Enables the use of *glGetProcAddress() + env.Append(LINKFLAGS=["-s", "GL_ENABLE_GET_PROC_ADDRESS=1"]) if env["javascript_eval"]: env.Append(CPPDEFINES=["JAVASCRIPT_EVAL_ENABLED"])