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:
parent
2a0c74f1d2
commit
f2b4788903
12 changed files with 321 additions and 184 deletions
|
@ -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():
|
||||
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_destroyed(peernode: PeerNode) -> void:
|
||||
Log.peer(self, "Peernode destroyed: %d" % peernode.get_multiplayer_authority())
|
||||
|
||||
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)
|
||||
Log.peer(self, "Playernode created: %s" % playernode)
|
||||
if is_multiplayer_authority():
|
||||
level_manager.add_player(playernode)
|
||||
|
||||
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():
|
||||
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)
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,19 +60,23 @@ 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
|
||||
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].
|
||||
|
@ -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,6 +103,9 @@ 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)
|
||||
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].
|
||||
|
@ -119,9 +122,12 @@ 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
|
||||
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.
|
||||
|
@ -135,24 +141,49 @@ 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
|
||||
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.
|
||||
|
@ -166,9 +197,12 @@ 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
|
||||
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.
|
||||
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
## 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
|
||||
# Determine the next level
|
||||
|
||||
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, "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()
|
||||
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()
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -4,3 +4,5 @@
|
|||
|
||||
[node name="PeerNodeDirectory" type="Node"]
|
||||
script = ExtResource("1_mc47a")
|
||||
|
||||
[connection signal="child_entered_tree" from="." to="." method="_on_peernode_created"]
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue