diff --git a/rc_core/src/persist/config/cubes_json.rs b/rc_core/src/persist/config/cubes_json.rs index 19e59f1..828a161 100644 --- a/rc_core/src/persist/config/cubes_json.rs +++ b/rc_core/src/persist/config/cubes_json.rs @@ -261,4 +261,13 @@ impl super::ConfigProvider for CubeConfig { database: self.settings.server.database.clone(), } } + + fn garage_upgrades(&self) -> super::GarageUpgrades { + super::GarageUpgrades { + increments: self.settings.garage_upgrades.iter().map(|inc| super::GarageUpgradeIncrement { + cpu: inc.cpu, + cost: inc.cost, + }).collect(), + } + } } diff --git a/rc_core/src/persist/config/mod.rs b/rc_core/src/persist/config/mod.rs index 9157a2c..f3ac795 100644 --- a/rc_core/src/persist/config/mod.rs +++ b/rc_core/src/persist/config/mod.rs @@ -2,7 +2,7 @@ mod cubes_json; pub use cubes_json::CubeConfig; mod traits; -pub use traits::{ConfigProvider, CompleteCampaignProvider, DevMessageProvider, ServerConfig}; +pub use traits::{ConfigProvider, CompleteCampaignProvider, DevMessageProvider, ServerConfig, GarageUpgrades, GarageUpgradeIncrement}; pub type ConfigImpl = CubeConfig; diff --git a/rc_core/src/persist/config/traits.rs b/rc_core/src/persist/config/traits.rs index 27a124a..d42a996 100644 --- a/rc_core/src/persist/config/traits.rs +++ b/rc_core/src/persist/config/traits.rs @@ -19,6 +19,7 @@ pub trait ConfigProvider { fn login_messages(&self) -> DevMessageProvider; fn public_channels(&self) -> Typed; fn server_config(&self) -> ServerConfig; + fn garage_upgrades(&self) -> GarageUpgrades; } pub struct CompleteCampaignProvider { @@ -88,3 +89,27 @@ pub struct TypedDevMessage { pub struct ServerConfig { pub database: String, } + +#[derive(Clone, Debug)] +pub struct GarageUpgrades { + pub increments: Vec, +} + +#[derive(Clone, Debug)] +pub struct GarageUpgradeIncrement { + pub cpu: u32, + pub cost: u32, +} + +impl GarageUpgrades { + pub fn slot_upgrades(&self) -> Typed { + Typed::HashMap(vec![ + (Typed::Str("cpuIncreaseCost".into()), Typed::Dict(polariton::operation::Dict { + key_ty: polariton::serdes::TypePrefix::Int, // int + val_ty: polariton::serdes::TypePrefix::Int, // int + // (CPU limit, upgrade cost) + items: self.increments.iter().map(|inc| (Typed::Int(inc.cpu as _), Typed::Int(inc.cost as _))).collect(), + })) + ].into()) + } +} diff --git a/rc_core/src/persist/settings.rs b/rc_core/src/persist/settings.rs index 2c09d95..cc84ce3 100644 --- a/rc_core/src/persist/settings.rs +++ b/rc_core/src/persist/settings.rs @@ -6,6 +6,8 @@ pub struct Settings { pub gameplay: super::GameplaySettings, #[serde(default = "default_dev_messages")] pub banners: Vec, + #[serde(default = "default_slot_upgrades")] + pub garage_upgrades: Vec, #[serde(default = "default_server_conf")] pub server: ServerSettings, } @@ -35,6 +37,37 @@ fn default_dev_messages() -> Vec { Vec::default() } +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct GarageSlotUpgrade { + pub cpu: u32, + pub cost: u32, +} + +fn default_slot_upgrades() -> Vec { + vec![ + GarageSlotUpgrade { + cpu: 100, + cost: 100, + }, + GarageSlotUpgrade { + cpu: 200, + cost: 200, + }, + GarageSlotUpgrade { + cpu: 1_000, + cost: 1_000, + }, + GarageSlotUpgrade { + cpu: 2_000, + cost: 2_000, + }, + GarageSlotUpgrade { + cpu: 10_000, + cost: 10_000, + }, + ] +} + #[derive(Serialize, Deserialize, Clone, Debug)] pub struct ServerSettings { #[serde(default = "default_db_conn")] diff --git a/rc_core/src/persist/user/account_json.rs b/rc_core/src/persist/user/account_json.rs index 742ea55..9f502f8 100644 --- a/rc_core/src/persist/user/account_json.rs +++ b/rc_core/src/persist/user/account_json.rs @@ -4,6 +4,7 @@ use crate::persist::config::ConfigProvider; pub struct AccountProvider { cubes: std::sync::Arc>, + garage_upgrades: std::sync::Arc, secret: Vec, db: std::sync::Arc, } @@ -17,6 +18,7 @@ impl AccountProvider { .map_err(|e| std::io::Error::new(std::io::ErrorKind::NotConnected, e))?; Ok(Self { cubes: std::sync::Arc::new(>::ids(conf)), + garage_upgrades: std::sync::Arc::new(>::garage_upgrades(conf)), secret: std::fs::read(&token_path)?, db: std::sync::Arc::new(db), }) @@ -47,6 +49,7 @@ impl super::UserProvider for AccountProvider { account: user_info, perms: user_perms, cubes: self.cubes.clone(), + garage_upgrades: self.garage_upgrades.clone(), extensions: ext, db: self.db.clone(), })) @@ -127,6 +130,7 @@ struct UserData { account: rc_database::schema::user::Model, perms: rc_database::schema::permissions::Model, cubes: std::sync::Arc>, + garage_upgrades: std::sync::Arc, extensions: std::collections::HashMap>, db: std::sync::Arc, } @@ -354,6 +358,45 @@ impl super::User for UserData { }) } + async fn upgrade_slot(&self, increments: i32) -> Result, i16> { + if increments <= 0 { + // no-op + return Ok(polariton::operation::Typed::Bool(true)); + } + let selected_slot = self.db.garage_selected(self.account.id).await.map_err(|e| { + log::error!("Failed to retrieve selected vehicle slot for user_id {}: {}", self.account.id, e); + DATABASE_ERR + })?.ok_or_else(|| { + log::error!("No selected vehicle slot for user_id {}", self.account.id); + DATABASE_ERR + })?; + let inc_opt = self.garage_upgrades.increments.iter().enumerate().filter(|(_i, inc)| inc.cpu <= selected_slot.bay_cpu).last(); + if let Some((i, _)) = inc_opt { + let max_upgrade = self.garage_upgrades.increments.len() - 1; + let upgrade_to = i + (increments as usize); + if upgrade_to > max_upgrade { + // over-upgraded + Ok(polariton::operation::Typed::Bool(false)) + } else { + let upgrade_to_cpu = self.garage_upgrades.increments[upgrade_to].cpu; + let entity = rc_database::schema::garage::ActiveModel { + bay_cpu: rc_database::sea_orm::ActiveValue::Set(upgrade_to_cpu), + ..Default::default() + }; + self.db.update_garage_by_user_id_and_slot(entity, self.account.id, selected_slot.slot).await.map_err(|e| { + log::error!("Failed to upgrade selected vehicle slot to bay cpu of {} for user_id {}: {}", upgrade_to_cpu, self.account.id, e); + DATABASE_ERR + })?; + // TODO subtract upgrade cost from user free currency total + Ok(polariton::operation::Typed::Bool(true)) + } + } else { + // probably a bad/changed garage update config + log::warn!("No vehicle slot upgrade found for bay CPU {} for user_id {}", selected_slot.bay_cpu, self.account.id); + Ok(polariton::operation::Typed::Bool(false)) + } + } + fn signup_date(&self) -> i64 { super::since_windows_epoch(self.account.creation_time) } diff --git a/rc_core/src/persist/user/traits.rs b/rc_core/src/persist/user/traits.rs index 5042e11..0a6ff4f 100644 --- a/rc_core/src/persist/user/traits.rs +++ b/rc_core/src/persist/user/traits.rs @@ -50,6 +50,7 @@ pub trait User { async fn save_slot(&self, vehicle: VehicleData) -> Result<(), i16>; async fn save_slot_order(&self, slots: Vec) -> Result<(), i16>; async fn new_slot(&self, reset_slot: Option) -> Result, i16>; + async fn upgrade_slot(&self, increments: i32) -> Result, i16>; fn signup_date(&self) -> i64; async fn singleplayer_robots(&self) -> Result, i16>; } diff --git a/rc_services_room/src/operations/garage_slot_dismantle.rs b/rc_services_room/src/operations/garage_slot_dismantle.rs new file mode 100644 index 0000000..a95f3f6 --- /dev/null +++ b/rc_services_room/src/operations/garage_slot_dismantle.rs @@ -0,0 +1,35 @@ +use polariton::operation::{ParameterTable, Typed, OperationResponse}; + +const CODE: u8 = 42; + +const SLOT_PARAM_KEY: u8 = 43; + +pub(super) fn garage_slot_dismantler() -> GarageSlotDismantler { + GarageSlotDismantler +} + +async fn do_handling(params: ParameterTable<()>, user: &crate::UserTy) -> Result { + let mut params = params.to_dict(); + if let Some(Typed::Int(slot)) = params.remove(&SLOT_PARAM_KEY) { + let user_info = user.user()?; + user_info.new_slot(Some(slot)).await?; + } + Ok(params.into()) +} + +pub struct GarageSlotDismantler; + +#[async_trait::async_trait] +impl polariton_server::operations::Operation<()> for GarageSlotDismantler { + type User = crate::UserTy; + + async fn handle_async(&self, params: ParameterTable<()>, user: &Self::User) -> OperationResponse<()> { + polariton_server::operations::result_to_op_resp::(do_handling(params, user).await) + } +} + +impl polariton_server::operations::OperationCode for GarageSlotDismantler { + fn op_code() -> u8 { + CODE + } +} diff --git a/rc_services_room/src/operations/garage_slot_upgrade.rs b/rc_services_room/src/operations/garage_slot_upgrade.rs new file mode 100644 index 0000000..05f8b39 --- /dev/null +++ b/rc_services_room/src/operations/garage_slot_upgrade.rs @@ -0,0 +1,36 @@ +use polariton::operation::{ParameterTable, Typed, OperationResponse}; + +const CODE: u8 = 39; + +const CPU_INCREMENT_PARAM_KEY: u8 = 7; +const SUCCESS_PARAM_KEY: u8 = 39; + +pub(super) fn garage_slot_upgrage_provider() -> GarageSlotUpgrade { + GarageSlotUpgrade +} + +async fn do_handling(params: ParameterTable<()>, user: &crate::UserTy) -> Result { + let mut params = params.to_dict(); + if let Some(Typed::Int(increments)) = params.remove(&CPU_INCREMENT_PARAM_KEY) { + let user_info = user.user()?; + params.insert(SUCCESS_PARAM_KEY, user_info.upgrade_slot(increments).await?); + } + Ok(params.into()) +} + +pub struct GarageSlotUpgrade; + +#[async_trait::async_trait] +impl polariton_server::operations::Operation<()> for GarageSlotUpgrade { + type User = crate::UserTy; + + async fn handle_async(&self, params: ParameterTable<()>, user: &Self::User) -> OperationResponse<()> { + polariton_server::operations::result_to_op_resp::(do_handling(params, user).await) + } +} + +impl polariton_server::operations::OperationCode for GarageSlotUpgrade { + fn op_code() -> u8 { + CODE + } +} diff --git a/rc_services_room/src/operations/garage_slots_order.rs b/rc_services_room/src/operations/garage_slots_order.rs index d49a016..cb07ebd 100644 --- a/rc_services_room/src/operations/garage_slots_order.rs +++ b/rc_services_room/src/operations/garage_slots_order.rs @@ -11,7 +11,7 @@ pub(super) fn garage_slot_order_provider() -> GarageSlotsOrderProvider { async fn do_handling(params: ParameterTable<()>, user: &crate::UserTy) -> Result { let mut params = params.to_dict(); if let Some(Typed::Arr(order)) = params.remove(&SLOT_ORDER_PARAM_KEY) { - log::info!("Slot order is {}", order); + //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 { diff --git a/rc_services_room/src/operations/garage_upgrades.rs b/rc_services_room/src/operations/garage_upgrades.rs index e30b35a..4c448f8 100644 --- a/rc_services_room/src/operations/garage_upgrades.rs +++ b/rc_services_room/src/operations/garage_upgrades.rs @@ -1,25 +1,39 @@ -use polariton_server::operations::SimpleFunc; -use polariton::{operation::{Dict, ParameterTable, Typed}, serdes::TypePrefix}; +use polariton::operation::{ParameterTable, OperationResponse}; +use rc_core::ConfigProvider; + +const CODE: u8 = 1; const PARAM_KEY: u8 = 1; -pub(super) fn garage_upgrades_provider() -> SimpleFunc<1, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { - SimpleFunc::new(|params, _| { +pub(super) fn garage_upgrades_provider(conf: &rc_core::ConfigImpl) -> GarageUpgradesProvider { + GarageUpgradesProvider { + upgrades: >::garage_upgrades(conf), + } +} + +pub struct GarageUpgradesProvider { + upgrades: rc_core::persist::config::GarageUpgrades, +} + +impl GarageUpgradesProvider { + async fn do_handling(&self, params: ParameterTable) -> Result { let mut params = params.to_dict(); - params.insert(PARAM_KEY, Typed::HashMap(vec![ - (Typed::Str("cpuIncreaseCost".into()), Typed::Dict(Dict { - key_ty: TypePrefix::Int, // int - val_ty: TypePrefix::Int, // int - items: vec![ - // (CPU limit, upgrade cost) - (Typed::Int(100), Typed::Int(100)), - (Typed::Int(200), Typed::Int(200)), - (Typed::Int(1_000), Typed::Int(1_000)), - (Typed::Int(2_000), Typed::Int(2_000)), // max regular bot CPU - (Typed::Int(10_000), Typed::Int(10_000)), // max mega bot cpu - ], - })) - ].into())); + params.insert(PARAM_KEY, self.upgrades.slot_upgrades()); Ok(params.into()) - }) + } +} + +#[async_trait::async_trait] +impl polariton_server::operations::Operation<()> for GarageUpgradesProvider { + type User = crate::UserTy; + + async fn handle_async(&self, params: ParameterTable<()>, _user: &Self::User) -> OperationResponse<()> { + polariton_server::operations::result_to_op_resp::(self.do_handling(params).await) + } +} + +impl polariton_server::operations::OperationCode for GarageUpgradesProvider { + fn op_code() -> u8 { + CODE + } } diff --git a/rc_services_room/src/operations/mod.rs b/rc_services_room/src/operations/mod.rs index 85fed5c..2b7435f 100644 --- a/rc_services_room/src/operations/mod.rs +++ b/rc_services_room/src/operations/mod.rs @@ -84,6 +84,8 @@ mod garage_slot_limit; mod garage_slot_add; mod garage_slots_order; mod garage_slot_select; +mod garage_slot_dismantle; +mod garage_slot_upgrade; use polariton_server::operations::OperationsHandler; @@ -132,7 +134,7 @@ pub fn handler(init_ctx: &crate::InitConfig) -> OperationsHandler .add(avatar_info::get_avatar_provider()) .add(custom_game_session::get_custom_session_provider()) .add(user_xp::get_user_xp_provider()) - .add(garage_upgrades::garage_upgrades_provider()) + .add(garage_upgrades::garage_upgrades_provider(&init_ctx.cubes)) .add(game_event_params::event_system_params_provider()) .add(garage_bay_uuid::garage_id_provider()) .add(tech_tree_data::tech_tree_layout_provider(&init_ctx.cubes)) @@ -190,4 +192,6 @@ pub fn handler(init_ctx: &crate::InitConfig) -> OperationsHandler .add(garage_slot_add::garage_slot_add_provider()) .add(garage_slots_order::garage_slot_order_provider()) .add(garage_slot_select::garage_slot_selector()) + .add(garage_slot_dismantle::garage_slot_dismantler()) + .add(garage_slot_upgrade::garage_slot_upgrage_provider()) }