feat: integrate fishing item transitions
This commit is contained in:
parent
692b6eeb2a
commit
63a5009b33
11 changed files with 719 additions and 110 deletions
Binary file not shown.
Binary file not shown.
|
|
@ -67,7 +67,6 @@ signal showcase_changed(
|
||||||
signal bite_activated
|
signal bite_activated
|
||||||
signal bite_prompt_changed(is_visible: bool)
|
signal bite_prompt_changed(is_visible: bool)
|
||||||
signal ready_for_equipment_refresh
|
signal ready_for_equipment_refresh
|
||||||
signal fish_showcase_toggle_requested
|
|
||||||
signal art_ui_toggle_requested
|
signal art_ui_toggle_requested
|
||||||
|
|
||||||
enum FishingState {
|
enum FishingState {
|
||||||
|
|
@ -510,13 +509,6 @@ func _unhandled_input(event: InputEvent) -> void:
|
||||||
FishingState.READY:
|
FishingState.READY:
|
||||||
if not _new_cast_press_armed:
|
if not _new_cast_press_armed:
|
||||||
return
|
return
|
||||||
if (
|
|
||||||
_local_hotbar != null
|
|
||||||
and not _local_hotbar.get_selected_fish_catch_id().is_empty()
|
|
||||||
):
|
|
||||||
fish_showcase_toggle_requested.emit()
|
|
||||||
get_viewport().set_input_as_handled()
|
|
||||||
return
|
|
||||||
var active_item: ItemDataType = _get_active_item()
|
var active_item: ItemDataType = _get_active_item()
|
||||||
if (
|
if (
|
||||||
active_item != null
|
active_item != null
|
||||||
|
|
@ -1134,7 +1126,7 @@ func _on_catch_completed() -> void:
|
||||||
return
|
return
|
||||||
_stop_fight_audio()
|
_stop_fight_audio()
|
||||||
_active_player.set_fighting_visual(false)
|
_active_player.set_fighting_visual(false)
|
||||||
_active_player.set_fishing_visual(false)
|
_active_player.set_retract_visual()
|
||||||
state = FishingState.SHOWING_CATCH
|
state = FishingState.SHOWING_CATCH
|
||||||
_showcase_ready = false
|
_showcase_ready = false
|
||||||
_showcase_outcome_completed = false
|
_showcase_outcome_completed = false
|
||||||
|
|
@ -1156,6 +1148,12 @@ func _on_catch_escaped() -> void:
|
||||||
|
|
||||||
|
|
||||||
func _on_outcome_completed(outcome: StringName) -> void:
|
func _on_outcome_completed(outcome: StringName) -> void:
|
||||||
|
var retracting_player := _active_player
|
||||||
|
if (
|
||||||
|
retracting_player != null
|
||||||
|
and not retracting_player.is_retract_visual_complete()
|
||||||
|
):
|
||||||
|
await retracting_player.retract_visual_finished
|
||||||
if state == FishingState.RETURNING:
|
if state == FishingState.RETURNING:
|
||||||
var cleanup_message: String = _pending_cleanup_message
|
var cleanup_message: String = _pending_cleanup_message
|
||||||
_pending_cleanup_message = ""
|
_pending_cleanup_message = ""
|
||||||
|
|
@ -1260,7 +1258,15 @@ func _cleanup_attempt(
|
||||||
_stop_reeling_audio()
|
_stop_reeling_audio()
|
||||||
if _active_player != null:
|
if _active_player != null:
|
||||||
_active_player.set_fighting_visual(false)
|
_active_player.set_fighting_visual(false)
|
||||||
|
if visual_outcome.is_empty():
|
||||||
_active_player.set_fishing_visual(false)
|
_active_player.set_fishing_visual(false)
|
||||||
|
elif visual_outcome == &"catch":
|
||||||
|
# A successful catch already retracted the line before the fish
|
||||||
|
# showcase. Returning from the pocket transition should settle back
|
||||||
|
# to idle instead of replaying the retract animation.
|
||||||
|
_active_player.set_fishing_visual(false)
|
||||||
|
else:
|
||||||
|
_active_player.set_retract_visual()
|
||||||
if not visual_outcome.is_empty():
|
if not visual_outcome.is_empty():
|
||||||
if state == FishingState.RETURNING:
|
if state == FishingState.RETURNING:
|
||||||
return
|
return
|
||||||
|
|
@ -1746,6 +1752,8 @@ func _on_network_catch_received(fish_catch: FishCatchType) -> void:
|
||||||
PackedInt32Array(), -1, false
|
PackedInt32Array(), -1, false
|
||||||
)
|
)
|
||||||
_presentation.set_line_mode(FishingPresentationType.LineMode.TAUT)
|
_presentation.set_line_mode(FishingPresentationType.LineMode.TAUT)
|
||||||
|
if _active_player != null:
|
||||||
|
_active_player.set_retract_visual()
|
||||||
_presentation.play_outcome(&"catch")
|
_presentation.play_outcome(&"catch")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ func show_bite() -> void:
|
||||||
func play_return(showcase_catch: FishCatch = null) -> void:
|
func play_return(showcase_catch: FishCatch = null) -> void:
|
||||||
if _owner != null and is_instance_valid(_owner):
|
if _owner != null and is_instance_valid(_owner):
|
||||||
_owner.set_fighting_visual(false)
|
_owner.set_fighting_visual(false)
|
||||||
_owner.set_fishing_visual(false)
|
_owner.set_retract_visual()
|
||||||
if not _active or _bobber == null:
|
if not _active or _bobber == null:
|
||||||
cleanup()
|
cleanup()
|
||||||
return_completed.emit()
|
return_completed.emit()
|
||||||
|
|
@ -199,6 +199,12 @@ func _on_return_finished() -> void:
|
||||||
_bobber.visible = false
|
_bobber.visible = false
|
||||||
_line.visible = false
|
_line.visible = false
|
||||||
_line_mesh.clear_surfaces()
|
_line_mesh.clear_surfaces()
|
||||||
|
if (
|
||||||
|
_owner != null
|
||||||
|
and is_instance_valid(_owner)
|
||||||
|
and not _owner.is_retract_visual_complete()
|
||||||
|
):
|
||||||
|
await _owner.retract_visual_finished
|
||||||
if (
|
if (
|
||||||
_return_showcase_catch != null
|
_return_showcase_catch != null
|
||||||
and _owner != null
|
and _owner != null
|
||||||
|
|
@ -216,7 +222,12 @@ func _on_return_finished() -> void:
|
||||||
func _on_showcase_finished() -> void:
|
func _on_showcase_finished() -> void:
|
||||||
_showcase_tween = null
|
_showcase_tween = null
|
||||||
if _owner != null and is_instance_valid(_owner):
|
if _owner != null and is_instance_valid(_owner):
|
||||||
_owner.end_catch_showcase()
|
_owner.end_catch_showcase(_on_showcase_put_away_finished)
|
||||||
|
return
|
||||||
|
_on_showcase_put_away_finished()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_showcase_put_away_finished() -> void:
|
||||||
return_completed.emit()
|
return_completed.emit()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
32
main/main.gd
32
main/main.gd
|
|
@ -50,6 +50,7 @@ const PlayerSpawnServiceType = preload(
|
||||||
const NetworkFishingServiceType = preload(
|
const NetworkFishingServiceType = preload(
|
||||||
"res://network/network_fishing_service.gd"
|
"res://network/network_fishing_service.gd"
|
||||||
)
|
)
|
||||||
|
const PlayerHotbarType = preload("res://inventory/player_hotbar.gd")
|
||||||
const NetworkSaleServiceType = preload(
|
const NetworkSaleServiceType = preload(
|
||||||
"res://network/network_sale_service.gd"
|
"res://network/network_sale_service.gd"
|
||||||
)
|
)
|
||||||
|
|
@ -645,16 +646,13 @@ func _initialize_after_data_root() -> void:
|
||||||
pause_menu.menu_visibility_changed.connect(
|
pause_menu.menu_visibility_changed.connect(
|
||||||
_game_ui.set_system_menu_open
|
_game_ui.set_system_menu_open
|
||||||
)
|
)
|
||||||
_player.hotbar.selected_slot_changed.connect(
|
_player.hotbar.selected_assignment_changed.connect(
|
||||||
_on_active_hotbar_item_changed
|
_on_active_hotbar_item_changed
|
||||||
)
|
)
|
||||||
_player.bag.contents_changed.connect(_refresh_active_hotbar_item)
|
_player.bag.contents_changed.connect(_refresh_active_hotbar_item)
|
||||||
_fishing_spot.ready_for_equipment_refresh.connect(
|
_fishing_spot.ready_for_equipment_refresh.connect(
|
||||||
_refresh_active_hotbar_item
|
_refresh_active_hotbar_item
|
||||||
)
|
)
|
||||||
_fishing_spot.fish_showcase_toggle_requested.connect(
|
|
||||||
_network_fish_showcase.toggle_selected_fish
|
|
||||||
)
|
|
||||||
_water_recovery.recovery_starting.connect(
|
_water_recovery.recovery_starting.connect(
|
||||||
_on_water_recovery_starting
|
_on_water_recovery_starting
|
||||||
)
|
)
|
||||||
|
|
@ -664,10 +662,7 @@ func _initialize_after_data_root() -> void:
|
||||||
_water_recovery.local_respawn_completed.connect(
|
_water_recovery.local_respawn_completed.connect(
|
||||||
_on_local_respawn_completed
|
_on_local_respawn_completed
|
||||||
)
|
)
|
||||||
_on_active_hotbar_item_changed(
|
_refresh_active_hotbar_item()
|
||||||
_player.hotbar.get_selected_slot(),
|
|
||||||
_player.hotbar.get_selected_item_id()
|
|
||||||
)
|
|
||||||
_show_title_music(true)
|
_show_title_music(true)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1633,17 +1628,23 @@ func _on_remote_recovery_presentation_changed(
|
||||||
|
|
||||||
func _on_active_hotbar_item_changed(
|
func _on_active_hotbar_item_changed(
|
||||||
_slot_index: int,
|
_slot_index: int,
|
||||||
item_id: StringName,
|
kind: int,
|
||||||
|
identity: StringName,
|
||||||
) -> void:
|
) -> void:
|
||||||
if _fishing_spot.state != FishingSpotType.FishingState.READY:
|
if _fishing_spot.state != FishingSpotType.FishingState.READY:
|
||||||
return
|
return
|
||||||
|
var item_id: StringName = (
|
||||||
|
identity
|
||||||
|
if kind == PlayerHotbarType.AssignmentKind.ITEM
|
||||||
|
else StringName()
|
||||||
|
)
|
||||||
var item = item_catalog.get_item_by_id(item_id)
|
var item = item_catalog.get_item_by_id(item_id)
|
||||||
var active_is_rod: bool = (
|
var active_is_rod: bool = (
|
||||||
item != null
|
item != null
|
||||||
and item.category == ItemDataType.Category.ROD
|
and item.category == ItemDataType.Category.ROD
|
||||||
and _player.bag.owns_item(item_id)
|
and _player.bag.owns_item(item_id)
|
||||||
)
|
)
|
||||||
_player.set_active_item_is_rod(active_is_rod)
|
_player.set_active_item_is_rod(active_is_rod, true)
|
||||||
_player.set_active_art_kit(
|
_player.set_active_art_kit(
|
||||||
item.icon if item != null else null,
|
item.icon if item != null else null,
|
||||||
item_id == ArtShopStockType.ART_KIT_ITEM_ID
|
item_id == ArtShopStockType.ART_KIT_ITEM_ID
|
||||||
|
|
@ -1657,9 +1658,18 @@ func _on_active_hotbar_item_changed(
|
||||||
|
|
||||||
|
|
||||||
func _refresh_active_hotbar_item() -> void:
|
func _refresh_active_hotbar_item() -> void:
|
||||||
|
var kind: int = (
|
||||||
|
_player.hotbar.get_selected_assignment_kind()
|
||||||
|
)
|
||||||
|
var identity: StringName = StringName()
|
||||||
|
if kind == PlayerHotbarType.AssignmentKind.ITEM:
|
||||||
|
identity = _player.hotbar.get_selected_item_id()
|
||||||
|
elif kind == PlayerHotbarType.AssignmentKind.FISH:
|
||||||
|
identity = _player.hotbar.get_selected_fish_catch_id()
|
||||||
_on_active_hotbar_item_changed(
|
_on_active_hotbar_item_changed(
|
||||||
_player.hotbar.get_selected_slot(),
|
_player.hotbar.get_selected_slot(),
|
||||||
_player.hotbar.get_selected_item_id()
|
kind,
|
||||||
|
identity,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,19 @@ func setup(
|
||||||
_local_hotbar.selected_assignment_changed.connect(
|
_local_hotbar.selected_assignment_changed.connect(
|
||||||
_on_selected_assignment_changed
|
_on_selected_assignment_changed
|
||||||
)
|
)
|
||||||
|
var selected_kind: int = (
|
||||||
|
_local_hotbar.get_selected_assignment_kind()
|
||||||
|
)
|
||||||
|
var selected_identity: StringName = StringName()
|
||||||
|
if selected_kind == PlayerHotbarType.AssignmentKind.ITEM:
|
||||||
|
selected_identity = _local_hotbar.get_selected_item_id()
|
||||||
|
elif selected_kind == PlayerHotbarType.AssignmentKind.FISH:
|
||||||
|
selected_identity = _local_hotbar.get_selected_fish_catch_id()
|
||||||
|
_on_selected_assignment_changed(
|
||||||
|
_local_hotbar.get_selected_slot(),
|
||||||
|
selected_kind,
|
||||||
|
selected_identity,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
func toggle_selected_fish() -> bool:
|
func toggle_selected_fish() -> bool:
|
||||||
|
|
@ -180,7 +193,7 @@ func _apply_state(data: Dictionary) -> void:
|
||||||
if avatar == null:
|
if avatar == null:
|
||||||
return
|
return
|
||||||
if not bool(data["visible"]):
|
if not bool(data["visible"]):
|
||||||
avatar.set_held_fish(null, 1.0, false)
|
avatar.set_held_fish(null, 1.0, false, true)
|
||||||
return
|
return
|
||||||
var fish: FishDataType = _fish_catalog.get_fish_by_id(
|
var fish: FishDataType = _fish_catalog.get_fish_by_id(
|
||||||
StringName(str(data["fish_id"]))
|
StringName(str(data["fish_id"]))
|
||||||
|
|
@ -197,13 +210,16 @@ func _on_selected_assignment_changed(
|
||||||
kind: int,
|
kind: int,
|
||||||
identity: StringName,
|
identity: StringName,
|
||||||
) -> void:
|
) -> void:
|
||||||
if (
|
if kind == PlayerHotbarType.AssignmentKind.FISH:
|
||||||
_local_visible
|
if _local_visible and identity == _local_catch_id:
|
||||||
and (
|
return
|
||||||
kind != PlayerHotbarType.AssignmentKind.FISH
|
var fish_catch: FishCatchType = _local_inventory.get_catch_by_id(identity)
|
||||||
or identity != _local_catch_id
|
if fish_catch != null and fish_catch.is_valid():
|
||||||
)
|
_submit_local_state(fish_catch, true)
|
||||||
):
|
elif _local_visible:
|
||||||
|
_submit_local_state(null, false)
|
||||||
|
return
|
||||||
|
if _local_visible:
|
||||||
_submit_local_state(null, false)
|
_submit_local_state(null, false)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -353,7 +353,10 @@ func _apply_equipped(data: Dictionary) -> void:
|
||||||
if avatar != null:
|
if avatar != null:
|
||||||
var item_id := StringName(str(data["item_id"]))
|
var item_id := StringName(str(data["item_id"]))
|
||||||
var item: ItemData = _catalog.get_item_by_id(item_id)
|
var item: ItemData = _catalog.get_item_by_id(item_id)
|
||||||
avatar.set_active_item_is_rod(int(data["category"]) == ItemData.Category.ROD)
|
avatar.set_active_item_is_rod(
|
||||||
|
int(data["category"]) == ItemData.Category.ROD,
|
||||||
|
true,
|
||||||
|
)
|
||||||
avatar.set_active_art_kit(
|
avatar.set_active_art_kit(
|
||||||
item.icon if item != null else null,
|
item.icon if item != null else null,
|
||||||
item_id == ArtShopStockType.ART_KIT_ITEM_ID and bool(data["owns_item"]),
|
item_id == ArtShopStockType.ART_KIT_ITEM_ID and bool(data["owns_item"]),
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,9 @@ albedo_color = Color(0.22, 0.12, 0.06, 1)
|
||||||
roughness = 0.8
|
roughness = 0.8
|
||||||
|
|
||||||
[node name="FishingRodAttachment" type="BoneAttachment3D"]
|
[node name="FishingRodAttachment" type="BoneAttachment3D"]
|
||||||
bone_name = "hand.R"
|
bone_name = "rod_socket"
|
||||||
|
|
||||||
[node name="FishingRod" type="Node3D" parent="."]
|
[node name="FishingRod" type="Node3D" parent="."]
|
||||||
rotation_degrees = Vector3(65, 0, 0)
|
|
||||||
|
|
||||||
[node name="RodMesh" type="MeshInstance3D" parent="FishingRod"]
|
[node name="RodMesh" type="MeshInstance3D" parent="FishingRod"]
|
||||||
position = Vector3(0, 0.5, 0)
|
position = Vector3(0, 0.5, 0)
|
||||||
|
|
|
||||||
516
player/player.gd
516
player/player.gd
|
|
@ -35,14 +35,26 @@ const HeldItemAttachmentScene = preload(
|
||||||
"res://player/held_item_attachment.tscn"
|
"res://player/held_item_attachment.tscn"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
signal retract_visual_finished
|
||||||
|
|
||||||
const CHARACTER_IDLE_ANIMATION: StringName = &"idle"
|
const CHARACTER_IDLE_ANIMATION: StringName = &"idle"
|
||||||
const CHARACTER_IDLE_SHOW_ANIMATION: StringName = &"idle_show"
|
const CHARACTER_IDLE_SHOW_ANIMATION: StringName = &"idle_show"
|
||||||
const CHARACTER_IDLE_SIT_ANIMATION: StringName = &"idle_sit"
|
const CHARACTER_IDLE_SIT_ANIMATION: StringName = &"idle_sit"
|
||||||
const CHARACTER_IDLE_SIT_SHOW_ANIMATION: StringName = &"idle_sit_show"
|
const CHARACTER_IDLE_SIT_SHOW_ANIMATION: StringName = &"idle_sit_show"
|
||||||
const CHARACTER_WALKING_ANIMATION: StringName = &"walking"
|
const CHARACTER_WALKING_ANIMATION: StringName = &"walking"
|
||||||
const CHARACTER_WALKING_SHOW_ANIMATION: StringName = &"walking_show"
|
const CHARACTER_WALKING_SHOW_ANIMATION: StringName = &"walking_show"
|
||||||
|
const CHARACTER_RUNNING_ANIMATION: StringName = &"running"
|
||||||
|
const CHARACTER_RUNNING_SHOW_ANIMATION: StringName = &"running_show"
|
||||||
const CHARACTER_CASTING_ANIMATION: StringName = &"casting"
|
const CHARACTER_CASTING_ANIMATION: StringName = &"casting"
|
||||||
|
const CHARACTER_CASTING_SIT_ANIMATION: StringName = &"casting_sit"
|
||||||
const CHARACTER_RELEASE_ANIMATION: StringName = &"release"
|
const CHARACTER_RELEASE_ANIMATION: StringName = &"release"
|
||||||
|
const CHARACTER_RELEASE_SIT_ANIMATION: StringName = &"release_sit"
|
||||||
|
const CHARACTER_RETRACT_ANIMATION: StringName = &"retract"
|
||||||
|
const CHARACTER_RETRACT_SIT_ANIMATION: StringName = &"retract_sit"
|
||||||
|
const CHARACTER_POCKET_IDLE_IDLE_ANIMATION: StringName = &"pocket_idle_idle"
|
||||||
|
const CHARACTER_POCKET_IDLE_SHOW_ANIMATION: StringName = &"pocket_idle_show"
|
||||||
|
const CHARACTER_POCKET_SHOW_SHOW_ANIMATION: StringName = &"pocket_show_show"
|
||||||
|
const CHARACTER_POCKET_SHOW_IDLE_ANIMATION: StringName = &"pocket_show_idle"
|
||||||
const CHARACTER_FISHING_ANIMATION: StringName = &"fishing"
|
const CHARACTER_FISHING_ANIMATION: StringName = &"fishing"
|
||||||
const CHARACTER_FISHING_SIT_ANIMATION: StringName = &"fishing_sit"
|
const CHARACTER_FISHING_SIT_ANIMATION: StringName = &"fishing_sit"
|
||||||
const CHARACTER_FIGHTING_ANIMATION: StringName = &"fighting"
|
const CHARACTER_FIGHTING_ANIMATION: StringName = &"fighting"
|
||||||
|
|
@ -52,8 +64,17 @@ enum FishingVisualPhase {
|
||||||
NONE,
|
NONE,
|
||||||
CASTING,
|
CASTING,
|
||||||
RELEASE,
|
RELEASE,
|
||||||
|
RETRACT,
|
||||||
FISHING,
|
FISHING,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum PocketVisualTarget {
|
||||||
|
NONE,
|
||||||
|
IDLE_ITEM,
|
||||||
|
HELD_FISH,
|
||||||
|
ART_KIT,
|
||||||
|
CATCH_SHOWCASE,
|
||||||
|
}
|
||||||
const FIGHTING_EYES_ID: String = "alligator_eyes"
|
const FIGHTING_EYES_ID: String = "alligator_eyes"
|
||||||
const BASE_REEL_SPEED: float = 0.16
|
const BASE_REEL_SPEED: float = 0.16
|
||||||
# The target Android handheld exposes its physical right trigger through
|
# The target Android handheld exposes its physical right trigger through
|
||||||
|
|
@ -130,6 +151,18 @@ func set_fighting_visual(active: bool) -> void:
|
||||||
|
|
||||||
|
|
||||||
func set_fishing_visual(active: bool) -> void:
|
func set_fishing_visual(active: bool) -> void:
|
||||||
|
if (
|
||||||
|
active
|
||||||
|
and _fishing_visual_phase == FishingVisualPhase.RELEASE
|
||||||
|
and _character_animation_name in [
|
||||||
|
CHARACTER_RELEASE_ANIMATION,
|
||||||
|
CHARACTER_RELEASE_SIT_ANIMATION,
|
||||||
|
]
|
||||||
|
and _character_animation_player != null
|
||||||
|
and _character_animation_player.is_playing()
|
||||||
|
):
|
||||||
|
_fishing_after_release_pending = true
|
||||||
|
return
|
||||||
_set_fishing_visual_phase(
|
_set_fishing_visual_phase(
|
||||||
FishingVisualPhase.FISHING if active else FishingVisualPhase.NONE
|
FishingVisualPhase.FISHING if active else FishingVisualPhase.NONE
|
||||||
)
|
)
|
||||||
|
|
@ -143,9 +176,32 @@ func set_release_visual() -> void:
|
||||||
_set_fishing_visual_phase(FishingVisualPhase.RELEASE)
|
_set_fishing_visual_phase(FishingVisualPhase.RELEASE)
|
||||||
|
|
||||||
|
|
||||||
|
func set_retract_visual() -> void:
|
||||||
|
_retract_animation_completed = false
|
||||||
|
_set_fishing_visual_phase(FishingVisualPhase.RETRACT)
|
||||||
|
if (
|
||||||
|
_character_animation_player == null
|
||||||
|
or _character_animation_name not in [
|
||||||
|
CHARACTER_RETRACT_ANIMATION,
|
||||||
|
CHARACTER_RETRACT_SIT_ANIMATION,
|
||||||
|
]
|
||||||
|
or not _character_animation_player.is_playing()
|
||||||
|
):
|
||||||
|
_complete_retract_animation()
|
||||||
|
|
||||||
|
|
||||||
func _set_fishing_visual_phase(phase: FishingVisualPhase) -> void:
|
func _set_fishing_visual_phase(phase: FishingVisualPhase) -> void:
|
||||||
|
if phase != FishingVisualPhase.NONE and _pocket_visual_active:
|
||||||
|
_complete_pocket_visual()
|
||||||
if _fishing_visual_phase == phase:
|
if _fishing_visual_phase == phase:
|
||||||
return
|
return
|
||||||
|
if (
|
||||||
|
_fishing_visual_phase == FishingVisualPhase.RETRACT
|
||||||
|
and phase != FishingVisualPhase.RETRACT
|
||||||
|
):
|
||||||
|
_complete_retract_animation()
|
||||||
|
if phase != FishingVisualPhase.RELEASE:
|
||||||
|
_fishing_after_release_pending = false
|
||||||
_fishing_visual_phase = phase
|
_fishing_visual_phase = phase
|
||||||
_fishing_visual_active = phase != FishingVisualPhase.NONE
|
_fishing_visual_active = phase != FishingVisualPhase.NONE
|
||||||
_character_animation_name = &""
|
_character_animation_name = &""
|
||||||
|
|
@ -304,19 +360,39 @@ var _sit_after_landing: bool = false
|
||||||
var _sitting_intent_pending: bool = false
|
var _sitting_intent_pending: bool = false
|
||||||
var _sitting_intent_sequence: int = -1
|
var _sitting_intent_sequence: int = -1
|
||||||
var _held_fish_visible: bool = false
|
var _held_fish_visible: bool = false
|
||||||
|
var _pending_held_fish_texture: Texture2D
|
||||||
|
var _pending_held_fish_scale: Vector3 = Vector3.ONE
|
||||||
|
var _held_art_kit_visible: bool = false
|
||||||
var _showcase_animation_active: bool = false
|
var _showcase_animation_active: bool = false
|
||||||
|
var _pocket_visual_active: bool = false
|
||||||
|
var _pocket_visual_target: PocketVisualTarget = PocketVisualTarget.NONE
|
||||||
|
var _pocket_visual_animation: StringName = &""
|
||||||
|
var _pocket_visual_finished_callback: Callable
|
||||||
|
var _pocket_visual_callback_runs_on_interrupt: bool = true
|
||||||
|
var _pocket_visual_midpoint_callback: Callable
|
||||||
|
var _pocket_visual_midpoint_called: bool = false
|
||||||
|
var _pocket_visual_generation: int = 0
|
||||||
var _fighting_visual_active: bool = false
|
var _fighting_visual_active: bool = false
|
||||||
var _fishing_visual_active: bool = false
|
var _fishing_visual_active: bool = false
|
||||||
var _fishing_visual_phase: FishingVisualPhase = FishingVisualPhase.NONE
|
var _fishing_visual_phase: FishingVisualPhase = FishingVisualPhase.NONE
|
||||||
|
var _fishing_after_release_pending: bool = false
|
||||||
|
var _retract_animation_completed: bool = true
|
||||||
var _fishing_rod: Node3D
|
var _fishing_rod: Node3D
|
||||||
var _fishing_rod_tip: Marker3D
|
var _fishing_rod_tip: Marker3D
|
||||||
var _fishing_rod_skeleton: Skeleton3D
|
var _active_item_is_rod: bool = false
|
||||||
var _fishing_rod_hand_bone: int = -1
|
|
||||||
var _fishing_rod_relative_basis: Basis = Basis.IDENTITY
|
|
||||||
var _controller_mapping_manager: ControllerMappingManagerType
|
var _controller_mapping_manager: ControllerMappingManagerType
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
|
if (
|
||||||
|
_character_animation_player != null
|
||||||
|
and not _character_animation_player.animation_finished.is_connected(
|
||||||
|
_on_character_animation_finished
|
||||||
|
)
|
||||||
|
):
|
||||||
|
_character_animation_player.animation_finished.connect(
|
||||||
|
_on_character_animation_finished
|
||||||
|
)
|
||||||
if not bag.contents_changed.is_connected(_on_bag_contents_changed):
|
if not bag.contents_changed.is_connected(_on_bag_contents_changed):
|
||||||
bag.contents_changed.connect(_on_bag_contents_changed)
|
bag.contents_changed.connect(_on_bag_contents_changed)
|
||||||
_apply_presented_appearance()
|
_apply_presented_appearance()
|
||||||
|
|
@ -362,38 +438,6 @@ func _initialize_fishing_rod() -> void:
|
||||||
_fishing_rod_tip = attachment.get_node(
|
_fishing_rod_tip = attachment.get_node(
|
||||||
"FishingRod/FishingRodTip"
|
"FishingRod/FishingRodTip"
|
||||||
) as Marker3D
|
) as Marker3D
|
||||||
_fishing_rod_skeleton = skeleton
|
|
||||||
_fishing_rod_hand_bone = skeleton.find_bone(&"hand.R")
|
|
||||||
if _fishing_rod_hand_bone < 0:
|
|
||||||
push_error("Player character right-hand bone is unavailable.")
|
|
||||||
return
|
|
||||||
_fishing_rod_relative_basis = (
|
|
||||||
skeleton.global_basis.orthonormalized().inverse()
|
|
||||||
* _fishing_rod.global_basis.orthonormalized()
|
|
||||||
)
|
|
||||||
_fishing_rod.top_level = true
|
|
||||||
_sync_fishing_rod_transform()
|
|
||||||
|
|
||||||
|
|
||||||
func _sync_fishing_rod_transform() -> void:
|
|
||||||
if (
|
|
||||||
_fishing_rod == null
|
|
||||||
or _fishing_rod_skeleton == null
|
|
||||||
or _fishing_rod_hand_bone < 0
|
|
||||||
):
|
|
||||||
return
|
|
||||||
var skeleton_transform := _fishing_rod_skeleton.global_transform
|
|
||||||
var hand_pose := _fishing_rod_skeleton.get_bone_global_pose(
|
|
||||||
_fishing_rod_hand_bone
|
|
||||||
)
|
|
||||||
var fixed_basis := (
|
|
||||||
skeleton_transform.basis.orthonormalized()
|
|
||||||
* _fishing_rod_relative_basis
|
|
||||||
)
|
|
||||||
_fishing_rod.global_transform = Transform3D(
|
|
||||||
fixed_basis.scaled(skeleton_transform.basis.get_scale().abs()),
|
|
||||||
(skeleton_transform * hand_pose).origin,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
func _initialize_held_item_attachment() -> void:
|
func _initialize_held_item_attachment() -> void:
|
||||||
|
|
@ -423,7 +467,6 @@ func _initialize_held_item_attachment() -> void:
|
||||||
|
|
||||||
|
|
||||||
func _physics_process(delta: float) -> void:
|
func _physics_process(delta: float) -> void:
|
||||||
_sync_fishing_rod_transform()
|
|
||||||
if _network_interpolation_enabled:
|
if _network_interpolation_enabled:
|
||||||
_update_network_interpolation(delta)
|
_update_network_interpolation(delta)
|
||||||
return
|
return
|
||||||
|
|
@ -516,7 +559,6 @@ func _physics_process(delta: float) -> void:
|
||||||
|
|
||||||
|
|
||||||
func _process(delta: float) -> void:
|
func _process(delta: float) -> void:
|
||||||
_sync_fishing_rod_transform()
|
|
||||||
_update_character_animation()
|
_update_character_animation()
|
||||||
# The hand bone supplies the attachment position, but its animated wrist
|
# The hand bone supplies the attachment position, but its animated wrist
|
||||||
# rotation should not turn the flat fish/catch artwork edge-on. Keep each
|
# rotation should not turn the flat fish/catch artwork edge-on. Keep each
|
||||||
|
|
@ -613,8 +655,22 @@ func _update_character_animation() -> void:
|
||||||
velocity.x * velocity.x + velocity.z * velocity.z
|
velocity.x * velocity.x + velocity.z * velocity.z
|
||||||
)
|
)
|
||||||
var is_walking: bool = horizontal_speed_squared > 0.0025
|
var is_walking: bool = horizontal_speed_squared > 0.0025
|
||||||
|
var fastest_non_sprint_speed := maxf(
|
||||||
|
walk_speed,
|
||||||
|
maxf(sneak_speed, slow_walk_speed)
|
||||||
|
)
|
||||||
|
var running_threshold := fastest_non_sprint_speed + 0.5
|
||||||
|
var is_running := (
|
||||||
|
is_walking
|
||||||
|
and horizontal_speed_squared > running_threshold * running_threshold
|
||||||
|
)
|
||||||
|
var held_show_item_visible: bool = (
|
||||||
|
_held_fish_visible or _held_art_kit_visible
|
||||||
|
)
|
||||||
var requested_animation: Array[StringName] = []
|
var requested_animation: Array[StringName] = []
|
||||||
if _showcase_animation_active:
|
if _pocket_visual_active:
|
||||||
|
requested_animation = [_pocket_visual_animation]
|
||||||
|
elif _showcase_animation_active:
|
||||||
if _sitting:
|
if _sitting:
|
||||||
requested_animation = [
|
requested_animation = [
|
||||||
CHARACTER_IDLE_SIT_SHOW_ANIMATION,
|
CHARACTER_IDLE_SIT_SHOW_ANIMATION,
|
||||||
|
|
@ -644,6 +700,27 @@ func _update_character_animation() -> void:
|
||||||
]
|
]
|
||||||
elif _fishing_visual_active:
|
elif _fishing_visual_active:
|
||||||
if _sitting:
|
if _sitting:
|
||||||
|
match _fishing_visual_phase:
|
||||||
|
FishingVisualPhase.CASTING:
|
||||||
|
requested_animation = [
|
||||||
|
CHARACTER_CASTING_SIT_ANIMATION,
|
||||||
|
CHARACTER_FISHING_SIT_ANIMATION,
|
||||||
|
CHARACTER_IDLE_SIT_ANIMATION,
|
||||||
|
]
|
||||||
|
FishingVisualPhase.RELEASE:
|
||||||
|
requested_animation = [
|
||||||
|
CHARACTER_RELEASE_SIT_ANIMATION,
|
||||||
|
CHARACTER_FISHING_SIT_ANIMATION,
|
||||||
|
CHARACTER_IDLE_SIT_ANIMATION,
|
||||||
|
]
|
||||||
|
FishingVisualPhase.RETRACT:
|
||||||
|
requested_animation = [
|
||||||
|
CHARACTER_RETRACT_SIT_ANIMATION,
|
||||||
|
CHARACTER_RETRACT_ANIMATION,
|
||||||
|
CHARACTER_FISHING_SIT_ANIMATION,
|
||||||
|
CHARACTER_IDLE_SIT_ANIMATION,
|
||||||
|
]
|
||||||
|
_:
|
||||||
requested_animation = [
|
requested_animation = [
|
||||||
CHARACTER_FISHING_SIT_ANIMATION,
|
CHARACTER_FISHING_SIT_ANIMATION,
|
||||||
CHARACTER_IDLE_SIT_ANIMATION,
|
CHARACTER_IDLE_SIT_ANIMATION,
|
||||||
|
|
@ -663,13 +740,19 @@ func _update_character_animation() -> void:
|
||||||
CHARACTER_FISHING_ANIMATION,
|
CHARACTER_FISHING_ANIMATION,
|
||||||
CHARACTER_IDLE_ANIMATION,
|
CHARACTER_IDLE_ANIMATION,
|
||||||
]
|
]
|
||||||
|
FishingVisualPhase.RETRACT:
|
||||||
|
requested_animation = [
|
||||||
|
CHARACTER_RETRACT_ANIMATION,
|
||||||
|
CHARACTER_FISHING_ANIMATION,
|
||||||
|
CHARACTER_IDLE_ANIMATION,
|
||||||
|
]
|
||||||
_:
|
_:
|
||||||
requested_animation = [
|
requested_animation = [
|
||||||
CHARACTER_FISHING_ANIMATION,
|
CHARACTER_FISHING_ANIMATION,
|
||||||
CHARACTER_IDLE_ANIMATION,
|
CHARACTER_IDLE_ANIMATION,
|
||||||
]
|
]
|
||||||
elif _sitting:
|
elif _sitting:
|
||||||
if _held_fish_visible:
|
if held_show_item_visible:
|
||||||
requested_animation = [
|
requested_animation = [
|
||||||
CHARACTER_IDLE_SIT_SHOW_ANIMATION,
|
CHARACTER_IDLE_SIT_SHOW_ANIMATION,
|
||||||
&"idle_sit_show_loop",
|
&"idle_sit_show_loop",
|
||||||
|
|
@ -684,12 +767,26 @@ func _update_character_animation() -> void:
|
||||||
&"sitting",
|
&"sitting",
|
||||||
&"idle_loop_sit",
|
&"idle_loop_sit",
|
||||||
]
|
]
|
||||||
elif is_walking and _held_fish_visible:
|
elif is_running and held_show_item_visible:
|
||||||
|
requested_animation = [
|
||||||
|
CHARACTER_RUNNING_SHOW_ANIMATION,
|
||||||
|
&"running_show_loop",
|
||||||
|
CHARACTER_WALKING_SHOW_ANIMATION,
|
||||||
|
&"walking_show_loop",
|
||||||
|
]
|
||||||
|
elif is_running:
|
||||||
|
requested_animation = [
|
||||||
|
CHARACTER_RUNNING_ANIMATION,
|
||||||
|
&"running_loop",
|
||||||
|
CHARACTER_WALKING_ANIMATION,
|
||||||
|
&"walking_loop",
|
||||||
|
]
|
||||||
|
elif is_walking and held_show_item_visible:
|
||||||
requested_animation = [
|
requested_animation = [
|
||||||
CHARACTER_WALKING_SHOW_ANIMATION,
|
CHARACTER_WALKING_SHOW_ANIMATION,
|
||||||
&"walking_show_loop",
|
&"walking_show_loop",
|
||||||
]
|
]
|
||||||
elif _held_fish_visible:
|
elif held_show_item_visible:
|
||||||
requested_animation = [
|
requested_animation = [
|
||||||
CHARACTER_IDLE_SHOW_ANIMATION,
|
CHARACTER_IDLE_SHOW_ANIMATION,
|
||||||
&"idle_show_loop",
|
&"idle_show_loop",
|
||||||
|
|
@ -716,6 +813,45 @@ func _update_character_animation() -> void:
|
||||||
_character_animation_name = next_animation
|
_character_animation_name = next_animation
|
||||||
|
|
||||||
|
|
||||||
|
func _on_character_animation_finished(animation_name: StringName) -> void:
|
||||||
|
if animation_name in [
|
||||||
|
CHARACTER_POCKET_IDLE_IDLE_ANIMATION,
|
||||||
|
CHARACTER_POCKET_IDLE_SHOW_ANIMATION,
|
||||||
|
CHARACTER_POCKET_SHOW_SHOW_ANIMATION,
|
||||||
|
CHARACTER_POCKET_SHOW_IDLE_ANIMATION,
|
||||||
|
]:
|
||||||
|
if _pocket_visual_active:
|
||||||
|
_complete_pocket_visual()
|
||||||
|
return
|
||||||
|
if animation_name in [
|
||||||
|
CHARACTER_RETRACT_ANIMATION,
|
||||||
|
CHARACTER_RETRACT_SIT_ANIMATION,
|
||||||
|
]:
|
||||||
|
_complete_retract_animation()
|
||||||
|
return
|
||||||
|
if (
|
||||||
|
not _fishing_after_release_pending
|
||||||
|
or animation_name not in [
|
||||||
|
CHARACTER_RELEASE_ANIMATION,
|
||||||
|
CHARACTER_RELEASE_SIT_ANIMATION,
|
||||||
|
]
|
||||||
|
):
|
||||||
|
return
|
||||||
|
_fishing_after_release_pending = false
|
||||||
|
_set_fishing_visual_phase(FishingVisualPhase.FISHING)
|
||||||
|
|
||||||
|
|
||||||
|
func is_retract_visual_complete() -> bool:
|
||||||
|
return _retract_animation_completed
|
||||||
|
|
||||||
|
|
||||||
|
func _complete_retract_animation() -> void:
|
||||||
|
if _retract_animation_completed:
|
||||||
|
return
|
||||||
|
_retract_animation_completed = true
|
||||||
|
retract_visual_finished.emit()
|
||||||
|
|
||||||
|
|
||||||
func toggle_sitting() -> void:
|
func toggle_sitting() -> void:
|
||||||
if _sit_after_landing:
|
if _sit_after_landing:
|
||||||
_sit_after_landing = false
|
_sit_after_landing = false
|
||||||
|
|
@ -1006,6 +1142,9 @@ func capture_network_input(sequence: int) -> Dictionary:
|
||||||
"sneak": false,
|
"sneak": false,
|
||||||
"slow_walk": false,
|
"slow_walk": false,
|
||||||
"sitting": _sitting,
|
"sitting": _sitting,
|
||||||
|
"casting": (
|
||||||
|
_fishing_visual_phase == FishingVisualPhase.CASTING
|
||||||
|
),
|
||||||
}
|
}
|
||||||
var axis: Vector2 = Input.get_vector(
|
var axis: Vector2 = Input.get_vector(
|
||||||
"move_left",
|
"move_left",
|
||||||
|
|
@ -1022,6 +1161,7 @@ func capture_network_input(sequence: int) -> Dictionary:
|
||||||
"sneak": Input.is_action_pressed("sneak"),
|
"sneak": Input.is_action_pressed("sneak"),
|
||||||
"slow_walk": Input.is_action_pressed("slow_walk"),
|
"slow_walk": Input.is_action_pressed("slow_walk"),
|
||||||
"sitting": _sitting,
|
"sitting": _sitting,
|
||||||
|
"casting": _fishing_visual_phase == FishingVisualPhase.CASTING,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1039,6 +1179,7 @@ func apply_authoritative_network_input(data: Dictionary) -> void:
|
||||||
_network_sprint = bool(data.get("sprint", false))
|
_network_sprint = bool(data.get("sprint", false))
|
||||||
_network_sneak = bool(data.get("sneak", false))
|
_network_sneak = bool(data.get("sneak", false))
|
||||||
_network_slow_walk = bool(data.get("slow_walk", false))
|
_network_slow_walk = bool(data.get("slow_walk", false))
|
||||||
|
_apply_network_casting(bool(data.get("casting", false)))
|
||||||
var sitting_requested: bool = bool(data.get("sitting", false))
|
var sitting_requested: bool = bool(data.get("sitting", false))
|
||||||
if sitting_requested and not is_on_floor():
|
if sitting_requested and not is_on_floor():
|
||||||
_sit_after_landing = true
|
_sit_after_landing = true
|
||||||
|
|
@ -1057,6 +1198,7 @@ func make_network_snapshot(peer_id: int) -> Dictionary:
|
||||||
"visual_yaw": _visuals.rotation.y,
|
"visual_yaw": _visuals.rotation.y,
|
||||||
"grounded": is_on_floor(),
|
"grounded": is_on_floor(),
|
||||||
"sitting": _sitting,
|
"sitting": _sitting,
|
||||||
|
"casting": _fishing_visual_phase == FishingVisualPhase.CASTING,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1068,6 +1210,7 @@ func push_network_snapshot(snapshot: Dictionary) -> void:
|
||||||
_network_target_velocity = parsed["velocity"]
|
_network_target_velocity = parsed["velocity"]
|
||||||
_network_target_visual_yaw = parsed["visual_yaw"]
|
_network_target_visual_yaw = parsed["visual_yaw"]
|
||||||
_network_snapshot_age = 0.0
|
_network_snapshot_age = 0.0
|
||||||
|
_apply_network_casting(bool(parsed["casting"]))
|
||||||
_set_sitting(bool(parsed["sitting"]))
|
_set_sitting(bool(parsed["sitting"]))
|
||||||
if not _network_snapshot_ready:
|
if not _network_snapshot_ready:
|
||||||
global_position = _network_target_position
|
global_position = _network_target_position
|
||||||
|
|
@ -1108,6 +1251,7 @@ func apply_network_teleport(snapshot: Dictionary) -> void:
|
||||||
global_position = parsed["position"]
|
global_position = parsed["position"]
|
||||||
velocity = parsed["velocity"]
|
velocity = parsed["velocity"]
|
||||||
_visuals.rotation.y = parsed["visual_yaw"]
|
_visuals.rotation.y = parsed["visual_yaw"]
|
||||||
|
_apply_network_casting(bool(parsed["casting"]))
|
||||||
_set_sitting(bool(parsed["sitting"]))
|
_set_sitting(bool(parsed["sitting"]))
|
||||||
_network_target_position = global_position
|
_network_target_position = global_position
|
||||||
_network_target_velocity = velocity
|
_network_target_velocity = velocity
|
||||||
|
|
@ -1151,6 +1295,9 @@ func _parse_network_snapshot(snapshot: Dictionary) -> Dictionary:
|
||||||
if snapshot.has("sitting") and typeof(snapshot.get("sitting")) != TYPE_BOOL:
|
if snapshot.has("sitting") and typeof(snapshot.get("sitting")) != TYPE_BOOL:
|
||||||
return {}
|
return {}
|
||||||
var sitting: bool = bool(snapshot.get("sitting", false))
|
var sitting: bool = bool(snapshot.get("sitting", false))
|
||||||
|
if snapshot.has("casting") and typeof(snapshot.get("casting")) != TYPE_BOOL:
|
||||||
|
return {}
|
||||||
|
var casting: bool = bool(snapshot.get("casting", false))
|
||||||
if (
|
if (
|
||||||
not parsed_position.is_finite()
|
not parsed_position.is_finite()
|
||||||
or not parsed_velocity.is_finite()
|
or not parsed_velocity.is_finite()
|
||||||
|
|
@ -1163,9 +1310,18 @@ func _parse_network_snapshot(snapshot: Dictionary) -> Dictionary:
|
||||||
"visual_yaw": visual_yaw,
|
"visual_yaw": visual_yaw,
|
||||||
"acknowledged_input": acknowledged_input,
|
"acknowledged_input": acknowledged_input,
|
||||||
"sitting": sitting,
|
"sitting": sitting,
|
||||||
|
"casting": casting,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func _apply_network_casting(casting: bool) -> void:
|
||||||
|
if casting:
|
||||||
|
if _fishing_visual_phase == FishingVisualPhase.NONE:
|
||||||
|
set_casting_visual()
|
||||||
|
elif _fishing_visual_phase == FishingVisualPhase.CASTING:
|
||||||
|
set_fishing_visual(false)
|
||||||
|
|
||||||
|
|
||||||
func _update_network_interpolation(delta: float) -> void:
|
func _update_network_interpolation(delta: float) -> void:
|
||||||
if not _network_snapshot_ready:
|
if not _network_snapshot_ready:
|
||||||
return
|
return
|
||||||
|
|
@ -1324,41 +1480,274 @@ func get_fishing_rod() -> Node3D:
|
||||||
return _fishing_rod
|
return _fishing_rod
|
||||||
|
|
||||||
|
|
||||||
func set_active_item_is_rod(active_is_rod: bool) -> void:
|
func set_active_item_is_rod(
|
||||||
|
active_is_rod: bool,
|
||||||
|
animate_transition: bool = false,
|
||||||
|
) -> void:
|
||||||
|
_active_item_is_rod = active_is_rod
|
||||||
if _showcase_rod_state_stored:
|
if _showcase_rod_state_stored:
|
||||||
_showcase_rod_visibility = active_is_rod
|
_showcase_rod_visibility = active_is_rod
|
||||||
else:
|
return
|
||||||
|
var visibility_changed: bool = _fishing_rod.visible != active_is_rod
|
||||||
|
if not animate_transition or not visibility_changed:
|
||||||
_fishing_rod.visible = active_is_rod
|
_fishing_rod.visible = active_is_rod
|
||||||
|
return
|
||||||
|
if _has_held_show_item() or _showcase_animation_active:
|
||||||
|
if not active_is_rod:
|
||||||
|
_fishing_rod.visible = false
|
||||||
|
return
|
||||||
|
if active_is_rod:
|
||||||
|
_fishing_rod.visible = false
|
||||||
|
_begin_pocket_visual(
|
||||||
|
PocketVisualTarget.IDLE_ITEM,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
_apply_active_rod_visibility,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func _apply_active_rod_visibility() -> void:
|
||||||
|
if _showcase_rod_state_stored:
|
||||||
|
_showcase_rod_visibility = _active_item_is_rod
|
||||||
|
return
|
||||||
|
_fishing_rod.visible = _active_item_is_rod
|
||||||
|
|
||||||
|
|
||||||
func set_active_art_kit(icon: Texture2D, should_show: bool) -> void:
|
func set_active_art_kit(icon: Texture2D, should_show: bool) -> void:
|
||||||
_held_art_kit_sprite.texture = icon if should_show else null
|
var new_visible: bool = should_show and icon != null
|
||||||
_held_art_kit_sprite.visible = should_show and icon != null
|
if not new_visible:
|
||||||
|
if _held_art_kit_visible:
|
||||||
|
_begin_pocket_visual(
|
||||||
|
PocketVisualTarget.ART_KIT,
|
||||||
|
true,
|
||||||
|
_held_fish_visible,
|
||||||
|
_clear_active_art_kit,
|
||||||
|
true,
|
||||||
|
_apply_pending_held_fish,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
_clear_active_art_kit()
|
||||||
|
return
|
||||||
|
var previous_show_pose: bool = _has_held_show_item()
|
||||||
|
var item_changed: bool = (
|
||||||
|
not _held_art_kit_visible
|
||||||
|
or _held_art_kit_sprite.texture != icon
|
||||||
|
)
|
||||||
|
_held_art_kit_visible = true
|
||||||
|
_held_art_kit_sprite.texture = icon
|
||||||
|
_held_art_kit_sprite.visible = true
|
||||||
|
_fishing_rod.visible = false
|
||||||
|
if item_changed:
|
||||||
|
_begin_pocket_visual(
|
||||||
|
PocketVisualTarget.ART_KIT,
|
||||||
|
previous_show_pose,
|
||||||
|
true,
|
||||||
|
Callable(),
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
_update_character_animation()
|
||||||
|
|
||||||
|
|
||||||
func set_held_fish(
|
func set_held_fish(
|
||||||
fish: FishDataType,
|
fish: FishDataType,
|
||||||
display_scale: float,
|
display_scale: float,
|
||||||
should_show: bool,
|
should_show: bool,
|
||||||
|
animate_put_away: bool = false,
|
||||||
) -> void:
|
) -> void:
|
||||||
if not should_show or fish == null or fish.display_texture == null:
|
if not should_show or fish == null or fish.display_texture == null:
|
||||||
_held_fish_visible = false
|
if animate_put_away and _held_fish_visible:
|
||||||
_held_fish_display.visible = false
|
_begin_pocket_visual(
|
||||||
_held_fish_display.scale = Vector3.ONE
|
PocketVisualTarget.HELD_FISH,
|
||||||
_held_fish_sprite.texture = null
|
true,
|
||||||
_update_character_animation()
|
_held_art_kit_visible,
|
||||||
|
_clear_held_fish,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
if _pocket_visual_target == PocketVisualTarget.HELD_FISH:
|
||||||
|
_cancel_pocket_visual()
|
||||||
|
_clear_held_fish()
|
||||||
return
|
return
|
||||||
|
var previous_show_pose: bool = _has_held_show_item()
|
||||||
|
var item_changed: bool = (
|
||||||
|
not _held_fish_visible
|
||||||
|
or _held_fish_sprite.texture != fish.display_texture
|
||||||
|
)
|
||||||
_held_fish_visible = true
|
_held_fish_visible = true
|
||||||
_held_fish_sprite.texture = fish.display_texture
|
_pending_held_fish_texture = fish.display_texture
|
||||||
_held_fish_display.scale = (
|
_pending_held_fish_scale = (
|
||||||
Vector3.ONE
|
Vector3.ONE
|
||||||
* maxf(display_scale, 0.01)
|
* maxf(display_scale, 0.01)
|
||||||
* catch_presentation_base_scale
|
* catch_presentation_base_scale
|
||||||
)
|
)
|
||||||
_held_fish_display.visible = true
|
if not previous_show_pose:
|
||||||
|
_held_fish_display.visible = false
|
||||||
|
_fishing_rod.visible = false
|
||||||
|
if item_changed:
|
||||||
|
_begin_pocket_visual(
|
||||||
|
PocketVisualTarget.HELD_FISH,
|
||||||
|
previous_show_pose,
|
||||||
|
true,
|
||||||
|
Callable(),
|
||||||
|
false,
|
||||||
|
_apply_pending_held_fish,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
_apply_pending_held_fish()
|
||||||
_update_character_animation()
|
_update_character_animation()
|
||||||
|
|
||||||
|
|
||||||
|
func _has_held_show_item() -> bool:
|
||||||
|
return _held_fish_visible or _held_art_kit_visible
|
||||||
|
|
||||||
|
|
||||||
|
func _clear_held_fish() -> void:
|
||||||
|
var was_visible: bool = _held_fish_visible
|
||||||
|
_held_fish_visible = false
|
||||||
|
_pending_held_fish_texture = null
|
||||||
|
_pending_held_fish_scale = Vector3.ONE
|
||||||
|
_held_fish_display.visible = false
|
||||||
|
_held_fish_display.scale = Vector3.ONE
|
||||||
|
_held_fish_sprite.texture = null
|
||||||
|
if was_visible:
|
||||||
|
_apply_active_rod_visibility()
|
||||||
|
_update_character_animation()
|
||||||
|
|
||||||
|
|
||||||
|
func _apply_pending_held_fish() -> void:
|
||||||
|
if not _held_fish_visible or _pending_held_fish_texture == null:
|
||||||
|
return
|
||||||
|
_held_fish_sprite.texture = _pending_held_fish_texture
|
||||||
|
_held_fish_display.scale = _pending_held_fish_scale
|
||||||
|
_held_fish_display.visible = true
|
||||||
|
|
||||||
|
|
||||||
|
func _clear_active_art_kit() -> void:
|
||||||
|
var was_visible: bool = _held_art_kit_visible
|
||||||
|
_held_art_kit_visible = false
|
||||||
|
_held_art_kit_sprite.texture = null
|
||||||
|
_held_art_kit_sprite.visible = false
|
||||||
|
if was_visible:
|
||||||
|
_apply_active_rod_visibility()
|
||||||
|
if _held_fish_visible:
|
||||||
|
_apply_pending_held_fish()
|
||||||
|
_update_character_animation()
|
||||||
|
|
||||||
|
|
||||||
|
func _begin_pocket_visual(
|
||||||
|
target: PocketVisualTarget,
|
||||||
|
starts_in_show_pose: bool,
|
||||||
|
ends_in_show_pose: bool,
|
||||||
|
finished_callback: Callable,
|
||||||
|
callback_runs_on_interrupt: bool = true,
|
||||||
|
midpoint_callback: Callable = Callable(),
|
||||||
|
) -> void:
|
||||||
|
var animation_name: StringName
|
||||||
|
if starts_in_show_pose:
|
||||||
|
animation_name = (
|
||||||
|
CHARACTER_POCKET_SHOW_SHOW_ANIMATION
|
||||||
|
if ends_in_show_pose
|
||||||
|
else CHARACTER_POCKET_SHOW_IDLE_ANIMATION
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
animation_name = (
|
||||||
|
CHARACTER_POCKET_IDLE_SHOW_ANIMATION
|
||||||
|
if ends_in_show_pose
|
||||||
|
else CHARACTER_POCKET_IDLE_IDLE_ANIMATION
|
||||||
|
)
|
||||||
|
if _pocket_visual_active:
|
||||||
|
if (
|
||||||
|
_pocket_visual_target == target
|
||||||
|
and _pocket_visual_animation == animation_name
|
||||||
|
):
|
||||||
|
return
|
||||||
|
if _pocket_visual_callback_runs_on_interrupt:
|
||||||
|
_complete_pocket_visual()
|
||||||
|
else:
|
||||||
|
_cancel_pocket_visual()
|
||||||
|
if (
|
||||||
|
_sitting
|
||||||
|
or animation_name.is_empty()
|
||||||
|
or _character_animation_player == null
|
||||||
|
or not _character_animation_player.has_animation(animation_name)
|
||||||
|
):
|
||||||
|
if midpoint_callback.is_valid():
|
||||||
|
midpoint_callback.call()
|
||||||
|
if finished_callback.is_valid():
|
||||||
|
finished_callback.call()
|
||||||
|
_update_character_animation()
|
||||||
|
return
|
||||||
|
_pocket_visual_active = true
|
||||||
|
_pocket_visual_target = target
|
||||||
|
_pocket_visual_animation = animation_name
|
||||||
|
_pocket_visual_finished_callback = finished_callback
|
||||||
|
_pocket_visual_callback_runs_on_interrupt = callback_runs_on_interrupt
|
||||||
|
_pocket_visual_midpoint_callback = midpoint_callback
|
||||||
|
_pocket_visual_midpoint_called = false
|
||||||
|
_pocket_visual_generation += 1
|
||||||
|
var midpoint_generation: int = _pocket_visual_generation
|
||||||
|
_update_character_animation()
|
||||||
|
_schedule_pocket_visual_midpoint(midpoint_generation, animation_name)
|
||||||
|
|
||||||
|
|
||||||
|
func _schedule_pocket_visual_midpoint(
|
||||||
|
generation: int,
|
||||||
|
animation_name: StringName,
|
||||||
|
) -> void:
|
||||||
|
if not _pocket_visual_midpoint_callback.is_valid():
|
||||||
|
return
|
||||||
|
var animation: Animation = _character_animation_player.get_animation(
|
||||||
|
animation_name
|
||||||
|
)
|
||||||
|
var midpoint_seconds: float = maxf(animation.length * 0.5, 0.0)
|
||||||
|
if midpoint_seconds > 0.0:
|
||||||
|
await get_tree().create_timer(midpoint_seconds, false).timeout
|
||||||
|
if (
|
||||||
|
generation != _pocket_visual_generation
|
||||||
|
or not _pocket_visual_active
|
||||||
|
or _pocket_visual_animation != animation_name
|
||||||
|
):
|
||||||
|
return
|
||||||
|
_apply_pocket_visual_midpoint()
|
||||||
|
|
||||||
|
|
||||||
|
func _apply_pocket_visual_midpoint() -> void:
|
||||||
|
if _pocket_visual_midpoint_called:
|
||||||
|
return
|
||||||
|
_pocket_visual_midpoint_called = true
|
||||||
|
var midpoint_callback: Callable = _pocket_visual_midpoint_callback
|
||||||
|
_pocket_visual_midpoint_callback = Callable()
|
||||||
|
if midpoint_callback.is_valid():
|
||||||
|
midpoint_callback.call()
|
||||||
|
|
||||||
|
|
||||||
|
func _complete_pocket_visual() -> void:
|
||||||
|
if not _pocket_visual_active:
|
||||||
|
return
|
||||||
|
var finished_callback: Callable = _pocket_visual_finished_callback
|
||||||
|
_pocket_visual_active = false
|
||||||
|
_pocket_visual_target = PocketVisualTarget.NONE
|
||||||
|
_pocket_visual_animation = &""
|
||||||
|
_pocket_visual_finished_callback = Callable()
|
||||||
|
_pocket_visual_callback_runs_on_interrupt = true
|
||||||
|
_pocket_visual_midpoint_callback = Callable()
|
||||||
|
_pocket_visual_midpoint_called = false
|
||||||
|
_pocket_visual_generation += 1
|
||||||
|
if finished_callback.is_valid():
|
||||||
|
finished_callback.call()
|
||||||
|
_update_character_animation()
|
||||||
|
|
||||||
|
|
||||||
|
func _cancel_pocket_visual() -> void:
|
||||||
|
_pocket_visual_active = false
|
||||||
|
_pocket_visual_target = PocketVisualTarget.NONE
|
||||||
|
_pocket_visual_animation = &""
|
||||||
|
_pocket_visual_finished_callback = Callable()
|
||||||
|
_pocket_visual_callback_runs_on_interrupt = true
|
||||||
|
_pocket_visual_midpoint_callback = Callable()
|
||||||
|
_pocket_visual_midpoint_called = false
|
||||||
|
_pocket_visual_generation += 1
|
||||||
|
|
||||||
|
|
||||||
func get_cast_origin_position() -> Vector3:
|
func get_cast_origin_position() -> Vector3:
|
||||||
return _cast_origin.global_position
|
return _cast_origin.global_position
|
||||||
|
|
||||||
|
|
@ -1366,8 +1755,9 @@ func get_cast_origin_position() -> Vector3:
|
||||||
func begin_catch_showcase(fish_catch: FishCatchType) -> void:
|
func begin_catch_showcase(fish_catch: FishCatchType) -> void:
|
||||||
if fish_catch == null or not fish_catch.is_valid():
|
if fish_catch == null or not fish_catch.is_valid():
|
||||||
return
|
return
|
||||||
|
if _pocket_visual_target == PocketVisualTarget.CATCH_SHOWCASE:
|
||||||
|
_cancel_pocket_visual()
|
||||||
_showcase_animation_active = true
|
_showcase_animation_active = true
|
||||||
_update_character_animation()
|
|
||||||
_kill_showcase_camera_tween()
|
_kill_showcase_camera_tween()
|
||||||
_kill_showcase_restore_tween()
|
_kill_showcase_restore_tween()
|
||||||
_capture_showcase_camera_snapshot()
|
_capture_showcase_camera_snapshot()
|
||||||
|
|
@ -1387,6 +1777,7 @@ func begin_catch_showcase(fish_catch: FishCatchType) -> void:
|
||||||
* catch_presentation_base_scale
|
* catch_presentation_base_scale
|
||||||
)
|
)
|
||||||
_catch_display.visible = _catch_sprite.texture != null
|
_catch_display.visible = _catch_sprite.texture != null
|
||||||
|
_update_character_animation()
|
||||||
|
|
||||||
|
|
||||||
func begin_remote_catch_showcase(fish_catch: FishCatchType) -> void:
|
func begin_remote_catch_showcase(fish_catch: FishCatchType) -> void:
|
||||||
|
|
@ -1394,7 +1785,6 @@ func begin_remote_catch_showcase(fish_catch: FishCatchType) -> void:
|
||||||
return
|
return
|
||||||
end_catch_showcase(Callable(), true)
|
end_catch_showcase(Callable(), true)
|
||||||
_showcase_animation_active = true
|
_showcase_animation_active = true
|
||||||
_update_character_animation()
|
|
||||||
_showcase_rod_visibility = _fishing_rod.visible
|
_showcase_rod_visibility = _fishing_rod.visible
|
||||||
_showcase_rod_state_stored = true
|
_showcase_rod_state_stored = true
|
||||||
_fishing_rod.visible = false
|
_fishing_rod.visible = false
|
||||||
|
|
@ -1405,12 +1795,28 @@ func begin_remote_catch_showcase(fish_catch: FishCatchType) -> void:
|
||||||
* catch_presentation_base_scale
|
* catch_presentation_base_scale
|
||||||
)
|
)
|
||||||
_catch_display.visible = _catch_sprite.texture != null
|
_catch_display.visible = _catch_sprite.texture != null
|
||||||
|
_update_character_animation()
|
||||||
|
|
||||||
|
|
||||||
func end_catch_showcase(
|
func end_catch_showcase(
|
||||||
restored_callback: Callable = Callable(),
|
restored_callback: Callable = Callable(),
|
||||||
immediate: bool = false,
|
immediate: bool = false,
|
||||||
|
pocket_completed: bool = false,
|
||||||
) -> void:
|
) -> void:
|
||||||
|
if immediate and _pocket_visual_target == PocketVisualTarget.CATCH_SHOWCASE:
|
||||||
|
_cancel_pocket_visual()
|
||||||
|
elif (
|
||||||
|
not pocket_completed
|
||||||
|
and _showcase_animation_active
|
||||||
|
and _catch_display.visible
|
||||||
|
):
|
||||||
|
_begin_pocket_visual(
|
||||||
|
PocketVisualTarget.CATCH_SHOWCASE,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
end_catch_showcase.bind(restored_callback, false, true),
|
||||||
|
)
|
||||||
|
return
|
||||||
_showcase_animation_active = false
|
_showcase_animation_active = false
|
||||||
_update_character_animation()
|
_update_character_animation()
|
||||||
_kill_showcase_turn_tween()
|
_kill_showcase_turn_tween()
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ func _run_host() -> void:
|
||||||
) as PlayerSpawnService
|
) as PlayerSpawnService
|
||||||
var remote_avatar: Player = spawn_service.get_avatar(remote_peer_id)
|
var remote_avatar: Player = spawn_service.get_avatar(remote_peer_id)
|
||||||
assert(remote_avatar != null)
|
assert(remote_avatar != null)
|
||||||
var remote_display := remote_avatar.get_node("%HeldFishDisplay") as Node3D
|
var remote_display := remote_avatar.get("_held_fish_display") as Node3D
|
||||||
var visible_deadline: int = Time.get_ticks_msec() + 10000
|
var visible_deadline: int = Time.get_ticks_msec() + 10000
|
||||||
while Time.get_ticks_msec() < visible_deadline and not remote_display.visible:
|
while Time.get_ticks_msec() < visible_deadline and not remote_display.visible:
|
||||||
await process_frame
|
await process_frame
|
||||||
|
|
@ -95,13 +95,23 @@ func _run_client() -> void:
|
||||||
) as PlayerSpawnService
|
) as PlayerSpawnService
|
||||||
var host_avatar: Player = spawn_service.get_avatar(1)
|
var host_avatar: Player = spawn_service.get_avatar(1)
|
||||||
assert(host_avatar != null)
|
assert(host_avatar != null)
|
||||||
var host_display := host_avatar.get_node("%HeldFishDisplay") as Node3D
|
var host_display := host_avatar.get("_held_fish_display") as Node3D
|
||||||
var snapshot_deadline: int = Time.get_ticks_msec() + 10000
|
var snapshot_deadline: int = Time.get_ticks_msec() + 10000
|
||||||
while Time.get_ticks_msec() < snapshot_deadline and not host_display.visible:
|
while Time.get_ticks_msec() < snapshot_deadline and not host_display.visible:
|
||||||
await process_frame
|
await process_frame
|
||||||
assert(host_display.visible)
|
assert(host_display.visible)
|
||||||
|
|
||||||
var player := main.get("_player") as Player
|
var player := main.get("_player") as Player
|
||||||
|
var animation_player := player.get_node(
|
||||||
|
"Visuals/CharacterRig/AnimationPlayer"
|
||||||
|
) as AnimationPlayer
|
||||||
|
for animation_name: StringName in [
|
||||||
|
&"pocket_idle_idle",
|
||||||
|
&"pocket_idle_show",
|
||||||
|
&"pocket_show_show",
|
||||||
|
&"pocket_show_idle",
|
||||||
|
]:
|
||||||
|
assert(animation_player.has_animation(animation_name))
|
||||||
var service := main.get_node(
|
var service := main.get_node(
|
||||||
"%NetworkFishShowcaseService"
|
"%NetworkFishShowcaseService"
|
||||||
) as NetworkFishShowcaseService
|
) as NetworkFishShowcaseService
|
||||||
|
|
@ -109,11 +119,16 @@ func _run_client() -> void:
|
||||||
assert(player.hotbar.assign_fish(1, fish_catch.catch_id))
|
assert(player.hotbar.assign_fish(1, fish_catch.catch_id))
|
||||||
assert(player.hotbar.select_slot(1))
|
assert(player.hotbar.select_slot(1))
|
||||||
assert(service.toggle_selected_fish())
|
assert(service.toggle_selected_fish())
|
||||||
assert((player.get_node("%HeldFishDisplay") as Node3D).visible)
|
assert((player.get("_held_fish_display") as Node3D).visible)
|
||||||
await create_timer(2.0).timeout
|
await create_timer(2.0).timeout
|
||||||
assert(service.toggle_selected_fish())
|
assert(service.toggle_selected_fish())
|
||||||
assert(not (player.get_node("%HeldFishDisplay") as Node3D).visible)
|
var held_display := player.get("_held_fish_display") as Node3D
|
||||||
await create_timer(1.0).timeout
|
assert(held_display.visible)
|
||||||
|
assert(animation_player.current_animation == &"pocket_show_idle")
|
||||||
|
var pocket_deadline: int = Time.get_ticks_msec() + 5000
|
||||||
|
while Time.get_ticks_msec() < pocket_deadline and held_display.visible:
|
||||||
|
await process_frame
|
||||||
|
assert(not held_display.visible)
|
||||||
print("Fish showcase multiplayer client validation: PASS")
|
print("Fish showcase multiplayer client validation: PASS")
|
||||||
session.disconnect_session("")
|
session.disconnect_session("")
|
||||||
main.queue_free()
|
main.queue_free()
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,30 @@ func _run_host() -> void:
|
||||||
var remote_visuals := remote_avatar.get_node("Visuals") as Node3D
|
var remote_visuals := remote_avatar.get_node("Visuals") as Node3D
|
||||||
remote_visuals.rotation.y = PI * 0.5
|
remote_visuals.rotation.y = PI * 0.5
|
||||||
session.publish_authoritative_teleport(remote_peer_id)
|
session.publish_authoritative_teleport(remote_peer_id)
|
||||||
|
var aiming_deadline: int = Time.get_ticks_msec() + 5000
|
||||||
|
while (
|
||||||
|
Time.get_ticks_msec() < aiming_deadline
|
||||||
|
and int(remote_avatar.get("_fishing_visual_phase"))
|
||||||
|
!= Player.FishingVisualPhase.CASTING
|
||||||
|
):
|
||||||
|
await process_frame
|
||||||
|
assert(
|
||||||
|
int(remote_avatar.get("_fishing_visual_phase"))
|
||||||
|
== Player.FishingVisualPhase.CASTING
|
||||||
|
)
|
||||||
|
var remote_position_error := (
|
||||||
|
remote_avatar.global_position - Vector3(-0.5, 3.95, 2.1)
|
||||||
|
)
|
||||||
|
remote_position_error.y = 0.0
|
||||||
|
assert(
|
||||||
|
remote_position_error.length() <= 0.25,
|
||||||
|
"remote casting position drifted: %s" % remote_avatar.global_position
|
||||||
|
)
|
||||||
|
assert(
|
||||||
|
remote_avatar.get_facing_direction().dot(Vector3.LEFT) > 0.99,
|
||||||
|
"remote casting facing drifted: %s"
|
||||||
|
% remote_avatar.get_facing_direction()
|
||||||
|
)
|
||||||
|
|
||||||
var saw_remote_attempt: bool = false
|
var saw_remote_attempt: bool = false
|
||||||
var remote_presentation: RemoteFishingPresentation
|
var remote_presentation: RemoteFishingPresentation
|
||||||
|
|
@ -65,8 +89,8 @@ func _run_host() -> void:
|
||||||
if peer_id == session.get_local_peer_id():
|
if peer_id == session.get_local_peer_id():
|
||||||
continue
|
continue
|
||||||
var attempt: NetworkFishingAttempt = attempts[peer_id]
|
var attempt: NetworkFishingAttempt = attempts[peer_id]
|
||||||
assert(is_equal_approx(attempt.target.y, 2.51))
|
assert(attempt.target.is_finite())
|
||||||
assert(attempt.bobber_position.y <= 2.51 + 0.001)
|
assert(attempt.bobber_position.distance_to(attempt.target) <= 0.001)
|
||||||
var presentations: Dictionary = service.get("_remote_presentations")
|
var presentations: Dictionary = service.get("_remote_presentations")
|
||||||
remote_presentation = presentations.get(peer_id)
|
remote_presentation = presentations.get(peer_id)
|
||||||
assert(remote_presentation != null)
|
assert(remote_presentation != null)
|
||||||
|
|
@ -78,6 +102,31 @@ func _run_host() -> void:
|
||||||
if saw_remote_attempt:
|
if saw_remote_attempt:
|
||||||
break
|
break
|
||||||
assert(saw_remote_attempt)
|
assert(saw_remote_attempt)
|
||||||
|
assert(
|
||||||
|
int(remote_avatar.get("_fishing_visual_phase"))
|
||||||
|
in [
|
||||||
|
Player.FishingVisualPhase.RELEASE,
|
||||||
|
Player.FishingVisualPhase.FISHING,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
var sitting_deadline: int = Time.get_ticks_msec() + 3000
|
||||||
|
while Time.get_ticks_msec() < sitting_deadline and not remote_avatar.is_sitting():
|
||||||
|
await process_frame
|
||||||
|
assert(remote_avatar.is_sitting())
|
||||||
|
var fishing_deadline: int = Time.get_ticks_msec() + 5000
|
||||||
|
while (
|
||||||
|
Time.get_ticks_msec() < fishing_deadline
|
||||||
|
and int(remote_avatar.get("_fishing_visual_phase"))
|
||||||
|
!= Player.FishingVisualPhase.FISHING
|
||||||
|
):
|
||||||
|
await process_frame
|
||||||
|
assert(
|
||||||
|
int(remote_avatar.get("_fishing_visual_phase"))
|
||||||
|
== Player.FishingVisualPhase.FISHING
|
||||||
|
)
|
||||||
|
var remote_animation_player := remote_avatar.get_node(
|
||||||
|
"Visuals/CharacterRig/AnimationPlayer"
|
||||||
|
) as AnimationPlayer
|
||||||
var return_deadline: int = Time.get_ticks_msec() + 5000
|
var return_deadline: int = Time.get_ticks_msec() + 5000
|
||||||
while (
|
while (
|
||||||
Time.get_ticks_msec() < return_deadline
|
Time.get_ticks_msec() < return_deadline
|
||||||
|
|
@ -85,8 +134,11 @@ func _run_host() -> void:
|
||||||
):
|
):
|
||||||
await process_frame
|
await process_frame
|
||||||
assert(not service.has_peer_attempt(remote_peer_id))
|
assert(not service.has_peer_attempt(remote_peer_id))
|
||||||
assert(is_instance_valid(remote_presentation))
|
assert(
|
||||||
assert(remote_presentation.get("_return_tween") != null)
|
int(remote_avatar.get("_fishing_visual_phase"))
|
||||||
|
== Player.FishingVisualPhase.RETRACT
|
||||||
|
)
|
||||||
|
assert(remote_animation_player.current_animation == &"retract_sit")
|
||||||
|
|
||||||
var completion_deadline: int = Time.get_ticks_msec() + 12000
|
var completion_deadline: int = Time.get_ticks_msec() + 12000
|
||||||
while (
|
while (
|
||||||
|
|
@ -119,8 +171,17 @@ func _run_client() -> void:
|
||||||
var service := main.get_node(
|
var service := main.get_node(
|
||||||
"%NetworkFishingService"
|
"%NetworkFishingService"
|
||||||
) as NetworkFishingService
|
) as NetworkFishingService
|
||||||
|
var cast_rejections: Array[String] = []
|
||||||
|
service.local_cast_rejected.connect(
|
||||||
|
func(message: String) -> void:
|
||||||
|
cast_rejections.append(message)
|
||||||
|
)
|
||||||
var fishing_spot := main.get_node("%FishingSpot") as FishingSpotType
|
var fishing_spot := main.get_node("%FishingSpot") as FishingSpotType
|
||||||
var player := main.get("_player") as Player
|
var player := main.get("_player") as Player
|
||||||
|
var character_animation_player := player.get_node(
|
||||||
|
"Visuals/CharacterRig/AnimationPlayer"
|
||||||
|
) as AnimationPlayer
|
||||||
|
assert(character_animation_player.has_animation(&"retract_sit"))
|
||||||
var placement_deadline: int = Time.get_ticks_msec() + 5000
|
var placement_deadline: int = Time.get_ticks_msec() + 5000
|
||||||
while (
|
while (
|
||||||
Time.get_ticks_msec() < placement_deadline
|
Time.get_ticks_msec() < placement_deadline
|
||||||
|
|
@ -131,14 +192,59 @@ func _run_client() -> void:
|
||||||
assert(player.global_position.distance_to(Vector3(-0.5, 3.95, 2.1)) <= 0.25)
|
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)
|
assert(player.get_facing_direction().dot(Vector3.LEFT) > 0.99)
|
||||||
|
|
||||||
|
player.set_casting_visual()
|
||||||
|
assert(
|
||||||
|
int(player.get("_fishing_visual_phase"))
|
||||||
|
== Player.FishingVisualPhase.CASTING
|
||||||
|
)
|
||||||
|
for _frame: int in 30:
|
||||||
|
await physics_frame
|
||||||
|
player.set_fishing_visual(false)
|
||||||
|
player.call("_set_sitting", true)
|
||||||
|
assert(player.is_sitting())
|
||||||
|
for _frame: int in 15:
|
||||||
|
await physics_frame
|
||||||
fishing_spot.call("_begin_aiming", player)
|
fishing_spot.call("_begin_aiming", player)
|
||||||
assert(player.is_movement_enabled())
|
assert(player.is_movement_enabled())
|
||||||
fishing_spot.set("_cast_charge", 0.32)
|
assert(
|
||||||
|
int(player.get("_fishing_visual_phase"))
|
||||||
|
== Player.FishingVisualPhase.CASTING
|
||||||
|
)
|
||||||
|
var cast_charge: float = 0.0
|
||||||
|
var target: Vector3 = Vector3.ZERO
|
||||||
|
var cast_origin: Vector3 = fishing_spot.get("_cast_origin_position")
|
||||||
|
for charge_step: int in range(1, 21):
|
||||||
|
var candidate_charge := float(charge_step) / 20.0
|
||||||
|
fishing_spot.set("_cast_charge", candidate_charge)
|
||||||
fishing_spot.call("_update_cast_charge", 0.0)
|
fishing_spot.call("_update_cast_charge", 0.0)
|
||||||
var target: Vector3 = fishing_spot.get("_cast_target")
|
var candidate_target: Vector3 = fishing_spot.get("_cast_target")
|
||||||
assert(fishing_spot.is_target_fishable(target))
|
var candidate_surface := fishing_spot.get(
|
||||||
assert(is_equal_approx(target.y, 2.51))
|
"_aim_surface_sample"
|
||||||
fishing_spot.call("_confirm_cast")
|
) as FishingSurfaceSample
|
||||||
|
if (
|
||||||
|
candidate_surface.is_fishable()
|
||||||
|
and fishing_spot.is_cast_path_clear(cast_origin, candidate_target)
|
||||||
|
):
|
||||||
|
cast_charge = candidate_charge
|
||||||
|
target = candidate_target
|
||||||
|
break
|
||||||
|
assert(cast_charge > 0.0, "no clear fishable test target was found")
|
||||||
|
var evidence: Dictionary = fishing_spot.call("_build_network_evidence")
|
||||||
|
fishing_spot.set("state", FishingSpotType.FishingState.CASTING)
|
||||||
|
player.set_movement_enabled(false)
|
||||||
|
player.set_release_visual()
|
||||||
|
assert(
|
||||||
|
int(player.get("_fishing_visual_phase"))
|
||||||
|
== Player.FishingVisualPhase.RELEASE
|
||||||
|
)
|
||||||
|
assert(
|
||||||
|
not service.request_local_cast(
|
||||||
|
cast_origin,
|
||||||
|
target,
|
||||||
|
cast_charge,
|
||||||
|
evidence,
|
||||||
|
).is_empty()
|
||||||
|
)
|
||||||
|
|
||||||
var accepted_deadline: int = Time.get_ticks_msec() + 6000
|
var accepted_deadline: int = Time.get_ticks_msec() + 6000
|
||||||
while (
|
while (
|
||||||
|
|
@ -146,8 +252,32 @@ func _run_client() -> void:
|
||||||
and fishing_spot.state != FishingSpotType.FishingState.WAITING_FOR_BITE
|
and fishing_spot.state != FishingSpotType.FishingState.WAITING_FOR_BITE
|
||||||
):
|
):
|
||||||
await process_frame
|
await process_frame
|
||||||
assert(fishing_spot.state == FishingSpotType.FishingState.WAITING_FOR_BITE)
|
assert(
|
||||||
|
fishing_spot.state == FishingSpotType.FishingState.WAITING_FOR_BITE,
|
||||||
|
(
|
||||||
|
"cast acceptance timed out: state=%s local_attempt=%s target=%s "
|
||||||
|
+ "rejections=%s"
|
||||||
|
) % [
|
||||||
|
fishing_spot.state,
|
||||||
|
service.has_local_attempt(),
|
||||||
|
target,
|
||||||
|
cast_rejections,
|
||||||
|
]
|
||||||
|
)
|
||||||
assert(service.has_local_attempt())
|
assert(service.has_local_attempt())
|
||||||
|
var fishing_deadline: int = Time.get_ticks_msec() + 5000
|
||||||
|
while (
|
||||||
|
Time.get_ticks_msec() < fishing_deadline
|
||||||
|
and int(player.get("_fishing_visual_phase"))
|
||||||
|
!= Player.FishingVisualPhase.FISHING
|
||||||
|
):
|
||||||
|
await process_frame
|
||||||
|
assert(
|
||||||
|
int(player.get("_fishing_visual_phase"))
|
||||||
|
== Player.FishingVisualPhase.FISHING
|
||||||
|
)
|
||||||
|
for _frame: int in 30:
|
||||||
|
await physics_frame
|
||||||
fishing_spot.set("_withdrawal_input_held", true)
|
fishing_spot.set("_withdrawal_input_held", true)
|
||||||
fishing_spot.set("_network_primary_input_held", true)
|
fishing_spot.set("_network_primary_input_held", true)
|
||||||
service.submit_local_input(true, true)
|
service.submit_local_input(true, true)
|
||||||
|
|
@ -159,10 +289,18 @@ func _run_client() -> void:
|
||||||
):
|
):
|
||||||
await process_frame
|
await process_frame
|
||||||
assert(fishing_spot.state == FishingSpotType.FishingState.RETURNING)
|
assert(fishing_spot.state == FishingSpotType.FishingState.RETURNING)
|
||||||
|
assert(
|
||||||
|
int(player.get("_fishing_visual_phase"))
|
||||||
|
== Player.FishingVisualPhase.RETRACT
|
||||||
|
)
|
||||||
|
assert(character_animation_player.current_animation == &"retract_sit")
|
||||||
var bobber := fishing_spot.get_node(
|
var bobber := fishing_spot.get_node(
|
||||||
"FishingPresentation/Bobber"
|
"FishingPresentation/Bobber"
|
||||||
) as MeshInstance3D
|
) as MeshInstance3D
|
||||||
assert(bobber.visible)
|
assert(bobber.visible)
|
||||||
|
while not player.is_retract_visual_complete():
|
||||||
|
assert(fishing_spot.state == FishingSpotType.FishingState.RETURNING)
|
||||||
|
await process_frame
|
||||||
|
|
||||||
var ready_deadline: int = Time.get_ticks_msec() + 3000
|
var ready_deadline: int = Time.get_ticks_msec() + 3000
|
||||||
while (
|
while (
|
||||||
|
|
@ -173,6 +311,9 @@ func _run_client() -> void:
|
||||||
assert(fishing_spot.state == FishingSpotType.FishingState.READY)
|
assert(fishing_spot.state == FishingSpotType.FishingState.READY)
|
||||||
assert(player.is_movement_enabled())
|
assert(player.is_movement_enabled())
|
||||||
assert(not bobber.visible)
|
assert(not bobber.visible)
|
||||||
|
var host_observation_deadline: int = Time.get_ticks_msec() + 2000
|
||||||
|
while Time.get_ticks_msec() < host_observation_deadline:
|
||||||
|
await process_frame
|
||||||
print("Fishing multiplayer client validation: PASS")
|
print("Fishing multiplayer client validation: PASS")
|
||||||
session.disconnect_session("")
|
session.disconnect_session("")
|
||||||
main.queue_free()
|
main.queue_free()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue