diff --git a/rc_core/src/persist/combat.rs b/rc_core/src/persist/combat.rs index 0dd71f8..1156348 100644 --- a/rc_core/src/persist/combat.rs +++ b/rc_core/src/persist/combat.rs @@ -384,13 +384,18 @@ pub(super) fn default_campaigns() -> super::SingleplayerConfig { player_spawn_location: 0, robots_in_wave: vec![ super::WaveRobot { - name: "strCampaignAnimalName".to_owned(), + vehicle: super::PrefabVehicle { + name: Some("strCampaignAnimalName".to_owned()), + username: "[ignored]".to_owned(), + id: super::PrefabId::Raw { + cube_data: super::VALID_ROBOT.into(), + colour_data: super::VALID_COLOUR.into(), + }, + }, weapon: "strT5PlasmaGoldenName".to_owned(), movement: "strT5SteeringWheelGoldenName".to_owned(), rank: "strT0".to_owned(), count: 5, - robot_data: super::VALID_ROBOT.into(), - colour_data: super::VALID_COLOUR.into(), time_to_spawn: 1, kills_to_spawn: 0, time_to_despawn: 60, @@ -442,22 +447,37 @@ fn default_rotation() -> GameEventSequence { GameEventSequence { strategy: GameRotationStrategy::Sequence, modes: vec![ + GameEvents { + singleplayer: GameEvent { + map: GameMap::Earth1, + visibility: GameVisibility::Good, + mode: GameType::BattleArena, + auto_heal: true, + }, + multiplayer: GameEvent { + map: GameMap::Earth1, + visibility: GameVisibility::Good, + mode: GameType::BattleArena, + auto_heal: true, + }, + duration_s: 30, + }, + GameEvents { + singleplayer: GameEvent { + map: GameMap::Earth1, + visibility: GameVisibility::Good, + mode: GameType::BattleArena, + auto_heal: true, + }, + multiplayer: GameEvent { + map: GameMap::Earth2, + visibility: GameVisibility::Good, + mode: GameType::BattleArena, + auto_heal: true, + }, + duration_s: 30, // 30 seconds + }, /*GameEvents { - singleplayer: GameEvent { - map: GameMap::Earth1, - visibility: GameVisibility::Good, - mode: GameType::BattleArena, - auto_heal: true, - }, - multiplayer: GameEvent { - map: GameMap::Earth1, - visibility: GameVisibility::Good, - mode: GameType::Pit, - auto_heal: true, - }, - duration_s: 5*60, // 5 minutes - }*/ - GameEvents { singleplayer: GameEvent { map: GameMap::Neptune1, visibility: GameVisibility::Good, @@ -576,14 +596,14 @@ fn default_rotation() -> GameEventSequence { auto_heal: true, }, duration_s: 5*60, - }, + },*/ ] } } fn default_multiplayer() -> super::MultiplayerConfig { super::MultiplayerConfig { - players_per_game: 1, + players_per_game: 2, enabled: true, network: super::multiplayer::default_net_conf(), fakes: super::multiplayer::default_fake_users(), diff --git a/rc_core/src/persist/config/campaign.rs b/rc_core/src/persist/config/campaign.rs new file mode 100644 index 0000000..b6aa60d --- /dev/null +++ b/rc_core/src/persist/config/campaign.rs @@ -0,0 +1,130 @@ +use polariton::operation::Typed; + +pub(super) struct CompleteCampaignData { + pub(super) difficulty_map: std::collections::HashMap, + pub(super) waves: Vec, +} + +pub struct CompleteCampaignProvider { + map: std::collections::HashMap, +} + +impl CompleteCampaignProvider { + pub(super) fn new(map: std::collections::HashMap) -> Self { + Self { map } + } + + pub async fn get( + &self, + id: &str, + difficulty: &i32, + user: &dyn crate::persist::user::CommonUser, + factory: &dyn oj_rc_factory::VehicleFactoryAdapter, + weapon_order: &crate::cubes::WeaponListParser, + cpu_counter: &crate::cubes::CpuListParser, + ) -> Result, i16> { + if let Some(campaign) = self.map.get(id) { + if let Some(difficulty_conf) = campaign.difficulty_map.get(difficulty) { + let mut waves = Vec::with_capacity(campaign.waves.len()); + for wave in campaign.waves.iter() { + let mut vehicles = Vec::with_capacity(wave.robots_in_wave.len()); + for vehicle in wave.robots_in_wave.iter() { + let resolved = user.resolve_config_vehicle(&vehicle.vehicle.into_conf(), factory, weapon_order, cpu_counter).await?; + vehicles.push(crate::data::campaign::CompleteWaveRobotData { + name: resolved.robot_name, + robot_data: resolved.robot_map, + colour_data: resolved.colour_map, + time_to_spawn: vehicle.time_to_spawn, + kills_to_spawn: vehicle.kills_to_spawn, + time_to_despawn: vehicle.time_to_despawn, + kills_to_despawn: vehicle.kills_to_despawn, + initial_robot_amount: vehicle.initial_robot_amount, + periodic_robot_amount: vehicle.periodic_robot_amount, + spawn_interval: vehicle.spawn_interval, + min_robot_amount: vehicle.min_robot_amount, + max_robot_amount: vehicle.max_robot_amount, + is_boss: vehicle.is_boss, + is_kill_requirement: vehicle.is_kill_requirement, + }); + } + waves.push(crate::data::campaign::CompleteWaveData { + player_spawn_location: wave.player_spawn_location, + robots_in_wave: vehicles, + kill_target: wave.kill_target, + time_min: wave.time_min, + time_max: wave.time_max, + }); + } + let details_data = crate::data::campaign::CampaignWavesDifficultyData { + difficulty: difficulty_conf.clone().into(), + waves, + }; + Ok(details_data.as_transmissible()) + } else { + log::warn!("Couldn't find difficulty {} in campaign `{}`", difficulty, id); + Err(crate::data::error_codes::WebServicesError::DatabaseError as i16) + } + } else { + log::warn!("Couldn't find campaign {} (ignoring difficulty {})", id, difficulty); + Err(crate::data::error_codes::WebServicesError::DatabaseError as i16) + } + } +} + +pub struct CampaignResolver { + pub(super) singleplayer: crate::persist::SingleplayerConfig, +} + +impl CampaignResolver { + pub fn campaigns_parameters(&self) -> Typed { + self.singleplayer.clone().into_campaign_params().as_transmissible() + } + + pub async fn campaign_waves( + &self, + user: &dyn crate::persist::user::CommonUser, + factory: &dyn oj_rc_factory::VehicleFactoryAdapter, + weapon_order: &crate::cubes::WeaponListParser, + cpu_counter: &crate::cubes::CpuListParser, + ) -> Result, polariton_server::operations::SimpleOpError> { + let mut campaigns = Vec::with_capacity(self.singleplayer.campaigns.len()); + for campaign in self.singleplayer.campaigns.iter() { + let mut waves = Vec::with_capacity(campaign.waves.len()); + for wave in campaign.waves.iter() { + let mut vehicles = Vec::with_capacity(wave.robots_in_wave.len()); + for robot in wave.robots_in_wave.iter() { + let resolved = user.resolve_config_vehicle(&robot.vehicle.into_conf(), factory, weapon_order, cpu_counter).await?; + vehicles.push(crate::data::campaign::WaveRobotData { + name: resolved.robot_name, + weapon: robot.weapon.clone(), + movement: robot.movement.clone(), + rank: robot.rank.clone(), + count: robot.count, + }); + } + waves.push(crate::data::campaign::WaveData { + robots_in_wave: vehicles, + }); + } + campaigns.push(crate::data::campaign::WavesData { + id: campaign.id.clone(), + waves, + campaign_type: campaign.campaign_type.into(), + }); + } + Ok(crate::data::campaign::LiveCampaignWaves { + waves: campaigns, + }.as_transmissible()) + } + + pub fn campaign_version(&self) -> Typed { + let mut locked_map = std::collections::HashMap::with_capacity(self.singleplayer.campaigns.len()); + for campaign in self.singleplayer.campaigns.iter() { + locked_map.insert(campaign.id.clone(), true); + } + crate::data::campaign::GameModeVersionParameters { + current_version: 0, + is_locked: locked_map, + }.as_transmissible() + } +} diff --git a/rc_core/src/persist/config/cubes_json.rs b/rc_core/src/persist/config/cubes_json.rs index a24805c..6d51cc3 100644 --- a/rc_core/src/persist/config/cubes_json.rs +++ b/rc_core/src/persist/config/cubes_json.rs @@ -244,43 +244,27 @@ impl super::ConfigProvider for CubeConfig { game_mode_data.as_transmissible() } - fn campaigns_parameters(&self) -> Typed { - self.battle.singleplayer.clone().into_campaign_params().as_transmissible() - } - - fn campaign_waves(&self) -> Typed { - self.battle.singleplayer.clone().into_waves().as_transmissible() - } - - fn campaign_version(&self) -> Typed { - let mut locked_map = std::collections::HashMap::with_capacity(self.battle.singleplayer.campaigns.len()); - for campaign in self.battle.singleplayer.campaigns.iter() { - locked_map.insert(campaign.id.clone(), true); - } - crate::data::campaign::GameModeVersionParameters { - current_version: 0, - is_locked: locked_map, - }.as_transmissible() - } - fn campaign_details(&self) -> super::CompleteCampaignProvider { let mut map = std::collections::HashMap::with_capacity(self.battle.singleplayer.campaigns.len()); for campaign in self.battle.singleplayer.campaigns.iter() { - //let waves_data: Vec = campaign.waves.iter().map(|x| x.clone().into()).collect(); let mut difficulty_map = std::collections::HashMap::with_capacity(campaign.difficulties.len()); for difficulty in campaign.difficulties.iter() { - let difficulty_data: crate::data::campaign::CampaignDifficultyData = difficulty.clone().into(); - let complete_campaign = crate::data::campaign::CampaignWavesDifficultyData { - difficulty: difficulty_data, - waves: campaign.waves.iter().map(|x| x.clone().into()).collect(), - }; - difficulty_map.insert(difficulty.level, complete_campaign); + difficulty_map.insert(difficulty.level, difficulty.to_owned()); } - map.insert(campaign.id.clone(), difficulty_map); + map.insert(campaign.id.clone(), super::campaign::CompleteCampaignData { + difficulty_map, + waves: campaign.waves.clone(), + }); } super::CompleteCampaignProvider::new(map) } + fn campaigns(&self) -> super::CampaignResolver { + super::CampaignResolver { + singleplayer: self.battle.singleplayer.clone(), + } + } + fn client_config(&self) -> Typed { let conf_data: crate::data::client_config::GameplaySettings = self.settings.gameplay.clone().into(); Typed::Dict(Dict { diff --git a/rc_core/src/persist/config/mod.rs b/rc_core/src/persist/config/mod.rs index 7e32e6e..1ea313c 100644 --- a/rc_core/src/persist/config/mod.rs +++ b/rc_core/src/persist/config/mod.rs @@ -2,11 +2,14 @@ mod cubes_json; pub use cubes_json::CubeConfig; mod traits; -pub use traits::{ConfigProvider, CompleteCampaignProvider, DevMessageProvider, ServerConfig, GarageUpgrades, GarageUpgradeIncrement, ChatSystemConfig, GameEventSequence, GameEvents, GameRotationStrategy, GameEvent, GameMap, GameVisibility, GameType, SingleplayerConfig, VehicleInfo, VehicleDescriptor, QueueChangeMode, Point, Sphere, MapConfig, LinksConfig, FakePlayer, ClientEmulator, EnergyConfig, BattleArenaResolver, PitSettings, PitWinCondition, TeamDeathMatchSettings}; +pub use traits::{ConfigProvider, DevMessageProvider, ServerConfig, GarageUpgrades, GarageUpgradeIncrement, ChatSystemConfig, GameEventSequence, GameEvents, GameRotationStrategy, GameEvent, GameMap, GameVisibility, GameType, SingleplayerConfig, VehicleInfo, VehicleDescriptor, QueueChangeMode, Point, Sphere, MapConfig, LinksConfig, FakePlayer, ClientEmulator, EnergyConfig, BattleArenaResolver, PitSettings, PitWinCondition, TeamDeathMatchSettings}; mod validation; pub use validation::{SelfValidator, ValidationInfo, ValidationMessage}; +mod campaign; +pub use campaign::{CampaignResolver, CompleteCampaignProvider}; + pub type ConfigImpl = CubeConfig; fn __must_impl>() {} diff --git a/rc_core/src/persist/config/traits.rs b/rc_core/src/persist/config/traits.rs index b7a7e38..724af13 100644 --- a/rc_core/src/persist/config/traits.rs +++ b/rc_core/src/persist/config/traits.rs @@ -12,10 +12,8 @@ pub trait ConfigProvider { fn regen_config(&self) -> Typed; fn after_battle_vote_config(&self) -> Typed; fn game_mode_config(&self) -> Typed; - fn campaigns_parameters(&self) -> Typed; - fn campaign_waves(&self) -> Typed; - fn campaign_version(&self) -> Typed; - fn campaign_details(&self) -> CompleteCampaignProvider; + fn campaign_details(&self) -> super::CompleteCampaignProvider; + fn campaigns(&self) -> super::CampaignResolver; fn client_config(&self) -> Typed; fn login_messages(&self) -> DevMessageProvider; fn public_channels(&self) -> Typed; @@ -40,30 +38,6 @@ pub trait ConfigProvider { fn tdm_settings(&self) -> TeamDeathMatchSettings; } -pub struct CompleteCampaignProvider { - map: std::collections::HashMap>, -} - -impl CompleteCampaignProvider { - pub fn new(map: std::collections::HashMap>) -> Self { - Self { map } - } - - pub fn get(&self, id: &str, difficulty: &i32) -> Result, i16> { - if let Some(campaign) = self.map.get(id) { - if let Some(details) = campaign.get(difficulty) { - Ok(details.as_transmissible()) - } else { - log::warn!("Couldn't find difficulty {} in campaign `{}`", difficulty, id); - Err(crate::data::error_codes::WebServicesError::DatabaseError as i16) - } - } else { - log::warn!("Couldn't find campaign {} (ignoring difficulty {})", id, difficulty); - Err(crate::data::error_codes::WebServicesError::DatabaseError as i16) - } - } -} - pub struct DevMessageProvider { messages: Vec>, } diff --git a/rc_core/src/persist/multiplayer.rs b/rc_core/src/persist/multiplayer.rs index 8bec6fe..907ab10 100644 --- a/rc_core/src/persist/multiplayer.rs +++ b/rc_core/src/persist/multiplayer.rs @@ -134,6 +134,30 @@ pub(super) fn default_fake_users() -> Vec { }, implementation: ClientEmulation::ClientAI, }, + FakePlayerConf { + team: None, + vehicle: super::garage::PrefabVehicle { + name: Some("fake3".to_owned()), + username: "Server3".to_owned(), + id: super::garage::PrefabId::Raw { + cube_data: Vec::from(crate::persist::VALID_ROBOT), + colour_data: Vec::from(crate::persist::VALID_COLOUR), + }, + }, + implementation: ClientEmulation::ClientAI, + }, + FakePlayerConf { + team: None, + vehicle: super::garage::PrefabVehicle { + name: Some("fake4".to_owned()), + username: "Server4".to_owned(), + id: super::garage::PrefabId::Raw { + cube_data: Vec::from(crate::persist::VALID_ROBOT), + colour_data: Vec::from(crate::persist::VALID_COLOUR), + }, + }, + implementation: ClientEmulation::ClientAI, + }, ] } diff --git a/rc_core/src/persist/settings.rs b/rc_core/src/persist/settings.rs index d3b6d03..f5f626a 100644 --- a/rc_core/src/persist/settings.rs +++ b/rc_core/src/persist/settings.rs @@ -114,7 +114,7 @@ fn default_server_conf() -> ServerSettings { ServerSettings { database: default_db_conn(), auto_signup: false, - queue_mode: QueueMode::Notify, + queue_mode: QueueMode::Upgrade, cdn_url: default_cdn_root_url(), auth_url: default_auth_root_url(), intercom_url: default_intercom_root_url(), diff --git a/rc_core/src/persist/singleplayer.rs b/rc_core/src/persist/singleplayer.rs index b76a9b6..e0beffa 100644 --- a/rc_core/src/persist/singleplayer.rs +++ b/rc_core/src/persist/singleplayer.rs @@ -14,10 +14,6 @@ impl SingleplayerConfig { crate::data::campaign::CampaignsGameParameters { campaigns: self.campaigns.into_iter().map(|x| x.into_campaign_params()).collect() } } - pub fn into_waves(self) -> crate::data::campaign::LiveCampaignWaves { - crate::data::campaign::LiveCampaignWaves { waves: self.campaigns.into_iter().map(|x| x.into_waves()).collect() } - } - pub fn into_singleplayer_conf(&self) -> crate::persist::config::SingleplayerConfig { crate::persist::config::SingleplayerConfig { max_teammates: self.max_teammates, @@ -86,14 +82,6 @@ impl Campaign { map: self.map, } } - - pub fn into_waves(self) -> crate::data::campaign::WavesData { - crate::data::campaign::WavesData { - id: self.id, - waves: self.waves.into_iter().map(|x| x.into()).collect(), - campaign_type: self.campaign_type.into(), - } - } } #[derive(Serialize, Deserialize, Clone, Debug)] @@ -150,35 +138,13 @@ pub struct Wave { pub time_max: i32, } -impl std::convert::From for crate::data::campaign::WaveData { - fn from(val: Wave) -> Self { - crate::data::campaign::WaveData { - robots_in_wave: val.robots_in_wave.into_iter().map(|x| x.into()).collect(), - } - } -} - -impl std::convert::From for crate::data::campaign::CompleteWaveData { - fn from(val: Wave) -> Self { - crate::data::campaign::CompleteWaveData { - player_spawn_location: val.player_spawn_location, - robots_in_wave: val.robots_in_wave.into_iter().map(|x| x.into()).collect(), - kill_target: val.kill_target, - time_min: val.time_min, - time_max: val.time_max, - } - } -} - #[derive(Serialize, Deserialize, Clone, Debug)] pub struct WaveRobot { // times appear to be in seconds - pub name: String, + pub vehicle: super::garage::PrefabVehicle, pub weapon: String, pub movement: String, pub rank: String, pub count: i32, - pub robot_data: Vec, - pub colour_data: Vec, #[serde(default)] pub time_to_spawn: i32, #[serde(default)] @@ -207,39 +173,6 @@ fn default_1() -> i32 { 1 } -impl std::convert::From for crate::data::campaign::WaveRobotData { - fn from(val: WaveRobot) -> Self { - crate::data::campaign::WaveRobotData { - name: val.name, - weapon: val.weapon, - movement: val.movement, - rank: val.rank, - count: val.count, - } - } -} - -impl std::convert::From for crate::data::campaign::CompleteWaveRobotData { - fn from(val: WaveRobot) -> Self { - crate::data::campaign::CompleteWaveRobotData { - name: val.name, - robot_data: val.robot_data, - colour_data: val.colour_data, - time_to_spawn: val.time_to_spawn, - kills_to_spawn: val.kills_to_spawn, - time_to_despawn: val.time_to_despawn, - kills_to_despawn: val.kills_to_despawn, - initial_robot_amount: val.initial_robot_amount, - periodic_robot_amount: val.periodic_robot_amount, - spawn_interval: val.spawn_interval, - min_robot_amount: val.min_robot_amount, - max_robot_amount: val.max_robot_amount, - is_boss: val.is_boss, - is_kill_requirement: val.is_kill_requirement, - } - } -} - #[derive(Serialize, Deserialize, Clone, Debug, Copy)] pub enum CampaignType { TimedElimination = 0, diff --git a/rc_services_room/src/operations/mod.rs b/rc_services_room/src/operations/mod.rs index 9433cfc..84d2a9b 100644 --- a/rc_services_room/src/operations/mod.rs +++ b/rc_services_room/src/operations/mod.rs @@ -171,7 +171,7 @@ pub fn handler(init_ctx: &crate::InitConfig) -> OperationsHandler .add(prebuilt_robots::garage_robot_data_provider()) .add(prebuilt_colours::garage_colour_combo_provider()) .add(robopass_preview_items::robopass_preview_provider()) - .add(singleplayer_campaigns::singleplayer_campaigns_provider(&init_ctx.cubes)) + .add(singleplayer_campaigns::singleplayer_campaigns_provider(init_ctx)) .add(purchases::pending_purchases_provider()) .add(building_xp_config::building_xp_config_provider()) .add(weapon_rating_static::weapon_rating_provider()) @@ -198,7 +198,7 @@ pub fn handler(init_ctx: &crate::InitConfig) -> OperationsHandler .add(score_multipliers_config::tdm_ai_score_config_provider()) .add(player_robot_rank::player_robot_rank_provider()) .add(validate_machine::validate_campaign_robot_provider()) - .add(singleplayer_campaigns::singleplayer_complete_campaign_provider(&init_ctx.cubes)) + .add(singleplayer_campaigns::singleplayer_complete_campaign_provider(init_ctx)) .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)) diff --git a/rc_services_room/src/operations/singleplayer_campaigns.rs b/rc_services_room/src/operations/singleplayer_campaigns.rs index ed32f58..ecd6f57 100644 --- a/rc_services_room/src/operations/singleplayer_campaigns.rs +++ b/rc_services_room/src/operations/singleplayer_campaigns.rs @@ -1,14 +1,33 @@ -use polariton_server::operations::{Immediate, SimpleFunc}; -use polariton_server::operations::{Operation, OperationCode}; +use polariton_server::operations::{Operation, OperationCode, SimpleFunc}; use polariton::operation::{ParameterTable, Typed}; +use polariton_server::operations::{SimpleOpError, SimpleOperation, SimpleOpImpl}; -use oj_rc_core::ConfigProvider; +//use oj_rc_core::ConfigProvider; const CAMPAIGNS_BYTES_PARAM_KEY: u8 = 64; // list of bytes (serialised data) const CAMPAIGNS_WAVES_PARAM_KEY: u8 = 70; // hashtable const CAMPAIGNS_VERSIONS_PARAM_KEY: u8 = 69; // hashtable -pub(super) fn singleplayer_campaigns_provider(conf: &oj_rc_core::ConfigImpl) -> Immediate<65, crate::UserTy> { +const CAMPAIGNS_OP_CODE: u8 = 65; + +pub struct SingleplayerCampaignProvider { + resolver: oj_rc_core::persist::config::CampaignResolver, + factory: std::sync::Arc, + weapon_order: std::sync::Arc, + cpu_counter: std::sync::Arc, +} + +pub(super) fn singleplayer_campaigns_provider(init_ctx: &crate::InitConfig) -> SimpleOpImpl { + let campaigns = >::campaigns(&init_ctx.cubes); + SimpleOpImpl::new(SingleplayerCampaignProvider { + resolver: campaigns, + factory: init_ctx.factory.clone(), + weapon_order: init_ctx.parsers.weapon_order(), + cpu_counter: init_ctx.parsers.cpu_counter(), + }) +} + +/*pub(super) fn singleplayer_campaigns_provider(conf: &oj_rc_core::ConfigImpl) -> Immediate<65, crate::UserTy> { Immediate::new(|| { let mut params = std::collections::HashMap::new(); params.insert(CAMPAIGNS_BYTES_PARAM_KEY, conf.campaigns_parameters()); // first 4 bytes are i32 for length of the rest @@ -24,24 +43,57 @@ pub(super) fn singleplayer_campaigns_provider(conf: &oj_rc_core::ConfigImpl) -> // ].into())); params.into() }) +}*/ + +#[async_trait::async_trait] +impl SimpleOperation for SingleplayerCampaignProvider { + type User = crate::UserTy; + const CODE: u8 = CAMPAIGNS_OP_CODE; + + async fn handle(&self, params: ParameterTable, user: &Self::User) -> Result, SimpleOpError> { + let mut params = params.to_dict(); + let user = user.user()?; + params.insert(CAMPAIGNS_BYTES_PARAM_KEY, self.resolver.campaigns_parameters()); + let waves = self.resolver.campaign_waves(user.as_ref().as_ref(), self.factory.as_ref(), &self.weapon_order, &self.cpu_counter).await?; + params.insert(CAMPAIGNS_WAVES_PARAM_KEY, waves); + params.insert(CAMPAIGNS_VERSIONS_PARAM_KEY, self.resolver.campaign_version()); + Ok(params.into()) + } } const CAMPAIGN_ID_PARAM_KEY: u8 = 22; // string; in const CAMPAIGN_DIFFICULTY_PARAM_KEY: u8 = 23; // i32; in const CAMPAIGN_WAVES_PARAM_KEY: u8 = 75; // bytes; out +const CAMPAIGN_COMPLETE_OP_CODE: u8 = 64; + pub struct SingleplayerCompleteCampaignProvider { campaign_details: oj_rc_core::persist::config::CompleteCampaignProvider, + factory: std::sync::Arc, + weapon_order: std::sync::Arc, + cpu_counter: std::sync::Arc, } +#[async_trait::async_trait] impl Operation for SingleplayerCompleteCampaignProvider { type User = crate::UserTy; - fn handle(&self, params: polariton::operation::ParameterTable, _user: &Self::User) -> polariton::operation::OperationResponse { + async fn handle_async(&self, params: polariton::operation::ParameterTable, user: &Self::User) -> polariton::operation::OperationResponse { let mut params = params.to_dict(); if let Some(Typed::Str(campaign_id)) = params.get(&CAMPAIGN_ID_PARAM_KEY) { if let Some(Typed::Int(campaign_difficulty)) = params.get(&CAMPAIGN_DIFFICULTY_PARAM_KEY) { - match self.campaign_details.get(&campaign_id.string, campaign_difficulty) { + let user = match user.user() { + Ok(x) => x, + Err(e) => { + return polariton::operation::OperationResponse { + code: Self::op_code(), + return_code: e, + message: polariton::operation::Typed::Null, + params: std::collections::HashMap::default().into(), + } + } + }; + match self.campaign_details.get(&campaign_id.string, campaign_difficulty, user.as_ref().as_ref(), self.factory.as_ref(), &self.weapon_order, &self.cpu_counter).await { Ok(complete_campaign) => { params.clear(); params.insert(CAMPAIGN_WAVES_PARAM_KEY, complete_campaign); @@ -69,16 +121,21 @@ impl Operation for SingleplayerCompleteCampaignProvider { impl OperationCode for SingleplayerCompleteCampaignProvider { fn op_code() -> u8 { - 64 + CAMPAIGN_COMPLETE_OP_CODE } } -pub(super) fn singleplayer_complete_campaign_provider(conf: &oj_rc_core::ConfigImpl) -> SingleplayerCompleteCampaignProvider { - let campaign_details: oj_rc_core::persist::config::CompleteCampaignProvider = >::campaign_details(conf); - SingleplayerCompleteCampaignProvider { campaign_details } +pub(super) fn singleplayer_complete_campaign_provider(init_ctx: &crate::InitConfig) -> SingleplayerCompleteCampaignProvider { + let campaign_details: oj_rc_core::persist::config::CompleteCampaignProvider = >::campaign_details(&init_ctx.cubes); + SingleplayerCompleteCampaignProvider { + campaign_details, + factory: init_ctx.factory.clone(), + weapon_order: init_ctx.parsers.weapon_order(), + cpu_counter: init_ctx.parsers.cpu_counter(), + } } -const CAMPAIGN_WAVE_NUMBER_PARAM_KEYL: u8 = 73; +const CAMPAIGN_WAVE_NUMBER_PARAM_KEY: u8 = 73; pub(super) fn singleplayer_save_complete_campaign_provider() -> SimpleFunc<68, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result) + Sync + Sync> { //let campaign_details = >::campaign_details(conf); @@ -86,7 +143,7 @@ pub(super) fn singleplayer_save_complete_campaign_provider() -> SimpleFunc<68, c let mut params = params.to_dict(); if let Some(Typed::Str(campaign_id)) = params.get(&CAMPAIGN_ID_PARAM_KEY) { if let Some(Typed::Int(campaign_difficulty)) = params.get(&CAMPAIGN_DIFFICULTY_PARAM_KEY) { - if let Some(Typed::Int(wave_number)) = params.get(&CAMPAIGN_WAVE_NUMBER_PARAM_KEYL) { + if let Some(Typed::Int(wave_number)) = params.get(&CAMPAIGN_WAVE_NUMBER_PARAM_KEY) { let user_info = user.user()?; log::info!("User {} completed campaign {} difficulty {} wave {}", user_info.public_id(), campaign_id.string, campaign_difficulty, wave_number); // TODO save wave as completed