fix: reset interrupted fishing state

This commit is contained in:
Alexander Sellite 2026-08-15 19:20:04 -04:00
parent d07adb530c
commit d7c887db21
3 changed files with 61 additions and 2 deletions

View file

@ -385,6 +385,24 @@ func set_gameplay_input_enabled(enabled: bool) -> void:
if not enabled: if not enabled:
_local_menu_input_owners.clear() _local_menu_input_owners.clear()
_stop_reeling_audio() _stop_reeling_audio()
# FishingSpot survives session and gameplay transitions. Restore the
# player's canonical movement state before input is disabled so a cast
# lock cannot follow that player into the next session.
reset_transient_state()
func reset_transient_state(restore_movement: bool = true) -> void:
var local_state_was_active: bool = (
state != FishingState.READY or _active_player != null
)
if local_state_was_active and _active_player == null and _local_player != null:
_local_player.set_fighting_visual(false)
_local_player.set_fishing_visual(false)
_local_player.end_catch_showcase(Callable(), true)
if restore_movement:
_local_player.set_movement_enabled(true)
_finalize_attempt_cleanup("", restore_movement)
_new_cast_press_armed = not Input.is_action_pressed("fish_primary")
func configure_accessibility_auto_click( func configure_accessibility_auto_click(
@ -1339,13 +1357,17 @@ func _cleanup_attempt(
_finalize_attempt_cleanup(cooldown_message) _finalize_attempt_cleanup(cooldown_message)
func _finalize_attempt_cleanup(cooldown_message: String) -> void: func _finalize_attempt_cleanup(
cooldown_message: String,
restore_movement: bool = true,
) -> void:
_showcase_restore_generation += 1 _showcase_restore_generation += 1
if _active_player != null: if _active_player != null:
_active_player.set_fighting_visual(false) _active_player.set_fighting_visual(false)
_active_player.set_fishing_visual(false) _active_player.set_fishing_visual(false)
_active_player.end_catch_showcase() _active_player.end_catch_showcase()
_active_player.set_movement_enabled(true) if restore_movement:
_active_player.set_movement_enabled(true)
_active_player = null _active_player = null
_state_time_remaining = 0.0 _state_time_remaining = 0.0
_cast_charge = 0.0 _cast_charge = 0.0
@ -1839,6 +1861,7 @@ func _on_network_session_state_changed(state_value: NetworkSession.State) -> voi
]: ]:
_stop_fight_audio() _stop_fight_audio()
_stop_reeling_audio() _stop_reeling_audio()
reset_transient_state()
func _start_fight_audio() -> void: func _start_fight_audio() -> void:

View file

@ -176,6 +176,31 @@ func _run() -> void:
assert(fishing_status.text.is_empty()) assert(fishing_status.text.is_empty())
assert(not fishing_status.visible) assert(not fishing_status.visible)
assert(not fishing_panel.visible) assert(not fishing_panel.visible)
var reset_test_deadline: int = Time.get_ticks_msec() + 3000
while (
Time.get_ticks_msec() < reset_test_deadline
and fishing_spot.state != FishingSpotType.FishingState.READY
):
await process_frame
assert(fishing_spot.state == FishingSpotType.FishingState.READY)
# Leaving a session during the cast presentation must release every local
# action and equipment lock. This is the same cleanup path used by an
# in-game server switch or a lost connection.
fishing_spot.call("_begin_aiming", player)
fishing_spot.set("_cast_charge", 0.32)
fishing_spot.call("_update_cast_charge", 0.0)
fishing_spot.call("_confirm_cast")
assert(fishing_spot.state == FishingSpotType.FishingState.CASTING)
assert(not player.is_movement_enabled())
fishing_spot.call(
"_on_network_session_state_changed",
NetworkSession.State.DISCONNECTING,
)
assert(fishing_spot.state == FishingSpotType.FishingState.READY)
assert(player.is_movement_enabled())
assert(fishing_spot.can_change_hotbar_selection())
assert(fishing_spot.can_open_fishing_shop())
print("Fishing authority validation: PASS") print("Fishing authority validation: PASS")
session.disconnect_session("") session.disconnect_session("")

View file

@ -146,6 +146,17 @@ func _run_host() -> void:
): ):
await process_frame await process_frame
assert(remote_animation_player.current_animation == &"retract_sit") assert(remote_animation_player.current_animation == &"retract_sit")
var retract_completion_deadline: int = Time.get_ticks_msec() + 5000
while (
Time.get_ticks_msec() < retract_completion_deadline
and not remote_avatar.is_retract_visual_complete()
):
await process_frame
assert(remote_avatar.is_retract_visual_complete())
# Give the client that owns the same presentation a frame boundary to finish
# local cleanup before the host intentionally tears down this test session.
for _frame: int in 4:
await physics_frame
print("Fishing multiplayer host validation: PASS") print("Fishing multiplayer host validation: PASS")
session.disconnect_session("") session.disconnect_session("")