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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user