Sequential Modes Check #260
@@ -47,12 +47,20 @@ impl From<crate::nats_types::CheckSubmissionRequest> for CheckRequest{
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,Copy,Debug,Hash,Eq,PartialEq)]
|
||||
#[derive(Clone,Copy,Debug,Hash,Eq,PartialEq,Ord,PartialOrd)]
|
||||
struct ModeID(u64);
|
||||
impl ModeID{
|
||||
const MAIN:Self=Self(0);
|
||||
const BONUS:Self=Self(1);
|
||||
}
|
||||
impl std::fmt::Display for ModeID{
|
||||
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||
match self{
|
||||
&ModeID::MAIN=>write!(f,"Main"),
|
||||
&ModeID(mode_id)=>write!(f,"Bonus{mode_id}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
enum Zone{
|
||||
Start,
|
||||
Finish,
|
||||
@@ -446,6 +454,8 @@ struct MapCheck<'a>{
|
||||
mode_finish_counts:SetDifferenceCheck<SetDifferenceCheckContextAtLeastOne<ModeID,Vec<&'a Instance>>>,
|
||||
// Check for dangling MapAnticheat zones (no associated MapStart)
|
||||
mode_anticheat_counts:SetDifferenceCheck<SetDifferenceCheckContextAllowNone<ModeID,Vec<&'a Instance>>>,
|
||||
// Check that modes are sequential
|
||||
modes_sequential:Result<(),Vec<ModeID>>,
|
||||
// Spawn1 must exist
|
||||
spawn1:Result<Exists,Absent>,
|
||||
// Check for dangling Teleport# (no associated Spawn#)
|
||||
@@ -514,6 +524,33 @@ impl<'a> ModelInfo<'a>{
|
||||
let mode_anticheat_counts=SetDifferenceCheckContextAllowNone::new(self.counts.mode_anticheat_counts)
|
||||
.check(&self.counts.mode_start_counts);
|
||||
|
||||
// There must not be non-sequential modes. If Bonus100 exists, Bonuses 1-99 had better also exist.
|
||||
fn count_sequential(modes:&HashMap<ModeID,Vec<&Instance>>)->usize{
|
||||
for mode_id in 0..modes.len(){
|
||||
if !modes.contains_key(&ModeID(mode_id as u64)){
|
||||
return mode_id;
|
||||
}
|
||||
}
|
||||
return modes.len();
|
||||
}
|
||||
let modes_sequential={
|
||||
let sequential=count_sequential(&self.counts.mode_start_counts);
|
||||
if sequential==self.counts.mode_start_counts.len(){
|
||||
Ok(())
|
||||
}else{
|
||||
let mut non_sequential=Vec::with_capacity(self.counts.mode_start_counts.len()-sequential);
|
||||
for (&mode_id,_) in &self.counts.mode_start_counts{
|
||||
let ModeID(mode_id_u64)=mode_id;
|
||||
if !(mode_id_u64<sequential as u64){
|
||||
non_sequential.push(mode_id);
|
||||
}
|
||||
}
|
||||
// sort so it's prettier when it prints out
|
||||
non_sequential.sort();
|
||||
Err(non_sequential)
|
||||
}
|
||||
};
|
||||
|
||||
// There must be exactly one start zone for every mode in the map.
|
||||
let mode_start_counts=DuplicateCheckContext(self.counts.mode_start_counts).check(|c|1<c.len());
|
||||
|
||||
@@ -550,6 +587,7 @@ impl<'a> ModelInfo<'a>{
|
||||
mode_start_counts,
|
||||
mode_finish_counts,
|
||||
mode_anticheat_counts,
|
||||
modes_sequential,
|
||||
spawn1,
|
||||
teleport_counts,
|
||||
spawn_counts,
|
||||
@@ -573,6 +611,7 @@ impl MapCheck<'_>{
|
||||
mode_start_counts:DuplicateCheck(Ok(())),
|
||||
mode_finish_counts:SetDifferenceCheck(Ok(())),
|
||||
mode_anticheat_counts:SetDifferenceCheck(Ok(())),
|
||||
modes_sequential:Ok(()),
|
||||
spawn1:Ok(Exists),
|
||||
teleport_counts:SetDifferenceCheck(Ok(())),
|
||||
spawn_counts:DuplicateCheck(Ok(())),
|
||||
@@ -746,6 +785,15 @@ impl MapCheck<'_>{
|
||||
}
|
||||
}
|
||||
};
|
||||
let sequential_modes=match &self.modes_sequential{
|
||||
Ok(())=>passed!("SequentialModes"),
|
||||
Err(context)=>{
|
||||
let non_sequential=context.len();
|
||||
let plural_non_sequential=if non_sequential==1{"mode"}else{"modes"};
|
||||
let comma_separated=Separated::new(", ",||context.iter());
|
||||
summary_format!("SequentialModes","{non_sequential} {plural_non_sequential} should use a lower ModeID (no gaps): {comma_separated}")
|
||||
}
|
||||
};
|
||||
let spawn1=match &self.spawn1{
|
||||
Ok(Exists)=>passed!("Spawn1"),
|
||||
Err(Absent)=>summary_format!("Spawn1","Model has no Spawn1"),
|
||||
@@ -824,6 +872,7 @@ impl MapCheck<'_>{
|
||||
extra_finish,
|
||||
missing_finish,
|
||||
dangling_anticheat,
|
||||
sequential_modes,
|
||||
spawn1,
|
||||
dangling_teleport,
|
||||
duplicate_spawns,
|
||||
|
||||
Reference in New Issue
Block a user