From e874bf142dcdb96bf010ec0585023ea53fda81db Mon Sep 17 00:00:00 2001 From: Maple Date: Fri, 24 Apr 2026 21:38:31 +0200 Subject: [PATCH 01/22] fix self holepunch --- rnex-core/src/nex/matchmake.rs | 36 ++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/rnex-core/src/nex/matchmake.rs b/rnex-core/src/nex/matchmake.rs index 032fbad..085c8a1 100644 --- a/rnex-core/src/nex/matchmake.rs +++ b/rnex-core/src/nex/matchmake.rs @@ -236,6 +236,9 @@ impl ExtendedMatchmakeSession { }*/ for pid in &list_of_connected_pids { + if other_conn.pid == *pid { + continue; + } other_conn .remote .process_notification_event(NotificationEvent { @@ -247,28 +250,31 @@ impl ExtendedMatchmakeSession { param_3: self.connected_players.len() as _, }) .await; - } + } } for old_conns in &old_particip { let Some(old_conns) = old_conns.upgrade() else { continue; }; - if old_conns.pid != self.session.gathering.host_pid{ - continue; + if old_conns.pid != self.session.gathering.host_pid { + continue; } - for new_conn_pid in conns.iter().filter_map(Weak::upgrade).map(|c| c.pid){ - old_conns - .remote - .process_notification_event(NotificationEvent { - pid_source: initiating_pid, - notif_type: 3001, - param_1: self.session.gathering.self_gid as PID, - param_2: new_conn_pid, - str_param: join_msg.clone(), - param_3: self.connected_players.len() as _, - }) - .await; + for new_conn_pid in conns.iter().filter_map(Weak::upgrade).map(|c| c.pid) { + if old_conns.pid == new_conn_pid { + continue; + } + old_conns + .remote + .process_notification_event(NotificationEvent { + pid_source: initiating_pid, + notif_type: 3001, + param_1: self.session.gathering.self_gid as PID, + param_2: new_conn_pid, + str_param: join_msg.clone(), + param_3: self.connected_players.len() as _, + }) + .await; } } } From 81824b1540120533c93b18bd29dc5a290a2fa91d Mon Sep 17 00:00:00 2001 From: Maple Date: Fri, 24 Apr 2026 22:09:02 +0200 Subject: [PATCH 02/22] try fixing matchmaking again --- rnex-core/src/nex/matchmake.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/rnex-core/src/nex/matchmake.rs b/rnex-core/src/nex/matchmake.rs index 085c8a1..e1afa21 100644 --- a/rnex-core/src/nex/matchmake.rs +++ b/rnex-core/src/nex/matchmake.rs @@ -235,10 +235,11 @@ impl ExtendedMatchmakeSession { continue; }*/ + if other_conn.pid != self.session.gathering.host_pid { + continue; + } + for pid in &list_of_connected_pids { - if other_conn.pid == *pid { - continue; - } other_conn .remote .process_notification_event(NotificationEvent { @@ -261,9 +262,6 @@ impl ExtendedMatchmakeSession { continue; } for new_conn_pid in conns.iter().filter_map(Weak::upgrade).map(|c| c.pid) { - if old_conns.pid == new_conn_pid { - continue; - } old_conns .remote .process_notification_event(NotificationEvent { From 09e5b1f92a1738e3a969bb82bed2d883659a88d3 Mon Sep 17 00:00:00 2001 From: Maple Date: Fri, 24 Apr 2026 22:38:25 +0200 Subject: [PATCH 03/22] try fixing matchmaking again really hopefully --- rnex-core/src/nex/matchmake.rs | 7 ++-- rnex-core/src/nex/user.rs | 58 ++++++++++++++++------------------ 2 files changed, 31 insertions(+), 34 deletions(-) diff --git a/rnex-core/src/nex/matchmake.rs b/rnex-core/src/nex/matchmake.rs index e1afa21..dbaf9c0 100644 --- a/rnex-core/src/nex/matchmake.rs +++ b/rnex-core/src/nex/matchmake.rs @@ -234,10 +234,10 @@ impl ExtendedMatchmakeSession { joining_pid == self.session.gathering.owner_pid{ continue; }*/ - + /* if other_conn.pid != self.session.gathering.host_pid { continue; - } + } */ for pid in &list_of_connected_pids { other_conn @@ -258,9 +258,10 @@ impl ExtendedMatchmakeSession { let Some(old_conns) = old_conns.upgrade() else { continue; }; + /* if old_conns.pid != self.session.gathering.host_pid { continue; - } + } */ for new_conn_pid in conns.iter().filter_map(Weak::upgrade).map(|c| c.pid) { old_conns .remote diff --git a/rnex-core/src/nex/user.rs b/rnex-core/src/nex/user.rs index c86ae73..29d5332 100644 --- a/rnex-core/src/nex/user.rs +++ b/rnex-core/src/nex/user.rs @@ -5,15 +5,12 @@ use crate::nex::remote_console::RemoteConsole; use crate::rmc::protocols::matchmake::{ Matchmake, RawMatchmake, RawMatchmakeInfo, RemoteMatchmake, }; -use serde::{Serialize, Deserialize}; -use std::env; -use std::str::FromStr; use crate::rmc::protocols::nat_traversal::{ NatTraversal, RawNatTraversal, RawNatTraversalInfo, RemoteNatTraversal, RemoteNatTraversalConsole, }; -use rnex_core::kerberos::KerberosDateTime; use rnex_core::PID; +use rnex_core::kerberos::KerberosDateTime; use rnex_core::prudp::station_url::StationUrl; use rnex_core::prudp::station_url::UrlOptions::{ Address, NatFiltering, NatMapping, Port, RVConnectionID, @@ -31,17 +28,22 @@ use rnex_core::rmc::structures::any::Any; use rnex_core::rmc::structures::matchmake::{ AutoMatchmakeParam, CreateMatchmakeSessionParam, JoinMatchmakeSessionParam, MatchmakeSession, }; +use serde::{Deserialize, Serialize}; +use std::env; +use std::str::FromStr; use crate::rmc::protocols::notifications::{NotificationEvent, RemoteNotification}; -use log::{info, error}; +use log::{error, info}; use macros::rmc_struct; -use rnex_core::rmc::structures::qbuffer::QBuffer; use rnex_core::prudp::socket_addr::PRUDPSockAddr; +use rnex_core::rmc::protocols::ranking::{ + CompetitionRankingGetParam, CompetitionRankingScoreData, CompetitionRankingScoreInfo, +}; use rnex_core::rmc::response::ErrorCode::{Core_InvalidArgument, RendezVous_AccountExpired}; +use rnex_core::rmc::structures::qbuffer::QBuffer; use rnex_core::rmc::structures::qresult::QResult; +use rnex_core::rmc::structures::ranking::UploadCompetitionData; use std::sync::{Arc, Weak}; -use rnex_core::rmc::protocols::ranking::{CompetitionRankingScoreData, CompetitionRankingGetParam, CompetitionRankingScoreInfo}; -use rnex_core::rmc::structures::ranking::{UploadCompetitionData}; use tokio::sync::{Mutex, RwLock}; define_rmc_proto!( @@ -617,10 +619,7 @@ fn fetch_team_votes(fest_id: u32) -> Result, ErrorCode> { })?; let body = body.trim().trim_start_matches('[').trim_end_matches(']'); - let votes: Result, _> = body - .split(',') - .map(|s| u32::from_str(s.trim())) - .collect(); + let votes: Result, _> = body.split(',').map(|s| u32::from_str(s.trim())).collect(); votes.map_err(|e| { error!("failed to parse votes: {:?}", e); @@ -635,23 +634,19 @@ impl Ranking for User { ) -> Result, ErrorCode> { let fest_id = param.festival_ids.get(0).copied().unwrap_or(0); - let endpoint_results = env::var("RNEX_SPLATOON_RESULTS_GET") - .map_err(|_| { - error!("RNEX_SPLATOON_RESULTS_GET not set"); - ErrorCode::RendezVous_InvalidConfiguration - })?; + let endpoint_results = env::var("RNEX_SPLATOON_RESULTS_GET").map_err(|_| { + error!("RNEX_SPLATOON_RESULTS_GET not set"); + ErrorCode::RendezVous_InvalidConfiguration + })?; let url_results = format!("{}?splatfest_id={}", endpoint_results, fest_id); let response_results = ureq::get(&url_results).call(); let results: Vec = match response_results { - Ok(mut res) => res - .body_mut() - .read_json() - .map_err(|e| { - error!("failed to parse JSON: {:?}", e); - ErrorCode::RendezVous_InvalidConfiguration - })?, + Ok(mut res) => res.body_mut().read_json().map_err(|e| { + error!("failed to parse JSON: {:?}", e); + ErrorCode::RendezVous_InvalidConfiguration + })?, Err(e) => { error!("GET failed: {:?}", e); return Err(ErrorCode::RendezVous_InvalidConfiguration); @@ -661,9 +656,8 @@ impl Ranking for User { let team_votes = fetch_team_votes(fest_id)?; let mut wins = vec![0u32, 0u32]; for r in &results { - if r.team_win == 1 && (r.team_id == 0 || r.team_id == 1) { - wins[r.team_id as usize] += 1; - } + let won_team = r.team_id ^ (!r.team_win); + wins[won_team as usize] += 1; } let score_data: Vec = results @@ -677,7 +671,7 @@ impl Ranking for User { appdata: QBuffer(vec![]), }) .collect(); - + let info = CompetitionRankingScoreInfo { fest_id, score_data, @@ -689,7 +683,10 @@ impl Ranking for User { Ok(vec![info]) } - async fn upload_competition_ranking_score(&self, param: UploadCompetitionData) -> Result { + async fn upload_competition_ranking_score( + &self, + param: UploadCompetitionData, + ) -> Result { info!("fest results for user {:?}:", self.pid); info!("fest id: {:?}", param.splatfest_id); info!("score: {:?}", param.score); @@ -732,8 +729,7 @@ impl Ranking for User { error!("POST borked: {:?}", e); } } - + Ok(true) } } - From 7ff0950617777779b983c6a02fc32427ae35be39 Mon Sep 17 00:00:00 2001 From: Maple Date: Fri, 24 Apr 2026 22:53:12 +0200 Subject: [PATCH 04/22] only let hosts see their own joins and let all other players not see their own joins --- rnex-core/src/nex/matchmake.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/rnex-core/src/nex/matchmake.rs b/rnex-core/src/nex/matchmake.rs index dbaf9c0..1129c76 100644 --- a/rnex-core/src/nex/matchmake.rs +++ b/rnex-core/src/nex/matchmake.rs @@ -240,6 +240,9 @@ impl ExtendedMatchmakeSession { } */ for pid in &list_of_connected_pids { + if other_conn.pid != self.session.gathering.host_pid && other_conn.pid == *pid { + continue; + } other_conn .remote .process_notification_event(NotificationEvent { @@ -258,11 +261,11 @@ impl ExtendedMatchmakeSession { let Some(old_conns) = old_conns.upgrade() else { continue; }; - /* - if old_conns.pid != self.session.gathering.host_pid { - continue; - } */ for new_conn_pid in conns.iter().filter_map(Weak::upgrade).map(|c| c.pid) { + if old_conns.pid != self.session.gathering.host_pid && old_conns.pid == new_conn_pid + { + continue; + } old_conns .remote .process_notification_event(NotificationEvent { From 757ca292b9bea687991496bae49f9c22fc8f5d39 Mon Sep 17 00:00:00 2001 From: Maple Date: Fri, 24 Apr 2026 23:05:53 +0200 Subject: [PATCH 05/22] yet another attempt --- rnex-core/src/nex/matchmake.rs | 36 +++++++++++++++------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/rnex-core/src/nex/matchmake.rs b/rnex-core/src/nex/matchmake.rs index 1129c76..f449ddc 100644 --- a/rnex-core/src/nex/matchmake.rs +++ b/rnex-core/src/nex/matchmake.rs @@ -239,33 +239,29 @@ impl ExtendedMatchmakeSession { continue; } */ - for pid in &list_of_connected_pids { - if other_conn.pid != self.session.gathering.host_pid && other_conn.pid == *pid { - continue; - } - other_conn - .remote - .process_notification_event(NotificationEvent { - pid_source: initiating_pid, - notif_type: 3001, - param_1: self.session.gathering.self_gid as PID, - param_2: *pid, - str_param: join_msg.clone(), - param_3: self.connected_players.len() as _, - }) - .await; - } + // for pid in &list_of_connected_pids { + other_conn + .remote + .process_notification_event(NotificationEvent { + pid_source: initiating_pid, + notif_type: 3001, + param_1: self.session.gathering.self_gid as PID, + param_2: other_conn.pid, + str_param: join_msg.clone(), + param_3: self.connected_players.len() as _, + }) + .await; + // } } for old_conns in &old_particip { let Some(old_conns) = old_conns.upgrade() else { continue; }; + if old_conns.pid != self.session.gathering.host_pid { + continue; + } for new_conn_pid in conns.iter().filter_map(Weak::upgrade).map(|c| c.pid) { - if old_conns.pid != self.session.gathering.host_pid && old_conns.pid == new_conn_pid - { - continue; - } old_conns .remote .process_notification_event(NotificationEvent { From 9fdca492c407faf0fac28a45d90ac8d7505135ab Mon Sep 17 00:00:00 2001 From: Maple Date: Fri, 24 Apr 2026 23:32:47 +0200 Subject: [PATCH 06/22] yet another another attempt --- rnex-core/src/nex/matchmake.rs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/rnex-core/src/nex/matchmake.rs b/rnex-core/src/nex/matchmake.rs index f449ddc..d5bdab4 100644 --- a/rnex-core/src/nex/matchmake.rs +++ b/rnex-core/src/nex/matchmake.rs @@ -246,13 +246,36 @@ impl ExtendedMatchmakeSession { pid_source: initiating_pid, notif_type: 3001, param_1: self.session.gathering.self_gid as PID, - param_2: other_conn.pid, + param_2: *pid, str_param: join_msg.clone(), param_3: self.connected_players.len() as _, }) .await; // } } + for other_connection in conns { + let Some(other_conn) = other_connection.upgrade() else { + continue; + }; + + for old_participant in &old_particip { + let Some(old_particip) = old_participant.upgrade() else { + continue; + }; + + other_conn + .remote + .process_notification_event(NotificationEvent { + pid_source: initiating_pid, + notif_type: 3001, + param_1: self.session.gathering.self_gid as PID, + param_2: old_particip.pid, + str_param: join_msg.clone(), + param_3: self.connected_players.len() as _, + }) + .await; + } + } for old_conns in &old_particip { let Some(old_conns) = old_conns.upgrade() else { From 9352687a4a4671fb1377173b2d141f920a080d7f Mon Sep 17 00:00:00 2001 From: Maple Date: Fri, 24 Apr 2026 23:43:57 +0200 Subject: [PATCH 07/22] fix building --- rnex-core/src/nex/matchmake.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rnex-core/src/nex/matchmake.rs b/rnex-core/src/nex/matchmake.rs index d5bdab4..a1a1f4c 100644 --- a/rnex-core/src/nex/matchmake.rs +++ b/rnex-core/src/nex/matchmake.rs @@ -246,7 +246,7 @@ impl ExtendedMatchmakeSession { pid_source: initiating_pid, notif_type: 3001, param_1: self.session.gathering.self_gid as PID, - param_2: *pid, + param_2: other_conn.pid, str_param: join_msg.clone(), param_3: self.connected_players.len() as _, }) From 40793af5c3fc7742ed0851a8c022426c7529f715 Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 25 Apr 2026 00:06:04 +0200 Subject: [PATCH 08/22] revert mostly back and try less big changes --- rnex-core/src/nex/matchmake.rs | 36 +++++----------------------------- 1 file changed, 5 insertions(+), 31 deletions(-) diff --git a/rnex-core/src/nex/matchmake.rs b/rnex-core/src/nex/matchmake.rs index a1a1f4c..0a18f74 100644 --- a/rnex-core/src/nex/matchmake.rs +++ b/rnex-core/src/nex/matchmake.rs @@ -234,42 +234,15 @@ impl ExtendedMatchmakeSession { joining_pid == self.session.gathering.owner_pid{ continue; }*/ - /* - if other_conn.pid != self.session.gathering.host_pid { - continue; - } */ - - // for pid in &list_of_connected_pids { - other_conn - .remote - .process_notification_event(NotificationEvent { - pid_source: initiating_pid, - notif_type: 3001, - param_1: self.session.gathering.self_gid as PID, - param_2: other_conn.pid, - str_param: join_msg.clone(), - param_3: self.connected_players.len() as _, - }) - .await; - // } - } - for other_connection in conns { - let Some(other_conn) = other_connection.upgrade() else { - continue; - }; - - for old_participant in &old_particip { - let Some(old_particip) = old_participant.upgrade() else { - continue; - }; + for pid in &list_of_connected_pids { other_conn .remote .process_notification_event(NotificationEvent { pid_source: initiating_pid, notif_type: 3001, param_1: self.session.gathering.self_gid as PID, - param_2: old_particip.pid, + param_2: *pid, str_param: join_msg.clone(), param_3: self.connected_players.len() as _, }) @@ -281,9 +254,9 @@ impl ExtendedMatchmakeSession { let Some(old_conns) = old_conns.upgrade() else { continue; }; - if old_conns.pid != self.session.gathering.host_pid { + /*if old_conns.pid != self.session.gathering.host_pid { continue; - } + }*/ for new_conn_pid in conns.iter().filter_map(Weak::upgrade).map(|c| c.pid) { old_conns .remote @@ -299,6 +272,7 @@ impl ExtendedMatchmakeSession { } } } + pub fn has_active_players(&self) -> bool { self.connected_players .iter() From 731fa91b72d5316266bc4513020685e854bdf4af Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 25 Apr 2026 10:52:40 +0200 Subject: [PATCH 09/22] fix potential crash bug --- rnex-core/src/nex/user.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rnex-core/src/nex/user.rs b/rnex-core/src/nex/user.rs index 29d5332..57c36d8 100644 --- a/rnex-core/src/nex/user.rs +++ b/rnex-core/src/nex/user.rs @@ -657,7 +657,9 @@ impl Ranking for User { let mut wins = vec![0u32, 0u32]; for r in &results { let won_team = r.team_id ^ (!r.team_win); - wins[won_team as usize] += 1; + if let Some(team) = wins.get_mut(won_team as usize) { + *team += 1 + }; } let score_data: Vec = results From 58c9e43fa3e2352822e2d470b979526ddd673e3f Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 25 Apr 2026 12:59:49 +0200 Subject: [PATCH 10/22] add fragments to v0 outgoing packets --- prudpv0/src/server.rs | 85 +++++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 40 deletions(-) diff --git a/prudpv0/src/server.rs b/prudpv0/src/server.rs index 34c7647..a336abb 100644 --- a/prudpv0/src/server.rs +++ b/prudpv0/src/server.rs @@ -106,50 +106,55 @@ impl Server { .expect("packet malformed in creation"), );*/ let mut inner = conn.inner.lock().await; - let seq = inner.server_packet_counter; - let packet = new_data_packet( - NEED_ACK | RELIABLE, - self.param.virtual_port, - conn.addr.virtual_port, - data, - inner.server_packet_counter, - conn.session_id, - 0, - &mut inner.crypto_instance, - &self.crypto, - ); - inner.server_packet_counter += 1; + let pieces = data.chunks(1000); + let max_piece = pieces.len() - 1; + let mut frag_num = 1; + for (i, piece) in pieces.enumerate() { + let seq = inner.server_packet_counter; + let packet = new_data_packet( + NEED_ACK | RELIABLE, + (&self).param.virtual_port, + conn.addr.virtual_port, + piece, + inner.server_packet_counter, + conn.session_id, + if i == max_piece { 0 } else { frag_num }, + &mut inner.crypto_instance, + &(&self).crypto, + ); + inner.server_packet_counter += 1; - let packet = Arc::new(packet); - let packet_ref = Arc::downgrade(&packet); + let packet = Arc::new(packet); + let packet_ref = Arc::downgrade(&packet); - inner.unacknowledged_packets.insert(seq, packet); + inner.unacknowledged_packets.insert(seq, packet); + let conn = Arc::downgrade(&conn); + let this = Arc::downgrade(&self); + + spawn(async move { + for n in 0..5 { + let Some(data) = packet_ref.upgrade() else { + return; + }; + let Some(conn) = conn.upgrade() else { + return; + }; + let Some(this) = this.upgrade() else { + return; + }; + info!("send attempt {}", n); + + self.socket + .send_to(&data, conn.addr.regular_socket_addr) + .await; + + break; + } + }); + frag_num += 1; + } drop(inner); - - let conn = Arc::downgrade(&conn); - let this = Arc::downgrade(&self); - - spawn(async move { - for n in 0..5 { - let Some(data) = packet_ref.upgrade() else { - return; - }; - let Some(conn) = conn.upgrade() else { - return; - }; - let Some(this) = this.upgrade() else { - return; - }; - info!("send attempt {}", n); - - self.socket - .send_to(&data, conn.addr.regular_socket_addr) - .await; - - break; - } - }); } async fn connection_thread( self: Arc, From 20fc294a36a0f276c4a0b466412a89c2116bf37e Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 25 Apr 2026 14:15:42 +0200 Subject: [PATCH 11/22] implement friendships --- rnex-core/src/executables/friends_backend.rs | 11 +- rnex-core/src/nex/friends_handler.rs | 136 ++++++++++++++++-- rnex-core/src/rmc/protocols/friends.rs | 6 +- rnex-core/src/rmc/protocols/mod.rs | 1 + .../rmc/protocols/nintendo_notification.rs | 39 +++++ rnex-core/src/rmc/structures/any.rs | 21 ++- rnex-core/src/rmc/structures/mod.rs | 3 + 7 files changed, 196 insertions(+), 21 deletions(-) create mode 100644 rnex-core/src/rmc/protocols/nintendo_notification.rs diff --git a/rnex-core/src/executables/friends_backend.rs b/rnex-core/src/executables/friends_backend.rs index 74983f7..6dceda1 100644 --- a/rnex-core/src/executables/friends_backend.rs +++ b/rnex-core/src/executables/friends_backend.rs @@ -9,10 +9,12 @@ use tokio::net::TcpListener; use crate::{ executables::common::{OWN_IP_PRIVATE, SERVER_PORT, new_simple_backend}, - nex::friends_handler::{FriendsGuest, FriendsManager, FriendsUser}, + nex::friends_handler::{FriendsGuest, FriendsManager, FriendsUser, RemoteFriendsUser}, reggie::UnitPacketRead, rmc::{ - protocols::{RmcCallable, new_rmc_gateway_connection}, + protocols::{ + RmcCallable, RmcPureRemoteObject, friends::RemoteFriends, new_rmc_gateway_connection, + }, structures::RmcSerialize, }, rnex_proxy_common::ConnectionInitData, @@ -21,6 +23,7 @@ use crate::{ pub async fn start_friends_backend() { let fm = Arc::new(FriendsManager { cid_counter: AtomicU32::new(1), + users: Default::default(), }); let listen = TcpListener::bind(SocketAddrV4::new(*OWN_IP_PRIVATE, *SERVER_PORT)) .await @@ -53,6 +56,10 @@ pub async fn start_friends_backend() { fm, addr: c.prudpsock_addr, pid: c.pid, + data: Default::default(), + current_friends: Default::default(), + this: this.clone(), + remote: RemoteFriendsUser::new(r), }) }); } else { diff --git a/rnex-core/src/nex/friends_handler.rs b/rnex-core/src/nex/friends_handler.rs index 42e5c71..2d9c2a8 100644 --- a/rnex-core/src/nex/friends_handler.rs +++ b/rnex-core/src/nex/friends_handler.rs @@ -1,4 +1,6 @@ use std::io::{Cursor, Write}; +use std::ops::Deref; +use std::sync::Weak; use std::sync::{Arc, atomic::AtomicU32}; use bytemuck::bytes_of; @@ -9,6 +11,10 @@ use rnex_core::rmc::protocols::account_management::{ AccountManagement, RawAccountManagement, RawAccountManagementInfo, RemoteAccountManagement, }; use rnex_core::rmc::protocols::friends::{Friends, RawFriends, RawFriendsInfo, RemoteFriends}; +use rnex_core::rmc::protocols::nintendo_notification::{ + NintendoNotification, RawNintendoNotification, RawNintendoNotificationInfo, + RemoteNintendoNotification, +}; use rnex_core::rmc::protocols::secure::{RawSecure, RawSecureInfo, RemoteSecure, Secure}; use rnex_core::{ define_rmc_proto, @@ -25,12 +31,15 @@ use rnex_core::{ }, }; use std::sync::atomic::Ordering::Relaxed; +use tokio::sync::RwLock; use rnex_core::rmc::protocols::friends::{GameKey, MiiV2, PrincipalBasicInfo}; use rnex_core::PID; +use crate::nex::user; use crate::rmc::protocols::account_management::NintendoCreateAccountData; +use crate::rmc::protocols::nintendo_notification::NintendoNotificationEvent; use rnex_core::rmc::structures::RmcSerialize; define_rmc_proto!( @@ -39,17 +48,32 @@ define_rmc_proto!( Friends } ); +define_rmc_proto!( + proto FriendRemote{ + NintendoNotification + } +); define_rmc_proto!( proto FriendsGuest{ Secure, AccountManagement } ); + +pub struct UserData { + info: NNAInfo, + presence: NintendoPresenceV2, +} + #[rmc_struct(FriendsUser)] pub struct FriendsUser { pub fm: Arc, pub addr: PRUDPSockAddr, pub pid: PID, + pub data: RwLock>, + pub current_friends: RwLock>, + pub this: Weak, + pub remote: RemoteFriendRemote, } #[rmc_struct(FriendsGuest)] @@ -60,6 +84,7 @@ pub struct FriendsGuest { pub struct FriendsManager { pub cid_counter: AtomicU32, + pub users: RwLock>>, } impl FriendsManager { @@ -68,11 +93,26 @@ impl FriendsManager { } } +pub fn friend_info_from_user(data: &UserData) -> FriendInfo { + FriendInfo { + nna_info: data.info.clone(), + presence: data.presence.clone(), + comment: Comment { + unk: 0, + message: "litterally everyone is friends here =w=".to_string(), + last_changed: KerberosDateTime::now(), + }, + became_friends: KerberosDateTime::now(), + last_online: KerberosDateTime::now(), + unk: 0, + } +} + impl Friends for FriendsUser { async fn update_and_get_all_information( &self, - _info: NNAInfo, - _presence: NintendoPresenceV2, + info: NNAInfo, + presence: NintendoPresenceV2, _date_time: KerberosDateTime, ) -> Result< ( @@ -88,17 +128,15 @@ impl Friends for FriendsUser { ), ErrorCode, > { - Ok(( - PrincipalPreference { - block_friend_request: false, - show_online: false, - show_playing_title: false, - }, - Comment { - last_changed: KerberosDateTime::now(), - message: "".to_string(), - unk: 0, - }, + let mut data = self.data.write().await; + *data = Some(UserData { info, presence }); + let self_fr_info = friend_info_from_user(data.as_ref().unwrap()); + let Ok(any_self_fr_info) = Any::new(&self_fr_info) else { + return Err(ErrorCode::RendezVous_ControlScriptFailure); + }; + drop(data); + + let mut fr_list = vec![FriendInfo { became_friends: KerberosDateTime::now(), comment: Comment { @@ -144,7 +182,51 @@ impl Friends for FriendsUser { unk7: 0 }, unk: 0 - }], + }]; + + let users = self.fm.users.read().await; + let mut curr_friends = self.current_friends.write().await; + for u in users.deref().iter().filter_map(|u| u.upgrade()) { + let data = u.data.read().await; + let Some(data) = data.as_ref() else { + continue; + }; + + let mut fr = u.current_friends.write().await; + if !fr.contains(&self.pid) { + fr.push(self.pid); + u.remote + .process_nintendo_notification_event_1(NintendoNotificationEvent { + event_type: 30, + sender: self.pid, + data: any_self_fr_info.clone(), + }) + .await; + } + drop(fr); + + fr_list.push(friend_info_from_user(&data)); + curr_friends.push(u.pid); + } + drop(curr_friends); + drop(users); + + let mut users = self.fm.users.write().await; + users.push(self.this.clone()); + drop(users); + + Ok(( + PrincipalPreference { + block_friend_request: false, + show_online: false, + show_playing_title: false, + }, + Comment { + last_changed: KerberosDateTime::now(), + message: "".to_string(), + unk: 0, + }, + fr_list, vec![], vec![], vec![], @@ -154,6 +236,32 @@ impl Friends for FriendsUser { )) } + async fn update_presence(&self, presence: NintendoPresenceV2) -> Result<(), ErrorCode> { + let mut data = self.data.write().await; + let Some(data) = data.as_mut() else { + return Err(ErrorCode::RendezVous_PermissionDenied); + }; + data.presence = presence; + let Ok(any_self_fr_info) = Any::new(&data.presence) else { + return Err(ErrorCode::RendezVous_ControlScriptFailure); + }; + drop(data); + + let users = self.fm.users.read().await; + for u in users.deref().iter().filter_map(|u| u.upgrade()) { + u.remote + .process_nintendo_notification_event_2(NintendoNotificationEvent { + event_type: 24, + sender: self.pid, + data: any_self_fr_info.clone(), + }) + .await; + } + drop(users); + + Ok(()) + } + async fn check_setting_status(&self) -> Result { Ok(0xFF) } diff --git a/rnex-core/src/rmc/protocols/friends.rs b/rnex-core/src/rmc/protocols/friends.rs index 3f6138f..fb179ce 100644 --- a/rnex-core/src/rmc/protocols/friends.rs +++ b/rnex-core/src/rmc/protocols/friends.rs @@ -29,14 +29,14 @@ pub struct NNAInfo { pub unk2: u8, } -#[derive(RmcSerialize)] +#[derive(RmcSerialize, Clone, Copy, Debug)] #[rmc_struct(0)] pub struct GameKey { pub tid: u64, pub version: u16, } -#[derive(RmcSerialize)] +#[derive(RmcSerialize, Clone, Debug)] #[rmc_struct(0)] pub struct NintendoPresenceV2 { pub changed_flags: u32, @@ -143,6 +143,8 @@ pub trait Friends { ), ErrorCode, >; + #[method_id(13)] + async fn update_presence(&self, presence: NintendoPresenceV2) -> Result<(), ErrorCode>; #[method_id(19)] async fn check_setting_status(&self) -> Result; } diff --git a/rnex-core/src/rmc/protocols/mod.rs b/rnex-core/src/rmc/protocols/mod.rs index 8feb2f3..eed0597 100644 --- a/rnex-core/src/rmc/protocols/mod.rs +++ b/rnex-core/src/rmc/protocols/mod.rs @@ -7,6 +7,7 @@ pub mod matchmake; pub mod matchmake_ext; pub mod matchmake_extension; pub mod nat_traversal; +pub mod nintendo_notification; pub mod notifications; pub mod ranking; pub mod secure; diff --git a/rnex-core/src/rmc/protocols/nintendo_notification.rs b/rnex-core/src/rmc/protocols/nintendo_notification.rs new file mode 100644 index 0000000..f7503fd --- /dev/null +++ b/rnex-core/src/rmc/protocols/nintendo_notification.rs @@ -0,0 +1,39 @@ +use macros::{RmcSerialize, method_id, rmc_proto}; + +use rnex_core::PID; +use rnex_core::rmc::structures::any::Any; + +#[derive(RmcSerialize)] +#[rmc_struct(0)] +pub struct NintendoNotificationEvent { + pub event_type: u32, + pub sender: PID, + pub data: Any, +} + +#[derive(RmcSerialize)] +#[rmc_struct(0)] +pub struct NintendoNotificationEventGeneral { + pub param1: u32, + pub param2: u64, + pub param3: u64, + pub str_param: String, +} + +#[derive(RmcSerialize)] +#[rmc_struct(0)] +pub struct NintendoNotificationEventProfile { + pub region: u8, + pub country: u8, + pub area: u8, + pub language: u8, + pub platform: u8, +} + +#[rmc_proto(3, NoReturn)] +pub trait NintendoNotification { + #[method_id(1)] + async fn process_nintendo_notification_event_1(&self, notif: NintendoNotificationEvent); + #[method_id(2)] + async fn process_nintendo_notification_event_2(&self, notif: NintendoNotificationEvent); +} diff --git a/rnex-core/src/rmc/structures/any.rs b/rnex-core/src/rmc/structures/any.rs index c4dc2ce..45ab453 100644 --- a/rnex-core/src/rmc/structures/any.rs +++ b/rnex-core/src/rmc/structures/any.rs @@ -1,8 +1,8 @@ use rnex_core::rmc::structures::{Result, RmcSerialize}; -use std::io::{Read, Write}; +use std::io::{Cursor, Read, Write}; use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; -#[derive(Debug, Default)] +#[derive(Debug, Default, Clone)] pub struct Any { pub name: String, pub data: Vec, @@ -14,7 +14,7 @@ impl RmcSerialize for Any { let u32_len = self.data.len() as u32; - u32_len.serialize(writer)?; + (u32_len + 4).serialize(writer)?; u32_len.serialize(writer)?; self.data.serialize(writer)?; @@ -35,3 +35,18 @@ impl RmcSerialize for Any { Ok(Any { name, data }) } } + +impl Any { + pub fn try_get(&self) -> Option> { + if self.name != T::name() { + return None; + } + return Some(T::deserialize(&mut Cursor::new(&self.data[..]))); + } + pub fn new(val: &T) -> Result { + return Ok(Self { + name: T::name().to_owned(), + data: val.to_data()?, + }); + } +} diff --git a/rnex-core/src/rmc/structures/mod.rs b/rnex-core/src/rmc/structures/mod.rs index 996cc4b..99bef0c 100644 --- a/rnex-core/src/rmc/structures/mod.rs +++ b/rnex-core/src/rmc/structures/mod.rs @@ -61,6 +61,9 @@ pub trait RmcSerialize { Ok(data) } + fn name() -> &'static str { + "NoNameSpecified" + } } impl RmcSerialize for () { From 0d026373db1db1a0f355ee348700a291e8b52715 Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 25 Apr 2026 14:24:33 +0200 Subject: [PATCH 12/22] fix compile error --- macros/src/lib.rs | 12 ++++++++++-- prudpv0/src/server.rs | 2 +- rnex-core/src/executables/friends_backend.rs | 6 ++++-- rnex-core/src/nex/friends_handler.rs | 5 ++--- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/macros/src/lib.rs b/macros/src/lib.rs index d0fc909..432fc03 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -10,8 +10,8 @@ use syn::parse::{Parse, ParseStream}; use syn::punctuated::Punctuated; use syn::spanned::Spanned; use syn::{ - parse_macro_input, Attribute, Data, DataStruct, DeriveInput, Fields, FnArg, LitInt, Pat, Token, - TraitItem, + parse_macro_input, Attribute, Data, DataStruct, DeriveInput, Fields, FnArg, Lit, LitInt, + LitStr, Pat, Token, TraitItem, }; struct ProtoInputParams { @@ -400,6 +400,10 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream { // generate base data + let str_name = Lit::Str(LitStr::new( + &derive_input.ident.to_string(), + derive_input.ident.span(), + )); let ident = derive_input.ident; let tokens = quote! { @@ -414,6 +418,10 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream { } #write_size + + fn name() -> &'static str{ + #str_name + } } }; diff --git a/prudpv0/src/server.rs b/prudpv0/src/server.rs index a336abb..d7a6dcc 100644 --- a/prudpv0/src/server.rs +++ b/prudpv0/src/server.rs @@ -145,7 +145,7 @@ impl Server { }; info!("send attempt {}", n); - self.socket + this.socket .send_to(&data, conn.addr.regular_socket_addr) .await; diff --git a/rnex-core/src/executables/friends_backend.rs b/rnex-core/src/executables/friends_backend.rs index 6dceda1..5dfcf02 100644 --- a/rnex-core/src/executables/friends_backend.rs +++ b/rnex-core/src/executables/friends_backend.rs @@ -9,7 +9,9 @@ use tokio::net::TcpListener; use crate::{ executables::common::{OWN_IP_PRIVATE, SERVER_PORT, new_simple_backend}, - nex::friends_handler::{FriendsGuest, FriendsManager, FriendsUser, RemoteFriendsUser}, + nex::friends_handler::{ + FriendsGuest, FriendsManager, FriendsUser, RemoteFriendRemote, RemoteFriendsUser, + }, reggie::UnitPacketRead, rmc::{ protocols::{ @@ -59,7 +61,7 @@ pub async fn start_friends_backend() { data: Default::default(), current_friends: Default::default(), this: this.clone(), - remote: RemoteFriendsUser::new(r), + remote: RemoteFriendRemote::new(r), }) }); } else { diff --git a/rnex-core/src/nex/friends_handler.rs b/rnex-core/src/nex/friends_handler.rs index 2d9c2a8..adab2b9 100644 --- a/rnex-core/src/nex/friends_handler.rs +++ b/rnex-core/src/nex/friends_handler.rs @@ -37,9 +37,8 @@ use rnex_core::rmc::protocols::friends::{GameKey, MiiV2, PrincipalBasicInfo}; use rnex_core::PID; -use crate::nex::user; -use crate::rmc::protocols::account_management::NintendoCreateAccountData; -use crate::rmc::protocols::nintendo_notification::NintendoNotificationEvent; +use rnex_core::rmc::protocols::account_management::NintendoCreateAccountData; +use rnex_core::rmc::protocols::nintendo_notification::NintendoNotificationEvent; use rnex_core::rmc::structures::RmcSerialize; define_rmc_proto!( From 02c08e6c759e43e746662761950078fa3bda6db1 Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 25 Apr 2026 15:06:00 +0200 Subject: [PATCH 13/22] add debugging --- rnex-core/src/nex/friends_handler.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/rnex-core/src/nex/friends_handler.rs b/rnex-core/src/nex/friends_handler.rs index adab2b9..64b359c 100644 --- a/rnex-core/src/nex/friends_handler.rs +++ b/rnex-core/src/nex/friends_handler.rs @@ -127,6 +127,7 @@ impl Friends for FriendsUser { ), ErrorCode, > { + println!("updating own data"); let mut data = self.data.write().await; *data = Some(UserData { info, presence }); let self_fr_info = friend_info_from_user(data.as_ref().unwrap()); @@ -183,8 +184,10 @@ impl Friends for FriendsUser { unk: 0 }]; + println!("acquiring user and current friends locks"); let users = self.fm.users.read().await; let mut curr_friends = self.current_friends.write().await; + println!("started summing users"); for u in users.deref().iter().filter_map(|u| u.upgrade()) { let data = u.data.read().await; let Some(data) = data.as_ref() else { @@ -207,13 +210,16 @@ impl Friends for FriendsUser { fr_list.push(friend_info_from_user(&data)); curr_friends.push(u.pid); } + println!("finished summing users"); drop(curr_friends); drop(users); + println!("adding self to users"); let mut users = self.fm.users.write().await; users.push(self.this.clone()); drop(users); + println!("done..."); Ok(( PrincipalPreference { block_friend_request: false, @@ -237,11 +243,11 @@ impl Friends for FriendsUser { async fn update_presence(&self, presence: NintendoPresenceV2) -> Result<(), ErrorCode> { let mut data = self.data.write().await; - let Some(data) = data.as_mut() else { + let Some(inner_data) = data.as_mut() else { return Err(ErrorCode::RendezVous_PermissionDenied); }; - data.presence = presence; - let Ok(any_self_fr_info) = Any::new(&data.presence) else { + inner_data.presence = presence; + let Ok(any_self_fr_info) = Any::new(&inner_data.presence) else { return Err(ErrorCode::RendezVous_ControlScriptFailure); }; drop(data); From aaa530341d6748dae2cc77a676c2c8d379d8e23b Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 25 Apr 2026 15:23:53 +0200 Subject: [PATCH 14/22] minimize the time we hold locks for and add sleep --- prudpv0/src/server.rs | 1 + rnex-core/src/nex/friends_handler.rs | 37 +++++++++++++++++----------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/prudpv0/src/server.rs b/prudpv0/src/server.rs index d7a6dcc..9a32bc7 100644 --- a/prudpv0/src/server.rs +++ b/prudpv0/src/server.rs @@ -153,6 +153,7 @@ impl Server { } }); frag_num += 1; + sleep(Duration::from_millis(16)).await; } drop(inner); } diff --git a/rnex-core/src/nex/friends_handler.rs b/rnex-core/src/nex/friends_handler.rs index 64b359c..1a0b499 100644 --- a/rnex-core/src/nex/friends_handler.rs +++ b/rnex-core/src/nex/friends_handler.rs @@ -31,6 +31,7 @@ use rnex_core::{ }, }; use std::sync::atomic::Ordering::Relaxed; +use tokio::spawn; use tokio::sync::RwLock; use rnex_core::rmc::protocols::friends::{GameKey, MiiV2, PrincipalBasicInfo}; @@ -186,32 +187,40 @@ impl Friends for FriendsUser { println!("acquiring user and current friends locks"); let users = self.fm.users.read().await; - let mut curr_friends = self.current_friends.write().await; println!("started summing users"); for u in users.deref().iter().filter_map(|u| u.upgrade()) { let data = u.data.read().await; - let Some(data) = data.as_ref() else { + let Some(inner_data) = data.as_ref() else { continue; }; + fr_list.push(friend_info_from_user(&inner_data)); + drop(data); + + let mut curr_friends = self.current_friends.write().await; + curr_friends.push(u.pid); + drop(curr_friends); let mut fr = u.current_friends.write().await; if !fr.contains(&self.pid) { fr.push(self.pid); - u.remote - .process_nintendo_notification_event_1(NintendoNotificationEvent { - event_type: 30, - sender: self.pid, - data: any_self_fr_info.clone(), - }) - .await; + drop(fr); + let data = any_self_fr_info.clone(); + let u = u.clone(); + let sender = self.pid; + spawn(async move { + u.remote + .process_nintendo_notification_event_1(NintendoNotificationEvent { + event_type: 30, + sender, + data, + }) + .await; + }); + } else { + drop(fr); } - drop(fr); - - fr_list.push(friend_info_from_user(&data)); - curr_friends.push(u.pid); } println!("finished summing users"); - drop(curr_friends); drop(users); println!("adding self to users"); From f9ce137c046a4983b0c987825165fdb2d68efe6f Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 25 Apr 2026 15:41:58 +0200 Subject: [PATCH 15/22] sleep inside the packet send task instead of outside --- prudpv0/src/server.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prudpv0/src/server.rs b/prudpv0/src/server.rs index 9a32bc7..022f6da 100644 --- a/prudpv0/src/server.rs +++ b/prudpv0/src/server.rs @@ -133,6 +133,7 @@ impl Server { let this = Arc::downgrade(&self); spawn(async move { + sleep(Duration::from_millis(i as u64 * 16)).await; for n in 0..5 { let Some(data) = packet_ref.upgrade() else { return; @@ -153,7 +154,6 @@ impl Server { } }); frag_num += 1; - sleep(Duration::from_millis(16)).await; } drop(inner); } From 2c08e35c36c0a910f4429bc3901ad3ac8b4a6d18 Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 25 Apr 2026 16:40:54 +0200 Subject: [PATCH 16/22] make fragment size smaller --- prudpv0/src/server.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prudpv0/src/server.rs b/prudpv0/src/server.rs index 022f6da..899bbd6 100644 --- a/prudpv0/src/server.rs +++ b/prudpv0/src/server.rs @@ -106,7 +106,7 @@ impl Server { .expect("packet malformed in creation"), );*/ let mut inner = conn.inner.lock().await; - let pieces = data.chunks(1000); + let pieces = data.chunks(700); let max_piece = pieces.len() - 1; let mut frag_num = 1; for (i, piece) in pieces.enumerate() { From 666a0b1ad7c6f202e1b94c3959d79d4e9159860d Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 25 Apr 2026 16:56:55 +0200 Subject: [PATCH 17/22] fix nintendo notifications --- rnex-core/src/rmc/protocols/nintendo_notification.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rnex-core/src/rmc/protocols/nintendo_notification.rs b/rnex-core/src/rmc/protocols/nintendo_notification.rs index f7503fd..ae31467 100644 --- a/rnex-core/src/rmc/protocols/nintendo_notification.rs +++ b/rnex-core/src/rmc/protocols/nintendo_notification.rs @@ -30,7 +30,7 @@ pub struct NintendoNotificationEventProfile { pub platform: u8, } -#[rmc_proto(3, NoReturn)] +#[rmc_proto(100, NoReturn)] pub trait NintendoNotification { #[method_id(1)] async fn process_nintendo_notification_event_1(&self, notif: NintendoNotificationEvent); From 51e7c63d667e80ee596b1dfab13c2303edcd4167 Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 25 Apr 2026 17:24:28 +0200 Subject: [PATCH 18/22] add delete persistent notif --- rnex-core/src/nex/friends_handler.rs | 9 ++++++++- rnex-core/src/rmc/protocols/friends.rs | 7 +++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/rnex-core/src/nex/friends_handler.rs b/rnex-core/src/nex/friends_handler.rs index 1a0b499..88190b2 100644 --- a/rnex-core/src/nex/friends_handler.rs +++ b/rnex-core/src/nex/friends_handler.rs @@ -99,7 +99,7 @@ pub fn friend_info_from_user(data: &UserData) -> FriendInfo { presence: data.presence.clone(), comment: Comment { unk: 0, - message: "litterally everyone is friends here =w=".to_string(), + message: "haii =w=".to_string(), last_changed: KerberosDateTime::now(), }, became_friends: KerberosDateTime::now(), @@ -276,6 +276,13 @@ impl Friends for FriendsUser { Ok(()) } + async fn delete_persistent_notification( + &self, + notifs: Vec, + ) -> Result<(), ErrorCode> { + Ok(()) + } + async fn check_setting_status(&self) -> Result { Ok(0xFF) } diff --git a/rnex-core/src/rmc/protocols/friends.rs b/rnex-core/src/rmc/protocols/friends.rs index fb179ce..b575c08 100644 --- a/rnex-core/src/rmc/protocols/friends.rs +++ b/rnex-core/src/rmc/protocols/friends.rs @@ -2,6 +2,8 @@ use macros::{RmcSerialize, method_id, rmc_proto}; use rnex_core::{kerberos::KerberosDateTime, rmc::response::ErrorCode}; +use crate::rmc::structures::rmc_struct; + #[derive(RmcSerialize, Debug, Clone)] #[rmc_struct(0)] pub struct MiiV2 { @@ -145,6 +147,11 @@ pub trait Friends { >; #[method_id(13)] async fn update_presence(&self, presence: NintendoPresenceV2) -> Result<(), ErrorCode>; + #[method_id(18)] + async fn delete_persistent_notification( + &self, + notifs: Vec, + ) -> Result<(), ErrorCode>; #[method_id(19)] async fn check_setting_status(&self) -> Result; } From 3c8ba491ddf2864634a5c84df685d2e7938254dc Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 25 Apr 2026 18:40:32 +0200 Subject: [PATCH 19/22] add data --- rnex-core/src/nex/friends_handler.rs | 3 +++ rnex-core/src/rmc/protocols/friends.rs | 4 +++- rnex-core/src/rmc/structures/data.rs | 5 +++++ rnex-core/src/rmc/structures/mod.rs | 1 + 4 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 rnex-core/src/rmc/structures/data.rs diff --git a/rnex-core/src/nex/friends_handler.rs b/rnex-core/src/nex/friends_handler.rs index 88190b2..b7f44e8 100644 --- a/rnex-core/src/nex/friends_handler.rs +++ b/rnex-core/src/nex/friends_handler.rs @@ -42,6 +42,8 @@ use rnex_core::rmc::protocols::account_management::NintendoCreateAccountData; use rnex_core::rmc::protocols::nintendo_notification::NintendoNotificationEvent; use rnex_core::rmc::structures::RmcSerialize; +use crate::rmc::structures::data::Data; + define_rmc_proto!( proto FriendsUser{ Secure, @@ -95,6 +97,7 @@ impl FriendsManager { pub fn friend_info_from_user(data: &UserData) -> FriendInfo { FriendInfo { + data: Data {}, nna_info: data.info.clone(), presence: data.presence.clone(), comment: Comment { diff --git a/rnex-core/src/rmc/protocols/friends.rs b/rnex-core/src/rmc/protocols/friends.rs index b575c08..766797f 100644 --- a/rnex-core/src/rmc/protocols/friends.rs +++ b/rnex-core/src/rmc/protocols/friends.rs @@ -2,7 +2,7 @@ use macros::{RmcSerialize, method_id, rmc_proto}; use rnex_core::{kerberos::KerberosDateTime, rmc::response::ErrorCode}; -use crate::rmc::structures::rmc_struct; +use crate::rmc::structures::{data::Data, rmc_struct}; #[derive(RmcSerialize, Debug, Clone)] #[rmc_struct(0)] @@ -76,6 +76,8 @@ pub struct Comment { #[derive(RmcSerialize)] #[rmc_struct(0)] pub struct FriendInfo { + #[extends] + pub data: Data, pub nna_info: NNAInfo, pub presence: NintendoPresenceV2, pub comment: Comment, diff --git a/rnex-core/src/rmc/structures/data.rs b/rnex-core/src/rmc/structures/data.rs new file mode 100644 index 0000000..0350c96 --- /dev/null +++ b/rnex-core/src/rmc/structures/data.rs @@ -0,0 +1,5 @@ +use macros::RmcSerialize; + +#[derive(RmcSerialize)] +#[rmc_struct(0)] +pub struct Data {} diff --git a/rnex-core/src/rmc/structures/mod.rs b/rnex-core/src/rmc/structures/mod.rs index 99bef0c..35dce08 100644 --- a/rnex-core/src/rmc/structures/mod.rs +++ b/rnex-core/src/rmc/structures/mod.rs @@ -26,6 +26,7 @@ pub type Result = std::result::Result; pub mod any; pub mod buffer; pub mod connection_data; +pub mod data; pub mod helpers; pub mod list; pub mod matchmake; From 3e8b96c82008bfe9dcc0f7c2e7b367a23119d6c5 Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 25 Apr 2026 18:49:18 +0200 Subject: [PATCH 20/22] fix build error --- rnex-core/src/nex/friends_handler.rs | 3 ++- rnex-core/src/rmc/protocols/friends.rs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/rnex-core/src/nex/friends_handler.rs b/rnex-core/src/nex/friends_handler.rs index b7f44e8..08cca05 100644 --- a/rnex-core/src/nex/friends_handler.rs +++ b/rnex-core/src/nex/friends_handler.rs @@ -42,7 +42,7 @@ use rnex_core::rmc::protocols::account_management::NintendoCreateAccountData; use rnex_core::rmc::protocols::nintendo_notification::NintendoNotificationEvent; use rnex_core::rmc::structures::RmcSerialize; -use crate::rmc::structures::data::Data; +use rnex_core::rmc::structures::data::Data; define_rmc_proto!( proto FriendsUser{ @@ -142,6 +142,7 @@ impl Friends for FriendsUser { let mut fr_list = vec![FriendInfo { + data: Data{}, became_friends: KerberosDateTime::now(), comment: Comment { last_changed: KerberosDateTime::now(), diff --git a/rnex-core/src/rmc/protocols/friends.rs b/rnex-core/src/rmc/protocols/friends.rs index 766797f..fa32120 100644 --- a/rnex-core/src/rmc/protocols/friends.rs +++ b/rnex-core/src/rmc/protocols/friends.rs @@ -2,7 +2,7 @@ use macros::{RmcSerialize, method_id, rmc_proto}; use rnex_core::{kerberos::KerberosDateTime, rmc::response::ErrorCode}; -use crate::rmc::structures::{data::Data, rmc_struct}; +use rnex_core::rmc::structures::{data::Data, rmc_struct}; #[derive(RmcSerialize, Debug, Clone)] #[rmc_struct(0)] From 9d89bc56e02f963fe379af8e622490dfb972ff53 Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 25 Apr 2026 19:15:23 +0200 Subject: [PATCH 21/22] add data to structs which were missing it --- rnex-core/src/nex/friends_handler.rs | 98 ++++++++++++++------------ rnex-core/src/rmc/protocols/friends.rs | 22 ++++++ rnex-core/src/rmc/structures/data.rs | 2 +- 3 files changed, 76 insertions(+), 46 deletions(-) diff --git a/rnex-core/src/nex/friends_handler.rs b/rnex-core/src/nex/friends_handler.rs index 08cca05..941b747 100644 --- a/rnex-core/src/nex/friends_handler.rs +++ b/rnex-core/src/nex/friends_handler.rs @@ -101,6 +101,7 @@ pub fn friend_info_from_user(data: &UserData) -> FriendInfo { nna_info: data.info.clone(), presence: data.presence.clone(), comment: Comment { + data: Data {}, unk: 0, message: "haii =w=".to_string(), last_changed: KerberosDateTime::now(), @@ -140,54 +141,59 @@ impl Friends for FriendsUser { }; drop(data); - let mut fr_list = - vec![FriendInfo { + let mut fr_list = vec![FriendInfo { + data: Data{}, + became_friends: KerberosDateTime::now(), + comment: Comment { data: Data{}, - became_friends: KerberosDateTime::now(), - comment: Comment { - last_changed: KerberosDateTime::now(), - message: "I'm just a dummy account :3".to_string(), - unk: 0, - }, - last_online: KerberosDateTime::now(), - nna_info: NNAInfo { - principal_basic_info: PrincipalBasicInfo { - pid: 101, - nnid: "dummy:3".to_string(), - mii: MiiV2{ - date_time: KerberosDateTime::now(), - name: "TheDummy".to_string(), - mii_data: hex::decode("030000402bd7c32986a771f2dc6b35e31da15e37ff7c0000391e6f006f006d0069000000000000000000000000004040001065033568641e2013661a611821640f0000290052485000000000000000000000000000000000000000000000e838").unwrap(), - unk: 0, - unk2: 0, - }, - unk: 0 - }, - unk: 0, - unk2: 0 - }, - presence: NintendoPresenceV2{ - changed_flags: 0, - message: "".to_string(), - app_data: vec![], - game_key: GameKey{ - tid: 0x00050002101ce400, - version: 0x0 - }, - game_server_id: 0, - is_online: true, - gid: 0, + last_changed: KerberosDateTime::now(), + message: "I'm just a dummy account :3".to_string(), + unk: 0, + }, + last_online: KerberosDateTime::now(), + nna_info: NNAInfo { + data: Data{}, + principal_basic_info: PrincipalBasicInfo { + data: Data{}, pid: 101, - unk: 0, - unk2: 0, - unk3: 0, - unk4: 0, - unk5: 0, - unk6: 0, - unk7: 0 + nnid: "dummy:3".to_string(), + mii: MiiV2{ + data: Data{}, + date_time: KerberosDateTime::now(), + name: "TheDummy".to_string(), + mii_data: hex::decode("030000402bd7c32986a771f2dc6b35e31da15e37ff7c0000391e6f006f006d0069000000000000000000000000004040001065033568641e2013661a611821640f0000290052485000000000000000000000000000000000000000000000e838").unwrap(), + unk: 0, + unk2: 0, + }, + unk: 0 }, - unk: 0 - }]; + unk: 0, + unk2: 0 + }, + presence: NintendoPresenceV2{ + data: Data{}, + changed_flags: 0, + message: "".to_string(), + app_data: vec![], + game_key: GameKey{ + data: Data{}, + tid: 0x00050002101ce400, + version: 0x0 + }, + game_server_id: 0, + is_online: true, + gid: 0, + pid: 101, + unk: 0, + unk2: 0, + unk3: 0, + unk4: 0, + unk5: 0, + unk6: 0, + unk7: 0 + }, + unk: 0 + }]; println!("acquiring user and current friends locks"); let users = self.fm.users.read().await; @@ -235,11 +241,13 @@ impl Friends for FriendsUser { println!("done..."); Ok(( PrincipalPreference { + data: Data {}, block_friend_request: false, show_online: false, show_playing_title: false, }, Comment { + data: Data {}, last_changed: KerberosDateTime::now(), message: "".to_string(), unk: 0, diff --git a/rnex-core/src/rmc/protocols/friends.rs b/rnex-core/src/rmc/protocols/friends.rs index fa32120..81dd63e 100644 --- a/rnex-core/src/rmc/protocols/friends.rs +++ b/rnex-core/src/rmc/protocols/friends.rs @@ -7,6 +7,8 @@ use rnex_core::rmc::structures::{data::Data, rmc_struct}; #[derive(RmcSerialize, Debug, Clone)] #[rmc_struct(0)] pub struct MiiV2 { + #[extends] + pub data: Data, pub name: String, pub unk: u8, pub unk2: u8, @@ -17,6 +19,8 @@ pub struct MiiV2 { #[derive(RmcSerialize, Debug, Clone)] #[rmc_struct(0)] pub struct PrincipalBasicInfo { + #[extends] + pub data: Data, pub pid: u32, pub nnid: String, pub mii: MiiV2, @@ -26,6 +30,8 @@ pub struct PrincipalBasicInfo { #[derive(RmcSerialize, Debug, Clone)] #[rmc_struct(0)] pub struct NNAInfo { + #[extends] + pub data: Data, pub principal_basic_info: PrincipalBasicInfo, pub unk: u8, pub unk2: u8, @@ -34,6 +40,8 @@ pub struct NNAInfo { #[derive(RmcSerialize, Clone, Copy, Debug)] #[rmc_struct(0)] pub struct GameKey { + #[extends] + pub data: Data, pub tid: u64, pub version: u16, } @@ -41,6 +49,8 @@ pub struct GameKey { #[derive(RmcSerialize, Clone, Debug)] #[rmc_struct(0)] pub struct NintendoPresenceV2 { + #[extends] + pub data: Data, pub changed_flags: u32, pub is_online: bool, pub game_key: GameKey, @@ -60,6 +70,8 @@ pub struct NintendoPresenceV2 { #[derive(RmcSerialize)] #[rmc_struct(0)] pub struct PrincipalPreference { + #[extends] + pub data: Data, pub show_online: bool, pub show_playing_title: bool, pub block_friend_request: bool, @@ -68,6 +80,8 @@ pub struct PrincipalPreference { #[derive(RmcSerialize)] #[rmc_struct(0)] pub struct Comment { + #[extends] + pub data: Data, pub unk: u8, pub message: String, pub last_changed: KerberosDateTime, @@ -89,6 +103,8 @@ pub struct FriendInfo { #[derive(RmcSerialize)] #[rmc_struct(0)] pub struct FriendRequestMessage { + #[extends] + pub data: Data, pub friend_request_id: u64, pub is_recieved: u8, pub unk: u8, @@ -103,6 +119,8 @@ pub struct FriendRequestMessage { #[derive(RmcSerialize)] #[rmc_struct(0)] pub struct FriendRequest { + #[extends] + pub data: Data, pub basic_info: PrincipalBasicInfo, pub request_message: FriendRequestMessage, pub sent_on: KerberosDateTime, @@ -111,6 +129,8 @@ pub struct FriendRequest { #[derive(RmcSerialize)] #[rmc_struct(0)] pub struct BlacklistedPrincipal { + #[extends] + pub data: Data, pub basic_info: PrincipalBasicInfo, pub game_key: GameKey, pub since: KerberosDateTime, @@ -118,6 +138,8 @@ pub struct BlacklistedPrincipal { #[derive(RmcSerialize)] #[rmc_struct(0)] pub struct PersistentNotification { + #[extends] + pub data: Data, pub unk1: u64, pub unk2: u32, pub unk3: u32, diff --git a/rnex-core/src/rmc/structures/data.rs b/rnex-core/src/rmc/structures/data.rs index 0350c96..c6064ae 100644 --- a/rnex-core/src/rmc/structures/data.rs +++ b/rnex-core/src/rmc/structures/data.rs @@ -1,5 +1,5 @@ use macros::RmcSerialize; -#[derive(RmcSerialize)] +#[derive(RmcSerialize, Debug, Clone, Copy)] #[rmc_struct(0)] pub struct Data {} From c705b59e314059cda872a68d8665e1d0d046390f Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 25 Apr 2026 20:49:31 +0200 Subject: [PATCH 22/22] fix anydataholder --- rnex-core/src/rmc/structures/any.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/rnex-core/src/rmc/structures/any.rs b/rnex-core/src/rmc/structures/any.rs index 45ab453..0f531d8 100644 --- a/rnex-core/src/rmc/structures/any.rs +++ b/rnex-core/src/rmc/structures/any.rs @@ -13,10 +13,7 @@ impl RmcSerialize for Any { self.name.serialize(writer)?; let u32_len = self.data.len() as u32; - (u32_len + 4).serialize(writer)?; - u32_len.serialize(writer)?; - self.data.serialize(writer)?; Ok(()) @@ -26,11 +23,7 @@ impl RmcSerialize for Any { // also length ? let _len2: u32 = reader.read_struct(IS_BIG_ENDIAN)?; - let length: u32 = reader.read_struct(IS_BIG_ENDIAN)?; - - let mut data = vec![0; length as usize]; - - reader.read_exact(&mut data)?; + let data = Vec::deserialize(reader)?; Ok(Any { name, data }) }