1
Fork 0
mirror of https://github.com/Steffo99/nanogolf.git synced 2024-11-24 00:54:19 +00:00

Sync more stuff

This commit is contained in:
Steffo 2024-03-18 06:08:31 +01:00
parent 2a0c74f1d2
commit f2b4788903
Signed by: steffo
GPG key ID: 5ADA3868646C3FC0
12 changed files with 321 additions and 184 deletions

View file

@ -1,12 +1,9 @@
extends Node
class_name Game
## The name to be given to the player controlled by the local peer.
var local_player_name: String
## The color to be given to the player controlled by the local peer.
var local_player_color: Color
@export_category("References")
## The [PeerNodeDirectory] instance child of this node.
@export var peer_dir: PeerNodeDirectory = null
@ -21,8 +18,21 @@ var local_player_color: Color
@export var level_manager: LevelManager = null
## Emitted when the player has requested to exit from the game.
signal leave_confirmed
signal lost_connection
## Emitted when the golf ball for the local player has been spawned.
##
## Used for [GameHUD] events.
signal local_player_spawned(ball: GolfBall)
## The name to be given to the player controlled by the local peer.
var local_player_name: String
## The color to be given to the player controlled by the local peer.
var local_player_color: Color
## Initialize some signals needed by this node to function properly.
@ -42,11 +52,11 @@ func _on_multiplayer_disconnected_from_server() -> void:
func _on_multiplayer_connection_failed() -> void:
Log.peer(self, "Connection failed...")
leave_confirmed.emit()
lost_connection.emit()
func _on_multiplayer_peer_connected(peer_id: int) -> void:
Log.peer(self, "Peer connected: %d" % peer_id)
if multiplayer.is_server():
if is_multiplayer_authority():
for peernode in peer_dir.get_children():
peer_dir.rpc_create_peernode.rpc_id(peer_id, peernode.get_multiplayer_authority())
for playernode in player_dir.get_children():
@ -55,60 +65,44 @@ func _on_multiplayer_peer_connected(peer_id: int) -> void:
playernode.rpc_query_color.rpc_id(playernode.get_multiplayer_authority())
playernode.rpc_query_scores.rpc_id(playernode.get_multiplayer_authority())
peer_dir.rpc_create_peernode.rpc(peer_id)
phase_tracker.rpc_set_phase.rpc_id(peer_id, phase_tracker.phase)
func _on_multiplayer_peer_disconnected(peer_id: int) -> void:
Log.peer(self, "Peer disconnected: %d" % peer_id)
if multiplayer.is_server():
if is_multiplayer_authority():
for playernode in player_dir.get_children():
if playernode.get_multiplayer_authority() == peer_id:
player_dir.rpc_possess_playernode.rpc(playernode.player_name, 1)
peer_dir.rpc_destroy_peernode.rpc(peer_id)
func _on_peerdir_peernode_created(peernode: PeerNode) -> void:
Log.peer(self, "Peernode created: %d" % peernode.get_multiplayer_authority())
if peernode.is_multiplayer_authority():
peernode.rpc_identify.rpc(local_player_name)
func _on_peerdir_peernode_destroyed(peernode: PeerNode) -> void:
Log.peer(self, "Peernode destroyed: %d" % peernode.get_multiplayer_authority())
func _on_peerdir_local_peernode_created(peernode: PeerNode) -> void:
Log.peer(self, "Local peernode created: %s" % peernode)
peernode.rpc_identify.rpc(local_player_name)
func _on_peerdir_peernode_identified(player_name: String, peernode: PeerNode) -> void:
Log.peer(self, "Peernode identified: %d%s" % [peernode.get_multiplayer_authority(), player_name])
player_dir.rpc_possess_playernode.rpc(player_name, peernode.get_multiplayer_authority())
Log.peer(self, "Peernode identified: %s%s" % [peernode, player_name])
if is_multiplayer_authority():
var peer_id = peernode.get_multiplayer_authority()
phase_tracker.rpc_set_phase.rpc_id(peer_id, phase_tracker.phase)
level_manager.sync_level(peer_id)
player_dir.rpc_possess_playernode.rpc(player_name, peer_id)
func _on_playerdir_playernode_created(playernode: PlayerNode) -> void:
Log.peer(self, "Playernode `%s` created" % playernode.player_name)
func _on_playerdir_playernode_destroyed(playernode: PlayerNode) -> void:
Log.peer(self, "Playernode `%s` destroyed" % playernode.player_name)
func _on_playerdir_playernode_name_changed(old: String, new: String, playernode: PlayerNode) -> void:
Log.peer(self, "Playernode `%s` changed name: %s (was %s)" % [playernode.player_name, new, old])
func _on_playerdir_playernode_color_changed(old: Color, new: Color, playernode: PlayerNode) -> void:
Log.peer(self, "Playernode `%s` changed color: %s (was %s)" % [playernode.player_name, new, old])
func _on_playerdir_playernode_score_reported(strokes: int, playernode: PlayerNode) -> void:
Log.peer(self, "Playernode `%s` reported score: %d" % [playernode.player_name, strokes])
func _on_playerdir_playernode_scores_changed(old: Array, new: Array, playernode: PlayerNode) -> void:
Log.peer(self, "Playernode `%s` changed scores: %s (was %s)" % [playernode.player_name, new, old])
func _on_playerdir_playernode_possessed(old: int, new: int, playernode: PlayerNode) -> void:
Log.peer(self, "Playernode `%s` possessed: %d (was %d)" % [playernode.player_name, new, old])
if playernode.is_multiplayer_authority() and not multiplayer.is_server():
playernode.rpc_set_name.rpc(local_player_name)
playernode.rpc_set_color.rpc(local_player_color)
Log.peer(self, "Playernode created: %s" % playernode)
if is_multiplayer_authority():
level_manager.add_player(playernode)
func _on_playerdir_local_playernode_possessed(old: int, new: int, playernode: PlayerNode) -> void:
Log.peer(self, "Local playernode possessed: %d%d" % [old, new])
playernode.rpc_set_name.rpc(local_player_name)
playernode.rpc_set_color.rpc(local_player_color)
func _on_main_start_confirmed() -> void:
if multiplayer.is_server():
if is_multiplayer_authority():
phase_tracker.rpc_set_phase.rpc(PhaseTracker.Phase.PLAYING)
level_manager.rpc_next_level.rpc()
level_manager.next_level()
func _on_level_manager_playlist_complete(_playlist: LevelPlaylist) -> void:
if multiplayer.is_server():
if is_multiplayer_authority():
phase_tracker.rpc_set_phase.rpc(PhaseTracker.Phase.ENDED)

