Unify fishing surfaces and presentation

This commit is contained in:
Alexander Sellite 2026-08-01 15:39:25 -04:00
parent c596b2aee7
commit 070765741c
19 changed files with 1705 additions and 372 deletions

View file

@ -0,0 +1,194 @@
extends SceneTree
const MainScene = preload("res://main/main.tscn")
const FishingSpotType = preload("res://fishing/fishing_spot.gd")
func _initialize() -> void:
call_deferred("_run")
func _run() -> void:
var arguments: PackedStringArray = OS.get_cmdline_user_args()
if arguments.has("host"):
await _run_host()
return
if arguments.has("client"):
await _run_client()
return
push_error("Fishing multiplayer validation requires host or client mode.")
quit(1)
func _run_host() -> void:
var main: Node = await _create_initialized_main()
assert(bool(main.call("_prepare_private_host")))
var save_manager := main.get("_save_manager") as PlayerSaveManager
assert(save_manager.initialize_new_game())
main.call("_enter_gameplay")
var session := main.get_node("%NetworkSession") as NetworkSession
assert(session.set_host_open(true))
var service := main.get_node(
"%NetworkFishingService"
) as NetworkFishingService
var join_deadline: int = Time.get_ticks_msec() + 20000
while (
Time.get_ticks_msec() < join_deadline
and session.get_authenticated_peer_ids().size() < 2
):
await process_frame
assert(session.get_authenticated_peer_ids().size() == 2)
var remote_peer_id: int = 0
for peer_id: int in session.get_authenticated_peer_ids():
if peer_id != session.get_local_peer_id():
remote_peer_id = peer_id
break
assert(remote_peer_id > 1)
var spawn_service := main.get_node(
"%PlayerSpawnService"
) as PlayerSpawnService
var remote_avatar: Player = spawn_service.get_avatar(remote_peer_id)
assert(remote_avatar != null)
remote_avatar.global_position = Vector3(-0.5, 3.95, 2.1)
var remote_visuals := remote_avatar.get_node("Visuals") as Node3D
remote_visuals.rotation.y = PI * 0.5
session.publish_authoritative_teleport(remote_peer_id)
var saw_remote_attempt: bool = false
var remote_presentation: RemoteFishingPresentation
var attempt_deadline: int = Time.get_ticks_msec() + 12000
while Time.get_ticks_msec() < attempt_deadline:
await process_frame
var attempts: Dictionary = service.get("_attempts")
for peer_id: int in attempts:
if peer_id == session.get_local_peer_id():
continue
var attempt: NetworkFishingAttempt = attempts[peer_id]
assert(is_equal_approx(attempt.target.y, 2.51))
assert(attempt.bobber_position.y <= 2.51 + 0.001)
var presentations: Dictionary = service.get("_remote_presentations")
remote_presentation = presentations.get(peer_id)
assert(remote_presentation != null)
var remote_bobber := remote_presentation.get(
"_bobber"
) as MeshInstance3D
assert(remote_bobber.visible)
saw_remote_attempt = true
if saw_remote_attempt:
break
assert(saw_remote_attempt)
var return_deadline: int = Time.get_ticks_msec() + 5000
while (
Time.get_ticks_msec() < return_deadline
and service.has_peer_attempt(remote_peer_id)
):
await process_frame
assert(not service.has_peer_attempt(remote_peer_id))
assert(is_instance_valid(remote_presentation))
assert(remote_presentation.get("_return_tween") != null)
var completion_deadline: int = Time.get_ticks_msec() + 12000
while (
Time.get_ticks_msec() < completion_deadline
and session.get_authenticated_peer_ids().size() == 2
):
await process_frame
print("Fishing multiplayer host validation: PASS")
session.disconnect_session("")
main.queue_free()
await process_frame
quit()
func _run_client() -> void:
var main: Node = await _create_initialized_main()
main.call("_on_title_join_game_requested", "127.0.0.1:7777")
var session := main.get_node("%NetworkSession") as NetworkSession
var joined: bool = false
var join_deadline: int = Time.get_ticks_msec() + 20000
while Time.get_ticks_msec() < join_deadline:
await process_frame
if session.state == NetworkSession.State.VERIFYING_SERVER_IDENTITY:
main.call("_confirm_server_trust")
if session.is_joined_client() and bool(main.get("_gameplay_started")):
joined = true
break
assert(joined)
var service := main.get_node(
"%NetworkFishingService"
) as NetworkFishingService
var fishing_spot := main.get_node("%FishingSpot") as FishingSpotType
var player := main.get("_player") as Player
var placement_deadline: int = Time.get_ticks_msec() + 5000
while (
Time.get_ticks_msec() < placement_deadline
and player.global_position.distance_to(Vector3(-0.5, 3.95, 2.1))
> 0.25
):
await physics_frame
assert(player.global_position.distance_to(Vector3(-0.5, 3.95, 2.1)) <= 0.25)
assert(player.get_facing_direction().dot(Vector3.LEFT) > 0.99)
fishing_spot.call("_begin_aiming", player)
assert(player.is_movement_enabled())
fishing_spot.set("_cast_charge", 0.32)
fishing_spot.call("_update_cast_charge", 0.0)
var target: Vector3 = fishing_spot.get("_cast_target")
assert(fishing_spot.is_target_fishable(target))
assert(is_equal_approx(target.y, 2.51))
fishing_spot.call("_confirm_cast")
var accepted_deadline: int = Time.get_ticks_msec() + 6000
while (
Time.get_ticks_msec() < accepted_deadline
and fishing_spot.state != FishingSpotType.FishingState.WAITING_FOR_BITE
):
await process_frame
assert(fishing_spot.state == FishingSpotType.FishingState.WAITING_FOR_BITE)
assert(service.has_local_attempt())
fishing_spot.set("_withdrawal_input_held", true)
fishing_spot.set("_network_primary_input_held", true)
service.submit_local_input(true, true)
var return_deadline: int = Time.get_ticks_msec() + 5000
while (
Time.get_ticks_msec() < return_deadline
and fishing_spot.state != FishingSpotType.FishingState.RETURNING
):
await process_frame
assert(fishing_spot.state == FishingSpotType.FishingState.RETURNING)
var bobber := fishing_spot.get_node(
"FishingPresentation/Bobber"
) as MeshInstance3D
assert(bobber.visible)
var ready_deadline: int = Time.get_ticks_msec() + 3000
while (
Time.get_ticks_msec() < ready_deadline
and fishing_spot.state != FishingSpotType.FishingState.READY
):
await process_frame
assert(fishing_spot.state == FishingSpotType.FishingState.READY)
assert(player.is_movement_enabled())
assert(not bobber.visible)
print("Fishing multiplayer client validation: PASS")
session.disconnect_session("")
main.queue_free()
await process_frame
quit()
func _create_initialized_main() -> Node:
root.size = Vector2i(1280, 720)
var main := MainScene.instantiate()
root.add_child(main)
for _frame: int in 4:
await process_frame
if not bool(main.get("_application_initialized")):
main.call("_activate_selected_data_path", "", true)
for _frame: int in 8:
await process_frame
assert(bool(main.get("_application_initialized")))
return main