Add NEX results and fix timers

This commit is contained in:
red binder 2026-04-06 13:35:55 +00:00 committed by Maple
commit 55b3959797
8 changed files with 586 additions and 52 deletions

View file

@ -247,27 +247,29 @@ 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;
};
let older_pid = old_conns.pid;
initiating_user
.remote
.process_notification_event(NotificationEvent {
pid_source: initiating_pid,
notif_type: 3001,
param_1: self.session.gathering.self_gid as PID,
param_2: older_pid,
str_param: join_msg.clone(),
param_3: self.connected_players.len() as _,
})
.await;
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;
}
}
}
pub fn has_active_players(&self) -> bool {

View file

@ -5,10 +5,14 @@ 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::prudp::station_url::StationUrl;
use rnex_core::prudp::station_url::UrlOptions::{
@ -29,12 +33,15 @@ use rnex_core::rmc::structures::matchmake::{
};
use crate::rmc::protocols::notifications::{NotificationEvent, RemoteNotification};
use log::info;
use log::{info, error};
use macros::rmc_struct;
use rnex_core::rmc::structures::qbuffer::QBuffer;
use rnex_core::prudp::socket_addr::PRUDPSockAddr;
use rnex_core::rmc::response::ErrorCode::{Core_InvalidArgument, RendezVous_AccountExpired};
use rnex_core::rmc::structures::qresult::QResult;
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!(
@ -582,4 +589,145 @@ impl NatTraversal for User {
}
}
impl Ranking for User {}
#[derive(Serialize, Deserialize)]
pub struct CompetitionPostResults {
pub splatfest_id: u32,
pub score: u32,
pub team_id: u8,
pub team_win: u8,
pub user: PID,
}
// Seperate function because I cannot give a fuck right now
fn fetch_team_votes(fest_id: u32) -> Result<Vec<u32>, ErrorCode> {
let endpoint_votes = env::var("RNEX_SPLATOON_RESULTS_VOTES_GET").map_err(|_| {
error!("RNEX_SPLATOON_RESULTS_VOTES_GET not set");
ErrorCode::RendezVous_InvalidConfiguration
})?;
let url_votes = format!("{}?splatfest_id={}", endpoint_votes, fest_id);
let mut response = ureq::get(&url_votes).call().map_err(|e| {
error!("GET for votes failed: {:?}", e);
ErrorCode::RendezVous_InvalidConfiguration
})?;
let body = response.body_mut().read_to_string().map_err(|e| {
error!("failed to read votes body: {:?}", e);
ErrorCode::RendezVous_InvalidConfiguration
})?;
let body = body.trim().trim_start_matches('[').trim_end_matches(']');
let votes: Result<Vec<u32>, _> = body
.split(',')
.map(|s| u32::from_str(s.trim()))
.collect();
votes.map_err(|e| {
error!("failed to parse votes: {:?}", e);
ErrorCode::RendezVous_InvalidConfiguration
})
}
impl Ranking for User {
async fn competition_ranking_get_param(
&self,
param: CompetitionRankingGetParam,
) -> Result<Vec<CompetitionRankingScoreInfo>, 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 url_results = format!("{}?splatfest_id={}", endpoint_results, fest_id);
let response_results = ureq::get(&url_results).call();
let results: Vec<CompetitionPostResults> = match response_results {
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);
}
};
let team_votes = fetch_team_votes(fest_id)?;
let score_data: Vec<CompetitionRankingScoreData> = results
.iter()
.map(|r| CompetitionRankingScoreData {
unk: 1,
pid: r.user,
score: r.score,
modified: KerberosDateTime::now(),
unk2: 1,
appdata: QBuffer(vec![]),
})
.collect();
let info = CompetitionRankingScoreInfo {
fest_id,
score_data,
unk: 0,
team_wins: results.iter().map(|r| r.team_win as u32).collect(),
team_votes,
};
Ok(vec![info])
}
async fn upload_competition_ranking_score(&self, param: UploadCompetitionData) -> Result<bool, ErrorCode> {
info!("fest results for user {:?}:", self.pid);
info!("fest id: {:?}", param.splatfest_id);
info!("score: {:?}", param.score);
info!("team id: {:?}", param.team_id);
info!("did current team win: {:?}", param.team_win);
let endpoint = match env::var("RNEX_SPLATOON_RESULTS_POST") {
Ok(url) => url,
Err(_) => {
error!("RNEX_SPLATOON_RESULTS_POST not set");
return Ok(false);
}
};
let payload = CompetitionPostResults {
splatfest_id: param.splatfest_id,
score: param.score,
team_id: param.team_id,
team_win: param.team_win,
user: self.pid,
};
let json_body = match serde_json::to_string(&payload) {
Ok(j) => j,
Err(e) => {
error!("error making json_body: {:?}", e);
return Ok(false);
}
};
let response = ureq::post(&endpoint)
.header("Content-Type", "application/json")
.send(json_body);
match response {
Ok(res) => {
info!("POST worked: {}", res.status());
}
Err(e) => {
error!("POST borked: {:?}", e);
}
}
Ok(true)
}
}