View file

@ -24,21 +24,16 @@ level_manager = NodePath("LevelManager")
[node name="PhaseTracker" parent="." instance=ExtResource("4_kab4c")]
[node name="LevelManager" parent="." node_paths=PackedStringArray("playlist", "player_dir") instance=ExtResource("5_tdqk1")]
playlist = NodePath("LevelPlaylist")
playlist = NodePath("../LevelPlaylist")
player_dir = NodePath("../PlayerNodeDirectory")
[node name="LevelPlaylist" parent="LevelManager" instance=ExtResource("6_bk2n3")]
[node name="LevelPlaylist" parent="." instance=ExtResource("6_bk2n3")]
script = ExtResource("7_akb5s")
levels = Array[PackedScene]([ExtResource("8_h8dsk"), ExtResource("9_2kliu")])
[connection signal="child_entered_tree" from="PeerNodeDirectory" to="." method="_on_peerdir_peernode_created"]
[connection signal="child_exiting_tree" from="PeerNodeDirectory" to="." method="_on_peerdir_peernode_destroyed"]
[connection signal="local_peernode_created" from="PeerNodeDirectory" to="." method="_on_peerdir_local_peernode_created"]
[connection signal="peernode_identified" from="PeerNodeDirectory" to="." method="_on_peerdir_peernode_identified"]
[connection signal="child_entered_tree" from="PlayerNodeDirectory" to="." method="_on_playerdir_playernode_created"]
[connection signal="child_exiting_tree" from="PlayerNodeDirectory" to="." method="_on_playerdir_playernode_destroyed"]
[connection signal="playernode_color_changed" from="PlayerNodeDirectory" to="." method="_on_playerdir_playernode_color_changed"]
[connection signal="playernode_name_changed" from="PlayerNodeDirectory" to="." method="_on_playerdir_playernode_name_changed"]
[connection signal="local_playernode_possessed" from="PlayerNodeDirectory" to="." method="_on_playerdir_local_playernode_possessed"]
[connection signal="playernode_possessed" from="PlayerNodeDirectory" to="." method="_on_playerdir_playernode_possessed"]
[connection signal="playernode_score_reported" from="PlayerNodeDirectory" to="." method="_on_playerdir_playernode_score_reported"]
[connection signal="playernode_scores_changed" from="PlayerNodeDirectory" to="." method="_on_playerdir_playernode_scores_changed"]
[connection signal="playlist_complete" from="LevelManager" to="." method="_on_level_manager_playlist_complete"]

View file

