diff --git a/scenes/game.gd b/scenes/game.gd new file mode 100644 index 0000000..2c4e4ef --- /dev/null +++ b/scenes/game.gd @@ -0,0 +1,28 @@ +extends Node +class_name Game + + +# This cannot be called in _ready because the multiplayer node is set *after* adding the node to the tree. +func init_signals(): + print("[Game] Initializing signals...") + multiplayer.connected_to_server.connect(_on_connected_to_server) + multiplayer.server_disconnected.connect(_on_server_disconnected) + multiplayer.connection_failed.connect(_on_connection_failed) + multiplayer.peer_connected.connect(_on_peer_connected) + multiplayer.peer_disconnected.connect(_on_peer_disconnected) + + +func _on_connected_to_server(): + print("{", multiplayer.multiplayer_peer.get_unique_id(), "} Connected to server!") + +func _on_server_disconnected(): + print("{", multiplayer.multiplayer_peer.get_unique_id(), "} Server disconnected...") + +func _on_connection_failed(): + print("{", multiplayer.multiplayer_peer.get_unique_id(), "} Connection failed...") + +func _on_peer_connected(peer_id: int): + print("{", multiplayer.multiplayer_peer.get_unique_id(), "} Peer connected: ", peer_id) + +func _on_peer_disconnected(peer_id: int): + print("{", multiplayer.multiplayer_peer.get_unique_id(), "} Peer disconnected: ", peer_id) diff --git a/scenes/game.tscn b/scenes/game.tscn new file mode 100644 index 0000000..2b1163b --- /dev/null +++ b/scenes/game.tscn @@ -0,0 +1,9 @@ +[gd_scene load_steps=3 format=3 uid="uid://b4w6ungwwjxsg"] + +[ext_resource type="Script" path="res://scenes/game.gd" id="1_cdtng"] +[ext_resource type="PackedScene" uid="uid://cwj0fyj6obj6r" path="res://scenes/multiple_players_tracker.tscn" id="2_f2gy2"] + +[node name="Game" type="Node"] +script = ExtResource("1_cdtng") + +[node name="MultiplePlayersTracker" parent="." instance=ExtResource("2_f2gy2")] diff --git a/scenes/main.gd b/scenes/main.gd index 02e804f..d2df763 100644 --- a/scenes/main.gd +++ b/scenes/main.gd @@ -2,26 +2,85 @@ extends Node class_name Main +@onready var scene_tree: SceneTree = get_tree() @onready var interface_instance: MarginContainer = $"Interface" const main_menu_scene: PackedScene = preload("res://scenes/main_menu.tscn") var main_menu_instance: MainMenu = null +const game_scene: PackedScene = preload("res://scenes/game.tscn") +var server_game_instance: Game = null +var client_game_instance: Game = null + + func init_main_menu(): main_menu_instance = main_menu_scene.instantiate() - main_menu_instance.room_created.connect(_on_room_created) - main_menu_instance.room_joined.connect(_on_room_joined) + main_menu_instance.hosting_confirmed.connect(_on_hosting_confirmed) + main_menu_instance.connecting_confirmed.connect(_on_connecting_confirmed) interface_instance.add_child(main_menu_instance) +func deinit_main_menu(): + main_menu_instance.queue_free() -func _on_room_created(server: ENetMultiplayerPeer, client: ENetMultiplayerPeer): - print(server, client) +func init_server_game(server_port: int): + server_game_instance = game_scene.instantiate() + server_game_instance.name = "Server" + add_child(server_game_instance, true) + + server_game_instance.init_signals() + + print("[Main] Creating server at: *:", server_port) + var smp: SceneMultiplayer = SceneMultiplayer.new() + var peer: ENetMultiplayerPeer = ENetMultiplayerPeer.new() + var error: Error = peer.create_server(server_port) + if error != OK or peer.get_connection_status() == MultiplayerPeer.CONNECTION_DISCONNECTED: + push_error(error) + return + + scene_tree.set_multiplayer(multiplayer, ^"/root/Main/Server") + smp.set_multiplayer_peer(peer) -func _on_room_joined(client: ENetMultiplayerPeer): - print(client) +func deinit_server_game(): + var smp: SceneMultiplayer = scene_tree.get_multiplayer(^"/root/Main/Server") + smp.multiplayer_peer.close() + smp.multiplayer_peer = null + scene_tree.set_multiplayer(multiplayer, ^"/root/Main/Server") + server_game_instance.queue_free() + +func init_client_game(player_name: String, player_color: Color, server_address: String, server_port: int): + client_game_instance = game_scene.instantiate() + client_game_instance.name = "Client" + add_child(client_game_instance, true) + + client_game_instance.init_signals() + + print("[Main] Creating client connecting to: ", server_address, ":", server_port) + var smp = SceneMultiplayer.new() + var peer: ENetMultiplayerPeer = ENetMultiplayerPeer.new() + var error: Error = peer.create_client(server_address, server_port) + if error != OK or peer.get_connection_status() == MultiplayerPeer.CONNECTION_DISCONNECTED: + push_error(error) + return + + scene_tree.set_multiplayer(smp, ^"/root/Main/Client") + smp.set_multiplayer_peer(peer) + +func deinit_client_game(): + var smp: SceneMultiplayer = scene_tree.get_multiplayer(^"/root/Main/Server") + smp.multiplayer_peer.close() + smp.multiplayer_peer = null + scene_tree.set_multiplayer(multiplayer, ^"/root/Main/Client") + client_game_instance.queue_free() func _ready(): init_main_menu() +func _on_hosting_confirmed(player_name: String, player_color: Color, server_port: int): + deinit_main_menu() + init_server_game(server_port) + init_client_game(player_name, player_color, "127.0.0.1", server_port) +func _on_connecting_confirmed(player_name: String, player_color: Color, server_address: String, server_port: int): + deinit_main_menu() + init_client_game(player_name, player_color, server_address, server_port) diff --git a/scenes/main_menu.gd b/scenes/main_menu.gd index b64e821..e1c12a2 100644 --- a/scenes/main_menu.gd +++ b/scenes/main_menu.gd @@ -2,8 +2,8 @@ extends Control class_name MainMenu -signal room_created(server: ENetMultiplayerPeer, client: ENetMultiplayerPeer) -signal room_joined(client: ENetMultiplayerPeer) +signal hosting_confirmed(player_name: String, player_color: Color, server_port: int) +signal connecting_confirmed(player_name: String, player_color: Color, server_address: String, server_port: int) enum MenuStage { @@ -87,16 +87,10 @@ func deinit_server_menu(): server_menu_instance.queue_free() func _on_hosting_confirmed(port: int): - var server = ENetMultiplayerPeer.new() - server.create_server(port) - var client = ENetMultiplayerPeer.new() - client.create_client("127.0.0.1", port) - room_created.emit(server, client) + hosting_confirmed.emit(player_name, player_color, port) func _on_connecting_confirmed(address: String, port: int): - var client = ENetMultiplayerPeer.new() - client.create_client(address, port) - room_joined.emit(client) + connecting_confirmed.emit(player_name, player_color, address, port) func _ready(): diff --git a/scenes/multiple_players_tracker.gd b/scenes/multiple_players_tracker.gd new file mode 100644 index 0000000..915b5ed --- /dev/null +++ b/scenes/multiple_players_tracker.gd @@ -0,0 +1,34 @@ +extends MultiplayerSpawner +class_name MultiplePlayersTracker + +# Requires the peer_id as data for the spawn function. + + +func get_tracker_by_peer(peer_id: int) -> SinglePlayerTracker: + for child in find_children("", "SinglePlayerTracker", false): + if child.peer_id == peer_id: + return child + return null + +func init_tracker(peer_id: int) -> SinglePlayerTracker: + var existing_tracker: SinglePlayerTracker = get_tracker_by_peer(peer_id) + if existing_tracker != null: + return existing_tracker + var single_tracker_instance = spawn(peer_id) + return single_tracker_instance + + +func _ready(): + spawn_function = _spawn_tracker + +func _spawn_tracker(data: Variant) -> Node: + print("Spawning ", data) + var single_tracker_scene: PackedScene = load(get_spawnable_scene(0)) + var single_tracker_instance: SinglePlayerTracker = single_tracker_scene.instantiate() + single_tracker_instance.peer_id = data + return single_tracker_instance + + +func _process(delta): + if multiplayer.is_server() and Input.is_action_just_pressed("ui_accept"): + spawn(1) diff --git a/scenes/multiple_players_tracker.tscn b/scenes/multiple_players_tracker.tscn new file mode 100644 index 0000000..c929dfd --- /dev/null +++ b/scenes/multiple_players_tracker.tscn @@ -0,0 +1,9 @@ +[gd_scene load_steps=2 format=3 uid="uid://cwj0fyj6obj6r"] + +[ext_resource type="Script" path="res://scenes/multiple_players_tracker.gd" id="1_fxysy"] + +[node name="MultiplePlayersTracker" type="MultiplayerSpawner"] +_spawnable_scenes = PackedStringArray("res://scenes/single_player_tracker.tscn") +spawn_path = NodePath(".") +spawn_limit = 32 +script = ExtResource("1_fxysy") diff --git a/scenes/server_options_menu.gd b/scenes/server_options_menu.gd index 5602a06..3358fc9 100644 --- a/scenes/server_options_menu.gd +++ b/scenes/server_options_menu.gd @@ -2,7 +2,7 @@ extends PanelContainer class_name ServerOptionsMenu -@export var port: int = 27015 +@export var port: int = 12345 signal hosting_confirmed(port: int) signal connecting_confirmed(address: String, port: int) diff --git a/scenes/single_player_tracker.gd b/scenes/single_player_tracker.gd new file mode 100644 index 0000000..308dfd7 --- /dev/null +++ b/scenes/single_player_tracker.gd @@ -0,0 +1,48 @@ +extends MultiplayerSynchronizer +class_name SinglePlayerTracker + +## Emitted when the peer represented by this object connects. +signal peer_has_connected + +## Emitted when the peer represented by this object connects. +signal peer_has_disconnected + + +## The peer ID that this object represents. +var peer_id: int = 0 + +## Whether the peer is connected or not. +var peer_connected: bool = false: + get: + return peer_connected + set(value): + var pvalue = peer_connected + peer_connected = value + if value != pvalue: + if value: + peer_has_connected.emit() + else: + peer_has_disconnected.emit() + +## The player's name. +var player_name: String = "Player" + +## The player's color. +var player_color: Color = Color.WHITE + +## This player's score, with an item per hole played. +var strokes_per_hole: Array[int] = [] + + +func _ready(): + replication_config = SceneReplicationConfig.new() + replication_config.add_property(^".:peer_id") + replication_config.property_set_replication_mode(^".:peer_id", SceneReplicationConfig.ReplicationMode.REPLICATION_MODE_ON_CHANGE) + replication_config.add_property(^".:peer_connected") + replication_config.property_set_replication_mode(^".:peer_connected", SceneReplicationConfig.ReplicationMode.REPLICATION_MODE_ON_CHANGE) + replication_config.add_property(^".:player_name") + replication_config.property_set_replication_mode(^".:player_name", SceneReplicationConfig.ReplicationMode.REPLICATION_MODE_ON_CHANGE) + replication_config.add_property(^".:player_color") + replication_config.property_set_replication_mode(^".:player_color", SceneReplicationConfig.ReplicationMode.REPLICATION_MODE_ON_CHANGE) + replication_config.add_property(^".:strokes_per_hole") + replication_config.property_set_replication_mode(^".:strokes_per_hole", SceneReplicationConfig.ReplicationMode.REPLICATION_MODE_ON_CHANGE) diff --git a/scenes/single_player_tracker.tscn b/scenes/single_player_tracker.tscn new file mode 100644 index 0000000..122713c --- /dev/null +++ b/scenes/single_player_tracker.tscn @@ -0,0 +1,7 @@ +[gd_scene load_steps=2 format=3 uid="uid://drccgvtcng3ju"] + +[ext_resource type="Script" path="res://scenes/single_player_tracker.gd" id="1_jwlkv"] + +[node name="SinglePlayerTracker" type="MultiplayerSynchronizer"] +root_path = NodePath(".") +script = ExtResource("1_jwlkv")