View file

@ -42,7 +42,8 @@ impl RMCMessage{
error!("received incorrect rmc packet: expected size {} but found {}", size, header_size + rest_of_data.len());
}
// println!("rmc packet: protoid: {}, method id: {}", protocol_id, method_id);
// println!("{}", hex::encode(&rest_of_data));
//stream.
Ok(Self{

View file

@ -1,33 +1,51 @@
use macros::{rmc_struct, rmc_proto, RmcSerialize};
use macros::{rmc_struct, rmc_proto, RmcSerialize, method_id};
use rnex_core::kerberos::KerberosDateTime;
use rnex_core::rmc::structures::qbuffer::QBuffer;
use rnex_core::rmc::response::ErrorCode;
use rnex_core::rmc::structures::ranking::UploadCompetitionData;
#[derive(RmcSerialize, Debug, Default, Clone)]
struct ResultsRange{
offset: u32,
size: u32
#[rmc_struct(0)]
pub struct ResultsRange{
pub offset: u32,
pub size: u32
}
#[derive(RmcSerialize, Debug, Default, Clone)]
#[rmc_struct(1)]
struct CompetitionRankingGetParam{
unk: u32,
range: ResultsRange,
festival_ids: Vec<u32>,
pub struct CompetitionRankingGetParam {
pub unk: u32,
pub range: ResultsRange,
pub festival_ids: Vec<u32>,
}
#[derive(RmcSerialize, Debug, Default, Clone)]
#[rmc_struct(0)]
struct CompetitionRankingScoreInfo{
fest_id: u32,
score_data: Vec<u32>,
unk: u32,
team_wins: Vec<u32>,
team_votes: Vec<u32>
pub struct CompetitionRankingScoreInfo{
pub fest_id: u32,
pub score_data: Vec<CompetitionRankingScoreData>,
pub unk: u32,
pub team_wins: Vec<u32>,
pub team_votes: Vec<u32>
}
#[derive(RmcSerialize, Debug, Clone)]
#[rmc_struct(0)]
pub struct CompetitionRankingScoreData{
pub unk: u32,
pub pid: u32,
pub score: u32,
pub modified: KerberosDateTime,
pub unk2: u8,
pub appdata: QBuffer
}
#[rmc_proto(112)]
pub trait Ranking{
//#[method_id(16)]
//async fn competition_ranking_get_param(&self, param: CompetitionRankingGetParam) -> Result<Vec<CompetitionRankingScoreInfo>,ErrorCode>;
}
#[method_id(16)]
async fn competition_ranking_get_param(&self, param: CompetitionRankingGetParam) -> Result<Vec<CompetitionRankingScoreInfo>,ErrorCode>;
#[method_id(18)]
async fn upload_competition_ranking_score(&self, param: UploadCompetitionData) -> Result<bool, ErrorCode>;
}

View file

@ -3,8 +3,7 @@ use bytemuck::bytes_of;
use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions};
use crate::rmc::structures::{Result, RmcSerialize};
#[derive(Debug)]
#[derive(Clone, Debug)]
pub struct QBuffer(pub Vec<u8>);
impl RmcSerialize for QBuffer{

View file

@ -4,15 +4,15 @@ use rnex_core::rmc::structures::qbuffer::QBuffer;
#[derive(RmcSerialize, Debug)]
#[rmc_struct(0)]
struct UploadCompetitionData {
winning_team: u32,
splatfest_id: u32,
unk_2: u32,
unk_3: u32,
team_id_1: u8,
team_id_2: u8,
unk_5: u32,
player_data: QBuffer,
pub struct UploadCompetitionData{
pub unk_1/*?*/: u32,
pub splatfest_id: u32,
pub unk_2/*?*/: u32,
pub score: u32,
pub team_id: u8,
pub team_win: u8,
pub is_first_upload: bool,
pub appdata: QBuffer,
}
#[derive(Copy, Clone, Pod, Zeroable)]