summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/math/vector2.cpp4
-rw-r--r--core/math/vector2.h1
-rw-r--r--core/templates/vector.h2
-rw-r--r--core/variant/variant_call.cpp2
-rw-r--r--core/variant/variant_utility.cpp11
-rw-r--r--doc/classes/@GlobalScope.xml17
-rw-r--r--doc/classes/CharacterBody2D.xml7
-rw-r--r--doc/classes/EditorPlugin.xml16
-rw-r--r--doc/classes/PhysicsServer2D.xml3
-rw-r--r--doc/classes/PhysicsServer3D.xml3
-rw-r--r--doc/classes/SoftBody3D.xml23
-rw-r--r--doc/classes/TextureProgressBar.xml3
-rw-r--r--doc/classes/Vector2.xml12
-rw-r--r--editor/debugger/debug_adapter/debug_adapter_parser.cpp203
-rw-r--r--editor/debugger/debug_adapter/debug_adapter_parser.h16
-rw-r--r--editor/debugger/debug_adapter/debug_adapter_protocol.cpp541
-rw-r--r--editor/debugger/debug_adapter/debug_adapter_protocol.h17
-rw-r--r--editor/debugger/debug_adapter/debug_adapter_server.cpp31
-rw-r--r--editor/debugger/debug_adapter/debug_adapter_server.h2
-rw-r--r--editor/debugger/debug_adapter/debug_adapter_types.h10
-rw-r--r--editor/debugger/editor_debugger_node.cpp3
-rw-r--r--editor/debugger/script_editor_debugger.cpp14
-rw-r--r--editor/debugger/script_editor_debugger.h3
-rw-r--r--editor/editor_node.cpp4
-rw-r--r--editor/editor_node.h1
-rw-r--r--editor/editor_run_native.cpp18
-rw-r--r--editor/editor_run_native.h3
-rw-r--r--editor/editor_themes.cpp6
-rw-r--r--editor/plugins/script_editor_plugin.cpp26
-rw-r--r--editor/plugins/script_editor_plugin.h4
-rw-r--r--editor/plugins/script_text_editor.cpp8
-rw-r--r--editor/plugins/script_text_editor.h2
-rw-r--r--editor/plugins/text_editor.h2
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp85
-rw-r--r--modules/gdscript/gdscript_analyzer.h6
-rw-r--r--modules/gdscript/gdscript_compiler.cpp29
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs26
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs11
-rw-r--r--modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml54
-rw-r--r--modules/visual_script/visual_script_builtin_funcs.cpp40
-rw-r--r--modules/visual_script/visual_script_builtin_funcs.h2
-rw-r--r--modules/visual_script/visual_script_editor.h2
-rw-r--r--platform/android/export/export_plugin.cpp5
-rw-r--r--platform/android/export/gradle_export_util.cpp6
-rw-r--r--platform/android/java/app/AndroidManifest.xml4
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/Godot.java6
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java14
-rw-r--r--scene/2d/physics_body_2d.cpp128
-rw-r--r--scene/2d/physics_body_2d.h22
-rw-r--r--scene/3d/physics_body_3d.cpp117
-rw-r--r--scene/3d/physics_body_3d.h10
-rw-r--r--scene/3d/soft_body_3d.cpp5
-rw-r--r--scene/3d/vehicle_body_3d.cpp33
-rw-r--r--scene/3d/vehicle_body_3d.h3
-rw-r--r--scene/gui/tab_container.cpp17
-rw-r--r--scene/gui/texture_progress_bar.cpp57
-rw-r--r--scene/gui/texture_progress_bar.h4
-rw-r--r--servers/physics_2d/body_2d_sw.cpp84
-rw-r--r--servers/physics_2d/body_2d_sw.h98
-rw-r--r--servers/physics_2d/body_direct_state_2d_sw.cpp182
-rw-r--r--servers/physics_2d/body_direct_state_2d_sw.h91
-rw-r--r--servers/physics_2d/physics_server_2d_sw.cpp20
-rw-r--r--servers/physics_2d/physics_server_2d_sw.h5
-rw-r--r--servers/physics_2d/physics_server_2d_wrap_mt.h1
-rw-r--r--servers/physics_2d/space_2d_sw.cpp4
-rw-r--r--servers/physics_2d/space_2d_sw.h5
-rw-r--r--servers/physics_2d/step_2d_sw.cpp2
-rw-r--r--servers/physics_3d/body_3d_sw.cpp72
-rw-r--r--servers/physics_3d/body_3d_sw.h111
-rw-r--r--servers/physics_3d/body_direct_state_3d_sw.cpp182
-rw-r--r--servers/physics_3d/body_direct_state_3d_sw.h94
-rw-r--r--servers/physics_3d/physics_server_3d_sw.cpp20
-rw-r--r--servers/physics_3d/physics_server_3d_sw.h4
-rw-r--r--servers/physics_3d/physics_server_3d_wrap_mt.h1
-rw-r--r--servers/physics_3d/space_3d_sw.h5
-rw-r--r--servers/physics_3d/step_3d_sw.cpp2
-rw-r--r--servers/physics_server_2d.h4
-rw-r--r--servers/physics_server_3d.h4
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp2
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp2
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp2
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp2
-rw-r--r--servers/rendering/renderer_rd/renderer_storage_rd.cpp2
83 files changed, 1991 insertions, 714 deletions
diff --git a/core/math/vector2.cpp b/core/math/vector2.cpp
index 54abc1b7f2..b53dc05a00 100644
--- a/core/math/vector2.cpp
+++ b/core/math/vector2.cpp
@@ -34,6 +34,10 @@ real_t Vector2::angle() const {
return Math::atan2(y, x);
}
+Vector2 Vector2::from_angle(const real_t p_angle) {
+ return Vector2(Math::cos(p_angle), Math::sin(p_angle));
+}
+
real_t Vector2::length() const {
return Math::sqrt(x * x + y * y);
}
diff --git a/core/math/vector2.h b/core/math/vector2.h
index 330b4741b1..332c0475fa 100644
--- a/core/math/vector2.h
+++ b/core/math/vector2.h
@@ -147,6 +147,7 @@ struct Vector2 {
bool operator>=(const Vector2 &p_vec2) const { return x == p_vec2.x ? (y >= p_vec2.y) : (x > p_vec2.x); }
real_t angle() const;
+ static Vector2 from_angle(const real_t p_angle);
_FORCE_INLINE_ Vector2 abs() const {
return Vector2(Math::abs(x), Math::abs(y));
diff --git a/core/templates/vector.h b/core/templates/vector.h
index 08cbef6ba4..033345d04c 100644
--- a/core/templates/vector.h
+++ b/core/templates/vector.h
@@ -229,7 +229,7 @@ public:
_FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return elem_ptr == b.elem_ptr; }
_FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return elem_ptr != b.elem_ptr; }
- ConstIterator(T *p_ptr) { elem_ptr = p_ptr; }
+ ConstIterator(const T *p_ptr) { elem_ptr = p_ptr; }
ConstIterator() {}
ConstIterator(const ConstIterator &p_it) { elem_ptr = p_it.elem_ptr; }
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index c9c7eca40d..39207df9e7 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -1502,6 +1502,8 @@ static void _register_variant_builtin_methods() {
bind_method(Vector2, clamp, sarray("min", "max"), varray());
bind_method(Vector2, snapped, sarray("step"), varray());
+ bind_static_method(Vector2, from_angle, sarray("angle"), varray());
+
/* Vector2i */
bind_method(Vector2i, aspect, sarray(), varray());
diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp
index f5cb2d40d6..232054d0ca 100644
--- a/core/variant/variant_utility.cpp
+++ b/core/variant/variant_utility.cpp
@@ -267,14 +267,6 @@ struct VariantUtilityFunctions {
return Math::db2linear(db);
}
- static inline Vector2 polar2cartesian(double r, double th) {
- return Vector2(r * Math::cos(th), r * Math::sin(th));
- }
-
- static inline Vector2 cartesian2polar(double x, double y) {
- return Vector2(Math::sqrt(x * x + y * y), Math::atan2(y, x));
- }
-
static inline int64_t wrapi(int64_t value, int64_t min, int64_t max) {
return Math::wrapi(value, min, max);
}
@@ -1214,9 +1206,6 @@ void Variant::_register_variant_utility_functions() {
FUNCBINDR(linear2db, sarray("lin"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(db2linear, sarray("db"), Variant::UTILITY_FUNC_TYPE_MATH);
- FUNCBINDR(polar2cartesian, sarray("r", "th"), Variant::UTILITY_FUNC_TYPE_MATH);
- FUNCBINDR(cartesian2polar, sarray("x", "y"), Variant::UTILITY_FUNC_TYPE_MATH);
-
FUNCBINDR(wrapi, sarray("value", "min", "max"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(wrapf, sarray("value", "min", "max"), Variant::UTILITY_FUNC_TYPE_MATH);
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index 585b94a522..616d88c7f3 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -99,14 +99,6 @@
[b]Warning:[/b] Deserialized object can contain code which gets executed. Do not use this option if the serialized object comes from untrusted sources to avoid potential security threats (remote code execution).
</description>
</method>
- <method name="cartesian2polar">
- <return type="Vector2" />
- <argument index="0" name="x" type="float" />
- <argument index="1" name="y" type="float" />
- <description>
- Converts a 2D point expressed in the cartesian coordinate system (X and Y axis) to the polar coordinate system (a distance from the origin and an angle).
- </description>
- </method>
<method name="ceil">
<return type="float" />
<argument index="0" name="x" type="float" />
@@ -521,14 +513,6 @@
[b]Warning:[/b] Due to the way it is implemented, this function returns [code]0[/code] rather than [code]1[/code] for non-positive values of [code]value[/code] (in reality, 1 is the smallest integer power of 2).
</description>
</method>
- <method name="polar2cartesian">
- <return type="Vector2" />
- <argument index="0" name="r" type="float" />
- <argument index="1" name="th" type="float" />
- <description>
- Converts a 2D point expressed in the polar coordinate system (a distance from the origin [code]r[/code] and an angle [code]th[/code]) to the cartesian coordinate system (X and Y axis).
- </description>
- </method>
<method name="posmod">
<return type="int" />
<argument index="0" name="x" type="int" />
@@ -2474,6 +2458,7 @@
<constant name="METHOD_FLAG_STATIC" value="256" enum="MethodFlags">
</constant>
<constant name="METHOD_FLAG_OBJECT_CORE" value="512" enum="MethodFlags">
+ Used internally. Allows to not dump core virtuals such as [code]_notification[/code] to the JSON API.
</constant>
<constant name="METHOD_FLAGS_DEFAULT" value="1" enum="MethodFlags">
Default method flags.
diff --git a/doc/classes/CharacterBody2D.xml b/doc/classes/CharacterBody2D.xml
index e5f60541b9..71e6eeab5a 100644
--- a/doc/classes/CharacterBody2D.xml
+++ b/doc/classes/CharacterBody2D.xml
@@ -152,8 +152,11 @@
<member name="motion_mode" type="int" setter="set_motion_mode" getter="get_motion_mode" enum="CharacterBody2D.MotionMode" default="0">
Sets the motion mode which defines the behaviour of [method move_and_slide]. See [enum MotionMode] constants for available modes.
</member>
- <member name="moving_platform_ignore_layers" type="int" setter="set_moving_platform_ignore_layers" getter="get_moving_platform_ignore_layers" default="0">
- Collision layers that will be excluded for detecting bodies that will act as moving platforms to be followed by the [CharacterBody2D]. By default, all touching bodies are detected and propagate their velocity. You can add excluded layers to ignore bodies that are contained in these layers.
+ <member name="moving_platform_floor_layers" type="int" setter="set_moving_platform_floor_layers" getter="get_moving_platform_floor_layers" default="4294967295">
+ Collision layers that will be included for detecting floor bodies that will act as moving platforms to be followed by the [CharacterBody2D]. By default, all floor bodies are detected and propagate their velocity.
+ </member>
+ <member name="moving_platform_wall_layers" type="int" setter="set_moving_platform_wall_layers" getter="get_moving_platform_wall_layers" default="0">
+ Collision layers that will be included for detecting wall bodies that will act as moving platforms to be followed by the [CharacterBody2D]. By default, all wall bodies are ignored.
</member>
<member name="slide_on_ceiling" type="bool" setter="set_slide_on_ceiling_enabled" getter="is_slide_on_ceiling_enabled" default="true">
If [code]true[/code], during a jump against the ceiling, the body will slide, if [code]false[/code] it will be stopped and will fall vertically.
diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml
index e564e8045c..b8436be76a 100644
--- a/doc/classes/EditorPlugin.xml
+++ b/doc/classes/EditorPlugin.xml
@@ -56,11 +56,11 @@
Called by the engine when the 3D editor's viewport is updated. Use the [code]overlay[/code] [Control] for drawing. You can update the viewport manually by calling [method update_overlays].
[codeblocks]
[gdscript]
- func _forward_spatial_3d_over_viewport(overlay):
+ func _forward_3d_draw_over_viewport(overlay):
# Draw a circle at cursor position.
overlay.draw_circle(overlay.get_local_mouse_position(), 64)
- func _forward_spatial_gui_input(camera, event):
+ func _forward_3d_gui_input(camera, event):
if event is InputEventMouseMotion:
# Redraw viewport when cursor is moved.
update_overlays()
@@ -68,13 +68,13 @@
return false
[/gdscript]
[csharp]
- public override void ForwardSpatialDrawOverViewport(Godot.Control overlay)
+ public override void _Forward3dDrawOverViewport(Godot.Control overlay)
{
// Draw a circle at cursor position.
overlay.DrawCircle(overlay.GetLocalMousePosition(), 64, Colors.White);
}
- public override bool ForwardSpatialGuiInput(Godot.Camera3D camera, InputEvent @event)
+ public override bool _Forward3dGuiInput(Godot.Camera3D camera, InputEvent @event)
{
if (@event is InputEventMouseMotion)
{
@@ -104,12 +104,12 @@
[codeblocks]
[gdscript]
# Prevents the InputEvent to reach other Editor classes.
- func _forward_spatial_gui_input(camera, event):
+ func _forward_3d_gui_input(camera, event):
return true
[/gdscript]
[csharp]
// Prevents the InputEvent to reach other Editor classes.
- public override bool ForwardSpatialGuiInput(Camera3D camera, InputEvent @event)
+ public override bool _Forward3dGuiInput(Camera3D camera, InputEvent @event)
{
return true;
}
@@ -119,12 +119,12 @@
[codeblocks]
[gdscript]
# Consumes InputEventMouseMotion and forwards other InputEvent types.
- func _forward_spatial_gui_input(camera, event):
+ func _forward_3d_gui_input(camera, event):
return event is InputEventMouseMotion
[/gdscript]
[csharp]
// Consumes InputEventMouseMotion and forwards other InputEvent types.
- public override bool ForwardSpatialGuiInput(Camera3D camera, InputEvent @event)
+ public override bool _Forward3dGuiInput(Camera3D camera, InputEvent @event)
{
return @event is InputEventMouseMotion;
}
diff --git a/doc/classes/PhysicsServer2D.xml b/doc/classes/PhysicsServer2D.xml
index d0ae665139..9867b98ae6 100644
--- a/doc/classes/PhysicsServer2D.xml
+++ b/doc/classes/PhysicsServer2D.xml
@@ -489,6 +489,9 @@
<argument index="2" name="userdata" type="Variant" default="null" />
<description>
Sets the function used to calculate physics for an object, if that object allows it (see [method body_set_omit_force_integration]).
+ The force integration function takes 2 arguments:
+ [code]state:[/code] [PhysicsDirectBodyState2D] used to retrieve and modify the body's state.
+ [code]userdata:[/code] Optional user data, if it was passed when calling [code]body_set_force_integration_callback[/code].
</description>
</method>
<method name="body_set_max_contacts_reported">
diff --git a/doc/classes/PhysicsServer3D.xml b/doc/classes/PhysicsServer3D.xml
index c47a311161..46cbe48b28 100644
--- a/doc/classes/PhysicsServer3D.xml
+++ b/doc/classes/PhysicsServer3D.xml
@@ -478,6 +478,9 @@
<argument index="2" name="userdata" type="Variant" default="null" />
<description>
Sets the function used to calculate physics for an object, if that object allows it (see [method body_set_omit_force_integration]).
+ The force integration function takes 2 arguments:
+ [code]state:[/code] [PhysicsDirectBodyState3D] used to retrieve and modify the body's state.
+ [code]userdata:[/code] Optional user data, if it was passed when calling [code]body_set_force_integration_callback[/code].
</description>
</method>
<method name="body_set_max_contacts_reported">
diff --git a/doc/classes/SoftBody3D.xml b/doc/classes/SoftBody3D.xml
index ddfc14ceac..d5f0e3c95c 100644
--- a/doc/classes/SoftBody3D.xml
+++ b/doc/classes/SoftBody3D.xml
@@ -42,6 +42,20 @@
<description>
</description>
</method>
+ <method name="get_point_transform">
+ <return type="Vector3" />
+ <argument index="0" name="point_index" type="int" />
+ <description>
+ Returns local translation of a vertex in the surface array.
+ </description>
+ </method>
+ <method name="is_point_pinned" qualifiers="const">
+ <return type="bool" />
+ <argument index="0" name="point_index" type="int" />
+ <description>
+ Returns [code]true[/code] if vertex is set to pinned.
+ </description>
+ </method>
<method name="remove_collision_exception_with">
<return type="void" />
<argument index="0" name="body" type="Node" />
@@ -65,6 +79,15 @@
Based on [code]value[/code], enables or disables the specified layer in the [member collision_mask], given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
+ <method name="set_point_pinned">
+ <return type="void" />
+ <argument index="0" name="point_index" type="int" />
+ <argument index="1" name="pinned" type="bool" />
+ <argument index="2" name="attachment_path" type="NodePath" default="NodePath(&quot;&quot;)" />
+ <description>
+ Sets the pinned state of a surface vertex. When set to [code]true[/code], the optional [code]attachment_path[/code] can define a [Node3D] the pinned vertex will be attached to.
+ </description>
+ </method>
</methods>
<members>
<member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="1">
diff --git a/doc/classes/TextureProgressBar.xml b/doc/classes/TextureProgressBar.xml
index 9da89ebe43..ee47557b39 100644
--- a/doc/classes/TextureProgressBar.xml
+++ b/doc/classes/TextureProgressBar.xml
@@ -60,6 +60,9 @@
[Texture2D] that clips based on the node's [code]value[/code] and [member fill_mode]. As [code]value[/code] increased, the texture fills up. It shows entirely when [code]value[/code] reaches [code]max_value[/code]. It doesn't show at all if [code]value[/code] is equal to [code]min_value[/code].
The [code]value[/code] property comes from [Range]. See [member Range.value], [member Range.min_value], [member Range.max_value].
</member>
+ <member name="texture_progress_offset" type="Vector2" setter="set_texture_progress_offset" getter="get_texture_progress_offset" default="Vector2(0, 0)">
+ The offset of [member texture_progress]. Useful for [member texture_over] and [member texture_under] with fancy borders, to avoid transparent margins in your progress texture.
+ </member>
<member name="texture_under" type="Texture2D" setter="set_under_texture" getter="get_under_texture">
[Texture2D] that draws under the progress bar. The bar's background.
</member>
diff --git a/doc/classes/Vector2.xml b/doc/classes/Vector2.xml
index cb5662419e..ab4d0e181a 100644
--- a/doc/classes/Vector2.xml
+++ b/doc/classes/Vector2.xml
@@ -155,6 +155,18 @@
Returns the vector with all components rounded down (towards negative infinity).
</description>
</method>
+ <method name="from_angle" qualifiers="static">
+ <return type="Vector2" />
+ <argument index="0" name="angle" type="float" />
+ <description>
+ Creates a unit [Vector2] rotated to the given [code]angle[/code] in radians. This is equivalent to doing [code]Vector2(cos(angle), sin(angle))[/code] or [code]Vector2.RIGHT.rotated(angle)[/code].
+ [codeblock]
+ print(Vector2.from_angle(0)) # Prints (1, 0).
+ print(Vector2(1, 0).angle()) # Prints 0, which is the angle used above.
+ print(Vector2.from_angle(PI / 2)) # Prints (0, 1).
+ [/codeblock]
+ </description>
+ </method>
<method name="is_equal_approx" qualifiers="const">
<return type="bool" />
<argument index="0" name="to" type="Vector2" />
diff --git a/editor/debugger/debug_adapter/debug_adapter_parser.cpp b/editor/debugger/debug_adapter/debug_adapter_parser.cpp
index 945291b163..fbd3aaa409 100644
--- a/editor/debugger/debug_adapter/debug_adapter_parser.cpp
+++ b/editor/debugger/debug_adapter/debug_adapter_parser.cpp
@@ -33,12 +33,15 @@
#include "editor/debugger/editor_debugger_node.h"
#include "editor/debugger/script_editor_debugger.h"
#include "editor/editor_node.h"
+#include "editor/editor_run_native.h"
void DebugAdapterParser::_bind_methods() {
// Requests
ClassDB::bind_method(D_METHOD("req_initialize", "params"), &DebugAdapterParser::req_initialize);
- ClassDB::bind_method(D_METHOD("req_disconnect", "params"), &DebugAdapterParser::prepare_success_response);
+ ClassDB::bind_method(D_METHOD("req_disconnect", "params"), &DebugAdapterParser::req_disconnect);
ClassDB::bind_method(D_METHOD("req_launch", "params"), &DebugAdapterParser::req_launch);
+ ClassDB::bind_method(D_METHOD("req_attach", "params"), &DebugAdapterParser::req_attach);
+ ClassDB::bind_method(D_METHOD("req_restart", "params"), &DebugAdapterParser::req_restart);
ClassDB::bind_method(D_METHOD("req_terminate", "params"), &DebugAdapterParser::req_terminate);
ClassDB::bind_method(D_METHOD("req_configurationDone", "params"), &DebugAdapterParser::prepare_success_response);
ClassDB::bind_method(D_METHOD("req_pause", "params"), &DebugAdapterParser::req_pause);
@@ -46,10 +49,13 @@ void DebugAdapterParser::_bind_methods() {
ClassDB::bind_method(D_METHOD("req_threads", "params"), &DebugAdapterParser::req_threads);
ClassDB::bind_method(D_METHOD("req_stackTrace", "params"), &DebugAdapterParser::req_stackTrace);
ClassDB::bind_method(D_METHOD("req_setBreakpoints", "params"), &DebugAdapterParser::req_setBreakpoints);
+ ClassDB::bind_method(D_METHOD("req_breakpointLocations", "params"), &DebugAdapterParser::req_breakpointLocations);
ClassDB::bind_method(D_METHOD("req_scopes", "params"), &DebugAdapterParser::req_scopes);
ClassDB::bind_method(D_METHOD("req_variables", "params"), &DebugAdapterParser::req_variables);
ClassDB::bind_method(D_METHOD("req_next", "params"), &DebugAdapterParser::req_next);
ClassDB::bind_method(D_METHOD("req_stepIn", "params"), &DebugAdapterParser::req_stepIn);
+ ClassDB::bind_method(D_METHOD("req_evaluate", "params"), &DebugAdapterParser::req_evaluate);
+ ClassDB::bind_method(D_METHOD("req_godot/put_msg", "params"), &DebugAdapterParser::req_godot_put_msg);
}
Dictionary DebugAdapterParser::prepare_base_event() const {
@@ -80,13 +86,31 @@ Dictionary DebugAdapterParser::prepare_error_response(const Dictionary &p_params
DAP::Message message;
String error, error_desc;
switch (err_type) {
+ case DAP::ErrorType::WRONG_PATH:
+ error = "wrong_path";
+ error_desc = "The editor and client are working on different paths; the client is on \"{clientPath}\", but the editor is on \"{editorPath}\"";
+ break;
+ case DAP::ErrorType::NOT_RUNNING:
+ error = "not_running";
+ error_desc = "Can't attach to a running session since there isn't one.";
+ break;
+ case DAP::ErrorType::TIMEOUT:
+ error = "timeout";
+ error_desc = "Timeout reached while processing a request.";
+ break;
+ case DAP::ErrorType::UNKNOWN_PLATFORM:
+ error = "unknown_platform";
+ error_desc = "The specified platform is unknown.";
+ break;
+ case DAP::ErrorType::MISSING_DEVICE:
+ error = "missing_device";
+ error_desc = "There's no connected device with specified id.";
+ break;
case DAP::ErrorType::UNKNOWN:
+ default:
error = "unknown";
error_desc = "An unknown error has ocurred when processing the request.";
break;
- case DAP::ErrorType::WRONG_PATH:
- error = "wrong_path";
- error_desc = "The editor and client are working on different paths; the client is on \"{clientPath}\", but the editor is on \"{editorPath}\"";
}
message.id = err_type;
@@ -114,10 +138,35 @@ Dictionary DebugAdapterParser::req_initialize(const Dictionary &p_params) const
DebugAdapterProtocol::get_singleton()->notify_initialized();
+ if (DebugAdapterProtocol::get_singleton()->_sync_breakpoints) {
+ // Send all current breakpoints
+ List<String> breakpoints;
+ ScriptEditor::get_singleton()->get_breakpoints(&breakpoints);
+ for (List<String>::Element *E = breakpoints.front(); E; E = E->next()) {
+ String breakpoint = E->get();
+
+ String path = breakpoint.left(breakpoint.find(":", 6)); // Skip initial part of path, aka "res://"
+ int line = breakpoint.substr(path.size()).to_int();
+
+ DebugAdapterProtocol::get_singleton()->on_debug_breakpoint_toggled(path, line, true);
+ }
+ } else {
+ // Remove all current breakpoints
+ EditorDebuggerNode::get_singleton()->get_default_debugger()->_clear_breakpoints();
+ }
+
return response;
}
-Dictionary DebugAdapterParser::req_launch(const Dictionary &p_params) {
+Dictionary DebugAdapterParser::req_disconnect(const Dictionary &p_params) const {
+ if (!DebugAdapterProtocol::get_singleton()->get_current_peer()->attached) {
+ EditorNode::get_singleton()->run_stop();
+ }
+
+ return prepare_success_response(p_params);
+}
+
+Dictionary DebugAdapterParser::req_launch(const Dictionary &p_params) const {
Dictionary args = p_params["arguments"];
if (args.has("project") && !is_valid_path(args["project"])) {
Dictionary variables;
@@ -126,17 +175,85 @@ Dictionary DebugAdapterParser::req_launch(const Dictionary &p_params) {
return prepare_error_response(p_params, DAP::ErrorType::WRONG_PATH, variables);
}
+ if (args.has("godot/custom_data")) {
+ DebugAdapterProtocol::get_singleton()->get_current_peer()->supportsCustomData = args["godot/custom_data"];
+ }
+
ScriptEditorDebugger *dbg = EditorDebuggerNode::get_singleton()->get_default_debugger();
if ((bool)args["noDebug"] != dbg->is_skip_breakpoints()) {
dbg->debug_skip_breakpoints();
}
- EditorNode::get_singleton()->run_play();
+ String platform_string = args.get("platform", "host");
+ if (platform_string == "host") {
+ EditorNode::get_singleton()->run_play();
+ } else {
+ int device = args.get("device", -1);
+ int idx = -1;
+ if (platform_string == "android") {
+ for (int i = 0; i < EditorExport::get_singleton()->get_export_platform_count(); i++) {
+ if (EditorExport::get_singleton()->get_export_platform(i)->get_name() == "Android") {
+ idx = i;
+ break;
+ }
+ }
+ } else if (platform_string == "web") {
+ for (int i = 0; i < EditorExport::get_singleton()->get_export_platform_count(); i++) {
+ if (EditorExport::get_singleton()->get_export_platform(i)->get_name() == "HTML5") {
+ idx = i;
+ break;
+ }
+ }
+ }
+
+ if (idx == -1) {
+ return prepare_error_response(p_params, DAP::ErrorType::UNKNOWN_PLATFORM);
+ }
+
+ EditorNode *editor = EditorNode::get_singleton();
+ Error err = platform_string == "android" ? editor->run_play_native(device, idx) : editor->run_play_native(-1, idx);
+ if (err) {
+ if (err == ERR_INVALID_PARAMETER && platform_string == "android") {
+ return prepare_error_response(p_params, DAP::ErrorType::MISSING_DEVICE);
+ } else {
+ return prepare_error_response(p_params, DAP::ErrorType::UNKNOWN);
+ }
+ }
+ }
+
+ DebugAdapterProtocol::get_singleton()->get_current_peer()->attached = false;
DebugAdapterProtocol::get_singleton()->notify_process();
return prepare_success_response(p_params);
}
+Dictionary DebugAdapterParser::req_attach(const Dictionary &p_params) const {
+ ScriptEditorDebugger *dbg = EditorDebuggerNode::get_singleton()->get_default_debugger();
+ if (!dbg->is_session_active()) {
+ return prepare_error_response(p_params, DAP::ErrorType::NOT_RUNNING);
+ }
+
+ DebugAdapterProtocol::get_singleton()->get_current_peer()->attached = true;
+ DebugAdapterProtocol::get_singleton()->notify_process();
+ return prepare_success_response(p_params);
+}
+
+Dictionary DebugAdapterParser::req_restart(const Dictionary &p_params) const {
+ // Extract embedded "arguments" so it can be given to req_launch/req_attach
+ Dictionary params = p_params, args;
+ args = params["arguments"];
+ args = args["arguments"];
+ params["arguments"] = args;
+
+ Dictionary response = DebugAdapterProtocol::get_singleton()->get_current_peer()->attached ? req_attach(params) : req_launch(params);
+ if (!response["success"]) {
+ response["command"] = p_params["command"];
+ return response;
+ }
+
+ return prepare_success_response(p_params);
+}
+
Dictionary DebugAdapterParser::req_terminate(const Dictionary &p_params) const {
EditorNode::get_singleton()->run_stop();
@@ -205,7 +322,7 @@ Dictionary DebugAdapterParser::req_stackTrace(const Dictionary &p_params) const
return response;
}
-Dictionary DebugAdapterParser::req_setBreakpoints(const Dictionary &p_params) {
+Dictionary DebugAdapterParser::req_setBreakpoints(const Dictionary &p_params) const {
Dictionary response = prepare_success_response(p_params), body;
response["body"] = body;
@@ -230,14 +347,30 @@ Dictionary DebugAdapterParser::req_setBreakpoints(const Dictionary &p_params) {
lines.push_back(breakpoint.line + !lines_at_one);
}
- EditorDebuggerNode::get_singleton()->set_breakpoints(ProjectSettings::get_singleton()->localize_path(source.path), lines);
Array updated_breakpoints = DebugAdapterProtocol::get_singleton()->update_breakpoints(source.path, lines);
body["breakpoints"] = updated_breakpoints;
return response;
}
-Dictionary DebugAdapterParser::req_scopes(const Dictionary &p_params) {
+Dictionary DebugAdapterParser::req_breakpointLocations(const Dictionary &p_params) const {
+ Dictionary response = prepare_success_response(p_params), body;
+ response["body"] = body;
+ Dictionary args = p_params["arguments"];
+
+ Array locations;
+ DAP::BreakpointLocation location;
+ location.line = args["line"];
+ if (args.has("endLine")) {
+ location.endLine = args["endLine"];
+ }
+ locations.push_back(location.to_json());
+
+ body["breakpoints"] = locations;
+ return response;
+}
+
+Dictionary DebugAdapterParser::req_scopes(const Dictionary &p_params) const {
Dictionary response = prepare_success_response(p_params), body;
response["body"] = body;
@@ -291,7 +424,14 @@ Dictionary DebugAdapterParser::req_variables(const Dictionary &p_params) const {
int variable_id = args["variablesReference"];
Map<int, Array>::Element *E = DebugAdapterProtocol::get_singleton()->variable_list.find(variable_id);
+
if (E) {
+ if (!DebugAdapterProtocol::get_singleton()->get_current_peer()->supportsVariableType) {
+ for (int i = 0; i < E->value().size(); i++) {
+ Dictionary variable = E->value()[i];
+ variable.erase("type");
+ }
+ }
body["variables"] = E ? E->value() : Array();
return response;
} else {
@@ -313,6 +453,29 @@ Dictionary DebugAdapterParser::req_stepIn(const Dictionary &p_params) const {
return prepare_success_response(p_params);
}
+Dictionary DebugAdapterParser::req_evaluate(const Dictionary &p_params) const {
+ Dictionary response = prepare_success_response(p_params), body;
+ response["body"] = body;
+
+ Dictionary args = p_params["arguments"];
+
+ String value = EditorDebuggerNode::get_singleton()->get_var_value(args["expression"]);
+ body["result"] = value;
+
+ return response;
+}
+
+Dictionary DebugAdapterParser::req_godot_put_msg(const Dictionary &p_params) const {
+ Dictionary args = p_params["arguments"];
+
+ String msg = args["message"];
+ Array data = args["data"];
+
+ EditorDebuggerNode::get_singleton()->get_default_debugger()->_put_msg(msg, data);
+
+ return prepare_success_response(p_params);
+}
+
Dictionary DebugAdapterParser::ev_initialized() const {
Dictionary event = prepare_base_event();
event["event"] = "initialized";
@@ -423,3 +586,25 @@ Dictionary DebugAdapterParser::ev_output(const String &p_message) const {
return event;
}
+
+Dictionary DebugAdapterParser::ev_breakpoint(const DAP::Breakpoint &p_breakpoint, const bool &p_enabled) const {
+ Dictionary event = prepare_base_event(), body;
+ event["event"] = "breakpoint";
+ event["body"] = body;
+
+ body["reason"] = p_enabled ? "new" : "removed";
+ body["breakpoint"] = p_breakpoint.to_json();
+
+ return event;
+}
+
+Dictionary DebugAdapterParser::ev_custom_data(const String &p_msg, const Array &p_data) const {
+ Dictionary event = prepare_base_event(), body;
+ event["event"] = "godot/custom_data";
+ event["body"] = body;
+
+ body["message"] = p_msg;
+ body["data"] = p_data;
+
+ return event;
+}
diff --git a/editor/debugger/debug_adapter/debug_adapter_parser.h b/editor/debugger/debug_adapter/debug_adapter_parser.h
index b86b37d067..4c93464e39 100644
--- a/editor/debugger/debug_adapter/debug_adapter_parser.h
+++ b/editor/debugger/debug_adapter/debug_adapter_parser.h
@@ -44,7 +44,7 @@ class DebugAdapterParser : public Object {
private:
friend DebugAdapterProtocol;
- _FORCE_INLINE_ bool is_valid_path(const String &p_path) {
+ _FORCE_INLINE_ bool is_valid_path(const String &p_path) const {
return p_path.begins_with(ProjectSettings::get_singleton()->get_resource_path());
}
@@ -60,17 +60,23 @@ protected:
public:
// Requests
Dictionary req_initialize(const Dictionary &p_params) const;
- Dictionary req_launch(const Dictionary &p_params);
+ Dictionary req_launch(const Dictionary &p_params) const;
+ Dictionary req_disconnect(const Dictionary &p_params) const;
+ Dictionary req_attach(const Dictionary &p_params) const;
+ Dictionary req_restart(const Dictionary &p_params) const;
Dictionary req_terminate(const Dictionary &p_params) const;
Dictionary req_pause(const Dictionary &p_params) const;
Dictionary req_continue(const Dictionary &p_params) const;
Dictionary req_threads(const Dictionary &p_params) const;
Dictionary req_stackTrace(const Dictionary &p_params) const;
- Dictionary req_setBreakpoints(const Dictionary &p_params);
- Dictionary req_scopes(const Dictionary &p_params);
+ Dictionary req_setBreakpoints(const Dictionary &p_params) const;
+ Dictionary req_breakpointLocations(const Dictionary &p_params) const;
+ Dictionary req_scopes(const Dictionary &p_params) const;
Dictionary req_variables(const Dictionary &p_params) const;
Dictionary req_next(const Dictionary &p_params) const;
Dictionary req_stepIn(const Dictionary &p_params) const;
+ Dictionary req_evaluate(const Dictionary &p_params) const;
+ Dictionary req_godot_put_msg(const Dictionary &p_params) const;
// Events
Dictionary ev_initialized() const;
@@ -83,6 +89,8 @@ public:
Dictionary ev_stopped_step() const;
Dictionary ev_continued() const;
Dictionary ev_output(const String &p_message) const;
+ Dictionary ev_custom_data(const String &p_msg, const Array &p_data) const;
+ Dictionary ev_breakpoint(const DAP::Breakpoint &p_breakpoint, const bool &p_enabled) const;
};
#endif
diff --git a/editor/debugger/debug_adapter/debug_adapter_protocol.cpp b/editor/debugger/debug_adapter/debug_adapter_protocol.cpp
index 0482271432..2e0e6cb7c8 100644
--- a/editor/debugger/debug_adapter/debug_adapter_protocol.cpp
+++ b/editor/debugger/debug_adapter/debug_adapter_protocol.cpp
@@ -94,11 +94,17 @@ Error DAPeer::handle_data() {
String msg;
msg.parse_utf8((const char *)req_buf, req_pos);
+ // Apply a timestamp if it there's none yet
+ if (!timestamp) {
+ timestamp = OS::get_singleton()->get_ticks_msec();
+ }
+
// Response
if (DebugAdapterProtocol::get_singleton()->process_message(msg)) {
// Reset to read again
req_pos = 0;
has_header = false;
+ timestamp = 0;
}
}
return OK;
@@ -180,12 +186,460 @@ void DebugAdapterProtocol::reset_stack_info() {
variable_list.clear();
}
+int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
+ switch (p_var.get_type()) {
+ case Variant::VECTOR2:
+ case Variant::VECTOR2I: {
+ int id = variable_id++;
+ Vector2 vec = p_var;
+ DAP::Variable x, y;
+ x.name = "x";
+ y.name = "y";
+ x.type = y.type = Variant::get_type_name(p_var.get_type() == Variant::VECTOR2 ? Variant::FLOAT : Variant::INT);
+ x.value = rtos(vec.x);
+ y.value = rtos(vec.y);
+
+ Array arr;
+ arr.push_back(x.to_json());
+ arr.push_back(y.to_json());
+ variable_list.insert(id, arr);
+ return id;
+ }
+ case Variant::RECT2:
+ case Variant::RECT2I: {
+ int id = variable_id++;
+ Rect2 rect = p_var;
+ DAP::Variable x, y, w, h;
+ x.name = "x";
+ y.name = "y";
+ w.name = "w";
+ h.name = "h";
+ x.type = y.type = w.type = h.type = Variant::get_type_name(p_var.get_type() == Variant::RECT2 ? Variant::FLOAT : Variant::INT);
+ x.value = rtos(rect.position.x);
+ y.value = rtos(rect.position.y);
+ w.value = rtos(rect.size.x);
+ h.value = rtos(rect.size.y);
+
+ Array arr;
+ arr.push_back(x.to_json());
+ arr.push_back(y.to_json());
+ arr.push_back(w.to_json());
+ arr.push_back(h.to_json());
+ variable_list.insert(id, arr);
+ return id;
+ }
+ case Variant::VECTOR3:
+ case Variant::VECTOR3I: {
+ int id = variable_id++;
+ Vector3 vec = p_var;
+ DAP::Variable x, y, z;
+ x.name = "x";
+ y.name = "y";
+ z.name = "z";
+ x.type = y.type = z.type = Variant::get_type_name(p_var.get_type() == Variant::VECTOR3 ? Variant::FLOAT : Variant::INT);
+ x.value = rtos(vec.x);
+ y.value = rtos(vec.y);
+ z.value = rtos(vec.z);
+
+ Array arr;
+ arr.push_back(x.to_json());
+ arr.push_back(y.to_json());
+ arr.push_back(z.to_json());
+ variable_list.insert(id, arr);
+ return id;
+ }
+ case Variant::TRANSFORM2D: {
+ int id = variable_id++;
+ Transform2D transform = p_var;
+ DAP::Variable x, y, origin;
+ x.name = "x";
+ y.name = "y";
+ origin.name = "origin";
+ x.type = y.type = origin.type = Variant::get_type_name(Variant::VECTOR2);
+ x.value = transform.elements[0];
+ y.value = transform.elements[1];
+ origin.value = transform.elements[2];
+ x.variablesReference = parse_variant(transform.elements[0]);
+ y.variablesReference = parse_variant(transform.elements[1]);
+ origin.variablesReference = parse_variant(transform.elements[2]);
+
+ Array arr;
+ arr.push_back(x.to_json());
+ arr.push_back(y.to_json());
+ arr.push_back(origin.to_json());
+ variable_list.insert(id, arr);
+ return id;
+ }
+ case Variant::PLANE: {
+ int id = variable_id++;
+ Plane plane = p_var;
+ DAP::Variable d, normal;
+ d.name = "d";
+ normal.name = "normal";
+ d.type = Variant::get_type_name(Variant::FLOAT);
+ normal.type = Variant::get_type_name(Variant::VECTOR3);
+ d.value = rtos(plane.d);
+ normal.value = plane.normal;
+ normal.variablesReference = parse_variant(plane.normal);
+
+ Array arr;
+ arr.push_back(d.to_json());
+ arr.push_back(normal.to_json());
+ variable_list.insert(id, arr);
+ return id;
+ }
+ case Variant::QUATERNION: {
+ int id = variable_id++;
+ Quaternion quat = p_var;
+ DAP::Variable x, y, z, w;
+ x.name = "x";
+ y.name = "y";
+ z.name = "z";
+ w.name = "w";
+ x.type = y.type = z.type = w.type = Variant::get_type_name(Variant::FLOAT);
+ x.value = rtos(quat.x);
+ y.value = rtos(quat.y);
+ z.value = rtos(quat.z);
+ w.value = rtos(quat.w);
+
+ Array arr;
+ arr.push_back(x.to_json());
+ arr.push_back(y.to_json());
+ arr.push_back(z.to_json());
+ arr.push_back(w.to_json());
+ variable_list.insert(id, arr);
+ return id;
+ }
+ case Variant::AABB: {
+ int id = variable_id++;
+ AABB aabb = p_var;
+ DAP::Variable position, size;
+ position.name = "position";
+ size.name = "size";
+ position.type = size.type = Variant::get_type_name(Variant::VECTOR3);
+ position.value = aabb.position;
+ size.value = aabb.size;
+ position.variablesReference = parse_variant(aabb.position);
+ size.variablesReference = parse_variant(aabb.size);
+
+ Array arr;
+ arr.push_back(position.to_json());
+ arr.push_back(size.to_json());
+ variable_list.insert(id, arr);
+ return id;
+ }
+ case Variant::BASIS: {
+ int id = variable_id++;
+ Basis basis = p_var;
+ DAP::Variable x, y, z;
+ x.name = "x";
+ y.name = "y";
+ z.name = "z";
+ x.type = y.type = z.type = Variant::get_type_name(Variant::VECTOR2);
+ x.value = basis.elements[0];
+ y.value = basis.elements[1];
+ z.value = basis.elements[2];
+ x.variablesReference = parse_variant(basis.elements[0]);
+ y.variablesReference = parse_variant(basis.elements[1]);
+ z.variablesReference = parse_variant(basis.elements[2]);
+
+ Array arr;
+ arr.push_back(x.to_json());
+ arr.push_back(y.to_json());
+ arr.push_back(z.to_json());
+ variable_list.insert(id, arr);
+ return id;
+ }
+ case Variant::TRANSFORM3D: {
+ int id = variable_id++;
+ Transform3D transform = p_var;
+ DAP::Variable basis, origin;
+ basis.name = "basis";
+ origin.name = "origin";
+ basis.type = Variant::get_type_name(Variant::BASIS);
+ origin.type = Variant::get_type_name(Variant::VECTOR3);
+ basis.value = transform.basis;
+ origin.value = transform.origin;
+ basis.variablesReference = parse_variant(transform.basis);
+ origin.variablesReference = parse_variant(transform.origin);
+
+ Array arr;
+ arr.push_back(basis.to_json());
+ arr.push_back(origin.to_json());
+ variable_list.insert(id, arr);
+ return id;
+ }
+ case Variant::COLOR: {
+ int id = variable_id++;
+ Color color = p_var;
+ DAP::Variable r, g, b, a;
+ r.name = "r";
+ g.name = "g";
+ b.name = "b";
+ a.name = "a";
+ r.type = g.type = b.type = a.type = Variant::get_type_name(Variant::FLOAT);
+ r.value = rtos(color.r);
+ g.value = rtos(color.g);
+ b.value = rtos(color.b);
+ a.value = rtos(color.a);
+
+ Array arr;
+ arr.push_back(r.to_json());
+ arr.push_back(g.to_json());
+ arr.push_back(b.to_json());
+ arr.push_back(a.to_json());
+ variable_list.insert(id, arr);
+ return id;
+ }
+ case Variant::ARRAY: {
+ int id = variable_id++;
+ Array array = p_var;
+ DAP::Variable size;
+ size.name = "size";
+ size.type = Variant::get_type_name(Variant::INT);
+ size.value = itos(array.size());
+
+ Array arr;
+ arr.push_back(size.to_json());
+
+ for (int i = 0; i < array.size(); i++) {
+ DAP::Variable var;
+ var.name = itos(i);
+ var.type = Variant::get_type_name(array[i].get_type());
+ var.value = array[i];
+ var.variablesReference = parse_variant(array[i]);
+ arr.push_back(var.to_json());
+ }
+ variable_list.insert(id, arr);
+ return id;
+ }
+ case Variant::DICTIONARY: {
+ int id = variable_id++;
+ Dictionary dictionary = p_var;
+ Array arr;
+
+ for (int i = 0; i < dictionary.size(); i++) {
+ DAP::Variable var;
+ var.name = dictionary.get_key_at_index(i);
+ Variant value = dictionary.get_value_at_index(i);
+ var.type = Variant::get_type_name(value.get_type());
+ var.value = value;
+ var.variablesReference = parse_variant(value);
+ arr.push_back(var.to_json());
+ }
+ variable_list.insert(id, arr);
+ return id;
+ }
+ case Variant::PACKED_BYTE_ARRAY: {
+ int id = variable_id++;
+ PackedByteArray array = p_var;
+ DAP::Variable size;
+ size.name = "size";
+ size.type = Variant::get_type_name(Variant::INT);
+ size.value = itos(array.size());
+
+ Array arr;
+ arr.push_back(size.to_json());
+
+ for (int i = 0; i < array.size(); i++) {
+ DAP::Variable var;
+ var.name = itos(i);
+ var.type = "byte";
+ var.value = itos(array[i]);
+ arr.push_back(var.to_json());
+ }
+ variable_list.insert(id, arr);
+ return id;
+ }
+ case Variant::PACKED_INT32_ARRAY: {
+ int id = variable_id++;
+ PackedInt32Array array = p_var;
+ DAP::Variable size;
+ size.name = "size";
+ size.type = Variant::get_type_name(Variant::INT);
+ size.value = itos(array.size());
+
+ Array arr;
+ arr.push_back(size.to_json());
+
+ for (int i = 0; i < array.size(); i++) {
+ DAP::Variable var;
+ var.name = itos(i);
+ var.type = "int";
+ var.value = itos(array[i]);
+ arr.push_back(var.to_json());
+ }
+ variable_list.insert(id, arr);
+ return id;
+ }
+ case Variant::PACKED_INT64_ARRAY: {
+ int id = variable_id++;
+ PackedInt64Array array = p_var;
+ DAP::Variable size;
+ size.name = "size";
+ size.type = Variant::get_type_name(Variant::INT);
+ size.value = itos(array.size());
+
+ Array arr;
+ arr.push_back(size.to_json());
+
+ for (int i = 0; i < array.size(); i++) {
+ DAP::Variable var;
+ var.name = itos(i);
+ var.type = "long";
+ var.value = itos(array[i]);
+ arr.push_back(var.to_json());
+ }
+ variable_list.insert(id, arr);
+ return id;
+ }
+ case Variant::PACKED_FLOAT32_ARRAY: {
+ int id = variable_id++;
+ PackedFloat32Array array = p_var;
+ DAP::Variable size;
+ size.name = "size";
+ size.type = Variant::get_type_name(Variant::INT);
+ size.value = itos(array.size());
+
+ Array arr;
+ arr.push_back(size.to_json());
+
+ for (int i = 0; i < array.size(); i++) {
+ DAP::Variable var;
+ var.name = itos(i);
+ var.type = "float";
+ var.value = rtos(array[i]);
+ arr.push_back(var.to_json());
+ }
+ variable_list.insert(id, arr);
+ return id;
+ }
+ case Variant::PACKED_FLOAT64_ARRAY: {
+ int id = variable_id++;
+ PackedFloat64Array array = p_var;
+ DAP::Variable size;
+ size.name = "size";
+ size.type = Variant::get_type_name(Variant::INT);
+ size.value = itos(array.size());
+
+ Array arr;
+ arr.push_back(size.to_json());
+
+ for (int i = 0; i < array.size(); i++) {
+ DAP::Variable var;
+ var.name = itos(i);
+ var.type = "double";
+ var.value = rtos(array[i]);
+ arr.push_back(var.to_json());
+ }
+ variable_list.insert(id, arr);
+ return id;
+ }
+ case Variant::PACKED_STRING_ARRAY: {
+ int id = variable_id++;
+ PackedStringArray array = p_var;
+ DAP::Variable size;
+ size.name = "size";
+ size.type = Variant::get_type_name(Variant::INT);
+ size.value = itos(array.size());
+
+ Array arr;
+ arr.push_back(size.to_json());
+
+ for (int i = 0; i < array.size(); i++) {
+ DAP::Variable var;
+ var.name = itos(i);
+ var.type = Variant::get_type_name(Variant::STRING);
+ var.value = array[i];
+ arr.push_back(var.to_json());
+ }
+ variable_list.insert(id, arr);
+ return id;
+ }
+ case Variant::PACKED_VECTOR2_ARRAY: {
+ int id = variable_id++;
+ PackedVector2Array array = p_var;
+ DAP::Variable size;
+ size.name = "size";
+ size.type = Variant::get_type_name(Variant::INT);
+ size.value = itos(array.size());
+
+ Array arr;
+ arr.push_back(size.to_json());
+
+ for (int i = 0; i < array.size(); i++) {
+ DAP::Variable var;
+ var.name = itos(i);
+ var.type = Variant::get_type_name(Variant::VECTOR2);
+ var.value = array[i];
+ var.variablesReference = parse_variant(array[i]);
+ arr.push_back(var.to_json());
+ }
+ variable_list.insert(id, arr);
+ return id;
+ }
+ case Variant::PACKED_VECTOR3_ARRAY: {
+ int id = variable_id++;
+ PackedVector2Array array = p_var;
+ DAP::Variable size;
+ size.name = "size";
+ size.type = Variant::get_type_name(Variant::INT);
+ size.value = itos(array.size());
+
+ Array arr;
+ arr.push_back(size.to_json());
+
+ for (int i = 0; i < array.size(); i++) {
+ DAP::Variable var;
+ var.name = itos(i);
+ var.type = Variant::get_type_name(Variant::VECTOR3);
+ var.value = array[i];
+ var.variablesReference = parse_variant(array[i]);
+ arr.push_back(var.to_json());
+ }
+ variable_list.insert(id, arr);
+ return id;
+ }
+ case Variant::PACKED_COLOR_ARRAY: {
+ int id = variable_id++;
+ PackedColorArray array = p_var;
+ DAP::Variable size;
+ size.name = "size";
+ size.type = Variant::get_type_name(Variant::INT);
+ size.value = itos(array.size());
+
+ Array arr;
+ arr.push_back(size.to_json());
+
+ for (int i = 0; i < array.size(); i++) {
+ DAP::Variable var;
+ var.name = itos(i);
+ var.type = Variant::get_type_name(Variant::COLOR);
+ var.value = array[i];
+ var.variablesReference = parse_variant(array[i]);
+ arr.push_back(var.to_json());
+ }
+ variable_list.insert(id, arr);
+ return id;
+ }
+ default:
+ // Simple atomic stuff, or too complex to be manipulated
+ return 0;
+ }
+}
+
bool DebugAdapterProtocol::process_message(const String &p_text) {
JSON json;
ERR_FAIL_COND_V_MSG(json.parse(p_text) != OK, true, "Mal-formed message!");
Dictionary params = json.get_data();
bool completed = true;
+ if (OS::get_singleton()->get_ticks_msec() - _current_peer->timestamp > _request_timeout) {
+ Dictionary response = parser->prepare_error_response(params, DAP::ErrorType::TIMEOUT);
+ _current_peer->res_queue.push_front(response);
+ return true;
+ }
+
// Append "req_" to any command received; prevents name clash with existing functions, and possibly exploiting
String command = "req_" + (String)params["command"];
if (parser->has_method(command)) {
@@ -211,7 +665,7 @@ void DebugAdapterProtocol::notify_initialized() {
}
void DebugAdapterProtocol::notify_process() {
- String launch_mode = _current_request.is_empty() ? "launch" : _current_request;
+ String launch_mode = _current_peer->attached ? "attach" : "launch";
Dictionary event = parser->ev_process(launch_mode);
for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
@@ -222,7 +676,7 @@ void DebugAdapterProtocol::notify_process() {
void DebugAdapterProtocol::notify_terminated() {
Dictionary event = parser->ev_terminated();
for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
- if (_current_request == "launch" && _current_peer == E->get()) {
+ if ((_current_request == "launch" || _current_request == "restart") && _current_peer == E->get()) {
continue;
}
E->get()->res_queue.push_back(event);
@@ -232,7 +686,7 @@ void DebugAdapterProtocol::notify_terminated() {
void DebugAdapterProtocol::notify_exited(const int &p_exitcode) {
Dictionary event = parser->ev_exited(p_exitcode);
for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
- if (_current_request == "launch" && _current_peer == E->get()) {
+ if ((_current_request == "launch" || _current_request == "restart") && _current_peer == E->get()) {
continue;
}
E->get()->res_queue.push_back(event);
@@ -286,25 +740,46 @@ void DebugAdapterProtocol::notify_output(const String &p_message) {
}
}
+void DebugAdapterProtocol::notify_custom_data(const String &p_msg, const Array &p_data) {
+ Dictionary event = parser->ev_custom_data(p_msg, p_data);
+ for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
+ Ref<DAPeer> peer = E->get();
+ if (peer->supportsCustomData) {
+ peer->res_queue.push_back(event);
+ }
+ }
+}
+
+void DebugAdapterProtocol::notify_breakpoint(const DAP::Breakpoint &p_breakpoint, const bool &p_enabled) {
+ Dictionary event = parser->ev_breakpoint(p_breakpoint, p_enabled);
+ for (List<Ref<DAPeer>>::Element *E = clients.front(); E; E = E->next()) {
+ if (_current_request == "setBreakpoints" && E->get() == _current_peer) {
+ continue;
+ }
+ E->get()->res_queue.push_back(event);
+ }
+}
+
Array DebugAdapterProtocol::update_breakpoints(const String &p_path, const Array &p_lines) {
Array updated_breakpoints;
+ // Add breakpoints
for (int i = 0; i < p_lines.size(); i++) {
+ EditorDebuggerNode::get_singleton()->get_default_debugger()->_set_breakpoint(p_path, p_lines[i], true);
DAP::Breakpoint breakpoint;
- breakpoint.verified = true;
- breakpoint.source.path = p_path;
- breakpoint.source.compute_checksums();
breakpoint.line = p_lines[i];
+ breakpoint.source.path = p_path;
- List<DAP::Breakpoint>::Element *E = breakpoint_list.find(breakpoint);
- if (E) {
- breakpoint.id = E->get().id;
- } else {
- breakpoint.id = breakpoint_id++;
- breakpoint_list.push_back(breakpoint);
- }
+ ERR_FAIL_COND_V(!breakpoint_list.find(breakpoint), Array());
+ updated_breakpoints.push_back(breakpoint_list.find(breakpoint)->get().to_json());
+ }
- updated_breakpoints.push_back(breakpoint.to_json());
+ // Remove breakpoints
+ for (List<DAP::Breakpoint>::Element *E = breakpoint_list.front(); E; E = E->next()) {
+ DAP::Breakpoint b = E->get();
+ if (b.source.path == p_path && !p_lines.has(b.line)) {
+ EditorDebuggerNode::get_singleton()->get_default_debugger()->_set_breakpoint(p_path, b.line, false);
+ }
}
return updated_breakpoints;
@@ -347,6 +822,29 @@ void DebugAdapterProtocol::on_debug_breaked(const bool &p_reallydid, const bool
_processing_stackdump = p_has_stackdump;
}
+void DebugAdapterProtocol::on_debug_breakpoint_toggled(const String &p_path, const int &p_line, const bool &p_enabled) {
+ DAP::Breakpoint breakpoint;
+ breakpoint.verified = true;
+ breakpoint.source.path = ProjectSettings::get_singleton()->globalize_path(p_path);
+ breakpoint.source.compute_checksums();
+ breakpoint.line = p_line;
+
+ if (p_enabled) {
+ // Add the breakpoint
+ breakpoint.id = breakpoint_id++;
+ breakpoint_list.push_back(breakpoint);
+ } else {
+ // Remove the breakpoint
+ List<DAP::Breakpoint>::Element *E = breakpoint_list.find(breakpoint);
+ if (E) {
+ breakpoint.id = E->get().id;
+ breakpoint_list.erase(E);
+ }
+ }
+
+ notify_breakpoint(breakpoint, p_enabled);
+}
+
void DebugAdapterProtocol::on_debug_stack_dump(const Array &p_stack_dump) {
if (_processing_breakpoint && !p_stack_dump.is_empty()) {
// Find existing breakpoint
@@ -424,11 +922,21 @@ void DebugAdapterProtocol::on_debug_stack_frame_var(const Array &p_data) {
variable.name = stack_var.name;
variable.value = stack_var.value;
variable.type = Variant::get_type_name(stack_var.value.get_type());
+ variable.variablesReference = parse_variant(stack_var.value);
variable_list.find(variable_id)->value().push_back(variable.to_json());
_remaining_vars--;
}
+void DebugAdapterProtocol::on_debug_data(const String &p_msg, const Array &p_data) {
+ // Ignore data that is already handled by DAP
+ if (p_msg == "debug_enter" || p_msg == "debug_exit" || p_msg == "stack_dump" || p_msg == "stack_frame_vars" || p_msg == "stack_frame_var" || p_msg == "output" || p_msg == "request_quit") {
+ return;
+ }
+
+ notify_custom_data(p_msg, p_data);
+}
+
void DebugAdapterProtocol::poll() {
if (server->is_connection_available()) {
on_client_connected();
@@ -459,6 +967,8 @@ void DebugAdapterProtocol::poll() {
}
Error DebugAdapterProtocol::start(int p_port, const IPAddress &p_bind_ip) {
+ _request_timeout = (uint64_t)_EDITOR_GET("network/debug_adapter/request_timeout");
+ _sync_breakpoints = (bool)_EDITOR_GET("network/debug_adapter/sync_breakpoints");
_initialized = true;
return server->listen(p_port, p_bind_ip);
}
@@ -484,12 +994,15 @@ DebugAdapterProtocol::DebugAdapterProtocol() {
node->get_pause_button()->connect("pressed", callable_mp(this, &DebugAdapterProtocol::on_debug_paused));
EditorDebuggerNode *debugger_node = EditorDebuggerNode::get_singleton();
+ debugger_node->connect("breakpoint_toggled", callable_mp(this, &DebugAdapterProtocol::on_debug_breakpoint_toggled));
+
debugger_node->get_default_debugger()->connect("stopped", callable_mp(this, &DebugAdapterProtocol::on_debug_stopped));
debugger_node->get_default_debugger()->connect("output", callable_mp(this, &DebugAdapterProtocol::on_debug_output));
debugger_node->get_default_debugger()->connect("breaked", callable_mp(this, &DebugAdapterProtocol::on_debug_breaked));
debugger_node->get_default_debugger()->connect("stack_dump", callable_mp(this, &DebugAdapterProtocol::on_debug_stack_dump));
debugger_node->get_default_debugger()->connect("stack_frame_vars", callable_mp(this, &DebugAdapterProtocol::on_debug_stack_frame_vars));
debugger_node->get_default_debugger()->connect("stack_frame_var", callable_mp(this, &DebugAdapterProtocol::on_debug_stack_frame_var));
+ debugger_node->get_default_debugger()->connect("debug_data", callable_mp(this, &DebugAdapterProtocol::on_debug_data));
}
DebugAdapterProtocol::~DebugAdapterProtocol() {
diff --git a/editor/debugger/debug_adapter/debug_adapter_protocol.h b/editor/debugger/debug_adapter/debug_adapter_protocol.h
index 6b542033ed..d4291992bf 100644
--- a/editor/debugger/debug_adapter/debug_adapter_protocol.h
+++ b/editor/debugger/debug_adapter/debug_adapter_protocol.h
@@ -52,12 +52,17 @@ struct DAPeer : RefCounted {
int content_length = 0;
List<Dictionary> res_queue;
int seq = 0;
+ uint64_t timestamp = 0;
// Client specific info
bool linesStartAt1 = false;
bool columnsStartAt1 = false;
bool supportsVariableType = false;
bool supportsInvalidatedEvent = false;
+ bool supportsCustomData = false;
+
+ // Internal client info
+ bool attached = false;
Error handle_data();
Error send_data();
@@ -82,20 +87,26 @@ private:
void on_debug_stopped();
void on_debug_output(const String &p_message);
void on_debug_breaked(const bool &p_reallydid, const bool &p_can_debug, const String &p_reason, const bool &p_has_stackdump);
+ void on_debug_breakpoint_toggled(const String &p_path, const int &p_line, const bool &p_enabled);
void on_debug_stack_dump(const Array &p_stack_dump);
void on_debug_stack_frame_vars(const int &p_size);
void on_debug_stack_frame_var(const Array &p_data);
+ void on_debug_data(const String &p_msg, const Array &p_data);
void reset_current_info();
void reset_ids();
void reset_stack_info();
+ int parse_variant(const Variant &p_var);
+
bool _initialized = false;
bool _processing_breakpoint = false;
bool _stepping = false;
bool _processing_stackdump = false;
int _remaining_vars = 0;
int _current_frame = 0;
+ uint64_t _request_timeout = 1000;
+ bool _sync_breakpoints = false;
String _current_request;
Ref<DAPeer> _current_peer;
@@ -108,6 +119,8 @@ private:
Map<int, Array> variable_list;
public:
+ friend class DebugAdapterServer;
+
_FORCE_INLINE_ static DebugAdapterProtocol *get_singleton() { return singleton; }
_FORCE_INLINE_ bool is_active() const { return _initialized && clients.size() > 0; }
@@ -126,8 +139,10 @@ public:
void notify_stopped_step();
void notify_continued();
void notify_output(const String &p_message);
+ void notify_custom_data(const String &p_msg, const Array &p_data);
+ void notify_breakpoint(const DAP::Breakpoint &p_breakpoint, const bool &p_enabled);
- Array update_breakpoints(const String &p_path, const Array &p_breakpoints);
+ Array update_breakpoints(const String &p_path, const Array &p_lines);
void poll();
Error start(int p_port, const IPAddress &p_bind_ip);
diff --git a/editor/debugger/debug_adapter/debug_adapter_server.cpp b/editor/debugger/debug_adapter/debug_adapter_server.cpp
index f9092a1791..4775e2c8b0 100644
--- a/editor/debugger/debug_adapter/debug_adapter_server.cpp
+++ b/editor/debugger/debug_adapter/debug_adapter_server.cpp
@@ -36,7 +36,8 @@
DebugAdapterServer::DebugAdapterServer() {
_EDITOR_DEF("network/debug_adapter/remote_port", remote_port);
- _EDITOR_DEF("network/debug_adapter/use_thread", use_thread);
+ _EDITOR_DEF("network/debug_adapter/request_timeout", protocol._request_timeout);
+ _EDITOR_DEF("network/debug_adapter/sync_breakpoints", protocol._sync_breakpoints);
}
void DebugAdapterServer::_notification(int p_what) {
@@ -50,16 +51,17 @@ void DebugAdapterServer::_notification(int p_what) {
case NOTIFICATION_INTERNAL_PROCESS: {
// The main loop can be run again during request processing, which modifies internal state of the protocol.
// Thus, "polling" is needed to prevent it from parsing other requests while the current one isn't finished.
- if (started && !use_thread && !polling) {
+ if (started && !polling) {
polling = true;
protocol.poll();
polling = false;
}
} break;
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
+ protocol._request_timeout = EditorSettings::get_singleton()->get("network/debug_adapter/request_timeout");
+ protocol._sync_breakpoints = EditorSettings::get_singleton()->get("network/debug_adapter/sync_breakpoints");
int remote_port = (int)_EDITOR_GET("network/debug_adapter/remote_port");
- bool use_thread = (bool)_EDITOR_GET("network/debug_adapter/use_thread");
- if (remote_port != this->remote_port || use_thread != this->use_thread) {
+ if (remote_port != this->remote_port) {
this->stop();
this->start();
}
@@ -67,35 +69,16 @@ void DebugAdapterServer::_notification(int p_what) {
}
}
-void DebugAdapterServer::thread_func(void *p_userdata) {
- DebugAdapterServer *self = static_cast<DebugAdapterServer *>(p_userdata);
- while (self->thread_running) {
- // Poll 20 times per second
- self->protocol.poll();
- OS::get_singleton()->delay_usec(50000);
- }
-}
-
void DebugAdapterServer::start() {
remote_port = (int)_EDITOR_GET("network/debug_adapter/remote_port");
- use_thread = (bool)_EDITOR_GET("network/debug_adapter/use_thread");
if (protocol.start(remote_port, IPAddress("127.0.0.1")) == OK) {
EditorNode::get_log()->add_message("--- Debug adapter server started ---", EditorLog::MSG_TYPE_EDITOR);
- if (use_thread) {
- thread_running = true;
- thread.start(DebugAdapterServer::thread_func, this);
- }
- set_process_internal(!use_thread);
+ set_process_internal(true);
started = true;
}
}
void DebugAdapterServer::stop() {
- if (use_thread) {
- ERR_FAIL_COND(!thread.is_started());
- thread_running = false;
- thread.wait_to_finish();
- }
protocol.stop();
started = false;
EditorNode::get_log()->add_message("--- Debug adapter server stopped ---", EditorLog::MSG_TYPE_EDITOR);
diff --git a/editor/debugger/debug_adapter/debug_adapter_server.h b/editor/debugger/debug_adapter/debug_adapter_server.h
index f8a38965cc..c449403cc2 100644
--- a/editor/debugger/debug_adapter/debug_adapter_server.h
+++ b/editor/debugger/debug_adapter/debug_adapter_server.h
@@ -39,11 +39,9 @@ class DebugAdapterServer : public EditorPlugin {
DebugAdapterProtocol protocol;
- Thread thread;
int remote_port = 6006;
bool thread_running = false;
bool started = false;
- bool use_thread = false;
bool polling = false;
static void thread_func(void *p_userdata);
diff --git a/editor/debugger/debug_adapter/debug_adapter_types.h b/editor/debugger/debug_adapter/debug_adapter_types.h
index aa9ab1adcd..5156c91d14 100644
--- a/editor/debugger/debug_adapter/debug_adapter_types.h
+++ b/editor/debugger/debug_adapter/debug_adapter_types.h
@@ -38,7 +38,11 @@ namespace DAP {
enum ErrorType {
UNKNOWN,
- WRONG_PATH
+ WRONG_PATH,
+ NOT_RUNNING,
+ TIMEOUT,
+ UNKNOWN_PLATFORM,
+ MISSING_DEVICE
};
struct Checksum {
@@ -118,10 +122,14 @@ struct Breakpoint {
struct BreakpointLocation {
int line;
+ int endLine = -1;
_FORCE_INLINE_ Dictionary to_json() const {
Dictionary dict;
dict["line"] = line;
+ if (endLine >= 0) {
+ dict["endLine"] = endLine;
+ }
return dict;
}
diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp
index a9cb1a0131..07c02eb022 100644
--- a/editor/debugger/editor_debugger_node.cpp
+++ b/editor/debugger/editor_debugger_node.cpp
@@ -164,6 +164,7 @@ void EditorDebuggerNode::_bind_methods() {
ADD_SIGNAL(MethodInfo("set_execution", PropertyInfo("script"), PropertyInfo(Variant::INT, "line")));
ADD_SIGNAL(MethodInfo("clear_execution", PropertyInfo("script")));
ADD_SIGNAL(MethodInfo("breaked", PropertyInfo(Variant::BOOL, "reallydid"), PropertyInfo(Variant::BOOL, "can_debug")));
+ ADD_SIGNAL(MethodInfo("breakpoint_toggled", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "line"), PropertyInfo(Variant::BOOL, "enabled")));
}
EditorDebuggerRemoteObject *EditorDebuggerNode::get_inspected_remote_object() {
@@ -487,6 +488,8 @@ void EditorDebuggerNode::set_breakpoint(const String &p_path, int p_line, bool p
_for_all(tabs, [&](ScriptEditorDebugger *dbg) {
dbg->set_breakpoint(p_path, p_line, p_enabled);
});
+
+ emit_signal("breakpoint_toggled", p_path, p_line, p_enabled);
}
void EditorDebuggerNode::set_breakpoints(const String &p_path, Array p_lines) {
diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp
index 2a5013893f..2f5bde64a9 100644
--- a/editor/debugger/script_editor_debugger.cpp
+++ b/editor/debugger/script_editor_debugger.cpp
@@ -296,6 +296,7 @@ Size2 ScriptEditorDebugger::get_minimum_size() const {
}
void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_data) {
+ emit_signal(SNAME("debug_data"), p_msg, p_data);
if (p_msg == "debug_enter") {
_put_msg("get_stack_dump", Array());
@@ -872,6 +873,16 @@ void ScriptEditorDebugger::_clear_execution() {
inspector->clear_stack_variables();
}
+void ScriptEditorDebugger::_set_breakpoint(const String &p_file, const int &p_line, const bool &p_enabled) {
+ Ref<Script> script = ResourceLoader::load(p_file);
+ emit_signal("set_breakpoint", script, p_line - 1, p_enabled);
+ script.unref();
+}
+
+void ScriptEditorDebugger::_clear_breakpoints() {
+ emit_signal("clear_breakpoints");
+}
+
void ScriptEditorDebugger::start(Ref<RemoteDebuggerPeer> p_peer) {
error_count = 0;
warning_count = 0;
@@ -1503,6 +1514,9 @@ void ScriptEditorDebugger::_bind_methods() {
ADD_SIGNAL(MethodInfo("stack_dump", PropertyInfo(Variant::ARRAY, "stack_dump")));
ADD_SIGNAL(MethodInfo("stack_frame_vars", PropertyInfo(Variant::INT, "num_vars")));
ADD_SIGNAL(MethodInfo("stack_frame_var", PropertyInfo(Variant::ARRAY, "data")));
+ ADD_SIGNAL(MethodInfo("debug_data", PropertyInfo(Variant::STRING, "msg"), PropertyInfo(Variant::ARRAY, "data")));
+ ADD_SIGNAL(MethodInfo("set_breakpoint", PropertyInfo("script"), PropertyInfo(Variant::INT, "line"), PropertyInfo(Variant::BOOL, "enabled")));
+ ADD_SIGNAL(MethodInfo("clear_breakpoints"));
}
void ScriptEditorDebugger::add_debugger_plugin(const Ref<Script> &p_script) {
diff --git a/editor/debugger/script_editor_debugger.h b/editor/debugger/script_editor_debugger.h
index 499dda86da..1c1c0fd3e5 100644
--- a/editor/debugger/script_editor_debugger.h
+++ b/editor/debugger/script_editor_debugger.h
@@ -205,6 +205,9 @@ private:
void _clear_execution();
void _stop_and_notify();
+ void _set_breakpoint(const String &p_path, const int &p_line, const bool &p_enabled);
+ void _clear_breakpoints();
+
protected:
void _notification(int p_what);
static void _bind_methods();
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 5f029e53c9..f86a36df2f 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -4764,6 +4764,10 @@ bool EditorNode::ensure_main_scene(bool p_from_native) {
return true;
}
+Error EditorNode::run_play_native(int p_idx, int p_platform) {
+ return run_native->run_native(p_idx, p_platform);
+}
+
void EditorNode::run_play() {
_menu_option_confirm(RUN_STOP, true);
_run(false);
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 51d01d07ef..03c18a8972 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -898,6 +898,7 @@ public:
bool ensure_main_scene(bool p_from_native);
+ Error run_play_native(int p_idx, int p_platform);
void run_play();
void run_play_current();
void run_play_custom(const String &p_custom);
diff --git a/editor/editor_run_native.cpp b/editor/editor_run_native.cpp
index e115cd77e1..5828549bdc 100644
--- a/editor/editor_run_native.cpp
+++ b/editor/editor_run_native.cpp
@@ -52,8 +52,8 @@ void EditorRunNative::_notification(int p_what) {
small_icon.instantiate();
small_icon->create_from_image(im);
MenuButton *mb = memnew(MenuButton);
- mb->get_popup()->connect("id_pressed", callable_mp(this, &EditorRunNative::_run_native), varray(i));
- mb->connect("pressed", callable_mp(this, &EditorRunNative::_run_native), varray(-1, i));
+ mb->get_popup()->connect("id_pressed", callable_mp(this, &EditorRunNative::run_native), varray(i));
+ mb->connect("pressed", callable_mp(this, &EditorRunNative::run_native), varray(-1, i));
mb->set_icon(small_icon);
add_child(mb);
menus[i] = mb;
@@ -93,22 +93,22 @@ void EditorRunNative::_notification(int p_what) {
}
}
-void EditorRunNative::_run_native(int p_idx, int p_platform) {
+Error EditorRunNative::run_native(int p_idx, int p_platform) {
if (!EditorNode::get_singleton()->ensure_main_scene(true)) {
resume_idx = p_idx;
resume_platform = p_platform;
- return;
+ return OK;
}
Ref<EditorExportPlatform> eep = EditorExport::get_singleton()->get_export_platform(p_platform);
- ERR_FAIL_COND(eep.is_null());
+ ERR_FAIL_COND_V(eep.is_null(), ERR_UNAVAILABLE);
if (p_idx == -1) {
if (eep->get_options_count() == 1) {
menus[p_platform]->get_popup()->hide();
p_idx = 0;
} else {
- return;
+ return ERR_INVALID_PARAMETER;
}
}
@@ -124,7 +124,7 @@ void EditorRunNative::_run_native(int p_idx, int p_platform) {
if (preset.is_null()) {
EditorNode::get_singleton()->show_warning(TTR("No runnable export preset found for this platform.\nPlease add a runnable preset in the Export menu or define an existing preset as runnable."));
- return;
+ return ERR_UNAVAILABLE;
}
emit_signal(SNAME("native_run"), preset);
@@ -149,11 +149,11 @@ void EditorRunNative::_run_native(int p_idx, int p_platform) {
flags |= EditorExportPlatform::DEBUG_FLAG_VIEW_NAVIGATION;
}
- eep->run(preset, p_idx, flags);
+ return eep->run(preset, p_idx, flags);
}
void EditorRunNative::resume_run_native() {
- _run_native(resume_idx, resume_platform);
+ run_native(resume_idx, resume_platform);
}
void EditorRunNative::_bind_methods() {
diff --git a/editor/editor_run_native.h b/editor/editor_run_native.h
index 3516f668c6..97f6fc005a 100644
--- a/editor/editor_run_native.h
+++ b/editor/editor_run_native.h
@@ -43,13 +43,12 @@ class EditorRunNative : public HBoxContainer {
int resume_idx;
int resume_platform;
- void _run_native(int p_idx, int p_platform);
-
protected:
static void _bind_methods();
void _notification(int p_what);
public:
+ Error run_native(int p_idx, int p_platform);
bool is_deploy_debug_remote_enabled() const;
void resume_run_native();
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index 8c348731d6..32ec49e11e 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -1201,11 +1201,11 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// TooltipPanel
Ref<StyleBoxFlat> style_tooltip = style_popup->duplicate();
style_tooltip->set_shadow_size(0);
- style_tooltip->set_default_margin(SIDE_LEFT, default_margin_size * EDSCALE);
+ style_tooltip->set_default_margin(SIDE_LEFT, default_margin_size * EDSCALE * 0.5);
style_tooltip->set_default_margin(SIDE_TOP, default_margin_size * EDSCALE * 0.5);
- style_tooltip->set_default_margin(SIDE_RIGHT, default_margin_size * EDSCALE);
+ style_tooltip->set_default_margin(SIDE_RIGHT, default_margin_size * EDSCALE * 0.5);
style_tooltip->set_default_margin(SIDE_BOTTOM, default_margin_size * EDSCALE * 0.5);
- style_tooltip->set_bg_color(mono_color.inverted() * Color(1, 1, 1, 0.9));
+ style_tooltip->set_bg_color(dark_color_3 * Color(0.8, 0.8, 0.8, 0.9));
style_tooltip->set_border_width_all(0);
theme->set_color("font_color", "TooltipLabel", font_hover_color);
theme->set_color("font_color_shadow", "TooltipLabel", Color(0, 0, 0, 0));
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index a24249b95b..7ef5993ec5 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -37,6 +37,7 @@
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "editor/debugger/editor_debugger_node.h"
+#include "editor/debugger/script_editor_debugger.h"
#include "editor/editor_node.h"
#include "editor/editor_run_script.h"
#include "editor/editor_scale.h"
@@ -479,6 +480,29 @@ void ScriptEditor::_clear_execution(REF p_script) {
}
}
+void ScriptEditor::_set_breakpoint(REF p_script, int p_line, bool p_enabled) {
+ Ref<Script> script = Object::cast_to<Script>(*p_script);
+ if (script.is_valid() && (script->has_source_code() || script->get_path().is_resource_file())) {
+ if (edit(p_script, p_line, 0, false)) {
+ editor->push_item(p_script.ptr());
+
+ ScriptEditorBase *se = _get_current_editor();
+ if (se) {
+ se->set_breakpoint(p_line, p_enabled);
+ }
+ }
+ }
+}
+
+void ScriptEditor::_clear_breakpoints() {
+ for (int i = 0; i < tab_container->get_child_count(); i++) {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+ if (se) {
+ se->clear_breakpoints();
+ }
+ }
+}
+
ScriptEditorBase *ScriptEditor::_get_current_editor() const {
int selected = tab_container->get_current_tab();
if (selected < 0 || selected >= tab_container->get_child_count()) {
@@ -3484,6 +3508,8 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
debugger->connect("set_execution", callable_mp(this, &ScriptEditor::_set_execution));
debugger->connect("clear_execution", callable_mp(this, &ScriptEditor::_clear_execution));
debugger->connect("breaked", callable_mp(this, &ScriptEditor::_breaked));
+ debugger->get_default_debugger()->connect("set_breakpoint", callable_mp(this, &ScriptEditor::_set_breakpoint));
+ debugger->get_default_debugger()->connect("clear_breakpoints", callable_mp(this, &ScriptEditor::_clear_breakpoints));
menu_hb->add_spacer();
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index a57aeea5c0..e2420b4623 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -155,6 +155,8 @@ public:
virtual void tag_saved_version() = 0;
virtual void reload(bool p_soft) {}
virtual Array get_breakpoints() = 0;
+ virtual void set_breakpoint(int p_line, bool p_enabled) = 0;
+ virtual void clear_breakpoints() = 0;
virtual void add_callback(const String &p_function, PackedStringArray p_args) = 0;
virtual void update_settings() = 0;
virtual void set_debugger_active(bool p_active) = 0;
@@ -374,6 +376,8 @@ class ScriptEditor : public PanelContainer {
void _breaked(bool p_breaked, bool p_can_debug);
void _update_window_menu();
void _script_created(Ref<Script> p_script);
+ void _set_breakpoint(REF p_scrpt, int p_line, bool p_enabled);
+ void _clear_breakpoints();
ScriptEditorBase *_get_current_editor() const;
Array _get_open_script_editors() const;
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index b7d5403919..c44760807f 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -1370,6 +1370,14 @@ Array ScriptTextEditor::get_breakpoints() {
return code_editor->get_text_editor()->get_breakpointed_lines();
}
+void ScriptTextEditor::set_breakpoint(int p_line, bool p_enabled) {
+ code_editor->get_text_editor()->set_line_as_breakpoint(p_line, p_enabled);
+}
+
+void ScriptTextEditor::clear_breakpoints() {
+ code_editor->get_text_editor()->clear_breakpointed_lines();
+}
+
void ScriptTextEditor::set_tooltip_request_func(String p_method, Object *p_obj) {
code_editor->get_text_editor()->set_tooltip_request_func(p_obj, p_method, this);
}
diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h
index 1ca6f56ea1..4208d67f17 100644
--- a/editor/plugins/script_text_editor.h
+++ b/editor/plugins/script_text_editor.h
@@ -225,6 +225,8 @@ public:
virtual void reload(bool p_soft) override;
virtual Array get_breakpoints() override;
+ virtual void set_breakpoint(int p_line, bool p_enabled) override;
+ virtual void clear_breakpoints() override;
virtual void add_callback(const String &p_function, PackedStringArray p_args) override;
virtual void update_settings() override;
diff --git a/editor/plugins/text_editor.h b/editor/plugins/text_editor.h
index 839e1c5f7a..6bf0042393 100644
--- a/editor/plugins/text_editor.h
+++ b/editor/plugins/text_editor.h
@@ -121,6 +121,8 @@ public:
virtual void set_edit_state(const Variant &p_state) override;
virtual Vector<String> get_functions() override;
virtual Array get_breakpoints() override;
+ virtual void set_breakpoint(int p_line, bool p_enabled) override{};
+ virtual void clear_breakpoints() override{};
virtual void goto_line(int p_line, bool p_with_error = false) override;
void goto_line_selection(int p_line, int p_begin, int p_end);
virtual void set_executing_line(int p_line) override;
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 6f76ca05dc..a0cf41d5a3 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -132,6 +132,76 @@ static GDScriptParser::DataType make_builtin_meta_type(Variant::Type p_type) {
return type;
}
+bool GDScriptAnalyzer::has_member_name_conflict_in_script_class(const StringName &p_member_name, const GDScriptParser::ClassNode *p_class) {
+ if (p_class->members_indices.has(p_member_name)) {
+ int index = p_class->members_indices[p_member_name];
+ const GDScriptParser::ClassNode::Member *member = &p_class->members[index];
+
+ if (member->type == GDScriptParser::ClassNode::Member::VARIABLE ||
+ member->type == GDScriptParser::ClassNode::Member::CONSTANT ||
+ member->type == GDScriptParser::ClassNode::Member::ENUM ||
+ member->type == GDScriptParser::ClassNode::Member::ENUM_VALUE ||
+ member->type == GDScriptParser::ClassNode::Member::CLASS ||
+ member->type == GDScriptParser::ClassNode::Member::SIGNAL) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool GDScriptAnalyzer::has_member_name_conflict_in_native_type(const StringName &p_member_name, const StringName &p_native_type_string) {
+ if (ClassDB::has_signal(p_native_type_string, p_member_name)) {
+ return true;
+ }
+ if (ClassDB::has_property(p_native_type_string, p_member_name)) {
+ return true;
+ }
+ if (ClassDB::has_integer_constant(p_native_type_string, p_member_name)) {
+ return true;
+ }
+
+ return false;
+}
+
+Error GDScriptAnalyzer::check_native_member_name_conflict(const StringName &p_member_name, const GDScriptParser::Node *p_member_node, const StringName &p_native_type_string) {
+ if (has_member_name_conflict_in_native_type(p_member_name, p_native_type_string)) {
+ push_error(vformat(R"(Member "%s" redefined (original in native class '%s'))", p_member_name, p_native_type_string), p_member_node);
+ return ERR_PARSE_ERROR;
+ }
+
+ if (class_exists(p_member_name)) {
+ push_error(vformat(R"(The class "%s" shadows a native class.)", p_member_name), p_member_node);
+ return ERR_PARSE_ERROR;
+ }
+
+ return OK;
+}
+
+Error GDScriptAnalyzer::check_class_member_name_conflict(const GDScriptParser::ClassNode *p_class_node, const StringName &p_member_name, const GDScriptParser::Node *p_member_node) {
+ const GDScriptParser::DataType *current_data_type = &p_class_node->base_type;
+ while (current_data_type && current_data_type->kind == GDScriptParser::DataType::Kind::CLASS) {
+ GDScriptParser::ClassNode *current_class_node = current_data_type->class_type;
+ if (has_member_name_conflict_in_script_class(p_member_name, current_class_node)) {
+ push_error(vformat(R"(The member "%s" already exists in a parent class.)", p_member_name),
+ p_member_node);
+ return ERR_PARSE_ERROR;
+ }
+ current_data_type = &current_class_node->base_type;
+ }
+
+ if (current_data_type && current_data_type->kind == GDScriptParser::DataType::Kind::NATIVE) {
+ if (current_data_type->native_type != StringName("")) {
+ return check_native_member_name_conflict(
+ p_member_name,
+ p_member_node,
+ current_data_type->native_type);
+ }
+ }
+
+ return OK;
+}
+
Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class, bool p_recursive) {
if (p_class->base_type.is_set()) {
// Already resolved
@@ -525,6 +595,8 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
switch (member.type) {
case GDScriptParser::ClassNode::Member::VARIABLE: {
+ check_class_member_name_conflict(p_class, member.variable->identifier->name, member.variable);
+
GDScriptParser::DataType datatype;
datatype.kind = GDScriptParser::DataType::VARIANT;
datatype.type_source = GDScriptParser::DataType::UNDETECTED;
@@ -598,6 +670,8 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
}
} break;
case GDScriptParser::ClassNode::Member::CONSTANT: {
+ check_class_member_name_conflict(p_class, member.constant->identifier->name, member.constant);
+
reduce_expression(member.constant->initializer);
GDScriptParser::DataType specified_type;
@@ -647,6 +721,8 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
}
} break;
case GDScriptParser::ClassNode::Member::SIGNAL: {
+ check_class_member_name_conflict(p_class, member.signal->identifier->name, member.signal);
+
for (int j = 0; j < member.signal->parameters.size(); j++) {
GDScriptParser::DataType signal_type = resolve_datatype(member.signal->parameters[j]->datatype_specifier);
signal_type.is_meta_type = false;
@@ -666,6 +742,8 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
}
} break;
case GDScriptParser::ClassNode::Member::ENUM: {
+ check_class_member_name_conflict(p_class, member.m_enum->identifier->name, member.m_enum);
+
GDScriptParser::DataType enum_type;
enum_type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
enum_type.kind = GDScriptParser::DataType::ENUM;
@@ -717,6 +795,8 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
break;
case GDScriptParser::ClassNode::Member::ENUM_VALUE: {
if (member.enum_value.custom_value) {
+ check_class_member_name_conflict(p_class, member.enum_value.identifier->name, member.enum_value.custom_value);
+
current_enum = member.enum_value.parent_enum;
reduce_expression(member.enum_value.custom_value);
current_enum = nullptr;
@@ -730,6 +810,8 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
member.enum_value.resolved = true;
}
} else {
+ check_class_member_name_conflict(p_class, member.enum_value.identifier->name, member.enum_value.parent_enum);
+
if (member.enum_value.index > 0) {
member.enum_value.value = member.enum_value.parent_enum->values[member.enum_value.index - 1].value + 1;
} else {
@@ -742,7 +824,8 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
p_class->members.write[i].enum_value = member.enum_value;
} break;
case GDScriptParser::ClassNode::Member::CLASS:
- break; // Done later.
+ check_class_member_name_conflict(p_class, member.m_class->identifier->name, member.m_class);
+ break;
case GDScriptParser::ClassNode::Member::UNDEFINED:
ERR_PRINT("Trying to resolve undefined member.");
break;
diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h
index 32bf049fa1..2e17e15452 100644
--- a/modules/gdscript/gdscript_analyzer.h
+++ b/modules/gdscript/gdscript_analyzer.h
@@ -44,6 +44,12 @@ class GDScriptAnalyzer {
const GDScriptParser::EnumNode *current_enum = nullptr;
List<const GDScriptParser::LambdaNode *> lambda_stack;
+ // Tests for detecting invalid overloading of script members
+ static _FORCE_INLINE_ bool has_member_name_conflict_in_script_class(const StringName &p_name, const GDScriptParser::ClassNode *p_current_class_node);
+ static _FORCE_INLINE_ bool has_member_name_conflict_in_native_type(const StringName &p_name, const StringName &p_native_type_string);
+ Error check_native_member_name_conflict(const StringName &p_member_name, const GDScriptParser::Node *p_member_node, const StringName &p_native_type_string);
+ Error check_class_member_name_conflict(const GDScriptParser::ClassNode *p_class_node, const StringName &p_member_name, const GDScriptParser::Node *p_member_node);
+
Error resolve_inheritance(GDScriptParser::ClassNode *p_class, bool p_recursive = true);
GDScriptParser::DataType resolve_datatype(GDScriptParser::TypeNode *p_type);
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index ddf4f281b4..e5cbcc545f 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -2186,6 +2186,13 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
p_script->tool = parser->is_tool();
p_script->name = p_class->identifier ? p_class->identifier->name : "";
+ if (p_script->name != "") {
+ if (ClassDB::class_exists(p_script->name) && ClassDB::is_class_exposed(p_script->name)) {
+ _set_error("The class '" + p_script->name + "' shadows a native class", p_class);
+ return ERR_ALREADY_EXISTS;
+ }
+ }
+
Ref<GDScriptNativeClass> native;
GDScriptDataType base_type = _gdtype_from_datatype(p_class->base_type);
@@ -2337,28 +2344,6 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
const GDScriptParser::SignalNode *signal = member.signal;
StringName name = signal->identifier->name;
- GDScript *c = p_script;
-
- while (c) {
- if (c->_signals.has(name)) {
- _set_error("Signal '" + name + "' redefined (in current or parent class)", p_class);
- return ERR_ALREADY_EXISTS;
- }
-
- if (c->base.is_valid()) {
- c = c->base.ptr();
- } else {
- c = nullptr;
- }
- }
-
- if (native.is_valid()) {
- if (ClassDB::has_signal(native->get_name(), name)) {
- _set_error("Signal '" + name + "' redefined (original in native class '" + String(native->get_name()) + "')", p_class);
- return ERR_ALREADY_EXISTS;
- }
- }
-
Vector<StringName> parameters_names;
parameters_names.resize(signal->parameters.size());
for (int j = 0; j < signal->parameters.size(); j++) {
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs
index 213f84ad73..c8dd0ac9ce 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs
@@ -110,19 +110,6 @@ namespace Godot
}
/// <summary>
- /// Converts a 2D point expressed in the cartesian coordinate
- /// system (X and Y axis) to the polar coordinate system
- /// (a distance from the origin and an angle).
- /// </summary>
- /// <param name="x">The input X coordinate.</param>
- /// <param name="y">The input Y coordinate.</param>
- /// <returns>A <see cref="Vector2"/> with X representing the distance and Y representing the angle.</returns>
- public static Vector2 Cartesian2Polar(real_t x, real_t y)
- {
- return new Vector2(Sqrt(x * x + y * y), Atan2(y, x));
- }
-
- /// <summary>
/// Rounds `s` upward (towards positive infinity).
/// </summary>
/// <param name="s">The number to ceil.</param>
@@ -436,19 +423,6 @@ namespace Godot
}
/// <summary>
- /// Converts a 2D point expressed in the polar coordinate
- /// system (a distance from the origin `r` and an angle `th`)
- /// to the cartesian coordinate system (X and Y axis).
- /// </summary>
- /// <param name="r">The distance from the origin.</param>
- /// <param name="th">The angle of the point.</param>
- /// <returns>A <see cref="Vector2"/> representing the cartesian coordinate.</returns>
- public static Vector2 Polar2Cartesian(real_t r, real_t th)
- {
- return new Vector2(r * Cos(th), r * Sin(th));
- }
-
- /// <summary>
/// Performs a canonical Modulus operation, where the output is on the range `[0, b)`.
/// </summary>
/// <param name="a">The dividend, the primary input.</param>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
index 8bb5e90a68..b4c4ddabb9 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
@@ -603,6 +603,17 @@ namespace Godot
y = v.y;
}
+ /// <summary>
+ /// Creates a unit Vector2 rotated to the given angle. This is equivalent to doing
+ /// `Vector2(Mathf.Cos(angle), Mathf.Sin(angle))` or `Vector2.Right.Rotated(angle)`.
+ /// </summary>
+ /// <param name="angle">Angle of the vector, in radians.</param>
+ /// <returns>The resulting vector.</returns>
+ public static Vector2 FromAngle(real_t angle)
+ {
+ return new Vector2(Mathf.Cos(angle), Mathf.Sin(angle));
+ }
+
public static Vector2 operator +(Vector2 left, Vector2 right)
{
left.x += right.x;
diff --git a/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml b/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
index 195d766c1d..55d0b392fa 100644
--- a/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
+++ b/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
@@ -138,81 +138,75 @@
<constant name="MATH_DB2LINEAR" value="40" enum="BuiltinFunc">
Convert the input from decibel volume to linear volume.
</constant>
- <constant name="MATH_POLAR2CARTESIAN" value="41" enum="BuiltinFunc">
- Converts a 2D point expressed in the polar coordinate system (a distance from the origin [code]r[/code] and an angle [code]th[/code]) to the cartesian coordinate system (X and Y axis).
+ <constant name="MATH_WRAP" value="41" enum="BuiltinFunc">
</constant>
- <constant name="MATH_CARTESIAN2POLAR" value="42" enum="BuiltinFunc">
- Converts a 2D point expressed in the cartesian coordinate system (X and Y axis) to the polar coordinate system (a distance from the origin and an angle).
+ <constant name="MATH_WRAPF" value="42" enum="BuiltinFunc">
</constant>
- <constant name="MATH_WRAP" value="43" enum="BuiltinFunc">
- </constant>
- <constant name="MATH_WRAPF" value="44" enum="BuiltinFunc">
- </constant>
- <constant name="LOGIC_MAX" value="45" enum="BuiltinFunc">
+ <constant name="LOGIC_MAX" value="43" enum="BuiltinFunc">
Return the greater of the two numbers, also known as their maximum.
</constant>
- <constant name="LOGIC_MIN" value="46" enum="BuiltinFunc">
+ <constant name="LOGIC_MIN" value="44" enum="BuiltinFunc">
Return the lesser of the two numbers, also known as their minimum.
</constant>
- <constant name="LOGIC_CLAMP" value="47" enum="BuiltinFunc">
+ <constant name="LOGIC_CLAMP" value="45" enum="BuiltinFunc">
Return the input clamped inside the given range, ensuring the result is never outside it. Equivalent to [code]min(max(input, range_low), range_high)[/code].
</constant>
- <constant name="LOGIC_NEAREST_PO2" value="48" enum="BuiltinFunc">
+ <constant name="LOGIC_NEAREST_PO2" value="46" enum="BuiltinFunc">
Return the nearest power of 2 to the input.
</constant>
- <constant name="OBJ_WEAKREF" value="49" enum="BuiltinFunc">
+ <constant name="OBJ_WEAKREF" value="47" enum="BuiltinFunc">
Create a [WeakRef] from the input.
</constant>
- <constant name="TYPE_CONVERT" value="50" enum="BuiltinFunc">
+ <constant name="TYPE_CONVERT" value="48" enum="BuiltinFunc">
Convert between types.
</constant>
- <constant name="TYPE_OF" value="51" enum="BuiltinFunc">
+ <constant name="TYPE_OF" value="49" enum="BuiltinFunc">
Return the type of the input as an integer. Check [enum Variant.Type] for the integers that might be returned.
</constant>
- <constant name="TYPE_EXISTS" value="52" enum="BuiltinFunc">
+ <constant name="TYPE_EXISTS" value="50" enum="BuiltinFunc">
Checks if a type is registered in the [ClassDB].
</constant>
- <constant name="TEXT_CHAR" value="53" enum="BuiltinFunc">
+ <constant name="TEXT_CHAR" value="51" enum="BuiltinFunc">
Return a character with the given ascii value.
</constant>
- <constant name="TEXT_STR" value="54" enum="BuiltinFunc">
+ <constant name="TEXT_STR" value="52" enum="BuiltinFunc">
Convert the input to a string.
</constant>
- <constant name="TEXT_PRINT" value="55" enum="BuiltinFunc">
+ <constant name="TEXT_PRINT" value="53" enum="BuiltinFunc">
Print the given string to the output window.
</constant>
- <constant name="TEXT_PRINTERR" value="56" enum="BuiltinFunc">
+ <constant name="TEXT_PRINTERR" value="54" enum="BuiltinFunc">
Print the given string to the standard error output.
</constant>
- <constant name="TEXT_PRINTRAW" value="57" enum="BuiltinFunc">
+ <constant name="TEXT_PRINTRAW" value="55" enum="BuiltinFunc">
Print the given string to the standard output, without adding a newline.
</constant>
- <constant name="VAR_TO_STR" value="58" enum="BuiltinFunc">
+ <constant name="VAR_TO_STR" value="56" enum="BuiltinFunc">
Serialize a [Variant] to a string.
</constant>
- <constant name="STR_TO_VAR" value="59" enum="BuiltinFunc">
+ <constant name="STR_TO_VAR" value="57" enum="BuiltinFunc">
Deserialize a [Variant] from a string serialized using [constant VAR_TO_STR].
</constant>
- <constant name="VAR_TO_BYTES" value="60" enum="BuiltinFunc">
+ <constant name="VAR_TO_BYTES" value="58" enum="BuiltinFunc">
Serialize a [Variant] to a [PackedByteArray].
</constant>
- <constant name="BYTES_TO_VAR" value="61" enum="BuiltinFunc">
+ <constant name="BYTES_TO_VAR" value="59" enum="BuiltinFunc">
Deserialize a [Variant] from a [PackedByteArray] serialized using [constant VAR_TO_BYTES].
</constant>
- <constant name="MATH_SMOOTHSTEP" value="62" enum="BuiltinFunc">
+ <constant name="MATH_SMOOTHSTEP" value="60" enum="BuiltinFunc">
Return a number smoothly interpolated between the first two inputs, based on the third input. Similar to [constant MATH_LERP], but interpolates faster at the beginning and slower at the end. Using Hermite interpolation formula:
[codeblock]
var t = clamp((weight - from) / (to - from), 0.0, 1.0)
return t * t * (3.0 - 2.0 * t)
[/codeblock]
</constant>
- <constant name="MATH_POSMOD" value="63" enum="BuiltinFunc">
+ <constant name="MATH_POSMOD" value="61" enum="BuiltinFunc">
</constant>
- <constant name="MATH_LERP_ANGLE" value="64" enum="BuiltinFunc">
+ <constant name="MATH_LERP_ANGLE" value="62" enum="BuiltinFunc">
</constant>
- <constant name="TEXT_ORD" value="65" enum="BuiltinFunc">
+ <constant name="TEXT_ORD" value="63" enum="BuiltinFunc">
</constant>
- <constant name="FUNC_MAX" value="66" enum="BuiltinFunc">
+ <constant name="FUNC_MAX" value="64" enum="BuiltinFunc">
Represents the size of the [enum BuiltinFunc] enum.
</constant>
</constants>
diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp
index c61c3ae272..2bd7220d15 100644
--- a/modules/visual_script/visual_script_builtin_funcs.cpp
+++ b/modules/visual_script/visual_script_builtin_funcs.cpp
@@ -79,8 +79,6 @@ const char *VisualScriptBuiltinFunc::func_name[VisualScriptBuiltinFunc::FUNC_MAX
"rad2deg",
"linear2db",
"db2linear",
- "polar2cartesian",
- "cartesian2polar",
"wrapi",
"wrapf",
"max",
@@ -194,8 +192,6 @@ int VisualScriptBuiltinFunc::get_func_argument_count(BuiltinFunc p_func) {
case MATH_SNAPPED:
case MATH_RANDF_RANGE:
case MATH_RANDI_RANGE:
- case MATH_POLAR2CARTESIAN:
- case MATH_CARTESIAN2POLAR:
case LOGIC_MAX:
case LOGIC_MIN:
case TYPE_CONVERT:
@@ -381,20 +377,6 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const
case MATH_DB2LINEAR: {
return PropertyInfo(Variant::FLOAT, "db");
} break;
- case MATH_POLAR2CARTESIAN: {
- if (p_idx == 0) {
- return PropertyInfo(Variant::FLOAT, "r");
- } else {
- return PropertyInfo(Variant::FLOAT, "th");
- }
- } break;
- case MATH_CARTESIAN2POLAR: {
- if (p_idx == 0) {
- return PropertyInfo(Variant::FLOAT, "x");
- } else {
- return PropertyInfo(Variant::FLOAT, "y");
- }
- } break;
case MATH_WRAP: {
if (p_idx == 0) {
return PropertyInfo(Variant::INT, "value");
@@ -553,10 +535,6 @@ PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) cons
case MATH_DB2LINEAR: {
t = Variant::FLOAT;
} break;
- case MATH_POLAR2CARTESIAN:
- case MATH_CARTESIAN2POLAR: {
- t = Variant::VECTOR2;
- } break;
case MATH_WRAP: {
t = Variant::INT;
} break;
@@ -874,20 +852,6 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in
VALIDATE_ARG_NUM(0);
*r_return = Math::db2linear((double)*p_inputs[0]);
} break;
- case VisualScriptBuiltinFunc::MATH_POLAR2CARTESIAN: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- double r = *p_inputs[0];
- double th = *p_inputs[1];
- *r_return = Vector2(r * Math::cos(th), r * Math::sin(th));
- } break;
- case VisualScriptBuiltinFunc::MATH_CARTESIAN2POLAR: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- double x = *p_inputs[0];
- double y = *p_inputs[1];
- *r_return = Vector2(Math::sqrt(x * x + y * y), Math::atan2(y, x));
- } break;
case VisualScriptBuiltinFunc::MATH_WRAP: {
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
@@ -1229,8 +1193,6 @@ void VisualScriptBuiltinFunc::_bind_methods() {
BIND_ENUM_CONSTANT(MATH_RAD2DEG);
BIND_ENUM_CONSTANT(MATH_LINEAR2DB);
BIND_ENUM_CONSTANT(MATH_DB2LINEAR);
- BIND_ENUM_CONSTANT(MATH_POLAR2CARTESIAN);
- BIND_ENUM_CONSTANT(MATH_CARTESIAN2POLAR);
BIND_ENUM_CONSTANT(MATH_WRAP);
BIND_ENUM_CONSTANT(MATH_WRAPF);
BIND_ENUM_CONSTANT(LOGIC_MAX);
@@ -1320,8 +1282,6 @@ void register_visual_script_builtin_func_node() {
VisualScriptLanguage::singleton->add_register_func("functions/built_in/rad2deg", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RAD2DEG>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/linear2db", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LINEAR2DB>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/db2linear", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DB2LINEAR>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/polar2cartesian", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_POLAR2CARTESIAN>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/cartesian2polar", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_CARTESIAN2POLAR>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/wrapi", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_WRAP>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/wrapf", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_WRAPF>);
diff --git a/modules/visual_script/visual_script_builtin_funcs.h b/modules/visual_script/visual_script_builtin_funcs.h
index f59a7a0f0c..26abc1e479 100644
--- a/modules/visual_script/visual_script_builtin_funcs.h
+++ b/modules/visual_script/visual_script_builtin_funcs.h
@@ -79,8 +79,6 @@ public:
MATH_RAD2DEG,
MATH_LINEAR2DB,
MATH_DB2LINEAR,
- MATH_POLAR2CARTESIAN,
- MATH_CARTESIAN2POLAR,
MATH_WRAP,
MATH_WRAPF,
LOGIC_MAX,
diff --git a/modules/visual_script/visual_script_editor.h b/modules/visual_script/visual_script_editor.h
index 7dfb4fa270..ab32aae7aa 100644
--- a/modules/visual_script/visual_script_editor.h
+++ b/modules/visual_script/visual_script_editor.h
@@ -311,6 +311,8 @@ public:
virtual void tag_saved_version() override;
virtual void reload(bool p_soft) override;
virtual Array get_breakpoints() override;
+ virtual void set_breakpoint(int p_line, bool p_enable) override{};
+ virtual void clear_breakpoints() override{};
virtual void add_callback(const String &p_function, PackedStringArray p_args) override;
virtual void update_settings() override;
virtual bool show_members_overview() override;
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index 5c1c3281a6..6b4a326ba7 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -977,6 +977,11 @@ void EditorExportPlatformAndroid::_fix_manifest(const Ref<EditorExportPreset> &p
Vector<int> feature_versions;
if (xr_mode_index == 1 /* XRMode.OVR */) {
+ // Set degrees of freedom
+ feature_names.push_back("android.hardware.vr.headtracking");
+ feature_required_list.push_back(true);
+ feature_versions.push_back(1);
+
// Check for hand tracking
int hand_tracking_index = p_preset->get("xr_features/hand_tracking"); // 0: none, 1: optional, 2: required
if (hand_tracking_index > 0) {
diff --git a/platform/android/export/gradle_export_util.cpp b/platform/android/export/gradle_export_util.cpp
index b9e28a7937..6fbdf73cd0 100644
--- a/platform/android/export/gradle_export_util.cpp
+++ b/platform/android/export/gradle_export_util.cpp
@@ -197,6 +197,8 @@ String _get_xr_features_tag(const Ref<EditorExportPreset> &p_preset) {
String manifest_xr_features;
bool uses_xr = (int)(p_preset->get("xr_features/xr_mode")) == 1;
if (uses_xr) {
+ manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"android.hardware.vr.headtracking\" android:required=\"true\" android:version=\"1\" />\n";
+
int hand_tracking_index = p_preset->get("xr_features/hand_tracking"); // 0: none, 1: optional, 2: required
if (hand_tracking_index == 1) {
manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"oculus.software.handtracking\" android:required=\"false\" />\n";
@@ -228,7 +230,9 @@ String _get_activity_tag(const Ref<EditorExportPreset> &p_preset) {
"tools:replace=\"android:screenOrientation\" "
"android:screenOrientation=\"%s\">\n",
orientation);
- if (!uses_xr) {
+ if (uses_xr) {
+ manifest_activity_text += " <meta-data tools:node=\"replace\" android:name=\"com.oculus.vr.focusaware\" android:value=\"true\" />\n";
+ } else {
manifest_activity_text += " <meta-data tools:node=\"remove\" android:name=\"com.oculus.vr.focusaware\" />\n";
}
manifest_activity_text += " </activity>\n";
diff --git a/platform/android/java/app/AndroidManifest.xml b/platform/android/java/app/AndroidManifest.xml
index 00e01884cf..d7bf6cef30 100644
--- a/platform/android/java/app/AndroidManifest.xml
+++ b/platform/android/java/app/AndroidManifest.xml
@@ -49,6 +49,10 @@
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
+
+ <!-- Enable access to OpenXR on Oculus mobile devices, no-op on other Android
+ platforms. -->
+ <category android:name="com.oculus.intent.category.VR" />
</intent-filter>
</activity>
diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
index 896b169953..70bc73b9ad 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
@@ -295,7 +295,11 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
View pluginView = plugin.onMainCreate(activity);
if (pluginView != null) {
- containerLayout.addView(pluginView);
+ if (plugin.shouldBeOnTop()) {
+ containerLayout.addView(pluginView);
+ } else {
+ containerLayout.addView(pluginView, 0);
+ }
}
}
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java
index 2dc8359615..4536c21ed3 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java
@@ -191,6 +191,9 @@ public abstract class GodotPlugin {
* The plugin can return a non-null {@link View} layout in order to add it to the Godot view
* hierarchy.
*
+ * Use shouldBeOnTop() to set whether the plugin's {@link View} should be added on top or behind
+ * the main Godot view.
+ *
* @see Activity#onCreate(Bundle)
* @return the plugin's view to be included; null if no views should be included.
*/
@@ -311,6 +314,17 @@ public abstract class GodotPlugin {
}
/**
+ * Returns whether the plugin's {@link View} returned in onMainCreate() should be placed on
+ * top of the main Godot view.
+ *
+ * Returning false causes the plugin's {@link View} to be placed behind, which can be useful
+ * when used with transparency in order to let the Godot view handle inputs.
+ */
+ public boolean shouldBeOnTop() {
+ return true;
+ }
+
+ /**
* Runs the specified action on the UI thread. If the current thread is the UI
* thread, then the action is executed immediately. If the current thread is
* not the UI thread, the action is posted to the event queue of the UI thread.
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index 8d8b187445..3518d434c3 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -259,15 +259,17 @@ bool StaticBody2D::is_sync_to_physics_enabled() const {
return sync_to_physics;
}
-void StaticBody2D::_direct_state_changed(Object *p_state) {
+void StaticBody2D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState2D *p_state) {
+ StaticBody2D *body = (StaticBody2D *)p_instance;
+ body->_body_state_changed(p_state);
+}
+
+void StaticBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state) {
if (!sync_to_physics) {
return;
}
- PhysicsDirectBodyState2D *state = Object::cast_to<PhysicsDirectBodyState2D>(p_state);
- ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState2D object as argument");
-
- last_valid_transform = state->get_transform();
+ last_valid_transform = p_state->get_transform();
set_notify_local_transform(false);
set_global_transform(last_valid_transform);
set_notify_local_transform(true);
@@ -293,7 +295,7 @@ void StaticBody2D::_notification(int p_what) {
// Used by sync to physics, send the new transform to the physics...
Transform2D new_transform = get_global_transform();
- real_t delta_time = get_physics_process_delta_time();
+ double delta_time = get_physics_process_delta_time();
new_transform.translate(constant_linear_velocity * delta_time);
new_transform.set_rotation(new_transform.get_rotation() + constant_angular_velocity * delta_time);
@@ -316,7 +318,7 @@ void StaticBody2D::_notification(int p_what) {
Transform2D new_transform = get_global_transform();
- real_t delta_time = get_physics_process_delta_time();
+ double delta_time = get_physics_process_delta_time();
new_transform.translate(constant_linear_velocity * delta_time);
new_transform.set_rotation(new_transform.get_rotation() + constant_angular_velocity * delta_time);
@@ -379,11 +381,11 @@ void StaticBody2D::_update_kinematic_motion() {
#endif
if (kinematic_motion && sync_to_physics) {
- PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &StaticBody2D::_direct_state_changed));
+ PhysicsServer2D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback);
set_only_update_transform_changes(true);
set_notify_local_transform(true);
} else {
- PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), Callable());
+ PhysicsServer2D::get_singleton()->body_set_state_sync_callback(get_rid(), nullptr, nullptr);
set_only_update_transform_changes(false);
set_notify_local_transform(false);
}
@@ -511,26 +513,26 @@ struct _RigidBody2DInOut {
int local_shape = 0;
};
-void RigidBody2D::_direct_state_changed(Object *p_state) {
-#ifdef DEBUG_ENABLED
- state = Object::cast_to<PhysicsDirectBodyState2D>(p_state);
- ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState2D object as argument");
-#else
- state = (PhysicsDirectBodyState2D *)p_state; //trust it
-#endif
+void RigidBody2D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState2D *p_state) {
+ RigidBody2D *body = (RigidBody2D *)p_instance;
+ body->_body_state_changed(p_state);
+}
+void RigidBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state) {
set_block_transform_notify(true); // don't want notify (would feedback loop)
if (mode != MODE_KINEMATIC) {
- set_global_transform(state->get_transform());
+ set_global_transform(p_state->get_transform());
}
- linear_velocity = state->get_linear_velocity();
- angular_velocity = state->get_angular_velocity();
- if (sleeping != state->is_sleeping()) {
- sleeping = state->is_sleeping();
+
+ linear_velocity = p_state->get_linear_velocity();
+ angular_velocity = p_state->get_angular_velocity();
+
+ if (sleeping != p_state->is_sleeping()) {
+ sleeping = p_state->is_sleeping();
emit_signal(SceneStringNames::get_singleton()->sleeping_state_changed);
}
- GDVIRTUAL_CALL(_integrate_forces, state);
+ GDVIRTUAL_CALL(_integrate_forces, p_state);
set_block_transform_notify(false); // want it back
@@ -546,20 +548,18 @@ void RigidBody2D::_direct_state_changed(Object *p_state) {
}
}
- _RigidBody2DInOut *toadd = (_RigidBody2DInOut *)alloca(state->get_contact_count() * sizeof(_RigidBody2DInOut));
+ _RigidBody2DInOut *toadd = (_RigidBody2DInOut *)alloca(p_state->get_contact_count() * sizeof(_RigidBody2DInOut));
int toadd_count = 0; //state->get_contact_count();
RigidBody2D_RemoveAction *toremove = (RigidBody2D_RemoveAction *)alloca(rc * sizeof(RigidBody2D_RemoveAction));
int toremove_count = 0;
//put the ones to add
- for (int i = 0; i < state->get_contact_count(); i++) {
- RID rid = state->get_contact_collider(i);
- ObjectID obj = state->get_contact_collider_id(i);
- int local_shape = state->get_contact_local_shape(i);
- int shape = state->get_contact_collider_shape(i);
-
- //bool found=false;
+ for (int i = 0; i < p_state->get_contact_count(); i++) {
+ RID rid = p_state->get_contact_collider(i);
+ ObjectID obj = p_state->get_contact_collider_id(i);
+ int local_shape = p_state->get_contact_local_shape(i);
+ int shape = p_state->get_contact_collider_shape(i);
Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.find(obj);
if (!E) {
@@ -612,8 +612,6 @@ void RigidBody2D::_direct_state_changed(Object *p_state) {
contact_monitor->locked = false;
}
-
- state = nullptr;
}
void RigidBody2D::set_mode(Mode p_mode) {
@@ -709,25 +707,15 @@ real_t RigidBody2D::get_angular_damp() const {
}
void RigidBody2D::set_axis_velocity(const Vector2 &p_axis) {
- Vector2 v = state ? state->get_linear_velocity() : linear_velocity;
Vector2 axis = p_axis.normalized();
- v -= axis * axis.dot(v);
- v += p_axis;
- if (state) {
- set_linear_velocity(v);
- } else {
- PhysicsServer2D::get_singleton()->body_set_axis_velocity(get_rid(), p_axis);
- linear_velocity = v;
- }
+ linear_velocity -= axis * axis.dot(linear_velocity);
+ linear_velocity += p_axis;
+ PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY, linear_velocity);
}
void RigidBody2D::set_linear_velocity(const Vector2 &p_velocity) {
linear_velocity = p_velocity;
- if (state) {
- state->set_linear_velocity(linear_velocity);
- } else {
- PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY, linear_velocity);
- }
+ PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY, linear_velocity);
}
Vector2 RigidBody2D::get_linear_velocity() const {
@@ -736,11 +724,7 @@ Vector2 RigidBody2D::get_linear_velocity() const {
void RigidBody2D::set_angular_velocity(real_t p_velocity) {
angular_velocity = p_velocity;
- if (state) {
- state->set_angular_velocity(angular_velocity);
- } else {
- PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY, angular_velocity);
- }
+ PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY, angular_velocity);
}
real_t RigidBody2D::get_angular_velocity() const {
@@ -1019,7 +1003,7 @@ void RigidBody2D::_bind_methods() {
RigidBody2D::RigidBody2D() :
PhysicsBody2D(PhysicsServer2D::BODY_MODE_DYNAMIC) {
- PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &RigidBody2D::_direct_state_changed));
+ PhysicsServer2D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback);
}
RigidBody2D::~RigidBody2D() {
@@ -1045,14 +1029,19 @@ void RigidBody2D::_reload_physics_characteristics() {
bool CharacterBody2D::move_and_slide() {
// Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky.
- float delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time();
+ double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time();
Vector2 current_platform_velocity = platform_velocity;
if ((on_floor || on_wall) && platform_rid.is_valid()) {
- bool excluded = (moving_platform_ignore_layers & platform_layer) != 0;
+ bool excluded = false;
+ if (on_floor) {
+ excluded = (moving_platform_floor_layers & platform_layer) == 0;
+ } else if (on_wall) {
+ excluded = (moving_platform_wall_layers & platform_layer) == 0;
+ }
if (!excluded) {
- // This approach makes sure there is less delay between the actual body velocity and the one we saved.
+ //this approach makes sure there is less delay between the actual body velocity and the one we saved
PhysicsDirectBodyState2D *bs = PhysicsServer2D::get_singleton()->body_get_direct_state(platform_rid);
if (bs) {
Transform2D gt = get_global_transform();
@@ -1095,7 +1084,7 @@ bool CharacterBody2D::move_and_slide() {
return motion_results.size() > 0;
}
-void CharacterBody2D::_move_and_slide_grounded(real_t p_delta, bool p_was_on_floor, const Vector2 &p_prev_platform_velocity) {
+void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_floor, const Vector2 &p_prev_platform_velocity) {
Vector2 motion = linear_velocity * p_delta;
Vector2 motion_slide_up = motion.slide(up_direction);
@@ -1239,7 +1228,7 @@ void CharacterBody2D::_move_and_slide_grounded(real_t p_delta, bool p_was_on_flo
}
}
-void CharacterBody2D::_move_and_slide_free(real_t p_delta) {
+void CharacterBody2D::_move_and_slide_free(double p_delta) {
Vector2 motion = linear_velocity * p_delta;
platform_rid = RID();
@@ -1469,12 +1458,20 @@ void CharacterBody2D::set_slide_on_ceiling_enabled(bool p_enabled) {
slide_on_ceiling = p_enabled;
}
-uint32_t CharacterBody2D::get_moving_platform_ignore_layers() const {
- return moving_platform_ignore_layers;
+uint32_t CharacterBody2D::get_moving_platform_floor_layers() const {
+ return moving_platform_floor_layers;
+}
+
+void CharacterBody2D::set_moving_platform_floor_layers(uint32_t p_exclude_layers) {
+ moving_platform_floor_layers = p_exclude_layers;
+}
+
+uint32_t CharacterBody2D::get_moving_platform_wall_layers() const {
+ return moving_platform_wall_layers;
}
-void CharacterBody2D::set_moving_platform_ignore_layers(uint32_t p_exclude_layers) {
- moving_platform_ignore_layers = p_exclude_layers;
+void CharacterBody2D::set_moving_platform_wall_layers(uint32_t p_exclude_layers) {
+ moving_platform_wall_layers = p_exclude_layers;
}
void CharacterBody2D::set_motion_mode(MotionMode p_mode) {
@@ -1559,8 +1556,10 @@ void CharacterBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_slide_on_ceiling_enabled", "enabled"), &CharacterBody2D::set_slide_on_ceiling_enabled);
ClassDB::bind_method(D_METHOD("is_slide_on_ceiling_enabled"), &CharacterBody2D::is_slide_on_ceiling_enabled);
- ClassDB::bind_method(D_METHOD("set_moving_platform_ignore_layers", "exclude_layer"), &CharacterBody2D::set_moving_platform_ignore_layers);
- ClassDB::bind_method(D_METHOD("get_moving_platform_ignore_layers"), &CharacterBody2D::get_moving_platform_ignore_layers);
+ ClassDB::bind_method(D_METHOD("set_moving_platform_floor_layers", "exclude_layer"), &CharacterBody2D::set_moving_platform_floor_layers);
+ ClassDB::bind_method(D_METHOD("get_moving_platform_floor_layers"), &CharacterBody2D::get_moving_platform_floor_layers);
+ ClassDB::bind_method(D_METHOD("set_moving_platform_wall_layers", "exclude_layer"), &CharacterBody2D::set_moving_platform_wall_layers);
+ ClassDB::bind_method(D_METHOD("get_moving_platform_wall_layers"), &CharacterBody2D::get_moving_platform_wall_layers);
ClassDB::bind_method(D_METHOD("get_max_slides"), &CharacterBody2D::get_max_slides);
ClassDB::bind_method(D_METHOD("set_max_slides", "max_slides"), &CharacterBody2D::set_max_slides);
@@ -1602,7 +1601,8 @@ void CharacterBody2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_max_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians"), "set_floor_max_angle", "get_floor_max_angle");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_snap_length", PROPERTY_HINT_RANGE, "0,1000,0.1"), "set_floor_snap_length", "get_floor_snap_length");
ADD_GROUP("Moving platform", "moving_platform");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_ignore_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_moving_platform_ignore_layers", "get_moving_platform_ignore_layers");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_floor_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_moving_platform_floor_layers", "get_moving_platform_floor_layers");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_wall_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_moving_platform_wall_layers", "get_moving_platform_wall_layers");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin");
BIND_ENUM_CONSTANT(MOTION_MODE_GROUNDED);
diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h
index 885f0ace05..1bf53ea53c 100644
--- a/scene/2d/physics_body_2d.h
+++ b/scene/2d/physics_body_2d.h
@@ -73,7 +73,8 @@ class StaticBody2D : public PhysicsBody2D {
Transform2D last_valid_transform;
- void _direct_state_changed(Object *p_state);
+ static void _body_state_changed_callback(void *p_instance, PhysicsDirectBodyState2D *p_state);
+ void _body_state_changed(PhysicsDirectBodyState2D *p_state);
protected:
void _notification(int p_what);
@@ -124,7 +125,6 @@ public:
private:
bool can_sleep = true;
- PhysicsDirectBodyState2D *state = nullptr;
Mode mode = MODE_DYNAMIC;
real_t mass = 1.0;
@@ -183,7 +183,9 @@ private:
void _body_exit_tree(ObjectID p_id);
void _body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_local_shape);
- void _direct_state_changed(Object *p_state);
+
+ static void _body_state_changed_callback(void *p_instance, PhysicsDirectBodyState2D *p_state);
+ void _body_state_changed(PhysicsDirectBodyState2D *p_state);
protected:
void _notification(int p_what);
@@ -310,7 +312,8 @@ private:
float floor_snap_length = 0;
real_t free_mode_min_slide_angle = Math::deg2rad((real_t)15.0);
Vector2 up_direction = Vector2(0.0, -1.0);
- uint32_t moving_platform_ignore_layers = 0;
+ uint32_t moving_platform_floor_layers = UINT32_MAX;
+ uint32_t moving_platform_wall_layers = 0;
Vector2 linear_velocity;
Vector2 floor_normal;
@@ -350,14 +353,17 @@ private:
real_t get_free_mode_min_slide_angle() const;
void set_free_mode_min_slide_angle(real_t p_radians);
- uint32_t get_moving_platform_ignore_layers() const;
- void set_moving_platform_ignore_layers(const uint32_t p_exclude_layer);
+ uint32_t get_moving_platform_floor_layers() const;
+ void set_moving_platform_floor_layers(const uint32_t p_exclude_layer);
+
+ uint32_t get_moving_platform_wall_layers() const;
+ void set_moving_platform_wall_layers(const uint32_t p_exclude_layer);
void set_motion_mode(MotionMode p_mode);
MotionMode get_motion_mode() const;
- void _move_and_slide_free(real_t p_delta);
- void _move_and_slide_grounded(real_t p_delta, bool p_was_on_floor, const Vector2 &p_prev_platform_velocity);
+ void _move_and_slide_free(double p_delta);
+ void _move_and_slide_grounded(double p_delta, bool p_was_on_floor, const Vector2 &p_prev_platform_velocity);
Ref<KinematicCollision2D> _get_slide_collision(int p_bounce);
Ref<KinematicCollision2D> _get_last_slide_collision();
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index 06a4087b60..0356994cdb 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -283,18 +283,20 @@ bool StaticBody3D::is_sync_to_physics_enabled() const {
return sync_to_physics;
}
-void StaticBody3D::_direct_state_changed(Object *p_state) {
- PhysicsDirectBodyState3D *state = Object::cast_to<PhysicsDirectBodyState3D>(p_state);
- ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState3D object as argument");
+void StaticBody3D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state) {
+ StaticBody3D *body = (StaticBody3D *)p_instance;
+ body->_body_state_changed(p_state);
+}
- linear_velocity = state->get_linear_velocity();
- angular_velocity = state->get_angular_velocity();
+void StaticBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
+ linear_velocity = p_state->get_linear_velocity();
+ angular_velocity = p_state->get_angular_velocity();
if (!sync_to_physics) {
return;
}
- last_valid_transform = state->get_transform();
+ last_valid_transform = p_state->get_transform();
set_notify_local_transform(false);
set_global_transform(last_valid_transform);
set_notify_local_transform(true);
@@ -347,7 +349,7 @@ void StaticBody3D::_notification(int p_what) {
// Used by sync to physics, send the new transform to the physics...
Transform3D new_transform = get_global_transform();
- real_t delta_time = get_physics_process_delta_time();
+ double delta_time = get_physics_process_delta_time();
new_transform.origin += constant_linear_velocity * delta_time;
real_t ang_vel = constant_angular_velocity.length();
@@ -378,7 +380,7 @@ void StaticBody3D::_notification(int p_what) {
Transform3D new_transform = get_global_transform();
- real_t delta_time = get_physics_process_delta_time();
+ double delta_time = get_physics_process_delta_time();
new_transform.origin += constant_linear_velocity * delta_time;
real_t ang_vel = constant_angular_velocity.length();
@@ -458,13 +460,13 @@ void StaticBody3D::_update_kinematic_motion() {
bool needs_physics_process = false;
if (kinematic_motion) {
- PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &StaticBody3D::_direct_state_changed));
+ PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), this, &StaticBody3D::_body_state_changed_callback);
if (!constant_angular_velocity.is_equal_approx(Vector3()) || !constant_linear_velocity.is_equal_approx(Vector3())) {
needs_physics_process = true;
}
} else {
- PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), Callable());
+ PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), nullptr, nullptr);
}
set_physics_process_internal(needs_physics_process);
@@ -582,25 +584,26 @@ struct _RigidBodyInOut {
int local_shape = 0;
};
-void RigidBody3D::_direct_state_changed(Object *p_state) {
-#ifdef DEBUG_ENABLED
- state = Object::cast_to<PhysicsDirectBodyState3D>(p_state);
- ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState3D object as argument");
-#else
- state = (PhysicsDirectBodyState3D *)p_state; //trust it
-#endif
+void RigidBody3D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state) {
+ RigidBody3D *body = (RigidBody3D *)p_instance;
+ body->_body_state_changed(p_state);
+}
+void RigidBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
set_ignore_transform_notification(true);
- set_global_transform(state->get_transform());
- linear_velocity = state->get_linear_velocity();
- angular_velocity = state->get_angular_velocity();
- inverse_inertia_tensor = state->get_inverse_inertia_tensor();
- if (sleeping != state->is_sleeping()) {
- sleeping = state->is_sleeping();
+ set_global_transform(p_state->get_transform());
+
+ linear_velocity = p_state->get_linear_velocity();
+ angular_velocity = p_state->get_angular_velocity();
+
+ inverse_inertia_tensor = p_state->get_inverse_inertia_tensor();
+
+ if (sleeping != p_state->is_sleeping()) {
+ sleeping = p_state->is_sleeping();
emit_signal(SceneStringNames::get_singleton()->sleeping_state_changed);
}
- GDVIRTUAL_CALL(_integrate_forces, state);
+ GDVIRTUAL_CALL(_integrate_forces, p_state);
set_ignore_transform_notification(false);
_on_transform_changed();
@@ -617,18 +620,18 @@ void RigidBody3D::_direct_state_changed(Object *p_state) {
}
}
- _RigidBodyInOut *toadd = (_RigidBodyInOut *)alloca(state->get_contact_count() * sizeof(_RigidBodyInOut));
+ _RigidBodyInOut *toadd = (_RigidBodyInOut *)alloca(p_state->get_contact_count() * sizeof(_RigidBodyInOut));
int toadd_count = 0; //state->get_contact_count();
RigidBody3D_RemoveAction *toremove = (RigidBody3D_RemoveAction *)alloca(rc * sizeof(RigidBody3D_RemoveAction));
int toremove_count = 0;
//put the ones to add
- for (int i = 0; i < state->get_contact_count(); i++) {
- RID rid = state->get_contact_collider(i);
- ObjectID obj = state->get_contact_collider_id(i);
- int local_shape = state->get_contact_local_shape(i);
- int shape = state->get_contact_collider_shape(i);
+ for (int i = 0; i < p_state->get_contact_count(); i++) {
+ RID rid = p_state->get_contact_collider(i);
+ ObjectID obj = p_state->get_contact_collider_id(i);
+ int local_shape = p_state->get_contact_local_shape(i);
+ int shape = p_state->get_contact_collider_shape(i);
//bool found=false;
@@ -683,8 +686,6 @@ void RigidBody3D::_direct_state_changed(Object *p_state) {
contact_monitor->locked = false;
}
-
- state = nullptr;
}
void RigidBody3D::_notification(int p_what) {
@@ -787,25 +788,15 @@ real_t RigidBody3D::get_angular_damp() const {
}
void RigidBody3D::set_axis_velocity(const Vector3 &p_axis) {
- Vector3 v = state ? state->get_linear_velocity() : linear_velocity;
Vector3 axis = p_axis.normalized();
- v -= axis * axis.dot(v);
- v += p_axis;
- if (state) {
- set_linear_velocity(v);
- } else {
- PhysicsServer3D::get_singleton()->body_set_axis_velocity(get_rid(), p_axis);
- linear_velocity = v;
- }
+ linear_velocity -= axis * axis.dot(linear_velocity);
+ linear_velocity += p_axis;
+ PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, linear_velocity);
}
void RigidBody3D::set_linear_velocity(const Vector3 &p_velocity) {
linear_velocity = p_velocity;
- if (state) {
- state->set_linear_velocity(linear_velocity);
- } else {
- PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, linear_velocity);
- }
+ PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, linear_velocity);
}
Vector3 RigidBody3D::get_linear_velocity() const {
@@ -814,11 +805,7 @@ Vector3 RigidBody3D::get_linear_velocity() const {
void RigidBody3D::set_angular_velocity(const Vector3 &p_velocity) {
angular_velocity = p_velocity;
- if (state) {
- state->set_angular_velocity(angular_velocity);
- } else {
- PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY, angular_velocity);
- }
+ PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY, angular_velocity);
}
Vector3 RigidBody3D::get_angular_velocity() const {
@@ -1055,7 +1042,7 @@ void RigidBody3D::_bind_methods() {
RigidBody3D::RigidBody3D() :
PhysicsBody3D(PhysicsServer3D::BODY_MODE_DYNAMIC) {
- PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &RigidBody3D::_direct_state_changed));
+ PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), this, &RigidBody3D::_body_state_changed_callback);
}
RigidBody3D::~RigidBody3D() {
@@ -1083,7 +1070,7 @@ bool CharacterBody3D::move_and_slide() {
bool was_on_floor = on_floor;
// Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky
- float delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time();
+ double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time();
for (int i = 0; i < 3; i++) {
if (locked_axis & (1 << i)) {
@@ -2252,23 +2239,19 @@ void PhysicalBone3D::_notification(int p_what) {
}
}
-void PhysicalBone3D::_direct_state_changed(Object *p_state) {
+void PhysicalBone3D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state) {
+ PhysicalBone3D *bone = (PhysicalBone3D *)p_instance;
+ bone->_body_state_changed(p_state);
+}
+
+void PhysicalBone3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
if (!simulate_physics || !_internal_simulate_physics) {
return;
}
- /// Update bone transform
-
- PhysicsDirectBodyState3D *state;
-
-#ifdef DEBUG_ENABLED
- state = Object::cast_to<PhysicsDirectBodyState3D>(p_state);
- ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState3D object as argument");
-#else
- state = (PhysicsDirectBodyState3D *)p_state; //trust it
-#endif
+ /// Update bone transform.
- Transform3D global_transform(state->get_transform());
+ Transform3D global_transform(p_state->get_transform());
set_ignore_transform_notification(true);
set_global_transform(global_transform);
@@ -2730,7 +2713,7 @@ void PhysicalBone3D::_start_physics_simulation() {
set_body_mode(PhysicsServer3D::BODY_MODE_DYNAMIC);
PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer());
PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask());
- PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &PhysicalBone3D::_direct_state_changed));
+ PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), this, &PhysicalBone3D::_body_state_changed_callback);
set_as_top_level(true);
_internal_simulate_physics = true;
}
@@ -2749,7 +2732,7 @@ void PhysicalBone3D::_stop_physics_simulation() {
PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), 0);
}
if (_internal_simulate_physics) {
- PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), Callable());
+ PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), nullptr, nullptr);
parent_skeleton->set_bone_global_pose_override(bone_id, Transform3D(), 0.0, false);
set_as_top_level(false);
_internal_simulate_physics = false;
diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h
index 17e688451d..8c09f77846 100644
--- a/scene/3d/physics_body_3d.h
+++ b/scene/3d/physics_body_3d.h
@@ -86,7 +86,8 @@ class StaticBody3D : public PhysicsBody3D {
Transform3D last_valid_transform;
- void _direct_state_changed(Object *p_state);
+ static void _body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state);
+ void _body_state_changed(PhysicsDirectBodyState3D *p_state);
protected:
void _notification(int p_what);
@@ -136,7 +137,6 @@ public:
protected:
bool can_sleep = true;
- PhysicsDirectBodyState3D *state = nullptr;
Mode mode = MODE_DYNAMIC;
real_t mass = 1.0;
@@ -197,7 +197,8 @@ protected:
void _body_exit_tree(ObjectID p_id);
void _body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_local_shape);
- virtual void _direct_state_changed(Object *p_state);
+ static void _body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state);
+ virtual void _body_state_changed(PhysicsDirectBodyState3D *p_state);
void _notification(int p_what);
static void _bind_methods();
@@ -525,7 +526,8 @@ protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
void _notification(int p_what);
- void _direct_state_changed(Object *p_state);
+ static void _body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state);
+ void _body_state_changed(PhysicsDirectBodyState3D *p_state);
static void _bind_methods();
diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp
index 28ff3e9412..7eb189e890 100644
--- a/scene/3d/soft_body_3d.cpp
+++ b/scene/3d/soft_body_3d.cpp
@@ -355,6 +355,11 @@ void SoftBody3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_drag_coefficient", "drag_coefficient"), &SoftBody3D::set_drag_coefficient);
ClassDB::bind_method(D_METHOD("get_drag_coefficient"), &SoftBody3D::get_drag_coefficient);
+ ClassDB::bind_method(D_METHOD("get_point_transform", "point_index"), &SoftBody3D::get_point_transform);
+
+ ClassDB::bind_method(D_METHOD("set_point_pinned", "point_index", "pinned", "attachment_path"), &SoftBody3D::pin_point, DEFVAL(NodePath()));
+ ClassDB::bind_method(D_METHOD("is_point_pinned", "point_index"), &SoftBody3D::is_point_pinned);
+
ClassDB::bind_method(D_METHOD("set_ray_pickable", "ray_pickable"), &SoftBody3D::set_ray_pickable);
ClassDB::bind_method(D_METHOD("is_ray_pickable"), &SoftBody3D::is_ray_pickable);
diff --git a/scene/3d/vehicle_body_3d.cpp b/scene/3d/vehicle_body_3d.cpp
index 92c0e09947..daeea81891 100644
--- a/scene/3d/vehicle_body_3d.cpp
+++ b/scene/3d/vehicle_body_3d.cpp
@@ -802,24 +802,21 @@ void VehicleBody3D::_update_friction(PhysicsDirectBodyState3D *s) {
}
}
-void VehicleBody3D::_direct_state_changed(Object *p_state) {
- RigidBody3D::_direct_state_changed(p_state);
+void VehicleBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
+ RigidBody3D::_body_state_changed(p_state);
- state = Object::cast_to<PhysicsDirectBodyState3D>(p_state);
- ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState3D object as argument");
-
- real_t step = state->get_step();
+ real_t step = p_state->get_step();
for (int i = 0; i < wheels.size(); i++) {
- _update_wheel(i, state);
+ _update_wheel(i, p_state);
}
for (int i = 0; i < wheels.size(); i++) {
- _ray_cast(i, state);
- wheels[i]->set_transform(state->get_transform().inverse() * wheels[i]->m_worldTransform);
+ _ray_cast(i, p_state);
+ wheels[i]->set_transform(p_state->get_transform().inverse() * wheels[i]->m_worldTransform);
}
- _update_suspension(state);
+ _update_suspension(p_state);
for (int i = 0; i < wheels.size(); i++) {
//apply suspension force
@@ -831,20 +828,20 @@ void VehicleBody3D::_direct_state_changed(Object *p_state) {
suspensionForce = wheel.m_maxSuspensionForce;
}
Vector3 impulse = wheel.m_raycastInfo.m_contactNormalWS * suspensionForce * step;
- Vector3 relative_position = wheel.m_raycastInfo.m_contactPointWS - state->get_transform().origin;
+ Vector3 relative_position = wheel.m_raycastInfo.m_contactPointWS - p_state->get_transform().origin;
- state->apply_impulse(impulse, relative_position);
+ p_state->apply_impulse(impulse, relative_position);
}
- _update_friction(state);
+ _update_friction(p_state);
for (int i = 0; i < wheels.size(); i++) {
VehicleWheel3D &wheel = *wheels[i];
- Vector3 relpos = wheel.m_raycastInfo.m_hardPointWS - state->get_transform().origin;
- Vector3 vel = state->get_linear_velocity() + (state->get_angular_velocity()).cross(relpos); // * mPos);
+ Vector3 relpos = wheel.m_raycastInfo.m_hardPointWS - p_state->get_transform().origin;
+ Vector3 vel = p_state->get_linear_velocity() + (p_state->get_angular_velocity()).cross(relpos); // * mPos);
if (wheel.m_raycastInfo.m_isInContact) {
- const Transform3D &chassisWorldTransform = state->get_transform();
+ const Transform3D &chassisWorldTransform = p_state->get_transform();
Vector3 fwd(
chassisWorldTransform.basis[0][Vector3::AXIS_Z],
@@ -864,8 +861,6 @@ void VehicleBody3D::_direct_state_changed(Object *p_state) {
wheel.m_deltaRotation *= real_t(0.99); //damping of rotation when not in contact
}
-
- state = nullptr;
}
void VehicleBody3D::set_engine_force(real_t p_engine_force) {
@@ -926,7 +921,5 @@ void VehicleBody3D::_bind_methods() {
VehicleBody3D::VehicleBody3D() {
exclude.insert(get_rid());
- //PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &VehicleBody3D::_direct_state_changed));
-
set_mass(40);
}
diff --git a/scene/3d/vehicle_body_3d.h b/scene/3d/vehicle_body_3d.h
index 2c10205ea3..f29c3d89b7 100644
--- a/scene/3d/vehicle_body_3d.h
+++ b/scene/3d/vehicle_body_3d.h
@@ -192,7 +192,8 @@ class VehicleBody3D : public RigidBody3D {
static void _bind_methods();
- void _direct_state_changed(Object *p_state) override;
+ static void _body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state);
+ virtual void _body_state_changed(PhysicsDirectBodyState3D *p_state) override;
public:
void set_engine_force(real_t p_engine_force);
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index 481e211eb3..845a2ec6c7 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -434,14 +434,14 @@ void TabContainer::_notification(int p_what) {
}
int tab_width = tab_widths[i];
- if (get_tab_disabled(index)) {
+ if (index == current) {
+ x_current = x;
+ } else if (get_tab_disabled(index)) {
if (rtl) {
_draw_tab(tab_disabled, font_disabled_color, index, size.width - (tabs_ofs_cache + x) - tab_width);
} else {
_draw_tab(tab_disabled, font_disabled_color, index, tabs_ofs_cache + x);
}
- } else if (index == current) {
- x_current = x;
} else {
if (rtl) {
_draw_tab(tab_unselected, font_unselected_color, index, size.width - (tabs_ofs_cache + x) - tab_width);
@@ -459,12 +459,13 @@ void TabContainer::_notification(int p_what) {
panel->draw(canvas, Rect2(0, header_height, size.width, size.height - header_height));
}
- // Draw selected tab in front. only draw selected tab when it's in visible range.
+ // Draw selected tab in front. Only draw selected tab when it's in visible range.
if (tabs.size() > 0 && current - first_tab_cache < tab_widths.size() && current >= first_tab_cache) {
+ Ref<StyleBox> current_style_box = get_tab_disabled(current) ? tab_disabled : tab_selected;
if (rtl) {
- _draw_tab(tab_selected, font_selected_color, current, size.width - (tabs_ofs_cache + x_current) - tab_widths[current]);
+ _draw_tab(current_style_box, font_selected_color, current, size.width - (tabs_ofs_cache + x_current) - tab_widths[current]);
} else {
- _draw_tab(tab_selected, font_selected_color, current, tabs_ofs_cache + x_current);
+ _draw_tab(current_style_box, font_selected_color, current, tabs_ofs_cache + x_current);
}
}
@@ -640,8 +641,8 @@ void TabContainer::_on_mouse_exited() {
int TabContainer::_get_tab_width(int p_index) const {
ERR_FAIL_INDEX_V(p_index, get_tab_count(), 0);
- Control *control = Object::cast_to<Control>(_get_tabs()[p_index]);
- if (!control || control->is_set_as_top_level() || get_tab_hidden(p_index)) {
+ Control *control = get_tab_control(p_index);
+ if (!control || get_tab_hidden(p_index)) {
return 0;
}
diff --git a/scene/gui/texture_progress_bar.cpp b/scene/gui/texture_progress_bar.cpp
index 5e5dec3579..286f01ee33 100644
--- a/scene/gui/texture_progress_bar.cpp
+++ b/scene/gui/texture_progress_bar.cpp
@@ -100,6 +100,15 @@ Ref<Texture2D> TextureProgressBar::get_progress_texture() const {
return progress;
}
+void TextureProgressBar::set_progress_offset(Point2 p_offset) {
+ progress_offset = p_offset;
+ update();
+}
+
+Point2 TextureProgressBar::get_progress_offset() const {
+ return progress_offset;
+}
+
void TextureProgressBar::set_tint_under(const Color &p_tint) {
tint_under = p_tint;
update();
@@ -360,6 +369,9 @@ void TextureProgressBar::draw_nine_patch_stretched(const Ref<Texture2D> &p_textu
}
}
+ if (p_texture == progress) {
+ dst_rect.position += progress_offset;
+ }
p_texture->get_rect_region(dst_rect, src_rect, dst_rect, src_rect);
RID ci = get_canvas_item();
@@ -403,20 +415,24 @@ void TextureProgressBar::_notification(int p_what) {
Size2 s = progress->get_size();
switch (mode) {
case FILL_LEFT_TO_RIGHT: {
- Rect2 region = Rect2(Point2(), Size2(s.x * get_as_ratio(), s.y));
- draw_texture_rect_region(progress, region, region, tint_progress);
+ Rect2 region = Rect2(progress_offset, Size2(s.x * get_as_ratio(), s.y));
+ Rect2 source = Rect2(Point2(), Size2(s.x * get_as_ratio(), s.y));
+ draw_texture_rect_region(progress, region, source, tint_progress);
} break;
case FILL_RIGHT_TO_LEFT: {
- Rect2 region = Rect2(Point2(s.x - s.x * get_as_ratio(), 0), Size2(s.x * get_as_ratio(), s.y));
- draw_texture_rect_region(progress, region, region, tint_progress);
+ Rect2 region = Rect2(progress_offset + Point2(s.x - s.x * get_as_ratio(), 0), Size2(s.x * get_as_ratio(), s.y));
+ Rect2 source = Rect2(Point2(s.x - s.x * get_as_ratio(), 0), Size2(s.x * get_as_ratio(), s.y));
+ draw_texture_rect_region(progress, region, source, tint_progress);
} break;
case FILL_TOP_TO_BOTTOM: {
- Rect2 region = Rect2(Point2(), Size2(s.x, s.y * get_as_ratio()));
- draw_texture_rect_region(progress, region, region, tint_progress);
+ Rect2 region = Rect2(progress_offset + Point2(), Size2(s.x, s.y * get_as_ratio()));
+ Rect2 source = Rect2(Point2(), Size2(s.x, s.y * get_as_ratio()));
+ draw_texture_rect_region(progress, region, source, tint_progress);
} break;
case FILL_BOTTOM_TO_TOP: {
- Rect2 region = Rect2(Point2(0, s.y - s.y * get_as_ratio()), Size2(s.x, s.y * get_as_ratio()));
- draw_texture_rect_region(progress, region, region, tint_progress);
+ Rect2 region = Rect2(progress_offset + Point2(0, s.y - s.y * get_as_ratio()), Size2(s.x, s.y * get_as_ratio()));
+ Rect2 source = Rect2(Point2(0, s.y - s.y * get_as_ratio()), Size2(s.x, s.y * get_as_ratio()));
+ draw_texture_rect_region(progress, region, source, tint_progress);
} break;
case FILL_CLOCKWISE:
case FILL_COUNTER_CLOCKWISE:
@@ -427,8 +443,9 @@ void TextureProgressBar::_notification(int p_what) {
float val = get_as_ratio() * rad_max_degrees / 360;
if (val == 1) {
- Rect2 region = Rect2(Point2(), s);
- draw_texture_rect(progress, region, false, tint_progress);
+ Rect2 region = Rect2(progress_offset, s);
+ Rect2 source = Rect2(Point2(), s);
+ draw_texture_rect_region(progress, region, source, tint_progress);
} else if (val != 0) {
Array pts;
float direction = mode == FILL_COUNTER_CLOCKWISE ? -1 : 1;
@@ -454,14 +471,14 @@ void TextureProgressBar::_notification(int p_what) {
Vector<Point2> uvs;
Vector<Point2> points;
uvs.push_back(get_relative_center());
- points.push_back(Point2(s.x * get_relative_center().x, s.y * get_relative_center().y));
+ points.push_back(progress_offset + Point2(s.x * get_relative_center().x, s.y * get_relative_center().y));
for (int i = 0; i < pts.size(); i++) {
Point2 uv = unit_val_to_uv(pts[i]);
if (uvs.find(uv) >= 0) {
continue;
}
uvs.push_back(uv);
- points.push_back(Point2(uv.x * s.x, uv.y * s.y));
+ points.push_back(progress_offset + Point2(uv.x * s.x, uv.y * s.y));
}
Vector<Color> colors;
colors.push_back(tint_progress);
@@ -484,17 +501,19 @@ void TextureProgressBar::_notification(int p_what) {
}
} break;
case FILL_BILINEAR_LEFT_AND_RIGHT: {
- Rect2 region = Rect2(Point2(s.x / 2 - s.x * get_as_ratio() / 2, 0), Size2(s.x * get_as_ratio(), s.y));
- draw_texture_rect_region(progress, region, region, tint_progress);
+ Rect2 region = Rect2(progress_offset + Point2(s.x / 2 - s.x * get_as_ratio() / 2, 0), Size2(s.x * get_as_ratio(), s.y));
+ Rect2 source = Rect2(Point2(s.x / 2 - s.x * get_as_ratio() / 2, 0), Size2(s.x * get_as_ratio(), s.y));
+ draw_texture_rect_region(progress, region, source, tint_progress);
} break;
case FILL_BILINEAR_TOP_AND_BOTTOM: {
- Rect2 region = Rect2(Point2(0, s.y / 2 - s.y * get_as_ratio() / 2), Size2(s.x, s.y * get_as_ratio()));
- draw_texture_rect_region(progress, region, region, tint_progress);
+ Rect2 region = Rect2(progress_offset + Point2(0, s.y / 2 - s.y * get_as_ratio() / 2), Size2(s.x, s.y * get_as_ratio()));
+ Rect2 source = Rect2(Point2(0, s.y / 2 - s.y * get_as_ratio() / 2), Size2(s.x, s.y * get_as_ratio()));
+ draw_texture_rect_region(progress, region, source, tint_progress);
} break;
case FILL_MODE_MAX:
break;
default:
- draw_texture_rect_region(progress, Rect2(Point2(), Size2(s.x * get_as_ratio(), s.y)), Rect2(Point2(), Size2(s.x * get_as_ratio(), s.y)), tint_progress);
+ draw_texture_rect_region(progress, Rect2(progress_offset, Size2(s.x * get_as_ratio(), s.y)), Rect2(Point2(), Size2(s.x * get_as_ratio(), s.y)), tint_progress);
}
}
if (over.is_valid()) {
@@ -585,6 +604,9 @@ void TextureProgressBar::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_tint_over", "tint"), &TextureProgressBar::set_tint_over);
ClassDB::bind_method(D_METHOD("get_tint_over"), &TextureProgressBar::get_tint_over);
+ ClassDB::bind_method(D_METHOD("set_texture_progress_offset", "offset"), &TextureProgressBar::set_progress_offset);
+ ClassDB::bind_method(D_METHOD("get_texture_progress_offset"), &TextureProgressBar::get_progress_offset);
+
ClassDB::bind_method(D_METHOD("set_radial_initial_angle", "mode"), &TextureProgressBar::set_radial_initial_angle);
ClassDB::bind_method(D_METHOD("get_radial_initial_angle"), &TextureProgressBar::get_radial_initial_angle);
@@ -604,6 +626,7 @@ void TextureProgressBar::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_under", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_under_texture", "get_under_texture");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_over", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_over_texture", "get_over_texture");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_progress", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_progress_texture", "get_progress_texture");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture_progress_offset"), "set_texture_progress_offset", "get_texture_progress_offset");
ADD_PROPERTY(PropertyInfo(Variant::INT, "fill_mode", PROPERTY_HINT_ENUM, "Left to Right,Right to Left,Top to Bottom,Bottom to Top,Clockwise,Counter Clockwise,Bilinear (Left and Right),Bilinear (Top and Bottom),Clockwise and Counter Clockwise"), "set_fill_mode", "get_fill_mode");
ADD_GROUP("Tint", "tint_");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "tint_under"), "set_tint_under", "get_tint_under");
diff --git a/scene/gui/texture_progress_bar.h b/scene/gui/texture_progress_bar.h
index d147c43a26..c508f41387 100644
--- a/scene/gui/texture_progress_bar.h
+++ b/scene/gui/texture_progress_bar.h
@@ -61,6 +61,9 @@ public:
void set_fill_mode(int p_fill);
int get_fill_mode();
+ void set_progress_offset(Point2 p_offset);
+ Point2 get_progress_offset() const;
+
void set_radial_initial_angle(float p_angle);
float get_radial_initial_angle();
@@ -100,6 +103,7 @@ public:
private:
FillMode mode = FILL_LEFT_TO_RIGHT;
+ Point2 progress_offset;
float rad_init_angle = 0.0;
float rad_max_degrees = 360.0;
Point2 rad_center_off;
diff --git a/servers/physics_2d/body_2d_sw.cpp b/servers/physics_2d/body_2d_sw.cpp
index ad47912b82..64f71fd25c 100644
--- a/servers/physics_2d/body_2d_sw.cpp
+++ b/servers/physics_2d/body_2d_sw.cpp
@@ -29,8 +29,9 @@
/*************************************************************************/
#include "body_2d_sw.h"
+
#include "area_2d_sw.h"
-#include "physics_server_2d_sw.h"
+#include "body_direct_state_2d_sw.h"
#include "space_2d_sw.h"
void Body2DSW::_update_inertia() {
@@ -495,7 +496,7 @@ void Body2DSW::integrate_velocities(real_t p_step) {
return;
}
- if (fi_callback) {
+ if (fi_callback_data || body_state_callback) {
get_space()->body_add_to_state_query_list(&direct_state_query_list);
}
@@ -547,27 +548,27 @@ void Body2DSW::wakeup_neighbours() {
}
void Body2DSW::call_queries() {
- if (fi_callback) {
- PhysicsDirectBodyState2DSW *dbs = PhysicsDirectBodyState2DSW::singleton;
- dbs->body = this;
-
- Variant v = dbs;
- const Variant *vp[2] = { &v, &fi_callback->callback_udata };
-
- Object *obj = fi_callback->callable.get_object();
- if (!obj) {
+ if (fi_callback_data) {
+ if (!fi_callback_data->callable.get_object()) {
set_force_integration_callback(Callable());
} else {
+ Variant direct_state_variant = get_direct_state();
+ const Variant *vp[2] = { &direct_state_variant, &fi_callback_data->udata };
+
Callable::CallError ce;
Variant rv;
- if (fi_callback->callback_udata.get_type() != Variant::NIL) {
- fi_callback->callable.call(vp, 2, rv, ce);
+ if (fi_callback_data->udata.get_type() != Variant::NIL) {
+ fi_callback_data->callable.call(vp, 2, rv, ce);
} else {
- fi_callback->callable.call(vp, 1, rv, ce);
+ fi_callback_data->callable.call(vp, 1, rv, ce);
}
}
}
+
+ if (body_state_callback) {
+ (body_state_callback)(body_state_callback_instance, get_direct_state());
+ }
}
bool Body2DSW::sleep_test(real_t p_step) {
@@ -587,17 +588,30 @@ bool Body2DSW::sleep_test(real_t p_step) {
}
}
+void Body2DSW::set_state_sync_callback(void *p_instance, PhysicsServer2D::BodyStateCallback p_callback) {
+ body_state_callback_instance = p_instance;
+ body_state_callback = p_callback;
+}
+
void Body2DSW::set_force_integration_callback(const Callable &p_callable, const Variant &p_udata) {
- if (fi_callback) {
- memdelete(fi_callback);
- fi_callback = nullptr;
+ if (p_callable.get_object()) {
+ if (!fi_callback_data) {
+ fi_callback_data = memnew(ForceIntegrationCallbackData);
+ }
+ fi_callback_data->callable = p_callable;
+ fi_callback_data->udata = p_udata;
+ } else if (fi_callback_data) {
+ memdelete(fi_callback_data);
+ fi_callback_data = nullptr;
}
+}
- if (p_callable.get_object()) {
- fi_callback = memnew(ForceIntegrationCallback);
- fi_callback->callable = p_callable;
- fi_callback->callback_udata = p_udata;
+PhysicsDirectBodyState2DSW *Body2DSW::get_direct_state() {
+ if (!direct_state) {
+ direct_state = memnew(PhysicsDirectBodyState2DSW);
+ direct_state->body = this;
}
+ return direct_state;
}
Body2DSW::Body2DSW() :
@@ -632,33 +646,13 @@ Body2DSW::Body2DSW() :
still_time = 0;
continuous_cd_mode = PhysicsServer2D::CCD_MODE_DISABLED;
can_sleep = true;
- fi_callback = nullptr;
}
Body2DSW::~Body2DSW() {
- if (fi_callback) {
- memdelete(fi_callback);
- }
-}
-
-PhysicsDirectBodyState2DSW *PhysicsDirectBodyState2DSW::singleton = nullptr;
-
-PhysicsDirectSpaceState2D *PhysicsDirectBodyState2DSW::get_space_state() {
- return body->get_space()->get_direct_state();
-}
-
-Variant PhysicsDirectBodyState2DSW::get_contact_collider_shape_metadata(int p_contact_idx) const {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Variant());
-
- if (!PhysicsServer2DSW::singletonsw->body_owner.owns(body->contacts[p_contact_idx].collider)) {
- return Variant();
+ if (fi_callback_data) {
+ memdelete(fi_callback_data);
}
- Body2DSW *other = PhysicsServer2DSW::singletonsw->body_owner.getornull(body->contacts[p_contact_idx].collider);
-
- int sidx = body->contacts[p_contact_idx].collider_shape;
- if (sidx < 0 || sidx >= other->get_shape_count()) {
- return Variant();
+ if (direct_state) {
+ memdelete(direct_state);
}
-
- return other->get_shape_metadata(sidx);
}
diff --git a/servers/physics_2d/body_2d_sw.h b/servers/physics_2d/body_2d_sw.h
index 30e14eb9c7..9cd53ceca1 100644
--- a/servers/physics_2d/body_2d_sw.h
+++ b/servers/physics_2d/body_2d_sw.h
@@ -38,6 +38,7 @@
#include "core/templates/vset.h"
class Constraint2DSW;
+class PhysicsDirectBodyState2DSW;
class Body2DSW : public CollisionObject2DSW {
PhysicsServer2D::BodyMode mode;
@@ -116,12 +117,17 @@ class Body2DSW : public CollisionObject2DSW {
Vector<Contact> contacts; //no contacts by default
int contact_count;
- struct ForceIntegrationCallback {
+ void *body_state_callback_instance = nullptr;
+ PhysicsServer2D::BodyStateCallback body_state_callback = nullptr;
+
+ struct ForceIntegrationCallbackData {
Callable callable;
- Variant callback_udata;
+ Variant udata;
};
- ForceIntegrationCallback *fi_callback;
+ ForceIntegrationCallbackData *fi_callback_data = nullptr;
+
+ PhysicsDirectBodyState2DSW *direct_state = nullptr;
uint64_t island_step;
@@ -130,8 +136,11 @@ class Body2DSW : public CollisionObject2DSW {
friend class PhysicsDirectBodyState2DSW; // i give up, too many functions to expose
public:
+ void set_state_sync_callback(void *p_instance, PhysicsServer2D::BodyStateCallback p_callback);
void set_force_integration_callback(const Callable &p_callable, const Variant &p_udata = Variant());
+ PhysicsDirectBodyState2DSW *get_direct_state();
+
_FORCE_INLINE_ void add_area(Area2DSW *p_area) {
int index = areas.find(AreaCMP(p_area));
if (index > -1) {
@@ -332,87 +341,4 @@ void Body2DSW::add_contact(const Vector2 &p_local_pos, const Vector2 &p_local_no
c[idx].collider_velocity_at_pos = p_collider_velocity_at_pos;
}
-class PhysicsDirectBodyState2DSW : public PhysicsDirectBodyState2D {
- GDCLASS(PhysicsDirectBodyState2DSW, PhysicsDirectBodyState2D);
-
-public:
- static PhysicsDirectBodyState2DSW *singleton;
- Body2DSW *body;
- real_t step;
-
- virtual Vector2 get_total_gravity() const override { return body->gravity; } // get gravity vector working on this body space/area
- virtual real_t get_total_angular_damp() const override { return body->area_angular_damp; } // get density of this body space/area
- virtual real_t get_total_linear_damp() const override { return body->area_linear_damp; } // get density of this body space/area
-
- virtual real_t get_inverse_mass() const override { return body->get_inv_mass(); } // get the mass
- virtual real_t get_inverse_inertia() const override { return body->get_inv_inertia(); } // get density of this body space
-
- virtual void set_linear_velocity(const Vector2 &p_velocity) override { body->set_linear_velocity(p_velocity); }
- virtual Vector2 get_linear_velocity() const override { return body->get_linear_velocity(); }
-
- virtual void set_angular_velocity(real_t p_velocity) override { body->set_angular_velocity(p_velocity); }
- virtual real_t get_angular_velocity() const override { return body->get_angular_velocity(); }
-
- virtual void set_transform(const Transform2D &p_transform) override { body->set_state(PhysicsServer2D::BODY_STATE_TRANSFORM, p_transform); }
- virtual Transform2D get_transform() const override { return body->get_transform(); }
-
- virtual Vector2 get_velocity_at_local_position(const Vector2 &p_position) const override { return body->get_velocity_in_local_point(p_position); }
-
- virtual void add_central_force(const Vector2 &p_force) override { body->add_central_force(p_force); }
- virtual void add_force(const Vector2 &p_force, const Vector2 &p_position = Vector2()) override { body->add_force(p_force, p_position); }
- virtual void add_torque(real_t p_torque) override { body->add_torque(p_torque); }
- virtual void apply_central_impulse(const Vector2 &p_impulse) override { body->apply_central_impulse(p_impulse); }
- virtual void apply_impulse(const Vector2 &p_impulse, const Vector2 &p_position = Vector2()) override { body->apply_impulse(p_impulse, p_position); }
- virtual void apply_torque_impulse(real_t p_torque) override { body->apply_torque_impulse(p_torque); }
-
- virtual void set_sleep_state(bool p_enable) override { body->set_active(!p_enable); }
- virtual bool is_sleeping() const override { return !body->is_active(); }
-
- virtual int get_contact_count() const override { return body->contact_count; }
-
- virtual Vector2 get_contact_local_position(int p_contact_idx) const override {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector2());
- return body->contacts[p_contact_idx].local_pos;
- }
- virtual Vector2 get_contact_local_normal(int p_contact_idx) const override {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector2());
- return body->contacts[p_contact_idx].local_normal;
- }
- virtual int get_contact_local_shape(int p_contact_idx) const override {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, -1);
- return body->contacts[p_contact_idx].local_shape;
- }
-
- virtual RID get_contact_collider(int p_contact_idx) const override {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, RID());
- return body->contacts[p_contact_idx].collider;
- }
- virtual Vector2 get_contact_collider_position(int p_contact_idx) const override {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector2());
- return body->contacts[p_contact_idx].collider_pos;
- }
- virtual ObjectID get_contact_collider_id(int p_contact_idx) const override {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, ObjectID());
- return body->contacts[p_contact_idx].collider_instance_id;
- }
- virtual int get_contact_collider_shape(int p_contact_idx) const override {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, 0);
- return body->contacts[p_contact_idx].collider_shape;
- }
- virtual Variant get_contact_collider_shape_metadata(int p_contact_idx) const override;
-
- virtual Vector2 get_contact_collider_velocity_at_position(int p_contact_idx) const override {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector2());
- return body->contacts[p_contact_idx].collider_velocity_at_pos;
- }
-
- virtual PhysicsDirectSpaceState2D *get_space_state() override;
-
- virtual real_t get_step() const override { return step; }
- PhysicsDirectBodyState2DSW() {
- singleton = this;
- body = nullptr;
- }
-};
-
#endif // BODY_2D_SW_H
diff --git a/servers/physics_2d/body_direct_state_2d_sw.cpp b/servers/physics_2d/body_direct_state_2d_sw.cpp
new file mode 100644
index 0000000000..1f68cca843
--- /dev/null
+++ b/servers/physics_2d/body_direct_state_2d_sw.cpp
@@ -0,0 +1,182 @@
+/*************************************************************************/
+/* body_direct_state_2d_sw.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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. */
+/*************************************************************************/
+
+#include "body_direct_state_2d_sw.h"
+
+#include "body_2d_sw.h"
+#include "physics_server_2d_sw.h"
+#include "space_2d_sw.h"
+
+Vector2 PhysicsDirectBodyState2DSW::get_total_gravity() const {
+ return body->gravity;
+}
+
+real_t PhysicsDirectBodyState2DSW::get_total_angular_damp() const {
+ return body->area_angular_damp;
+}
+
+real_t PhysicsDirectBodyState2DSW::get_total_linear_damp() const {
+ return body->area_linear_damp;
+}
+
+real_t PhysicsDirectBodyState2DSW::get_inverse_mass() const {
+ return body->get_inv_mass();
+}
+
+real_t PhysicsDirectBodyState2DSW::get_inverse_inertia() const {
+ return body->get_inv_inertia();
+}
+
+void PhysicsDirectBodyState2DSW::set_linear_velocity(const Vector2 &p_velocity) {
+ body->set_linear_velocity(p_velocity);
+}
+
+Vector2 PhysicsDirectBodyState2DSW::get_linear_velocity() const {
+ return body->get_linear_velocity();
+}
+
+void PhysicsDirectBodyState2DSW::set_angular_velocity(real_t p_velocity) {
+ body->set_angular_velocity(p_velocity);
+}
+
+real_t PhysicsDirectBodyState2DSW::get_angular_velocity() const {
+ return body->get_angular_velocity();
+}
+
+void PhysicsDirectBodyState2DSW::set_transform(const Transform2D &p_transform) {
+ body->set_state(PhysicsServer2D::BODY_STATE_TRANSFORM, p_transform);
+}
+
+Transform2D PhysicsDirectBodyState2DSW::get_transform() const {
+ return body->get_transform();
+}
+
+Vector2 PhysicsDirectBodyState2DSW::get_velocity_at_local_position(const Vector2 &p_position) const {
+ return body->get_velocity_in_local_point(p_position);
+}
+
+void PhysicsDirectBodyState2DSW::add_central_force(const Vector2 &p_force) {
+ body->add_central_force(p_force);
+}
+
+void PhysicsDirectBodyState2DSW::add_force(const Vector2 &p_force, const Vector2 &p_position) {
+ body->add_force(p_force, p_position);
+}
+
+void PhysicsDirectBodyState2DSW::add_torque(real_t p_torque) {
+ body->add_torque(p_torque);
+}
+
+void PhysicsDirectBodyState2DSW::apply_central_impulse(const Vector2 &p_impulse) {
+ body->apply_central_impulse(p_impulse);
+}
+
+void PhysicsDirectBodyState2DSW::apply_impulse(const Vector2 &p_impulse, const Vector2 &p_position) {
+ body->apply_impulse(p_impulse, p_position);
+}
+
+void PhysicsDirectBodyState2DSW::apply_torque_impulse(real_t p_torque) {
+ body->apply_torque_impulse(p_torque);
+}
+
+void PhysicsDirectBodyState2DSW::set_sleep_state(bool p_enable) {
+ body->set_active(!p_enable);
+}
+
+bool PhysicsDirectBodyState2DSW::is_sleeping() const {
+ return !body->is_active();
+}
+
+int PhysicsDirectBodyState2DSW::get_contact_count() const {
+ return body->contact_count;
+}
+
+Vector2 PhysicsDirectBodyState2DSW::get_contact_local_position(int p_contact_idx) const {
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector2());
+ return body->contacts[p_contact_idx].local_pos;
+}
+
+Vector2 PhysicsDirectBodyState2DSW::get_contact_local_normal(int p_contact_idx) const {
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector2());
+ return body->contacts[p_contact_idx].local_normal;
+}
+
+int PhysicsDirectBodyState2DSW::get_contact_local_shape(int p_contact_idx) const {
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, -1);
+ return body->contacts[p_contact_idx].local_shape;
+}
+
+RID PhysicsDirectBodyState2DSW::get_contact_collider(int p_contact_idx) const {
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, RID());
+ return body->contacts[p_contact_idx].collider;
+}
+Vector2 PhysicsDirectBodyState2DSW::get_contact_collider_position(int p_contact_idx) const {
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector2());
+ return body->contacts[p_contact_idx].collider_pos;
+}
+
+ObjectID PhysicsDirectBodyState2DSW::get_contact_collider_id(int p_contact_idx) const {
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, ObjectID());
+ return body->contacts[p_contact_idx].collider_instance_id;
+}
+
+int PhysicsDirectBodyState2DSW::get_contact_collider_shape(int p_contact_idx) const {
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, 0);
+ return body->contacts[p_contact_idx].collider_shape;
+}
+
+Vector2 PhysicsDirectBodyState2DSW::get_contact_collider_velocity_at_position(int p_contact_idx) const {
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector2());
+ return body->contacts[p_contact_idx].collider_velocity_at_pos;
+}
+
+Variant PhysicsDirectBodyState2DSW::get_contact_collider_shape_metadata(int p_contact_idx) const {
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Variant());
+
+ if (!PhysicsServer2DSW::singletonsw->body_owner.owns(body->contacts[p_contact_idx].collider)) {
+ return Variant();
+ }
+ Body2DSW *other = PhysicsServer2DSW::singletonsw->body_owner.getornull(body->contacts[p_contact_idx].collider);
+
+ int sidx = body->contacts[p_contact_idx].collider_shape;
+ if (sidx < 0 || sidx >= other->get_shape_count()) {
+ return Variant();
+ }
+
+ return other->get_shape_metadata(sidx);
+}
+
+PhysicsDirectSpaceState2D *PhysicsDirectBodyState2DSW::get_space_state() {
+ return body->get_space()->get_direct_state();
+}
+
+real_t PhysicsDirectBodyState2DSW::get_step() const {
+ return body->get_space()->get_last_step();
+}
diff --git a/servers/physics_2d/body_direct_state_2d_sw.h b/servers/physics_2d/body_direct_state_2d_sw.h
new file mode 100644
index 0000000000..aef9186086
--- /dev/null
+++ b/servers/physics_2d/body_direct_state_2d_sw.h
@@ -0,0 +1,91 @@
+/*************************************************************************/
+/* body_direct_state_2d_sw.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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 BODY_DIRECT_STATE_2D_SW_H
+#define BODY_DIRECT_STATE_2D_SW_H
+
+#include "servers/physics_server_2d.h"
+
+class Body2DSW;
+
+class PhysicsDirectBodyState2DSW : public PhysicsDirectBodyState2D {
+ GDCLASS(PhysicsDirectBodyState2DSW, PhysicsDirectBodyState2D);
+
+public:
+ Body2DSW *body = nullptr;
+
+ virtual Vector2 get_total_gravity() const override;
+ virtual real_t get_total_angular_damp() const override;
+ virtual real_t get_total_linear_damp() const override;
+
+ virtual real_t get_inverse_mass() const override;
+ virtual real_t get_inverse_inertia() const override;
+
+ virtual void set_linear_velocity(const Vector2 &p_velocity) override;
+ virtual Vector2 get_linear_velocity() const override;
+
+ virtual void set_angular_velocity(real_t p_velocity) override;
+ virtual real_t get_angular_velocity() const override;
+
+ virtual void set_transform(const Transform2D &p_transform) override;
+ virtual Transform2D get_transform() const override;
+
+ virtual Vector2 get_velocity_at_local_position(const Vector2 &p_position) const override;
+
+ virtual void add_central_force(const Vector2 &p_force) override;
+ virtual void add_force(const Vector2 &p_force, const Vector2 &p_position = Vector2()) override;
+ virtual void add_torque(real_t p_torque) override;
+ virtual void apply_central_impulse(const Vector2 &p_impulse) override;
+ virtual void apply_impulse(const Vector2 &p_impulse, const Vector2 &p_position = Vector2()) override;
+ virtual void apply_torque_impulse(real_t p_torque) override;
+
+ virtual void set_sleep_state(bool p_enable) override;
+ virtual bool is_sleeping() const override;
+
+ virtual int get_contact_count() const override;
+
+ virtual Vector2 get_contact_local_position(int p_contact_idx) const override;
+ virtual Vector2 get_contact_local_normal(int p_contact_idx) const override;
+ virtual int get_contact_local_shape(int p_contact_idx) const override;
+
+ virtual RID get_contact_collider(int p_contact_idx) const override;
+ virtual Vector2 get_contact_collider_position(int p_contact_idx) const override;
+ virtual ObjectID get_contact_collider_id(int p_contact_idx) const override;
+ virtual int get_contact_collider_shape(int p_contact_idx) const override;
+ virtual Variant get_contact_collider_shape_metadata(int p_contact_idx) const override;
+
+ virtual Vector2 get_contact_collider_velocity_at_position(int p_contact_idx) const override;
+
+ virtual PhysicsDirectSpaceState2D *get_space_state() override;
+
+ virtual real_t get_step() const override;
+};
+
+#endif // BODY_2D_SW_H
diff --git a/servers/physics_2d/physics_server_2d_sw.cpp b/servers/physics_2d/physics_server_2d_sw.cpp
index 813e5ddc17..85b5e40752 100644
--- a/servers/physics_2d/physics_server_2d_sw.cpp
+++ b/servers/physics_2d/physics_server_2d_sw.cpp
@@ -30,6 +30,7 @@
#include "physics_server_2d_sw.h"
+#include "body_direct_state_2d_sw.h"
#include "broad_phase_2d_bvh.h"
#include "collision_solver_2d_sw.h"
#include "core/config/project_settings.h"
@@ -926,6 +927,12 @@ int PhysicsServer2DSW::body_get_max_contacts_reported(RID p_body) const {
return body->get_max_contacts_reported();
}
+void PhysicsServer2DSW::body_set_state_sync_callback(RID p_body, void *p_instance, BodyStateCallback p_callback) {
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+ body->set_state_sync_callback(p_instance, p_callback);
+}
+
void PhysicsServer2DSW::body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata) {
Body2DSW *body = body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
@@ -960,17 +967,13 @@ bool PhysicsServer2DSW::body_test_motion(RID p_body, const Transform2D &p_from,
PhysicsDirectBodyState2D *PhysicsServer2DSW::body_get_direct_state(RID p_body) {
ERR_FAIL_COND_V_MSG((using_threads && !doing_sync), nullptr, "Body state is inaccessible right now, wait for iteration or physics process notification.");
- if (!body_owner.owns(p_body)) {
- return nullptr;
- }
-
Body2DSW *body = body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, nullptr);
+
ERR_FAIL_COND_V(!body->get_space(), nullptr);
ERR_FAIL_COND_V_MSG(body->get_space()->is_locked(), nullptr, "Body state is inaccessible right now, wait for iteration or physics process notification.");
- direct_state->body = body;
- return direct_state;
+ return body->get_direct_state();
}
/* JOINT API */
@@ -1234,10 +1237,8 @@ void PhysicsServer2DSW::set_collision_iterations(int p_iterations) {
void PhysicsServer2DSW::init() {
doing_sync = false;
- last_step = 0.001;
iterations = 8; // 8?
stepper = memnew(Step2DSW);
- direct_state = memnew(PhysicsDirectBodyState2DSW);
};
void PhysicsServer2DSW::step(real_t p_step) {
@@ -1247,8 +1248,6 @@ void PhysicsServer2DSW::step(real_t p_step) {
_update_shapes();
- last_step = p_step;
- PhysicsDirectBodyState2DSW::singleton->step = p_step;
island_count = 0;
active_objects = 0;
collision_pairs = 0;
@@ -1320,7 +1319,6 @@ void PhysicsServer2DSW::end_sync() {
void PhysicsServer2DSW::finish() {
memdelete(stepper);
- memdelete(direct_state);
};
void PhysicsServer2DSW::_update_shapes() {
diff --git a/servers/physics_2d/physics_server_2d_sw.h b/servers/physics_2d/physics_server_2d_sw.h
index c5b6d550d7..ef1306cf59 100644
--- a/servers/physics_2d/physics_server_2d_sw.h
+++ b/servers/physics_2d/physics_server_2d_sw.h
@@ -46,7 +46,6 @@ class PhysicsServer2DSW : public PhysicsServer2D {
bool active;
int iterations;
bool doing_sync;
- real_t last_step;
int island_count;
int active_objects;
@@ -59,8 +58,6 @@ class PhysicsServer2DSW : public PhysicsServer2D {
Step2DSW *stepper;
Set<const Space2DSW *> active_spaces;
- PhysicsDirectBodyState2DSW *direct_state;
-
mutable RID_PtrOwner<Shape2DSW, true> shape_owner;
mutable RID_PtrOwner<Space2DSW, true> space_owner;
mutable RID_PtrOwner<Area2DSW, true> area_owner;
@@ -242,7 +239,9 @@ public:
virtual void body_set_max_contacts_reported(RID p_body, int p_contacts) override;
virtual int body_get_max_contacts_reported(RID p_body) const override;
+ virtual void body_set_state_sync_callback(RID p_body, void *p_instance, BodyStateCallback p_callback) override;
virtual void body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata = Variant()) override;
+
virtual bool body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) override;
virtual void body_set_pickable(RID p_body, bool p_pickable) override;
diff --git a/servers/physics_2d/physics_server_2d_wrap_mt.h b/servers/physics_2d/physics_server_2d_wrap_mt.h
index 05d4ac64b0..6761e37daa 100644
--- a/servers/physics_2d/physics_server_2d_wrap_mt.h
+++ b/servers/physics_2d/physics_server_2d_wrap_mt.h
@@ -245,6 +245,7 @@ public:
FUNC2(body_set_omit_force_integration, RID, bool);
FUNC1RC(bool, body_is_omitting_force_integration, RID);
+ FUNC3(body_set_state_sync_callback, RID, void *, BodyStateCallback);
FUNC3(body_set_force_integration_callback, RID, const Callable &, const Variant &);
bool body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) override {
diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp
index c0493749e0..6c23f49928 100644
--- a/servers/physics_2d/space_2d_sw.cpp
+++ b/servers/physics_2d/space_2d_sw.cpp
@@ -634,7 +634,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
//fix for moving platforms (kinematic and dynamic), margin is increased by how much it moved in the given direction
Vector2 lv = b->get_linear_velocity();
//compute displacement from linear velocity
- Vector2 motion = lv * PhysicsDirectBodyState2DSW::singleton->step;
+ Vector2 motion = lv * last_step;
real_t motion_len = motion.length();
motion.normalize();
cbk.valid_depth += motion_len * MAX(motion.dot(-cbk.valid_dir), 0.0);
@@ -926,7 +926,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
//fix for moving platforms (kinematic and dynamic), margin is increased by how much it moved in the given direction
Vector2 lv = b->get_linear_velocity();
//compute displacement from linear velocity
- Vector2 motion = lv * PhysicsDirectBodyState2DSW::singleton->step;
+ Vector2 motion = lv * last_step;
real_t motion_len = motion.length();
motion.normalize();
rcd.valid_depth += motion_len * MAX(motion.dot(-rcd.valid_dir), 0.0);
diff --git a/servers/physics_2d/space_2d_sw.h b/servers/physics_2d/space_2d_sw.h
index 392df9b025..5de071a475 100644
--- a/servers/physics_2d/space_2d_sw.h
+++ b/servers/physics_2d/space_2d_sw.h
@@ -117,6 +117,8 @@ private:
bool locked;
+ real_t last_step = 0.001;
+
int island_count;
int active_objects;
int collision_pairs;
@@ -172,6 +174,9 @@ public:
void lock();
void unlock();
+ real_t get_last_step() const { return last_step; }
+ void set_last_step(real_t p_step) { last_step = p_step; }
+
void set_param(PhysicsServer2D::SpaceParameter p_param, real_t p_value);
real_t get_param(PhysicsServer2D::SpaceParameter p_param) const;
diff --git a/servers/physics_2d/step_2d_sw.cpp b/servers/physics_2d/step_2d_sw.cpp
index 8b30160cc1..0306ec5050 100644
--- a/servers/physics_2d/step_2d_sw.cpp
+++ b/servers/physics_2d/step_2d_sw.cpp
@@ -129,6 +129,8 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) {
p_space->setup(); //update inertias, etc
+ p_space->set_last_step(p_delta);
+
iterations = p_iterations;
delta = p_delta;
diff --git a/servers/physics_3d/body_3d_sw.cpp b/servers/physics_3d/body_3d_sw.cpp
index 397a38079b..7f62e4eb85 100644
--- a/servers/physics_3d/body_3d_sw.cpp
+++ b/servers/physics_3d/body_3d_sw.cpp
@@ -29,7 +29,9 @@
/*************************************************************************/
#include "body_3d_sw.h"
+
#include "area_3d_sw.h"
+#include "body_direct_state_3d_sw.h"
#include "space_3d_sw.h"
void Body3DSW::_update_inertia() {
@@ -536,7 +538,7 @@ void Body3DSW::integrate_velocities(real_t p_step) {
return;
}
- if (fi_callback) {
+ if (fi_callback_data || body_state_callback) {
get_space()->body_add_to_state_query_list(&direct_state_query_list);
}
@@ -593,11 +595,6 @@ void Body3DSW::integrate_velocities(real_t p_step) {
_set_inv_transform(get_transform().inverse());
_update_transform_dependant();
-
- /*
- if (fi_callback) {
- get_space()->body_add_to_state_query_list(&direct_state_query_list);
- */
}
/*
@@ -655,24 +652,23 @@ void Body3DSW::wakeup_neighbours() {
}
void Body3DSW::call_queries() {
- if (fi_callback) {
- PhysicsDirectBodyState3DSW *dbs = PhysicsDirectBodyState3DSW::singleton;
- dbs->body = this;
-
- Variant v = dbs;
-
- Object *obj = fi_callback->callable.get_object();
- if (!obj) {
+ if (fi_callback_data) {
+ if (!fi_callback_data->callable.get_object()) {
set_force_integration_callback(Callable());
} else {
- const Variant *vp[2] = { &v, &fi_callback->udata };
+ Variant direct_state_variant = get_direct_state();
+ const Variant *vp[2] = { &direct_state_variant, &fi_callback_data->udata };
Callable::CallError ce;
- int argc = (fi_callback->udata.get_type() == Variant::NIL) ? 1 : 2;
+ int argc = (fi_callback_data->udata.get_type() == Variant::NIL) ? 1 : 2;
Variant rv;
- fi_callback->callable.call(vp, argc, rv, ce);
+ fi_callback_data->callable.call(vp, argc, rv, ce);
}
}
+
+ if (body_state_callback_instance) {
+ (body_state_callback)(body_state_callback_instance, get_direct_state());
+ }
}
bool Body3DSW::sleep_test(real_t p_step) {
@@ -692,22 +688,34 @@ bool Body3DSW::sleep_test(real_t p_step) {
}
}
+void Body3DSW::set_state_sync_callback(void *p_instance, PhysicsServer3D::BodyStateCallback p_callback) {
+ body_state_callback_instance = p_instance;
+ body_state_callback = p_callback;
+}
+
void Body3DSW::set_force_integration_callback(const Callable &p_callable, const Variant &p_udata) {
- if (fi_callback) {
- memdelete(fi_callback);
- fi_callback = nullptr;
+ if (p_callable.get_object()) {
+ if (!fi_callback_data) {
+ fi_callback_data = memnew(ForceIntegrationCallbackData);
+ }
+ fi_callback_data->callable = p_callable;
+ fi_callback_data->udata = p_udata;
+ } else if (fi_callback_data) {
+ memdelete(fi_callback_data);
+ fi_callback_data = nullptr;
}
+}
- if (p_callable.get_object()) {
- fi_callback = memnew(ForceIntegrationCallback);
- fi_callback->callable = p_callable;
- fi_callback->udata = p_udata;
+PhysicsDirectBodyState3DSW *Body3DSW::get_direct_state() {
+ if (!direct_state) {
+ direct_state = memnew(PhysicsDirectBodyState3DSW);
+ direct_state->body = this;
}
+ return direct_state;
}
Body3DSW::Body3DSW() :
CollisionObject3DSW(TYPE_BODY),
-
active_list(this),
inertia_update_list(this),
direct_state_query_list(this) {
@@ -735,17 +743,13 @@ Body3DSW::Body3DSW() :
still_time = 0;
continuous_cd = false;
can_sleep = true;
- fi_callback = nullptr;
}
Body3DSW::~Body3DSW() {
- if (fi_callback) {
- memdelete(fi_callback);
+ if (fi_callback_data) {
+ memdelete(fi_callback_data);
+ }
+ if (direct_state) {
+ memdelete(direct_state);
}
-}
-
-PhysicsDirectBodyState3DSW *PhysicsDirectBodyState3DSW::singleton = nullptr;
-
-PhysicsDirectSpaceState3D *PhysicsDirectBodyState3DSW::get_space_state() {
- return body->get_space()->get_direct_state();
}
diff --git a/servers/physics_3d/body_3d_sw.h b/servers/physics_3d/body_3d_sw.h
index 130be2d42f..f58f40652b 100644
--- a/servers/physics_3d/body_3d_sw.h
+++ b/servers/physics_3d/body_3d_sw.h
@@ -28,14 +28,15 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef BODY_SW_H
-#define BODY_SW_H
+#ifndef BODY_3D_SW_H
+#define BODY_3D_SW_H
#include "area_3d_sw.h"
#include "collision_object_3d_sw.h"
#include "core/templates/vset.h"
class Constraint3DSW;
+class PhysicsDirectBodyState3DSW;
class Body3DSW : public CollisionObject3DSW {
PhysicsServer3D::BodyMode mode;
@@ -113,12 +114,17 @@ class Body3DSW : public CollisionObject3DSW {
Vector<Contact> contacts; //no contacts by default
int contact_count;
- struct ForceIntegrationCallback {
+ void *body_state_callback_instance = nullptr;
+ PhysicsServer3D::BodyStateCallback body_state_callback = nullptr;
+
+ struct ForceIntegrationCallbackData {
Callable callable;
Variant udata;
};
- ForceIntegrationCallback *fi_callback;
+ ForceIntegrationCallbackData *fi_callback_data = nullptr;
+
+ PhysicsDirectBodyState3DSW *direct_state = nullptr;
uint64_t island_step;
@@ -129,8 +135,11 @@ class Body3DSW : public CollisionObject3DSW {
friend class PhysicsDirectBodyState3DSW; // i give up, too many functions to expose
public:
+ void set_state_sync_callback(void *p_instance, PhysicsServer3D::BodyStateCallback p_callback);
void set_force_integration_callback(const Callable &p_callable, const Variant &p_udata = Variant());
+ PhysicsDirectBodyState3DSW *get_direct_state();
+
_FORCE_INLINE_ void add_area(Area3DSW *p_area) {
int index = areas.find(AreaCMP(p_area));
if (index > -1) {
@@ -349,96 +358,4 @@ void Body3DSW::add_contact(const Vector3 &p_local_pos, const Vector3 &p_local_no
c[idx].collider_velocity_at_pos = p_collider_velocity_at_pos;
}
-class PhysicsDirectBodyState3DSW : public PhysicsDirectBodyState3D {
- GDCLASS(PhysicsDirectBodyState3DSW, PhysicsDirectBodyState3D);
-
-public:
- static PhysicsDirectBodyState3DSW *singleton;
- Body3DSW *body;
- real_t step;
-
- virtual Vector3 get_total_gravity() const override { return body->gravity; } // get gravity vector working on this body space/area
- virtual real_t get_total_angular_damp() const override { return body->area_angular_damp; } // get density of this body space/area
- virtual real_t get_total_linear_damp() const override { return body->area_linear_damp; } // get density of this body space/area
-
- virtual Vector3 get_center_of_mass() const override { return body->get_center_of_mass(); }
- virtual Basis get_principal_inertia_axes() const override { return body->get_principal_inertia_axes(); }
-
- virtual real_t get_inverse_mass() const override { return body->get_inv_mass(); } // get the mass
- virtual Vector3 get_inverse_inertia() const override { return body->get_inv_inertia(); } // get density of this body space
- virtual Basis get_inverse_inertia_tensor() const override { return body->get_inv_inertia_tensor(); } // get density of this body space
-
- virtual void set_linear_velocity(const Vector3 &p_velocity) override { body->set_linear_velocity(p_velocity); }
- virtual Vector3 get_linear_velocity() const override { return body->get_linear_velocity(); }
-
- virtual void set_angular_velocity(const Vector3 &p_velocity) override { body->set_angular_velocity(p_velocity); }
- virtual Vector3 get_angular_velocity() const override { return body->get_angular_velocity(); }
-
- virtual void set_transform(const Transform3D &p_transform) override { body->set_state(PhysicsServer3D::BODY_STATE_TRANSFORM, p_transform); }
- virtual Transform3D get_transform() const override { return body->get_transform(); }
-
- virtual Vector3 get_velocity_at_local_position(const Vector3 &p_position) const override { return body->get_velocity_in_local_point(p_position); }
-
- virtual void add_central_force(const Vector3 &p_force) override { body->add_central_force(p_force); }
- virtual void add_force(const Vector3 &p_force, const Vector3 &p_position = Vector3()) override {
- body->add_force(p_force, p_position);
- }
- virtual void add_torque(const Vector3 &p_torque) override { body->add_torque(p_torque); }
- virtual void apply_central_impulse(const Vector3 &p_impulse) override { body->apply_central_impulse(p_impulse); }
- virtual void apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position = Vector3()) override {
- body->apply_impulse(p_impulse, p_position);
- }
- virtual void apply_torque_impulse(const Vector3 &p_impulse) override { body->apply_torque_impulse(p_impulse); }
-
- virtual void set_sleep_state(bool p_sleep) override { body->set_active(!p_sleep); }
- virtual bool is_sleeping() const override { return !body->is_active(); }
-
- virtual int get_contact_count() const override { return body->contact_count; }
-
- virtual Vector3 get_contact_local_position(int p_contact_idx) const override {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector3());
- return body->contacts[p_contact_idx].local_pos;
- }
- virtual Vector3 get_contact_local_normal(int p_contact_idx) const override {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector3());
- return body->contacts[p_contact_idx].local_normal;
- }
- virtual real_t get_contact_impulse(int p_contact_idx) const override {
- return 0.0f; // Only implemented for bullet
- }
- virtual int get_contact_local_shape(int p_contact_idx) const override {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, -1);
- return body->contacts[p_contact_idx].local_shape;
- }
-
- virtual RID get_contact_collider(int p_contact_idx) const override {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, RID());
- return body->contacts[p_contact_idx].collider;
- }
- virtual Vector3 get_contact_collider_position(int p_contact_idx) const override {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector3());
- return body->contacts[p_contact_idx].collider_pos;
- }
- virtual ObjectID get_contact_collider_id(int p_contact_idx) const override {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, ObjectID());
- return body->contacts[p_contact_idx].collider_instance_id;
- }
- virtual int get_contact_collider_shape(int p_contact_idx) const override {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, 0);
- return body->contacts[p_contact_idx].collider_shape;
- }
- virtual Vector3 get_contact_collider_velocity_at_position(int p_contact_idx) const override {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector3());
- return body->contacts[p_contact_idx].collider_velocity_at_pos;
- }
-
- virtual PhysicsDirectSpaceState3D *get_space_state() override;
-
- virtual real_t get_step() const override { return step; }
- PhysicsDirectBodyState3DSW() {
- singleton = this;
- body = nullptr;
- }
-};
-
-#endif // BODY__SW_H
+#endif // BODY_3D_SW_H
diff --git a/servers/physics_3d/body_direct_state_3d_sw.cpp b/servers/physics_3d/body_direct_state_3d_sw.cpp
new file mode 100644
index 0000000000..d197dd288d
--- /dev/null
+++ b/servers/physics_3d/body_direct_state_3d_sw.cpp
@@ -0,0 +1,182 @@
+/*************************************************************************/
+/* body_direct_state_3d_sw.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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. */
+/*************************************************************************/
+
+#include "body_direct_state_3d_sw.h"
+
+#include "body_3d_sw.h"
+#include "space_3d_sw.h"
+
+Vector3 PhysicsDirectBodyState3DSW::get_total_gravity() const {
+ return body->gravity;
+}
+
+real_t PhysicsDirectBodyState3DSW::get_total_angular_damp() const {
+ return body->area_angular_damp;
+}
+
+real_t PhysicsDirectBodyState3DSW::get_total_linear_damp() const {
+ return body->area_linear_damp;
+}
+
+Vector3 PhysicsDirectBodyState3DSW::get_center_of_mass() const {
+ return body->get_center_of_mass();
+}
+
+Basis PhysicsDirectBodyState3DSW::get_principal_inertia_axes() const {
+ return body->get_principal_inertia_axes();
+}
+
+real_t PhysicsDirectBodyState3DSW::get_inverse_mass() const {
+ return body->get_inv_mass();
+}
+
+Vector3 PhysicsDirectBodyState3DSW::get_inverse_inertia() const {
+ return body->get_inv_inertia();
+}
+
+Basis PhysicsDirectBodyState3DSW::get_inverse_inertia_tensor() const {
+ return body->get_inv_inertia_tensor();
+}
+
+void PhysicsDirectBodyState3DSW::set_linear_velocity(const Vector3 &p_velocity) {
+ body->set_linear_velocity(p_velocity);
+}
+
+Vector3 PhysicsDirectBodyState3DSW::get_linear_velocity() const {
+ return body->get_linear_velocity();
+}
+
+void PhysicsDirectBodyState3DSW::set_angular_velocity(const Vector3 &p_velocity) {
+ body->set_angular_velocity(p_velocity);
+}
+
+Vector3 PhysicsDirectBodyState3DSW::get_angular_velocity() const {
+ return body->get_angular_velocity();
+}
+
+void PhysicsDirectBodyState3DSW::set_transform(const Transform3D &p_transform) {
+ body->set_state(PhysicsServer3D::BODY_STATE_TRANSFORM, p_transform);
+}
+
+Transform3D PhysicsDirectBodyState3DSW::get_transform() const {
+ return body->get_transform();
+}
+
+Vector3 PhysicsDirectBodyState3DSW::get_velocity_at_local_position(const Vector3 &p_position) const {
+ return body->get_velocity_in_local_point(p_position);
+}
+
+void PhysicsDirectBodyState3DSW::add_central_force(const Vector3 &p_force) {
+ body->add_central_force(p_force);
+}
+
+void PhysicsDirectBodyState3DSW::add_force(const Vector3 &p_force, const Vector3 &p_position) {
+ body->add_force(p_force, p_position);
+}
+
+void PhysicsDirectBodyState3DSW::add_torque(const Vector3 &p_torque) {
+ body->add_torque(p_torque);
+}
+
+void PhysicsDirectBodyState3DSW::apply_central_impulse(const Vector3 &p_impulse) {
+ body->apply_central_impulse(p_impulse);
+}
+
+void PhysicsDirectBodyState3DSW::apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position) {
+ body->apply_impulse(p_impulse, p_position);
+}
+
+void PhysicsDirectBodyState3DSW::apply_torque_impulse(const Vector3 &p_impulse) {
+ body->apply_torque_impulse(p_impulse);
+}
+
+void PhysicsDirectBodyState3DSW::set_sleep_state(bool p_sleep) {
+ body->set_active(!p_sleep);
+}
+
+bool PhysicsDirectBodyState3DSW::is_sleeping() const {
+ return !body->is_active();
+}
+
+int PhysicsDirectBodyState3DSW::get_contact_count() const {
+ return body->contact_count;
+}
+
+Vector3 PhysicsDirectBodyState3DSW::get_contact_local_position(int p_contact_idx) const {
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector3());
+ return body->contacts[p_contact_idx].local_pos;
+}
+
+Vector3 PhysicsDirectBodyState3DSW::get_contact_local_normal(int p_contact_idx) const {
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector3());
+ return body->contacts[p_contact_idx].local_normal;
+}
+
+real_t PhysicsDirectBodyState3DSW::get_contact_impulse(int p_contact_idx) const {
+ return 0.0f; // Only implemented for bullet
+}
+
+int PhysicsDirectBodyState3DSW::get_contact_local_shape(int p_contact_idx) const {
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, -1);
+ return body->contacts[p_contact_idx].local_shape;
+}
+
+RID PhysicsDirectBodyState3DSW::get_contact_collider(int p_contact_idx) const {
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, RID());
+ return body->contacts[p_contact_idx].collider;
+}
+
+Vector3 PhysicsDirectBodyState3DSW::get_contact_collider_position(int p_contact_idx) const {
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector3());
+ return body->contacts[p_contact_idx].collider_pos;
+}
+
+ObjectID PhysicsDirectBodyState3DSW::get_contact_collider_id(int p_contact_idx) const {
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, ObjectID());
+ return body->contacts[p_contact_idx].collider_instance_id;
+}
+
+int PhysicsDirectBodyState3DSW::get_contact_collider_shape(int p_contact_idx) const {
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, 0);
+ return body->contacts[p_contact_idx].collider_shape;
+}
+
+Vector3 PhysicsDirectBodyState3DSW::get_contact_collider_velocity_at_position(int p_contact_idx) const {
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector3());
+ return body->contacts[p_contact_idx].collider_velocity_at_pos;
+}
+
+PhysicsDirectSpaceState3D *PhysicsDirectBodyState3DSW::get_space_state() {
+ return body->get_space()->get_direct_state();
+}
+
+real_t PhysicsDirectBodyState3DSW::get_step() const {
+ return body->get_space()->get_last_step();
+}
diff --git a/servers/physics_3d/body_direct_state_3d_sw.h b/servers/physics_3d/body_direct_state_3d_sw.h
new file mode 100644
index 0000000000..5132376715
--- /dev/null
+++ b/servers/physics_3d/body_direct_state_3d_sw.h
@@ -0,0 +1,94 @@
+/*************************************************************************/
+/* body_direct_state_3d_sw.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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 BODY_DIRECT_STATE_3D_SW_H
+#define BODY_DIRECT_STATE_3D_SW_H
+
+#include "servers/physics_server_3d.h"
+
+class Body3DSW;
+
+class PhysicsDirectBodyState3DSW : public PhysicsDirectBodyState3D {
+ GDCLASS(PhysicsDirectBodyState3DSW, PhysicsDirectBodyState3D);
+
+public:
+ Body3DSW *body = nullptr;
+
+ virtual Vector3 get_total_gravity() const override;
+ virtual real_t get_total_angular_damp() const override;
+ virtual real_t get_total_linear_damp() const override;
+
+ virtual Vector3 get_center_of_mass() const override;
+ virtual Basis get_principal_inertia_axes() const override;
+
+ virtual real_t get_inverse_mass() const override;
+ virtual Vector3 get_inverse_inertia() const override;
+ virtual Basis get_inverse_inertia_tensor() const override;
+
+ virtual void set_linear_velocity(const Vector3 &p_velocity) override;
+ virtual Vector3 get_linear_velocity() const override;
+
+ virtual void set_angular_velocity(const Vector3 &p_velocity) override;
+ virtual Vector3 get_angular_velocity() const override;
+
+ virtual void set_transform(const Transform3D &p_transform) override;
+ virtual Transform3D get_transform() const override;
+
+ virtual Vector3 get_velocity_at_local_position(const Vector3 &p_position) const override;
+
+ virtual void add_central_force(const Vector3 &p_force) override;
+ virtual void add_force(const Vector3 &p_force, const Vector3 &p_position = Vector3()) override;
+ virtual void add_torque(const Vector3 &p_torque) override;
+ virtual void apply_central_impulse(const Vector3 &p_impulse) override;
+ virtual void apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position = Vector3()) override;
+ virtual void apply_torque_impulse(const Vector3 &p_impulse) override;
+
+ virtual void set_sleep_state(bool p_sleep) override;
+ virtual bool is_sleeping() const override;
+
+ virtual int get_contact_count() const override;
+
+ virtual Vector3 get_contact_local_position(int p_contact_idx) const override;
+ virtual Vector3 get_contact_local_normal(int p_contact_idx) const override;
+ virtual real_t get_contact_impulse(int p_contact_idx) const override;
+ virtual int get_contact_local_shape(int p_contact_idx) const override;
+
+ virtual RID get_contact_collider(int p_contact_idx) const override;
+ virtual Vector3 get_contact_collider_position(int p_contact_idx) const override;
+ virtual ObjectID get_contact_collider_id(int p_contact_idx) const override;
+ virtual int get_contact_collider_shape(int p_contact_idx) const override;
+ virtual Vector3 get_contact_collider_velocity_at_position(int p_contact_idx) const override;
+
+ virtual PhysicsDirectSpaceState3D *get_space_state() override;
+
+ virtual real_t get_step() const override;
+};
+
+#endif // BODY_DIRECT_STATE_3D_SW_H
diff --git a/servers/physics_3d/physics_server_3d_sw.cpp b/servers/physics_3d/physics_server_3d_sw.cpp
index fbc6f7eee8..a214e80c6c 100644
--- a/servers/physics_3d/physics_server_3d_sw.cpp
+++ b/servers/physics_3d/physics_server_3d_sw.cpp
@@ -30,6 +30,7 @@
#include "physics_server_3d_sw.h"
+#include "body_direct_state_3d_sw.h"
#include "broad_phase_3d_bvh.h"
#include "core/debugger/engine_debugger.h"
#include "core/os/os.h"
@@ -842,6 +843,12 @@ int PhysicsServer3DSW::body_get_max_contacts_reported(RID p_body) const {
return body->get_max_contacts_reported();
}
+void PhysicsServer3DSW::body_set_state_sync_callback(RID p_body, void *p_instance, BodyStateCallback p_callback) {
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+ body->set_state_sync_callback(p_instance, p_callback);
+}
+
void PhysicsServer3DSW::body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata) {
Body3DSW *body = body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
@@ -869,11 +876,12 @@ PhysicsDirectBodyState3D *PhysicsServer3DSW::body_get_direct_state(RID p_body) {
ERR_FAIL_COND_V_MSG((using_threads && !doing_sync), nullptr, "Body state is inaccessible right now, wait for iteration or physics process notification.");
Body3DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, nullptr);
+ ERR_FAIL_NULL_V(body, nullptr);
+
+ ERR_FAIL_NULL_V(body->get_space(), nullptr);
ERR_FAIL_COND_V_MSG(body->get_space()->is_locked(), nullptr, "Body state is inaccessible right now, wait for iteration or physics process notification.");
- direct_state->body = body;
- return direct_state;
+ return body->get_direct_state();
}
/* SOFT BODY */
@@ -1578,10 +1586,8 @@ void PhysicsServer3DSW::set_collision_iterations(int p_iterations) {
};
void PhysicsServer3DSW::init() {
- last_step = 0.001;
iterations = 8; // 8?
stepper = memnew(Step3DSW);
- direct_state = memnew(PhysicsDirectBodyState3DSW);
};
void PhysicsServer3DSW::step(real_t p_step) {
@@ -1593,9 +1599,6 @@ void PhysicsServer3DSW::step(real_t p_step) {
_update_shapes();
- last_step = p_step;
- PhysicsDirectBodyState3DSW::singleton->step = p_step;
-
island_count = 0;
active_objects = 0;
collision_pairs = 0;
@@ -1671,7 +1674,6 @@ void PhysicsServer3DSW::end_sync() {
void PhysicsServer3DSW::finish() {
memdelete(stepper);
- memdelete(direct_state);
};
int PhysicsServer3DSW::get_process_info(ProcessInfo p_info) {
diff --git a/servers/physics_3d/physics_server_3d_sw.h b/servers/physics_3d/physics_server_3d_sw.h
index a18593c90c..f283f83112 100644
--- a/servers/physics_3d/physics_server_3d_sw.h
+++ b/servers/physics_3d/physics_server_3d_sw.h
@@ -44,7 +44,6 @@ class PhysicsServer3DSW : public PhysicsServer3D {
friend class PhysicsDirectSpaceState3DSW;
bool active;
int iterations;
- real_t last_step;
int island_count;
int active_objects;
@@ -57,8 +56,6 @@ class PhysicsServer3DSW : public PhysicsServer3D {
Step3DSW *stepper;
Set<const Space3DSW *> active_spaces;
- PhysicsDirectBodyState3DSW *direct_state;
-
mutable RID_PtrOwner<Shape3DSW, true> shape_owner;
mutable RID_PtrOwner<Space3DSW, true> space_owner;
mutable RID_PtrOwner<Area3DSW, true> area_owner;
@@ -238,6 +235,7 @@ public:
virtual void body_set_max_contacts_reported(RID p_body, int p_contacts) override;
virtual int body_get_max_contacts_reported(RID p_body) const override;
+ virtual void body_set_state_sync_callback(RID p_body, void *p_instance, BodyStateCallback p_callback) override;
virtual void body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata = Variant()) override;
virtual void body_set_ray_pickable(RID p_body, bool p_enable) override;
diff --git a/servers/physics_3d/physics_server_3d_wrap_mt.h b/servers/physics_3d/physics_server_3d_wrap_mt.h
index 674c52d4a3..8865bd4bd2 100644
--- a/servers/physics_3d/physics_server_3d_wrap_mt.h
+++ b/servers/physics_3d/physics_server_3d_wrap_mt.h
@@ -246,6 +246,7 @@ public:
FUNC2(body_set_omit_force_integration, RID, bool);
FUNC1RC(bool, body_is_omitting_force_integration, RID);
+ FUNC3(body_set_state_sync_callback, RID, void *, BodyStateCallback);
FUNC3(body_set_force_integration_callback, RID, const Callable &, const Variant &);
FUNC2(body_set_ray_pickable, RID, bool);
diff --git a/servers/physics_3d/space_3d_sw.h b/servers/physics_3d/space_3d_sw.h
index 1c3d1cf9f6..eff494a7bc 100644
--- a/servers/physics_3d/space_3d_sw.h
+++ b/servers/physics_3d/space_3d_sw.h
@@ -112,6 +112,8 @@ private:
bool locked;
+ real_t last_step = 0.001;
+
int island_count;
int active_objects;
int collision_pairs;
@@ -174,6 +176,9 @@ public:
void lock();
void unlock();
+ real_t get_last_step() const { return last_step; }
+ void set_last_step(real_t p_step) { last_step = p_step; }
+
void set_param(PhysicsServer3D::SpaceParameter p_param, real_t p_value);
real_t get_param(PhysicsServer3D::SpaceParameter p_param) const;
diff --git a/servers/physics_3d/step_3d_sw.cpp b/servers/physics_3d/step_3d_sw.cpp
index ba18bac611..d0604b0aa0 100644
--- a/servers/physics_3d/step_3d_sw.cpp
+++ b/servers/physics_3d/step_3d_sw.cpp
@@ -185,6 +185,8 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
p_space->setup(); //update inertias, etc
+ p_space->set_last_step(p_delta);
+
iterations = p_iterations;
delta = p_delta;
diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h
index 9afac0cbd1..021d7be7c0 100644
--- a/servers/physics_server_2d.h
+++ b/servers/physics_server_2d.h
@@ -457,6 +457,10 @@ public:
virtual void body_set_omit_force_integration(RID p_body, bool p_omit) = 0;
virtual bool body_is_omitting_force_integration(RID p_body) const = 0;
+ // Callback for C++ use only.
+ typedef void (*BodyStateCallback)(void *p_instance, PhysicsDirectBodyState2D *p_state);
+ virtual void body_set_state_sync_callback(RID p_body, void *p_instance, BodyStateCallback p_callback) = 0;
+
virtual void body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata = Variant()) = 0;
virtual bool body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) = 0;
diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h
index 8f83e360f2..a365802220 100644
--- a/servers/physics_server_3d.h
+++ b/servers/physics_server_3d.h
@@ -471,6 +471,10 @@ public:
virtual void body_set_omit_force_integration(RID p_body, bool p_omit) = 0;
virtual bool body_is_omitting_force_integration(RID p_body) const = 0;
+ // Callback for C++ use only.
+ typedef void (*BodyStateCallback)(void *p_instance, PhysicsDirectBodyState3D *p_state);
+ virtual void body_set_state_sync_callback(RID p_body, void *p_instance, BodyStateCallback p_callback) = 0;
+
virtual void body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata = Variant()) = 0;
virtual void body_set_ray_pickable(RID p_body, bool p_enable) = 0;
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
index 611f7c6494..1b730567d9 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -484,7 +484,7 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p
if (material_uniform_set != prev_material_uniform_set) {
// Update uniform set.
- if (RD::get_singleton()->uniform_set_is_valid(material_uniform_set)) { // Material may not have a uniform set.
+ if (material_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(material_uniform_set)) { // Material may not have a uniform set.
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_uniform_set, MATERIAL_UNIFORM_SET);
}
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
index 1b4052b622..276a44bc27 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -1982,7 +1982,7 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
if (material_uniform_set != prev_material_uniform_set) {
// Update uniform set.
- if (RD::get_singleton()->uniform_set_is_valid(material_uniform_set)) { // Material may not have a uniform set.
+ if (material_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(material_uniform_set)) { // Material may not have a uniform set.
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_uniform_set, MATERIAL_UNIFORM_SET);
}
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index 6267f684e3..647c348d9f 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -1102,7 +1102,7 @@ void RendererCanvasRenderRD::_render_items(RID p_to_render_target, int p_item_co
if (material_data->shader_data->version.is_valid() && material_data->shader_data->valid) {
pipeline_variants = &material_data->shader_data->pipeline_variants;
// Update uniform set.
- if (RD::get_singleton()->uniform_set_is_valid(material_data->uniform_set)) { // Material may not have a uniform set.
+ if (material_data->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(material_data->uniform_set)) { // Material may not have a uniform set.
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_data->uniform_set, MATERIAL_UNIFORM_SET);
}
} else {
diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp
index da84f615b2..c388da755c 100644
--- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp
@@ -288,7 +288,7 @@ void RendererSceneSkyRD::_render_sky(RD::DrawListID p_list, float p_time, RID p_
// Update uniform sets.
{
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, sky_scene_state.uniform_set, 0);
- if (RD::get_singleton()->uniform_set_is_valid(p_uniform_set)) { // Material may not have a uniform set.
+ if (p_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(p_uniform_set)) { // Material may not have a uniform set.
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_uniform_set, 1);
}
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_texture_set, 2);
diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
index 14a5a01054..ec0d25376f 100644
--- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
@@ -4848,7 +4848,7 @@ void RendererStorageRD::_particles_process(Particles *p_particles, double p_delt
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, p_particles->particles_material_uniform_set, 1);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, p_particles->collision_textures_uniform_set, 2);
- if (m->uniform_set.is_valid()) {
+ if (m->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(m->uniform_set)) {
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, m->uniform_set, 3);
}