Submission Validation Requirements #105

Closed
opened 2025-04-06 03:07:51 +00:00 by Quaternions · 6 comments
Owner

To create a new submission the following requirements must be met:

  • Model contains DisplayName StringValue
  • Model contains Creator StringValue
  • bhop_ or surf_ or flytrials_ model name prefix

To "Submit" a map (after creating the submission) the following requirements must be met:

  • Exactly one MapStart
  • At least one MapFinish
  • Spawn0 or Spawn1 must exist
  • No duplicate Spawn#
  • No duplicate WormholeOut# (duplicate WormholeIn# ok)
To create a new submission the following requirements must be met: - Model contains DisplayName StringValue - Model contains Creator StringValue - `bhop_` or `surf_` or `flytrials_` model name prefix To "Submit" a map (after creating the submission) the following requirements must be met: - Exactly one `MapStart` - At least one `MapFinish` - `Spawn0` or `Spawn1` must exist - No duplicate `Spawn#` - No duplicate WormholeOut# (duplicate WormholeIn# ok)
Quaternions added the
validator
label 2025-04-06 03:12:42 +00:00
Quaternions added this to the 1.1 Centralize Maptest milestone 2025-04-06 03:12:46 +00:00

the maptest bot currently checks:

  • the model must have exactly 1 root part (models uploaded to roblox can have multiple roots)
  • the root must be of class Model
  • the prefix of the model's name must match the game it was submitted for. bhop_ for bhop, and surf_ for surf
  • your model's name must match this regex: ^[a-z0-9_]
  • map must have a StringValue named Creator and DisplayName. additionally, they must both have a value
  • the display name must be capitalized
  • there must be exactly 1 MapStart
  • there must be at least 1 MapFinish
  • they must have CanCollide disabled (does this matter anymore?)
  • there must be a Spawn1 part
  • you cannot have duplicate Spawn# parts
  • you cannot have any Scripts or ModuleScripts that have the keyword 'getfenv" or 'require'
  • you cannot have more than 50 duplicate scripts
the maptest bot currently checks: - the model must have exactly 1 root part (models uploaded to roblox can have multiple roots) - the root must be of class `Model` - the prefix of the model's name must match the game it was submitted for. `bhop_` for bhop, and `surf_` for surf - your model's name must match this regex: `^[a-z0-9_]` - map must have a `StringValue` named `Creator` and `DisplayName`. additionally, they must both have a value - the display name must be capitalized - there must be exactly 1 `MapStart` - there must be at least 1 `MapFinish` - they must have CanCollide disabled (does this matter anymore?) - there must be a `Spawn1` part - you cannot have duplicate `Spawn#` parts - you cannot have any `Script`s or `ModuleScript`s that have the keyword 'getfenv" or 'require' - you cannot have more than 50 duplicate scripts

for reference:

common.js Line 181 in 7e3b03ff07
let modelDomRes;

for reference: https://git.itzana.me/StrafesNET/maptest-bot/src/commit/7e3b03ff07189c56e312f7c026daea8f36389d89/common.js#L181
Author
Owner

Thanks for the list.

they must have CanCollide disabled (does this matter anymore?)

This was fixed in the 2022 physics update

50 duplicate scripts

Tough stuff

Thanks for the list. > they must have CanCollide disabled (does this matter anymore?) This was fixed in the 2022 physics update > 50 duplicate scripts Tough stuff
Author
Owner

I wrote a prototype on the checks branch, still need to actually use them at submission time though.