@ -19,37 +19,31 @@ func _on_level_completed(_level: GolfLevel) -> void:
scores_panel.hide()
func _on_playernode_name_changed(old: String, new: String, playernode: PlayerNode) -> void:
var instance = get_node_or_null("PlayerScoreLabel__%s" % old)
var instance = get_node_or_null(old)
if instance != null:
instance.from_score(playernode)
instance.name = "PlayerScoreLabel__%s" % new
instance.name = new
func _on_playernode_color_changed(_old: Color, _new: Color, playernode: PlayerNode) -> void:
var instance = get_node_or_null("PlayerScoreLabel__%s" % playernode.player_name)
var instance = get_node_or_null(playernode.player_name)
if instance != null:
instance.from_score(playernode)
func _on_playernode_possessed(_old: int, _new: int, playernode: PlayerNode) -> void:
var instance = get_node_or_null("PlayerScoreLabel__%s" % playernode.player_name)
var instance = get_node_or_null(playernode.player_name)
if instance != null:
instance.from_score(playernode)
func _on_playernode_score_reported(strokes: int, playernode: PlayerNode) -> void:
var score_instance = score_scene.instantiate()
score_instance.from_score(strokes, playernode)
score_instance.name = "PlayerScoreLabel__%s" % playernode.player_name
score_instance.name = playernode.player_name
scores_container.add_child(score_instance)
scores_panel.show()
func _on_playernode_scores_changed(_old: Array, _new: Array, _playernode: PlayerNode) -> void:
pass
func _on_local_player_spawned(ball: GolfBall, _level: GolfLevel) -> void:
ball.putt_controller.putt.connect(_on_putt.bind(ball))
func _on_putt(_putt_vector: Vector2, ball: GolfBall) -> void:
strokes_label.text = "%d" % ball.strokes
func _on_strokes_changed(strokes: int) -> void:
strokes_label.text = "%s" % strokes
func _on_playernode_putt_performed(ball: GolfBall, playernode: PlayerNode) -> void:
if playernode.is_multiplayer_authority():
strokes_label.text = "%s" % ball.strokes

View file

@ -131,20 +131,22 @@ func check_has_entered_hole() -> bool:
@rpc("authority", "call_local", "reliable")
func rpc_sync_enter_hole():
func rpc_do_enter_hole():
enter_hole()
func enter_hole():
in_hole = true
visible = false
hide()
putt_controller.can_putt = false
if not multiplayer.is_server():
hole_sound.play()
entered_hole.emit(strokes)
# FIXME: What happens on the server?
## Push this object's [field global_position] to all other clients.
@rpc("authority", "call_remote", "unreliable_ordered")
func rpc_sync_global_position(nposition: Vector2):
func rpc_set_global_position(nposition: Vector2):
global_position = nposition
@ -156,9 +158,9 @@ func _physics_process(delta) -> void:
if not multiplayer.is_server() and is_multiplayer_authority():
if not in_hole:
do_movement(delta)
rpc_sync_global_position.rpc(global_position)
rpc_set_global_position.rpc(global_position)
apply_friction(delta)
if check_has_entered_hole():
rpc_sync_enter_hole.rpc()
rpc_do_enter_hole.rpc()
if check_has_stopped():
putt_controller.can_putt = true

View file

