2026-08-07 02:50:54 -05:00
|
|
|
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 init_match():
|
|
|
|
|
var match_entry = Dictionary()
|
|
|
|
|
match_entry.set("type", Globals.game_data.game_mode)
|
|
|
|
|
|
|
|
|
|
rpc("set_active_player_id", Globals.game_data.client1)
|
|
|
|
|
|
2026-08-08 01:22:54 -05:00
|
|
|
MessageBus.emit_propagation_clients_only.rpc_id(
|
2026-08-07 02:50:54 -05:00
|
|
|
Globals.game_data.client1,
|
2026-08-08 01:22:54 -05:00
|
|
|
"match_list_entry_load_match",
|
|
|
|
|
[match_entry, true],
|
|
|
|
|
true
|
2026-08-07 02:50:54 -05:00
|
|
|
)
|
2026-08-08 01:22:54 -05:00
|
|
|
|
|
|
|
|
MessageBus.emit_propagation_clients_only.rpc_id(
|
2026-08-07 02:50:54 -05:00
|
|
|
Globals.game_data.client2,
|
2026-08-08 01:22:54 -05:00
|
|
|
"match_list_entry_load_match",
|
|
|
|
|
[match_entry, false],
|
|
|
|
|
true
|
2026-08-07 02:50:54 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func wait_for_connection() -> void:
|
|
|
|
|
while not Globals.lobby_data.lobby_ui.client.peer:
|
|
|
|
|
await get_tree().process_frame
|
|
|
|
|
|
|
|
|
|
while Globals.lobby_data.lobby_ui.client.peer.get_connection_status() != 2:
|
|
|
|
|
await get_tree().process_frame
|
|
|
|
|
|
|
|
|
|
func wait_for_connection_close() -> void:
|
|
|
|
|
while Globals.lobby_data.lobby_ui.client.peer:
|
|
|
|
|
await get_tree().process_frame
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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" )
|
|
|
|
|
|
|
|
|
|
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 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")
|
|
|
|
|
|
|
|
|
|
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)
|