mirror of
https://git.ngram.ca/OpenJam/rc-servers
synced 2026-08-23 23:08:52 +00:00
Implement vehicle validation before match
This commit is contained in:
@@ -29,3 +29,4 @@ pub mod quest;
|
||||
pub mod score_multipliers;
|
||||
//pub use oj_rc_core::data::campaign;
|
||||
pub use oj_rc_core::data::crf;
|
||||
pub mod vehicle_validation;
|
||||
|
||||
22
rc_services_room/src/data/vehicle_validation.rs
Normal file
22
rc_services_room/src/data/vehicle_validation.rs
Normal file
@@ -0,0 +1,22 @@
|
||||
// possible codes
|
||||
#[allow(dead_code)]
|
||||
#[repr(u8)]
|
||||
pub enum ValidateMachineResult {
|
||||
Invalid = 0,
|
||||
Ok = 1,
|
||||
NoWeapon = 2,
|
||||
NoMovement = 3,
|
||||
Sanctioned = 4,
|
||||
}
|
||||
|
||||
impl ValidateMachineResult {
|
||||
pub fn from_plugin(code: oj_rc_plugins::vehicle_validation::ValidationResultCode) -> Self {
|
||||
match code {
|
||||
oj_rc_plugins::vehicle_validation::ValidationResultCode::Invalid => Self::Invalid,
|
||||
oj_rc_plugins::vehicle_validation::ValidationResultCode::Ok => Self::Ok,
|
||||
oj_rc_plugins::vehicle_validation::ValidationResultCode::NoWeapon => Self::NoWeapon,
|
||||
oj_rc_plugins::vehicle_validation::ValidationResultCode::NoMovement => Self::NoMovement,
|
||||
oj_rc_plugins::vehicle_validation::ValidationResultCode::Sanctioned => Self::Sanctioned,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ mod cli;
|
||||
mod data;
|
||||
mod events;
|
||||
mod operations;
|
||||
mod vehicle_validators;
|
||||
|
||||
use oj_polariton_auth::Handshake;
|
||||
use tokio::net;
|
||||
@@ -23,6 +24,7 @@ pub struct InitConfig {
|
||||
pub users: std::sync::Arc<oj_rc_core::persist::user::UserImpl>,
|
||||
pub factory: std::sync::Arc<oj_rc_core::factory::Factory>,
|
||||
pub parsers: oj_rc_core::cubes::CubeParsers,
|
||||
pub vehicle_validators: vehicle_validators::InitedVehicleValidators,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
@@ -35,11 +37,18 @@ async fn main() -> std::io::Result<()> {
|
||||
let users = std::sync::Arc::new(oj_rc_core::persist::user::UserImpl::load(&args.data, &cubes).await.expect("Bad user data"));
|
||||
let factory = std::sync::Arc::new(<oj_rc_core::persist::config::ConfigImpl as oj_rc_core::ConfigProvider<()>>::factory(&cubes, &|| users.factory_impl()).await.expect("Bad vehicle factory (CRF) config"));
|
||||
let parsers = oj_rc_core::cubes::CubeParsers::new(&cubes);
|
||||
let vehicle_validator_plugins_path = std::path::PathBuf::from(&args.data).join("plugins/vehicle_validation");
|
||||
let vehicle_validators = vehicle_validators::validators_from_conf(
|
||||
&<oj_rc_core::persist::config::ConfigImpl as oj_rc_core::ConfigProvider<()>>::vehicle_validation(&cubes),
|
||||
&parsers,
|
||||
vehicle_validator_plugins_path,
|
||||
);
|
||||
let init_ctx = std::sync::Arc::new(InitConfig {
|
||||
cubes,
|
||||
users,
|
||||
factory,
|
||||
parsers,
|
||||
vehicle_validators
|
||||
});
|
||||
|
||||
let server = std::sync::Arc::new(polariton_server::Server::new(operations::handler(&init_ctx), polariton_server::events::EventsHandler::new()));
|
||||
|
||||
@@ -19,7 +19,7 @@ impl <C: Send + 'static> SimpleOperation<C> for BattleArenaConfigurer {
|
||||
|
||||
async fn handle(&self, params: ParameterTable<C>, user: &Self::User) -> Result<ParameterTable<C>, SimpleOpError> {
|
||||
let user_info = user.user()?;
|
||||
log::warn!("Retrieved ba config");
|
||||
//log::warn!("Retrieved ba config");
|
||||
let data = self.ba_conf.resolve_typed(user_info.as_ref().as_ref(), self.factory.as_ref(), &self.weapon_list, &self.cpu_counter).await?;
|
||||
let mut params = params.to_dict();
|
||||
params.insert(PARAM_KEY, data);
|
||||
|
||||
@@ -75,7 +75,8 @@ mod reconnect_game;
|
||||
mod regen_config;
|
||||
mod pageantry;
|
||||
mod signup_time;
|
||||
mod validate_machine;
|
||||
mod validate_vehicle_by_lobby;
|
||||
mod validate_vehicle_by_campaign;
|
||||
mod game_mode_config;
|
||||
mod score_multipliers_config;
|
||||
mod player_robot_rank;
|
||||
@@ -202,11 +203,11 @@ pub fn handler(init_ctx: &crate::InitConfig) -> OperationsHandler<crate::UserTy>
|
||||
.add(regen_config::auto_regen_config_provider(&init_ctx.cubes))
|
||||
.add(pageantry::after_battle_vote_thresholds_provider(&init_ctx.cubes))
|
||||
.add(signup_time::user_signup_date_provider())
|
||||
.add(validate_machine::validate_robot_provider())
|
||||
.add(validate_vehicle_by_lobby::validate_robot_provider(&init_ctx.vehicle_validators))
|
||||
.add(game_mode_config::game_mode_config_provider(&init_ctx.cubes))
|
||||
.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(validate_vehicle_by_campaign::validate_campaign_robot_provider(&init_ctx.vehicle_validators))
|
||||
.add(singleplayer_campaigns::singleplayer_complete_campaign_provider(init_ctx))
|
||||
.add(campaign_save_result::campaign_save_awards_provider())
|
||||
.add(singleplayer_campaigns::singleplayer_save_complete_campaign_provider()) // TODO handle UpdatePlayerCompletedCampaignWaveRequest saving
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
use polariton_server::operations::SimpleFunc;
|
||||
use polariton::operation::{ParameterTable, Typed};
|
||||
|
||||
const LOBBY_PARAM_KEY: u8 = 134;
|
||||
const VALIDATE_ROBOT_RESULT_PARAM_KEY: u8 = 111;
|
||||
|
||||
// possible codes
|
||||
#[allow(dead_code)]
|
||||
#[repr(u8)]
|
||||
enum ValidateMachineResult {
|
||||
Invalid = 0,
|
||||
Ok = 1,
|
||||
NoWeapon = 2,
|
||||
NoMovement = 3,
|
||||
Sanctioned = 4,
|
||||
}
|
||||
|
||||
pub(super) fn validate_robot_provider() -> SimpleFunc<102, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result<ParameterTable, i16>) + Sync + Sync> {
|
||||
SimpleFunc::new(|params, _user: &crate::UserTy| {
|
||||
let mut params = params.to_dict();
|
||||
if let Some(Typed::Int(lobby_ty)) = params.get(&LOBBY_PARAM_KEY) {
|
||||
log::info!("Got lobby type {} ({:?})", lobby_ty, oj_rc_core::data::lobby::LobbyType::from_int(*lobby_ty));
|
||||
}
|
||||
// let lock = user.read().unwrap();
|
||||
// let user_info = lock.user()?;
|
||||
// TODO actually validate the vehicle
|
||||
params.insert(VALIDATE_ROBOT_RESULT_PARAM_KEY, Typed::Int(ValidateMachineResult::Ok as _));
|
||||
Ok(params.into())
|
||||
})
|
||||
}
|
||||
|
||||
const CAMPAIGN_ID_PARAM_KEY: u8 = 22;
|
||||
|
||||
pub(super) fn validate_campaign_robot_provider() -> SimpleFunc<59, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy) -> Result<ParameterTable, i16>) + Sync + Sync> {
|
||||
SimpleFunc::new(|params, _user: &crate::UserTy| {
|
||||
let mut params = params.to_dict();
|
||||
if let Some(Typed::Str(campaign_id)) = params.get(&CAMPAIGN_ID_PARAM_KEY) {
|
||||
log::info!("Got campaign id {}", campaign_id.string);
|
||||
}
|
||||
// let lock = user.read().unwrap();
|
||||
// let user_info = lock.user()?;
|
||||
// TODO actually validate the vehicle
|
||||
params.insert(VALIDATE_ROBOT_RESULT_PARAM_KEY, Typed::Int(ValidateMachineResult::Ok as _)); // this is ignored
|
||||
Ok(params.into())
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
use polariton_server::operations::{SimpleOpError, SimpleOperation, SimpleOpImpl};
|
||||
use polariton::operation::{ParameterTable, Typed};
|
||||
|
||||
use crate::data::vehicle_validation::*;
|
||||
|
||||
const VALIDATE_CAMPAIGN_ROBOT_CODE: u8 = 59;
|
||||
|
||||
const CAMPAIGN_ID_PARAM_KEY: u8 = 22;
|
||||
const VALIDATE_ROBOT_RESULT_PARAM_KEY: u8 = 111;
|
||||
|
||||
pub(super) struct CampaignVehicleValidator {
|
||||
campaign_map: std::sync::Arc<std::collections::HashMap<String, crate::vehicle_validators::InitedVehicleValidator>>,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl <C: Send + 'static> SimpleOperation<C> for CampaignVehicleValidator {
|
||||
type User = crate::UserTy;
|
||||
const CODE: u8 = VALIDATE_CAMPAIGN_ROBOT_CODE;
|
||||
|
||||
async fn handle(&self, params: ParameterTable<C>, user: &Self::User) -> Result<ParameterTable<C>, SimpleOpError> {
|
||||
let mut params = params.to_dict();
|
||||
if let Some(Typed::Str(campaign_id)) = params.get(&CAMPAIGN_ID_PARAM_KEY) {
|
||||
log::debug!("Got campaign id {}", campaign_id.string);
|
||||
if let Some(campaign_validator) = self.campaign_map.get(&campaign_id.string) {
|
||||
let user_info = user.user()?;
|
||||
let vehicle_data = user_info.selected_vehicle_data().await?;
|
||||
let result_code = ValidateMachineResult::from_plugin(campaign_validator.validate(
|
||||
&vehicle_data.robot_data,
|
||||
&vehicle_data.colour_data,
|
||||
));
|
||||
params.insert(VALIDATE_ROBOT_RESULT_PARAM_KEY, Typed::Int(result_code as _));
|
||||
} else {
|
||||
// bad state, assume user is doing something sketchy
|
||||
log::warn!("Failed to find vehicle validator for campaign {}", campaign_id.string);
|
||||
params.insert(VALIDATE_ROBOT_RESULT_PARAM_KEY, Typed::Int(ValidateMachineResult::Sanctioned as _));
|
||||
}
|
||||
} else {
|
||||
log::warn!("No campaign ID provided for campaign vehicle validator");
|
||||
}
|
||||
Ok(params.into())
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn validate_campaign_robot_provider<C: Send + 'static>(validators: &crate::vehicle_validators::InitedVehicleValidators) -> SimpleOpImpl<C, crate::UserTy, CampaignVehicleValidator> {
|
||||
SimpleOpImpl::new(CampaignVehicleValidator {
|
||||
campaign_map: validators.campaigns.clone(),
|
||||
})
|
||||
}
|
||||
58
rc_services_room/src/operations/validate_vehicle_by_lobby.rs
Normal file
58
rc_services_room/src/operations/validate_vehicle_by_lobby.rs
Normal file
@@ -0,0 +1,58 @@
|
||||
use polariton_server::operations::{SimpleOpError, SimpleOperation, SimpleOpImpl};
|
||||
use polariton::operation::{ParameterTable, Typed};
|
||||
|
||||
use crate::data::vehicle_validation::*;
|
||||
|
||||
const VALIDATE_LOBBY_ROBOT_CODE: u8 = 102;
|
||||
|
||||
const LOBBY_PARAM_KEY: u8 = 134;
|
||||
const VALIDATE_ROBOT_RESULT_PARAM_KEY: u8 = 111;
|
||||
|
||||
pub(super) struct MultiplayerVehicleValidator {
|
||||
multiplayer: std::sync::Arc<crate::vehicle_validators::InitedVehicleValidator>,
|
||||
custom_game: std::sync::Arc<crate::vehicle_validators::InitedVehicleValidator>,
|
||||
singleplayer: std::sync::Arc<crate::vehicle_validators::InitedVehicleValidator>,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl <C: Send + 'static> SimpleOperation<C> for MultiplayerVehicleValidator {
|
||||
type User = crate::UserTy;
|
||||
const CODE: u8 = VALIDATE_LOBBY_ROBOT_CODE;
|
||||
|
||||
async fn handle(&self, params: ParameterTable<C>, user: &Self::User) -> Result<ParameterTable<C>, SimpleOpError> {
|
||||
let mut params = params.to_dict();
|
||||
if let Some(Typed::Int(lobby_ty)) = params.get(&LOBBY_PARAM_KEY) {
|
||||
let lobby_ty = oj_rc_core::data::lobby::LobbyType::from_int(*lobby_ty)?;
|
||||
log::debug!("Got lobby type {:?}", lobby_ty);
|
||||
let user_info = user.user()?;
|
||||
let vehicle_data = user_info.selected_vehicle_data().await?;
|
||||
let result_code = match lobby_ty {
|
||||
oj_rc_core::data::lobby::LobbyType::None => ValidateMachineResult::Ok,
|
||||
oj_rc_core::data::lobby::LobbyType::CustomGame => ValidateMachineResult::from_plugin(self.custom_game.validate(
|
||||
&vehicle_data.robot_data,
|
||||
&vehicle_data.colour_data,
|
||||
)),
|
||||
oj_rc_core::data::lobby::LobbyType::QuickPlay => ValidateMachineResult::from_plugin(self.multiplayer.validate(
|
||||
&vehicle_data.robot_data,
|
||||
&vehicle_data.colour_data,
|
||||
)),
|
||||
oj_rc_core::data::lobby::LobbyType::Solo => ValidateMachineResult::from_plugin(self.singleplayer.validate(
|
||||
&vehicle_data.robot_data,
|
||||
&vehicle_data.colour_data,
|
||||
)),
|
||||
};
|
||||
params.insert(VALIDATE_ROBOT_RESULT_PARAM_KEY, Typed::Int(result_code as _));
|
||||
} else {
|
||||
log::warn!("No lobby type provided for vehicle validator");
|
||||
}
|
||||
Ok(params.into())
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn validate_robot_provider<C: Send + 'static>(validators: &crate::vehicle_validators::InitedVehicleValidators) -> SimpleOpImpl<C, crate::UserTy, MultiplayerVehicleValidator> {
|
||||
SimpleOpImpl::new(MultiplayerVehicleValidator {
|
||||
multiplayer: validators.multiplayer.clone(),
|
||||
custom_game: validators.custom_game.clone(),
|
||||
singleplayer: validators.singleplayer.clone(),
|
||||
})
|
||||
}
|
||||
136
rc_services_room/src/vehicle_validators.rs
Normal file
136
rc_services_room/src/vehicle_validators.rs
Normal file
@@ -0,0 +1,136 @@
|
||||
pub type InitedVehicleValidator = Box<dyn oj_rc_plugins::vehicle_validation::VehicleValidatorPlugin>;
|
||||
|
||||
pub struct InitedVehicleValidators {
|
||||
pub multiplayer: std::sync::Arc<InitedVehicleValidator>,
|
||||
pub custom_game: std::sync::Arc<InitedVehicleValidator>,
|
||||
pub singleplayer: std::sync::Arc<InitedVehicleValidator>,
|
||||
pub campaigns: std::sync::Arc<std::collections::HashMap<String, InitedVehicleValidator>>,
|
||||
}
|
||||
|
||||
pub fn validators_from_conf(conf: &oj_rc_core::persist::config::VehicleValidators, parsers: &oj_rc_core::cubes::CubeParsers, plugins_path: impl AsRef<std::path::Path>) -> InitedVehicleValidators {
|
||||
let plugins_path = plugins_path.as_ref();
|
||||
InitedVehicleValidators {
|
||||
multiplayer: std::sync::Arc::new(validator_from_conf(&conf.multiplayer, parsers, plugins_path)),
|
||||
custom_game: std::sync::Arc::new(validator_from_conf(&conf.multiplayer, parsers, plugins_path)),
|
||||
singleplayer: std::sync::Arc::new(validator_from_conf(&conf.singleplayer, parsers, plugins_path)),
|
||||
campaigns: std::sync::Arc::new(
|
||||
conf.campaigns.iter()
|
||||
.map(|(campaign_id, validator)| (campaign_id.to_owned(), validator_from_conf(validator, parsers, plugins_path)))
|
||||
.collect()
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn validator_from_conf(conf: &oj_rc_core::persist::VehicleValidator, parsers: &oj_rc_core::cubes::CubeParsers, plugins_path: impl AsRef<std::path::Path>) -> InitedVehicleValidator {
|
||||
match conf {
|
||||
oj_rc_core::persist::VehicleValidator::None => Box::new(AlwaysValid) as _,
|
||||
oj_rc_core::persist::VehicleValidator::Cpu { min, max } => Box::new(CpuRange {
|
||||
range: *min..=*max,
|
||||
parser: parsers.cpu_counter(),
|
||||
}) as _,
|
||||
oj_rc_core::persist::VehicleValidator::All { all } => Box::new(All::init(all, parsers, plugins_path)) as _,
|
||||
oj_rc_core::persist::VehicleValidator::Any { any } => Box::new(Any::init(any, parsers, plugins_path)) as _,
|
||||
oj_rc_core::persist::VehicleValidator::Custom { path } => {
|
||||
let full_path = plugins_path.as_ref().join(path);
|
||||
log::warn!("Custom vehicle validator plugin {} is experimental and insecure", full_path.display());
|
||||
let result = oj_rc_plugins::vehicle_validation::VehicleValidatorCPlugin::new(&full_path);
|
||||
match result {
|
||||
Ok(c_plugin) => Box::new(c_plugin) as _,
|
||||
Err(e) => {
|
||||
log::error!("Failed to load custom vehicle validator plugin {}: {} (crashing!)", full_path.display(), e);
|
||||
panic!("Failed to load custom vehicle validator plugin {}: {}", full_path.display(), e)
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
struct AlwaysValid;
|
||||
|
||||
impl oj_rc_plugins::vehicle_validation::VehicleValidatorPlugin for AlwaysValid {
|
||||
fn validate(&self, _cube_data: &[u8], _colour_data: &[u8]) -> oj_rc_plugins::vehicle_validation::ValidationResultCode {
|
||||
oj_rc_plugins::vehicle_validation::ValidationResultCode::Ok
|
||||
}
|
||||
}
|
||||
|
||||
impl oj_rc_plugins::Plugin for AlwaysValid {}
|
||||
|
||||
struct CpuRange {
|
||||
range: std::ops::RangeInclusive<u32>,
|
||||
parser: std::sync::Arc<oj_rc_core::cubes::CpuListParser>,
|
||||
}
|
||||
|
||||
impl oj_rc_plugins::vehicle_validation::VehicleValidatorPlugin for CpuRange {
|
||||
fn validate(&self, cube_data: &[u8], _colour_data: &[u8]) -> oj_rc_plugins::vehicle_validation::ValidationResultCode {
|
||||
let cpu_info = self.parser.calculate_cpu(&mut std::io::Cursor::new(cube_data));
|
||||
if self.range.contains(&(cpu_info.total - cpu_info.cosmetic)) {
|
||||
oj_rc_plugins::vehicle_validation::ValidationResultCode::Ok
|
||||
} else {
|
||||
oj_rc_plugins::vehicle_validation::ValidationResultCode::Invalid
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl oj_rc_plugins::Plugin for CpuRange {}
|
||||
|
||||
struct All(Vec<InitedVehicleValidator>);
|
||||
|
||||
impl All {
|
||||
fn init(items: &[oj_rc_core::persist::VehicleValidator], parsers: &oj_rc_core::cubes::CubeParsers, plugins_path: impl AsRef<std::path::Path>) -> Self {
|
||||
let plugins_path = plugins_path.as_ref();
|
||||
All(
|
||||
items.iter()
|
||||
.map(|item| validator_from_conf(item, parsers, plugins_path))
|
||||
.collect()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl oj_rc_plugins::vehicle_validation::VehicleValidatorPlugin for All {
|
||||
fn validate(&self, cube_data: &[u8], colour_data: &[u8]) -> oj_rc_plugins::vehicle_validation::ValidationResultCode {
|
||||
self.0.iter()
|
||||
.filter_map(|item| {
|
||||
let code = item.validate(cube_data, colour_data);
|
||||
if matches!(code, oj_rc_plugins::vehicle_validation::ValidationResultCode::Ok) {
|
||||
None
|
||||
} else {
|
||||
Some(code)
|
||||
}
|
||||
})
|
||||
.next()
|
||||
.unwrap_or(oj_rc_plugins::vehicle_validation::ValidationResultCode::Ok)
|
||||
}
|
||||
}
|
||||
|
||||
impl oj_rc_plugins::Plugin for All {}
|
||||
|
||||
struct Any(Vec<InitedVehicleValidator>);
|
||||
|
||||
impl Any {
|
||||
fn init(items: &[oj_rc_core::persist::VehicleValidator], parsers: &oj_rc_core::cubes::CubeParsers, plugins_path: impl AsRef<std::path::Path>) -> Self {
|
||||
let plugins_path = plugins_path.as_ref();
|
||||
Any(
|
||||
items.iter()
|
||||
.map(|item| validator_from_conf(item, parsers, plugins_path))
|
||||
.collect()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl oj_rc_plugins::vehicle_validation::VehicleValidatorPlugin for Any {
|
||||
fn validate(&self, cube_data: &[u8], colour_data: &[u8]) -> oj_rc_plugins::vehicle_validation::ValidationResultCode {
|
||||
self.0.iter()
|
||||
.map_while(|item| {
|
||||
let code = item.validate(cube_data, colour_data);
|
||||
if matches!(code, oj_rc_plugins::vehicle_validation::ValidationResultCode::Ok) {
|
||||
None
|
||||
} else {
|
||||
Some(code)
|
||||
}
|
||||
})
|
||||
.next()
|
||||
.unwrap_or(oj_rc_plugins::vehicle_validation::ValidationResultCode::Ok)
|
||||
}
|
||||
}
|
||||
|
||||
impl oj_rc_plugins::Plugin for Any {}
|
||||
Reference in New Issue
Block a user