@ -2,12 +2,6 @@ extends Node2D
class_name GolfLevel
## Emitted when it's time to change to the next level.
signal level_completed
## Emitted when the [GolfBall] for the local player has been spawned.
signal local_player_spawned(ball: GolfBall)
@export_category("Level Data")
@ -30,10 +24,11 @@ signal local_player_spawned(ball: GolfBall)
## The [TileMap] of this level.
@export var map: TileMap = null
## If active, the [Timer] between emissions of [signal everyone_entered_hole] and [signal level_completed].
var complete_timer: Timer = null
## If on server, this variable indicates the [GolfLevel] to replicate.
##
## The [GolfLevel] in question should not be added to the scene tree, or it will cause problems on the client acting as server.
@ -65,20 +60,24 @@ const complete_timer_scene: PackedScene = preload("res://scenes/complete_timer.t
## Replicate the [field target] from the server to the clients via RPC.
func build() -> void:
build_tilemap()
build_tilemap_cells()
build_tee()
build_balls()
build_hole()
build_camera()
func build(peer_id: int = 0) -> void:
build_tilemap(peer_id)
build_tilemap_cells(peer_id)
build_tee(peer_id)
build_existing_balls(peer_id)
build_new_balls(peer_id)
build_hole(peer_id)
build_camera(peer_id)
## Replicate the [field map] of the [field target] to the remote [field map].
func build_tilemap() -> void:
func build_tilemap(peer_id: int = 0) -> void:
Log.peer(self, "Replicating map...")
var tmap: TileMap = target.map
rpc_build_tilemap.rpc(tmap.global_position, tmap.global_rotation, tmap.global_scale)
if peer_id > 0:
rpc_build_tilemap.rpc_id(peer_id, tmap.global_position, tmap.global_rotation, tmap.global_scale)
else:
rpc_build_tilemap.rpc(tmap.global_position, tmap.global_rotation, tmap.global_scale)
## Create the [field map].
@rpc("authority", "call_local", "reliable")
@ -90,12 +89,13 @@ func rpc_build_tilemap(tposition: Vector2, trotation: float, tscale: Vector2):
map.global_scale = tscale
add_child(map)
## Replicate the cells of [field target]'s [field map] to the remote [field map].
##
## The [field map] must be already created.
##
## Only takes layer 0 into consideration.
func build_tilemap_cells() -> void:
func build_tilemap_cells(peer_id: int = 0) -> void:
Log.peer(self, "Replicating map cells...")
var tmap: TileMap = target.map
const layer = 0
@ -103,8 +103,11 @@ func build_tilemap_cells() -> void:
var source_id: int = tmap.get_cell_source_id(0, coords)
var atlas_coords: Vector2i = tmap.get_cell_atlas_coords(0, coords)
var alternative_tile: int = tmap.get_cell_alternative_tile(0, coords)
rpc_build_tilemap_cell.rpc(layer, coords, source_id, atlas_coords, alternative_tile)
if peer_id > 0:
rpc_build_tilemap_cell.rpc_id(peer_id, layer, coords, source_id, atlas_coords, alternative_tile)
else:
rpc_build_tilemap_cell.rpc(layer, coords, source_id, atlas_coords, alternative_tile)
## Create a cell of [field map].
@rpc("authority", "call_local", "reliable")
func rpc_build_tilemap_cell(
@ -119,10 +122,13 @@ func rpc_build_tilemap_cell(
## Replicate the [field tee] of the [field target] to the remote [field tee].
func build_tee() -> void:
func build_tee(peer_id: int = 0) -> void:
Log.peer(self, "Replicating tee...")
var ttee: GolfTee = target.tee
rpc_build_tee.rpc(ttee.global_position)
if peer_id > 0:
rpc_build_tee.rpc_id(peer_id, ttee.global_position)
else:
rpc_build_tee.rpc(ttee.global_position)
## Create the [GolfTee] object.
@rpc("authority", "call_local", "reliable")
@ -135,25 +141,50 @@ func rpc_build_tee(tposition: Vector2):
## Replicate the currently connected players' [GolfBall]s to the remote [field tee].
func build_balls() -> void:
for playernode in player_dir.get_children():
rpc_build_ball.rpc(playernode.player_name)
func build_existing_balls(peer_id: int = 0) -> void:
Log.peer(self, "Replicating existing golf balls...")
for tball in tee.get_children():
if peer_id > 0:
rpc_build_ball.rpc_id(peer_id, tball.name, tball.position, tball.strokes, tball.in_hole)
else:
rpc_build_ball.rpc(tball.name, tball.position, tball.strokes, tball.in_hole)
func build_new_balls(peer_id: int = 0) -> void:
Log.peer(self, "Replicating new golf balls...")
for playernode in player_dir.get_children():
if peer_id > 0:
rpc_build_ball.rpc_id(peer_id, playernode.player_name, Vector2.ZERO, 0, false)
else:
rpc_build_ball.rpc(playernode.player_name, Vector2.ZERO, 0, false)
## Create the specified player's [GolfBall] at the remote [field tee].
func build_new_ball(player_name: String, peer_id: int = 0) -> void:
Log.peer(self, "Replicating new golf ball for: %s" % player_name)
if peer_id > 0:
rpc_build_ball.rpc_id(peer_id, player_name, Vector2.ZERO, 0, false)
else:
rpc_build_ball.rpc(player_name, Vector2.ZERO, 0, false)
## Create and initialize a [GolfBall] for a single [PlayerNode] with the given name.
@rpc("authority", "call_local", "reliable")
func rpc_build_ball(player_name: String):
Log.peer(self, "Building tee ball for: %s" % player_name)
func rpc_build_ball(player_name: String, tposition: Vector2, tstrokes: int, thole: bool):
var playernode: PlayerNode = player_dir.get_playernode(player_name)
var ball = tee.spawn(playernode)
if playernode.is_multiplayer_authority():
local_player_spawned.emit(ball)
var ball: GolfBall = tee.get_golfball(playernode)
if ball == null:
Log.peer(self, "Building golf ball for: %s" % player_name)
ball = tee.spawn(playernode, tposition, tstrokes, thole)
else:
Log.peer(self, "Not building duplicate golf ball for: %s" % player_name)
## Replicate the [field hole] of the [field target] to the remote [field hole].
func build_hole() -> void:
func build_hole(peer_id: int = 0) -> void:
Log.peer(self, "Replicating hole...")
var thole: GolfHole = target.hole
rpc_build_hole.rpc(thole.global_position, thole.global_scale)
if peer_id > 0:
rpc_build_hole.rpc_id(peer_id, thole.global_position, thole.global_scale)
else:
rpc_build_hole.rpc(thole.global_position, thole.global_scale)
## Create the [GolfHole] object.
@rpc("authority", "call_local", "reliable")
@ -166,10 +197,13 @@ func rpc_build_hole(tposition: Vector2, tscale: Vector2):
## Replicate the [field camera] of the [field target] to the remote [field camera].
func build_camera() -> void:
func build_camera(peer_id: int = 0) -> void:
Log.peer(self, "Replicating camera...")
var tcamera: FollowCamera = target.camera
rpc_build_camera.rpc(tcamera.global_position, target.camera_follows_player)
if peer_id > 0:
rpc_build_camera.rpc_id(peer_id, tcamera.global_position, target.camera_follows_player)
else:
rpc_build_camera.rpc(tcamera.global_position, target.camera_follows_player)
## Create the [Camera2D] object.
@rpc("authority", "call_local", "reliable")
@ -185,37 +219,40 @@ func rpc_build_camera(tposition: Vector2, tfocus: bool):
for child in player_dir.get_children():
var playernode = child as PlayerNode
if playernode.is_multiplayer_authority():
var ctarget = tee.get_node("GolfBall__%s" % child.player_name)
var ctarget = tee.get_node(child.player_name)
camera.target = ctarget
add_child(camera)
func _ready() -> void:
player_dir.child_entered_tree.connect(_on_playernode_created)
player_dir.local_playernode_possessed.connect(_on_local_playernode_possessed)
if multiplayer.is_server():
set_physics_process(false)
hide()
func _on_playernode_created(node: Node) -> void:
Log.peer(self, "Spawning new player...")
var playernode: PlayerNode = node as PlayerNode
rpc_build_ball.rpc(playernode.player_name)
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)
func _on_complete_timer_timeout():
complete_timer.queue_free()
Log.peer(self, "End timer has timed out, emitting level_completed signal...")
level_completed.emit()
complete_timer.queue_free()
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.
signal level_completed
func _on_tree_exiting() -> void:
player_dir.child_entered_tree.disconnect(_on_playernode_created)
if target:
target.queue_free()
target = null

View file

@ -10,17 +10,25 @@ signal everyone_entered_hole
const ball_scene: PackedScene = preload("res://scenes/golf_ball.tscn")
func get_golfball(playernode: PlayerNode) -> GolfBall:
var nname = playernode.player_name
return get_node_or_null(nname)
## Add a new [GolfBall] from [field ball_scene], initialize it with details from the given [PlayerNode], and return it.
func spawn(playernode: PlayerNode) -> GolfBall:
func spawn(playernode: PlayerNode, tposition: Vector2 = Vector2.ZERO, tstrokes: int = 0, thole: bool = false) -> GolfBall:
# Create the [GolfBall]
var obj: GolfBall = ball_scene.instantiate()
# Setup the initial values
obj.position = Vector2.ZERO
obj.name = "GolfBall__%s" % playernode.player_name
obj.position = tposition
obj.name = playernode.player_name
obj.strokes = tstrokes
obj.player_name = playernode.player_name
obj.player_color = playernode.player_color
obj.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()
# Create callables to be able to cleanup signals on destruction
var on_name_changed: Callable = _on_name_changed.bind(obj)
var on_color_changed: Callable = _on_color_changed.bind(obj)
@ -31,9 +39,10 @@ func spawn(playernode: PlayerNode) -> GolfBall:
playernode.color_changed.connect(on_color_changed)
playernode.possessed.connect(on_possessed)
obj.tree_exiting.connect(on_cleanup)
obj.putt_controller.putt.connect(_on_putt_performed.bind(playernode, obj))
obj.entered_hole.connect(_on_entered_hole.bind(playernode))
# Add the golf ball as a child of the tee
add_child(obj)
add_child(obj, true)
# Return the created [GolfBall]
return obj
@ -51,16 +60,26 @@ func is_everyone_in_hole() -> bool:
return true
func _on_name_changed(_old: String, new: String, obj: GolfBall) -> void:
obj.name = "GolfBall__%s" % new
func _on_name_changed(old: String, new: String, obj: GolfBall) -> void:
Log.peer(self, "PlayerNode changed name, updating it on GolfBall: %s%s" % [old, new])
obj.name = new
obj.player_name = new
func _on_color_changed(_old: Color, new: Color, obj: GolfBall) -> void:
func _on_color_changed(old: Color, new: Color, obj: GolfBall) -> void:
Log.peer(self, "PlayerNode changed color, updating it on GolfBall: %s%s" % [old, new])
obj.player_color = new
func _on_possessed(_old: int, new: int, 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.can_putt = is_multiplayer_authority()
if new == 1:
obj.hide()
else:
obj.show()
func _on_putt_performed(_dir: Vector2, playernode: PlayerNode, obj: GolfBall) -> void:
playernode.putt_performed.emit(obj)
func _on_cleanup(playernode: PlayerNode, on_name_changed: Callable, on_color_changed: Callable, on_possessed: Callable) -> void:
playernode.name_changed.disconnect(on_name_changed)

View file

@ -12,23 +12,10 @@ class_name LevelManager
@export var player_dir: PlayerNodeDirectory = null
## Emitted when the [GolfBall] for the local player was spawned in a level.
signal local_player_spawned(ball: GolfBall, level: GolfLevel)
## Emitted when the current level is about to be destroyed.
signal level_destroying(level: GolfLevel)
## Emitted when the next level has been determined by calling [LevelPlaylist.advance].
signal level_determined(scene: PackedScene)
## Emitted when the new level has been added to the tree, but not built.
signal level_created(level: GolfLevel)
## Emitted when a level has been completed.
signal level_completed(level: GolfLevel)
## Emitted when all levels in the [field playlist] have been exausted.
signal playlist_complete(playlist: LevelPlaylist)
## The blank [GolfLevel] to initialize on clients.
@ -37,57 +24,139 @@ const base_scene: PackedScene = preload("res://scenes/golf_level.tscn")
## The currently instantiated [GolfLevel].
var level: GolfLevel = null
## The next scene to use as [field target].
##
## Should be null on everything that's not the server.
var next: PackedScene = null
## Create the empty [GolfLevel] object everywhere.
@rpc("authority", "call_local", "reliable")
func rpc_next_level():
Log.peer(self, "Advancinng to the next level!")
# Destroy the current level
if level != null:
Log.peer(self, "Destroying the current level: %s" % level)
level_destroying.emit(level)
level.queue_free()
level = null
# Determine the next level
## The currently instantiated target [GolfLevel].
##
## Should be null on everything that's not the server.
var target: GolfLevel = null
## Destroy the current [field level].
func destroy_level() -> void:
Log.peer(self, "Emitting level_destroying signal...")
level_destroying.emit(level)
Log.peer(self, "Queueing the free of the level and removing references...")
remove_child(level)
level.queue_free()
level = null
Log.peer(self, "Emitting level_destroyed signal...")
level_destroyed.emit()
## Emitted when the current level is about to be destroyed.
signal level_destroying(level: GolfLevel)
## Emitted when the current level has been destroyed.
signal level_destroyed
## Advance the [field playlist] and return the next level to play.
func determine_next_level() -> void:
Log.peer(self, "Determining the next level...")
var next = playlist.advance()
next = playlist.advance()
Log.peer(self, "Determined the next level: %s" % next)
level_determined.emit(next)
## Make sure the playlist hasn't been exausted
if next == null:
Log.peer(self, "Playlist is complete, not doing anything.")
Log.peer(self, "Playlist is complete.")
playlist_complete.emit(playlist)
return
# Create the new level
Log.peer(self, "Instantiating empty level template...")
## Emitted when the next level has been determined by calling [LevelPlaylist.advance].
signal level_determined(scene: PackedScene)
## Emitted when all levels in the [field playlist] have been exausted.
signal playlist_complete(playlist: LevelPlaylist)
## Instantiate and setup a copy of the [field base_scene].
func initialize_level() -> void:
Log.peer(self, "Instantiating level template...")
level = base_scene.instantiate()
Log.peer(self, "Instantiated empty level template: %s" % level)
# Configure the new level
Log.peer(self, "Configuring level variables...")
level.player_dir = player_dir
level.local_player_spawned.connect(_on_local_player_spawned)
Log.peer(self, "Connecting level signals...")
level.level_completed.connect(_on_level_completed)
if multiplayer.is_server():
Log.peer(self, "Instantiating the target level scene...")
level.target = next.instantiate()
Log.peer(self, "Instantiated the target level scene: %s" % level.target)
# Add the level to the tree
Log.peer(self, "Adding level to the tree...")
Log.peer(self, "Adding level to the scene tree...")
add_child(level, true)
level_created.emit(level)
# Start the replication
if multiplayer.is_server():
Log.peer(self, "Building level...")
level.build()
Log.peer(self, "Emitting level_initialized signal...")
level_initialized.emit(level)
## Emitted when a copy of [field base_scene] has been initialized by [method initialize_level].
signal level_initialized(level: GolfLevel)
## Instantiate a copy of the given target [GolfLevel].
func init_target() -> void:
Log.peer(self, "Instantiating level targets...")
level.target = next.instantiate()
Log.peer(self, "Emitting target_initialized signal...")
target_initialized.emit(level.target)
## Emitted when a copy of the target level has been initialized by [method init_target].
signal target_initialized(level: GolfLevel)
## Replicate the [method target] onto the [method level] of all currently connected clients if no peer_id is specified, or to only that client if a peer_id is specified.
func build_level(peer_id: int = 0) -> void:
Log.peer(self, "Building level...")
level.build(peer_id)
Log.peer(self, "Emitting level_built signal...")
level_built.emit(level)
## Emitted on the server when it has finished sending out RPCs for the [method GolfLevel.build] of the [field target] level.
signal level_built(level: GolfLevel)
## Send the current level to a given client.
func sync_level(peer_id: int = 0) -> void:
Log.peer(self, "Repeating the current level to: %d" % peer_id)
if level:
if peer_id > 0:
rpc_wipe_level.rpc_id(peer_id)
else:
rpc_wipe_level.rpc()
build_level(peer_id)
## Add a new player to the current level.
func add_player(playernode: PlayerNode):
Log.peer(self, "Adding a new player to the level in progress...")
if level != null:
level.build_new_ball(playernode.player_name)
## Advance to the next level.
func next_level() -> void:
Log.peer(self, "Advancing to the next level...")
determine_next_level()
if next != null:
rpc_wipe_level.rpc()
init_target()
build_level()
## Clear the current level on all clients and prepare to build a new one.
@rpc("authority", "call_local", "reliable")
func rpc_wipe_level():
if level != null:
destroy_level()
initialize_level()
func _on_level_completed() -> void:
Log.peer(self, "Level completed!")
level_completed.emit(level)
if is_multiplayer_authority():
rpc_next_level.rpc()
func _on_local_player_spawned(ball: GolfBall) -> void:
Log.peer(self, "Local player spawned: %s" % ball)
local_player_spawned.emit(ball, level)
next_level()

View file

@ -44,7 +44,7 @@ func init_server_game(server_port: int) -> void:
scene_tree.set_multiplayer(smp, ^"/root/Main/Server")
server_game_instance.init_signals()
server_game_instance.leave_confirmed.connect(_on_leave_confirmed)
server_game_instance.lost_connection.connect(_on_lost_connection)
smp.set_multiplayer_peer(peer)
func deinit_server_game() -> void:
@ -71,7 +71,7 @@ func init_client_game(player_name: String, player_color: Color, server_address:
client_game_instance.local_player_name = player_name
client_game_instance.local_player_color = player_color
client_game_instance.phase_tracker.phase_changed.connect(_on_phase_changed)
client_game_instance.leave_confirmed.connect(_on_leave_confirmed)
client_game_instance.lost_connection.connect(_on_lost_connection)
smp.set_multiplayer_peer(peer)
func deinit_client_game() -> void:
@ -83,11 +83,11 @@ func deinit_client_game() -> void:
func init_lobby_menu() -> void:
lobby_menu_instance = lobby_menu_scene.instantiate()
lobby_menu_instance.init_refs()
lobby_menu_instance.leave_confirmed.connect(_on_leave_confirmed)
lobby_menu_instance.leave_confirmed.connect(_on_lost_connection)
if server_game_instance:
lobby_menu_instance.start_button.disabled = false
lobby_menu_instance.start_confirmed.connect(server_game_instance._on_main_start_confirmed)
client_game_instance.multiplayer.server_disconnected.connect(_on_leave_confirmed)
client_game_instance.multiplayer.server_disconnected.connect(_on_lost_connection)
client_game_instance.player_dir.child_entered_tree.connect(lobby_menu_instance.players_list._on_playernode_created)
client_game_instance.player_dir.child_exiting_tree.connect(lobby_menu_instance.players_list._on_playernode_destroyed)
client_game_instance.player_dir.playernode_name_changed.connect(lobby_menu_instance.players_list._on_playernode_name_changed)
@ -96,10 +96,10 @@ func init_lobby_menu() -> void:
interface_instance.add_child(lobby_menu_instance)
func deinit_lobby_menu() -> void:
lobby_menu_instance.leave_confirmed.disconnect(_on_leave_confirmed)
lobby_menu_instance.leave_confirmed.disconnect(_on_lost_connection)
if server_game_instance:
lobby_menu_instance.start_confirmed.disconnect(server_game_instance._on_main_start_confirmed)
client_game_instance.multiplayer.server_disconnected.disconnect(_on_leave_confirmed)
client_game_instance.multiplayer.server_disconnected.disconnect(_on_lost_connection)
client_game_instance.player_dir.child_entered_tree.disconnect(lobby_menu_instance.players_list._on_playernode_created)
client_game_instance.player_dir.child_exiting_tree.disconnect(lobby_menu_instance.players_list._on_playernode_destroyed)
client_game_instance.player_dir.playernode_name_changed.disconnect(lobby_menu_instance.players_list._on_playernode_name_changed)
@ -111,22 +111,22 @@ func deinit_lobby_menu() -> void:
func init_game_hud() -> void:
game_hud_instance = game_hud_scene.instantiate()
client_game_instance.level_manager.level_completed.connect(game_hud_instance._on_level_completed)
client_game_instance.level_manager.local_player_spawned.connect(game_hud_instance._on_local_player_spawned)
client_game_instance.player_dir.playernode_name_changed.connect(game_hud_instance._on_playernode_name_changed)
client_game_instance.player_dir.playernode_color_changed.connect(game_hud_instance._on_playernode_color_changed)
client_game_instance.player_dir.playernode_possessed.connect(game_hud_instance._on_playernode_possessed)
client_game_instance.player_dir.playernode_score_reported.connect(game_hud_instance._on_playernode_score_reported)
client_game_instance.player_dir.playernode_scores_changed.connect(game_hud_instance._on_playernode_scores_changed)
client_game_instance.player_dir.playernode_putt_performed.connect(game_hud_instance._on_playernode_putt_performed)
interface_instance.add_child(game_hud_instance)
func deinit_game_hud() -> void:
client_game_instance.level_manager.level_completed.disconnect(game_hud_instance._on_level_completed)
client_game_instance.level_manager.local_player_spawned.disconnect(game_hud_instance._on_local_player_spawned)
client_game_instance.player_dir.playernode_name_changed.disconnect(game_hud_instance._on_playernode_name_changed)
client_game_instance.player_dir.playernode_color_changed.disconnect(game_hud_instance._on_playernode_color_changed)
client_game_instance.player_dir.playernode_possessed.disconnect(game_hud_instance._on_playernode_possessed)
client_game_instance.player_dir.playernode_score_reported.disconnect(game_hud_instance._on_playernode_score_reported)
client_game_instance.player_dir.playernode_scores_changed.disconnect(game_hud_instance._on_playernode_scores_changed)
client_game_instance.player_dir.playernode_putt_performed.disconnect(game_hud_instance._on_playernode_putt_performed)
game_hud_instance.queue_free()
game_hud_instance = null
@ -144,7 +144,7 @@ func _on_connecting_confirmed(player_name: String, player_color: Color, server_a
init_client_game(player_name, player_color, server_address, server_port)
init_lobby_menu()
func _on_leave_confirmed() -> void:
func _on_lost_connection() -> void:
if lobby_menu_instance != null:
deinit_lobby_menu()
if game_hud_instance != null:

View file

@ -37,6 +37,14 @@ func rpc_destroy_peernode(peer_id: int):
peernode.queue_free()
func _on_peernode_created(peernode: PeerNode) -> void:
if peernode.is_multiplayer_authority():
local_peernode_created.emit(peernode)
## Emitted on a client when the [PeerNode] for itself has been created.
signal local_peernode_created(peernode: PeerNode)
## Called on the server when a [PeerNode] calls [method rpc_identify] for itself.
func _on_peernode_identified(player_name: String, peernode: PeerNode):
peernode_identified.emit(player_name, peernode)

View file

@ -4,3 +4,5 @@
[node name="PeerNodeDirectory" type="Node"]
script = ExtResource("1_mc47a")
[connection signal="child_entered_tree" from="." to="." method="_on_peernode_created"]

View file

@ -106,3 +106,8 @@ signal score_reported(strokes: int)
## Emitted when the hole scores have changed because of [method rpc_set_scores].
signal scores_changed(old: Array, new: Array)
## Emitted when a stroke has been performed on this player's [GolfBall].
##
## Currently tracked only for the local ball.
signal putt_performed(ball: GolfBall)

View file

@ -28,6 +28,7 @@ func rpc_possess_playernode(player_name: String, peer_id: int):
playernode.possessed.connect(_on_playernode_possessed.bind(playernode))
playernode.score_reported.connect(_on_playernode_score_reported.bind(playernode))
playernode.scores_changed.connect(_on_playernode_scores_changed.bind(playernode))
playernode.putt_performed.connect(_on_playernode_putt_performed.bind(playernode))
var sanitized_player_name = PlayerNode.sanitize_player_name(player_name)
playernode.player_name = sanitized_player_name
playernode.name = sanitized_player_name
@ -45,6 +46,8 @@ func _on_playernode_color_changed(old: Color, new: Color, playernode: PlayerNode
func _on_playernode_possessed(old: int, new: int, playernode: PlayerNode) -> void:
playernode_possessed.emit(old, new, playernode)
if playernode.is_multiplayer_authority() and not multiplayer.is_server():
local_playernode_possessed.emit(old, new, playernode)
func _on_playernode_score_reported(strokes: int, playernode: PlayerNode) -> void:
playernode_score_reported.emit(strokes, playernode)
@ -52,6 +55,9 @@ func _on_playernode_score_reported(strokes: int, playernode: PlayerNode) -> void
func _on_playernode_scores_changed(old: Array, new: Array, playernode: PlayerNode) -> void:
playernode_scores_changed.emit(old, new, playernode)
func _on_playernode_putt_performed(ball: GolfBall, playernode: PlayerNode) -> void:
playernode_putt_performed.emit(ball, playernode)
## Emitted when the name of one of the children [PlayerNode]s changes on the local scene.
signal playernode_name_changed(old: String, new: String, playernode: PlayerNode)
@ -62,8 +68,14 @@ signal playernode_color_changed(old: Color, new: Color, playernode: PlayerNode)
## Emitted everywhere when one of the children [PlayerNode]s has changed multiplayer authority.
signal playernode_possessed(old: int, new: int, playernode: PlayerNode)
## Emitted on a client when it becomes authority of a [PlayerNode].
signal local_playernode_possessed(old: int, new: int, playernode: PlayerNode)
## Emitted when a [PlayerNode] reports a score.
signal playernode_score_reported(strokes: int, playernode: PlayerNode)
## Emitted when the scores of one of the children [PlayerNode]s change on the local scene.
signal playernode_scores_changed(old: Array, new: Array, playernode: PlayerNode)
## Emitted when a [PlayerNode] performs a putt on its controlled [GolfBall].
signal playernode_putt_performed(ball: GolfBall, playernode: PlayerNode)