forked from StrafesNET/map-tool
Compare commits
8 Commits
script-upl
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
4cd8c4b888
|
|||
|
1e82ad6af8
|
|||
|
4587ff89ee
|
|||
|
d27cf2d69e
|
|||
|
1f8a66638f
|
|||
| 0995ced783 | |||
| 49d071fd56 | |||
| d9a39cc046 |
1717
Cargo.lock
generated
1717
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
14
Cargo.toml
14
Cargo.toml
@@ -8,15 +8,11 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.75"
|
anyhow = "1.0.75"
|
||||||
clap = { version = "4.4.2", features = ["derive"] }
|
clap = { version = "4.4.2", features = ["derive"] }
|
||||||
futures = "0.3.31"
|
rbx_binary = "2.0.0"
|
||||||
lazy-regex = "3.1.0"
|
rbx_dom_weak = "4.0.0"
|
||||||
rbx_binary = { version = "0.7.4", registry = "strafesnet"}
|
rbx_reflection_database = "2.0.1"
|
||||||
rbx_dom_weak = { version = "2.7.0", registry = "strafesnet"}
|
rbx_xml = "2.0.0"
|
||||||
rbx_reflection_database = { version = "0.2.10", registry = "strafesnet"}
|
regex = { version = "1.11.3", default-features = false, features = ["unicode-perl"] }
|
||||||
rbx_xml = { version = "0.13.3", registry = "strafesnet"}
|
|
||||||
siphasher = "1.0.1"
|
|
||||||
submissions-api = { path = "../maps-service/validation/api", features = ["external"], default-features = false}
|
|
||||||
tokio = { version = "1.41.1", features = ["macros", "rt-multi-thread", "fs"] }
|
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
|
|||||||
317
src/main.rs
317
src/main.rs
@@ -1,24 +1,25 @@
|
|||||||
use std::{io::{Read, Seek}, path::PathBuf};
|
use std::{io::{Read, Seek}, path::PathBuf};
|
||||||
use clap::{Args, Parser, Subcommand};
|
use clap::{Args, Parser, Subcommand};
|
||||||
use anyhow::Result as AResult;
|
use anyhow::Result as AResult;
|
||||||
use futures::{StreamExt,TryStreamExt};
|
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(author,version,about,long_about=None)]
|
#[command(author, version, about, long_about = None)]
|
||||||
#[command(propagate_version=true)]
|
#[command(propagate_version = true)]
|
||||||
struct Cli{
|
struct Cli {
|
||||||
|
#[arg(long)]
|
||||||
|
path:Option<PathBuf>,
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
command:Commands,
|
command: Commands,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
enum Commands{
|
enum Commands {
|
||||||
ExtractScripts(PathBufList),
|
ExtractScripts(PathBufList),
|
||||||
Interactive,
|
Interactive,
|
||||||
Replace,
|
Replace,
|
||||||
Scan,
|
Scan,
|
||||||
Upload,
|
Upload,
|
||||||
UploadScripts(UploadScriptsCommand)
|
WriteAttributes,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Args)]
|
#[derive(Args)]
|
||||||
@@ -31,14 +32,7 @@ struct MapList {
|
|||||||
maps: Vec<u64>,
|
maps: Vec<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Args)]
|
fn main() -> AResult<()> {
|
||||||
struct UploadScriptsCommand{
|
|
||||||
#[arg(long)]
|
|
||||||
session_id:PathBuf,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::main]
|
|
||||||
async fn main() -> AResult<()> {
|
|
||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
match cli.command {
|
match cli.command {
|
||||||
Commands::ExtractScripts(pathlist)=>extract_scripts(pathlist.paths),
|
Commands::ExtractScripts(pathlist)=>extract_scripts(pathlist.paths),
|
||||||
@@ -46,7 +40,7 @@ async fn main() -> AResult<()> {
|
|||||||
Commands::Replace=>replace(),
|
Commands::Replace=>replace(),
|
||||||
Commands::Scan=>scan(),
|
Commands::Scan=>scan(),
|
||||||
Commands::Upload=>upload(),
|
Commands::Upload=>upload(),
|
||||||
Commands::UploadScripts(command)=>upload_scripts(command.session_id).await,
|
Commands::WriteAttributes=>write_attributes(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,7 +48,7 @@ fn class_is_a(class: &str, superclass: &str) -> bool {
|
|||||||
if class==superclass {
|
if class==superclass {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
let class_descriptor=rbx_reflection_database::get().classes.get(class);
|
let class_descriptor=rbx_reflection_database::get().unwrap().classes.get(class);
|
||||||
if let Some(descriptor) = &class_descriptor {
|
if let Some(descriptor) = &class_descriptor {
|
||||||
if let Some(class_super) = &descriptor.superclass {
|
if let Some(class_super) = &descriptor.superclass {
|
||||||
return class_is_a(&class_super, superclass)
|
return class_is_a(&class_super, superclass)
|
||||||
@@ -72,15 +66,16 @@ fn recursive_collect_superclass(objects: &mut std::vec::Vec<rbx_dom_weak::types:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn get_full_name(dom:&rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance) -> String{
|
|
||||||
let mut full_name=instance.name.clone();
|
fn get_full_name(dom:&rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance)->String{
|
||||||
let mut pref=instance.parent();
|
let mut names:Vec<_>=core::iter::successors(
|
||||||
while let Some(parent)=dom.get_by_ref(pref){
|
Some(instance),
|
||||||
full_name.insert(0, '.');
|
|i|dom.get_by_ref(i.parent())
|
||||||
full_name.insert_str(0, &parent.name);
|
).map(
|
||||||
pref=parent.parent();
|
|i|i.name.as_str()
|
||||||
}
|
).collect();
|
||||||
full_name
|
names.reverse();
|
||||||
|
names.join(".")
|
||||||
}
|
}
|
||||||
|
|
||||||
//scan (scripts)
|
//scan (scripts)
|
||||||
@@ -179,7 +174,17 @@ fn find_first_child_class<'a>(dom:&'a rbx_dom_weak::WeakDom,instance:&'a rbx_dom
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_mapinfo(dom:&rbx_dom_weak::WeakDom) -> AResult<(String,String,String,rbx_dom_weak::types::Ref)>{
|
struct GetMapInfoUstrs{
|
||||||
|
value:rbx_dom_weak::Ustr,
|
||||||
|
}
|
||||||
|
impl GetMapInfoUstrs{
|
||||||
|
fn new()->Self{
|
||||||
|
let value=rbx_dom_weak::ustr("Value");
|
||||||
|
Self{value}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_mapinfo(ustrs:&GetMapInfoUstrs,dom:&rbx_dom_weak::WeakDom)->AResult<(String,String,String,rbx_dom_weak::types::Ref)>{
|
||||||
let workspace_children=dom.root().children();
|
let workspace_children=dom.root().children();
|
||||||
if workspace_children.len()!=1{
|
if workspace_children.len()!=1{
|
||||||
return Err(anyhow::Error::msg("there can only be one model"));
|
return Err(anyhow::Error::msg("there can only be one model"));
|
||||||
@@ -190,8 +195,8 @@ fn get_mapinfo(dom:&rbx_dom_weak::WeakDom) -> AResult<(String,String,String,rbx_
|
|||||||
Some(rbx_dom_weak::types::Variant::String(creator_string)),
|
Some(rbx_dom_weak::types::Variant::String(creator_string)),
|
||||||
Some(rbx_dom_weak::types::Variant::String(displayname_string))
|
Some(rbx_dom_weak::types::Variant::String(displayname_string))
|
||||||
)=(
|
)=(
|
||||||
creator.properties.get("Value"),
|
creator.properties.get(&ustrs.value),
|
||||||
displayname.properties.get("Value")
|
displayname.properties.get(&ustrs.value)
|
||||||
){
|
){
|
||||||
return Ok((model_instance.name.clone(),creator_string.clone(),displayname_string.clone(),displayname.referent()));
|
return Ok((model_instance.name.clone(),creator_string.clone(),displayname_string.clone(),displayname.referent()));
|
||||||
}
|
}
|
||||||
@@ -207,6 +212,7 @@ enum Scan{
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn scan() -> AResult<()>{
|
fn scan() -> AResult<()>{
|
||||||
|
let source_ustr=rbx_dom_weak::ustr("Source");
|
||||||
let mut id = get_id()?;
|
let mut id = get_id()?;
|
||||||
//Construct allowed scripts
|
//Construct allowed scripts
|
||||||
let allowed_set = get_allowed_set()?;
|
let allowed_set = get_allowed_set()?;
|
||||||
@@ -225,7 +231,7 @@ fn scan() -> AResult<()>{
|
|||||||
let mut fail_type=Scan::Passed;
|
let mut fail_type=Scan::Passed;
|
||||||
for &script_ref in script_refs.iter() {
|
for &script_ref in script_refs.iter() {
|
||||||
if let Some(script)=dom.get_by_ref(script_ref){
|
if let Some(script)=dom.get_by_ref(script_ref){
|
||||||
if let Some(rbx_dom_weak::types::Variant::String(s)) = script.properties.get("Source") {
|
if let Some(rbx_dom_weak::types::Variant::String(s)) = script.properties.get(&source_ustr) {
|
||||||
//flag keywords and instantly fail
|
//flag keywords and instantly fail
|
||||||
if check_source_illegal_keywords(s){
|
if check_source_illegal_keywords(s){
|
||||||
println!("{:?} - flagged.",file_thing.file_name());
|
println!("{:?} - flagged.",file_thing.file_name());
|
||||||
@@ -266,6 +272,7 @@ fn scan() -> AResult<()>{
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn extract_scripts(paths: Vec<PathBuf>) -> AResult<()>{
|
fn extract_scripts(paths: Vec<PathBuf>) -> AResult<()>{
|
||||||
|
let source_ustr=rbx_dom_weak::ustr("Source");
|
||||||
let mut id = 0;
|
let mut id = 0;
|
||||||
//Construct allowed scripts
|
//Construct allowed scripts
|
||||||
let mut script_set = std::collections::HashSet::<String>::new();
|
let mut script_set = std::collections::HashSet::<String>::new();
|
||||||
@@ -281,7 +288,7 @@ fn extract_scripts(paths: Vec<PathBuf>) -> AResult<()>{
|
|||||||
//extract scribb
|
//extract scribb
|
||||||
for &script_ref in script_refs.iter() {
|
for &script_ref in script_refs.iter() {
|
||||||
if let Some(script)=dom.get_by_ref(script_ref){
|
if let Some(script)=dom.get_by_ref(script_ref){
|
||||||
if let Some(rbx_dom_weak::types::Variant::String(s)) = script.properties.get("Source") {
|
if let Some(rbx_dom_weak::types::Variant::String(s))=script.properties.get(&source_ustr){
|
||||||
if script_set.contains(s) {
|
if script_set.contains(s) {
|
||||||
continue;
|
continue;
|
||||||
}else{
|
}else{
|
||||||
@@ -301,6 +308,7 @@ fn extract_scripts(paths: Vec<PathBuf>) -> AResult<()>{
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn replace() -> AResult<()>{
|
fn replace() -> AResult<()>{
|
||||||
|
let source_ustr=rbx_dom_weak::ustr("Source");
|
||||||
let allowed_map=get_allowed_map()?;
|
let allowed_map=get_allowed_map()?;
|
||||||
let replace_map=get_replace_map()?;
|
let replace_map=get_replace_map()?;
|
||||||
|
|
||||||
@@ -316,12 +324,12 @@ fn replace() -> AResult<()>{
|
|||||||
let mut any_failed=false;
|
let mut any_failed=false;
|
||||||
for &script_ref in script_refs.iter() {
|
for &script_ref in script_refs.iter() {
|
||||||
if let Some(script)=dom.get_by_ref(script_ref){
|
if let Some(script)=dom.get_by_ref(script_ref){
|
||||||
if let Some(rbx_dom_weak::types::Variant::String(source)) = script.properties.get("Source") {
|
if let Some(rbx_dom_weak::types::Variant::String(source)) = script.properties.get(&source_ustr) {
|
||||||
if let (Some(replace_id),Some(replace_script))=(replace_map.get(source),dom.get_by_ref_mut(script.referent())) {
|
if let (Some(replace_id),Some(replace_script))=(replace_map.get(source),dom.get_by_ref_mut(script.referent())) {
|
||||||
println!("replace {}",replace_id);
|
println!("replace {}",replace_id);
|
||||||
//replace the source
|
//replace the source
|
||||||
if let Some(replace_source)=allowed_map.get(replace_id){
|
if let Some(replace_source)=allowed_map.get(replace_id){
|
||||||
replace_script.properties.insert("Source".to_string(), rbx_dom_weak::types::Variant::String(replace_source.clone()));
|
replace_script.properties.insert(source_ustr, rbx_dom_weak::types::Variant::String(replace_source.clone()));
|
||||||
}else{
|
}else{
|
||||||
println!("failed to get replacement source {}",replace_id);
|
println!("failed to get replacement source {}",replace_id);
|
||||||
any_failed=true;
|
any_failed=true;
|
||||||
@@ -379,14 +387,19 @@ impl std::str::FromStr for UploadAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn upload() -> AResult<()>{
|
fn upload() -> AResult<()>{
|
||||||
|
let gmi_ustrs=GetMapInfoUstrs::new();
|
||||||
//interactive prompt per upload:
|
//interactive prompt per upload:
|
||||||
for entry in std::fs::read_dir("maps/passed")? {
|
for entry in std::fs::read_dir("maps/passed")?{
|
||||||
let file_thing=entry?;
|
let file_thing=entry?;
|
||||||
|
if !file_thing.file_type()?.is_file(){
|
||||||
|
println!("skipping non-file: {:?}",file_thing.file_name());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
println!("map file: {:?}",file_thing.file_name());
|
println!("map file: {:?}",file_thing.file_name());
|
||||||
let mut input = std::io::BufReader::new(std::fs::File::open(file_thing.path())?);
|
let mut input = std::io::BufReader::new(std::fs::File::open(file_thing.path())?);
|
||||||
|
|
||||||
let dom = load_dom(&mut input)?;
|
let dom = load_dom(&mut input)?;
|
||||||
let (modelname,creator,displayname,_) = get_mapinfo(&dom)?;
|
let (modelname,creator,displayname,_)=get_mapinfo(&gmi_ustrs,&dom)?;
|
||||||
|
|
||||||
//Creator: [auto fill creator]
|
//Creator: [auto fill creator]
|
||||||
//DisplayName: [auto fill DisplayName]
|
//DisplayName: [auto fill DisplayName]
|
||||||
@@ -405,7 +418,7 @@ fn upload() -> AResult<()>{
|
|||||||
}
|
}
|
||||||
match upload_action {
|
match upload_action {
|
||||||
UploadAction::Upload(asset_id) => {
|
UploadAction::Upload(asset_id) => {
|
||||||
let status=std::process::Command::new("asset-tool")
|
let output=std::process::Command::new("asset-tool")
|
||||||
.args([
|
.args([
|
||||||
"upload-asset",
|
"upload-asset",
|
||||||
"--cookie-envvar","RBXCOOKIE",
|
"--cookie-envvar","RBXCOOKIE",
|
||||||
@@ -413,16 +426,17 @@ fn upload() -> AResult<()>{
|
|||||||
])
|
])
|
||||||
.arg("--asset-id").arg(asset_id.to_string())
|
.arg("--asset-id").arg(asset_id.to_string())
|
||||||
.arg("--input-file").arg(file_thing.path().into_os_string().into_string().unwrap())
|
.arg("--input-file").arg(file_thing.path().into_os_string().into_string().unwrap())
|
||||||
.status()?;
|
.output()?;
|
||||||
match status.code() {
|
match output.status.code() {
|
||||||
Some(0)=>{
|
Some(0)=>{
|
||||||
//move file
|
//move file
|
||||||
let mut dest=PathBuf::from("maps/uploaded");
|
let mut dest=PathBuf::from("maps/uploaded");
|
||||||
dest.push(file_thing.file_name());
|
dest.push(file_thing.file_name());
|
||||||
std::fs::rename(file_thing.path(), dest)?;
|
std::fs::rename(file_thing.path(), dest)?;
|
||||||
}
|
}
|
||||||
Some(code)=>println!("upload failed! code={}",code),
|
other=>{
|
||||||
None => println!("no status code!"),
|
println!("upload failed! code={:?}\noutput={}\nerr={}",other,String::from_utf8_lossy(&output.stdout),String::from_utf8_lossy(&output.stderr));
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UploadAction::Skip => continue,
|
UploadAction::Skip => continue,
|
||||||
@@ -444,9 +458,10 @@ fn upload() -> AResult<()>{
|
|||||||
let mut dest=PathBuf::from("maps/uploaded");
|
let mut dest=PathBuf::from("maps/uploaded");
|
||||||
dest.push(file_thing.file_name());
|
dest.push(file_thing.file_name());
|
||||||
std::fs::rename(file_thing.path(), dest)?;
|
std::fs::rename(file_thing.path(), dest)?;
|
||||||
}
|
},
|
||||||
Some(code)=>println!("upload failed! code={}",code),
|
other=>{
|
||||||
None => println!("no status code!"),
|
println!("upload failed! code={:?}\noutput={}\nerr={}",other,String::from_utf8_lossy(&output.stdout),String::from_utf8_lossy(&output.stderr));
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UploadAction::Delete => std::fs::remove_file(file_thing.path())?,
|
UploadAction::Delete => std::fs::remove_file(file_thing.path())?,
|
||||||
@@ -495,11 +510,20 @@ fn is_first_letter_lowercase(s:&str)->bool{
|
|||||||
s.chars().next().map(char::is_lowercase).unwrap_or(false)
|
s.chars().next().map(char::is_lowercase).unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! lazy_regex{
|
||||||
|
($r:literal)=>{{
|
||||||
|
use regex::Regex;
|
||||||
|
use std::sync::LazyLock;
|
||||||
|
static RE:LazyLock<Regex>=LazyLock::new(||Regex::new($r).unwrap());
|
||||||
|
&RE
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
fn is_title_case(display_name:&str)->bool{
|
fn is_title_case(display_name:&str)->bool{
|
||||||
display_name.len()!=0
|
display_name.len()!=0
|
||||||
&&!is_first_letter_lowercase(display_name)
|
&&!is_first_letter_lowercase(display_name)
|
||||||
&&{
|
&&{
|
||||||
let display_name_pattern=lazy_regex::regex!(r"\b\S+");
|
let display_name_pattern=lazy_regex!(r"\b\S+");
|
||||||
display_name_pattern.find_iter(display_name)
|
display_name_pattern.find_iter(display_name)
|
||||||
.all(|capture|match capture.as_str(){
|
.all(|capture|match capture.as_str(){
|
||||||
"a"=>true,
|
"a"=>true,
|
||||||
@@ -513,20 +537,23 @@ fn is_title_case(display_name:&str)->bool{
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn interactive() -> AResult<()>{
|
fn interactive() -> AResult<()>{
|
||||||
|
let gmi_utrs=GetMapInfoUstrs::new();
|
||||||
|
let value_ustr=rbx_dom_weak::ustr("Value");
|
||||||
|
let source_ustr=rbx_dom_weak::ustr("Source");
|
||||||
let mut id=get_id()?;
|
let mut id=get_id()?;
|
||||||
//Construct allowed scripts
|
//Construct allowed scripts
|
||||||
let mut allowed_set=get_allowed_set()?;
|
let mut allowed_set=get_allowed_set()?;
|
||||||
let mut allowed_map=get_allowed_map()?;
|
let mut allowed_map=get_allowed_map()?;
|
||||||
let mut replace_map=get_replace_map()?;
|
let mut replace_map=get_replace_map()?;
|
||||||
let mut blocked = get_blocked()?;
|
let mut blocked = get_blocked()?;
|
||||||
let model_name_pattern=lazy_regex::regex!(r"^[a-z0-9_]+$");
|
let model_name_pattern=lazy_regex!(r"^[a-z0-9_]+$");
|
||||||
|
|
||||||
'map_loop: for entry in std::fs::read_dir("maps/unprocessed")? {
|
'map_loop: for entry in std::fs::read_dir("maps/unprocessed")? {
|
||||||
let file_thing=entry?;
|
let file_thing=entry?;
|
||||||
println!("processing map={:?}",file_thing.file_name());
|
println!("processing map={:?}",file_thing.file_name());
|
||||||
let mut input = std::io::BufReader::new(std::fs::File::open(file_thing.path())?);
|
let mut input = std::io::BufReader::new(std::fs::File::open(file_thing.path())?);
|
||||||
let mut dom = load_dom(&mut input)?;
|
let mut dom = load_dom(&mut input)?;
|
||||||
let (modelname,creator,displayname,displayname_ref)=get_mapinfo(&dom)?;
|
let (modelname,creator,displayname,displayname_ref)=get_mapinfo(&gmi_utrs,&dom)?;
|
||||||
|
|
||||||
let mut script_count=0;
|
let mut script_count=0;
|
||||||
let mut replace_count=0;
|
let mut replace_count=0;
|
||||||
@@ -598,7 +625,7 @@ fn interactive() -> AResult<()>{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let displayname_instance=dom.get_by_ref_mut(displayname_ref).unwrap();
|
let displayname_instance=dom.get_by_ref_mut(displayname_ref).unwrap();
|
||||||
assert!(displayname_instance.properties.insert("Value".to_owned(),new_display_name.into()).is_some(),"StringValue we have a problem");
|
assert!(displayname_instance.properties.insert(value_ustr,new_display_name.into()).is_some(),"StringValue we have a problem");
|
||||||
//mark file as edited so a new file is generated
|
//mark file as edited so a new file is generated
|
||||||
replace_count+=1;
|
replace_count+=1;
|
||||||
}
|
}
|
||||||
@@ -617,7 +644,7 @@ fn interactive() -> AResult<()>{
|
|||||||
let mut fail_type=Interactive::Passed;
|
let mut fail_type=Interactive::Passed;
|
||||||
for (script_ref,script_full_name) in script_refs{
|
for (script_ref,script_full_name) in script_refs{
|
||||||
if let Some(script)=dom.get_by_ref(script_ref){
|
if let Some(script)=dom.get_by_ref(script_ref){
|
||||||
if let Some(rbx_dom_weak::types::Variant::String(source)) = script.properties.get("Source") {
|
if let Some(rbx_dom_weak::types::Variant::String(source)) = script.properties.get(&source_ustr) {
|
||||||
script_count+=1;
|
script_count+=1;
|
||||||
let source_action=if check_source_illegal_keywords(source) {
|
let source_action=if check_source_illegal_keywords(source) {
|
||||||
ScriptAction::Flag//script triggers flagging -> Flag
|
ScriptAction::Flag//script triggers flagging -> Flag
|
||||||
@@ -695,7 +722,7 @@ fn interactive() -> AResult<()>{
|
|||||||
if let (Some(replace_source),Some(replace_script))=(allowed_map.get(&replace_id),dom.get_by_ref_mut(script.referent())){
|
if let (Some(replace_source),Some(replace_script))=(allowed_map.get(&replace_id),dom.get_by_ref_mut(script.referent())){
|
||||||
replace_count+=1;
|
replace_count+=1;
|
||||||
println!("replaced source id={} location={}",replace_id,location);
|
println!("replaced source id={} location={}",replace_id,location);
|
||||||
replace_script.properties.insert("Source".to_string(), rbx_dom_weak::types::Variant::String(replace_source.clone()));
|
replace_script.properties.insert(source_ustr,rbx_dom_weak::types::Variant::String(replace_source.clone()));
|
||||||
}else{
|
}else{
|
||||||
panic!("failed to get replacement source id={} location={}",replace_id,location);
|
panic!("failed to get replacement source id={} location={}",replace_id,location);
|
||||||
}
|
}
|
||||||
@@ -762,143 +789,65 @@ fn interactive() -> AResult<()>{
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hash_source(source:&str)->u64{
|
fn recursive_collect_regex(objects:&mut std::vec::Vec<rbx_dom_weak::types::Ref>,dom:&rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance,regex:®ex::Regex){
|
||||||
let mut hasher=siphasher::sip::SipHasher::new();
|
for &referent in instance.children(){
|
||||||
std::hash::Hasher::write(&mut hasher,source.as_bytes());
|
if let Some(c)=dom.get_by_ref(referent){
|
||||||
std::hash::Hasher::finish(&hasher)
|
if regex.captures(c.name.as_str()).is_some(){
|
||||||
}
|
objects.push(c.referent());//copy ref
|
||||||
|
}
|
||||||
fn hash_format(hash:u64)->String{
|
recursive_collect_regex(objects,dom,c,regex);
|
||||||
format!("{:016x}",hash)
|
|
||||||
}
|
|
||||||
|
|
||||||
type GOCError=submissions_api::types::SingleItemError;
|
|
||||||
type GOCResult=Result<submissions_api::types::ScriptID,GOCError>;
|
|
||||||
|
|
||||||
async fn get_or_create_script(api:&submissions_api::external::Context,source:&str)->GOCResult{
|
|
||||||
let script_response=api.get_script_from_hash(submissions_api::types::HashRequest{
|
|
||||||
hash:hash_format(hash_source(source)).as_str(),
|
|
||||||
}).await?;
|
|
||||||
|
|
||||||
Ok(match script_response{
|
|
||||||
Some(script_response)=>script_response.ID,
|
|
||||||
None=>api.create_script(submissions_api::types::CreateScriptRequest{
|
|
||||||
Name:"Script",
|
|
||||||
Source:source,
|
|
||||||
SubmissionID:None,
|
|
||||||
}).await.map_err(GOCError::Other)?.ID
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn check_or_create_script_poicy(
|
|
||||||
api:&submissions_api::external::Context,
|
|
||||||
hash:&str,
|
|
||||||
script_policy:submissions_api::types::CreateScriptPolicyRequest,
|
|
||||||
)->Result<(),GOCError>{
|
|
||||||
let script_policy_result=api.get_script_policy_from_hash(submissions_api::types::HashRequest{
|
|
||||||
hash,
|
|
||||||
}).await?;
|
|
||||||
|
|
||||||
match script_policy_result{
|
|
||||||
Some(script_policy_reponse)=>{
|
|
||||||
// check that everything matches the expectation
|
|
||||||
assert!(hash==script_policy_reponse.FromScriptHash);
|
|
||||||
assert!(script_policy.ToScriptID==script_policy_reponse.ToScriptID);
|
|
||||||
assert!(script_policy.Policy==script_policy_reponse.Policy);
|
|
||||||
},
|
|
||||||
None=>{
|
|
||||||
// create a new policy
|
|
||||||
api.create_script_policy(script_policy).await.map_err(GOCError::Other)?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
fn get_button_refs(dom:&rbx_dom_weak::WeakDom) -> Vec<rbx_dom_weak::types::Ref>{
|
||||||
}
|
let mut buttons = std::vec::Vec::new();
|
||||||
|
recursive_collect_regex(&mut buttons, dom, dom.root(),lazy_regex!(r"Button(\d+)$"));
|
||||||
async fn do_policy(
|
buttons
|
||||||
api:&submissions_api::external::Context,
|
}
|
||||||
script_ids:&std::collections::HashMap<&str,submissions_api::types::ScriptID>,
|
|
||||||
source:&str,
|
fn write_attributes() -> AResult<()>{
|
||||||
to_script_id:submissions_api::types::ScriptID,
|
let attributes_ustr=rbx_dom_weak::ustr("Attributes");
|
||||||
policy:submissions_api::types::Policy,
|
for entry in std::fs::read_dir("maps/unprocessed")? {
|
||||||
)->Result<(),GOCError>{
|
let file_thing=entry?;
|
||||||
let hash=hash_format(hash_source(source));
|
println!("processing map={:?}",file_thing.file_name());
|
||||||
check_or_create_script_poicy(api,hash.as_str(),submissions_api::types::CreateScriptPolicyRequest{
|
let mut input = std::io::BufReader::new(std::fs::File::open(file_thing.path())?);
|
||||||
FromScriptID:script_ids[source],
|
let mut dom = load_dom(&mut input)?;
|
||||||
ToScriptID:to_script_id,
|
|
||||||
Policy:policy,
|
let button_refs = get_button_refs(&dom);
|
||||||
}).await
|
|
||||||
}
|
for &button_ref in &button_refs {
|
||||||
|
if let Some(button)=dom.get_by_ref_mut(button_ref){
|
||||||
async fn upload_scripts(session_id:PathBuf)->AResult<()>{
|
match button.properties.get_mut(&attributes_ustr){
|
||||||
let cookie={
|
Some(rbx_dom_weak::types::Variant::Attributes(attributes))=>{
|
||||||
let mut cookie=String::new();
|
println!("Appending Ref={} to existing attributes for {}",button_ref,button.name);
|
||||||
std::fs::File::open(session_id)?.read_to_string(&mut cookie)?;
|
attributes.insert("Ref".to_string(),rbx_dom_weak::types::Variant::String(button_ref.to_string()));
|
||||||
submissions_api::Cookie::new(&cookie)?
|
},
|
||||||
};
|
None=>{
|
||||||
let api=&submissions_api::external::Context::new("http://localhost:8083".to_owned(),cookie)?;
|
println!("Creating new attributes with Ref={} for {}",button_ref,button.name);
|
||||||
|
let mut attributes=rbx_dom_weak::types::Attributes::new();
|
||||||
let allowed_set=get_allowed_set()?;
|
attributes.insert("Ref".to_string(),rbx_dom_weak::types::Variant::String(button_ref.to_string()));
|
||||||
let allowed_map=get_allowed_map()?;
|
button.properties.insert(attributes_ustr,rbx_dom_weak::types::Variant::Attributes(attributes));
|
||||||
let replace_map=get_replace_map()?;
|
}
|
||||||
let blocked=get_blocked()?;
|
_=>unreachable!("Fetching attributes did not return attributes."),
|
||||||
|
}
|
||||||
// create a unified deduplicated set of all scripts
|
}
|
||||||
let script_set:std::collections::HashSet<&str>=allowed_set.iter()
|
}
|
||||||
.map(|s|s.as_str())
|
let mut dest={
|
||||||
.chain(
|
let mut dest=PathBuf::from("maps/attributes");
|
||||||
replace_map.keys().map(|s|s.as_str())
|
dest.push(file_thing.file_name());
|
||||||
).chain(
|
let output = std::io::BufWriter::new(std::fs::File::create(dest)?);
|
||||||
blocked.iter().map(|s|s.as_str())
|
//write workspace:GetChildren()[1]
|
||||||
).collect();
|
let workspace_children=dom.root().children();
|
||||||
|
if workspace_children.len()!=1{
|
||||||
// get or create every unique script
|
return Err(anyhow::Error::msg("there can only be one model"));
|
||||||
let script_ids:std::collections::HashMap<&str,submissions_api::types::ScriptID>=
|
}
|
||||||
futures::stream::iter(script_set)
|
rbx_binary::to_writer(output, &dom, &[workspace_children[0]])?;
|
||||||
.map(|source|async move{
|
//move original to processed folder
|
||||||
let script_id=get_or_create_script(api,source).await?;
|
PathBuf::from("maps/unaltered")
|
||||||
Ok::<_,GOCError>((source,script_id))
|
};
|
||||||
})
|
dest.push(file_thing.file_name());
|
||||||
.buffer_unordered(16)
|
std::fs::rename(file_thing.path(), dest)?;
|
||||||
.try_collect().await?;
|
}
|
||||||
|
|
||||||
// get or create policy for each script in each category
|
|
||||||
//
|
|
||||||
// replace
|
|
||||||
futures::stream::iter(replace_map.iter().map(Ok))
|
|
||||||
.try_for_each_concurrent(Some(16),|(source,id)|async{
|
|
||||||
do_policy(
|
|
||||||
api,
|
|
||||||
&script_ids,
|
|
||||||
source,
|
|
||||||
script_ids[allowed_map[id].as_str()],
|
|
||||||
submissions_api::types::Policy::Replace
|
|
||||||
).await
|
|
||||||
}).await?;
|
|
||||||
|
|
||||||
// allowed
|
|
||||||
futures::stream::iter(allowed_set.iter().map(Ok))
|
|
||||||
.try_for_each_concurrent(Some(16),|source|async{
|
|
||||||
do_policy(
|
|
||||||
api,
|
|
||||||
&script_ids,
|
|
||||||
source,
|
|
||||||
script_ids[source.as_str()],
|
|
||||||
submissions_api::types::Policy::Allowed
|
|
||||||
).await
|
|
||||||
}).await?;
|
|
||||||
|
|
||||||
// blocked
|
|
||||||
futures::stream::iter(blocked.iter().map(Ok))
|
|
||||||
.try_for_each_concurrent(Some(16),|source|async{
|
|
||||||
do_policy(
|
|
||||||
api,
|
|
||||||
&script_ids,
|
|
||||||
source,
|
|
||||||
script_ids[source.as_str()],
|
|
||||||
submissions_api::types::Policy::Blocked
|
|
||||||
).await
|
|
||||||
}).await?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user