1
0
mirror of https://git.ngram.ca/OpenJam/rc-servers synced 2026-08-23 23:08:52 +00:00

Add garage add, select, and re-order operations for #14

This commit is contained in:
NGnius (Graham)
2025-05-10 13:19:35 -04:00
parent e05649f09d
commit 221a5d5ca9
15 changed files with 420 additions and 34 deletions

View File

@@ -100,13 +100,14 @@ impl std::convert::Into<crate::data::garage_bay::GarageSlotInfo> for GarageSlot
}
pub fn db_into_data(garage: rc_database::schema::garage::Model) -> crate::data::garage_bay::GarageSlotInfo {
let cube_count = garage.cube_count();
crate::data::garage_bay::GarageSlotInfo {
name: garage.name,
cubes: 0, // TODO garage.cubes,
cubes: cube_count,
crf_id: garage.crf_id.unwrap_or(0),
was_rated: garage.was_rated,
movement_categories: movement_category_into_data(&garage.movement_categories),
uuid: i64_split(garage.uuid),
uuid: super::user::i64_split(garage.uuid),
thumbnail_version: garage.thumbnail_version,
total_robot_cpu: garage.total_robot_cpu,
total_cosmetic_cpu: garage.total_cosmetic_cpu,
@@ -133,23 +134,6 @@ fn movement_category_into_data(mov_cat: &str) -> Vec<crate::data::weapon_list::I
.collect()
}
pub fn i64_split(num: i64) -> (u32, u32) {
let bytes = (num as u64).to_le_bytes();
(
u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]),
u32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]])
)
}
#[allow(dead_code)]
pub fn u64_join(uuid: (u32, u32)) -> u64 {
let bytes = (uuid.0.to_le_bytes(), uuid.1.to_le_bytes());
u64::from_le_bytes(
[bytes.0[0], bytes.0[1], bytes.0[2], bytes.0[3],
bytes.1[0], bytes.1[1], bytes.1[2], bytes.1[3]]
)
}
pub fn control_ty_into_data(control_ty: rc_database::schema::garage::ControlType) -> crate::data::garage_bay::ControlType {
match control_ty {
rc_database::schema::garage::ControlType::Camera => crate::data::garage_bay::ControlType::Camera,

View File

@@ -15,8 +15,6 @@ impl AccountProvider {
log::debug!("Connecting to user database URI: {}", database_uri);
let db = rc_database::Database::init(&database_uri).await
.map_err(|e| std::io::Error::new(std::io::ErrorKind::NotConnected, e))?;
let root = root.as_ref().join(super::USERS_DIR);
std::fs::create_dir_all(&root)?;
Ok(Self {
cubes: std::sync::Arc::new(<crate::persist::config::ConfigImpl as ConfigProvider<()>>::ids(conf)),
secret: std::fs::read(&token_path)?,
@@ -214,7 +212,14 @@ impl <C: Clone> super::User<C> for UserData {
}
}
async fn all_slots_by_id(&self) -> super::UserSlots<C> {
async fn select_garage(&self, slot: i32) -> Result<(), i16> {
self.db.update_garage_selected_by_user_id_and_slot(self.account.id, slot as u32).await.map_err(|e| {
log::error!("Failed to select vehicle slot {} user_id {}: {}", slot, self.account.id, e);
DATABASE_ERR
})
}
async fn all_slots(&self) -> super::UserSlots<C> {
let slots = match self.all_vehicles().await {
Ok(slots) => slots,
Err(e) => {
@@ -222,7 +227,21 @@ impl <C: Clone> super::User<C> for UserData {
Vec::default()
}
};
let slot_order = polariton::operation::Typed::ObjArr(slots.iter().map(|slot| polariton::operation::Typed::Int(slot.slot as _)).collect::<Vec<_>>().into());
let slot_order = match self.db.user_aux_by_user_id_and_descriptor(self.account.id, rc_database::schema::user_aux::Descriptor::GarageSlotOrder).await{
Ok(Some(slot_order_db)) => {
let slots = serde_json::from_str::<Vec<u32>>(&slot_order_db.data).unwrap_or_default();
polariton::operation::Typed::ObjArr(slots.iter().map(|slot| polariton::operation::Typed::Int(*slot as _)).collect::<Vec<_>>().into())
},
Ok(None) => {
log::error!("No vehicle slot order for user_id {}", self.account.id);
polariton::operation::Typed::ObjArr(slots.iter().map(|slot| polariton::operation::Typed::Int(slot.slot as _)).collect::<Vec<_>>().into())
},
Err(e) => {
log::error!("Failed to get vehicle slot order for user_id {}: {}", self.account.id, e);
polariton::operation::Typed::ObjArr(slots.iter().map(|slot| polariton::operation::Typed::Int(slot.slot as _)).collect::<Vec<_>>().into())
},
};
//let slot_order = polariton::operation::Typed::ObjArr(slots.iter().map(|slot| polariton::operation::Typed::Int(slot.slot as _)).collect::<Vec<_>>().into());
let slot_info = polariton::operation::Typed::Dict(polariton::operation::Dict {
key_ty: polariton::serdes::TypePrefix::Int,
val_ty: polariton::serdes:: TypePrefix::HashMap,
@@ -275,9 +294,9 @@ impl <C: Clone> super::User<C> for UserData {
async fn save_slot(&self, vehicle: crate::persist::user::VehicleData) -> Result<(), i16> {
let entity = rc_database::schema::garage::ActiveModel {
weapon_order: rc_database::sea_orm::ActiveValue::Set(rc_database::schema::dump_csv(&vehicle.weapon_order)),
robot_data: rc_database::sea_orm::ActiveValue::Set(vehicle.robot_data),
colour_data: rc_database::sea_orm::ActiveValue::Set(vehicle.colour_data),
weapon_order: rc_database::sea_orm::ActiveValue::Set(rc_database::schema::dump_csv(&vehicle.weapon_order)),
..Default::default()
};
self.save_garage_by_slot(entity, vehicle.slot as u32).await.map_err(|e| {
@@ -287,6 +306,54 @@ impl <C: Clone> super::User<C> for UserData {
Ok(())
}
async fn save_slot_order(&self, slots: Vec<i32>) -> Result<(), i16> {
let slots: Vec<u32> = slots.into_iter().map(|x| x as u32).collect();
let entity = rc_database::schema::user_aux::ActiveModel {
data: rc_database::sea_orm::ActiveValue::Set(serde_json::to_string_pretty(&slots).unwrap()),
..Default::default()
};
self.db.update_user_aux_by_user_id_and_descriptor(entity, self.account.id, rc_database::schema::user_aux::Descriptor::GarageSlotOrder).await.map_err(|e| {
log::error!("Failed to update garage slot order for user_id {}: {}", self.account.id, e);
DATABASE_ERR
})?;
Ok(())
}
async fn new_slot(&self, reset_slot: Option<i32>) -> Result<super::NewSlotData<C>, i16> {
let model = if let Some(slot) = reset_slot {
let new_data = super::initial_data::default_reset_slot();
if let Some(reset_g) = self.db.update_garage_by_user_id_and_slot(new_data, self.account.id, slot as u32).await.map_err(|e| {
log::error!("Failed to reset vehicle slot {} for user_id {}: {}", slot, self.account.id, e);
DATABASE_ERR
})? {
reset_g
} else {
log::warn!("No vehicle slot {} to reset for user_id {}, creating new slot", slot, self.account.id);
return self.new_slot(None).await;
}
} else {
let max_slot = self.db.garage_max_slot_by_user_id(self.account.id).await.map_err(|e| {
log::error!("Failed to get max slot for user_id {}: {}", self.account.id, e);
DATABASE_ERR
})?;
let next_slot = max_slot + 1;
let new_data = super::initial_data::default_new_slot(self.account.id, next_slot, 2_000);
self.db.insert_garage(new_data).await.map_err(|e| {
log::error!("Failed to create new vehicle slot {} for user_id {}: {}", next_slot, self.account.id, e);
DATABASE_ERR
})?
};
let split_uuid = super::i64_split(model.uuid);
Ok(super::NewSlotData {
name: polariton::operation::Typed::Str(model.name.into()),
uuid_0: polariton::operation::Typed::Str(split_uuid.0.to_string().into()), // yes, seriously
uuid_1: polariton::operation::Typed::Str(split_uuid.1.to_string().into()), // also yes, seriously
slot: polariton::operation::Typed::Int(model.slot as _),
bay_cpu: polariton::operation::Typed::Int(model.bay_cpu as _),
mastery_level: polariton::operation::Typed::Int(model.mastery_level as _),
})
}
fn signup_date(&self) -> i64 {
super::since_windows_epoch(self.account.creation_time)
}

View File

@@ -133,6 +133,13 @@ r#"{
creation_time: rc_database::sea_orm::ActiveValue::Set(current_unix_time()),
descriptor: rc_database::sea_orm::ActiveValue::Set(rc_database::schema::user_aux::Descriptor::UserPaidCurrency),
data: rc_database::sea_orm::ActiveValue::Set("1000".to_owned()),
},
rc_database::schema::user_aux::ActiveModel {
id: Default::default(),
user_id: rc_database::sea_orm::ActiveValue::Set(user_id),
creation_time: rc_database::sea_orm::ActiveValue::Set(current_unix_time()),
descriptor: rc_database::sea_orm::ActiveValue::Set(rc_database::schema::user_aux::Descriptor::GarageSlotOrder),
data: rc_database::sea_orm::ActiveValue::Set("[0]".to_owned()),
}
]
}
@@ -149,6 +156,69 @@ fn default_user_perms(user_id: u32) -> rc_database::schema::permissions::ActiveM
}
}
pub fn default_new_slot(user_id: u32, slot: u32, bay_cpu: u32) -> rc_database::schema::garage::ActiveModel {
let current_time = current_unix_time();
rc_database::schema::garage::ActiveModel {
id: Default::default(),
user_id: rc_database::sea_orm::ActiveValue::Set(user_id),
creation_time: rc_database::sea_orm::ActiveValue::Set(current_time),
slot: rc_database::sea_orm::ActiveValue::Set(slot),
name: rc_database::sea_orm::ActiveValue::Set(format!("Bay {}", slot)),
crf_id: rc_database::sea_orm::ActiveValue::Set(None),
was_rated: rc_database::sea_orm::ActiveValue::Set(false),
movement_categories: rc_database::sea_orm::ActiveValue::Set("".to_owned()),
uuid: rc_database::sea_orm::ActiveValue::Set(super::uuid_sanitize(current_time)),
thumbnail_version: rc_database::sea_orm::ActiveValue::Set(0),
total_robot_cpu: rc_database::sea_orm::ActiveValue::Set(0),
total_cosmetic_cpu: rc_database::sea_orm::ActiveValue::Set(0),
total_robot_ranking: rc_database::sea_orm::ActiveValue::Set(0),
bay_cpu: rc_database::sea_orm::ActiveValue::Set(bay_cpu),
tutorial_robot: rc_database::sea_orm::ActiveValue::Set(false),
starter_robot_index: rc_database::sea_orm::ActiveValue::Set(None),
control_type: rc_database::sea_orm::ActiveValue::Set(rc_database::schema::garage::ControlType::Camera),
vertical_strafing: rc_database::sea_orm::ActiveValue::Set(false),
sideways_driving: rc_database::sea_orm::ActiveValue::Set(false),
tracks_turn_on_spot: rc_database::sea_orm::ActiveValue::Set(false),
mastery_level: rc_database::sea_orm::ActiveValue::Set(1),
bay_skin_id: rc_database::sea_orm::ActiveValue::Set("RC_MothershipSkin_Neptune_01".to_owned()),
weapon_order: rc_database::sea_orm::ActiveValue::Set("".to_owned()),
robot_data: rc_database::sea_orm::ActiveValue::Set(vec![0u8; 4]),
colour_data: rc_database::sea_orm::ActiveValue::Set(vec![0u8; 4]),
selected: rc_database::sea_orm::ActiveValue::Set(false),
}
}
pub fn default_reset_slot() -> rc_database::schema::garage::ActiveModel {
rc_database::schema::garage::ActiveModel {
id: Default::default(),
user_id: Default::default(),
creation_time: Default::default(),
slot: Default::default(),
name: Default::default(),
crf_id: rc_database::sea_orm::ActiveValue::Set(None),
was_rated: rc_database::sea_orm::ActiveValue::Set(false),
movement_categories: rc_database::sea_orm::ActiveValue::Set("".to_owned()),
uuid: Default::default(),
thumbnail_version: rc_database::sea_orm::ActiveValue::Set(0),
total_robot_cpu: rc_database::sea_orm::ActiveValue::Set(0),
total_cosmetic_cpu: rc_database::sea_orm::ActiveValue::Set(0),
total_robot_ranking: rc_database::sea_orm::ActiveValue::Set(0),
bay_cpu: Default::default(),
tutorial_robot: rc_database::sea_orm::ActiveValue::Set(false),
starter_robot_index: rc_database::sea_orm::ActiveValue::Set(None),
control_type: rc_database::sea_orm::ActiveValue::Set(rc_database::schema::garage::ControlType::Camera),
vertical_strafing: rc_database::sea_orm::ActiveValue::Set(false),
sideways_driving: rc_database::sea_orm::ActiveValue::Set(false),
tracks_turn_on_spot: rc_database::sea_orm::ActiveValue::Set(false),
mastery_level: Default::default(),
bay_skin_id: rc_database::sea_orm::ActiveValue::Set("RC_MothershipSkin_Neptune_01".to_owned()),
weapon_order: rc_database::sea_orm::ActiveValue::Set("".to_owned()),
robot_data: rc_database::sea_orm::ActiveValue::Set(vec![0u8; 4]),
colour_data: rc_database::sea_orm::ActiveValue::Set(vec![0u8; 4]),
selected: Default::default(),
}
}
fn default_garage_slots(user_id: u32) -> Vec<rc_database::schema::garage::ActiveModel> {
let current_time = current_unix_time();
vec![
@@ -161,7 +231,7 @@ fn default_garage_slots(user_id: u32) -> Vec<rc_database::schema::garage::Active
crf_id: rc_database::sea_orm::ActiveValue::Set(None),
was_rated: rc_database::sea_orm::ActiveValue::Set(false),
movement_categories: rc_database::sea_orm::ActiveValue::Set("".to_owned()),
uuid: rc_database::sea_orm::ActiveValue::Set(current_time),
uuid: rc_database::sea_orm::ActiveValue::Set(super::uuid_sanitize(current_time)),
thumbnail_version: rc_database::sea_orm::ActiveValue::Set(0),
total_robot_cpu: rc_database::sea_orm::ActiveValue::Set(0),
total_cosmetic_cpu: rc_database::sea_orm::ActiveValue::Set(0),

View File

@@ -11,7 +11,7 @@ mod inventory;
pub use inventory::UnlockedParts;
mod traits;
pub use traits::{UserProvider, User, UserToken, UserSlots, UserSlotData, VehicleData, UserInfo, UserLoginInfo, ExtraUserInfo, UserAuthenticator};
pub use traits::{UserProvider, User, UserToken, UserSlots, UserSlotData, VehicleData, UserInfo, UserLoginInfo, ExtraUserInfo, UserAuthenticator, NewSlotData};
pub const TOKEN_SECRET_FILENAME: &str = "token_secret.key";
@@ -35,10 +35,34 @@ pub fn since_windows_epoch(since_unix_epoch: i64) -> i64 {
time_in.signed_duration_since(windows_epoch).num_milliseconds() * 10_000
}
pub fn uuid_sanitize(num: i64) -> i64 {
let unsan = i64_split(num);
i64_join((
unsan.0.clamp(0, i32::MAX as _),
unsan.1.clamp(0, i32::MAX as _),
))
}
pub fn uuid_str(uuid: &(u32, u32)) -> String {
format!("{}_{}", uuid.0, uuid.1)
}
pub fn i64_as_uuid_str(num: i64) -> String {
uuid_str(&super::garage::i64_split(num))
uuid_str(&i64_split(num))
}
pub fn i64_split(num: i64) -> (u32, u32) {
let bytes = (num as u64).to_le_bytes();
(
u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]),
u32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]])
)
}
pub fn i64_join(uuid: (u32, u32)) -> i64 {
let bytes = (uuid.0.to_le_bytes(), uuid.1.to_le_bytes());
u64::from_le_bytes(
[bytes.0[0], bytes.0[1], bytes.0[2], bytes.0[3],
bytes.1[0], bytes.1[1], bytes.1[2], bytes.1[3]]
) as i64
}

View File

@@ -44,9 +44,12 @@ pub trait User<C> {
fn is_dev(&self) -> bool;
async fn unlocked_parts(&self) -> Vec<u32>;
async fn selected_garage(&self) -> (String, u32);
async fn all_slots_by_id(&self) -> UserSlots<C>;
async fn select_garage(&self, slot: i32) -> Result<(), i16>;
async fn all_slots(&self) -> UserSlots<C>;
async fn slot_by_id(&self, id: i32) -> Result<UserSlotData<C>, i16>;
async fn save_slot(&self, vehicle: VehicleData) -> Result<(), i16>;
async fn save_slot_order(&self, slots: Vec<i32>) -> Result<(), i16>;
async fn new_slot(&self, reset_slot: Option<i32>) -> Result<NewSlotData<C>, i16>;
fn signup_date(&self) -> i64;
async fn singleplayer_robots(&self) -> Result<polariton::operation::Typed<C>, i16>;
}
@@ -71,6 +74,15 @@ pub struct UserSlotData<C> {
pub uuid: polariton::operation::Typed<C>,
}
pub struct NewSlotData<C> {
pub name: polariton::operation::Typed<C>,
pub uuid_0: polariton::operation::Typed<C>,
pub uuid_1: polariton::operation::Typed<C>,
pub slot: polariton::operation::Typed<C>,
pub bay_cpu: polariton::operation::Typed<C>,
pub mastery_level: polariton::operation::Typed<C>,
}
pub struct VehicleData {
pub slot: i32,
pub robot_data: Vec<u8>,

View File

@@ -8,8 +8,11 @@ impl OpIdCopy {
impl <C: Clone + Send + Sync + 'static> OperationModifier<C> for OpIdCopy {
fn after(&self, req: &mut polariton::operation::OperationRequest<C>, resp: &mut polariton::operation::OperationResponse<C>) {
if let Some(svelto_service_id) = req.params.get(&Self::SERVICE_MAPPING_KEY) {
resp.params.insert(Self::SERVICE_MAPPING_KEY, svelto_service_id.to_owned());
if resp.params.get(&Self::SERVICE_MAPPING_KEY).is_none() {
if let Some(svelto_service_id) = req.params.get(&Self::SERVICE_MAPPING_KEY) {
resp.params.insert(Self::SERVICE_MAPPING_KEY, svelto_service_id.to_owned());
}
}
}
}

View File

@@ -4,3 +4,15 @@ use sea_orm::FromQueryResult;
pub struct Id {
pub id: u32,
}
#[derive(FromQueryResult)]
pub struct SingleColumn<T: sea_orm::TryGetable> {
pub column: T,
}
impl <T: sea_orm::TryGetable> std::ops::Deref for SingleColumn<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.column
}
}

View File

@@ -39,4 +39,5 @@ pub enum Descriptor {
UserRank, // u32
UserFreeCurrency, // u64
UserPaidCurrency, // u64
GarageSlotOrder, // Vec<u32>,
}

View File

@@ -1,5 +1,5 @@
use sea_orm_migration::MigratorTrait;
use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter, QueryOrder, QuerySelect};
use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter, QueryOrder, QuerySelect, TransactionTrait};
pub struct Database {
orm: sea_orm::DatabaseConnection,
@@ -46,6 +46,26 @@ impl Database {
Ok(())
}
pub async fn update_user_aux_by_user_id_and_descriptor(&self, mut entity: crate::schema::user_aux::ActiveModel, user_id: u32, descriptor: crate::schema::user_aux::Descriptor) -> Result<Option<crate::schema::user_aux::Model>, sea_orm::DbErr> {
let id_opt = crate::schema::user_aux::Entity::find()
.select_only()
.column(crate::schema::user_aux::Column::Id)
.filter(crate::schema::user_aux::Column::UserId.eq(user_id))
.filter(crate::schema::user_aux::Column::Descriptor.eq(descriptor.clone()))
.into_model::<crate::schema::common_query::Id>()
.one(&self.orm)
.await?;
if let Some(id) = id_opt {
// update
entity.id = sea_orm::ActiveValue::Set(id.id);
Ok(Some(crate::schema::user_aux::Entity::update(entity)
.exec(&self.orm)
.await?))
} else {
Ok(None)
}
}
pub async fn perms_by_user_id(&self, user_id: u32) -> Result<Option<crate::schema::permissions::Model>, sea_orm::DbErr> {
crate::schema::permissions::Entity::find()
.filter(crate::schema::permissions::Column::UserId.eq(user_id))
@@ -57,6 +77,17 @@ impl Database {
entity.insert(&self.orm).await
}
pub async fn garage_max_slot_by_user_id(&self, user_id: u32) -> Result<u32, sea_orm::DbErr> {
let result = crate::schema::garage::Entity::find()
.select_only()
.column_as(crate::schema::garage::Column::Slot.max(), "column")
.filter(crate::schema::garage::Column::UserId.eq(user_id))
.into_model::<crate::schema::common_query::SingleColumn<u32>>()
.one(&self.orm)
.await?;
Ok(result.map(|x| *x).unwrap_or(0))
}
pub async fn garage_selected(&self, user_id: u32) -> Result<Option<crate::schema::garage::Model>, sea_orm::DbErr> {
crate::schema::garage::Entity::find()
.filter(crate::schema::garage::Column::UserId.eq(user_id))
@@ -86,12 +117,16 @@ impl Database {
Ok(())
}
pub async fn update_garage(&self, entity: crate::schema::garage::ActiveModel, id: u32) -> Result<crate::schema::garage::Model, sea_orm::DbErr> {
pub async fn insert_garage(&self, entity: crate::schema::garage::ActiveModel) -> Result<crate::schema::garage::Model, sea_orm::DbErr> {
entity.insert(&self.orm).await
}
/*pub async fn update_garage(&self, entity: crate::schema::garage::ActiveModel, id: u32) -> Result<crate::schema::garage::Model, sea_orm::DbErr> {
crate::schema::garage::Entity::update(entity)
.filter(crate::schema::garage::Column::Id.eq(id))
.exec(&self.orm)
.await
}
}*/
pub async fn update_garage_by_user_id_and_slot(&self, mut entity: crate::schema::garage::ActiveModel, user_id: u32, slot: u32) -> Result<Option<crate::schema::garage::Model>, sea_orm::DbErr> {
let id_opt = crate::schema::garage::Entity::find()
@@ -110,6 +145,33 @@ impl Database {
} else {
Ok(None)
}
}
pub async fn update_garage_selected_by_user_id_and_slot(&self, user_id: u32, slot: u32) -> Result<(), sea_orm::DbErr> {
self.orm.transaction(|txn| {
Box::pin(async move {
crate::schema::garage::Entity::update_many()
.col_expr(crate::schema::garage::Column::Selected, sea_orm::sea_query::Expr::value(false))
.filter(crate::schema::garage::Column::UserId.eq(user_id))
.filter(crate::schema::garage::Column::Slot.ne(slot))
.exec(txn)
.await?;
crate::schema::garage::Entity::update_many()
.col_expr(crate::schema::garage::Column::Selected, sea_orm::sea_query::Expr::value(true))
.filter(crate::schema::garage::Column::UserId.eq(user_id))
.filter(crate::schema::garage::Column::Slot.eq(slot))
.exec(txn)
.await?;
Ok(())
})
}).await.map_err(|e| {
match e {
sea_orm::TransactionError::Connection(db) => db,
sea_orm::TransactionError::Transaction(txn) => txn,
}
})?;
Ok(())
}
}

View File

@@ -0,0 +1,52 @@
use polariton::operation::{ParameterTable, Typed, OperationResponse};
const CODE: u8 = 38;
const SLOT_REUSE_PARAM_KEY: u8 = 43; // int; in
const SLOT_PARAM_KEY: u8 = 45; // uint
const UUID_0_PARAM_KEY: u8 = 40; // str of uint
const UUID_1_PARAM_KEY: u8 = 41; // str of uint
const NAME_PARAM_KEY: u8 = 42; // str
const DEFAULT_BAY_CPU_PARAM_KEY: u8 = 8; // int
const MASTERY_LEVEL_PARAM_KEY: u8 = 18; // int
pub(super) fn garage_slot_add_provider() -> SlotCreator {
SlotCreator
}
async fn do_add(params: ParameterTable<()>, user: &crate::UserTy) -> Result<ParameterTable, i16> {
let mut params = params.to_dict();
let user_info = user.user()?;
let reset_slot = if let Some(Typed::Int(reuse_garage_slot)) = params.get(&SLOT_REUSE_PARAM_KEY) {
// reset existing garage slot
Some(*reuse_garage_slot)
} else {
// create new garage slot
None
};
let new_slot = user_info.new_slot(reset_slot).await?;
params.insert(SLOT_PARAM_KEY, new_slot.slot);
params.insert(UUID_0_PARAM_KEY, new_slot.uuid_0);
params.insert(UUID_1_PARAM_KEY, new_slot.uuid_1);
params.insert(MASTERY_LEVEL_PARAM_KEY, new_slot.mastery_level);
params.insert(NAME_PARAM_KEY, new_slot.name);
params.insert(DEFAULT_BAY_CPU_PARAM_KEY, new_slot.bay_cpu);
Ok(params.into())
}
pub struct SlotCreator;
#[async_trait::async_trait]
impl polariton_server::operations::Operation<()> for SlotCreator {
type User = crate::UserTy;
async fn handle_async(&self, params: ParameterTable<()>, user: &Self::User) -> OperationResponse<()> {
polariton_server::operations::result_to_op_resp::<CODE, ()>(do_add(params, user).await)
}
}
impl polariton_server::operations::OperationCode for SlotCreator {
fn op_code() -> u8 {
CODE
}
}

View File

@@ -0,0 +1,14 @@
use polariton_server::operations::Immediate;
//use rc_core::ConfigProvider;
const PARAM_KEY: u8 = 68;
pub(super) fn garage_slots_limit(_conf: &rc_core::ConfigImpl) -> Immediate<60, crate::UserTy> {
//let limit = conf.game_mode_config();
Immediate::new(move || {
let mut params = std::collections::HashMap::with_capacity(1);
params.insert(PARAM_KEY, polariton::operation::Typed::Int(100));
params.into()
})
}

View File

@@ -0,0 +1,35 @@
use polariton::operation::{ParameterTable, Typed, OperationResponse};
const CODE: u8 = 44;
const SLOT_PARAM_KEY: u8 = 48; // uint; in
pub(super) fn garage_slot_selector() -> SlotSelector {
SlotSelector
}
async fn do_select(params: ParameterTable<()>, user: &crate::UserTy) -> Result<ParameterTable, i16> {
let mut params = params.to_dict();
let user_info = user.user()?;
if let Some(Typed::Int(to_select)) = params.remove(&SLOT_PARAM_KEY) {
user_info.select_garage(to_select).await?;
}
Ok(params.into())
}
pub struct SlotSelector;
#[async_trait::async_trait]
impl polariton_server::operations::Operation<()> for SlotSelector {
type User = crate::UserTy;
async fn handle_async(&self, params: ParameterTable<()>, user: &Self::User) -> OperationResponse<()> {
polariton_server::operations::result_to_op_resp::<CODE, ()>(do_select(params, user).await)
}
}
impl polariton_server::operations::OperationCode for SlotSelector {
fn op_code() -> u8 {
CODE
}
}

View File

@@ -13,7 +13,7 @@ pub(super) fn garage_slot_provider() -> GarageSlotsProvider {
async fn do_handling(params: ParameterTable<()>, user: &crate::UserTy) -> Result<ParameterTable, i16> {
let user_info = user.user()?;
let mut params = params.to_dict();
let all_slots = user_info.all_slots_by_id().await;
let all_slots = user_info.all_slots().await;
params.insert(SLOTS_PARAM_KEY, all_slots.slot_info);
params.insert(SELECTED_SLOT_PARAM_KEY, Typed::Int(user_info.selected_garage().await.1 as _));
params.insert(SLOT_ORDER_PARAM_KEY, all_slots.slot_order);

View File

@@ -0,0 +1,42 @@
use polariton::operation::{ParameterTable, Typed, OperationResponse};
const CODE: u8 = 114;
const SLOT_ORDER_PARAM_KEY: u8 = 58;
pub(super) fn garage_slot_order_provider() -> GarageSlotsOrderProvider {
GarageSlotsOrderProvider
}
async fn do_handling(params: ParameterTable<()>, user: &crate::UserTy) -> Result<ParameterTable, i16> {
let mut params = params.to_dict();
if let Some(Typed::Arr(order)) = params.remove(&SLOT_ORDER_PARAM_KEY) {
log::info!("Slot order is {}", order);
let mut order_i32 = Vec::with_capacity(order.items.len());
for item in order.items.iter() {
if let Typed::Int(item) = item {
order_i32.push(*item);
}
}
let user_info = user.user()?;
user_info.save_slot_order(order_i32).await?;
}
Ok(params.into())
}
pub struct GarageSlotsOrderProvider;
#[async_trait::async_trait]
impl polariton_server::operations::Operation<()> for GarageSlotsOrderProvider {
type User = crate::UserTy;
async fn handle_async(&self, params: ParameterTable<()>, user: &Self::User) -> OperationResponse<()> {
polariton_server::operations::result_to_op_resp::<CODE, ()>(do_handling(params, user).await)
}
}
impl polariton_server::operations::OperationCode for GarageSlotsOrderProvider {
fn op_code() -> u8 {
CODE
}
}

View File

@@ -80,6 +80,10 @@ mod game_mode_config;
mod score_multipliers_config;
mod player_robot_rank;
mod weapon_order;
mod garage_slot_limit;
mod garage_slot_add;
mod garage_slots_order;
mod garage_slot_select;
use polariton_server::operations::OperationsHandler;
@@ -182,4 +186,8 @@ pub fn handler(init_ctx: &crate::InitConfig) -> OperationsHandler<crate::UserTy>
.add(singleplayer_campaigns::singleplayer_complete_campaign_provider(&init_ctx.cubes))
.add(polariton_server::operations::Ack::<78, _>::default()) // TODO handle SaveCampaignGameAwardsRequest instead of ignoring it
.add(singleplayer_campaigns::singleplayer_save_complete_campaign_provider()) // TODO handle UpdatePlayerCompletedCampaignWaveRequest saving
.add(garage_slot_limit::garage_slots_limit(&init_ctx.cubes))
.add(garage_slot_add::garage_slot_add_provider())
.add(garage_slots_order::garage_slot_order_provider())
.add(garage_slot_select::garage_slot_selector())
}