diff --git a/assets/robocraft/config.json b/assets/robocraft/config.json index 566d1c7..d315ed5 100644 --- a/assets/robocraft/config.json +++ b/assets/robocraft/config.json @@ -14535,4 +14535,4 @@ } ] } -} \ No newline at end of file +} diff --git a/rc_core/src/data/error_codes.rs b/rc_core/src/data/error_codes.rs index d024dc2..4bd23a9 100644 --- a/rc_core/src/data/error_codes.rs +++ b/rc_core/src/data/error_codes.rs @@ -60,3 +60,15 @@ pub enum ChatErrorCodes { PasswordRequired = 16, ChannelExpired = 17, } + +#[repr(i16)] +#[allow(dead_code)] +#[derive(Debug)] +pub enum SingleplayerErrorCode { + None = 0, + DatabaseError = 1, + UnexpectedError = 2, + WrongNumberOfAuthParams = 3, + MaintenanceMode = 4, + DuplicateLogin = 5, +} diff --git a/rc_core/src/data/mod.rs b/rc_core/src/data/mod.rs index 5f951be..4e83ee5 100644 --- a/rc_core/src/data/mod.rs +++ b/rc_core/src/data/mod.rs @@ -13,6 +13,7 @@ pub mod weapon_upgrade; pub mod crf; pub mod channel; pub mod sanction; +pub mod robot_data; pub mod error_codes; diff --git a/rc_services_room/src/data/robot_data.rs b/rc_core/src/data/robot_data.rs similarity index 93% rename from rc_services_room/src/data/robot_data.rs rename to rc_core/src/data/robot_data.rs index b85ff0a..0f4666b 100644 --- a/rc_services_room/src/data/robot_data.rs +++ b/rc_core/src/data/robot_data.rs @@ -10,7 +10,7 @@ pub struct PrebuiltRobotInfo { } impl PrebuiltRobotInfo { - pub fn as_transmissible(&self) -> Typed { + pub fn as_transmissible(&self) -> Typed { Typed::HashMap(vec![ //(Typed::Str("[key]".into()), Typed::Str(self.id.clone().into())), (Typed::Str("Name".into()), Typed::Str(self.name.clone().into())), diff --git a/rc_core/src/persist/combat.rs b/rc_core/src/persist/combat.rs index 80ba80c..21ccab9 100644 --- a/rc_core/src/persist/combat.rs +++ b/rc_core/src/persist/combat.rs @@ -9,7 +9,7 @@ pub struct BattleConfig { #[serde(default = "default_game_modes")] pub games: GameModes, #[serde(default = "default_campaigns")] - pub singleplayer: super::Campaigns, + pub singleplayer: super::SingleplayerConfig, #[serde(default = "default_rotation")] pub rotation: GameEventSequence, } @@ -252,8 +252,8 @@ fn default_game_modes() -> GameModes { } } -fn default_campaigns() -> super::Campaigns { - super::Campaigns { +pub(super) fn default_campaigns() -> super::SingleplayerConfig { + super::SingleplayerConfig { campaigns: vec![ super::Campaign { id: "strCampaignModeBattle".to_owned(), @@ -317,7 +317,24 @@ fn default_campaigns() -> super::Campaigns { } ], } - ] + ], + vehicles: vec![ + super::PrefabVehicle { + name: Some("Config your singleplayer!".to_owned()), + username: "NGnius".to_owned(), + id: super::PrefabId::Database { garage: 1 } + }, + super::PrefabVehicle { + name: Some("Config your singleplayer!".to_owned()), + username: "NGram".to_owned(), + id: super::PrefabId::Database { garage: 1 } + }, + super::PrefabVehicle { + name: Some("Config your singleplayer!".to_owned()), + username: "NGniusness".to_owned(), + id: super::PrefabId::Database { garage: 1 } + }, + ], } } diff --git a/rc_core/src/persist/config/cubes_json.rs b/rc_core/src/persist/config/cubes_json.rs index 63cfc63..280f6f2 100644 --- a/rc_core/src/persist/config/cubes_json.rs +++ b/rc_core/src/persist/config/cubes_json.rs @@ -30,7 +30,7 @@ impl CubeConfig { } #[async_trait::async_trait] -impl super::ConfigProvider for CubeConfig { +impl super::ConfigProvider for CubeConfig { fn cube_list(&self) -> Typed { Typed::Dict(Dict { key_ty: TypePrefix::Str, @@ -303,4 +303,55 @@ impl super::ConfigProvider for CubeConfig { started: chrono::Utc::now().timestamp(), } } + + fn singleplayer_vehicles(&self) -> Vec { + // FIXME don't use serializable types in traits + self.battle.singleplayer.vehicles.clone() + } + + /*async fn prefab_vehicles(&self, user: &(dyn crate::persist::user::User + Sync), factory: &crate::factory::Factory) -> Typed { + let mut next_id = 0; + let mut id_map = Vec::with_capacity(self.battle.singleplayer.vehicles.len()); + let mut debug_str_map = Vec::with_capacity(self.battle.singleplayer.vehicles.len()); + for vehicle in self.battle.singleplayer.vehicles.clone().into_iter() { + let current_id = next_id; + let uuid_i64 = crate::persist::user::uuid_sanitize(crate::persist::user::i64_join((i32::MAX as u32, current_id))); + let uuid_str = crate::persist::user::i64_as_uuid_str(uuid_i64); + let prebuilt = match &vehicle.id { + crate::persist::PrefabId::Factory { factory: factory_id } => { + use rc_factory::VehicleFactoryAdapter; + let factory_vehicle = factory.vehicle(*factory_id).await + .expect("Failed to retrieve prefab vehicle from factory") // result + .expect("Prefab vehicle does not exist in factory"); // option + crate::data::robot_data::PrebuiltRobotInfo { + name: vehicle.name.unwrap_or(factory_vehicle.1.name), + class: vehicle.class, + category: "RE_robot_category0".to_owned(), + robot_data: factory_vehicle.0.cube_data, + colour_data: factory_vehicle.0.colour_data, + } + }, + crate::persist::PrefabId::Database { garage } => { + let db_vehicle = user.garage_by_id(*garage).await + .expect("Prefab vehicle does not exist in main garage database"); + crate::data::robot_data::PrebuiltRobotInfo { + name: vehicle.name.unwrap_or(db_vehicle.name.expect("Prefab vehicle name is required")), + class: vehicle.class, + category: "RE_robot_category0".to_owned(), + robot_data: db_vehicle.robot_data, + colour_data: db_vehicle.colour_data, + } + }, + }; + debug_str_map.push(format!("`{}` -> `{}`", uuid_str, prebuilt.name)); + id_map.push((Typed::Str(uuid_str.into()), prebuilt.as_transmissible())); + next_id += 1; + } + log::debug!("Prefab mapping generated `` -> ``:\n\t{}", debug_str_map.join("\n\t")); + Typed::Dict(Dict { + key_ty: TypePrefix::Str, // str + val_ty: TypePrefix::HashMap, // hashmap + items: id_map, + }) + }*/ } diff --git a/rc_core/src/persist/config/traits.rs b/rc_core/src/persist/config/traits.rs index 27746e6..498f3ad 100644 --- a/rc_core/src/persist/config/traits.rs +++ b/rc_core/src/persist/config/traits.rs @@ -25,6 +25,8 @@ pub trait ConfigProvider { fn cubes(&self) -> &'_ std::collections::HashMap; fn chat_system_config(&self) -> ChatSystemConfig; fn gamemode_events(&self) -> GameEventSequence; + // FIXME don't use serializable types in traits + fn singleplayer_vehicles(&self) -> Vec; } pub struct CompleteCampaignProvider { diff --git a/rc_core/src/persist/garage.rs b/rc_core/src/persist/garage.rs index 8c5b777..64b7dbf 100644 --- a/rc_core/src/persist/garage.rs +++ b/rc_core/src/persist/garage.rs @@ -176,3 +176,24 @@ impl std::convert::Into for GarageContr } } } + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct PrefabVehicle { + pub name: Option, + pub username: String, + #[serde(flatten)] + pub id: PrefabId, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(untagged)] +pub enum PrefabId { + Factory { + #[serde(alias="crf")] + factory: u32, + }, + Database { + garage: u32, + }, + // TODO File, Raw +} diff --git a/rc_core/src/persist/mod.rs b/rc_core/src/persist/mod.rs index daecb4c..217623a 100644 --- a/rc_core/src/persist/mod.rs +++ b/rc_core/src/persist/mod.rs @@ -6,7 +6,7 @@ pub use cube_data::{Cube, ItemTier, ItemCategory, ItemType}; //pub use cube_data::{VisibilityMode, ItemType}; mod garage; -pub use garage::{GarageSlot, GarageControls, ControlType}; +pub use garage::{GarageSlot, GarageControls, ControlType, PrefabVehicle, PrefabId}; mod movement; pub use movement::{MovementCategoryData, MovementData}; @@ -21,7 +21,7 @@ mod combat; pub use combat::BattleConfig; mod singleplayer; -pub use singleplayer::{Campaigns, Campaign, CampaignDifficulty, CampaignCompletion, CampaignType, Wave, WaveRobot}; +pub use singleplayer::{SingleplayerConfig, Campaign, CampaignDifficulty, CampaignCompletion, CampaignType, Wave, WaveRobot}; mod client_config; pub use client_config::GameplaySettings; diff --git a/rc_core/src/persist/singleplayer.rs b/rc_core/src/persist/singleplayer.rs index 14a93a0..0a1e1c7 100644 --- a/rc_core/src/persist/singleplayer.rs +++ b/rc_core/src/persist/singleplayer.rs @@ -1,11 +1,13 @@ use serde::{Serialize, Deserialize}; #[derive(Serialize, Deserialize, Clone, Debug)] -pub struct Campaigns { +pub struct SingleplayerConfig { + #[serde(default = "default_campaigns")] pub campaigns: Vec, + pub vehicles: Vec, } -impl Campaigns { +impl SingleplayerConfig { pub fn into_campaign_params(self) -> crate::data::campaign::CampaignsGameParameters { crate::data::campaign::CampaignsGameParameters { campaigns: self.campaigns.into_iter().map(|x| x.into_campaign_params()).collect() } } @@ -222,3 +224,7 @@ impl std::convert::Into for CampaignType { } } } + +fn default_campaigns() -> Vec { + super::combat::default_campaigns().campaigns +} diff --git a/rc_core/src/persist/user/account_json.rs b/rc_core/src/persist/user/account_json.rs index cc36d53..6a4cd57 100644 --- a/rc_core/src/persist/user/account_json.rs +++ b/rc_core/src/persist/user/account_json.rs @@ -5,6 +5,7 @@ use crate::persist::config::ConfigProvider; pub struct AccountProvider { cubes: std::sync::Arc>, garage_upgrades: std::sync::Arc, + singleplayer_vehicles: std::sync::Arc>, auto_signups: bool, secret: Vec, db: std::sync::Arc, @@ -21,11 +22,41 @@ impl AccountProvider { Ok(Self { cubes: std::sync::Arc::new(>::ids(conf)), garage_upgrades: std::sync::Arc::new(>::garage_upgrades(conf)), + singleplayer_vehicles: std::sync::Arc::new(>::singleplayer_vehicles(conf)), auto_signups: server_settings.auto_signup, secret: std::fs::read(&token_path)?, db: std::sync::Arc::new(db), }) } + + pub fn fake_user(&self) -> Box + Send + Sync> { + Box::new(UserData { + token: super::UserToken { uuid: "fake user!".to_owned(), token: "".to_owned(), refresh_token: "".to_owned() }, + account: rc_database::schema::user::Model { + id: 0, + creation_time: 0, + public_id: "".to_owned(), + display_name: "".to_owned(), + password: "".to_owned(), + email: "".to_owned(), + steam_id: None, + }, + perms: rc_database::schema::permissions::Model { + id: 0, + user_id: 0, + moderator: true, + administrator: true, + developer: true, + royalty: false, + banned: false, + }, + cubes: self.cubes.clone(), + garage_upgrades: self.garage_upgrades.clone(), + singleplayer_vehicles: self.singleplayer_vehicles.clone(), + extensions: Default::default(), + db: self.db.clone(), + }) + } } #[async_trait::async_trait] @@ -53,6 +84,7 @@ impl super::UserProvider for AccountProvider { perms: user_perms, cubes: self.cubes.clone(), garage_upgrades: self.garage_upgrades.clone(), + singleplayer_vehicles: self.singleplayer_vehicles.clone(), extensions: ext, db: self.db.clone(), })) @@ -163,6 +195,7 @@ struct UserData { perms: rc_database::schema::permissions::Model, cubes: std::sync::Arc>, garage_upgrades: std::sync::Arc, + singleplayer_vehicles: std::sync::Arc>, extensions: std::collections::HashMap>, db: std::sync::Arc, } @@ -225,6 +258,105 @@ impl UserData { fn has_admin_or_better_perms(&self) -> bool { self.perms.administrator | self.perms.developer } + + async fn resolve_some_singleplayer_vehicles(&self, factory: &dyn rc_factory::VehicleFactoryAdapter, weapon_order: &crate::cubes::WeaponListParser) -> Result, i16> { + use rand::seq::IndexedRandom; + let mut enemies = Vec::with_capacity(5); + let mut next_id = 0; + let mut seen_usernames = std::collections::HashSet::::new(); + for _ in 0..5 { + let vehicle = self.singleplayer_vehicles.choose(&mut rand::rng()) + .ok_or(crate::data::error_codes::SingleplayerErrorCode::UnexpectedError as i16)?; + let current_id = next_id; + let uuid_i64 = crate::persist::user::uuid_sanitize(crate::persist::user::i64_join((i32::MAX as u32, current_id))); + let uuid_str = crate::persist::user::i64_as_uuid_str(uuid_i64); + let username = if seen_usernames.contains(&vehicle.username) { + let mut username = vehicle.username.clone(); + while seen_usernames.contains(&username) { + username = format!("{}{}", username, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].choose(&mut rand::rng()).unwrap()); + } + username + } else { + vehicle.username.clone() + }; + seen_usernames.insert(username.clone()); + let enemy = match &vehicle.id { + crate::persist::PrefabId::Factory { factory: factory_id } => { + //use rc_factory::VehicleFactoryAdapter; + match factory.vehicle(*factory_id).await { + Ok(Some(factory_vehicle)) => { + let weapons_guess = weapon_order.guess_weapons(&mut std::io::Cursor::new(&factory_vehicle.0.cube_data)); + let weapons_guess = vec![weapons_guess[0], 0, 0]; + let weapon_ranks = weapons_guess.iter().map(|&x| (x, if x == 0 { 0 } else { 1 })).collect(); + crate::data::player_data::PlayerData { + name: username.clone(), + display_name: username.clone(), + mastery: 1, + tier: 1, // FIXME + robot_name: vehicle.name.clone().unwrap_or_else(|| factory_vehicle.1.name.clone()), + robot_map: factory_vehicle.0.cube_data, + team: 1, + has_premium: false, + robot_uuid: uuid_str, + cpu: 420, + weapon_order: weapons_guess, + colour_map: factory_vehicle.0.colour_data, + is_ai: true, + spawn_effect: "Spawn".to_owned(), + death_effect: "Explosion".to_owned(), + player_rank: 1, + weapon_rank: weapon_ranks, + } + }, + Ok(None) => { + log::error!("Prefab vehicle {} does not exist in factory", factory_id); + return Err(crate::data::error_codes::SingleplayerErrorCode::UnexpectedError as i16); + }, + Err(e) => { + log::error!("Failed to retrieve prefab vehicle {} from factory: {}", factory_id, e); + return Err(crate::data::error_codes::SingleplayerErrorCode::DatabaseError as i16); + } + } + }, + crate::persist::PrefabId::Database { garage } => { + match self.db.garage_by_id(*garage).await { + Ok(Some(db_vehicle)) => { + crate::data::player_data::PlayerData { + name: username.clone(), + display_name: username.clone(), + mastery: 1, + tier: 1, // FIXME + robot_name: vehicle.name.clone().unwrap_or_else(|| db_vehicle.name.clone()), + robot_map: db_vehicle.robot_data, + team: 1, + has_premium: false, + robot_uuid: uuid_str, + cpu: db_vehicle.total_robot_cpu as i32, + weapon_order: rc_database::schema::parse_int_csv(&db_vehicle.weapon_order).into_iter().map(|x| x as i32).collect::>(), + colour_map: db_vehicle.colour_data, + is_ai: true, + spawn_effect: "Spawn".to_owned(), + death_effect: "Explosion".to_owned(), + player_rank: 1, + weapon_rank: rc_database::schema::parse_int_csv(&db_vehicle.weapon_order).into_iter().map(|x| (x as i32, if x == 0 { 0 } else { 1 })).collect(), + } + }, + Ok(None) => { + log::error!("Prefab vehicle {} does not exist in main garage database", garage); + return Err(crate::data::error_codes::SingleplayerErrorCode::UnexpectedError as i16); + } + Err(e) => { + log::error!("Failed to retrieve prefab vehicle {} from main garage database: {}", garage, e); + return Err(crate::data::error_codes::SingleplayerErrorCode::DatabaseError as i16); + } + } + }, + }; + next_id += 1; + enemies.push(enemy); + } + Ok(enemies) + } } const INVALID_ROBOT_ERR: i16 = crate::data::error_codes::WebServicesError::InvalidRobot as i16; // 140 @@ -539,8 +671,9 @@ impl super::User for UserData { super::since_windows_epoch(self.account.creation_time) } - async fn singleplayer_robots(&self) -> Result, i16> { - self.err_on_banned().await?; + async fn singleplayer_robots(&self, factory: &dyn rc_factory::VehicleFactoryAdapter, weapon_order: &crate::cubes::WeaponListParser) -> Result, i16> { + //self.err_on_banned().await?; + let mut vehicles = self.resolve_some_singleplayer_vehicles(factory, weapon_order).await?; let current_slot = self.db.garage_selected(self.account.id).await.map_err(|e| { log::error!("Failed to retrieve selected vehicle for user_id {} (singleplayer_robots): {}", self.account.id, e); DATABASE_ERR @@ -550,28 +683,30 @@ impl super::User for UserData { INVALID_ROBOT_ERR })?; let user_uuid = self.token.uuid.clone(); + let weapon_order = rc_database::schema::parse_int_csv(¤t_slot.weapon_order).into_iter().map(|x| x as i32).collect::>(); + + // real user MUST be last + vehicles.push(crate::data::player_data::PlayerData { + name: user_uuid.clone(), + display_name: self.account.display_name.clone(), + mastery: current_slot.mastery_level as i32, + tier: 1, // FIXME + robot_name: current_slot.name, + robot_map: current_slot.robot_data.clone(), + team: 0, + has_premium: false, // FIXME + robot_uuid: super::i64_as_uuid_str(current_slot.uuid).into(), + cpu: current_slot.total_robot_cpu as i32, + weapon_order: weapon_order.clone(), + colour_map: current_slot.colour_data.clone(), + is_ai: false, + spawn_effect: "Spawn_Warp".to_owned(), // FIXME + death_effect: "Explosion_Warp".to_owned(), // FIXME + player_rank: 1, // FIXME + weapon_rank: rc_database::schema::parse_int_csv(¤t_slot.weapon_order).into_iter().map(|x| (x as i32, if x == 0 { 0 } else { 1 })).collect(), + }); Ok(crate::data::player_data::PlayerDatas { - players: vec![ - crate::data::player_data::PlayerData { - name: user_uuid.clone(), - display_name: self.account.display_name.clone(), - mastery: current_slot.mastery_level as i32, - tier: 1, // FIXME - robot_name: current_slot.name, - robot_map: current_slot.robot_data, - team: 0, - has_premium: true, // FIXME - robot_uuid: super::i64_as_uuid_str(current_slot.uuid).into(), - cpu: current_slot.total_robot_cpu as i32, - weapon_order: rc_database::schema::parse_int_csv(¤t_slot.weapon_order).into_iter().map(|x| x as i32).collect::>(), - colour_map: current_slot.colour_data, - is_ai: false, - spawn_effect: "Spawn_Warp".to_owned(), // FIXME - death_effect: "Explosion_Warp".to_owned(), // FIXME - player_rank: 1, // FIXME - weapon_rank: rc_database::schema::parse_int_csv(¤t_slot.weapon_order).into_iter().map(|x| (x as i32, if x == 0 { 0 } else { 1 })).collect(), - } - ], + players: vehicles, }.as_transmissible()) } diff --git a/rc_core/src/persist/user/traits.rs b/rc_core/src/persist/user/traits.rs index 5e0c9f8..3c7e6ab 100644 --- a/rc_core/src/persist/user/traits.rs +++ b/rc_core/src/persist/user/traits.rs @@ -73,7 +73,7 @@ pub trait User: ChatUser { async fn save_slot_customisations(&self, customs: CustomisationData) -> Result<(), i16>; async fn get_slot_customisations(&self, uuid: &str) -> Result, i16>; fn signup_date(&self) -> i64; - async fn singleplayer_robots(&self) -> Result, i16>; + async fn singleplayer_robots(&self, factory: &dyn rc_factory::VehicleFactoryAdapter, weapon_order: &crate::cubes::WeaponListParser) -> Result, i16>; async fn prepare_factory_upload(&self, vehicle: VehicleUploadData) -> Result; async fn last_seen(&self) -> Result; async fn get_avatar_info(&self) -> Result, i16>; diff --git a/rc_database/src/wrapper.rs b/rc_database/src/wrapper.rs index ed78308..1392ccb 100644 --- a/rc_database/src/wrapper.rs +++ b/rc_database/src/wrapper.rs @@ -165,6 +165,12 @@ impl Database { .await } + pub async fn garage_by_id(&self, id: u32) -> Result, sea_orm::DbErr> { + crate::schema::garage::Entity::find_by_id(id) + .one(&self.orm) + .await + } + pub async fn insert_garages(&self, entities: Vec) -> Result<(), sea_orm::DbErr> { crate::schema::garage::Entity::insert_many(entities.into_iter()).exec(&self.orm).await?; Ok(()) diff --git a/rc_factory/src/arc/adapter.rs b/rc_factory/src/arc/adapter.rs index 9029103..12cfae3 100644 --- a/rc_factory/src/arc/adapter.rs +++ b/rc_factory/src/arc/adapter.rs @@ -68,7 +68,7 @@ impl crate::VehicleFactoryAdapter for ArcAdapter { banner_message: Default::default(), combat_rating: meta.combat_rating, cosmetic_rating: meta.cosmetic_rating, - cube_amounts: Default::default(), + cube_amounts: Default::default(), // FIXME parse cube amounts } ))) } else { diff --git a/rc_services_room/src/data/mod.rs b/rc_services_room/src/data/mod.rs index 43af8bb..9d99c47 100644 --- a/rc_services_room/src/data/mod.rs +++ b/rc_services_room/src/data/mod.rs @@ -19,7 +19,7 @@ pub mod item_shop_bundle; pub mod player_robopass_season; //pub use rc_core::data::weapon_upgrade; pub mod player_rank; -pub mod robot_data; +// pub use rc_core::data::robot_data; pub mod quest; //pub use rc_core::data::auto_regen; //pub use rc_core::data::voting; diff --git a/rc_services_room/src/operations/prebuilt_robots.rs b/rc_services_room/src/operations/prebuilt_robots.rs index 601c9b4..2b229c5 100644 --- a/rc_services_room/src/operations/prebuilt_robots.rs +++ b/rc_services_room/src/operations/prebuilt_robots.rs @@ -1,7 +1,7 @@ use polariton_server::operations::SimpleFunc; use polariton::{operation::{Dict, ParameterTable, Typed}, serdes::TypePrefix}; -use crate::data::robot_data::*; +use rc_core::data::robot_data::*; const PARAM_KEY: u8 = 1; diff --git a/rc_singleplayer_room/src/main.rs b/rc_singleplayer_room/src/main.rs index 77f39ee..107edbe 100644 --- a/rc_singleplayer_room/src/main.rs +++ b/rc_singleplayer_room/src/main.rs @@ -10,6 +10,13 @@ use tokio::net; use polariton::packet::{Data, Message, Packet, StandardMessage}; use polariton::operation::{OperationResponse, Typed}; +pub struct InitConfig { + pub cubes: rc_core::persist::config::ConfigImpl, + pub users: std::sync::Arc, + pub factory: std::sync::Arc, + pub parsers: rc_core::cubes::CubeParsers, +} + pub type UserTy = rc_core::UserState<()>; #[tokio::main] @@ -20,8 +27,17 @@ async fn main() -> std::io::Result<()> { let cubes = rc_core::persist::config::ConfigImpl::load(&args.assets).expect("Bad config data"); let users = std::sync::Arc::new(rc_core::persist::user::UserImpl::load(&args.data, &cubes).await.expect("Bad user data")); + let factory = std::sync::Arc::new(>::factory::<'_, '_>(&cubes).await.expect("Bad vehicle factory (CRF) config")); + let parsers = rc_core::cubes::CubeParsers::new(&cubes); - let server = std::sync::Arc::new(polariton_server::Server::new(operations::handler(), polariton_server::events::EventsHandler::new())); + let init_ctx = InitConfig { + cubes, + users, + factory, + parsers, + }; + + let server = std::sync::Arc::new(polariton_server::Server::new(operations::handler(&init_ctx), polariton_server::events::EventsHandler::new())); let ip_addr: std::net::IpAddr = args.ip.parse().expect("Invalid IP address"); @@ -30,11 +46,11 @@ async fn main() -> std::io::Result<()> { if args.once { log::warn!("Handling first connection and then exiting"); let (socket, address) = listener.accept().await?; - process_socket(socket, address, server.clone(), users.clone()).await; + process_socket(socket, address, server.clone(), init_ctx.users.clone()).await; } else { loop { let (socket, address) = listener.accept().await?; - tokio::spawn(process_socket(socket, address, server.clone(), users.clone())); + tokio::spawn(process_socket(socket, address, server.clone(), init_ctx.users.clone())); } } server.join(); diff --git a/rc_singleplayer_room/src/operations/load_ai_robots.rs b/rc_singleplayer_room/src/operations/load_ai_robots.rs index dcba960..a4346cb 100644 --- a/rc_singleplayer_room/src/operations/load_ai_robots.rs +++ b/rc_singleplayer_room/src/operations/load_ai_robots.rs @@ -1,26 +1,29 @@ -use polariton::operation::{ParameterTable, Typed, OperationResponse}; +use polariton::operation::{ParameterTable, OperationResponse}; const CODE: u8 = 1; const PARAM_KEY: u8 = 8; -pub(super) fn tdm_machines_provider() -> AiRobots { - AiRobots +pub(super) fn tdm_machines_provider(factory: &std::sync::Arc, weapon_order: std::sync::Arc) -> AiRobots { + AiRobots { + factory: factory.to_owned(), + weapon_parser: weapon_order, + } } -async fn do_handling(params: ParameterTable<()>, user: &crate::UserTy) -> Result, i16> { +async fn do_handling(params: ParameterTable<()>, user: &crate::UserTy, factory: &rc_core::factory::Factory, weapon_order: &rc_core::cubes::WeaponListParser) -> Result, i16> { let ulock = user.user()?; let mut params = params.to_dict(); - params.insert(PARAM_KEY, ulock.singleplayer_robots().await?); - let event_tx = user.event_sender(); + params.insert(PARAM_KEY, ulock.singleplayer_robots(factory, weapon_order).await?); + /*let event_tx = user.event_sender(); let user_bot_data = ulock.slot_by_id(ulock.selected_garage().await.1 as _).await?; tokio::spawn(async move { tokio::time::sleep(std::time::Duration::from_secs(20)).await; log::debug!("Sending singleplayer event"); let mut spawn_params = std::collections::HashMap::with_capacity(4); - spawn_params.insert(2 /* robot GUID */, Typed::Str("1337_1337".into())); + spawn_params.insert(2 /* robot GUID */, user_bot_data.uuid); spawn_params.insert(3 /* machine model */, user_bot_data.data); - spawn_params.insert(4 /* robot name */, Typed::Str("RE_robot_spawn_name0".into())); // FIXME + spawn_params.insert(4 /* robot name */, Typed::Str("Robot123".into())); // FIXME spawn_params.insert(7 /* color model */, user_bot_data.colour_data); event_tx.send(polariton_server::ToSend::Data { data: polariton::packet::Data::Event(polariton::operation::Event { code: 3, params: spawn_params.into() }), @@ -36,18 +39,21 @@ async fn do_handling(params: ParameterTable<()>, user: &crate::UserTy) -> Result channel: 0, reliable: true, }).unwrap();*/ - }); + });*/ Ok(params.into()) } -pub struct AiRobots; +pub struct AiRobots { + factory: std::sync::Arc, + weapon_parser: std::sync::Arc, +} #[async_trait::async_trait] impl polariton_server::operations::Operation<()> for AiRobots { 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) + polariton_server::operations::result_to_op_resp::(do_handling(params, user, self.factory.as_ref(), self.weapon_parser.as_ref()).await) } } diff --git a/rc_singleplayer_room/src/operations/mod.rs b/rc_singleplayer_room/src/operations/mod.rs index 92fefa0..2d28f85 100644 --- a/rc_singleplayer_room/src/operations/mod.rs +++ b/rc_singleplayer_room/src/operations/mod.rs @@ -4,11 +4,11 @@ mod load_ai_robots; use polariton_server::operations::OperationsHandler; -pub fn handler() -> OperationsHandler { +pub fn handler(init_ctx: &crate::InitConfig) -> OperationsHandler { OperationsHandler::::new() .modify(rc_core::polariton::OpIdCopy) .add(more_auth::MoreLobbyAuth) .add(eac::EacChallengeIgnorer) - .add(load_ai_robots::tdm_machines_provider()) + .add(load_ai_robots::tdm_machines_provider(&init_ctx.factory, init_ctx.parsers.weapon_order())) //.add(polariton_server::operations::Ack::<33, _>::default()) // get user clan info (this is equivalent to not being in a clan) }