validation/src/check.rs Lines 121 to 216 in 7520c955d0
pub fn check(dom:&rbx_dom_weak::WeakDom)->CheckReport{
// empty report with all checks failed
let mut report=CheckReport::default();
// extract the root instance, otherwise immediately return
let Ok(model_instance)=get_root_instance(&dom)else{
return report;
};
report.exactly_one_root=true;
if model_instance.class=="Model"{
report.root_is_model=true;
}
if model_instance.name==model_instance.name.to_snake_case(){
report.model_name_is_snake_case=true;
}
// extract model info
let MapInfo{display_name,creator,game_id}=get_mapinfo(&dom,model_instance);
// check DisplayName
if let Ok(display_name)=display_name{
if !display_name.is_empty(){
report.has_display_name=true;
if display_name==display_name.to_title_case(){
report.display_name_is_title_case=true;
}
}
}
// check Creator
if let Ok(creator)=creator{
if !creator.is_empty(){
report.has_creator=true;
}
}
// check GameID
if game_id.is_ok(){
report.model_name_prefix_is_valid=true;
}
// === MODE CHECKS ===
// count objects
let mut counts=Counts::new();
for instance in dom.descendants_of(model_instance.referent()){
if class_is_a(instance.class.as_str(),"BasePart"){
// Zones
match instance.name.parse(){
Ok(Zone::Start(mode_id))=>*counts.mode_start_counts.entry(mode_id).or_insert(0)+=1,
Ok(Zone::Finish(mode_id))=>*counts.mode_finish_counts.entry(mode_id).or_insert(0)+=1,
_=>(),
}
// Spawns
let spawn_pattern=lazy_regex::lazy_regex!(r"^Spawn(\d+)$");
if let Some(captures)=spawn_pattern.captures(instance.name.as_str()){
if let Ok(spawn_id)=captures[1].parse(){
*counts.spawn_counts.entry(SpawnID(spawn_id)).or_insert(0)+=1;
}
}
// WormholeOuts
let wormhole_out_pattern=lazy_regex::lazy_regex!(r"^WormholeOut(\d+)$");
if let Some(captures)=wormhole_out_pattern.captures(instance.name.as_str()){
if let Ok(wormhole_out_id)=captures[1].parse(){
*counts.wormhole_out_counts.entry(WormholeOutID(wormhole_out_id)).or_insert(0)+=1;
}
}
}
}
// MapStart must exist && there must be exactly one of any bonus start zones.
if counts.mode_start_counts.get(&ModeID::MAIN)==Some(&1)
&&counts.mode_start_counts.iter().all(|(_,&c)|c==1){
report.exactly_one_mapstart=true;
}
// iterate over start zones
if counts.mode_start_counts.iter().all(|(mode_id,_)|
// ensure that at least one end zone exists with the same mode id
counts.mode_finish_counts.get(mode_id).is_some_and(|&num|0<num)
){
report.at_least_one_mapfinish=true;
}
// Spawn1 must exist
if counts.spawn_counts.get(&SpawnID::FIRST).is_some(){
report.spawn1_exists=true;
}
if counts.spawn_counts.iter().all(|(_,&c)|c==1){
report.no_duplicate_spawns=true;
}
if counts.wormhole_out_counts.iter().all(|(_,&c)|c==1){
report.no_duplicate_wormhole_out=true;
}
report
}

I wrote a prototype on the `checks` branch, still need to actually use them at submission time though. https://git.itzana.me/StrafesNET/maps-service/src/commit/7520c955d05a663e0d51768a0e1f980166e2a6f8/validation/src/check.rs#L121-L216
Author
Owner

Closed by .

Closed by #119.
Author
Owner

Refactored in .

Old error message:

exactly_one_root=passed root_is_model=passed model_name_prefix_is_valid=passed model_name_is_snake_case=passed has_display_name=passed has_creator=passed display_name_is_title_case=failed exactly_one_mapstart=passed at_least_one_mapfinish=passed spawn1_exists=passed no_duplicate_spawns=passed no_duplicate_wormhole_out=passed

New error message:

Invalid DisplayName: expected: Eazy V2, observed: Eazy v2
Refactored in #126. Old error message: ``` exactly_one_root=passed root_is_model=passed model_name_prefix_is_valid=passed model_name_is_snake_case=passed has_display_name=passed has_creator=passed display_name_is_title_case=failed exactly_one_mapstart=passed at_least_one_mapfinish=passed spawn1_exists=passed no_duplicate_spawns=passed no_duplicate_wormhole_out=passed ``` New error message: ``` Invalid DisplayName: expected: Eazy V2, observed: Eazy v2 ```
Sign in to join this conversation.
No description provided.