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

Add upgrade and dismantle vehicle slot functionality for #14

This commit is contained in:
NG (Graham)
2025-05-11 12:09:23 -04:00
parent 221a5d5ca9
commit b04a8902e2
11 changed files with 222 additions and 22 deletions

View File

@@ -261,4 +261,13 @@ impl <C: Clone> super::ConfigProvider<C> 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(),
}
}
}

View File

@@ -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;

View File

@@ -19,6 +19,7 @@ pub trait ConfigProvider<C: Clone> {
fn login_messages(&self) -> DevMessageProvider<C>;
fn public_channels(&self) -> Typed<C>;
fn server_config(&self) -> ServerConfig;
fn garage_upgrades(&self) -> GarageUpgrades;
}
pub struct CompleteCampaignProvider {
@@ -88,3 +89,27 @@ pub struct TypedDevMessage<C> {
pub struct ServerConfig {
pub database: String,
}
#[derive(Clone, Debug)]
pub struct GarageUpgrades {
pub increments: Vec<GarageUpgradeIncrement>,
}
#[derive(Clone, Debug)]
pub struct GarageUpgradeIncrement {
pub cpu: u32,
pub cost: u32,
}
impl GarageUpgrades {
pub fn slot_upgrades<C>(&self) -> Typed<C> {
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())
}
}

View File

@@ -6,6 +6,8 @@ pub struct Settings {
pub gameplay: super::GameplaySettings,
#[serde(default = "default_dev_messages")]
pub banners: Vec<BannerMessage>,
#[serde(default = "default_slot_upgrades")]
pub garage_upgrades: Vec<GarageSlotUpgrade>,
#[serde(default = "default_server_conf")]
pub server: ServerSettings,
}
@@ -35,6 +37,37 @@ fn default_dev_messages() -> Vec<BannerMessage> {
Vec::default()
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct GarageSlotUpgrade {
pub cpu: u32,
pub cost: u32,
}
fn default_slot_upgrades() -> Vec<GarageSlotUpgrade> {
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")]

View File

@@ -4,6 +4,7 @@ use crate::persist::config::ConfigProvider;
pub struct AccountProvider {
cubes: std::sync::Arc<Vec<u32>>,
garage_upgrades: std::sync::Arc<crate::persist::config::GarageUpgrades>,
secret: Vec<u8>,
db: std::sync::Arc<rc_database::Database>,
}
@@ -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(<crate::persist::config::ConfigImpl as ConfigProvider<()>>::ids(conf)),
garage_upgrades: std::sync::Arc::new(<crate::persist::config::ConfigImpl as ConfigProvider<()>>::garage_upgrades(conf)),
secret: std::fs::read(&token_path)?,
db: std::sync::Arc::new(db),
})
@@ -47,6 +49,7 @@ impl <C: Clone> super::UserProvider<C> 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<Vec<u32>>,
garage_upgrades: std::sync::Arc<crate::persist::config::GarageUpgrades>,
extensions: std::collections::HashMap<std::any::TypeId, Box<dyn std::any::Any + Send + Sync + 'static>>,
db: std::sync::Arc<rc_database::Database>,
}
@@ -354,6 +358,45 @@ impl <C: Clone> super::User<C> for UserData {
})
}
async fn upgrade_slot(&self, increments: i32) -> Result<polariton::operation::Typed<C>, 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)
}

View File

@@ -50,6 +50,7 @@ pub trait User<C> {
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>;
async fn upgrade_slot(&self, increments: i32) -> Result<polariton::operation::Typed<C>, i16>;
fn signup_date(&self) -> i64;
async fn singleplayer_robots(&self) -> Result<polariton::operation::Typed<C>, i16>;
}