diff --git a/scenes/golf_level.gd b/scenes/golf_level.gd index 7cd181d..5d599bd 100644 --- a/scenes/golf_level.gd +++ b/scenes/golf_level.gd @@ -233,22 +233,24 @@ func _ready() -> void: func _on_everyone_entered_hole(): Log.peer(self, "Everyone entered hole, starting end timer...") - complete_timer = complete_timer_scene.instantiate() - complete_timer.timeout.connect(_on_complete_timer_timeout) - add_child(complete_timer) + if is_multiplayer_authority(): + complete_timer = complete_timer_scene.instantiate() + complete_timer.timeout.connect(_on_complete_timer_timeout) + add_child(complete_timer) func _on_complete_timer_timeout(): Log.peer(self, "End timer has timed out, emitting level_completed signal...") - level_completed.emit() complete_timer.queue_free() + player_dir.rpc_push_reported_scores.rpc() + level_completed.emit() -func _on_local_playernode_possessed(_old: int, new: int, playernode: PlayerNode): +func _on_local_playernode_possessed(_old: int, _new: int, playernode: PlayerNode): if camera != null: var ctarget = tee.get_node(playernode.player_name) camera.target = ctarget -## Emitted when it's time to change to the next level. +## Emitted on the server when it's time to change to the next level. signal level_completed diff --git a/scenes/golf_tee.gd b/scenes/golf_tee.gd index 699cd6b..9d0fc37 100644 --- a/scenes/golf_tee.gd +++ b/scenes/golf_tee.gd @@ -26,6 +26,7 @@ func spawn(playernode: PlayerNode, tposition: Vector2 = Vector2.ZERO, tstrokes: obj.player_name = playernode.player_name obj.player_color = playernode.player_color obj.set_multiplayer_authority(playernode.get_multiplayer_authority()) + obj.putt_controller.set_multiplayer_authority(playernode.get_multiplayer_authority()) obj.putt_controller.can_putt = not multiplayer.is_server() and playernode.is_multiplayer_authority() if thole: obj.enter_hole() @@ -72,6 +73,7 @@ func _on_color_changed(old: Color, new: Color, obj: GolfBall) -> void: func _on_possessed(old: int, new: int, obj: GolfBall) -> void: Log.peer(self, "PlayerNode changed owner, updating it on GolfBall: %d → %d" % [old, new]) obj.set_multiplayer_authority(new) + obj.putt_controller.set_multiplayer_authority(new) obj.putt_controller.can_putt = is_multiplayer_authority() if new == 1: obj.hide() @@ -88,6 +90,6 @@ func _on_cleanup(playernode: PlayerNode, on_name_changed: Callable, on_color_cha func _on_entered_hole(strokes: int, playernode: PlayerNode) -> void: if playernode.is_multiplayer_authority(): - playernode.report_score(strokes) + playernode.rpc_report_score.rpc(strokes) if is_everyone_in_hole(): everyone_entered_hole.emit() diff --git a/scenes/level_manager.gd b/scenes/level_manager.gd index f7eef15..7a8fe99 100644 --- a/scenes/level_manager.gd +++ b/scenes/level_manager.gd @@ -145,6 +145,8 @@ func next_level() -> void: rpc_wipe_level.rpc() init_target() build_level() + else: + rpc_destroy_level.rpc() ## Clear the current level on all clients and prepare to build a new one. @@ -154,9 +156,22 @@ func rpc_wipe_level(): destroy_level() initialize_level() +## Clear the current level on all clients. +@rpc("authority", "call_local", "reliable") +func rpc_destroy_level(): + if level != null: + destroy_level() + + +## Emit [signal level_completed] everywhere. +@rpc("authority", "call_local", "reliable") +func rpc_level_completed() -> void: + level_completed.emit(level) + + func _on_level_completed() -> void: Log.peer(self, "Level completed!") - level_completed.emit(level) + rpc_level_completed.rpc() if is_multiplayer_authority(): next_level() diff --git a/scenes/playernode.gd b/scenes/playernode.gd index 8716ea9..0157cfb 100644 --- a/scenes/playernode.gd +++ b/scenes/playernode.gd @@ -58,21 +58,18 @@ func rpc_query_color(): if is_multiplayer_authority(): rpc_set_color.rpc(player_color) +## The score reported for the current level. +## +## If the player hasn't completed the level, this should be -1. +var reported_score: int = -1 -## Add a new score entry to the [field hole_scores]. -func report_score(strokes: int) -> void: - assert(is_multiplayer_authority()) - rpc_report_score.rpc(strokes) - var tscores = hole_scores.duplicate(true) - tscores.push_back(strokes) - rpc_set_scores.rpc(tscores) -## Emit [signal score_reported] everywhere. +## Update [field reported_score] and emit [signal score_reported] everywhere. @rpc("authority", "call_local", "reliable") func rpc_report_score(strokes: int): + reported_score = strokes score_reported.emit(strokes) - ## Change the [field hole_scores] everywhere. @rpc("authority", "call_local", "reliable") func rpc_set_scores(value: Array): diff --git a/scenes/playernode_directory.gd b/scenes/playernode_directory.gd index b80f178..469b6ea 100644 --- a/scenes/playernode_directory.gd +++ b/scenes/playernode_directory.gd @@ -3,7 +3,7 @@ class_name PlayerNodeDirectory ## The scene to instantiate on creation of a new [PlayerNode]. -@export var playernode_scene: PackedScene = preload("res://scenes/playernode.tscn") +const playernode_scene: PackedScene = preload("res://scenes/playernode.tscn") ## Find the subordinate [PlayerNode] with the given player_name, and return it if found, otherwise return null. @@ -32,11 +32,28 @@ func rpc_possess_playernode(player_name: String, peer_id: int): var sanitized_player_name = PlayerNode.sanitize_player_name(player_name) playernode.player_name = sanitized_player_name playernode.name = sanitized_player_name + # Determine the number of holes that this player has skipped + var played_holes = 0 + for othernode in get_children(): + var othernode_played_holes = len(othernode.hole_scores) + if othernode_played_holes > played_holes: + played_holes = othernode_played_holes + # Fill the empty scores with -1 + for _index in range(played_holes): + playernode.hole_scores.push_back(-1) + # Add the playernode to the SceneTree add_child(playernode) # If the multiplayer authority does not match the requested one, make it match playernode.possess(peer_id) +## Push the [field reported_score] of all children to the [field hole_scores] array, and reset its value to -1. +@rpc("authority", "call_local", "reliable") +func rpc_push_reported_scores(): + for playernode in get_children(): + playernode.hole_scores.push_back(playernode.reported_score) + playernode.reported_score = -1 + func _on_playernode_name_changed(old: String, new: String, playernode: PlayerNode) -> void: playernode_name_changed.emit(old, new, playernode) diff --git a/scenes/putt_controller.gd b/scenes/putt_controller.gd index 1e8b35e..8f41bd3 100644 --- a/scenes/putt_controller.gd +++ b/scenes/putt_controller.gd @@ -104,9 +104,9 @@ func end_putt(end_position: Vector2): can_putt = false var putt_vector = compute_putt(drag_start_point, end_position) putt.emit(putt_vector) - play_putt_sound(putt_vector) - + play_putt_sound.rpc(putt_vector) +@rpc("authority", "call_local", "reliable") func play_putt_sound(putt_vector: Vector2): var putt_impulse: float = putt_vector.length() sound.volume_db = putt_volume.sample(putt_impulse / putt_max_impulse)