diff --git a/doc/classes/PhysicsServer2D.xml b/doc/classes/PhysicsServer2D.xml index 8be92edbad26..7ae11793cc1a 100644 --- a/doc/classes/PhysicsServer2D.xml +++ b/doc/classes/PhysicsServer2D.xml @@ -935,6 +935,13 @@ Creates a 2D space in the physics server, and returns the [RID] that identifies it. A space contains bodies and areas, and controls the stepping of the physics simulation of the objects in it. + + + + + Flushes [param space]'s queries. It is necessary to call this method after calling [method space_step] with an active space from [code]_physics_process[/code]. Otherwise, call this method before calling [method space_step]. + + @@ -942,6 +949,14 @@ Returns the state of a space, a [PhysicsDirectSpaceState2D]. This object can be used for collision/intersection queries. + + + + + + Returns information about the current state of [param space]. See [enum ProcessInfo] for a list of available states. + + @@ -974,6 +989,15 @@ Sets the value of the given space parameter. See [enum SpaceParameter] for the list of available parameters. + + + + + + Manually advance [param space] forward in [param delta]. This technique can be used for speeding up physics simulations, as seen in advanced rollback-style networking, or for predicting outcomes in scenarios such as hitting a ball in a billiards game. + [b]Note:[/b] If call this method with an active [param space] from [code]_physics_process()[/code], you should call [method space_flush_queries] afterwards. Otherwise, call [method space_flush_queries] beforehand. + + diff --git a/doc/classes/PhysicsServer2DExtension.xml b/doc/classes/PhysicsServer2DExtension.xml index 8d9a17133733..1b8136612f92 100644 --- a/doc/classes/PhysicsServer2DExtension.xml +++ b/doc/classes/PhysicsServer2DExtension.xml @@ -882,6 +882,12 @@ + + + + + + @@ -900,6 +906,13 @@ + + + + + + + @@ -935,6 +948,13 @@ + + + + + + + diff --git a/doc/classes/PhysicsServer3D.xml b/doc/classes/PhysicsServer3D.xml index 32810b0daf35..9710ff5d703f 100644 --- a/doc/classes/PhysicsServer3D.xml +++ b/doc/classes/PhysicsServer3D.xml @@ -1026,6 +1026,13 @@ Creates a space. A space is a collection of parameters for the physics engine that can be assigned to an area or a body. It can be assigned to an area with [method area_set_space], or to a body with [method body_set_space]. + + + + + Flushes [param space]'s queries. It is necessary to call this method after calling [method space_step] with an active space from [code]_physics_process[/code]. Otherwise, call this method before calling [method space_step]. + + @@ -1033,6 +1040,14 @@ Returns the state of a space, a [PhysicsDirectSpaceState3D]. This object can be used to make collision/intersection queries. + + + + + + Returns information about the current state of [param space]. See [enum ProcessInfo] for a list of available states. + + @@ -1065,6 +1080,15 @@ Sets the value for a space parameter. A list of available parameters is on the [enum SpaceParameter] constants. + + + + + + Manually advance [param space] forward in [param delta]. This technique can be used for speeding up physics simulations, as seen in advanced rollback-style networking, or for predicting outcomes in scenarios such as hitting a ball in a billiards game. + [b]Note:[/b] If call this method with an active [param space] from [code]_physics_process()[/code], you should call [method space_flush_queries] afterwards. Otherwise, call [method space_flush_queries] beforehand. + + diff --git a/doc/classes/PhysicsServer3DExtension.xml b/doc/classes/PhysicsServer3DExtension.xml index e58a7ff9a8aa..c8e267274368 100644 --- a/doc/classes/PhysicsServer3DExtension.xml +++ b/doc/classes/PhysicsServer3DExtension.xml @@ -1214,6 +1214,12 @@ + + + + + + @@ -1232,6 +1238,13 @@ + + + + + + + @@ -1267,6 +1280,13 @@ + + + + + + + diff --git a/servers/extensions/physics_server_2d_extension.cpp b/servers/extensions/physics_server_2d_extension.cpp index f8e78d655f49..ec3c0ac2fd93 100644 --- a/servers/extensions/physics_server_2d_extension.cpp +++ b/servers/extensions/physics_server_2d_extension.cpp @@ -151,6 +151,8 @@ void PhysicsServer2DExtension::_bind_methods() { GDVIRTUAL_BIND(_space_create); GDVIRTUAL_BIND(_space_set_active, "space", "active"); GDVIRTUAL_BIND(_space_is_active, "space"); + GDVIRTUAL_BIND(_space_step, "space", "delta") + GDVIRTUAL_BIND(_space_flush_queries, "space") GDVIRTUAL_BIND(_space_set_param, "space", "param", "value"); GDVIRTUAL_BIND(_space_get_param, "space", "param"); @@ -342,6 +344,7 @@ void PhysicsServer2DExtension::_bind_methods() { GDVIRTUAL_BIND(_is_flushing_queries); GDVIRTUAL_BIND(_get_process_info, "process_info"); + GDVIRTUAL_BIND(_space_get_last_process_info, "space", "process_info"); } PhysicsServer2DExtension::PhysicsServer2DExtension() { diff --git a/servers/extensions/physics_server_2d_extension.h b/servers/extensions/physics_server_2d_extension.h index 6e0277a7c681..583504239530 100644 --- a/servers/extensions/physics_server_2d_extension.h +++ b/servers/extensions/physics_server_2d_extension.h @@ -227,6 +227,8 @@ class PhysicsServer2DExtension : public PhysicsServer2D { EXBIND0R(RID, space_create) EXBIND2(space_set_active, RID, bool) EXBIND1RC(bool, space_is_active, RID) + EXBIND2(space_step, RID, real_t) + EXBIND1(space_flush_queries, RID) EXBIND3(space_set_param, RID, SpaceParameter, real_t) EXBIND2RC(real_t, space_get_param, RID, SpaceParameter) @@ -448,6 +450,7 @@ class PhysicsServer2DExtension : public PhysicsServer2D { EXBIND0RC(bool, is_flushing_queries) EXBIND1R(int, get_process_info, ProcessInfo) + EXBIND2R(int, space_get_last_process_info, RID, ProcessInfo) PhysicsServer2DExtension(); ~PhysicsServer2DExtension(); diff --git a/servers/extensions/physics_server_3d_extension.cpp b/servers/extensions/physics_server_3d_extension.cpp index 0937021c641f..5e3a755b3130 100644 --- a/servers/extensions/physics_server_3d_extension.cpp +++ b/servers/extensions/physics_server_3d_extension.cpp @@ -157,6 +157,8 @@ void PhysicsServer3DExtension::_bind_methods() { GDVIRTUAL_BIND(_space_create); GDVIRTUAL_BIND(_space_set_active, "space", "active"); GDVIRTUAL_BIND(_space_is_active, "space"); + GDVIRTUAL_BIND(_space_step, "space", "delta") + GDVIRTUAL_BIND(_space_flush_queries, "space") GDVIRTUAL_BIND(_space_set_param, "space", "param", "value"); GDVIRTUAL_BIND(_space_get_param, "space", "param"); @@ -422,6 +424,7 @@ void PhysicsServer3DExtension::_bind_methods() { GDVIRTUAL_BIND(_is_flushing_queries); GDVIRTUAL_BIND(_get_process_info, "process_info"); + GDVIRTUAL_BIND(_space_get_last_process_info, "space", "process_info"); } PhysicsServer3DExtension::PhysicsServer3DExtension() { diff --git a/servers/extensions/physics_server_3d_extension.h b/servers/extensions/physics_server_3d_extension.h index eb8b62724582..8f7bb1b80535 100644 --- a/servers/extensions/physics_server_3d_extension.h +++ b/servers/extensions/physics_server_3d_extension.h @@ -233,6 +233,8 @@ class PhysicsServer3DExtension : public PhysicsServer3D { EXBIND0R(RID, space_create) EXBIND2(space_set_active, RID, bool) EXBIND1RC(bool, space_is_active, RID) + EXBIND2(space_step, RID, real_t) + EXBIND1(space_flush_queries, RID) EXBIND3(space_set_param, RID, SpaceParameter, real_t) EXBIND2RC(real_t, space_get_param, RID, SpaceParameter) @@ -536,6 +538,7 @@ class PhysicsServer3DExtension : public PhysicsServer3D { EXBIND0RC(bool, is_flushing_queries) EXBIND1R(int, get_process_info, ProcessInfo) + EXBIND2R(int, space_get_last_process_info, RID, ProcessInfo) PhysicsServer3DExtension(); ~PhysicsServer3DExtension(); diff --git a/servers/physics_2d/godot_physics_server_2d.cpp b/servers/physics_2d/godot_physics_server_2d.cpp index 8df17992ea4e..2717436f800f 100644 --- a/servers/physics_2d/godot_physics_server_2d.cpp +++ b/servers/physics_2d/godot_physics_server_2d.cpp @@ -245,6 +245,44 @@ bool GodotPhysicsServer2D::space_is_active(RID p_space) const { return active_spaces.has(space); } +void GodotPhysicsServer2D::space_step(RID p_space, real_t p_delta) { + GodotSpace2D *space = space_owner.get_or_null(p_space); + ERR_FAIL_NULL(space); + + // TODO: + // May be let pending_shape_update_list as a member of GodotSpaces3D and update shapes by themselves. + // To avoid effecting Spces which are handled by developer (for lockstep/rollback netcode, it is particularly sensitive). + // Otherwise, call _update_shapes() directly. + SelfList *collision_object_self = pending_shape_update_list.first(); + while (collision_object_self) { + if (collision_object_self->self()->get_space() == space) { + collision_object_self->self()->_shape_changed(); + + SelfList *to_remove = collision_object_self; + collision_object_self = collision_object_self->next(); + + pending_shape_update_list.remove(to_remove); + } else { + collision_object_self = collision_object_self->next(); + } + } + + stepper->step(space, p_delta); +} + +void GodotPhysicsServer2D::space_flush_queries(RID p_space) { + // TODO:: + // Like _update_shapes(), to provide controllability for developers, flushing_queries flag should active as a member of space and check it for each space. + // But I'm not sure about that, I am not familiar with multi-threads and the architecture of GodotPhysics. + flushing_queries = true; + + GodotSpace2D *space = space_owner.get_or_null(p_space); + ERR_FAIL_NULL(space); + space->call_queries(); + + flushing_queries = false; +} + void GodotPhysicsServer2D::space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) { GodotSpace2D *space = space_owner.get_or_null(p_space); ERR_FAIL_NULL(space); @@ -1390,6 +1428,25 @@ int GodotPhysicsServer2D::get_process_info(ProcessInfo p_info) { return 0; } +int GodotPhysicsServer2D::space_get_last_process_info(RID p_space, ProcessInfo p_info) { + GodotSpace2D *space = space_owner.get_or_null(p_space); + ERR_FAIL_NULL_V(space, 0); + + switch (p_info) { + case INFO_ACTIVE_OBJECTS: { + return space->get_active_objects(); + } break; + case INFO_COLLISION_PAIRS: { + return space->get_collision_pairs(); + } break; + case INFO_ISLAND_COUNT: { + return space->get_island_count(); + } break; + } + + return 0; +} + GodotPhysicsServer2D *GodotPhysicsServer2D::godot_singleton = nullptr; GodotPhysicsServer2D::GodotPhysicsServer2D(bool p_using_threads) { diff --git a/servers/physics_2d/godot_physics_server_2d.h b/servers/physics_2d/godot_physics_server_2d.h index 991cf67c951f..300d23a348dc 100644 --- a/servers/physics_2d/godot_physics_server_2d.h +++ b/servers/physics_2d/godot_physics_server_2d.h @@ -108,6 +108,8 @@ class GodotPhysicsServer2D : public PhysicsServer2D { virtual RID space_create() override; virtual void space_set_active(RID p_space, bool p_active) override; virtual bool space_is_active(RID p_space) const override; + virtual void space_step(RID p_space, real_t p_delta) override; + virtual void space_flush_queries(RID p_space) override; virtual void space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) override; virtual real_t space_get_param(RID p_space, SpaceParameter p_param) const override; @@ -299,6 +301,7 @@ class GodotPhysicsServer2D : public PhysicsServer2D { virtual bool is_flushing_queries() const override { return flushing_queries; } int get_process_info(ProcessInfo p_info) override; + virtual int space_get_last_process_info(RID p_space, ProcessInfo p_info) override; GodotPhysicsServer2D(bool p_using_threads = false); ~GodotPhysicsServer2D() {} diff --git a/servers/physics_3d/godot_physics_server_3d.cpp b/servers/physics_3d/godot_physics_server_3d.cpp index 8a7b4e0f07b1..943f8cbe4d18 100644 --- a/servers/physics_3d/godot_physics_server_3d.cpp +++ b/servers/physics_3d/godot_physics_server_3d.cpp @@ -175,6 +175,44 @@ bool GodotPhysicsServer3D::space_is_active(RID p_space) const { return active_spaces.has(space); } +void GodotPhysicsServer3D::space_step(RID p_space, real_t p_delta) { + GodotSpace3D *space = space_owner.get_or_null(p_space); + ERR_FAIL_NULL(space); + + // TODO: + // May be let pending_shape_update_list as a member of GodotSpaces3D and update shapes by themselves. + // To avoid effecting Spces which are handled by developer (for lockstep/rollback netcode, it is particularly sensitive). + // If it is unnecessary, call _update_shapes() directly. + SelfList *collision_object_self = pending_shape_update_list.first(); + while (collision_object_self) { + if (collision_object_self->self()->get_space() == space) { + collision_object_self->self()->_shape_changed(); + + SelfList *to_remove = collision_object_self; + collision_object_self = collision_object_self->next(); + + pending_shape_update_list.remove(to_remove); + } else { + collision_object_self = collision_object_self->next(); + } + } + + stepper->step(space, p_delta); +} + +void GodotPhysicsServer3D::space_flush_queries(RID p_space) { + // TODO: + // Like _update_shapes(), to provide controllability for developers, flushing_queries flag should active as a member of space and check it for each space. + // But I'm not sure about that, I am not familiar with multi-threads and the architecture of GodotPhysics. + flushing_queries = true; + + GodotSpace3D *space = space_owner.get_or_null(p_space); + ERR_FAIL_NULL(space); + space->call_queries(); + + flushing_queries = false; +} + void GodotPhysicsServer3D::space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) { GodotSpace3D *space = space_owner.get_or_null(p_space); ERR_FAIL_NULL(space); @@ -1730,6 +1768,25 @@ int GodotPhysicsServer3D::get_process_info(ProcessInfo p_info) { return 0; } +int GodotPhysicsServer3D::space_get_last_process_info(RID p_space, ProcessInfo p_info) { + GodotSpace3D *space = space_owner.get_or_null(p_space); + ERR_FAIL_NULL_V(space, 0); + + switch (p_info) { + case INFO_ACTIVE_OBJECTS: { + return space->get_active_objects(); + } break; + case INFO_COLLISION_PAIRS: { + return space->get_collision_pairs(); + } break; + case INFO_ISLAND_COUNT: { + return space->get_island_count(); + } break; + } + + return 0; +} + void GodotPhysicsServer3D::_update_shapes() { while (pending_shape_update_list.first()) { pending_shape_update_list.first()->self()->_shape_changed(); diff --git a/servers/physics_3d/godot_physics_server_3d.h b/servers/physics_3d/godot_physics_server_3d.h index 040e673dcd82..3369774ed2c4 100644 --- a/servers/physics_3d/godot_physics_server_3d.h +++ b/servers/physics_3d/godot_physics_server_3d.h @@ -106,6 +106,8 @@ class GodotPhysicsServer3D : public PhysicsServer3D { virtual RID space_create() override; virtual void space_set_active(RID p_space, bool p_active) override; virtual bool space_is_active(RID p_space) const override; + virtual void space_step(RID p_space, real_t p_delta) override; + virtual void space_flush_queries(RID p_space) override; virtual void space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) override; virtual real_t space_get_param(RID p_space, SpaceParameter p_param) const override; @@ -377,6 +379,7 @@ class GodotPhysicsServer3D : public PhysicsServer3D { virtual bool is_flushing_queries() const override { return flushing_queries; } int get_process_info(ProcessInfo p_info) override; + virtual int space_get_last_process_info(RID p_space, ProcessInfo p_info) override; GodotPhysicsServer3D(bool p_using_threads = false); ~GodotPhysicsServer3D() {} diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp index aea0c52a630f..852d623186b6 100644 --- a/servers/physics_server_2d.cpp +++ b/servers/physics_server_2d.cpp @@ -635,6 +635,8 @@ void PhysicsServer2D::_bind_methods() { ClassDB::bind_method(D_METHOD("space_create"), &PhysicsServer2D::space_create); ClassDB::bind_method(D_METHOD("space_set_active", "space", "active"), &PhysicsServer2D::space_set_active); ClassDB::bind_method(D_METHOD("space_is_active", "space"), &PhysicsServer2D::space_is_active); + ClassDB::bind_method(D_METHOD("space_step", "space", "delta"), &PhysicsServer2D::space_step); + ClassDB::bind_method(D_METHOD("space_flush_queries", "space"), &PhysicsServer2D::space_flush_queries); ClassDB::bind_method(D_METHOD("space_set_param", "space", "param", "value"), &PhysicsServer2D::space_set_param); ClassDB::bind_method(D_METHOD("space_get_param", "space", "param"), &PhysicsServer2D::space_get_param); ClassDB::bind_method(D_METHOD("space_get_direct_state", "space"), &PhysicsServer2D::space_get_direct_state); @@ -792,6 +794,7 @@ void PhysicsServer2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_active", "active"), &PhysicsServer2D::set_active); ClassDB::bind_method(D_METHOD("get_process_info", "process_info"), &PhysicsServer2D::get_process_info); + ClassDB::bind_method(D_METHOD("space_get_last_process_info", "space", "process_info"), &PhysicsServer2D::space_get_last_process_info); BIND_ENUM_CONSTANT(SPACE_PARAM_CONTACT_RECYCLE_RADIUS); BIND_ENUM_CONSTANT(SPACE_PARAM_CONTACT_MAX_SEPARATION); diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h index 67fc0ed899d5..13a6f283c7e7 100644 --- a/servers/physics_server_2d.h +++ b/servers/physics_server_2d.h @@ -253,6 +253,8 @@ class PhysicsServer2D : public Object { virtual RID space_create() = 0; virtual void space_set_active(RID p_space, bool p_active) = 0; virtual bool space_is_active(RID p_space) const = 0; + virtual void space_step(RID p_space, real_t p_delta) = 0; + virtual void space_flush_queries(RID p_space) = 0; enum SpaceParameter { SPACE_PARAM_CONTACT_RECYCLE_RADIUS, @@ -608,6 +610,7 @@ class PhysicsServer2D : public Object { }; virtual int get_process_info(ProcessInfo p_info) = 0; + virtual int space_get_last_process_info(RID p_space, ProcessInfo p_info) = 0; PhysicsServer2D(); ~PhysicsServer2D(); diff --git a/servers/physics_server_2d_wrap_mt.h b/servers/physics_server_2d_wrap_mt.h index 0ae004da198e..25c8a66bc205 100644 --- a/servers/physics_server_2d_wrap_mt.h +++ b/servers/physics_server_2d_wrap_mt.h @@ -104,6 +104,8 @@ class PhysicsServer2DWrapMT : public PhysicsServer2D { FUNCRID(space); FUNC2(space_set_active, RID, bool); FUNC1RC(bool, space_is_active, RID); + FUNC2(space_step, RID, real_t); + FUNC1(space_flush_queries, RID); FUNC3(space_set_param, RID, SpaceParameter, real_t); FUNC2RC(real_t, space_get_param, RID, SpaceParameter); @@ -321,10 +323,14 @@ class PhysicsServer2DWrapMT : public PhysicsServer2D { return physics_server_2d->is_flushing_queries(); } - int get_process_info(ProcessInfo p_info) override { + virtual int get_process_info(ProcessInfo p_info) override { return physics_server_2d->get_process_info(p_info); } + virtual int space_get_last_process_info(RID p_space, ProcessInfo p_info) override { + return physics_server_2d->space_get_last_process_info(p_space, p_info); + } + PhysicsServer2DWrapMT(PhysicsServer2D *p_contained, bool p_create_thread); ~PhysicsServer2DWrapMT(); diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp index d523f4b1ec41..26d7c44f93b8 100644 --- a/servers/physics_server_3d.cpp +++ b/servers/physics_server_3d.cpp @@ -709,6 +709,8 @@ void PhysicsServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("space_create"), &PhysicsServer3D::space_create); ClassDB::bind_method(D_METHOD("space_set_active", "space", "active"), &PhysicsServer3D::space_set_active); ClassDB::bind_method(D_METHOD("space_is_active", "space"), &PhysicsServer3D::space_is_active); + ClassDB::bind_method(D_METHOD("space_step", "space", "delta"), &PhysicsServer3D::space_step); + ClassDB::bind_method(D_METHOD("space_flush_queries", "space"), &PhysicsServer3D::space_flush_queries); ClassDB::bind_method(D_METHOD("space_set_param", "space", "param", "value"), &PhysicsServer3D::space_set_param); ClassDB::bind_method(D_METHOD("space_get_param", "space", "param"), &PhysicsServer3D::space_get_param); ClassDB::bind_method(D_METHOD("space_get_direct_state", "space"), &PhysicsServer3D::space_get_direct_state); @@ -967,6 +969,7 @@ void PhysicsServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_active", "active"), &PhysicsServer3D::set_active); ClassDB::bind_method(D_METHOD("get_process_info", "process_info"), &PhysicsServer3D::get_process_info); + ClassDB::bind_method(D_METHOD("space_get_last_process_info", "space", "process_info"), &PhysicsServer3D::space_get_last_process_info); BIND_ENUM_CONSTANT(SHAPE_WORLD_BOUNDARY); BIND_ENUM_CONSTANT(SHAPE_SEPARATION_RAY); diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h index 248b6cd8f804..9596101f3d9f 100644 --- a/servers/physics_server_3d.h +++ b/servers/physics_server_3d.h @@ -284,6 +284,8 @@ class PhysicsServer3D : public Object { virtual RID space_create() = 0; virtual void space_set_active(RID p_space, bool p_active) = 0; virtual bool space_is_active(RID p_space) const = 0; + virtual void space_step(RID p_space, real_t p_delta) = 0; + virtual void space_flush_queries(RID p_space) = 0; enum SpaceParameter { SPACE_PARAM_CONTACT_RECYCLE_RADIUS, @@ -809,6 +811,7 @@ class PhysicsServer3D : public Object { }; virtual int get_process_info(ProcessInfo p_info) = 0; + virtual int space_get_last_process_info(RID p_space, ProcessInfo p_info) = 0; PhysicsServer3D(); ~PhysicsServer3D(); diff --git a/servers/physics_server_3d_wrap_mt.h b/servers/physics_server_3d_wrap_mt.h index 99179d8248be..c5b5f1187e85 100644 --- a/servers/physics_server_3d_wrap_mt.h +++ b/servers/physics_server_3d_wrap_mt.h @@ -108,6 +108,8 @@ class PhysicsServer3DWrapMT : public PhysicsServer3D { FUNCRID(space); FUNC2(space_set_active, RID, bool); FUNC1RC(bool, space_is_active, RID); + FUNC2(space_step, RID, real_t); + FUNC1(space_flush_queries, RID); FUNC3(space_set_param, RID, SpaceParameter, real_t); FUNC2RC(real_t, space_get_param, RID, SpaceParameter); @@ -394,10 +396,14 @@ class PhysicsServer3DWrapMT : public PhysicsServer3D { return physics_server_3d->is_flushing_queries(); } - int get_process_info(ProcessInfo p_info) override { + virtual int get_process_info(ProcessInfo p_info) override { return physics_server_3d->get_process_info(p_info); } + virtual int space_get_last_process_info(RID p_space, ProcessInfo p_info) override { + return physics_server_3d->space_get_last_process_info(p_space, p_info); + } + PhysicsServer3DWrapMT(PhysicsServer3D *p_contained, bool p_create_thread); ~PhysicsServer3DWrapMT();