refactor: reorganize networking and data bridge scenes

* Move networking scenes under `controllers/networking`
* Move data bridge scene under `scenes/data`
* Rename the bridge node to `data_bridge`
* Update lobby UI scene path
* Remove unused lobby RPC node/script
This commit is contained in:
2026-08-12 16:52:16 -05:00
parent 84b3600044
commit 09369d3dd4
21 changed files with 14 additions and 21 deletions

View File

@@ -0,0 +1,20 @@
[gd_scene load_steps=5 format=3 uid="uid://dy51wny4x53f4"]
[ext_resource type="Script" uid="uid://52eithlmedm3" path="res://scenes/data/game_data.gd" id="1_hulqm"]
[ext_resource type="Script" uid="uid://dvw46rvml3ec" path="res://scenes/data/game_state.gd" id="2_6ash1"]
[ext_resource type="Script" uid="uid://6sfwe1hwgf0g" path="res://scenes/data/lobby_data.gd" id="3_80q4n"]
[ext_resource type="Script" uid="uid://bs4vblwa3u5jq" path="res://scenes/data/multiplayer_data.gd" id="4_setx2"]
[node name="data_bridge" type="Node"]
[node name="game_data" type="Node" parent="."]
script = ExtResource("1_hulqm")
[node name="game_state" type="Node" parent="."]
script = ExtResource("2_6ash1")
[node name="lobby_data" type="Node" parent="."]
script = ExtResource("3_80q4n")
[node name="multiplayer_data" type="Node" parent="."]
script = ExtResource("4_setx2")

58
scenes/data/game_data.gd Normal file
View File

@@ -0,0 +1,58 @@
class_name GameData extends Node
var client1: int
var client2: int
var player_id: String = ""
var game_address: String = "0.0.0.0"
var game_port: int = 8080
var game_mode: String = "freeball"
enum PlayerType {
Player1,
Player2
}
enum GameModeType {
BALL_8,
BALL_9,
SNOOKER,
FREE_BALL
}
const MATCH_TYPES: Dictionary = {
"8ball": GameModeType.BALL_8,
"9ball": GameModeType.BALL_9,
"snooker": GameModeType.SNOOKER,
"freeball": GameModeType.FREE_BALL
}
var GameMode: Dictionary = {
GameModeType.BALL_8: Ball8,
GameModeType.BALL_9: Ball9,
GameModeType.SNOOKER: Snooker,
GameModeType.FREE_BALL: FreeBall
}
var SelectedGameMode: GameModeType = GameModeType.FREE_BALL
func _init() -> void:
Globals.game_data = self
@rpc("authority", "reliable")
func set_game_address(address: String) -> void:
game_address = address
@rpc("authority", "reliable")
func set_game_port(port: String) -> void:
game_port = int(port)
func set_game_mode(mode: String) -> void:
SelectedGameMode = MATCH_TYPES[mode]
func set_player_id(is_player_1: bool) -> void:
player_id = "Player 1" if is_player_1 else "Player 2"

View File

@@ -0,0 +1 @@
uid://52eithlmedm3

57
scenes/data/game_state.gd Normal file
View File

@@ -0,0 +1,57 @@
class_name GameState extends Node
@warning_ignore_start("unused_signal")
signal update_cue_cam_position
signal balls_stopped_moving
signal white_ball_sunk
signal white_ball_needs_hard_reset
signal reload_scene
signal process_ball
signal reap_ball
@warning_ignore_restore("unused_signal")
func _init() -> void:
Globals.game_state = self
func load_game_scene(scene_str: String) -> void:
var scene = load(scene_str).instantiate()
var target = get_tree().root.get_node("billiards/scene")
target.add_child(scene)
func set_game_scene(scene_str: String) -> void:
var scene = load(scene_str).instantiate()
var target = get_tree().root.get_node("billiards/scene")
if "game" in scene_str:
scene.name = "game"
elif "lobby" in scene_str:
scene.name = "lobby_screen"
elif "start" in scene_str:
scene.name = "start_screen"
clear_game_scene(target)
target.add_child(scene)
func clear_game_scene(container: Node) -> void:
for child in container.get_children():
child.queue_free()
await get_tree().process_frame
func switch_active_player() -> void:
# TODO: Move away from using client ID or mask it with a map ID
if Globals.multiplayer_data.current_turn_player_id == Globals.game_data.client1:
Globals.multiplayer_data.rpc(
"set_active_player_id",
Globals.game_data.client2
)
elif Globals.multiplayer_data.current_turn_player_id == Globals.game_data.client2:
Globals.multiplayer_data.rpc(
"set_active_player_id",
Globals.game_data.client1
)

View File

@@ -0,0 +1 @@
uid://dvw46rvml3ec

31
scenes/data/lobby_data.gd Normal file
View File

@@ -0,0 +1,31 @@
class_name LobbyData extends Node
func _init() -> void:
Globals.lobby_data = self
@rpc("authority", "reliable")
func connect_to_game() -> void:
# NOTE: Leave the lobby
MessageBus.emit_local("lobby_close_connection", null)
# NOTE: Join target game server
MessageBus.emit_local(
"game_start_client",
[
Globals.game_data.game_address,
Globals.game_data.game_port
],
true
)
@rpc("authority", "reliable")
func go_back_to_match_screen() -> void:
if multiplayer.is_server(): return
push_warning("Client peer disconnected...")
Globals.game_state.set_game_scene(
"res://scenes/screens/lobby_screen/lobby.tscn"
)

