mirror of
https://git.ngram.ca/OpenJam/rc-servers
synced 2026-08-23 23:08:52 +00:00
Get enemies spawning in singleplayer #23
This commit is contained in:
@@ -60,3 +60,15 @@ pub enum ChatErrorCodes {
|
|||||||
PasswordRequired = 16,
|
PasswordRequired = 16,
|
||||||
ChannelExpired = 17,
|
ChannelExpired = 17,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(i16)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum SingleplayerErrorCode {
|
||||||
|
None = 0,
|
||||||
|
DatabaseError = 1,
|
||||||
|
UnexpectedError = 2,
|
||||||
|
WrongNumberOfAuthParams = 3,
|
||||||
|
MaintenanceMode = 4,
|
||||||
|
DuplicateLogin = 5,
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ pub mod weapon_upgrade;
|
|||||||
pub mod crf;
|
pub mod crf;
|
||||||
pub mod channel;
|
pub mod channel;
|
||||||
pub mod sanction;
|
pub mod sanction;
|
||||||
|
pub mod robot_data;
|
||||||
|
|
||||||
pub mod error_codes;
|
pub mod error_codes;
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ pub struct PrebuiltRobotInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PrebuiltRobotInfo {
|
impl PrebuiltRobotInfo {
|
||||||
pub fn as_transmissible(&self) -> Typed {
|
pub fn as_transmissible<C>(&self) -> Typed<C> {
|
||||||
Typed::HashMap(vec![
|
Typed::HashMap(vec![
|
||||||
//(Typed::Str("[key]".into()), Typed::Str(self.id.clone().into())),
|
//(Typed::Str("[key]".into()), Typed::Str(self.id.clone().into())),
|
||||||
(Typed::Str("Name".into()), Typed::Str(self.name.clone().into())),
|
(Typed::Str("Name".into()), Typed::Str(self.name.clone().into())),
|
||||||
@@ -9,7 +9,7 @@ pub struct BattleConfig {
|
|||||||
#[serde(default = "default_game_modes")]
|
#[serde(default = "default_game_modes")]
|
||||||
pub games: GameModes,
|
pub games: GameModes,
|
||||||
#[serde(default = "default_campaigns")]
|
#[serde(default = "default_campaigns")]
|
||||||
pub singleplayer: super::Campaigns,
|
pub singleplayer: super::SingleplayerConfig,
|
||||||
#[serde(default = "default_rotation")]
|
#[serde(default = "default_rotation")]
|
||||||
pub rotation: GameEventSequence,
|
pub rotation: GameEventSequence,
|
||||||
}
|
}
|
||||||
@@ -252,8 +252,8 @@ fn default_game_modes() -> GameModes {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_campaigns() -> super::Campaigns {
|
pub(super) fn default_campaigns() -> super::SingleplayerConfig {
|
||||||
super::Campaigns {
|
super::SingleplayerConfig {
|
||||||
campaigns: vec![
|
campaigns: vec![
|
||||||
super::Campaign {
|
super::Campaign {
|
||||||
id: "strCampaignModeBattle".to_owned(),
|
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 }
|
||||||
|
},
|
||||||
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ impl CubeConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl <C: Clone> super::ConfigProvider<C> for CubeConfig {
|
impl <C: Clone + Send> super::ConfigProvider<C> for CubeConfig {
|
||||||
fn cube_list(&self) -> Typed<C> {
|
fn cube_list(&self) -> Typed<C> {
|
||||||
Typed::Dict(Dict {
|
Typed::Dict(Dict {
|
||||||
key_ty: TypePrefix::Str,
|
key_ty: TypePrefix::Str,
|
||||||
@@ -303,4 +303,55 @@ impl <C: Clone> super::ConfigProvider<C> for CubeConfig {
|
|||||||
started: chrono::Utc::now().timestamp(),
|
started: chrono::Utc::now().timestamp(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn singleplayer_vehicles(&self) -> Vec<crate::persist::garage::PrefabVehicle> {
|
||||||
|
// FIXME don't use serializable types in traits
|
||||||
|
self.battle.singleplayer.vehicles.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*async fn prefab_vehicles(&self, user: &(dyn crate::persist::user::User<C> + Sync), factory: &crate::factory::Factory) -> Typed<C> {
|
||||||
|
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 `<uuid>` -> `<name>`:\n\t{}", debug_str_map.join("\n\t"));
|
||||||
|
Typed::Dict(Dict {
|
||||||
|
key_ty: TypePrefix::Str, // str
|
||||||
|
val_ty: TypePrefix::HashMap, // hashmap
|
||||||
|
items: id_map,
|
||||||
|
})
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ pub trait ConfigProvider<C: Clone> {
|
|||||||
fn cubes(&self) -> &'_ std::collections::HashMap<String, crate::persist::Cube>;
|
fn cubes(&self) -> &'_ std::collections::HashMap<String, crate::persist::Cube>;
|
||||||
fn chat_system_config(&self) -> ChatSystemConfig;
|
fn chat_system_config(&self) -> ChatSystemConfig;
|
||||||
fn gamemode_events(&self) -> GameEventSequence;
|
fn gamemode_events(&self) -> GameEventSequence;
|
||||||
|
// FIXME don't use serializable types in traits
|
||||||
|
fn singleplayer_vehicles(&self) -> Vec<crate::persist::garage::PrefabVehicle>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CompleteCampaignProvider {
|
pub struct CompleteCampaignProvider {
|
||||||
|
|||||||
@@ -176,3 +176,24 @@ impl std::convert::Into<crate::data::garage_bay::ControlOptions> for GarageContr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
pub struct PrefabVehicle {
|
||||||
|
pub name: Option<String>,
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ pub use cube_data::{Cube, ItemTier, ItemCategory, ItemType};
|
|||||||
//pub use cube_data::{VisibilityMode, ItemType};
|
//pub use cube_data::{VisibilityMode, ItemType};
|
||||||
|
|
||||||
mod garage;
|
mod garage;
|
||||||
pub use garage::{GarageSlot, GarageControls, ControlType};
|
pub use garage::{GarageSlot, GarageControls, ControlType, PrefabVehicle, PrefabId};
|
||||||
|
|
||||||
mod movement;
|
mod movement;
|
||||||
pub use movement::{MovementCategoryData, MovementData};
|
pub use movement::{MovementCategoryData, MovementData};
|
||||||
@@ -21,7 +21,7 @@ mod combat;
|
|||||||
pub use combat::BattleConfig;
|
pub use combat::BattleConfig;
|
||||||
|
|
||||||
mod singleplayer;
|
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;
|
mod client_config;
|
||||||
pub use client_config::GameplaySettings;
|
pub use client_config::GameplaySettings;
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct Campaigns {
|
pub struct SingleplayerConfig {
|
||||||
|
#[serde(default = "default_campaigns")]
|
||||||
pub campaigns: Vec<Campaign>,
|
pub campaigns: Vec<Campaign>,
|
||||||
|
pub vehicles: Vec<super::PrefabVehicle>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Campaigns {
|
impl SingleplayerConfig {
|
||||||
pub fn into_campaign_params(self) -> crate::data::campaign::CampaignsGameParameters {
|
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() }
|
crate::data::campaign::CampaignsGameParameters { campaigns: self.campaigns.into_iter().map(|x| x.into_campaign_params()).collect() }
|
||||||
}
|
}
|
||||||
@@ -222,3 +224,7 @@ impl std::convert::Into<crate::data::campaign::CampaignType> for CampaignType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_campaigns() -> Vec<Campaign> {
|
||||||
|
super::combat::default_campaigns().campaigns
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ use crate::persist::config::ConfigProvider;
|
|||||||
pub struct AccountProvider {
|
pub struct AccountProvider {
|
||||||
cubes: std::sync::Arc<Vec<u32>>,
|
cubes: std::sync::Arc<Vec<u32>>,
|
||||||
garage_upgrades: std::sync::Arc<crate::persist::config::GarageUpgrades>,
|
garage_upgrades: std::sync::Arc<crate::persist::config::GarageUpgrades>,
|
||||||
|
singleplayer_vehicles: std::sync::Arc<Vec<crate::persist::garage::PrefabVehicle>>,
|
||||||
auto_signups: bool,
|
auto_signups: bool,
|
||||||
secret: Vec<u8>,
|
secret: Vec<u8>,
|
||||||
db: std::sync::Arc<rc_database::Database>,
|
db: std::sync::Arc<rc_database::Database>,
|
||||||
@@ -21,11 +22,41 @@ impl AccountProvider {
|
|||||||
Ok(Self {
|
Ok(Self {
|
||||||
cubes: std::sync::Arc::new(<crate::persist::config::ConfigImpl as ConfigProvider<()>>::ids(conf)),
|
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)),
|
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,
|
auto_signups: server_settings.auto_signup,
|
||||||
secret: std::fs::read(&token_path)?,
|
secret: std::fs::read(&token_path)?,
|
||||||
db: std::sync::Arc::new(db),
|
db: std::sync::Arc::new(db),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn fake_user<C: Clone>(&self) -> Box<dyn super::User<C> + 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]
|
#[async_trait::async_trait]
|
||||||
@@ -53,6 +84,7 @@ impl <C: Clone> super::UserProvider<C> for AccountProvider {
|
|||||||
perms: user_perms,
|
perms: user_perms,
|
||||||
cubes: self.cubes.clone(),
|
cubes: self.cubes.clone(),
|
||||||
garage_upgrades: self.garage_upgrades.clone(),
|
garage_upgrades: self.garage_upgrades.clone(),
|
||||||
|
singleplayer_vehicles: self.singleplayer_vehicles.clone(),
|
||||||
extensions: ext,
|
extensions: ext,
|
||||||
db: self.db.clone(),
|
db: self.db.clone(),
|
||||||
}))
|
}))
|
||||||
@@ -163,6 +195,7 @@ struct UserData {
|
|||||||
perms: rc_database::schema::permissions::Model,
|
perms: rc_database::schema::permissions::Model,
|
||||||
cubes: std::sync::Arc<Vec<u32>>,
|
cubes: std::sync::Arc<Vec<u32>>,
|
||||||
garage_upgrades: std::sync::Arc<crate::persist::config::GarageUpgrades>,
|
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>>,
|
extensions: std::collections::HashMap<std::any::TypeId, Box<dyn std::any::Any + Send + Sync + 'static>>,
|
||||||
db: std::sync::Arc<rc_database::Database>,
|
db: std::sync::Arc<rc_database::Database>,
|
||||||
}
|
}
|
||||||
@@ -225,6 +258,105 @@ impl UserData {
|
|||||||
fn has_admin_or_better_perms(&self) -> bool {
|
fn has_admin_or_better_perms(&self) -> bool {
|
||||||
self.perms.administrator | self.perms.developer
|
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> {
|
||||||
|
use rand::seq::IndexedRandom;
|
||||||
|
let mut enemies = Vec::with_capacity(5);
|
||||||
|
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())
|
||||||
|
.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::<Vec<_>>(),
|
||||||
|
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
|
const INVALID_ROBOT_ERR: i16 = crate::data::error_codes::WebServicesError::InvalidRobot as i16; // 140
|
||||||
@@ -539,8 +671,9 @@ impl <C: Clone> super::User<C> for UserData {
|
|||||||
super::since_windows_epoch(self.account.creation_time)
|
super::since_windows_epoch(self.account.creation_time)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn singleplayer_robots(&self) -> Result<polariton::operation::Typed<C>, i16> {
|
async fn singleplayer_robots(&self, factory: &dyn rc_factory::VehicleFactoryAdapter, weapon_order: &crate::cubes::WeaponListParser) -> Result<polariton::operation::Typed<C>, i16> {
|
||||||
self.err_on_banned().await?;
|
//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| {
|
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);
|
log::error!("Failed to retrieve selected vehicle for user_id {} (singleplayer_robots): {}", self.account.id, e);
|
||||||
DATABASE_ERR
|
DATABASE_ERR
|
||||||
@@ -550,28 +683,30 @@ impl <C: Clone> super::User<C> for UserData {
|
|||||||
INVALID_ROBOT_ERR
|
INVALID_ROBOT_ERR
|
||||||
})?;
|
})?;
|
||||||
let user_uuid = self.token.uuid.clone();
|
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::<Vec<_>>();
|
||||||
|
|
||||||
|
// 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 {
|
Ok(crate::data::player_data::PlayerDatas {
|
||||||
players: vec![
|
players: vehicles,
|
||||||
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::<Vec<_>>(),
|
|
||||||
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(),
|
|
||||||
}
|
|
||||||
],
|
|
||||||
}.as_transmissible())
|
}.as_transmissible())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ pub trait User<C>: ChatUser {
|
|||||||
async fn save_slot_customisations(&self, customs: CustomisationData) -> Result<(), i16>;
|
async fn save_slot_customisations(&self, customs: CustomisationData) -> Result<(), i16>;
|
||||||
async fn get_slot_customisations(&self, uuid: &str) -> Result<GetCustomisationData<C>, i16>;
|
async fn get_slot_customisations(&self, uuid: &str) -> Result<GetCustomisationData<C>, i16>;
|
||||||
fn signup_date(&self) -> i64;
|
fn signup_date(&self) -> i64;
|
||||||
async fn singleplayer_robots(&self) -> Result<polariton::operation::Typed<C>, i16>;
|
async fn singleplayer_robots(&self, factory: &dyn rc_factory::VehicleFactoryAdapter, weapon_order: &crate::cubes::WeaponListParser) -> Result<polariton::operation::Typed<C>, i16>;
|
||||||
async fn prepare_factory_upload(&self, vehicle: VehicleUploadData) -> Result<rc_factory::VehicleUploadInfo, i16>;
|
async fn prepare_factory_upload(&self, vehicle: VehicleUploadData) -> Result<rc_factory::VehicleUploadInfo, i16>;
|
||||||
async fn last_seen(&self) -> Result<u64, i16>;
|
async fn last_seen(&self) -> Result<u64, i16>;
|
||||||
async fn get_avatar_info(&self) -> Result<GetAvatarInfo<C>, i16>;
|
async fn get_avatar_info(&self) -> Result<GetAvatarInfo<C>, i16>;
|
||||||
|
|||||||
@@ -165,6 +165,12 @@ impl Database {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn garage_by_id(&self, id: u32) -> Result<Option<crate::schema::garage::Model>, sea_orm::DbErr> {
|
||||||
|
crate::schema::garage::Entity::find_by_id(id)
|
||||||
|
.one(&self.orm)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn insert_garages(&self, entities: Vec<crate::schema::garage::ActiveModel>) -> Result<(), sea_orm::DbErr> {
|
pub async fn insert_garages(&self, entities: Vec<crate::schema::garage::ActiveModel>) -> Result<(), sea_orm::DbErr> {
|
||||||
crate::schema::garage::Entity::insert_many(entities.into_iter()).exec(&self.orm).await?;
|
crate::schema::garage::Entity::insert_many(entities.into_iter()).exec(&self.orm).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ impl crate::VehicleFactoryAdapter for ArcAdapter {
|
|||||||
banner_message: Default::default(),
|
banner_message: Default::default(),
|
||||||
combat_rating: meta.combat_rating,
|
combat_rating: meta.combat_rating,
|
||||||
cosmetic_rating: meta.cosmetic_rating,
|
cosmetic_rating: meta.cosmetic_rating,
|
||||||
cube_amounts: Default::default(),
|
cube_amounts: Default::default(), // FIXME parse cube amounts
|
||||||
}
|
}
|
||||||
)))
|
)))
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ pub mod item_shop_bundle;
|
|||||||
pub mod player_robopass_season;
|
pub mod player_robopass_season;
|
||||||
//pub use rc_core::data::weapon_upgrade;
|
//pub use rc_core::data::weapon_upgrade;
|
||||||
pub mod player_rank;
|
pub mod player_rank;
|
||||||
pub mod robot_data;
|
// pub use rc_core::data::robot_data;
|
||||||
pub mod quest;
|
pub mod quest;
|
||||||
//pub use rc_core::data::auto_regen;
|
//pub use rc_core::data::auto_regen;
|
||||||
//pub use rc_core::data::voting;
|
//pub use rc_core::data::voting;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use polariton_server::operations::SimpleFunc;
|
use polariton_server::operations::SimpleFunc;
|
||||||
use polariton::{operation::{Dict, ParameterTable, Typed}, serdes::TypePrefix};
|
use polariton::{operation::{Dict, ParameterTable, Typed}, serdes::TypePrefix};
|
||||||
|
|
||||||
use crate::data::robot_data::*;
|
use rc_core::data::robot_data::*;
|
||||||
|
|
||||||
const PARAM_KEY: u8 = 1;
|
const PARAM_KEY: u8 = 1;
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,13 @@ use tokio::net;
|
|||||||
use polariton::packet::{Data, Message, Packet, StandardMessage};
|
use polariton::packet::{Data, Message, Packet, StandardMessage};
|
||||||
use polariton::operation::{OperationResponse, Typed};
|
use polariton::operation::{OperationResponse, Typed};
|
||||||
|
|
||||||
|
pub struct InitConfig {
|
||||||
|
pub cubes: 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,
|
||||||
|
}
|
||||||
|
|
||||||
pub type UserTy = rc_core::UserState<()>;
|
pub type UserTy = rc_core::UserState<()>;
|
||||||
|
|
||||||
#[tokio::main]
|
#[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 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 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 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");
|
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 {
|
if args.once {
|
||||||
log::warn!("Handling first connection and then exiting");
|
log::warn!("Handling first connection and then exiting");
|
||||||
let (socket, address) = listener.accept().await?;
|
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 {
|
} else {
|
||||||
loop {
|
loop {
|
||||||
let (socket, address) = listener.accept().await?;
|
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();
|
server.join();
|
||||||
|
|||||||
@@ -1,26 +1,29 @@
|
|||||||
use polariton::operation::{ParameterTable, Typed, OperationResponse};
|
use polariton::operation::{ParameterTable, OperationResponse};
|
||||||
|
|
||||||
const CODE: u8 = 1;
|
const CODE: u8 = 1;
|
||||||
|
|
||||||
const PARAM_KEY: u8 = 8;
|
const PARAM_KEY: u8 = 8;
|
||||||
|
|
||||||
pub(super) fn tdm_machines_provider() -> AiRobots {
|
pub(super) fn tdm_machines_provider(factory: &std::sync::Arc<rc_core::factory::Factory>, weapon_order: std::sync::Arc<rc_core::cubes::WeaponListParser>) -> AiRobots {
|
||||||
AiRobots
|
AiRobots {
|
||||||
|
factory: factory.to_owned(),
|
||||||
|
weapon_parser: weapon_order,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn do_handling(params: ParameterTable<()>, user: &crate::UserTy) -> Result<ParameterTable<()>, i16> {
|
async fn do_handling(params: ParameterTable<()>, user: &crate::UserTy, factory: &rc_core::factory::Factory, weapon_order: &rc_core::cubes::WeaponListParser) -> Result<ParameterTable<()>, i16> {
|
||||||
let ulock = user.user()?;
|
let ulock = user.user()?;
|
||||||
let mut params = params.to_dict();
|
let mut params = params.to_dict();
|
||||||
params.insert(PARAM_KEY, ulock.singleplayer_robots().await?);
|
params.insert(PARAM_KEY, ulock.singleplayer_robots(factory, weapon_order).await?);
|
||||||
let event_tx = user.event_sender();
|
/*let event_tx = user.event_sender();
|
||||||
let user_bot_data = ulock.slot_by_id(ulock.selected_garage().await.1 as _).await?;
|
let user_bot_data = ulock.slot_by_id(ulock.selected_garage().await.1 as _).await?;
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
tokio::time::sleep(std::time::Duration::from_secs(20)).await;
|
tokio::time::sleep(std::time::Duration::from_secs(20)).await;
|
||||||
log::debug!("Sending singleplayer event");
|
log::debug!("Sending singleplayer event");
|
||||||
let mut spawn_params = std::collections::HashMap::with_capacity(4);
|
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(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);
|
spawn_params.insert(7 /* color model */, user_bot_data.colour_data);
|
||||||
event_tx.send(polariton_server::ToSend::Data {
|
event_tx.send(polariton_server::ToSend::Data {
|
||||||
data: polariton::packet::Data::Event(polariton::operation::Event { code: 3, params: spawn_params.into() }),
|
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,
|
channel: 0,
|
||||||
reliable: true,
|
reliable: true,
|
||||||
}).unwrap();*/
|
}).unwrap();*/
|
||||||
});
|
});*/
|
||||||
Ok(params.into())
|
Ok(params.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct AiRobots;
|
pub struct AiRobots {
|
||||||
|
factory: std::sync::Arc<rc_core::factory::Factory>,
|
||||||
|
weapon_parser: std::sync::Arc<rc_core::cubes::WeaponListParser>,
|
||||||
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl polariton_server::operations::Operation<()> for AiRobots {
|
impl polariton_server::operations::Operation<()> for AiRobots {
|
||||||
type User = crate::UserTy;
|
type User = crate::UserTy;
|
||||||
|
|
||||||
async fn handle_async(&self, params: ParameterTable<()>, user: &Self::User) -> OperationResponse<()> {
|
async fn handle_async(&self, params: ParameterTable<()>, user: &Self::User) -> OperationResponse<()> {
|
||||||
polariton_server::operations::result_to_op_resp::<CODE, ()>(do_handling(params, user).await)
|
polariton_server::operations::result_to_op_resp::<CODE, ()>(do_handling(params, user, self.factory.as_ref(), self.weapon_parser.as_ref()).await)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ mod load_ai_robots;
|
|||||||
|
|
||||||
use polariton_server::operations::OperationsHandler;
|
use polariton_server::operations::OperationsHandler;
|
||||||
|
|
||||||
pub fn handler() -> OperationsHandler<crate::UserTy> {
|
pub fn handler(init_ctx: &crate::InitConfig) -> OperationsHandler<crate::UserTy> {
|
||||||
OperationsHandler::<crate::UserTy>::new()
|
OperationsHandler::<crate::UserTy>::new()
|
||||||
.modify(rc_core::polariton::OpIdCopy)
|
.modify(rc_core::polariton::OpIdCopy)
|
||||||
.add(more_auth::MoreLobbyAuth)
|
.add(more_auth::MoreLobbyAuth)
|
||||||
.add(eac::EacChallengeIgnorer)
|
.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)
|
//.add(polariton_server::operations::Ack::<33, _>::default()) // get user clan info (this is equivalent to not being in a clan)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user