Fix review findings: expose netplay callbacks on AppWindow, use rfd::AsyncFileDialog, set is_host on lobby update
Some checks failed
Rust / build-linux (linux-x86_64, X64, ubuntu-24.04, x86_64-unknown-linux-gnu) (pull_request) Failing after 8s
Rust / build-android (29.0.14206865, ubuntu-24.04, 33) (pull_request) Failing after 4s
Rust-lint / lint-linux (pull_request) Failing after 18s
Rust / build-linux (linux-aarch64, ARM64, ubuntu-24.04-arm, aarch64-unknown-linux-gnu) (pull_request) Has been cancelled
Rust / build-windows (windows-aarch64, woa64, windows-11-arm, aarch64-pc-windows-msvc) (pull_request) Has been cancelled
Rust / build-windows (windows-x86_64, win64, windows-2025, x86_64-pc-windows-msvc) (pull_request) Has been cancelled
Rust / build-macos (macos-aarch64, ARM64, aarch64-apple-darwin) (pull_request) Has been cancelled
Rust / Collect release artifacts (pull_request) Has been cancelled

Finding 1: the Rust side calls on_netplay_resume_session,
on_netplay_save_session and set_netplay_is_host on AppWindow, but the
callbacks/property were only declared on the NetplayCreate/NetplayWait
sub-components. appwindow.slint now declares callback
netplay_resume_session(string), callback netplay_save_session and the
in-out property netplay_is_host <=> NetplayWaitData.is_host, and
forwards them at the NetplayCreate/NetplayWait instantiation sites,
matching the existing netplay callback pattern.

Finding 2: rfd::AsyncFilePicker does not exist in rfd 0.17; the crate
exports AsyncFileDialog (already used by this repo in src/ui/gui.rs).
Switch the resume file picker to rfd::AsyncFileDialog and use
FileHandle::path() for the display path.

Finding 3: set is_host from the ResponseSession lobby update instead of
at wait-window open, comparing the local player name against players[0]
(the session creator, always registered first). Re-evaluates on every
lobby update.
This commit is contained in:
Claude 2026-08-25 21:02:06 -05:00 committed by Hermes CI
parent 8e2c29039c
commit 98d9c6f0d0
2 changed files with 28 additions and 8 deletions

View File

@ -53,6 +53,8 @@ export component AppWindow inherits Window {
callback netplay_create_session(string, string, string, string, string, string, bool, bool);
callback netplay_select_rom(string);
callback netplay_join_session(string, string, string, string);
callback netplay_resume_session(string);
callback netplay_save_session;
callback netplay_close;
callback cheats_select_rom_clicked(string);
callback cheats_clear_clicked;
@ -134,6 +136,8 @@ export component AppWindow inherits Window {
in-out property netplay_recommended_delay <=> NetplayWaitData.recommended_delay;
in-out property netplay_game_pal <=> NetplayWaitData.game_pal;
in-out property netplay_connected_peers_count <=> NetplayWaitData.connected_peers_count;
in-out property netplay_is_host <=> NetplayWaitData.is_host;
in-out property netplay_resyncing <=> NetplayWaitData.resyncing;
private property <string> popup_message;
private property <bool> popup_has_close;
@ -275,6 +279,9 @@ export component AppWindow inherits Window {
begin_game(a) => {
netplay_begin_game(a);
}
save_session => {
netplay_save_session();
}
close => {
netplay_close();
}
@ -288,6 +295,9 @@ export component AppWindow inherits Window {
create_session(a, b, c, d, e, f, g, h) => {
netplay_create_session(a,b,c,d,e,f,g,h);
}
resume_session(rom_dir) => {
netplay_resume_session(rom_dir);
}
close => {
netplay_close();
}

View File

@ -277,13 +277,13 @@ fn setup_callbacks(
app.on_netplay_resume_session(move |rom_dir| {
let weak_app = weak_app.clone();
tokio::spawn(async move {
if let Some(file) = rfd::AsyncFilePicker::new()
if let Some(file) = rfd::AsyncFileDialog::new()
.add_filter("Netplay State", &["netplay-state"])
.set_directory(rom_dir)
.pick_file()
.await
{
eprintln!("resume session from: {}", file.display());
eprintln!("resume session from: {}", file.path().display());
// TODO: #3 — load the netplay session state from the file and
// re-establish the connection. For now, just show a message.
weak_app
@ -793,12 +793,8 @@ fn setup_wait_window(
app.set_netplay_game_name(game_name);
app.set_netplay_rom_path(rom_path);
app.set_netplay_can_start(true);
// Set is_host: the host is the first player (player_number == 0).
// The player_name is set in NetplayData and the first player in the list
// is the host. This is determined when the session is created.
app.set_netplay_is_host(
app.get_netplay_player_name() == app.get_netplay_players().iter().next().map(|s| s.to_string()).unwrap_or_default().as_str()
);
// is_host is set when the first ResponseSession arrives and the players
// list is populated (host is players[0], see netplay_wait.slint).
let request_update = NetplayLobbyMessage {
message_type: MessageType::RequestUpdateSession,
@ -828,6 +824,20 @@ fn setup_wait_window(
.collect::<Vec<slint::SharedString>>(),
),
)));
// The host is the session creator, always
// registered first in the lobby; the wait
// window's host-gated controls (input delay,
// Start Game, Save Session) all key off
// players[0] == player_name.
handle.set_netplay_is_host(
handle.get_netplay_player_name()
== handle
.get_netplay_players()
.iter()
.next()
.map(|s| s.to_string())
.unwrap_or_default(),
);
})
.unwrap();
}