feat(network): add selectable privacy-preserving discovery

This commit is contained in:
Alexander Sellite 2026-09-01 10:21:26 -04:00
parent 9cf0c8fc9c
commit 4d31fd1517
26 changed files with 959 additions and 153 deletions

View file

@ -2234,9 +2234,15 @@ func _on_return_to_title_requested() -> void:
_show_title_music(true)
func _on_title_join_game_requested(endpoint: String) -> void:
func _on_title_join_game_requested(requested_route: Variant) -> void:
if _quit_in_progress or _gameplay_started:
return
var route := _coerce_connection_route(requested_route)
if route == null:
_game_ui.get_title_screen().report_network_error(
"That connection address is invalid."
)
return
var active_slot: Dictionary = _save_slots.ensure_active_slot()
if not bool(active_slot.get("ok", false)):
_game_ui.get_title_screen().report_network_error(
@ -2247,14 +2253,26 @@ func _on_title_join_game_requested(endpoint: String) -> void:
_network_session.disconnect_session("Preparing direct connection.")
_join_requested_from_title = true
_join_requested_from_pause = false
_pending_join_endpoint = endpoint
if not _network_session.join_direct(endpoint):
_pending_join_endpoint = (
route.direct_endpoint.normalized_display
if route != null
and not route.is_discovery_join()
and route.direct_endpoint != null
else ""
)
if not _network_session.join_route(route):
_join_requested_from_title = false
func _on_pause_join_game_requested(endpoint: String) -> void:
func _on_pause_join_game_requested(requested_route: Variant) -> void:
if _quit_in_progress or not _gameplay_started:
return
var route := _coerce_connection_route(requested_route)
if route == null:
_game_ui.get_pause_menu().report_network_error(
"That connection address is invalid."
)
return
if not _save_manager.save_world_time_checkpoint():
_game_ui.get_pause_menu().report_network_error(
"Could not save progression before leaving this session."
@ -2262,20 +2280,36 @@ func _on_pause_join_game_requested(endpoint: String) -> void:
return
_join_requested_from_pause = true
_join_requested_from_title = false
_pending_join_endpoint = endpoint
_pending_join_endpoint = (
route.direct_endpoint.normalized_display
if route != null
and not route.is_discovery_join()
and route.direct_endpoint != null
else ""
)
_game_ui.get_pause_menu().close_for_title_transition()
var preserved_public_join: bool = (
_discovery.preserve_public_join_for_session_switch()
)
_network_session.disconnect_session("Connecting to another game.")
if not _network_session.join_direct(endpoint):
if not _network_session.join_route(route):
if preserved_public_join:
_discovery.cancel_pending_public_join()
_handle_failed_session_switch(
"Could not begin the direct connection."
"Could not begin the connection."
)
func _coerce_connection_route(value: Variant) -> ConnectionRoute:
if value is ConnectionRoute:
var supplied_route := value as ConnectionRoute
return supplied_route if supplied_route.is_valid() else null
if typeof(value) != TYPE_STRING:
return null
var endpoint := EndpointParser.parse(str(value))
return ConnectionRoute.direct(endpoint) if endpoint.is_valid() else null
func _on_friend_request_received(
request_id: String,
fingerprint: String,
@ -2335,8 +2369,17 @@ func _show_next_social_prompt() -> void:
elif kind == "friend_invite":
var room: Dictionary = _active_social_prompt.get("room", {})
var room_name := str(room.get("room_name", "their room"))
var relayed := str(room.get("connection_mode", "")) == "relay"
var privacy_message := (
"This join uses a privacy relay; the relay service still handles "
+ "both network addresses."
if relayed
else "This is a direct connection. Joining shares your public IP "
+ "address with the host."
)
shown = _game_ui.show_social_prompt(
"%s invited you to join %s." % [display_name, room_name],
"%s invited you to join %s.\n%s"
% [display_name, room_name, privacy_message],
"join",
"not now",
)
@ -2375,16 +2418,16 @@ func _on_social_prompt_declined() -> void:
call_deferred("_show_next_social_prompt")
func _on_social_public_join_prepared(endpoint: String) -> void:
func _on_social_public_join_prepared(route: ConnectionRoute) -> void:
if not _pending_social_invite_join:
return
var from_gameplay := _pending_social_invite_gameplay
_pending_social_invite_join = false
_pending_social_invite_gameplay = false
if from_gameplay:
_on_pause_join_game_requested(endpoint)
_on_pause_join_game_requested(route)
else:
_on_title_join_game_requested(endpoint)
_on_title_join_game_requested(route)
func _on_social_public_join_status_changed(
@ -2412,7 +2455,7 @@ func _on_network_join_authenticated() -> void:
var server_metadata: Dictionary = (
_network_session.get_last_server_metadata()
)
if connected_endpoint != null:
if connected_endpoint != null and not _network_session.is_current_route_discovery():
_saved_servers.record_successful_connection(
connected_endpoint,
int(server_metadata.get("max_players", 0)),
@ -2455,7 +2498,7 @@ func _on_network_connection_error(message: String) -> void:
var failed_endpoint: ConnectionEndpoint = (
_network_session.get_current_endpoint()
)
if failed_endpoint != null:
if failed_endpoint != null and not _network_session.is_current_route_discovery():
_saved_servers.record_connection_failure(
failed_endpoint,
_connection_result_code(message),