-
-
Notifications
You must be signed in to change notification settings - Fork 55
Stepping Physics with Rollback #437
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 33 commits
Commits
Show all changes
44 commits
Select commit
Hold shift + click to select a range
6c14525
Base classes for driving rapier via tick loop
albertok b47b710
init physics
albertok 681a728
support stepping PR
albertok 92f82b7
remove breaking types
elementbound eca1cc3
physics driver toggles
elementbound f1a7554
fxs
elementbound b2ff965
Merge branch 'foxssake:main' into step-physics-rapier
albertok a224fc6
Merge branch 'foxssake:main' into step-physics-rapier
albertok fd60ae0
state and rollback synchronizer compatible RigidBody classes
f2670d3
Overidable method for applying forces
ec0ec3d
warning fix
7ddf146
Merge branch 'foxssake:main' into step-physics-rapier
albertok 22258fe
Set state only if in rollback prepare phase
albertok e5fdfb0
flush queries before stepping in Godot PR
albertok 237d36e
docs
albertok b8accae
use groups to call network_rigid_bodies while stepping
albertok 9093b07
2D Godot physics driver
albertok 8f37a9c
uid files
albertok 4c9772b
touched docs up
albertok bd575d7
doc edits
albertok 093ed4c
Fix global space rollback
albertok cf72568
Merge branch 'foxssake:main' into step-physics-rapier
albertok 4e4e3c0
update docs regarding state-synchronizer
albertok a2f170e
snapshot only physics bodies in 3D
albertok 4ba030c
Update addons/netfox.extras/physics/godot_driver_2d.gd.off
albertok da57924
Update addons/netfox.extras/physics/network-rigid-body-2d.gd
albertok 3a6e9e5
Update addons/netfox.extras/physics/network-rigid-body-2d.gd
albertok 33481c3
Update addons/netfox.extras/physics/network-rigid-body-2d.gd
albertok 0c1b31e
performance tweaks
albertok d5a8ee4
Update addons/netfox.extras/physics/godot_driver_3d.gd.off
albertok f929fed
Update addons/netfox.extras/physics/godot_driver_2d.gd.off
albertok 29e86ac
Update addons/netfox.extras/physics/godot_driver_2d.gd.off
albertok d20499b
Merge branch 'main' into step-physics-rapier
albertok 748a345
Update docs/netfox.extras/guides/physics.md
albertok 5763610
Update addons/netfox.extras/physics/godot_driver_3d.gd.off
albertok 0570a52
Update addons/netfox.extras/physics/godot_driver_2d.gd.off
albertok 8df9035
fxs + ci
elementbound 5202049
bv
elementbound d73e04b
docs
elementbound ed6d9d9
Merge branch 'main' into step-physics-rapier
elementbound c1b869d
icons
elementbound 8123c03
disconnect signal handlers on exit tree
elementbound 11efc4c
Merge branch 'main' into step-physics-rapier
elementbound 6b5b541
docs
elementbound File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| extends PhysicsDriver | ||
|
|
||
| class_name PhysicsDriver2D | ||
|
|
||
| # Physics driver based on netfox ticks | ||
| # Requires a custom build of Godot with https://github.com/godotengine/godot/pull/76462 | ||
|
|
||
| var scene_collision_objects: Array = [] | ||
| var collision_objects_snapshots: Dictionary[int, Dictionary] = {} | ||
|
|
||
| func _init_physics_space() -> void: | ||
| physics_space = get_viewport().world_2d.space | ||
| PhysicsServer2D.space_set_active(physics_space, false) | ||
|
|
||
| get_tree().node_added.connect(node_added) | ||
| get_tree().node_removed.connect(node_removed) | ||
| scan_tree() | ||
|
|
||
| func _physics_step(delta) -> void: | ||
| PhysicsServer2D.space_flush_queries(physics_space) | ||
| PhysicsServer2D.space_step(physics_space, delta) | ||
|
|
||
| func _snapshot_space(tick: int) -> void: | ||
| var rid_states: Dictionary[RID, Array] = {} | ||
| for element in scene_collision_objects: | ||
| if element is CharacterBody2D: | ||
| element.force_update_transform() # force colliders to update | ||
|
|
||
| var rid = element.get_rid() | ||
| rid_states[rid] = get_body_states(rid) | ||
| snapshots[tick] = rid_states | ||
|
|
||
| func _rollback_space(tick) -> void: | ||
| if snapshots.has(tick): | ||
| var rid_states = snapshots[tick] | ||
| for rid in rid_states.keys(): | ||
| set_body_states(rid, rid_states[rid]) | ||
|
|
||
| for body in scene_collision_objects: | ||
| if body is CharacterBody2D: | ||
| body.force_update_transform() # force colliders to update | ||
albertok marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| func get_body_states(rid: RID) -> Array: | ||
| var body_state: Array = [Vector3.ZERO, Quaternion.IDENTITY, Vector3.ZERO, Vector3.ZERO] | ||
| body_state[0] = PhysicsServer2D.body_get_state(rid, PhysicsServer2D.BODY_STATE_TRANSFORM) | ||
| body_state[1] = PhysicsServer2D.body_get_state(rid, PhysicsServer2D.BODY_STATE_LINEAR_VELOCITY) | ||
| body_state[2] = PhysicsServer2D.body_get_state(rid, PhysicsServer2D.BODY_STATE_ANGULAR_VELOCITY) | ||
| body_state[3] = PhysicsServer2D.body_get_state(rid, PhysicsServer2D.BODY_STATE_SLEEPING) | ||
| return body_state | ||
|
|
||
| func set_body_states(rid: RID, body_state: Array) -> void: | ||
| PhysicsServer2D.body_set_state(rid, PhysicsServer2D.BODY_STATE_TRANSFORM, body_state[0]) | ||
| PhysicsServer2D.body_set_state(rid, PhysicsServer2D.BODY_STATE_LINEAR_VELOCITY, body_state[1]) | ||
| PhysicsServer2D.body_set_state(rid, PhysicsServer2D.BODY_STATE_ANGULAR_VELOCITY, body_state[2]) | ||
| PhysicsServer2D.body_set_state(rid, PhysicsServer2D.BODY_STATE_SLEEPING, body_state[3]) | ||
|
|
||
| func scan_tree(): | ||
| scene_collision_objects.clear() | ||
| scene_collision_objects = get_all_children(get_node('/root')) | ||
|
|
||
| func get_all_children(in_node: Node) -> Array: | ||
| var nodes = [] | ||
| nodes = in_node.find_children("*", "PhysicsBody2D", true, false) | ||
| return nodes | ||
|
|
||
| func node_added(node: Node) -> void: | ||
| if node is PhysicsBody2D: | ||
| scene_collision_objects.append(node) | ||
|
|
||
| func node_removed(node: Node) -> void: | ||
| if node is PhysicsBody2D: | ||
| scene_collision_objects.erase(node) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| uid://c8p8gymii2y5v |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| extends PhysicsDriver | ||
| class_name PhysicsDriver3D | ||
|
|
||
| # Physics driver based on netfox ticks | ||
| # Requires a custom build of Godot with https://github.com/godotengine/godot/pull/76462 | ||
|
|
||
| # Maps ticks ( int ) to global snapshots ( Dictionary<RID, Array> ) | ||
| var scene_collision_objects: Array = [] | ||
|
|
||
| func _init_physics_space() -> void: | ||
| physics_space = get_viewport().world_3d.space | ||
| PhysicsServer3D.space_set_active(physics_space, false) | ||
|
|
||
| get_tree().node_added.connect(node_added) | ||
| get_tree().node_removed.connect(node_removed) | ||
| scan_tree() | ||
|
|
||
| func _physics_step(delta) -> void: | ||
| PhysicsServer3D.space_flush_queries(physics_space) | ||
| PhysicsServer3D.space_step(physics_space, delta) | ||
|
|
||
| func _snapshot_space(tick: int) -> void: | ||
| # Maps RIDs to physics state ( Array ) | ||
| var rid_states := {} | ||
| for element in scene_collision_objects: | ||
| var rid = element.get_rid() | ||
| rid_states[rid] = get_body_states(rid) | ||
albertok marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| snapshots[tick] = rid_states | ||
|
|
||
| func _rollback_space(tick) -> void: | ||
| if snapshots.has(tick): | ||
| var rid_states = snapshots[tick] | ||
| for rid in rid_states.keys(): | ||
| set_body_states(rid, rid_states[rid]) | ||
albertok marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| for body in scene_collision_objects: | ||
| if body is CharacterBody3D: | ||
| body.force_update_transform() | ||
albertok marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
|
|
||
| func get_body_states(rid: RID) -> Array: | ||
| var body_state: Array = [Vector3.ZERO, Quaternion.IDENTITY, Vector3.ZERO, Vector3.ZERO] | ||
| body_state[0] = PhysicsServer3D.body_get_state(rid, PhysicsServer3D.BODY_STATE_TRANSFORM) | ||
| body_state[1] = PhysicsServer3D.body_get_state(rid, PhysicsServer3D.BODY_STATE_LINEAR_VELOCITY) | ||
| body_state[2] = PhysicsServer3D.body_get_state(rid, PhysicsServer3D.BODY_STATE_ANGULAR_VELOCITY) | ||
| body_state[3] = PhysicsServer3D.body_get_state(rid, PhysicsServer3D.BODY_STATE_SLEEPING) | ||
| return body_state | ||
|
|
||
| func set_body_states(rid: RID, body_state: Array) -> void: | ||
| PhysicsServer3D.body_set_state(rid, PhysicsServer3D.BODY_STATE_TRANSFORM, body_state[0]) | ||
| PhysicsServer3D.body_set_state(rid, PhysicsServer3D.BODY_STATE_LINEAR_VELOCITY, body_state[1]) | ||
| PhysicsServer3D.body_set_state(rid, PhysicsServer3D.BODY_STATE_ANGULAR_VELOCITY, body_state[2]) | ||
| PhysicsServer3D.body_set_state(rid, PhysicsServer3D.BODY_STATE_SLEEPING, body_state[3]) | ||
|
|
||
| func scan_tree(): | ||
| scene_collision_objects.clear() | ||
| scene_collision_objects = get_all_children(get_node('/root')) | ||
|
|
||
| func get_all_children(in_node: Node) -> Array: | ||
| var nodes = [] | ||
| nodes = in_node.find_children("*", "PhysicsBody3D", true, false) | ||
| return nodes | ||
|
|
||
| func node_added(node: Node) -> void: | ||
| if node is PhysicsBody3D: | ||
| scene_collision_objects.append(node) | ||
|
|
||
| func node_removed(node: Node) -> void: | ||
| if node is PhysicsBody3D: | ||
| scene_collision_objects.erase(node) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| uid://wr5ur5dqrkni |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| extends RigidBody2D | ||
|
|
||
| class_name NetworkRigidBody2D | ||
|
|
||
| ## A rollback / state synchronizer class for RigidBody2D. | ||
| ## Set state property path to physics_state to synchronize the state of this body. | ||
|
|
||
| @onready var direct_state = PhysicsServer2D.body_get_direct_state(get_rid()) | ||
|
|
||
| var physics_state: Array: | ||
| get: return get_state() | ||
| set(v): set_state(v) | ||
|
|
||
| enum { | ||
| ORIGIN, | ||
| ROT, | ||
| LIN_VEL, | ||
| ANG_VEL, | ||
| SLEEPING | ||
| } | ||
|
|
||
| func _notification(notification: int): | ||
| if notification == NOTIFICATION_READY: | ||
| add_to_group("network_rigid_body") | ||
|
|
||
| func get_state() -> Array: | ||
| var body_state: Array = [Vector3.ZERO, Quaternion.IDENTITY, Vector3.ZERO, Vector3.ZERO, false] | ||
| body_state[ORIGIN] = direct_state.transform.origin | ||
| body_state[ROT] = direct_state.transform.get_rotation() | ||
| body_state[LIN_VEL] = direct_state.linear_velocity | ||
| body_state[ANG_VEL] = direct_state.angular_velocity | ||
| body_state[SLEEPING] = direct_state.sleeping | ||
| return body_state | ||
|
|
||
| func set_state(remote_state: Array) -> void: | ||
| direct_state.transform = Transform2D(remote_state[ROT], remote_state[ORIGIN]) | ||
| direct_state.linear_velocity = remote_state[LIN_VEL] | ||
| direct_state.angular_velocity = remote_state[ANG_VEL] | ||
| direct_state.sleeping = remote_state[SLEEPING] | ||
|
|
||
| ## Override and apply any logic, forces or impulses to the rigid body as you would in physics_process | ||
| ## The physics engine will run its simulation during rollback_tick with other nodes | ||
| func _physics_rollback_tick(_delta, _tick): | ||
| pass |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| uid://c8hw7ol53m55g |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| extends RigidBody3D | ||
|
|
||
| class_name NetworkRigidBody3D | ||
|
|
||
| ## A rollback / state synchronizer class for RigidBody3D. | ||
| ## Set state property path to physics_state to synchronize the state of this body. | ||
|
|
||
| @onready var direct_state = PhysicsServer3D.body_get_direct_state(get_rid()) | ||
|
|
||
| var physics_state: Array: | ||
| get: return get_state() | ||
| set(v): set_state(v) | ||
|
|
||
| enum { | ||
| ORIGIN, | ||
| QUAT, | ||
| LIN_VEL, | ||
| ANG_VEL, | ||
| SLEEPING | ||
| } | ||
|
|
||
| func _notification(notification: int): | ||
| if notification == NOTIFICATION_READY: | ||
| add_to_group("network_rigid_body") | ||
|
|
||
| func get_state() -> Array: | ||
| var body_state: Array = [Vector3.ZERO, Quaternion.IDENTITY, Vector3.ZERO, Vector3.ZERO, false] | ||
| body_state[ORIGIN] = direct_state.transform.origin | ||
| body_state[QUAT] = direct_state.transform.basis.get_rotation_quaternion() | ||
| body_state[LIN_VEL] = direct_state.linear_velocity | ||
| body_state[ANG_VEL] = direct_state.angular_velocity | ||
| body_state[SLEEPING] = direct_state.sleeping | ||
| return body_state | ||
|
|
||
| func set_state(remote_state: Array) -> void: | ||
| direct_state.transform.origin = remote_state[ORIGIN] | ||
| direct_state.transform.basis = Basis(remote_state[QUAT]) | ||
| direct_state.linear_velocity = remote_state[LIN_VEL] | ||
| direct_state.angular_velocity = remote_state[ANG_VEL] | ||
| direct_state.sleeping = remote_state[SLEEPING] | ||
|
|
||
|
|
||
| ## Override and apply any logic, forces or impulses to the rigid body as you would in physics_process | ||
| ## The physics engine will run its simulation during rollback_tick with other nodes | ||
| func _physics_rollback_tick(_delta, _tick): | ||
| pass |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| uid://bklxcdyxgbjg2 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| extends Object | ||
|
|
||
| class PhysicsDriverToggle: | ||
| const INACTIVE_SUFFIX := ".off" | ||
|
|
||
| func get_name() -> String: | ||
| return "???" | ||
|
|
||
| func get_files() -> Array[String]: | ||
| return [] | ||
|
|
||
| func get_error_messages() -> Array[String]: | ||
| return [] | ||
|
|
||
| func is_enabled() -> bool: | ||
| return get_files().any(func(it): return FileAccess.file_exists(it)) | ||
|
|
||
| func toggle() -> Array[String]: | ||
| var errors := get_error_messages() | ||
| if not errors.is_empty(): | ||
| return errors | ||
|
|
||
| var enable := not is_enabled() | ||
|
|
||
| var uid_files := get_files().map(func(it): return it + ".uid") | ||
| var renames = (get_files() + uid_files).map(func(it): | ||
| if enable: return [it + INACTIVE_SUFFIX, it] | ||
| else: return [it, it + INACTIVE_SUFFIX] | ||
| ) | ||
|
|
||
| for rename in renames: | ||
| var result := DirAccess.rename_absolute(rename[0], rename[1]) | ||
| if result != OK: | ||
| errors.append( | ||
| "Failed rename \"%s\" -> \"%s\"; reason: %s" % | ||
| [rename[0], rename[1], error_string(result)] | ||
| ) | ||
| return errors | ||
|
|
||
| class RapierPhysicsDriverToggle extends PhysicsDriverToggle: | ||
| func get_name() -> String: | ||
| return "Rapier" | ||
|
|
||
| func get_files() -> Array[String]: | ||
| return [ | ||
| "res://addons/netfox.extras/physics/rapier_driver_2d.gd", | ||
| "res://addons/netfox.extras/physics/rapier_driver_3d.gd", | ||
| ] | ||
|
|
||
| func get_error_messages() -> Array[String]: | ||
| if not ClassDB.class_exists("RapierPhysicsServer2D") or not ClassDB.class_exists("RapierPhysicsServer3D"): | ||
| return ["Rapier physics is not available! Is the extension installed?"] | ||
| return [] | ||
|
|
||
| class GodotPhysicsDriverToggle extends PhysicsDriverToggle: | ||
| func get_name() -> String: | ||
| return "Godot" | ||
|
|
||
| func get_files() -> Array[String]: | ||
| return [ | ||
| "res://addons/netfox.extras/physics/godot_driver_3d.gd", | ||
| "res://addons/netfox.extras/physics/godot_driver_2d.gd" | ||
| ] | ||
|
|
||
| func get_error_messages() -> Array[String]: | ||
| if not PhysicsServer3D.has_method("space_step") or not PhysicsServer2D.has_method("space_step"): | ||
| return ["Physics stepping is not available! Is this the right Godot build?"] | ||
| return [] | ||
|
|
||
| static func all() -> Array[PhysicsDriverToggle]: | ||
| return [ | ||
| RapierPhysicsDriverToggle.new(), | ||
| GodotPhysicsDriverToggle.new() | ||
| ] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| uid://bu4ppfj0ovkbr |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.