use no-intro names in netplay/cheats (#1133)

* use no-intro names in netplay/cheats

* more

* more
This commit is contained in:
Logan McNaughton 2026-06-29 21:37:33 +02:00 committed by GitHub
parent 0eddf31f92
commit 01a53ce1c0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 22335 additions and 13 deletions

15
Cargo.lock generated
View File

@ -2790,6 +2790,7 @@ dependencies = [
"mimalloc",
"open",
"postcard",
"quick-xml 0.40.1",
"rand 0.10.1",
"regex",
"reqwest",
@ -5701,6 +5702,16 @@ dependencies = [
"serde",
]
[[package]]
name = "quick-xml"
version = "0.40.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2474bd2e5029e7ccb6abb2ba48cf2383a333851dedf495901544281590c7da7f"
dependencies = [
"memchr",
"tokio",
]
[[package]]
name = "quote"
version = "1.0.46"
@ -8255,7 +8266,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c324a910fd86ebdc364a3e61ec1f11737d3b1d6c273c0239ee8ff4bc0d24b4a"
dependencies = [
"proc-macro2",
"quick-xml",
"quick-xml 0.39.4",
"quote",
]
@ -9435,7 +9446,7 @@ version = "5.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8067892e940ed1727dea64690378601603b31d62dfde019a5335fbb7c0e0ed9"
dependencies = [
"quick-xml",
"quick-xml 0.39.4",
"serde",
"zbus_names",
"zvariant",

View File

@ -36,6 +36,7 @@ postcard = { version = "1.1", features = ["use-std"] }
clap = { version = "4.5", features = ["derive"] }
reqwest = { version = "0.13", default-features = false, features = ["native-tls-vendored", "charset", "http2", "system-proxy", "json", "query"] }
discord-rich-presence = "1.1"
quick-xml = { version = "0.40", features = ["async-tokio"] }
[target.'cfg(not(target_os = "android"))'.dependencies]
slint = { version = "1.16", default-features = false, features = ["compat-1-2", "std", "unstable-winit-030", "backend-winit", "renderer-femtovg-wgpu", "accessibility"], optional = true }

File diff suppressed because it is too large Load Diff

View File

@ -334,8 +334,10 @@ pub fn run(args: Args, arg_count: usize) -> std::io::Result<()> {
#[cfg(feature = "gui")]
{
let app = ui::gui::AppWindow::new().unwrap();
let no_intro_map =
std::sync::Arc::new(tokio::sync::Mutex::new(rustc_hash::FxHashMap::default()));
set_app_id();
ui::gui::app_window(&app, false);
ui::gui::app_window(&app, false, no_intro_map);
}
}
@ -380,7 +382,9 @@ fn android_main(app: slint::android::AndroidApp) {
std::fs::create_dir_all(dirs.data_dir.join("saves")).unwrap();
std::fs::create_dir_all(dirs.data_dir.join("states")).unwrap();
ui::gui::app_window(&app_window, true);
let no_intro_map =
std::sync::Arc::new(tokio::sync::Mutex::new(rustc_hash::FxHashMap::default()));
ui::gui::app_window(&app_window, true, no_intro_map);
close_tx.send(()).unwrap();
*android::WEAK_SLINT_WINDOW.lock().unwrap() = None;
*android::ANDROID_APP.lock().unwrap() = None;

View File

@ -3,17 +3,21 @@ use crate::ui::gui::AppWindow;
use crate::{cheats, device};
use slint::ComponentHandle;
pub fn cheats_window(app: &AppWindow) {
pub fn cheats_window(
app: &AppWindow,
no_intro_map: std::sync::Arc<tokio::sync::Mutex<rustc_hash::FxHashMap<String, String>>>,
) {
let weak = app.as_weak();
app.on_cheats_select_rom_clicked(move |rom_dir| {
let select_rom = ui::gui::select_rom(rom_dir);
let weak = weak.clone();
let no_intro_map = no_intro_map.clone();
tokio::spawn(async move {
if let Some(file) = select_rom.await
&& let Some(rom_contents) = device::get_rom_contents(&file)
{
let game_crc = ui::storage::get_game_crc(&rom_contents);
let game_name = ui::storage::get_game_name(&rom_contents);
let game_name = ui::gui::get_nointro_name(&rom_contents, no_intro_map).await;
weak.upgrade_in_event_loop(move |handle| {
handle.set_cheat_game_name(game_name.into());
})

View File

@ -1,3 +1,4 @@
use crate::device;
use crate::retroachievements;
use crate::ui;
#[cfg(target_os = "android")]
@ -521,7 +522,16 @@ fn about_window(app: &AppWindow) {
}
}
pub fn app_window(app: &AppWindow, is_android: bool) {
pub fn app_window(
app: &AppWindow,
is_android: bool,
no_intro_map: std::sync::Arc<tokio::sync::Mutex<rustc_hash::FxHashMap<String, String>>>,
) {
let no_intro_map_clone = no_intro_map.clone();
tokio::spawn(async move {
load_no_intro(no_intro_map_clone).await;
});
retroachievements::init_client(false, false, false);
app.set_is_android(is_android);
about_window(app);
@ -532,8 +542,8 @@ pub fn app_window(app: &AppWindow, is_android: bool) {
controller_window(app, &config);
local_game_window(app, &config);
}
ui::netplay::netplay_window(app);
ui::cheats::cheats_window(app);
ui::netplay::netplay_window(app, no_intro_map.clone());
ui::cheats::cheats_window(app, no_intro_map);
#[cfg(not(target_os = "android"))]
{
@ -657,6 +667,55 @@ pub fn update_recent_roms(app: &AppWindow, file_path: std::path::PathBuf) {
app.set_recent_roms(slint::ModelRc::from(std::rc::Rc::new(recent_roms)));
}
pub async fn get_nointro_name(
rom: &[u8],
no_intro_map: std::sync::Arc<tokio::sync::Mutex<rustc_hash::FxHashMap<String, String>>>,
) -> String {
let hash = device::cart::rom::calculate_hash(rom).to_lowercase();
if let Some(name) = no_intro_map.lock().await.get(&hash) {
name.clone()
} else {
ui::storage::get_game_name(rom)
}
}
async fn load_no_intro(
no_intro_map: std::sync::Arc<tokio::sync::Mutex<rustc_hash::FxHashMap<String, String>>>,
) {
let mut reader = quick_xml::Reader::from_str(include_str!(
"../../data/ui/Nintendo - Nintendo 64 (DB Export) (20260609-194259).xml"
));
let mut buf = Vec::new();
let mut current_game = String::new();
let mut map = no_intro_map.lock().await;
loop {
match reader.read_event_into_async(&mut buf).await {
Ok(quick_xml::events::Event::Start(e)) => {
if e.name().as_ref() == b"game"
&& let Ok(Some(name_attribute)) = e.try_get_attribute("name")
&& let Ok(name) = String::from_utf8(name_attribute.value.into_owned())
{
current_game = name;
}
}
Ok(quick_xml::events::Event::Empty(e)) => {
if e.name().as_ref() == b"file"
&& let Ok(Some(format_attribute)) = e.try_get_attribute("format")
&& format_attribute.value.as_ref() == b"BigEndian"
&& let Ok(Some(sha256_attribute)) = e.try_get_attribute("sha256")
&& let Ok(sha256) = String::from_utf8(sha256_attribute.value.into_owned())
{
map.insert(sha256.to_lowercase(), current_game.clone());
}
}
Err(e) => panic!("Error at position {}: {:?}", reader.error_position(), e),
Ok(quick_xml::events::Event::Eof) => break,
_ => (),
}
buf.clear();
}
}
pub async fn select_rom(rom_dir: slint::SharedString) -> Option<std::path::PathBuf> {
#[cfg(target_os = "android")]
return ui::android::select_rom(rom_dir).await;

View File

@ -65,13 +65,17 @@ struct NetplayPingMessage {
num_of_peers: usize,
}
fn select_rom(weak: slint::Weak<AppWindow>, rom_dir: slint::SharedString) {
fn select_rom(
weak: slint::Weak<AppWindow>,
rom_dir: slint::SharedString,
no_intro_map: std::sync::Arc<tokio::sync::Mutex<rustc_hash::FxHashMap<String, String>>>,
) {
let select_rom = ui::gui::select_rom(rom_dir);
tokio::spawn(async move {
if let Some(file) = select_rom.await {
if let Some(rom_contents) = device::get_rom_contents(&file) {
let hash = device::cart::rom::calculate_hash(&rom_contents);
let mut game_name = ui::storage::get_game_name(&rom_contents);
let mut game_name = ui::gui::get_nointro_name(&rom_contents, no_intro_map).await;
let pal = device::cart::rom::is_system_pal(&rom_contents);
let game_crc = ui::storage::get_game_crc(&rom_contents);
let cheats = ui::config::Cheats::new();
@ -108,6 +112,7 @@ fn select_rom(weak: slint::Weak<AppWindow>, rom_dir: slint::SharedString) {
});
}
#[allow(clippy::too_many_arguments)]
fn setup_callbacks(
app: &AppWindow,
netplay_write_sender: &tokio::sync::broadcast::Sender<Option<NetplayLobbyMessage>>,
@ -116,6 +121,7 @@ fn setup_callbacks(
netplay_write_receiver: &tokio::sync::broadcast::Receiver<Option<NetplayLobbyMessage>>,
close_ping_tx: &tokio::sync::broadcast::Sender<()>,
close_ping_rx: &tokio::sync::broadcast::Receiver<()>,
no_intro_map: std::sync::Arc<tokio::sync::Mutex<rustc_hash::FxHashMap<String, String>>>,
) {
let weak = app.as_weak();
let netplay_write_sender_create_session = netplay_write_sender.clone();
@ -238,7 +244,7 @@ fn setup_callbacks(
let weak_app = app.as_weak();
app.on_netplay_select_rom(move |rom_dir| {
select_rom(weak_app.clone(), rom_dir);
select_rom(weak_app.clone(), rom_dir, no_intro_map.clone());
});
let weak_app = app.as_weak();
@ -992,7 +998,10 @@ fn setup_join_window(
app.invoke_netplay_refresh_sessions();
}
pub fn netplay_window(app: &AppWindow) {
pub fn netplay_window(
app: &AppWindow,
no_intro_map: std::sync::Arc<tokio::sync::Mutex<rustc_hash::FxHashMap<String, String>>>,
) {
let (netplay_read_sender, netplay_read_receiver): (
tokio::sync::broadcast::Sender<Option<NetplayLobbyMessage>>,
tokio::sync::broadcast::Receiver<Option<NetplayLobbyMessage>>,
@ -1016,5 +1025,6 @@ pub fn netplay_window(app: &AppWindow) {
&netplay_write_receiver,
&close_ping_tx,
&close_ping_rx,
no_intro_map,
);
}