Add portable RV homes and decor prototype
This commit is contained in:
parent
81decf2b71
commit
fe099f47dd
56 changed files with 5459 additions and 112 deletions
|
|
@ -19,9 +19,15 @@ func _run() -> void:
|
|||
for _frame: int in 8:
|
||||
await process_frame
|
||||
assert(bool(main.get("_application_initialized")))
|
||||
assert(bool(main.call(
|
||||
"_apply_world", WorldLayout.STARTER_ISLAND, 1, true
|
||||
)))
|
||||
assert(bool(main.call(
|
||||
"_prepare_host_world", WorldLayout.STARTER_ISLAND, 1
|
||||
)))
|
||||
assert(bool(main.call("_prepare_private_host")))
|
||||
var save_manager := main.get("_save_manager") as PlayerSaveManager
|
||||
assert(save_manager.initialize_new_game())
|
||||
assert(save_manager.initialize_new_game(1, WorldLayout.STARTER_ISLAND))
|
||||
main.call("_enter_gameplay")
|
||||
await physics_frame
|
||||
await physics_frame
|
||||
|
|
@ -94,11 +100,7 @@ func _run() -> void:
|
|||
assert(keyboard_mapping.reset_mapping())
|
||||
await process_frame
|
||||
var shop_prompt_key := game_ui.get_node("%ShopPromptKey") as Label
|
||||
var storage_prompt_message := game_ui.get_node(
|
||||
"%StoragePromptMessage"
|
||||
) as Label
|
||||
assert(shop_prompt_key.text == "E")
|
||||
assert(storage_prompt_message.text == "E open storage")
|
||||
var remapped_interact := InputEventKey.new()
|
||||
remapped_interact.physical_keycode = KEY_F
|
||||
remapped_interact.pressed = true
|
||||
|
|
@ -108,7 +110,6 @@ func _run() -> void:
|
|||
))
|
||||
await process_frame
|
||||
assert(shop_prompt_key.text == "F")
|
||||
assert(storage_prompt_message.text == "F open storage")
|
||||
assert(keyboard_mapping.reset_mapping())
|
||||
await process_frame
|
||||
assert(toolbar.get_parent() == chat_ui.get_parent())
|
||||
|
|
|
|||
|
|
@ -104,7 +104,10 @@ func _run() -> void:
|
|||
var hotbar_data: Dictionary = parsed["hotbar"]
|
||||
assert(typeof(hotbar_data.get("fish_slots")) == TYPE_ARRAY)
|
||||
assert(str((hotbar_data["fish_slots"] as Array)[1]) == fish_catch.catch_id)
|
||||
assert(int(parsed["save_version"]) == 10)
|
||||
assert(int(parsed["save_version"]) == 11)
|
||||
assert(not PlayerHomeState.sanitize_save_data(
|
||||
parsed.get("home", {})
|
||||
).is_empty())
|
||||
assert(
|
||||
int(parsed["experience"]["total_experience"])
|
||||
== 125
|
||||
|
|
|
|||
|
|
@ -485,7 +485,7 @@ func _validate_version_four_migration() -> void:
|
|||
version_four,
|
||||
4,
|
||||
)
|
||||
assert(int(migrated.get("save_version", -1)) == 10)
|
||||
assert(int(migrated.get("save_version", -1)) == 11)
|
||||
assert(int((migrated["experience"] as Dictionary)["total_experience"]) == 0)
|
||||
assert(
|
||||
is_equal_approx(
|
||||
|
|
@ -509,4 +509,7 @@ func _validate_version_four_migration() -> void:
|
|||
assert(
|
||||
PlayerJobService.validate_save_data(migrated.get("jobs", {}))
|
||||
)
|
||||
assert(not PlayerHomeState.sanitize_save_data(
|
||||
migrated.get("home", {})
|
||||
).is_empty())
|
||||
manager.queue_free()
|
||||
|
|
|
|||
178
tests/home_spawn_multiplayer_validation.gd
Normal file
178
tests/home_spawn_multiplayer_validation.gd
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
extends SceneTree
|
||||
|
||||
const MainScene: PackedScene = preload("res://main/main.tscn")
|
||||
const TEST_PORT: int = 18222
|
||||
|
||||
|
||||
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("Home spawn validation needs host or client mode.")
|
||||
quit(1)
|
||||
|
||||
|
||||
func _run_host() -> void:
|
||||
var main: Node = await _create_initialized_main()
|
||||
var session := main.get_node("%NetworkSession") as NetworkSession
|
||||
var network_home := main.get_node(
|
||||
"%NetworkHomeService"
|
||||
) as NetworkHomeService
|
||||
var home_world := main.get_node("%HomeWorldService") as HomeWorldService
|
||||
var spawn_service := main.get_node(
|
||||
"%PlayerSpawnService"
|
||||
) as PlayerSpawnService
|
||||
var save_manager := main.get("_save_manager") as PlayerSaveManager
|
||||
assert(bool(main.call(
|
||||
"_apply_world", WorldLayout.STARTER_ISLAND, 1, true
|
||||
)))
|
||||
assert(bool(main.call(
|
||||
"_prepare_host_world", WorldLayout.STARTER_ISLAND, 1
|
||||
)))
|
||||
assert(save_manager.initialize_new_game(1, WorldLayout.STARTER_ISLAND))
|
||||
assert(session.start_private_host(TEST_PORT))
|
||||
main.call("_enter_gameplay")
|
||||
assert(session.set_host_open(true))
|
||||
|
||||
var host_fingerprint: String = session.get_local_identity_fingerprint()
|
||||
assert(await _wait_for_home(network_home, host_fingerprint))
|
||||
var host_avatar: Player = spawn_service.get_avatar(1)
|
||||
var host_spawn: Transform3D = home_world.get_exterior_spawn_transform(
|
||||
host_fingerprint
|
||||
)
|
||||
assert(_same_door_position(host_avatar.global_position, host_spawn.origin))
|
||||
assert(network_home.request_enter(host_fingerprint))
|
||||
await physics_frame
|
||||
host_avatar.global_position = home_world.get_interior_exit_position(
|
||||
host_fingerprint
|
||||
)
|
||||
assert(network_home.request_exit())
|
||||
await physics_frame
|
||||
assert(_same_door_position(host_avatar.global_position, host_spawn.origin))
|
||||
|
||||
var remote_peer_id: int = await _wait_for_remote_peer(session)
|
||||
assert(remote_peer_id > 1)
|
||||
var remote_record := session.get_peer_record(remote_peer_id)
|
||||
var remote_fingerprint: String = remote_record.identity_fingerprint
|
||||
assert(await _wait_for_home(network_home, remote_fingerprint))
|
||||
var remote_avatar: Player = spawn_service.get_avatar(remote_peer_id)
|
||||
var remote_spawn: Transform3D = home_world.get_exterior_spawn_transform(
|
||||
remote_fingerprint
|
||||
)
|
||||
assert(_same_door_position(
|
||||
remote_avatar.global_position, remote_spawn.origin
|
||||
))
|
||||
|
||||
var disconnect_deadline: int = Time.get_ticks_msec() + 12000
|
||||
while (
|
||||
Time.get_ticks_msec() < disconnect_deadline
|
||||
and session.is_authenticated_peer(remote_peer_id)
|
||||
):
|
||||
await process_frame
|
||||
assert(not session.is_authenticated_peer(remote_peer_id))
|
||||
print("Home spawn multiplayer host validation: PASS")
|
||||
await _cleanup(main, session)
|
||||
|
||||
|
||||
func _run_client() -> void:
|
||||
var main: Node = await _create_initialized_main()
|
||||
main.call(
|
||||
"_on_title_join_game_requested",
|
||||
"127.0.0.1:%d" % TEST_PORT,
|
||||
)
|
||||
var session := main.get_node("%NetworkSession") as NetworkSession
|
||||
var network_home := main.get_node(
|
||||
"%NetworkHomeService"
|
||||
) as NetworkHomeService
|
||||
var home_world := main.get_node("%HomeWorldService") as HomeWorldService
|
||||
var deadline: int = Time.get_ticks_msec() + 20000
|
||||
while Time.get_ticks_msec() < 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")):
|
||||
break
|
||||
assert(session.is_joined_client())
|
||||
var fingerprint: String = session.get_local_identity_fingerprint()
|
||||
assert(await _wait_for_home(network_home, fingerprint))
|
||||
var player := main.get("_player") as Player
|
||||
var exterior_spawn: Transform3D = (
|
||||
home_world.get_exterior_spawn_transform(fingerprint)
|
||||
)
|
||||
deadline = Time.get_ticks_msec() + 5000
|
||||
while (
|
||||
Time.get_ticks_msec() < deadline
|
||||
and not _same_door_position(
|
||||
player.global_position, exterior_spawn.origin
|
||||
)
|
||||
):
|
||||
await physics_frame
|
||||
assert(_same_door_position(
|
||||
player.global_position, exterior_spawn.origin
|
||||
))
|
||||
print("Home spawn multiplayer client validation: PASS")
|
||||
await _cleanup(main, session)
|
||||
|
||||
|
||||
func _create_initialized_main() -> Node:
|
||||
root.size = Vector2i(1280, 720)
|
||||
var main: Node = 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
|
||||
|
||||
|
||||
func _wait_for_home(
|
||||
network_home: NetworkHomeService,
|
||||
fingerprint: String,
|
||||
) -> bool:
|
||||
var deadline: int = Time.get_ticks_msec() + 10000
|
||||
while Time.get_ticks_msec() < deadline:
|
||||
await process_frame
|
||||
var manifests: Dictionary = network_home.get(
|
||||
"_manifests_by_fingerprint"
|
||||
)
|
||||
if manifests.has(fingerprint):
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
func _wait_for_remote_peer(session: NetworkSession) -> int:
|
||||
var deadline: int = Time.get_ticks_msec() + 20000
|
||||
while Time.get_ticks_msec() < deadline:
|
||||
await process_frame
|
||||
for peer_id: int in session.get_authenticated_peer_ids():
|
||||
if peer_id != session.get_local_peer_id():
|
||||
return peer_id
|
||||
return 0
|
||||
|
||||
|
||||
func _same_door_position(first: Vector3, second: Vector3) -> bool:
|
||||
return (
|
||||
Vector2(first.x, first.z).distance_to(Vector2(second.x, second.z))
|
||||
< 0.08
|
||||
and absf(first.y - second.y) < 0.3
|
||||
)
|
||||
|
||||
|
||||
func _cleanup(main: Node, session: NetworkSession) -> void:
|
||||
session.disconnect_session("")
|
||||
main.queue_free()
|
||||
for _frame: int in 4:
|
||||
await process_frame
|
||||
await create_timer(0.1).timeout
|
||||
quit()
|
||||
1
tests/home_spawn_multiplayer_validation.gd.uid
Normal file
1
tests/home_spawn_multiplayer_validation.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://bndtkip5p6xma
|
||||
|
|
@ -205,8 +205,11 @@ func _run() -> void:
|
|||
)
|
||||
assert(bool(decoded.get("ok", false)))
|
||||
var save_data: Dictionary = decoded["data"]
|
||||
assert(int(save_data.get("save_version", -1)) == 10)
|
||||
assert(int(save_data.get("save_version", -1)) == 11)
|
||||
assert(PlayerJobService.validate_save_data(save_data.get("jobs", {})))
|
||||
assert(not PlayerHomeState.sanitize_save_data(
|
||||
save_data.get("home", {})
|
||||
).is_empty())
|
||||
|
||||
_validate_pause_session_switch(main, session)
|
||||
main.queue_free()
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ func _validate_save_migration() -> void:
|
|||
version_five,
|
||||
5,
|
||||
)
|
||||
assert(int(migrated.get("save_version", -1)) == 10)
|
||||
assert(int(migrated.get("save_version", -1)) == 11)
|
||||
var experience_data: Dictionary = migrated.get("experience", {})
|
||||
assert(int(experience_data.get("total_experience", -1)) == 0)
|
||||
var world_data: Dictionary = migrated.get("world", {})
|
||||
|
|
@ -155,6 +155,9 @@ func _validate_save_migration() -> void:
|
|||
assert(
|
||||
PlayerJobService.validate_save_data(migrated.get("jobs", {}))
|
||||
)
|
||||
assert(not PlayerHomeState.sanitize_save_data(
|
||||
migrated.get("home", {})
|
||||
).is_empty())
|
||||
manager.queue_free()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -22,11 +22,24 @@ func _run() -> void:
|
|||
var save_manager := main.get("_save_manager") as PlayerSaveManager
|
||||
var player := main.get("_player") as Player
|
||||
var data_root := main.get("_data_root") as PlayerDataRoot
|
||||
assert(save_manager != null and player != null and data_root != null)
|
||||
var home_state := main.get("_home_state") as PlayerHomeState
|
||||
assert(
|
||||
save_manager != null
|
||||
and player != null
|
||||
and data_root != null
|
||||
and home_state != null
|
||||
)
|
||||
assert(save_manager.initialize_new_game(864209))
|
||||
save_manager.set_autosave_enabled(true)
|
||||
assert(player.wallet.restore_balance(4321))
|
||||
assert(player.bag.add_item(&"coffee"))
|
||||
assert(home_state.add_owned_decor(&"basic_cube"))
|
||||
assert(not home_state.place_decor(
|
||||
&"basic_cube",
|
||||
Vector3.ZERO,
|
||||
0.0,
|
||||
PlayerHomeState.PlacementMode.GRID,
|
||||
).is_empty())
|
||||
assert(save_manager.save_now())
|
||||
|
||||
var save_path: String = str(save_manager.get("_save_path"))
|
||||
|
|
@ -38,7 +51,14 @@ func _run() -> void:
|
|||
_assert_opaque(save_path)
|
||||
var decoded: Dictionary = ProgressionSaveCodec.read_local_save(save_path)
|
||||
assert(bool(decoded.get("ok", false)))
|
||||
assert(int((decoded["data"] as Dictionary)["save_version"]) == 10)
|
||||
assert(int((decoded["data"] as Dictionary)["save_version"]) == 11)
|
||||
assert(not PlayerHomeState.sanitize_save_data(
|
||||
(decoded["data"] as Dictionary).get("home", {})
|
||||
).is_empty())
|
||||
assert(
|
||||
((decoded["data"] as Dictionary)["home"] as Dictionary)
|
||||
.get("placements", []).size() == 1
|
||||
)
|
||||
var legacy_container_path: String = data_root.progression_backup_directory().path_join(
|
||||
"netfishing-container.nfsave"
|
||||
)
|
||||
|
|
@ -74,6 +94,8 @@ func _run() -> void:
|
|||
assert(save_manager.load_player_data())
|
||||
assert(player.wallet.get_balance() == 4321)
|
||||
assert(save_manager.get_world_seed() == 864209)
|
||||
assert(home_state.get_owned_count(&"basic_cube") == 1)
|
||||
assert(home_state.get_placed_count(&"basic_cube") == 1)
|
||||
|
||||
var legacy_data: Dictionary = (
|
||||
ProgressionSaveCodec.read_local_save(save_path)["data"]
|
||||
|
|
|
|||
|
|
@ -35,6 +35,41 @@ func _run() -> void:
|
|||
hotbar.setup(bag, ItemCatalogResource, catches, layout)
|
||||
assert(PlayerInventoryLayout.INVENTORY_CAPACITIES == [9, 18, 27, 36])
|
||||
assert(PlayerCoolerCapacity.CAPACITIES == [9, 18, 27, 36, 45, 54, 63, 72])
|
||||
var basic_cube: ItemData = ItemCatalogResource.get_item_by_id(&"basic_cube")
|
||||
assert(basic_cube != null)
|
||||
assert(basic_cube.icon != null)
|
||||
assert(basic_cube.hotbar_allowed)
|
||||
assert(bag.add_item(&"basic_cube"))
|
||||
assert(layout.is_item_in_inventory(&"basic_cube"))
|
||||
assert(hotbar.assign_item(0, &"basic_cube"))
|
||||
assert(hotbar.get_item_id(0) == &"basic_cube")
|
||||
assert(
|
||||
layout.get_container(
|
||||
PlayerInventoryLayout.EntryKind.ITEM,
|
||||
&"basic_cube",
|
||||
) == PlayerInventoryLayout.InventoryContainer.HOTBAR
|
||||
)
|
||||
assert(hotbar.clear_slot(0))
|
||||
assert(layout.is_item_in_inventory(&"basic_cube"))
|
||||
assert(bag.remove_item(&"basic_cube"))
|
||||
var packed_decor_slot: int = hotbar.find_first_empty_slot()
|
||||
assert(packed_decor_slot == 0)
|
||||
assert(layout.prepare_new_item_placement(
|
||||
&"basic_cube",
|
||||
PlayerInventoryLayout.InventoryContainer.HOTBAR,
|
||||
packed_decor_slot,
|
||||
))
|
||||
assert(bag.add_item(&"basic_cube"))
|
||||
assert(
|
||||
layout.get_container(
|
||||
PlayerInventoryLayout.EntryKind.ITEM,
|
||||
&"basic_cube",
|
||||
) == PlayerInventoryLayout.InventoryContainer.HOTBAR
|
||||
)
|
||||
assert(hotbar.assign_item(packed_decor_slot, &"basic_cube"))
|
||||
assert(hotbar.select_slot(packed_decor_slot))
|
||||
assert(hotbar.get_selected_item_id() == &"basic_cube")
|
||||
assert(bag.remove_item(&"basic_cube"))
|
||||
|
||||
assert(bag.add_item(&"coffee", 3))
|
||||
assert(layout.get_inventory_count() == 1)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue