Fix airborne sitting and remote animation playback

This commit is contained in:
Alexander Sellite 2026-08-24 10:36:17 -04:00
parent a1ea341e8c
commit c65176b99f
3 changed files with 105 additions and 9 deletions

View file

@ -1036,7 +1036,13 @@ func _simulate_movement_physics(delta: float) -> void:
or (_network_authoritative_simulation and _network_jump_pending)
)
)
if _sit_after_landing and is_on_floor():
# 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.
if _sitting and not _can_begin_sitting():
_sit_after_landing = true
_set_sitting(false)
if _sit_after_landing and not jump_requested and _can_begin_sitting():
_sit_after_landing = false
_set_sitting(true, local_control_enabled)
if _sitting:
@ -1489,8 +1495,20 @@ func _update_character_animation() -> void:
_presented_animation_action_id = &""
_presented_animation_action_sequence = -1
_presented_animation_action_paused = false
if _character_animation_name == next_animation and not action_changed:
if (
_character_animation_playback_matches(
next_animation,
action_selected and animation_action_paused,
)
and not action_changed
):
return
# The animation name is only a selection cache. A remote player's
# AnimationPlayer can occasionally stop or lose its assigned animation while
# its replicated locomotion state remains valid. Reassert the selected
# presentation here instead of waiting for another network state transition;
# movement simulation and replication remain untouched.
_character_animation_player.active = true
_character_animation_player.play(next_animation)
_character_animation_name = next_animation
if action_selected:
@ -1513,6 +1531,26 @@ func _update_character_animation() -> void:
_character_animation_player.pause()
func _character_animation_playback_matches(
animation_name: StringName,
paused_action_selected: bool,
) -> bool:
if (
_character_animation_name != animation_name
or _character_animation_player.assigned_animation != animation_name
or not _character_animation_player.active
):
return false
if paused_action_selected:
return true
var animation := _character_animation_player.get_animation(animation_name)
if animation == null or animation.loop_mode == Animation.LOOP_NONE:
# Completed one-shot actions deliberately keep their final pose until the
# authoritative action state advances; they must not be restarted here.
return true
return _character_animation_player.is_playing()
func _on_character_animation_finished(animation_name: StringName) -> void:
if animation_name == CHARACTER_NET_STRIKE_ANIMATION:
if local_control_enabled:
@ -1610,7 +1648,7 @@ func toggle_sitting() -> void:
])
):
return
if not is_on_floor():
if not _can_begin_sitting():
_sit_after_landing = true
return
_set_sitting(should_sit, local_control_enabled)
@ -1645,7 +1683,15 @@ func is_sitting() -> bool:
return _sitting
func _can_begin_sitting() -> bool:
return is_on_floor() and velocity.y <= 0.0
func get_network_sitting_state() -> bool:
return _sitting
func get_network_sitting_intent() -> bool:
return _sitting or _sit_after_landing
@ -1654,7 +1700,9 @@ func apply_network_sitting_state(should_sit: bool) -> void:
func apply_authoritative_network_sitting_state(should_sit: bool) -> void:
if should_sit and not is_on_floor():
if should_sit and (
not _can_begin_sitting() or _network_jump_pending
):
_sit_after_landing = true
_set_sitting(false)
return
@ -2038,7 +2086,7 @@ func capture_network_input(sequence: int) -> Dictionary:
"sprint": false,
"sneak": false,
"slow_walk": false,
"sitting": get_network_sitting_state(),
"sitting": get_network_sitting_intent(),
"casting": (
_fishing_visual_phase == FishingVisualPhase.CASTING
),
@ -2063,7 +2111,7 @@ func capture_network_input(sequence: int) -> Dictionary:
"sprint": Input.is_action_pressed("sprint"),
"sneak": Input.is_action_pressed("sneak"),
"slow_walk": Input.is_action_pressed("slow_walk"),
"sitting": get_network_sitting_state(),
"sitting": get_network_sitting_intent(),
"casting": _fishing_visual_phase == FishingVisualPhase.CASTING,
"animation_action": _make_animation_action_state(),
}
@ -2111,7 +2159,7 @@ func get_network_input_state_hash() -> int:
Input.is_action_pressed("sprint"),
Input.is_action_pressed("sneak"),
Input.is_action_pressed("slow_walk"),
get_network_sitting_state(),
get_network_sitting_intent(),
_fishing_visual_phase == FishingVisualPhase.CASTING,
_animation_action_id,
_animation_action_sequence,