mirror of
https://git.ngram.ca/OpenJam/rc-servers
synced 2026-08-23 23:08:52 +00:00
Make enemy and teammate count customizable
This commit is contained in:
@@ -321,20 +321,27 @@ pub(super) fn default_campaigns() -> super::SingleplayerConfig {
|
||||
vehicles: vec![
|
||||
super::PrefabVehicle {
|
||||
name: Some("Config your singleplayer!".to_owned()),
|
||||
username: "NGnius!".to_owned(),
|
||||
id: super::PrefabId::Database { garage: 1 }
|
||||
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 }
|
||||
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 }
|
||||
username: "NGniusness*".to_owned(),
|
||||
id: super::PrefabId::Database { garage: 1 },
|
||||
},
|
||||
super::PrefabVehicle {
|
||||
name: Some("Config your singleplayer!".to_owned()),
|
||||
username: "NG~".to_owned(),
|
||||
id: super::PrefabId::Database { garage: 1 },
|
||||
},
|
||||
],
|
||||
max_teammates: 0,
|
||||
max_enemies: 5,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -304,9 +304,8 @@ impl <C: Clone + Send> super::ConfigProvider<C> for CubeConfig {
|
||||
}
|
||||
}
|
||||
|
||||
fn singleplayer_vehicles(&self) -> Vec<crate::persist::garage::PrefabVehicle> {
|
||||
// FIXME don't use serializable types in traits
|
||||
self.battle.singleplayer.vehicles.clone()
|
||||
fn singleplayer_details(&self) -> super::SingleplayerConfig {
|
||||
self.battle.singleplayer.into_singleplayer_conf()
|
||||
}
|
||||
|
||||
/*async fn prefab_vehicles(&self, user: &(dyn crate::persist::user::User<C> + Sync), factory: &crate::factory::Factory) -> Typed<C> {
|
||||
|
||||
@@ -2,7 +2,7 @@ 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};
|
||||
pub use traits::{ConfigProvider, CompleteCampaignProvider, DevMessageProvider, ServerConfig, GarageUpgrades, GarageUpgradeIncrement, ChatSystemConfig, GameEventSequence, GameEvents, GameRotationStrategy, GameEvent, GameMap, GameVisibility, GameType, SingleplayerConfig, VehicleInfo, VehicleDescriptor};
|
||||
|
||||
pub type ConfigImpl = CubeConfig;
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ pub trait ConfigProvider<C: Clone> {
|
||||
fn chat_system_config(&self) -> ChatSystemConfig;
|
||||
fn gamemode_events(&self) -> GameEventSequence;
|
||||
// FIXME don't use serializable types in traits
|
||||
fn singleplayer_vehicles(&self) -> Vec<crate::persist::garage::PrefabVehicle>;
|
||||
fn singleplayer_details(&self) -> SingleplayerConfig;
|
||||
}
|
||||
|
||||
pub struct CompleteCampaignProvider {
|
||||
@@ -259,3 +259,32 @@ pub enum GameType {
|
||||
TeamDeathmatch,
|
||||
Campaign,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SingleplayerConfig {
|
||||
pub max_teammates: u32,
|
||||
pub max_enemies: u32,
|
||||
pub vehicles: Vec<VehicleInfo>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct VehicleInfo {
|
||||
pub name: Option<String>,
|
||||
pub username: String,
|
||||
pub id: VehicleDescriptor,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum VehicleDescriptor {
|
||||
Factory {
|
||||
factory: u32,
|
||||
},
|
||||
Database {
|
||||
garage: u32,
|
||||
},
|
||||
Raw {
|
||||
cube_data: Vec<u8>,
|
||||
colour_data: Vec<u8>,
|
||||
}
|
||||
// TODO File
|
||||
}
|
||||
|
||||
@@ -201,3 +201,13 @@ pub enum PrefabId {
|
||||
}
|
||||
// TODO File
|
||||
}
|
||||
|
||||
impl std::convert::Into<crate::persist::config::VehicleDescriptor> for PrefabId {
|
||||
fn into(self) -> crate::persist::config::VehicleDescriptor {
|
||||
match self {
|
||||
Self::Factory { factory } => crate::persist::config::VehicleDescriptor::Factory { factory },
|
||||
Self::Database { garage } => crate::persist::config::VehicleDescriptor::Database { garage },
|
||||
Self::Raw { cube_data, colour_data } => crate::persist::config::VehicleDescriptor::Raw { cube_data , colour_data },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ pub struct SingleplayerConfig {
|
||||
#[serde(default = "default_campaigns")]
|
||||
pub campaigns: Vec<Campaign>,
|
||||
pub vehicles: Vec<super::PrefabVehicle>,
|
||||
pub max_teammates: u32,
|
||||
pub max_enemies: u32,
|
||||
}
|
||||
|
||||
impl SingleplayerConfig {
|
||||
@@ -15,6 +17,18 @@ impl SingleplayerConfig {
|
||||
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,
|
||||
max_enemies: self.max_enemies,
|
||||
vehicles: self.vehicles.iter().map(|v| crate::persist::config::VehicleInfo {
|
||||
name: v.name.clone(),
|
||||
username: v.username.clone(),
|
||||
id: v.id.clone().into(),
|
||||
}).collect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
|
||||
@@ -5,7 +5,6 @@ use crate::persist::config::ConfigProvider;
|
||||
pub struct AccountProvider {
|
||||
cubes: std::sync::Arc<Vec<u32>>,
|
||||
garage_upgrades: std::sync::Arc<crate::persist::config::GarageUpgrades>,
|
||||
singleplayer_vehicles: std::sync::Arc<Vec<crate::persist::garage::PrefabVehicle>>,
|
||||
auto_signups: bool,
|
||||
secret: Vec<u8>,
|
||||
db: std::sync::Arc<rc_database::Database>,
|
||||
@@ -22,7 +21,6 @@ impl AccountProvider {
|
||||
Ok(Self {
|
||||
cubes: std::sync::Arc::new(<crate::persist::config::ConfigImpl as ConfigProvider<()>>::ids(conf)),
|
||||
garage_upgrades: std::sync::Arc::new(<crate::persist::config::ConfigImpl as ConfigProvider<()>>::garage_upgrades(conf)),
|
||||
singleplayer_vehicles: std::sync::Arc::new(<crate::persist::config::ConfigImpl as ConfigProvider<()>>::singleplayer_vehicles(conf)),
|
||||
auto_signups: server_settings.auto_signup,
|
||||
secret: std::fs::read(&token_path)?,
|
||||
db: std::sync::Arc::new(db),
|
||||
@@ -84,7 +82,6 @@ impl <C: Clone> super::UserProvider<C> 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(),
|
||||
}))
|
||||
@@ -195,7 +192,6 @@ struct UserData {
|
||||
perms: rc_database::schema::permissions::Model,
|
||||
cubes: std::sync::Arc<Vec<u32>>,
|
||||
garage_upgrades: std::sync::Arc<crate::persist::config::GarageUpgrades>,
|
||||
singleplayer_vehicles: std::sync::Arc<Vec<crate::persist::garage::PrefabVehicle>>,
|
||||
extensions: std::collections::HashMap<std::any::TypeId, Box<dyn std::any::Any + Send + Sync + 'static>>,
|
||||
db: std::sync::Arc<rc_database::Database>,
|
||||
}
|
||||
@@ -259,13 +255,13 @@ impl UserData {
|
||||
self.perms.administrator | self.perms.developer
|
||||
}
|
||||
|
||||
async fn resolve_some_singleplayer_vehicles(&self, factory: &dyn rc_factory::VehicleFactoryAdapter, weapon_order: &crate::cubes::WeaponListParser) -> Result<Vec<crate::data::player_data::PlayerData>, i16> {
|
||||
async fn resolve_some_singleplayer_vehicles(&self, factory: &dyn rc_factory::VehicleFactoryAdapter, weapon_order: &crate::cubes::WeaponListParser, singleplayer_config: &crate::persist::config::SingleplayerConfig) -> Result<Vec<crate::data::player_data::PlayerData>, i16> {
|
||||
use rand::seq::IndexedRandom;
|
||||
let mut enemies = Vec::with_capacity(5);
|
||||
let mut players = Vec::with_capacity((singleplayer_config.max_enemies + singleplayer_config.max_teammates + 1) as usize);
|
||||
let mut next_id = 0;
|
||||
let mut seen_usernames = std::collections::HashSet::<String>::new();
|
||||
for _ in 0..5 {
|
||||
let vehicle = self.singleplayer_vehicles.choose(&mut rand::rng())
|
||||
for i in 0..(singleplayer_config.max_enemies + singleplayer_config.max_teammates) {
|
||||
let vehicle = singleplayer_config.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)));
|
||||
@@ -280,8 +276,9 @@ impl UserData {
|
||||
vehicle.username.clone()
|
||||
};
|
||||
seen_usernames.insert(username.clone());
|
||||
let team_num = if i < singleplayer_config.max_enemies { 1 } else { 0 };
|
||||
let enemy = match &vehicle.id {
|
||||
crate::persist::PrefabId::Factory { factory: factory_id } => {
|
||||
crate::persist::config::VehicleDescriptor::Factory { factory: factory_id } => {
|
||||
//use rc_factory::VehicleFactoryAdapter;
|
||||
match factory.vehicle(*factory_id).await {
|
||||
Ok(Some(factory_vehicle)) => {
|
||||
@@ -295,7 +292,7 @@ impl UserData {
|
||||
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,
|
||||
team: team_num,
|
||||
has_premium: false,
|
||||
robot_uuid: uuid_str,
|
||||
cpu: 420,
|
||||
@@ -318,7 +315,7 @@ impl UserData {
|
||||
}
|
||||
}
|
||||
},
|
||||
crate::persist::PrefabId::Database { garage } => {
|
||||
crate::persist::config::VehicleDescriptor::Database { garage } => {
|
||||
match self.db.garage_by_id(*garage).await {
|
||||
Ok(Some(db_vehicle)) => {
|
||||
crate::data::player_data::PlayerData {
|
||||
@@ -328,7 +325,7 @@ impl UserData {
|
||||
tier: 1, // FIXME
|
||||
robot_name: vehicle.name.clone().unwrap_or_else(|| db_vehicle.name.clone()),
|
||||
robot_map: db_vehicle.robot_data,
|
||||
team: 1,
|
||||
team: team_num,
|
||||
has_premium: false,
|
||||
robot_uuid: uuid_str,
|
||||
cpu: db_vehicle.total_robot_cpu as i32,
|
||||
@@ -351,7 +348,7 @@ impl UserData {
|
||||
}
|
||||
}
|
||||
},
|
||||
crate::persist::PrefabId::Raw {
|
||||
crate::persist::config::VehicleDescriptor::Raw {
|
||||
cube_data,
|
||||
colour_data,
|
||||
} => {
|
||||
@@ -365,7 +362,7 @@ impl UserData {
|
||||
tier: 1, // FIXME
|
||||
robot_name: vehicle.name.clone().unwrap_or_else(|| "Raw Robot".to_owned()),
|
||||
robot_map: cube_data.to_owned(),
|
||||
team: 1,
|
||||
team: team_num,
|
||||
has_premium: false,
|
||||
robot_uuid: uuid_str,
|
||||
cpu: 420, // FIXME
|
||||
@@ -380,9 +377,9 @@ impl UserData {
|
||||
}
|
||||
};
|
||||
next_id += 1;
|
||||
enemies.push(enemy);
|
||||
players.push(enemy);
|
||||
}
|
||||
Ok(enemies)
|
||||
Ok(players)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -784,9 +781,9 @@ impl <C: Clone> super::User<C> for UserData {
|
||||
super::since_windows_epoch(self.account.creation_time)
|
||||
}
|
||||
|
||||
async fn singleplayer_robots(&self, factory: &dyn rc_factory::VehicleFactoryAdapter, weapon_order: &crate::cubes::WeaponListParser) -> Result<polariton::operation::Typed<C>, i16> {
|
||||
async fn singleplayer_robots(&self, factory: &dyn rc_factory::VehicleFactoryAdapter, weapon_order: &crate::cubes::WeaponListParser, singleplayer_config: &crate::persist::config::SingleplayerConfig) -> Result<polariton::operation::Typed<C>, i16> {
|
||||
//self.err_on_banned().await?;
|
||||
let mut vehicles = self.resolve_some_singleplayer_vehicles(factory, weapon_order).await?;
|
||||
let mut vehicles = self.resolve_some_singleplayer_vehicles(factory, weapon_order, singleplayer_config).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
|
||||
|
||||
@@ -75,7 +75,7 @@ pub trait User<C>: ChatUser {
|
||||
async fn get_slot_customisations(&self, uuid: &str) -> Result<GetCustomisationData<C>, i16>;
|
||||
async fn set_slot_name(&self, slot: i32, name: String) -> Result<(), i16>;
|
||||
fn signup_date(&self) -> i64;
|
||||
async fn singleplayer_robots(&self, factory: &dyn rc_factory::VehicleFactoryAdapter, weapon_order: &crate::cubes::WeaponListParser) -> Result<polariton::operation::Typed<C>, i16>;
|
||||
async fn singleplayer_robots(&self, factory: &dyn rc_factory::VehicleFactoryAdapter, weapon_order: &crate::cubes::WeaponListParser, singleplayer_config: &crate::persist::config::SingleplayerConfig) -> Result<polariton::operation::Typed<C>, i16>;
|
||||
async fn prepare_factory_upload(&self, vehicle: VehicleUploadData) -> Result<rc_factory::VehicleUploadInfo, i16>;
|
||||
async fn last_seen(&self) -> Result<u64, i16>;
|
||||
async fn get_avatar_info(&self) -> Result<GetAvatarInfo<C>, i16>;
|
||||
|
||||
@@ -11,7 +11,7 @@ use polariton::packet::{Data, Message, Packet, StandardMessage};
|
||||
use polariton::operation::{OperationResponse, Typed};
|
||||
|
||||
pub struct InitConfig {
|
||||
pub cubes: rc_core::persist::config::ConfigImpl,
|
||||
pub config: rc_core::persist::config::ConfigImpl,
|
||||
pub users: std::sync::Arc<rc_core::persist::user::UserImpl>,
|
||||
pub factory: std::sync::Arc<rc_core::factory::Factory>,
|
||||
pub parsers: rc_core::cubes::CubeParsers,
|
||||
@@ -25,13 +25,13 @@ async fn main() -> std::io::Result<()> {
|
||||
let args = cli::CliArgs::get();
|
||||
log::debug!("Got cli args {:?}", args);
|
||||
|
||||
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(<rc_core::persist::config::ConfigImpl as rc_core::ConfigProvider<()>>::factory::<'_, '_>(&cubes).await.expect("Bad vehicle factory (CRF) config"));
|
||||
let parsers = rc_core::cubes::CubeParsers::new(&cubes);
|
||||
let config = 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, &config).await.expect("Bad user data"));
|
||||
let factory = std::sync::Arc::new(<rc_core::persist::config::ConfigImpl as rc_core::ConfigProvider<()>>::factory::<'_, '_>(&config).await.expect("Bad vehicle factory (CRF) config"));
|
||||
let parsers = rc_core::cubes::CubeParsers::new(&config);
|
||||
|
||||
let init_ctx = InitConfig {
|
||||
cubes,
|
||||
config,
|
||||
users,
|
||||
factory,
|
||||
parsers,
|
||||
|
||||
@@ -4,23 +4,25 @@ const CODE: u8 = 1;
|
||||
|
||||
const PARAM_KEY: u8 = 8;
|
||||
|
||||
pub(super) fn tdm_machines_provider(factory: &std::sync::Arc<rc_core::factory::Factory>, weapon_order: std::sync::Arc<rc_core::cubes::WeaponListParser>) -> AiRobots {
|
||||
pub(super) fn tdm_machines_provider(factory: &std::sync::Arc<rc_core::factory::Factory>, weapon_order: std::sync::Arc<rc_core::cubes::WeaponListParser>, conf: &rc_core::ConfigImpl) -> AiRobots {
|
||||
AiRobots {
|
||||
factory: factory.to_owned(),
|
||||
weapon_parser: weapon_order,
|
||||
singleplayer_config: <rc_core::ConfigImpl as rc_core::ConfigProvider<()>>::singleplayer_details(conf),
|
||||
}
|
||||
}
|
||||
|
||||
async fn do_handling(params: ParameterTable<()>, user: &crate::UserTy, factory: &rc_core::factory::Factory, weapon_order: &rc_core::cubes::WeaponListParser) -> Result<ParameterTable<()>, i16> {
|
||||
async fn do_handling(params: ParameterTable<()>, user: &crate::UserTy, factory: &rc_core::factory::Factory, weapon_order: &rc_core::cubes::WeaponListParser, singleplayer_conf: &rc_core::persist::config::SingleplayerConfig) -> Result<ParameterTable<()>, i16> {
|
||||
let ulock = user.user()?;
|
||||
let mut params = params.to_dict();
|
||||
params.insert(PARAM_KEY, ulock.singleplayer_robots(factory, weapon_order).await?);
|
||||
params.insert(PARAM_KEY, ulock.singleplayer_robots(factory, weapon_order, singleplayer_conf).await?);
|
||||
Ok(params.into())
|
||||
}
|
||||
|
||||
pub struct AiRobots {
|
||||
factory: std::sync::Arc<rc_core::factory::Factory>,
|
||||
weapon_parser: std::sync::Arc<rc_core::cubes::WeaponListParser>,
|
||||
singleplayer_config: rc_core::persist::config::SingleplayerConfig,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
@@ -28,7 +30,7 @@ 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::<CODE, ()>(do_handling(params, user, self.factory.as_ref(), self.weapon_parser.as_ref()).await)
|
||||
polariton_server::operations::result_to_op_resp::<CODE, ()>(do_handling(params, user, self.factory.as_ref(), self.weapon_parser.as_ref(), &self.singleplayer_config).await)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ pub fn handler(init_ctx: &crate::InitConfig) -> OperationsHandler<crate::UserTy>
|
||||
.modify(rc_core::polariton::OpIdCopy)
|
||||
.add(more_auth::MoreLobbyAuth)
|
||||
.add(eac::EacChallengeIgnorer)
|
||||
.add(load_ai_robots::tdm_machines_provider(&init_ctx.factory, init_ctx.parsers.weapon_order()))
|
||||
.add(load_ai_robots::tdm_machines_provider(&init_ctx.factory, init_ctx.parsers.weapon_order(), &init_ctx.config))
|
||||
//.add(polariton_server::operations::Ack::<33, _>::default()) // get user clan info (this is equivalent to not being in a clan)
|
||||
.add(polariton_server::operations::Ack::<2, _>::default()) // Save singleplayer result (parameter-less response)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user