mirror of
https://git.ngram.ca/OpenJam/rc-servers
synced 2026-08-23 23:08:52 +00:00
Use resolvable vehicles in campaign mode instead of raw cube data
This commit is contained in:
@@ -384,13 +384,18 @@ pub(super) fn default_campaigns() -> super::SingleplayerConfig {
|
|||||||
player_spawn_location: 0,
|
player_spawn_location: 0,
|
||||||
robots_in_wave: vec![
|
robots_in_wave: vec![
|
||||||
super::WaveRobot {
|
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(),
|
weapon: "strT5PlasmaGoldenName".to_owned(),
|
||||||
movement: "strT5SteeringWheelGoldenName".to_owned(),
|
movement: "strT5SteeringWheelGoldenName".to_owned(),
|
||||||
rank: "strT0".to_owned(),
|
rank: "strT0".to_owned(),
|
||||||
count: 5,
|
count: 5,
|
||||||
robot_data: super::VALID_ROBOT.into(),
|
|
||||||
colour_data: super::VALID_COLOUR.into(),
|
|
||||||
time_to_spawn: 1,
|
time_to_spawn: 1,
|
||||||
kills_to_spawn: 0,
|
kills_to_spawn: 0,
|
||||||
time_to_despawn: 60,
|
time_to_despawn: 60,
|
||||||
@@ -442,22 +447,37 @@ fn default_rotation() -> GameEventSequence {
|
|||||||
GameEventSequence {
|
GameEventSequence {
|
||||||
strategy: GameRotationStrategy::Sequence,
|
strategy: GameRotationStrategy::Sequence,
|
||||||
modes: vec![
|
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 {
|
/*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 {
|
singleplayer: GameEvent {
|
||||||
map: GameMap::Neptune1,
|
map: GameMap::Neptune1,
|
||||||
visibility: GameVisibility::Good,
|
visibility: GameVisibility::Good,
|
||||||
@@ -576,14 +596,14 @@ fn default_rotation() -> GameEventSequence {
|
|||||||
auto_heal: true,
|
auto_heal: true,
|
||||||
},
|
},
|
||||||
duration_s: 5*60,
|
duration_s: 5*60,
|
||||||
},
|
},*/
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_multiplayer() -> super::MultiplayerConfig {
|
fn default_multiplayer() -> super::MultiplayerConfig {
|
||||||
super::MultiplayerConfig {
|
super::MultiplayerConfig {
|
||||||
players_per_game: 1,
|
players_per_game: 2,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
network: super::multiplayer::default_net_conf(),
|
network: super::multiplayer::default_net_conf(),
|
||||||
fakes: super::multiplayer::default_fake_users(),
|
fakes: super::multiplayer::default_fake_users(),
|
||||||
|
|||||||
130
rc_core/src/persist/config/campaign.rs
Normal file
130
rc_core/src/persist/config/campaign.rs
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
use polariton::operation::Typed;
|
||||||
|
|
||||||
|
pub(super) struct CompleteCampaignData {
|
||||||
|
pub(super) difficulty_map: std::collections::HashMap<i32, crate::persist::CampaignDifficulty>,
|
||||||
|
pub(super) waves: Vec<crate::persist::Wave>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CompleteCampaignProvider {
|
||||||
|
map: std::collections::HashMap<String, CompleteCampaignData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CompleteCampaignProvider {
|
||||||
|
pub(super) fn new(map: std::collections::HashMap<String, CompleteCampaignData>) -> Self {
|
||||||
|
Self { map }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get<C>(
|
||||||
|
&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<Typed<C>, 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<C>(&self) -> Typed<C> {
|
||||||
|
self.singleplayer.clone().into_campaign_params().as_transmissible()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn campaign_waves<C>(
|
||||||
|
&self,
|
||||||
|
user: &dyn crate::persist::user::CommonUser,
|
||||||
|
factory: &dyn oj_rc_factory::VehicleFactoryAdapter,
|
||||||
|
weapon_order: &crate::cubes::WeaponListParser,
|
||||||
|
cpu_counter: &crate::cubes::CpuListParser,
|
||||||
|
) -> Result<Typed<C>, 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<C>(&self) -> Typed<C> {
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -244,43 +244,27 @@ impl <C: Clone + Send> super::ConfigProvider<C> for CubeConfig {
|
|||||||
game_mode_data.as_transmissible()
|
game_mode_data.as_transmissible()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn campaigns_parameters(&self) -> Typed<C> {
|
|
||||||
self.battle.singleplayer.clone().into_campaign_params().as_transmissible()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn campaign_waves(&self) -> Typed<C> {
|
|
||||||
self.battle.singleplayer.clone().into_waves().as_transmissible()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn campaign_version(&self) -> Typed<C> {
|
|
||||||
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 {
|
fn campaign_details(&self) -> super::CompleteCampaignProvider {
|
||||||
let mut map = std::collections::HashMap::with_capacity(self.battle.singleplayer.campaigns.len());
|
let mut map = std::collections::HashMap::with_capacity(self.battle.singleplayer.campaigns.len());
|
||||||
for campaign in self.battle.singleplayer.campaigns.iter() {
|
for campaign in self.battle.singleplayer.campaigns.iter() {
|
||||||
//let waves_data: Vec<crate::data::campaign::CompleteWaveData> = campaign.waves.iter().map(|x| x.clone().into()).collect();
|
|
||||||
let mut difficulty_map = std::collections::HashMap::with_capacity(campaign.difficulties.len());
|
let mut difficulty_map = std::collections::HashMap::with_capacity(campaign.difficulties.len());
|
||||||
for difficulty in campaign.difficulties.iter() {
|
for difficulty in campaign.difficulties.iter() {
|
||||||
let difficulty_data: crate::data::campaign::CampaignDifficultyData = difficulty.clone().into();
|
difficulty_map.insert(difficulty.level, difficulty.to_owned());
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
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)
|
super::CompleteCampaignProvider::new(map)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn campaigns(&self) -> super::CampaignResolver {
|
||||||
|
super::CampaignResolver {
|
||||||
|
singleplayer: self.battle.singleplayer.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn client_config(&self) -> Typed<C> {
|
fn client_config(&self) -> Typed<C> {
|
||||||
let conf_data: crate::data::client_config::GameplaySettings = self.settings.gameplay.clone().into();
|
let conf_data: crate::data::client_config::GameplaySettings = self.settings.gameplay.clone().into();
|
||||||
Typed::Dict(Dict {
|
Typed::Dict(Dict {
|
||||||
|
|||||||
@@ -2,11 +2,14 @@ mod cubes_json;
|
|||||||
pub use cubes_json::CubeConfig;
|
pub use cubes_json::CubeConfig;
|
||||||
|
|
||||||
mod traits;
|
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;
|
mod validation;
|
||||||
pub use validation::{SelfValidator, ValidationInfo, ValidationMessage};
|
pub use validation::{SelfValidator, ValidationInfo, ValidationMessage};
|
||||||
|
|
||||||
|
mod campaign;
|
||||||
|
pub use campaign::{CampaignResolver, CompleteCampaignProvider};
|
||||||
|
|
||||||
pub type ConfigImpl = CubeConfig;
|
pub type ConfigImpl = CubeConfig;
|
||||||
|
|
||||||
fn __must_impl<T: ConfigProvider<()>>() {}
|
fn __must_impl<T: ConfigProvider<()>>() {}
|
||||||
|
|||||||
@@ -12,10 +12,8 @@ pub trait ConfigProvider<C: Clone> {
|
|||||||
fn regen_config(&self) -> Typed<C>;
|
fn regen_config(&self) -> Typed<C>;
|
||||||
fn after_battle_vote_config(&self) -> Typed<C>;
|
fn after_battle_vote_config(&self) -> Typed<C>;
|
||||||
fn game_mode_config(&self) -> Typed<C>;
|
fn game_mode_config(&self) -> Typed<C>;
|
||||||
fn campaigns_parameters(&self) -> Typed<C>;
|
fn campaign_details(&self) -> super::CompleteCampaignProvider;
|
||||||
fn campaign_waves(&self) -> Typed<C>;
|
fn campaigns(&self) -> super::CampaignResolver;
|
||||||
fn campaign_version(&self) -> Typed<C>;
|
|
||||||
fn campaign_details(&self) -> CompleteCampaignProvider;
|
|
||||||
fn client_config(&self) -> Typed<C>;
|
fn client_config(&self) -> Typed<C>;
|
||||||
fn login_messages(&self) -> DevMessageProvider<C>;
|
fn login_messages(&self) -> DevMessageProvider<C>;
|
||||||
fn public_channels(&self) -> Typed<C>;
|
fn public_channels(&self) -> Typed<C>;
|
||||||
@@ -40,30 +38,6 @@ pub trait ConfigProvider<C: Clone> {
|
|||||||
fn tdm_settings(&self) -> TeamDeathMatchSettings;
|
fn tdm_settings(&self) -> TeamDeathMatchSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CompleteCampaignProvider {
|
|
||||||
map: std::collections::HashMap<String, std::collections::HashMap<i32, crate::data::campaign::CampaignWavesDifficultyData>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CompleteCampaignProvider {
|
|
||||||
pub fn new(map: std::collections::HashMap<String, std::collections::HashMap<i32, crate::data::campaign::CampaignWavesDifficultyData>>) -> Self {
|
|
||||||
Self { map }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get<C>(&self, id: &str, difficulty: &i32) -> Result<Typed<C>, 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<C: Clone> {
|
pub struct DevMessageProvider<C: Clone> {
|
||||||
messages: Vec<TypedDevMessage<C>>,
|
messages: Vec<TypedDevMessage<C>>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -134,6 +134,30 @@ pub(super) fn default_fake_users() -> Vec<FakePlayerConf> {
|
|||||||
},
|
},
|
||||||
implementation: ClientEmulation::ClientAI,
|
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,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ fn default_server_conf() -> ServerSettings {
|
|||||||
ServerSettings {
|
ServerSettings {
|
||||||
database: default_db_conn(),
|
database: default_db_conn(),
|
||||||
auto_signup: false,
|
auto_signup: false,
|
||||||
queue_mode: QueueMode::Notify,
|
queue_mode: QueueMode::Upgrade,
|
||||||
cdn_url: default_cdn_root_url(),
|
cdn_url: default_cdn_root_url(),
|
||||||
auth_url: default_auth_root_url(),
|
auth_url: default_auth_root_url(),
|
||||||
intercom_url: default_intercom_root_url(),
|
intercom_url: default_intercom_root_url(),
|
||||||
|
|||||||
@@ -14,10 +14,6 @@ impl SingleplayerConfig {
|
|||||||
crate::data::campaign::CampaignsGameParameters { campaigns: self.campaigns.into_iter().map(|x| x.into_campaign_params()).collect() }
|
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 {
|
pub fn into_singleplayer_conf(&self) -> crate::persist::config::SingleplayerConfig {
|
||||||
crate::persist::config::SingleplayerConfig {
|
crate::persist::config::SingleplayerConfig {
|
||||||
max_teammates: self.max_teammates,
|
max_teammates: self.max_teammates,
|
||||||
@@ -86,14 +82,6 @@ impl Campaign {
|
|||||||
map: self.map,
|
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)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
@@ -150,35 +138,13 @@ pub struct Wave {
|
|||||||
pub time_max: i32,
|
pub time_max: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::From<Wave> 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<Wave> 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)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct WaveRobot { // times appear to be in seconds
|
pub struct WaveRobot { // times appear to be in seconds
|
||||||
pub name: String,
|
pub vehicle: super::garage::PrefabVehicle,
|
||||||
pub weapon: String,
|
pub weapon: String,
|
||||||
pub movement: String,
|
pub movement: String,
|
||||||
pub rank: String,
|
pub rank: String,
|
||||||
pub count: i32,
|
pub count: i32,
|
||||||
pub robot_data: Vec<u8>,
|
|
||||||
pub colour_data: Vec<u8>,
|
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub time_to_spawn: i32,
|
pub time_to_spawn: i32,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
@@ -207,39 +173,6 @@ fn default_1() -> i32 {
|
|||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::From<WaveRobot> 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<WaveRobot> 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)]
|
#[derive(Serialize, Deserialize, Clone, Debug, Copy)]
|
||||||
pub enum CampaignType {
|
pub enum CampaignType {
|
||||||
TimedElimination = 0,
|
TimedElimination = 0,
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ pub fn handler(init_ctx: &crate::InitConfig) -> OperationsHandler<crate::UserTy>
|
|||||||
.add(prebuilt_robots::garage_robot_data_provider())
|
.add(prebuilt_robots::garage_robot_data_provider())
|
||||||
.add(prebuilt_colours::garage_colour_combo_provider())
|
.add(prebuilt_colours::garage_colour_combo_provider())
|
||||||
.add(robopass_preview_items::robopass_preview_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(purchases::pending_purchases_provider())
|
||||||
.add(building_xp_config::building_xp_config_provider())
|
.add(building_xp_config::building_xp_config_provider())
|
||||||
.add(weapon_rating_static::weapon_rating_provider())
|
.add(weapon_rating_static::weapon_rating_provider())
|
||||||
@@ -198,7 +198,7 @@ pub fn handler(init_ctx: &crate::InitConfig) -> OperationsHandler<crate::UserTy>
|
|||||||
.add(score_multipliers_config::tdm_ai_score_config_provider())
|
.add(score_multipliers_config::tdm_ai_score_config_provider())
|
||||||
.add(player_robot_rank::player_robot_rank_provider())
|
.add(player_robot_rank::player_robot_rank_provider())
|
||||||
.add(validate_machine::validate_campaign_robot_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(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(singleplayer_campaigns::singleplayer_save_complete_campaign_provider()) // TODO handle UpdatePlayerCompletedCampaignWaveRequest saving
|
||||||
.add(garage_slot_limit::garage_slots_limit(&init_ctx.cubes))
|
.add(garage_slot_limit::garage_slots_limit(&init_ctx.cubes))
|
||||||
|
|||||||
@@ -1,14 +1,33 @@
|
|||||||
use polariton_server::operations::{Immediate, SimpleFunc};
|
use polariton_server::operations::{Operation, OperationCode, SimpleFunc};
|
||||||
use polariton_server::operations::{Operation, OperationCode};
|
|
||||||
use polariton::operation::{ParameterTable, Typed};
|
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_BYTES_PARAM_KEY: u8 = 64; // list of bytes (serialised data)
|
||||||
const CAMPAIGNS_WAVES_PARAM_KEY: u8 = 70; // hashtable
|
const CAMPAIGNS_WAVES_PARAM_KEY: u8 = 70; // hashtable
|
||||||
const CAMPAIGNS_VERSIONS_PARAM_KEY: u8 = 69; // 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<oj_rc_core::factory::Factory>,
|
||||||
|
weapon_order: std::sync::Arc<oj_rc_core::cubes::WeaponListParser>,
|
||||||
|
cpu_counter: std::sync::Arc<oj_rc_core::cubes::CpuListParser>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn singleplayer_campaigns_provider<C: Send + Clone + 'static>(init_ctx: &crate::InitConfig) -> SimpleOpImpl<C, crate::UserTy, SingleplayerCampaignProvider> {
|
||||||
|
let campaigns = <oj_rc_core::ConfigImpl as oj_rc_core::ConfigProvider<()>>::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(|| {
|
Immediate::new(|| {
|
||||||
let mut params = std::collections::HashMap::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
|
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()));
|
// ].into()));
|
||||||
params.into()
|
params.into()
|
||||||
})
|
})
|
||||||
|
}*/
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl <C: Send + 'static> SimpleOperation<C> for SingleplayerCampaignProvider {
|
||||||
|
type User = crate::UserTy;
|
||||||
|
const CODE: u8 = CAMPAIGNS_OP_CODE;
|
||||||
|
|
||||||
|
async fn handle(&self, params: ParameterTable<C>, user: &Self::User) -> Result<ParameterTable<C>, 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_ID_PARAM_KEY: u8 = 22; // string; in
|
||||||
const CAMPAIGN_DIFFICULTY_PARAM_KEY: u8 = 23; // i32; in
|
const CAMPAIGN_DIFFICULTY_PARAM_KEY: u8 = 23; // i32; in
|
||||||
const CAMPAIGN_WAVES_PARAM_KEY: u8 = 75; // bytes; out
|
const CAMPAIGN_WAVES_PARAM_KEY: u8 = 75; // bytes; out
|
||||||
|
|
||||||
|
const CAMPAIGN_COMPLETE_OP_CODE: u8 = 64;
|
||||||
|
|
||||||
pub struct SingleplayerCompleteCampaignProvider {
|
pub struct SingleplayerCompleteCampaignProvider {
|
||||||
campaign_details: oj_rc_core::persist::config::CompleteCampaignProvider,
|
campaign_details: oj_rc_core::persist::config::CompleteCampaignProvider,
|
||||||
|
factory: std::sync::Arc<oj_rc_core::factory::Factory>,
|
||||||
|
weapon_order: std::sync::Arc<oj_rc_core::cubes::WeaponListParser>,
|
||||||
|
cpu_counter: std::sync::Arc<oj_rc_core::cubes::CpuListParser>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
impl <C: Send + 'static> Operation<C> for SingleplayerCompleteCampaignProvider {
|
impl <C: Send + 'static> Operation<C> for SingleplayerCompleteCampaignProvider {
|
||||||
type User = crate::UserTy;
|
type User = crate::UserTy;
|
||||||
|
|
||||||
fn handle(&self, params: polariton::operation::ParameterTable<C>, _user: &Self::User) -> polariton::operation::OperationResponse<C> {
|
async fn handle_async(&self, params: polariton::operation::ParameterTable<C>, user: &Self::User) -> polariton::operation::OperationResponse<C> {
|
||||||
let mut params = params.to_dict();
|
let mut params = params.to_dict();
|
||||||
if let Some(Typed::Str(campaign_id)) = params.get(&CAMPAIGN_ID_PARAM_KEY) {
|
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(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) => {
|
Ok(complete_campaign) => {
|
||||||
params.clear();
|
params.clear();
|
||||||
params.insert(CAMPAIGN_WAVES_PARAM_KEY, complete_campaign);
|
params.insert(CAMPAIGN_WAVES_PARAM_KEY, complete_campaign);
|
||||||
@@ -69,16 +121,21 @@ impl <C: Send + 'static> Operation<C> for SingleplayerCompleteCampaignProvider {
|
|||||||
|
|
||||||
impl OperationCode for SingleplayerCompleteCampaignProvider {
|
impl OperationCode for SingleplayerCompleteCampaignProvider {
|
||||||
fn op_code() -> u8 {
|
fn op_code() -> u8 {
|
||||||
64
|
CAMPAIGN_COMPLETE_OP_CODE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn singleplayer_complete_campaign_provider(conf: &oj_rc_core::ConfigImpl) -> SingleplayerCompleteCampaignProvider {
|
pub(super) fn singleplayer_complete_campaign_provider(init_ctx: &crate::InitConfig) -> SingleplayerCompleteCampaignProvider {
|
||||||
let campaign_details: oj_rc_core::persist::config::CompleteCampaignProvider = <oj_rc_core::ConfigImpl as oj_rc_core::ConfigProvider<()>>::campaign_details(conf);
|
let campaign_details: oj_rc_core::persist::config::CompleteCampaignProvider = <oj_rc_core::ConfigImpl as oj_rc_core::ConfigProvider<()>>::campaign_details(&init_ctx.cubes);
|
||||||
SingleplayerCompleteCampaignProvider { campaign_details }
|
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<ParameterTable, i16>) + Sync + Sync> {
|
pub(super) fn singleplayer_save_complete_campaign_provider() -> SimpleFunc<68, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result<ParameterTable, i16>) + Sync + Sync> {
|
||||||
//let campaign_details = <oj_rc_core::ConfigImpl as oj_rc_core::ConfigProvider<()>>::campaign_details(conf);
|
//let campaign_details = <oj_rc_core::ConfigImpl as oj_rc_core::ConfigProvider<()>>::campaign_details(conf);
|
||||||
@@ -86,7 +143,7 @@ pub(super) fn singleplayer_save_complete_campaign_provider() -> SimpleFunc<68, c
|
|||||||
let mut params = params.to_dict();
|
let mut params = params.to_dict();
|
||||||
if let Some(Typed::Str(campaign_id)) = params.get(&CAMPAIGN_ID_PARAM_KEY) {
|
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(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()?;
|
let user_info = user.user()?;
|
||||||
log::info!("User {} completed campaign {} difficulty {} wave {}", user_info.public_id(), campaign_id.string, campaign_difficulty, wave_number);
|
log::info!("User {} completed campaign {} difficulty {} wave {}", user_info.public_id(), campaign_id.string, campaign_difficulty, wave_number);
|
||||||
// TODO save wave as completed
|
// TODO save wave as completed
|
||||||
|
|||||||
Reference in New Issue
Block a user