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:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -2661,6 +2661,7 @@ dependencies = [
|
|||||||
"oj_polariton_auth",
|
"oj_polariton_auth",
|
||||||
"oj_rc_core",
|
"oj_rc_core",
|
||||||
"oj_rc_factory",
|
"oj_rc_factory",
|
||||||
|
"oj_rc_plugins",
|
||||||
"oj_serdes",
|
"oj_serdes",
|
||||||
"polariton",
|
"polariton",
|
||||||
"polariton_server",
|
"polariton_server",
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ impl PlayerDatas {
|
|||||||
pub fn as_transmissible<C>(&self) -> Typed<C> {
|
pub fn as_transmissible<C>(&self) -> Typed<C> {
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
let write_size = self.dump(&mut std::io::Cursor::new(&mut buf)).unwrap();
|
let write_size = self.dump(&mut std::io::Cursor::new(&mut buf)).unwrap();
|
||||||
log::debug!("PlayerDatas serialized to {} bytes: {:?}", write_size, buf);
|
log::debug!("PlayerDatas serialized to {} bytes", write_size);
|
||||||
Typed::Bytes(buf.into())
|
Typed::Bytes(buf.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -428,6 +428,7 @@ pub(super) fn default_campaigns() -> super::SingleplayerConfig {
|
|||||||
time_max: 60,
|
time_max: 60,
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
vehicle_validator: super::VehicleValidator::None,
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
vehicles: vec![
|
vehicles: vec![
|
||||||
@@ -454,6 +455,7 @@ pub(super) fn default_campaigns() -> super::SingleplayerConfig {
|
|||||||
],
|
],
|
||||||
max_teammates: 0,
|
max_teammates: 0,
|
||||||
max_enemies: 5,
|
max_enemies: 5,
|
||||||
|
vehicle_validator: super::VehicleValidator::None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -629,6 +631,7 @@ fn default_multiplayer() -> super::MultiplayerConfig {
|
|||||||
battle_arena: super::multiplayer::default_ba_conf(),
|
battle_arena: super::multiplayer::default_ba_conf(),
|
||||||
pit_config: super::multiplayer::default_pit_conf(),
|
pit_config: super::multiplayer::default_pit_conf(),
|
||||||
team_death_match: super::multiplayer::default_tdm_conf(),
|
team_death_match: super::multiplayer::default_tdm_conf(),
|
||||||
|
vehicle_validator: super::multiplayer::default_validator(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -553,4 +553,15 @@ impl <C: Clone + Send> super::ConfigProvider<C> for CubeConfig {
|
|||||||
}
|
}
|
||||||
map
|
map
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn vehicle_validation(&self) -> super::VehicleValidators {
|
||||||
|
super::VehicleValidators {
|
||||||
|
multiplayer: self.battle.multiplayer.vehicle_validator.clone(),
|
||||||
|
custom_game: crate::persist::VehicleValidator::None, // TODO
|
||||||
|
singleplayer: self.battle.singleplayer.vehicle_validator.clone(),
|
||||||
|
campaigns: self.battle.singleplayer.campaigns.iter()
|
||||||
|
.map(|campaign| (campaign.id.clone(), campaign.vehicle_validator.clone()))
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ mod cubes_json;
|
|||||||
pub use cubes_json::CubeConfig;
|
pub use cubes_json::CubeConfig;
|
||||||
|
|
||||||
mod traits;
|
mod traits;
|
||||||
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, ShopEntriesResolver, ShopAction, ShopGain, PromoCode, MultiplayerSettings, BattleArenaCrystalParams};
|
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, ShopEntriesResolver, ShopAction, ShopGain, PromoCode, MultiplayerSettings, BattleArenaCrystalParams, VehicleValidators};
|
||||||
|
|
||||||
mod validation;
|
mod validation;
|
||||||
pub use validation::{SelfValidator, ValidationInfo, ValidationMessage};
|
pub use validation::{SelfValidator, ValidationInfo, ValidationMessage};
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ pub trait ConfigProvider<C: Clone> {
|
|||||||
fn tdm_settings(&self) -> TeamDeathMatchSettings;
|
fn tdm_settings(&self) -> TeamDeathMatchSettings;
|
||||||
fn shop_entries(&self) -> ShopEntriesResolver;
|
fn shop_entries(&self) -> ShopEntriesResolver;
|
||||||
fn promo_codes(&self) -> std::collections::HashMap<String, PromoCode>;
|
fn promo_codes(&self) -> std::collections::HashMap<String, PromoCode>;
|
||||||
|
fn vehicle_validation(&self) -> VehicleValidators;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DevMessageProvider<C: Clone> {
|
pub struct DevMessageProvider<C: Clone> {
|
||||||
@@ -536,3 +537,11 @@ pub struct MultiplayerSettings {
|
|||||||
pub lobby_autostart_after: Option<std::time::Duration>,
|
pub lobby_autostart_after: Option<std::time::Duration>,
|
||||||
pub loading_autostart_after: Option<std::time::Duration>,
|
pub loading_autostart_after: Option<std::time::Duration>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct VehicleValidators {
|
||||||
|
// FIXME don't use serializable types in traits
|
||||||
|
pub multiplayer: crate::persist::VehicleValidator,
|
||||||
|
pub custom_game: crate::persist::VehicleValidator,
|
||||||
|
pub singleplayer: crate::persist::VehicleValidator,
|
||||||
|
pub campaigns: std::collections::HashMap<String, crate::persist::VehicleValidator>,
|
||||||
|
}
|
||||||
|
|||||||
@@ -44,6 +44,9 @@ pub use maps::{MapsConfig, MapConfig};
|
|||||||
mod item_shop;
|
mod item_shop;
|
||||||
pub use item_shop::{ItemShopConfig, ItemBundle};
|
pub use item_shop::{ItemShopConfig, ItemBundle};
|
||||||
|
|
||||||
|
mod vehicle_validator;
|
||||||
|
pub use vehicle_validator::VehicleValidator;
|
||||||
|
|
||||||
const VALID_ROBOT: &[u8] = &[64,
|
const VALID_ROBOT: &[u8] = &[64,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ pub struct MultiplayerConfig {
|
|||||||
pub pit_config: PitConfig,
|
pub pit_config: PitConfig,
|
||||||
#[serde(default = "default_tdm_conf")]
|
#[serde(default = "default_tdm_conf")]
|
||||||
pub team_death_match: TeamDeathMatchConfig,
|
pub team_death_match: TeamDeathMatchConfig,
|
||||||
|
#[serde(default = "default_validator")]
|
||||||
|
pub vehicle_validator: super::VehicleValidator,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl super::config::SelfValidator for MultiplayerConfig {
|
impl super::config::SelfValidator for MultiplayerConfig {
|
||||||
@@ -525,3 +527,10 @@ pub(super) fn default_tdm_conf() -> TeamDeathMatchConfig {
|
|||||||
self_destruct_is_kill: true,
|
self_destruct_is_kill: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn default_validator() -> super::VehicleValidator {
|
||||||
|
super::VehicleValidator::Cpu {
|
||||||
|
min: 100,
|
||||||
|
max: 2_000,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ pub struct SingleplayerConfig {
|
|||||||
pub vehicles: Vec<super::PrefabVehicle>,
|
pub vehicles: Vec<super::PrefabVehicle>,
|
||||||
pub max_teammates: u32,
|
pub max_teammates: u32,
|
||||||
pub max_enemies: u32,
|
pub max_enemies: u32,
|
||||||
|
#[serde(default = "default_singleplayer_vehicle_validator")]
|
||||||
|
pub vehicle_validator: super::VehicleValidator,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SingleplayerConfig {
|
impl SingleplayerConfig {
|
||||||
@@ -62,6 +64,8 @@ pub struct Campaign {
|
|||||||
pub map: String,
|
pub map: String,
|
||||||
pub campaign_type: CampaignType,
|
pub campaign_type: CampaignType,
|
||||||
pub waves: Vec<Wave>,
|
pub waves: Vec<Wave>,
|
||||||
|
#[serde(default = "default_campaign_vehicle_validator")]
|
||||||
|
pub vehicle_validator: super::VehicleValidator,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Campaign {
|
impl Campaign {
|
||||||
@@ -193,3 +197,11 @@ impl std::convert::From<CampaignType> for crate::data::campaign::CampaignType {
|
|||||||
fn default_campaigns() -> Vec<Campaign> {
|
fn default_campaigns() -> Vec<Campaign> {
|
||||||
super::combat::default_campaigns().campaigns
|
super::combat::default_campaigns().campaigns
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_campaign_vehicle_validator() -> super::VehicleValidator {
|
||||||
|
super::VehicleValidator::None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_singleplayer_vehicle_validator() -> super::VehicleValidator {
|
||||||
|
super::VehicleValidator::None
|
||||||
|
}
|
||||||
|
|||||||
@@ -859,6 +859,36 @@ impl <C: Clone + Send> super::User<C> for UserData {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn selected_vehicle_data(&self) -> Result<super::VehicleData, polariton_server::operations::SimpleOpError> {
|
||||||
|
let garage = self.db.garage_selected(self.account.id).await
|
||||||
|
.map_err(|e| {
|
||||||
|
log::error!("Failed to retrieve selected garage data for user_id {}: {}", self.account.id, e);
|
||||||
|
polariton_server::operations::SimpleOpError::with_message(
|
||||||
|
crate::data::error_codes::WebServicesError::DatabaseError as i16,
|
||||||
|
"Failed to retrieve selected garage data for user".to_owned(),
|
||||||
|
)
|
||||||
|
})?
|
||||||
|
.ok_or_else(|| {
|
||||||
|
log::error!("No selected garage data for user_id {}", self.account.id);
|
||||||
|
polariton_server::operations::SimpleOpError::with_message(
|
||||||
|
crate::data::error_codes::WebServicesError::UnexpectedError as i16,
|
||||||
|
"No selected garage data for user".to_owned(),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
Ok(super::VehicleData {
|
||||||
|
name: Some(garage.name),
|
||||||
|
slot: garage.slot,
|
||||||
|
robot_data: garage.robot_data,
|
||||||
|
colour_data: garage.colour_data,
|
||||||
|
weapon_order: oj_rc_database::schema::parse_int_csv(&garage.weapon_order)
|
||||||
|
.into_iter()
|
||||||
|
.map(|x| x as i32)
|
||||||
|
.collect(),
|
||||||
|
crf_id: garage.crf_id,
|
||||||
|
was_rated: Some(garage.was_rated),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
async fn all_slots(&self) -> super::UserSlots<C> {
|
async fn all_slots(&self) -> super::UserSlots<C> {
|
||||||
let slots = match self.all_vehicles().await {
|
let slots = match self.all_vehicles().await {
|
||||||
Ok(slots) => slots,
|
Ok(slots) => slots,
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ pub trait User<C>: ChatUser + SocialUser + SocialUserC<C> + LobbyUser + Multipla
|
|||||||
async fn unlock_parts(&self, parts: &[u32]) -> Result<(), polariton_server::operations::SimpleOpError>;
|
async fn unlock_parts(&self, parts: &[u32]) -> Result<(), polariton_server::operations::SimpleOpError>;
|
||||||
async fn selected_garage(&self) -> (String, u32);
|
async fn selected_garage(&self) -> (String, u32);
|
||||||
async fn select_garage(&self, slot: i32) -> Result<(), i16>;
|
async fn select_garage(&self, slot: i32) -> Result<(), i16>;
|
||||||
|
async fn selected_vehicle_data(&self) -> Result<VehicleData, polariton_server::operations::SimpleOpError>;
|
||||||
async fn all_slots(&self) -> UserSlots<C>;
|
async fn all_slots(&self) -> UserSlots<C>;
|
||||||
async fn slot_by_id(&self, id: i32) -> Result<UserSlotData<C>, i16>;
|
async fn slot_by_id(&self, id: i32) -> Result<UserSlotData<C>, i16>;
|
||||||
async fn save_slot(&self, vehicle: VehicleData, cpu_counter: &crate::cubes::CpuListParser) -> Result<(), i16>;
|
async fn save_slot(&self, vehicle: VehicleData, cpu_counter: &crate::cubes::CpuListParser) -> Result<(), i16>;
|
||||||
|
|||||||
22
rc_core/src/persist/vehicle_validator.rs
Normal file
22
rc_core/src/persist/vehicle_validator.rs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
#[serde(tag = "validator")]
|
||||||
|
pub enum VehicleValidator {
|
||||||
|
None,
|
||||||
|
Cpu {
|
||||||
|
min: u32,
|
||||||
|
max: u32,
|
||||||
|
},
|
||||||
|
// TODO other validators
|
||||||
|
All {
|
||||||
|
all: Vec<Self>,
|
||||||
|
},
|
||||||
|
Any {
|
||||||
|
any: Vec<Self>,
|
||||||
|
},
|
||||||
|
Custom {
|
||||||
|
#[serde(alias = "library")]
|
||||||
|
path: String,
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -19,7 +19,7 @@ impl ChatCPlugin {
|
|||||||
let dll = unsafe { libloading::Library::new(file.as_ref()) }?;
|
let dll = unsafe { libloading::Library::new(file.as_ref()) }?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
dll,
|
dll,
|
||||||
pretty_name: file.as_ref().to_string_lossy().to_string(),
|
pretty_name: file.as_ref().display().to_string(),
|
||||||
provider: std::sync::Mutex::new(None),
|
provider: std::sync::Mutex::new(None),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
pub mod chat;
|
pub mod chat;
|
||||||
|
pub mod vehicle_validation;
|
||||||
|
|
||||||
pub trait Plugin: Send + Sync {}
|
pub trait Plugin: Send + Sync {
|
||||||
|
fn self_check(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
48
rc_plugins/src/vehicle_validation/c_binding.rs
Normal file
48
rc_plugins/src/vehicle_validation/c_binding.rs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
//! The foreign function interface implementation for validation vehicles in different shared objects/libraries.
|
||||||
|
//use std::ffi::{CString, c_char, CStr};
|
||||||
|
|
||||||
|
const VALIDATE_VEHICLE_SYMBOL_NAME: &[u8] = b"oj_rc_validate_vehicle";
|
||||||
|
const VALIDATE_VEHICLE_SYMBOL_NAME_STR: &str = "oj_rc_validate_vehicle";
|
||||||
|
|
||||||
|
pub struct VehicleValidatorCPlugin {
|
||||||
|
dll: libloading::Library,
|
||||||
|
pretty_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VehicleValidatorCPlugin {
|
||||||
|
pub fn new(file: impl AsRef<std::path::Path>) -> Result<Self, libloading::Error> {
|
||||||
|
let dll = unsafe { libloading::Library::new(file.as_ref()) }?;
|
||||||
|
Ok(Self {
|
||||||
|
dll,
|
||||||
|
pretty_name: file.as_ref().display().to_string(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl super::VehicleValidatorPlugin for VehicleValidatorCPlugin {
|
||||||
|
fn validate(&self, cube_data: &[u8], colour_data: &[u8]) -> super::ValidationResultCode {
|
||||||
|
let func: libloading::Symbol<unsafe extern "C" fn(u32, *const u8, u32, *const u8) -> u8> = match unsafe { self.dll.get(VALIDATE_VEHICLE_SYMBOL_NAME) } {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Failed to find symbol {} in library {}: {}", VALIDATE_VEHICLE_SYMBOL_NAME_STR, self.pretty_name, e);
|
||||||
|
return super::ValidationResultCode::Invalid;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let cubes_len = cube_data.len() as u32;
|
||||||
|
let cubes = cube_data.as_ptr();
|
||||||
|
let colour_len = colour_data.len() as u32;
|
||||||
|
let colours = colour_data.as_ptr();
|
||||||
|
let code = unsafe {
|
||||||
|
func(cubes_len, cubes, colour_len, colours)
|
||||||
|
};
|
||||||
|
super::ValidationResultCode::from_u8(code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::Plugin for VehicleValidatorCPlugin {
|
||||||
|
fn self_check(&self) -> bool {
|
||||||
|
unsafe {
|
||||||
|
self.dll.get::<unsafe extern "C" fn(u32, *const u8, u32, *const u8) -> u8>(VALIDATE_VEHICLE_SYMBOL_NAME)
|
||||||
|
}.is_ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
5
rc_plugins/src/vehicle_validation/mod.rs
Normal file
5
rc_plugins/src/vehicle_validation/mod.rs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
mod plugin;
|
||||||
|
pub use plugin::{ValidationResultCode, VehicleValidatorPlugin};
|
||||||
|
|
||||||
|
mod c_binding;
|
||||||
|
pub use c_binding::VehicleValidatorCPlugin;
|
||||||
25
rc_plugins/src/vehicle_validation/plugin.rs
Normal file
25
rc_plugins/src/vehicle_validation/plugin.rs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#[repr(u8)]
|
||||||
|
pub enum ValidationResultCode {
|
||||||
|
Invalid = 0,
|
||||||
|
Ok = 1,
|
||||||
|
NoWeapon = 2,
|
||||||
|
NoMovement = 3,
|
||||||
|
Sanctioned = 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ValidationResultCode {
|
||||||
|
pub(super) fn from_u8(num: u8) -> Self {
|
||||||
|
match num {
|
||||||
|
0 => Self::Invalid,
|
||||||
|
1 => Self::Ok,
|
||||||
|
2 => Self::NoWeapon,
|
||||||
|
3 => Self::NoMovement,
|
||||||
|
4 => Self::Sanctioned,
|
||||||
|
_ => Self::Invalid,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait VehicleValidatorPlugin: crate::Plugin {
|
||||||
|
fn validate(&self, cube_data: &[u8], colour_data: &[u8]) -> ValidationResultCode;
|
||||||
|
}
|
||||||
@@ -27,3 +27,4 @@ async-trait.workspace = true
|
|||||||
git-version.workspace = true
|
git-version.workspace = true
|
||||||
libfj.workspace = true
|
libfj.workspace = true
|
||||||
oj_serdes.workspace = true
|
oj_serdes.workspace = true
|
||||||
|
oj_rc_plugins = { version = "*", path = "../rc_plugins" }
|
||||||
|
|||||||
@@ -29,3 +29,4 @@ pub mod quest;
|
|||||||
pub mod score_multipliers;
|
pub mod score_multipliers;
|
||||||
//pub use oj_rc_core::data::campaign;
|
//pub use oj_rc_core::data::campaign;
|
||||||
pub use oj_rc_core::data::crf;
|
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 data;
|
||||||
mod events;
|
mod events;
|
||||||
mod operations;
|
mod operations;
|
||||||
|
mod vehicle_validators;
|
||||||
|
|
||||||
use oj_polariton_auth::Handshake;
|
use oj_polariton_auth::Handshake;
|
||||||
use tokio::net;
|
use tokio::net;
|
||||||
@@ -23,6 +24,7 @@ pub struct InitConfig {
|
|||||||
pub users: std::sync::Arc<oj_rc_core::persist::user::UserImpl>,
|
pub users: std::sync::Arc<oj_rc_core::persist::user::UserImpl>,
|
||||||
pub factory: std::sync::Arc<oj_rc_core::factory::Factory>,
|
pub factory: std::sync::Arc<oj_rc_core::factory::Factory>,
|
||||||
pub parsers: oj_rc_core::cubes::CubeParsers,
|
pub parsers: oj_rc_core::cubes::CubeParsers,
|
||||||
|
pub vehicle_validators: vehicle_validators::InitedVehicleValidators,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[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 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 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 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 {
|
let init_ctx = std::sync::Arc::new(InitConfig {
|
||||||
cubes,
|
cubes,
|
||||||
users,
|
users,
|
||||||
factory,
|
factory,
|
||||||
parsers,
|
parsers,
|
||||||
|
vehicle_validators
|
||||||
});
|
});
|
||||||
|
|
||||||
let server = std::sync::Arc::new(polariton_server::Server::new(operations::handler(&init_ctx), polariton_server::events::EventsHandler::new()));
|
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> {
|
async fn handle(&self, params: ParameterTable<C>, user: &Self::User) -> Result<ParameterTable<C>, SimpleOpError> {
|
||||||
let user_info = user.user()?;
|
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 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();
|
let mut params = params.to_dict();
|
||||||
params.insert(PARAM_KEY, data);
|
params.insert(PARAM_KEY, data);
|
||||||
|
|||||||
@@ -75,7 +75,8 @@ mod reconnect_game;
|
|||||||
mod regen_config;
|
mod regen_config;
|
||||||
mod pageantry;
|
mod pageantry;
|
||||||
mod signup_time;
|
mod signup_time;
|
||||||
mod validate_machine;
|
mod validate_vehicle_by_lobby;
|
||||||
|
mod validate_vehicle_by_campaign;
|
||||||
mod game_mode_config;
|
mod game_mode_config;
|
||||||
mod score_multipliers_config;
|
mod score_multipliers_config;
|
||||||
mod player_robot_rank;
|
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(regen_config::auto_regen_config_provider(&init_ctx.cubes))
|
||||||
.add(pageantry::after_battle_vote_thresholds_provider(&init_ctx.cubes))
|
.add(pageantry::after_battle_vote_thresholds_provider(&init_ctx.cubes))
|
||||||
.add(signup_time::user_signup_date_provider())
|
.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(game_mode_config::game_mode_config_provider(&init_ctx.cubes))
|
||||||
.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_vehicle_by_campaign::validate_campaign_robot_provider(&init_ctx.vehicle_validators))
|
||||||
.add(singleplayer_campaigns::singleplayer_complete_campaign_provider(init_ctx))
|
.add(singleplayer_campaigns::singleplayer_complete_campaign_provider(init_ctx))
|
||||||
.add(campaign_save_result::campaign_save_awards_provider())
|
.add(campaign_save_result::campaign_save_awards_provider())
|
||||||
.add(singleplayer_campaigns::singleplayer_save_complete_campaign_provider()) // TODO handle UpdatePlayerCompletedCampaignWaveRequest saving
|
.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