View File

@@ -0,0 +1 @@
uid://6sfwe1hwgf0g

View File

@@ -0,0 +1,137 @@
class_name MultiplayerData extends Node
var is_multiplayer_active: bool = false
var multiplayer_synchronizer: MultiplayerSynchronizer = MultiplayerSynchronizer.new()
var synchronizer_config: SceneReplicationConfig = SceneReplicationConfig.new()
var current_turn_player_id: int = -1
func _init() -> void:
Globals.multiplayer_data = self
multiplayer_synchronizer.name = "multiplayer_synchronizer"
multiplayer_synchronizer.replication_config = synchronizer_config
multiplayer_synchronizer.root_path = "/root/billiards"
@rpc("authority", "call_local", "reliable")
func set_multiplayer_active() -> void:
is_multiplayer_active = true
@rpc("authority", "call_local", "reliable")
func set_active_player_id(id: int) -> void:
push_warning("Server assigned active player: ", id)
current_turn_player_id = id
func reset() -> void:
multiplayer_synchronizer = MultiplayerSynchronizer.new()
synchronizer_config = SceneReplicationConfig.new()
current_turn_player_id = -1
is_multiplayer_active = true
multiplayer_synchronizer.name = "multiplayer_synchronizer"
multiplayer_synchronizer.replication_config = synchronizer_config
multiplayer_synchronizer.root_path = "/root/billiards"
func init_match() -> void:
var match_entry = Dictionary()
match_entry.set("type", Globals.game_data.game_mode)
rpc("set_active_player_id", Globals.game_data.client1)
MessageBus.emit_propagation_clients_only.rpc_id(
Globals.game_data.client1,
"match_list_entry_load_match",
[match_entry, true],
true
)
MessageBus.emit_propagation_clients_only.rpc_id(
Globals.game_data.client2,
"match_list_entry_load_match",
[match_entry, false],
true
)
func set_multiplayer_inactive() -> void:
is_multiplayer_active = false
func can_do_request_server_only() -> bool:
return can_do_request(true)
# NOTE: Clients could be modified to pass checks; but, because we are server authority based
# it wouldn't matter because server should/will override any state of balls/scores and
# checks which player is active when processing input. This is mostly patterned
# to reduce client side overhead.
func can_do_request(server_only: bool = false) -> bool:
# NOTE: If request is local and not multiplayer
if not is_multiplayer_active:
return true
# NOTE: If request is server only; checkable by client and server side
# server_only check must return so CANNOT do if 'server_only and multiplayer.is_server()' ...
if server_only:
return multiplayer.is_server()
# NOTE: If request is local or server side
if current_turn_player_id == multiplayer.get_unique_id():
return true
# NOTE: If request is on server and checking active player
if current_turn_player_id == multiplayer.get_remote_sender_id():
return true
return false
func set_tracking_of_cue(path: String) -> void:
path = str(path).trim_prefix(str(multiplayer_synchronizer.root_path) + "/")
var position_pth = NodePath( path + ":position" )
var rotation_pth = NodePath( path + ":rotation" )
synchronizer_config.add_property(position_pth)
synchronizer_config.add_property(rotation_pth)
synchronizer_config.property_set_replication_mode(
position_pth, SceneReplicationConfig.REPLICATION_MODE_ON_CHANGE
)
synchronizer_config.property_set_replication_mode(
rotation_pth, SceneReplicationConfig.REPLICATION_MODE_ON_CHANGE
)
func set_tracking_of_ball(path: String) -> void:
path = str(path).trim_prefix(str(multiplayer_synchronizer.root_path) + "/")
var position_pth = NodePath( path + ":position" )
var rotation_pth = NodePath( path + ":rotation" )
var linear_velocity_pth = NodePath( path + ":linear_velocity" )
synchronizer_config.add_property(position_pth)
synchronizer_config.add_property(rotation_pth)
synchronizer_config.add_property(linear_velocity_pth)
synchronizer_config.property_set_replication_mode(
position_pth, SceneReplicationConfig.REPLICATION_MODE_ON_CHANGE
)
synchronizer_config.property_set_replication_mode(
rotation_pth, SceneReplicationConfig.REPLICATION_MODE_ON_CHANGE
)
synchronizer_config.property_set_replication_mode(
linear_velocity_pth, SceneReplicationConfig.REPLICATION_MODE_ON_CHANGE
)
func remove_tracking_of_ball(path: String) -> void:
path = str(path).trim_prefix(str(multiplayer_synchronizer.root_path) + "/")
var position_pth = NodePath( path + ":position" )
var rotation_pth = NodePath( path + ":rotation" )
var linear_velocity_pth = NodePath( path + ":linear_velocity" )
if synchronizer_config.has_property(position_pth):
synchronizer_config.remove_property(position_pth)
if synchronizer_config.has_property(rotation_pth):
synchronizer_config.remove_property(rotation_pth)
if synchronizer_config.has_property(linear_velocity_pth):
synchronizer_config.remove_property(linear_velocity_pth)

View File

@@ -0,0 +1 @@
uid://bs4vblwa3u5jq