From 0615e3e663b57b8bf596e6afa36ec533dd943a43 Mon Sep 17 00:00:00 2001 From: red binder Date: Sun, 21 Jun 2026 22:21:54 +0200 Subject: [PATCH] GetCustomRankings method --- ...93cfdef21c64fd31d1b2bd7a7605f97d550ee.json | 32 ++++++++ rnex-core/src/nex/datastore.rs | 81 ++++++++++++++++++- rnex-core/src/rmc/protocols/datastore.rs | 22 +++++ 3 files changed, 133 insertions(+), 2 deletions(-) create mode 100644 rnex-core/.sqlx/query-555c438210f49e3a8fd279bf3d493cfdef21c64fd31d1b2bd7a7605f97d550ee.json diff --git a/rnex-core/.sqlx/query-555c438210f49e3a8fd279bf3d493cfdef21c64fd31d1b2bd7a7605f97d550ee.json b/rnex-core/.sqlx/query-555c438210f49e3a8fd279bf3d493cfdef21c64fd31d1b2bd7a7605f97d550ee.json new file mode 100644 index 0000000..40763ff --- /dev/null +++ b/rnex-core/.sqlx/query-555c438210f49e3a8fd279bf3d493cfdef21c64fd31d1b2bd7a7605f97d550ee.json @@ -0,0 +1,32 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n data_id,\n value\n FROM datastore.object_custom_rankings\n WHERE application_id = $1\n AND value >= $2\n AND value <= $3\n ORDER BY value DESC\n LIMIT $4 OFFSET $5\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "data_id", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "value", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Int8", + "Int8", + "Int8", + "Int8", + "Int8" + ] + }, + "nullable": [ + false, + true + ] + }, + "hash": "555c438210f49e3a8fd279bf3d493cfdef21c64fd31d1b2bd7a7605f97d550ee" +} diff --git a/rnex-core/src/nex/datastore.rs b/rnex-core/src/nex/datastore.rs index 3f1d3ca..20e2acd 100644 --- a/rnex-core/src/nex/datastore.rs +++ b/rnex-core/src/nex/datastore.rs @@ -24,6 +24,7 @@ use rnex_core::rmc::protocols::datastore::{ use rnex_core::rmc::response::ErrorCode; use rnex_core::rmc::structures::qbuffer::QBuffer; use rnex_core::rmc::structures::qresult::QResult; +use crate::rmc::protocols::datastore::DataStoreGetCustomRankingParam; fn map_row_to_meta_info( row_data_id: i64, @@ -1306,9 +1307,10 @@ impl DataStore for User { // this might be good to keep as a sanity check but as long as we zip the two vecs together // we already avoid crashes which can be caused by this // (previous comment) SMM seems to work fine with this, no clue for other DTSR games - /*if targets.len() != params.len() { + // binder: we should keep it anyways, just in case. no harm no foul right? + if targets.len() != params.len() { return Err(ErrorCode::DataStore_OperationNotAllowed); - }*/ + } let actions = targets @@ -1733,4 +1735,79 @@ impl DataStore for User { Ok(()) } + + async fn get_custom_ranking( + &self, + param: DataStoreGetCustomRankingParam + ) -> Result<(Vec, Vec), ErrorCode> { + let mut ranking_results = Vec::new(); + + let rows = sqlx::query!( + r#" + SELECT + data_id, + value + FROM datastore.object_custom_rankings + WHERE application_id = $1 + AND value >= $2 + AND value <= $3 + ORDER BY value DESC + LIMIT $4 OFFSET $5 + "#, + param.application_id as i64, + param.condition.min_value as i64, + param.condition.max_value as i64, + param.result_range.size as i64, + param.result_range.offset as i64, + ) + .fetch_all(get_db()) + .await + .map_err(|e| { + log::error!("DB Error: {:?}", e); + ErrorCode::DataStore_NotFound + })?; + + let mut current_order = param.result_range.offset + 1; + + for row in rows { + let data_id = row.data_id; + let score = row.value.unwrap_or(0) as u32; + + if let Ok(meta) = get_object_info_by_data_id(data_id, 0).await { + ranking_results.push(DataStoreCustomRankingResult { + order: current_order, + score, + meta_info: meta, + }); + } else { + log::warn!("could not find metadata for ranked object {}", data_id); + } + + current_order += 1; + } + + let mut q_results = Vec::with_capacity(ranking_results.len()); + + for result in &mut ranking_results { + if (param.result_option & 0x01) == 0 { + result.meta_info.tags = Vec::new(); + } + + if (param.result_option & 0x02) == 0 { + result.meta_info.ratings = Vec::new(); + } + + if (param.result_option & 0x04) == 0 { + result.meta_info.meta_binary = QBuffer(Vec::new()); + } + + if (param.result_option & 0x20) == 0 { + result.score = 0; + } + + q_results.push(QResult::success(ErrorCode::Core_Unknown)); + } + + Ok((ranking_results, q_results)) + } } diff --git a/rnex-core/src/rmc/protocols/datastore.rs b/rnex-core/src/rmc/protocols/datastore.rs index 524d25d..a30b857 100644 --- a/rnex-core/src/rmc/protocols/datastore.rs +++ b/rnex-core/src/rmc/protocols/datastore.rs @@ -318,6 +318,23 @@ pub struct DataStoreDeleteParam { pub update_password: i64, } +#[derive(RmcSerialize, Clone)] +#[rmc_struct(0)] +pub struct DataStoreCustomRankingRatingCondition { + pub slot: i8, + pub min_value: i32, + pub max_value: i32, +} + +#[derive(RmcSerialize, Clone)] +#[rmc_struct(0)] +pub struct DataStoreGetCustomRankingParam { + pub application_id: u32, + pub condition: DataStoreCustomRankingRatingCondition, + pub result_option: u8, + pub result_range: ResultsRange, +} + #[rmc_proto(115)] pub trait DataStore { #[method_id(4)] @@ -355,6 +372,11 @@ pub trait DataStore { ) -> Result<(), ErrorCode>; #[method_id(61)] async fn get_application_config(&self, appid: u32) -> Result, ErrorCode>; + #[method_id(49)] + async fn get_custom_ranking( + &self, + param: DataStoreGetCustomRankingParam, + ) -> Result<(Vec, Vec), ErrorCode>; #[method_id(50)] async fn get_custom_ranking_by_data_id( &self,