stabilize movement reconciliation states
This commit is contained in:
parent
1ab2a291d2
commit
135fd9110f
2 changed files with 156 additions and 9 deletions
|
|
@ -1036,6 +1036,8 @@ func _simulate_movement_physics(delta: float) -> void:
|
|||
or (_network_authoritative_simulation and _network_jump_pending)
|
||||
)
|
||||
)
|
||||
if jump_requested:
|
||||
_cancel_sitting_for_jump()
|
||||
# Sitting deliberately stops movement processing, so never allow a stale
|
||||
# grounded flag or a reconciled network state to leave an airborne avatar in
|
||||
# that early-return path. Preserve the intent and sit once landing is real.
|
||||
|
|
@ -1635,6 +1637,7 @@ func _complete_retract_animation() -> void:
|
|||
func toggle_sitting() -> void:
|
||||
if _sit_after_landing:
|
||||
_sit_after_landing = false
|
||||
_set_sitting(false, local_control_enabled)
|
||||
return
|
||||
var should_sit: bool = not _sitting
|
||||
if should_sit:
|
||||
|
|
@ -1667,12 +1670,12 @@ func _set_sitting(
|
|||
should_sit: bool,
|
||||
is_local_intent: bool = false,
|
||||
) -> void:
|
||||
if _sitting == should_sit:
|
||||
return
|
||||
_sitting = should_sit
|
||||
if is_local_intent:
|
||||
_sitting_intent_pending = true
|
||||
_sitting_intent_sequence = -1
|
||||
if _sitting == should_sit:
|
||||
return
|
||||
_sitting = should_sit
|
||||
if _sitting:
|
||||
velocity = Vector3.ZERO
|
||||
_character_animation_name = &""
|
||||
|
|
@ -1687,11 +1690,23 @@ func _can_begin_sitting() -> bool:
|
|||
return is_on_floor() and velocity.y <= 0.0
|
||||
|
||||
|
||||
func _cancel_sitting_for_jump() -> void:
|
||||
if not _sitting and not _sit_after_landing:
|
||||
return
|
||||
_sit_after_landing = false
|
||||
_set_sitting(false, local_control_enabled)
|
||||
|
||||
|
||||
func get_network_sitting_state() -> bool:
|
||||
return _sitting
|
||||
|
||||
|
||||
func get_network_sitting_intent() -> bool:
|
||||
# Jumping is an explicit cancellation of both a current sit and a deferred
|
||||
# sit. Input capture can run before the matching physics frame, so suppress
|
||||
# the stale seated bit as soon as the reliable jump intent is queued.
|
||||
if _local_network_jump_intent_pending:
|
||||
return false
|
||||
return _sitting or _sit_after_landing
|
||||
|
||||
|
||||
|
|
@ -2352,6 +2367,21 @@ func apply_local_prediction_correction(
|
|||
_local_prediction_hard_corrections += 1
|
||||
_reset_local_prediction_error()
|
||||
return
|
||||
if _should_defer_local_prediction_correction(parsed):
|
||||
# A host and its client do not reach the apex or landing on the same
|
||||
# frame. Correcting that expected vertical disagreement while either
|
||||
# side is airborne can pull the local body off narrow platforms.
|
||||
_reset_local_prediction_error()
|
||||
return
|
||||
# Both simulations agree the player is standing. Let ordinary floor motion
|
||||
# and gravity resolve the vertical component; a stale height sample must not
|
||||
# press a locally controlled player down or turn a horizontal correction
|
||||
# into an early floor collision.
|
||||
error_offset.y = 0.0
|
||||
error_distance = error_offset.length()
|
||||
if error_distance <= LOCAL_PREDICTION_CORRECTION_THRESHOLD:
|
||||
_reset_local_prediction_error()
|
||||
return
|
||||
var error_direction: Vector3 = error_offset.normalized()
|
||||
if (
|
||||
not _local_prediction_error_direction.is_zero_approx()
|
||||
|
|
@ -2386,22 +2416,34 @@ func apply_local_prediction_correction(
|
|||
correction.normalized()
|
||||
* LOCAL_PREDICTION_MAX_SOFT_CORRECTION_STEP
|
||||
)
|
||||
_apply_camera_safe_local_correction(correction)
|
||||
_local_prediction_soft_corrections += 1
|
||||
if _apply_camera_safe_local_correction(correction):
|
||||
_local_prediction_soft_corrections += 1
|
||||
|
||||
|
||||
func _apply_camera_safe_local_correction(correction: Vector3) -> void:
|
||||
func _should_defer_local_prediction_correction(parsed: Dictionary) -> bool:
|
||||
if not bool(parsed.get("grounded", true)):
|
||||
return true
|
||||
return _local_network_jump_intent_pending or not is_on_floor()
|
||||
|
||||
|
||||
func _apply_camera_safe_local_correction(correction: Vector3) -> bool:
|
||||
if correction.is_zero_approx():
|
||||
return
|
||||
return false
|
||||
var previous_visual_position: Vector3 = _visuals.global_position
|
||||
var previous_camera_position: Vector3 = _camera_yaw.global_position
|
||||
var previous_body_position: Vector3 = global_position
|
||||
var base_visual_local_position: Vector3 = (
|
||||
_visuals.position - _local_reconciliation_visual_offset
|
||||
)
|
||||
var base_camera_local_position: Vector3 = (
|
||||
_camera_yaw.position - _local_reconciliation_camera_offset
|
||||
)
|
||||
global_position += correction
|
||||
# Reconciliation is still physical movement. Going through the physics
|
||||
# server prevents a delayed host audit from placing the capsule through a
|
||||
# tree, cliff, or stepping stone on the way to the authoritative position.
|
||||
move_and_collide(correction)
|
||||
if global_position.is_equal_approx(previous_body_position):
|
||||
return false
|
||||
_visuals.global_position = previous_visual_position
|
||||
_camera_yaw.global_position = previous_camera_position
|
||||
_local_reconciliation_visual_offset = (
|
||||
|
|
@ -2410,6 +2452,7 @@ func _apply_camera_safe_local_correction(correction: Vector3) -> void:
|
|||
_local_reconciliation_camera_offset = (
|
||||
_camera_yaw.position - base_camera_local_position
|
||||
)
|
||||
return true
|
||||
|
||||
|
||||
func _reset_local_prediction_error() -> void:
|
||||
|
|
@ -2625,6 +2668,9 @@ func _parse_network_snapshot(snapshot: Dictionary) -> Dictionary:
|
|||
if snapshot.has("casting") and typeof(snapshot.get("casting")) != TYPE_BOOL:
|
||||
return {}
|
||||
var casting: bool = bool(snapshot.get("casting", false))
|
||||
if snapshot.has("grounded") and typeof(snapshot.get("grounded")) != TYPE_BOOL:
|
||||
return {}
|
||||
var grounded: bool = bool(snapshot.get("grounded", true))
|
||||
if (
|
||||
not parsed_position.is_finite()
|
||||
or not parsed_velocity.is_finite()
|
||||
|
|
@ -2636,6 +2682,7 @@ func _parse_network_snapshot(snapshot: Dictionary) -> Dictionary:
|
|||
"velocity": parsed_velocity,
|
||||
"visual_yaw": visual_yaw,
|
||||
"animation_state": animation_state,
|
||||
"grounded": grounded,
|
||||
"acknowledged_input": acknowledged_input,
|
||||
"sitting": sitting,
|
||||
"casting": casting,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue