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:
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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>,
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,4 +39,5 @@ pub enum Descriptor {
|
||||
UserRank, // u32
|
||||
UserFreeCurrency, // u64
|
||||
UserPaidCurrency, // u64
|
||||
GarageSlotOrder, // Vec<u32>,
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
52
rc_services_room/src/operations/garage_slot_add.rs
Normal file
52
rc_services_room/src/operations/garage_slot_add.rs
Normal 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
|
||||
}
|
||||
}
|
||||
14
rc_services_room/src/operations/garage_slot_limit.rs
Normal file
14
rc_services_room/src/operations/garage_slot_limit.rs
Normal 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()
|
||||
})
|
||||
}
|
||||
35
rc_services_room/src/operations/garage_slot_select.rs
Normal file
35
rc_services_room/src/operations/garage_slot_select.rs
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
42
rc_services_room/src/operations/garage_slots_order.rs
Normal file
42
rc_services_room/src/operations/garage_slots_order.rs
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user