Unify fishing surfaces and presentation
This commit is contained in:
parent
c596b2aee7
commit
070765741c
19 changed files with 1705 additions and 372 deletions
104
tests/fishing_authority_validation.gd
Normal file
104
tests/fishing_authority_validation.gd
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
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:
|
||||
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")))
|
||||
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")
|
||||
for _frame: int in 8:
|
||||
await process_frame
|
||||
|
||||
var session := main.get_node("%NetworkSession") as NetworkSession
|
||||
var service := main.get_node(
|
||||
"%NetworkFishingService"
|
||||
) as NetworkFishingService
|
||||
var fishing_spot := main.get_node("%FishingSpot") as FishingSpotType
|
||||
var player := main.get("_player") as Player
|
||||
assert(session.is_host())
|
||||
assert(not session.is_open_host())
|
||||
assert(service != null and fishing_spot != null and player != null)
|
||||
assert(player.hotbar.get_selected_item_id() == &"basic_fishing_rod")
|
||||
|
||||
player.global_position = Vector3(-0.5, 3.95, 2.1)
|
||||
var visuals := player.get_node("Visuals") as Node3D
|
||||
visuals.rotation.y = PI * 0.5
|
||||
for _frame: int in 4:
|
||||
await physics_frame
|
||||
assert(player.get_facing_direction().dot(Vector3.LEFT) > 0.99)
|
||||
|
||||
fishing_spot.call("_begin_aiming", player)
|
||||
assert(fishing_spot.state == FishingSpotType.FishingState.AIMING_CAST)
|
||||
assert(player.is_movement_enabled())
|
||||
fishing_spot.set("_cast_charge", 0.32)
|
||||
fishing_spot.call("_update_cast_charge", 0.0)
|
||||
var aimed_target: Vector3 = fishing_spot.get("_cast_target")
|
||||
assert(aimed_target.x < -1.35)
|
||||
assert(is_equal_approx(aimed_target.y, 2.51))
|
||||
assert(fishing_spot.is_target_fishable(aimed_target))
|
||||
fishing_spot.call("_confirm_cast")
|
||||
assert(fishing_spot.state == FishingSpotType.FishingState.CASTING)
|
||||
assert(not player.is_movement_enabled())
|
||||
|
||||
var wait_deadline: int = Time.get_ticks_msec() + 4000
|
||||
while (
|
||||
Time.get_ticks_msec() < wait_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())
|
||||
var attempts: Dictionary = service.get("_attempts")
|
||||
var attempt: NetworkFishingAttempt = attempts.get(session.get_local_peer_id())
|
||||
assert(attempt != null)
|
||||
assert(is_equal_approx(attempt.target.y, 2.51))
|
||||
assert(attempt.bobber_position.is_equal_approx(attempt.target))
|
||||
|
||||
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() + 4000
|
||||
while (
|
||||
Time.get_ticks_msec() < return_deadline
|
||||
and fishing_spot.state != FishingSpotType.FishingState.RETURNING
|
||||
):
|
||||
await process_frame
|
||||
assert(fishing_spot.state == FishingSpotType.FishingState.RETURNING)
|
||||
assert(not service.has_local_attempt())
|
||||
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 authority validation: PASS")
|
||||
session.disconnect_session("")
|
||||
main.queue_free()
|
||||
await process_frame
|
||||
quit()
|
||||
1
tests/fishing_authority_validation.gd.uid
Normal file
1
tests/fishing_authority_validation.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://cgqcyldad6dsj
|
||||
194
tests/fishing_multiplayer_validation.gd
Normal file
194
tests/fishing_multiplayer_validation.gd
Normal 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
|
||||
1
tests/fishing_multiplayer_validation.gd.uid
Normal file
1
tests/fishing_multiplayer_validation.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://chyq7wjhpko7d
|
||||
337
tests/fishing_surface_validation.gd
Normal file
337
tests/fishing_surface_validation.gd
Normal file
|
|
@ -0,0 +1,337 @@
|
|||
extends SceneTree
|
||||
|
||||
const FishingSpotScene = preload("res://fishing/fishing_spot.tscn")
|
||||
const FishingSpotType = preload("res://fishing/fishing_spot.gd")
|
||||
const FishingPresentationType = preload(
|
||||
"res://fishing/fishing_presentation.gd"
|
||||
)
|
||||
const RemoteFishingPresentationType = preload(
|
||||
"res://fishing/remote_fishing_presentation.gd"
|
||||
)
|
||||
const PlayerScene = preload("res://player/player.tscn")
|
||||
const FishCatchType = preload("res://fish/fish_catch.gd")
|
||||
const FishingSurfaceResolverType = preload(
|
||||
"res://fishing/fishing_surface_resolver.gd"
|
||||
)
|
||||
const FishingSurfaceSampleType = preload(
|
||||
"res://fishing/fishing_surface_sample.gd"
|
||||
)
|
||||
const FishableWaterRegionType = preload(
|
||||
"res://world/fishable_water_region.gd"
|
||||
)
|
||||
const FishPoolType = preload("res://fish/fish_pool.gd")
|
||||
const WaterBodyScene = preload("res://world/water_body.tscn")
|
||||
const StarterRegionScene = preload(
|
||||
"res://world/regions/starter_island_region.tscn"
|
||||
)
|
||||
const PondPool: FishPoolType = preload(
|
||||
"res://fish/pools/starter_pond_pool.tres"
|
||||
)
|
||||
|
||||
|
||||
func _initialize() -> void:
|
||||
call_deferred("_run")
|
||||
|
||||
|
||||
func _run() -> void:
|
||||
await _validate_resolver_layers()
|
||||
await _validate_portable_water_body()
|
||||
await _validate_starter_region_surfaces()
|
||||
await _validate_presentation()
|
||||
await _validate_remote_presentation()
|
||||
await _validate_bite_wait_distribution()
|
||||
print("Fishing surface validation: PASS")
|
||||
quit()
|
||||
|
||||
|
||||
func _validate_resolver_layers() -> void:
|
||||
var world := Node3D.new()
|
||||
root.add_child(world)
|
||||
_add_solid_box(world, Vector3(40.0, 2.0, 12.0), Vector3(10.0, -1.0, 0.0))
|
||||
_add_water_region(world, Vector3(0.0, 2.0, 0.0), Vector2(8.0, 8.0), PondPool)
|
||||
_add_solid_box(world, Vector3(1.0, 1.0, 1.0), Vector3(2.0, 2.25, 0.0))
|
||||
_add_water_region(world, Vector3(10.0, 5.0, 0.0), Vector2(6.0, 6.0), PondPool)
|
||||
_add_water_region(world, Vector3(20.0, 3.0, 0.0), Vector2(6.0, 6.0), null)
|
||||
await physics_frame
|
||||
await physics_frame
|
||||
|
||||
var resolver := FishingSurfaceResolverType.new()
|
||||
var space_state: PhysicsDirectSpaceState3D = world.get_world_3d().direct_space_state
|
||||
var water: FishingSurfaceSampleType = resolver.resolve_surface(
|
||||
space_state,
|
||||
Vector3.ZERO,
|
||||
4.0,
|
||||
)
|
||||
assert(water.is_fishable())
|
||||
assert(is_equal_approx(water.position.y, 2.0))
|
||||
|
||||
var covered_water: FishingSurfaceSampleType = resolver.resolve_surface(
|
||||
space_state,
|
||||
Vector3(2.0, 2.0, 0.0),
|
||||
4.0,
|
||||
)
|
||||
assert(covered_water.has_surface)
|
||||
assert(not covered_water.is_water_surface)
|
||||
assert(is_equal_approx(covered_water.position.y, 2.75))
|
||||
|
||||
var elevated_water: FishingSurfaceSampleType = resolver.resolve_surface(
|
||||
space_state,
|
||||
Vector3(10.0, 0.0, 0.0),
|
||||
8.0,
|
||||
)
|
||||
assert(elevated_water.is_fishable())
|
||||
assert(is_equal_approx(elevated_water.position.y, 5.0))
|
||||
|
||||
var unstocked_water: FishingSurfaceSampleType = resolver.resolve_surface(
|
||||
space_state,
|
||||
Vector3(20.0, 0.0, 0.0),
|
||||
6.0,
|
||||
)
|
||||
assert(unstocked_water.has_surface)
|
||||
assert(unstocked_water.is_water_surface)
|
||||
assert(not unstocked_water.is_fishable())
|
||||
assert(is_equal_approx(unstocked_water.position.y, 3.0))
|
||||
|
||||
var safe_reel: FishingSurfaceSampleType = resolver.resolve_withdrawal_surface(
|
||||
space_state,
|
||||
Vector3(0.0, 2.0, 0.0),
|
||||
Vector3(3.0, 2.0, 0.0),
|
||||
Vector3.RIGHT,
|
||||
4.0,
|
||||
0.4,
|
||||
)
|
||||
assert(safe_reel.is_fishable())
|
||||
assert(is_equal_approx(safe_reel.position.y, 2.0))
|
||||
var shoreline_reel: FishingSurfaceSampleType = (
|
||||
resolver.resolve_withdrawal_surface(
|
||||
space_state,
|
||||
Vector3(3.0, 2.0, 0.0),
|
||||
Vector3(3.7, 2.0, 0.0),
|
||||
Vector3.RIGHT,
|
||||
4.0,
|
||||
0.4,
|
||||
)
|
||||
)
|
||||
assert(not shoreline_reel.is_fishable())
|
||||
assert(shoreline_reel.position.is_equal_approx(Vector3(3.0, 2.0, 0.0)))
|
||||
|
||||
world.queue_free()
|
||||
await process_frame
|
||||
|
||||
|
||||
func _validate_portable_water_body() -> void:
|
||||
var water_body := WaterBodyScene.instantiate() as Node3D
|
||||
water_body.position = Vector3(3.0, 7.0, -2.0)
|
||||
water_body.set("surface_size", Vector2(12.0, 8.0))
|
||||
water_body.set("fishing_depth", 6.0)
|
||||
water_body.set("recovery_depth", 7.0)
|
||||
water_body.set("fish_pool", PondPool)
|
||||
root.add_child(water_body)
|
||||
await process_frame
|
||||
|
||||
var visual := water_body.get_node("VisualWater") as MeshInstance3D
|
||||
var visual_mesh := visual.mesh as PlaneMesh
|
||||
assert(visual_mesh.size.is_equal_approx(Vector2(12.0, 8.0)))
|
||||
var fishing_region := water_body.get_node(
|
||||
"FishingRegion"
|
||||
) as FishableWaterRegionType
|
||||
var fishing_shape_node := water_body.get_node(
|
||||
"FishingRegion/Shape"
|
||||
) as CollisionShape3D
|
||||
var fishing_shape := fishing_shape_node.shape as BoxShape3D
|
||||
assert(fishing_region.fish_pool == PondPool)
|
||||
assert(is_equal_approx(fishing_region.get_surface_height(), 7.0))
|
||||
assert(is_equal_approx(fishing_shape_node.position.y, -3.0))
|
||||
assert(fishing_shape.size.is_equal_approx(Vector3(12.0, 6.0, 8.0)))
|
||||
var recovery_region := water_body.get_node("RecoveryRegion") as Area3D
|
||||
assert(is_equal_approx(recovery_region.position.y, -3.5))
|
||||
|
||||
water_body.queue_free()
|
||||
await process_frame
|
||||
|
||||
|
||||
func _validate_starter_region_surfaces() -> void:
|
||||
var region := StarterRegionScene.instantiate() as Node3D
|
||||
root.add_child(region)
|
||||
var fishing_spot := FishingSpotScene.instantiate() as FishingSpotType
|
||||
root.add_child(fishing_spot)
|
||||
await physics_frame
|
||||
await physics_frame
|
||||
|
||||
var pond: FishingSurfaceSampleType = fishing_spot.resolve_fishing_surface(
|
||||
Vector3(-9.4, 2.51, 2.1),
|
||||
4.0,
|
||||
)
|
||||
assert(pond.is_fishable())
|
||||
assert(is_equal_approx(pond.position.y, 2.51))
|
||||
var ocean: FishingSurfaceSampleType = fishing_spot.resolve_fishing_surface(
|
||||
Vector3(50.0, -0.45, 0.0),
|
||||
4.0,
|
||||
)
|
||||
assert(ocean.is_fishable())
|
||||
assert(is_equal_approx(ocean.position.y, -0.45))
|
||||
var covered_ocean: FishingSurfaceSampleType = (
|
||||
fishing_spot.resolve_fishing_surface(
|
||||
Vector3(20.0, -0.45, 0.0),
|
||||
4.0,
|
||||
)
|
||||
)
|
||||
assert(covered_ocean.has_surface)
|
||||
assert(not covered_ocean.is_fishable())
|
||||
assert(covered_ocean.position.y > -0.45)
|
||||
|
||||
fishing_spot.queue_free()
|
||||
region.queue_free()
|
||||
await process_frame
|
||||
|
||||
|
||||
func _validate_presentation() -> void:
|
||||
var fishing_spot := FishingSpotScene.instantiate() as FishingSpotType
|
||||
root.add_child(fishing_spot)
|
||||
var presentation := fishing_spot.get_node(
|
||||
"FishingPresentation"
|
||||
) as FishingPresentationType
|
||||
var rod := Node3D.new()
|
||||
var rod_tip := Marker3D.new()
|
||||
rod.add_child(rod_tip)
|
||||
root.add_child(rod)
|
||||
rod_tip.position = Vector3(0.0, 1.0, 0.0)
|
||||
await process_frame
|
||||
|
||||
var slope_normal := Vector3(0.0, 1.0, 1.0).normalized()
|
||||
presentation.begin_aim(
|
||||
rod_tip,
|
||||
rod,
|
||||
Vector3(0.0, 0.1, -1.0),
|
||||
slope_normal,
|
||||
false,
|
||||
)
|
||||
var marker := presentation.get_node("CastTargetMarker") as Node3D
|
||||
var valid_marker := presentation.get_node(
|
||||
"CastTargetMarker/ValidTargetMarker"
|
||||
) as MeshInstance3D
|
||||
var invalid_marker := presentation.get_node(
|
||||
"CastTargetMarker/InvalidTargetMarker"
|
||||
) as Node3D
|
||||
assert(not valid_marker.visible)
|
||||
assert(invalid_marker.visible)
|
||||
assert(invalid_marker.get_child_count() == 2)
|
||||
assert(marker.global_basis.y.normalized().dot(slope_normal) > 0.999)
|
||||
|
||||
var landing := Vector3(0.0, 0.13, -4.0)
|
||||
presentation.begin_cast(landing, landing, true)
|
||||
await presentation.cast_completed
|
||||
var bobber := presentation.get_node("Bobber") as MeshInstance3D
|
||||
assert(bobber.visible)
|
||||
assert(bobber.global_position.is_equal_approx(landing))
|
||||
presentation.play_outcome(&"invalid")
|
||||
await process_frame
|
||||
assert(bobber.visible)
|
||||
await presentation.outcome_completed
|
||||
assert(not bobber.visible)
|
||||
|
||||
rod.queue_free()
|
||||
fishing_spot.queue_free()
|
||||
await process_frame
|
||||
|
||||
|
||||
func _validate_bite_wait_distribution() -> void:
|
||||
var fishing_spot := FishingSpotScene.instantiate() as FishingSpotType
|
||||
root.add_child(fishing_spot)
|
||||
await process_frame
|
||||
var quick_count: int = 0
|
||||
var typical_or_long_count: int = 0
|
||||
for _sample_index: int in 10000:
|
||||
var wait_seconds: float = fishing_spot.roll_bite_wait_time()
|
||||
assert(wait_seconds >= 10.0)
|
||||
assert(wait_seconds <= 240.0)
|
||||
if wait_seconds < 30.0:
|
||||
quick_count += 1
|
||||
else:
|
||||
typical_or_long_count += 1
|
||||
assert(quick_count > 0)
|
||||
assert(typical_or_long_count > quick_count)
|
||||
fishing_spot.queue_free()
|
||||
await process_frame
|
||||
|
||||
|
||||
func _validate_remote_presentation() -> void:
|
||||
var player := PlayerScene.instantiate() as Player
|
||||
root.add_child(player)
|
||||
player.set_local_control(false)
|
||||
var presentation := RemoteFishingPresentationType.new()
|
||||
root.add_child(presentation)
|
||||
presentation.setup(player)
|
||||
await process_frame
|
||||
var origin: Vector3 = player.get_fishing_rod_tip().global_position
|
||||
var target: Vector3 = origin + Vector3(-4.0, -0.5, 0.0)
|
||||
presentation.show_cast(origin, target)
|
||||
var bobber := presentation.get("_bobber") as MeshInstance3D
|
||||
assert(bobber.visible)
|
||||
assert(presentation.get("_cast_tween") != null)
|
||||
await create_timer(0.7).timeout
|
||||
assert(bobber.global_position.distance_to(target) < 0.1)
|
||||
var first_bob_y: float = bobber.global_position.y
|
||||
await create_timer(0.2).timeout
|
||||
assert(not is_equal_approx(bobber.global_position.y, first_bob_y))
|
||||
|
||||
var fish_catch := FishCatchType.new()
|
||||
var fish: FishData = PondPool.candidates.front()
|
||||
fish_catch.fish = fish
|
||||
fish_catch.fish_id = fish.id
|
||||
fish_catch.catch_id = &"remote-presentation-test"
|
||||
fish_catch.weight_lb = 1.0
|
||||
fish_catch.display_scale = 1.0
|
||||
fish_catch.sale_value = 1
|
||||
assert(fish_catch.is_valid())
|
||||
presentation.play_return(fish_catch)
|
||||
await create_timer(0.6).timeout
|
||||
var catch_display := player.get_node("%CatchDisplay") as Node3D
|
||||
assert(catch_display.visible)
|
||||
await presentation.return_completed
|
||||
assert(not catch_display.visible)
|
||||
|
||||
presentation.queue_free()
|
||||
player.queue_free()
|
||||
await process_frame
|
||||
|
||||
|
||||
func _add_water_region(
|
||||
parent: Node3D,
|
||||
position: Vector3,
|
||||
surface_size: Vector2,
|
||||
fish_pool: FishPoolType,
|
||||
) -> void:
|
||||
var water_root := Node3D.new()
|
||||
water_root.position = position
|
||||
parent.add_child(water_root)
|
||||
var region := FishableWaterRegionType.new()
|
||||
region.collision_layer = 4
|
||||
region.collision_mask = 0
|
||||
region.monitoring = false
|
||||
region.surface_height_mode = FishableWaterRegionType.SurfaceHeightMode.PARENT_GLOBAL_Y
|
||||
region.fish_pool = fish_pool
|
||||
water_root.add_child(region)
|
||||
var shape_node := CollisionShape3D.new()
|
||||
shape_node.position.y = -2.0
|
||||
var shape := BoxShape3D.new()
|
||||
shape.size = Vector3(surface_size.x, 4.0, surface_size.y)
|
||||
shape_node.shape = shape
|
||||
region.add_child(shape_node)
|
||||
|
||||
|
||||
func _add_solid_box(
|
||||
parent: Node3D,
|
||||
size: Vector3,
|
||||
position: Vector3,
|
||||
) -> void:
|
||||
var body := StaticBody3D.new()
|
||||
body.position = position
|
||||
body.collision_layer = 1
|
||||
body.collision_mask = 0
|
||||
parent.add_child(body)
|
||||
var shape_node := CollisionShape3D.new()
|
||||
var shape := BoxShape3D.new()
|
||||
shape.size = size
|
||||
shape_node.shape = shape
|
||||
body.add_child(shape_node)
|
||||
1
tests/fishing_surface_validation.gd.uid
Normal file
1
tests/fishing_surface_validation.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://bh8g62bagphbd
|
||||
Loading…
Add table
Add a link
Reference in a new issue