feat: expand progression and multiplayer systems
Add named save slots, progression import/export, and a unified play flow. Add live friend requests, presence, invitations, and relationship controls without durable discovery-server social storage. Advance the network protocol with isolated channels, movement reconciliation, late-join recovery, fishing replication, and animation synchronization. Preserve per-species catch totals, refine generated-world startup and water recovery, and complete the related input and interface improvements.
This commit is contained in:
parent
1db1a5b754
commit
3b84bfe3a0
97 changed files with 7869 additions and 982 deletions
|
|
@ -81,12 +81,36 @@ func _run() -> void:
|
|||
"%NetworkSurfaceDrawingService"
|
||||
) as NetworkSurfaceDrawingService
|
||||
var game_ui := main.get_node("%GameUI") as GameUI
|
||||
var keyboard_mapping := main.get_node(
|
||||
"%KeyboardMouseMappingManager"
|
||||
) as KeyboardMouseMappingManager
|
||||
var toolbar := game_ui.get_node(
|
||||
"%SurfaceDrawingToolbar"
|
||||
) as SurfaceDrawingToolbar
|
||||
var chat_ui := game_ui.get_node("%ChatUI") as ChatUI
|
||||
assert(player != null and service != null and toolbar != null)
|
||||
assert(chat_ui != null)
|
||||
assert(keyboard_mapping != null)
|
||||
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
|
||||
assert(keyboard_mapping.set_binding(
|
||||
KeyboardMouseMappingManager.ROLE_INTERACT,
|
||||
keyboard_mapping.binding_from_event(remapped_interact),
|
||||
))
|
||||
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())
|
||||
assert(
|
||||
toolbar.get_index() > chat_ui.get_index(),
|
||||
|
|
@ -252,6 +276,33 @@ func _run() -> void:
|
|||
else:
|
||||
assert(not typed_chat_entry.virtual_keyboard_enabled)
|
||||
assert(on_screen_keyboard.is_open())
|
||||
|
||||
# A bite temporarily owns gameplay input without discarding an in-progress
|
||||
# message. The draft and insertion point return only after fishing releases
|
||||
# that ownership, and any controller keyboard follows the restored field.
|
||||
var chat_fishing_spot := main.get_node("%FishingSpot") as FishingSpot
|
||||
assert(chat_fishing_spot != null)
|
||||
var interrupted_draft := "finish this message after fishing"
|
||||
var interrupted_caret: int = 12
|
||||
typed_chat_entry.text = interrupted_draft
|
||||
typed_chat_entry.caret_column = interrupted_caret
|
||||
chat_fishing_spot.call("_set_fishing_input_priority", true)
|
||||
await process_frame
|
||||
assert(not chat_ui.is_open())
|
||||
assert(not bool(chat_ui.get("_input_lock_applied")))
|
||||
assert(chat_ui.has_fishing_resume_pending())
|
||||
assert(not on_screen_keyboard.is_open())
|
||||
chat_ui.open_chat()
|
||||
assert(not chat_ui.is_open())
|
||||
chat_fishing_spot.call("_set_fishing_input_priority", false)
|
||||
for _frame: int in 4:
|
||||
await process_frame
|
||||
assert(chat_ui.is_open())
|
||||
assert(typed_chat_entry.text == interrupted_draft)
|
||||
assert(typed_chat_entry.caret_column == interrupted_caret)
|
||||
assert(bool(chat_ui.get("_input_lock_applied")))
|
||||
if not DisplayServer.has_feature(DisplayServer.FEATURE_VIRTUAL_KEYBOARD):
|
||||
assert(on_screen_keyboard.is_open())
|
||||
on_screen_keyboard.call("_close_keyboard", true)
|
||||
assert(typed_chat_entry.has_focus())
|
||||
var left_bumper := InputEventJoypadButton.new()
|
||||
|
|
@ -507,7 +558,7 @@ func _run() -> void:
|
|||
and stamp_button != null
|
||||
)
|
||||
assert(export_button.text == "png")
|
||||
assert(export_button.tooltip_text == "export aimed artwork as PNG")
|
||||
assert(export_button.tooltip_text == "aim at artwork, then click to export PNG")
|
||||
assert(stamp_button.text == "stamp")
|
||||
assert(stamp_button.disabled)
|
||||
assert(toolbar.get_node_or_null("%CloseButton") == null)
|
||||
|
|
@ -830,6 +881,18 @@ func _run() -> void:
|
|||
await process_frame
|
||||
assert(player.hotbar.get_selected_slot() == 1)
|
||||
assert(not service.is_active() and not toolbar.visible)
|
||||
hotbar_ui.set_swap_hotbar_camera_scroll(true)
|
||||
hotbar_ui._unhandled_input(wheel_down)
|
||||
await process_frame
|
||||
assert(player.hotbar.get_selected_slot() == 1)
|
||||
var shifted_wheel_down := InputEventMouseButton.new()
|
||||
shifted_wheel_down.button_index = MOUSE_BUTTON_WHEEL_DOWN
|
||||
shifted_wheel_down.pressed = true
|
||||
shifted_wheel_down.shift_pressed = true
|
||||
hotbar_ui._unhandled_input(shifted_wheel_down)
|
||||
await process_frame
|
||||
assert(player.hotbar.get_selected_slot() == 2)
|
||||
hotbar_ui.set_swap_hotbar_camera_scroll(false)
|
||||
|
||||
var number_one := InputEventKey.new()
|
||||
number_one.physical_keycode = KEY_1
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue