2023-09-13 01:16:25 +00:00
use clap ::{ Args , Parser , Subcommand } ;
2023-09-13 14:13:23 +00:00
mod error ;
mod prelude ;
// this * means we are importing everything from the prelude module and in turn we overwrite the default `Result` with our own
// if you want the original back you can use StdResult<T, E> or just std::result::Result<T, E>
// using the new result also means the error type is implicitly Box<dyn std::error::Error> (works for any errors that implement the std::error::Error trait)
use crate ::prelude ::* ;
2023-09-13 01:16:25 +00:00
#[ derive(Parser) ]
#[ command(author, version, about, long_about = None) ]
#[ command(propagate_version = true) ]
struct Cli {
#[ command(subcommand) ]
command : Commands ,
}
#[ derive(Subcommand) ]
enum Commands {
Download ( MapList ) ,
2023-09-12 02:37:37 +00:00
Upload ,
2023-09-13 01:16:25 +00:00
Scan ,
2023-09-13 00:52:45 +00:00
Extract ( Map ) ,
2023-09-13 01:16:25 +00:00
Replace ,
2023-09-12 02:37:37 +00:00
Interactive ,
2023-09-13 01:16:25 +00:00
}
2023-09-13 00:52:45 +00:00
#[ derive(Args) ]
struct Map {
id :u64 ,
}
2023-09-13 01:16:25 +00:00
#[ derive(Args) ]
struct MapList {
maps : Vec < u64 > ,
}
2023-09-05 00:16:02 +00:00
fn class_is_a ( class : & str , superclass : & str ) -> bool {
if class = = superclass {
return true
}
let class_descriptor = rbx_reflection_database ::get ( ) . classes . get ( class ) ;
if let Some ( descriptor ) = & class_descriptor {
if let Some ( class_super ) = & descriptor . superclass {
return class_is_a ( & class_super , superclass )
}
}
return false
}
2023-09-13 01:30:34 +00:00
fn recursive_collect_scripts ( scripts : & mut std ::vec ::Vec < rbx_dom_weak ::types ::Ref > , dom : & rbx_dom_weak ::WeakDom , instance : & rbx_dom_weak ::Instance ) {
for & referent in instance . children ( ) {
if let Some ( c ) = dom . get_by_ref ( referent ) {
if class_is_a ( c . class . as_str ( ) , " LuaSourceContainer " ) {
scripts . push ( c . referent ( ) ) ; //copy ref
}
recursive_collect_scripts ( scripts , dom , c ) ;
}
}
}
2023-09-12 20:57:47 +00:00
fn get_full_name ( dom :& rbx_dom_weak ::WeakDom , instance :& rbx_dom_weak ::Instance ) -> String {
let mut full_name = instance . name . clone ( ) ;
let mut pref = instance . parent ( ) ;
while let Some ( parent ) = dom . get_by_ref ( pref ) {
full_name . insert ( 0 , '.' ) ;
full_name . insert_str ( 0 , & parent . name ) ;
pref = parent . parent ( ) ;
}
full_name
}
2023-09-13 01:16:25 +00:00
//download
//download list of maps to maps/unprocessed
//scan (scripts)
//iter maps/unprocessed
//passing moves to maps/verified
2023-09-12 23:41:24 +00:00
//failing moves to maps/blocked
2023-09-13 01:16:25 +00:00
//replace (edits & deletions)
2023-09-12 23:41:24 +00:00
//iter maps/blocked
2023-09-13 01:16:25 +00:00
//replace scripts and put in maps/unprocessed
//upload
//iter maps/verified
//interactively print DisplayName/Creator and ask for target upload ids
2023-09-12 02:37:37 +00:00
//interactive
//iter maps/unprocessed
//for each unique script, load it into the file current.lua and have it open in sublime text
//I can edit the file and it will edit it in place
//I pass/fail(with comment)/allow each script
2023-09-13 01:16:25 +00:00
2023-09-13 01:30:34 +00:00
fn get_script_refs ( dom :& rbx_dom_weak ::WeakDom ) -> Vec < rbx_dom_weak ::types ::Ref > {
let mut scripts = std ::vec ::Vec ::new ( ) ;
recursive_collect_scripts ( & mut scripts , dom , dom . root ( ) ) ;
2023-09-13 01:16:45 +00:00
scripts
2023-09-05 00:16:02 +00:00
}
2023-09-14 04:03:17 +00:00
fn get_id ( ) -> BoxResult < u32 > {
2023-09-12 23:28:10 +00:00
match std ::fs ::read_to_string ( " id " ) {
Ok ( id_file ) = > Ok ( id_file . parse ::< u32 > ( ) ? ) ,
Err ( e ) = > match e . kind ( ) {
std ::io ::ErrorKind ::NotFound = > Ok ( 0 ) , //implicitly take on id=0
_ = > Err ( e ) ? ,
}
}
}
2023-09-14 04:03:17 +00:00
fn get_set_from_file ( file :& str ) -> BoxResult < std ::collections ::HashSet < String > > {
2023-09-12 23:28:10 +00:00
let mut set = std ::collections ::HashSet ::< String > ::new ( ) ;
for entry in std ::fs ::read_dir ( file ) ? {
set . insert ( std ::fs ::read_to_string ( entry ? . path ( ) ) ? ) ;
}
Ok ( set )
}
2023-09-14 04:03:17 +00:00
fn get_allowed_set ( ) -> BoxResult < std ::collections ::HashSet < String > > {
2023-09-12 23:28:10 +00:00
get_set_from_file ( " scripts/allowed " )
}
2023-09-14 04:03:17 +00:00
fn get_blocked ( ) -> BoxResult < std ::collections ::HashSet < String > > {
2023-09-12 23:28:10 +00:00
get_set_from_file ( " scripts/blocked " )
}
2023-09-14 04:03:17 +00:00
fn get_allowed_map ( ) -> BoxResult < std ::collections ::HashMap ::< u32 , String > > {
2023-09-12 23:28:10 +00:00
let mut allowed_map = std ::collections ::HashMap ::< u32 , String > ::new ( ) ;
for entry in std ::fs ::read_dir ( " scripts/allowed " ) ? {
let entry = entry ? ;
2023-09-13 00:18:44 +00:00
allowed_map . insert ( entry . path ( ) . file_stem ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) . parse ::< u32 > ( ) ? , std ::fs ::read_to_string ( entry . path ( ) ) ? ) ;
2023-09-12 23:28:10 +00:00
}
Ok ( allowed_map )
}
2023-09-14 04:03:17 +00:00
fn get_replace_map ( ) -> BoxResult < std ::collections ::HashMap ::< String , u32 > > {
2023-09-12 23:28:10 +00:00
let mut replace = std ::collections ::HashMap ::< String , u32 > ::new ( ) ;
for entry in std ::fs ::read_dir ( " scripts/replace " ) ? {
let entry = entry ? ;
2023-09-13 00:18:44 +00:00
replace . insert ( std ::fs ::read_to_string ( entry . path ( ) ) ? , entry . path ( ) . file_stem ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) . parse ::< u32 > ( ) ? ) ;
2023-09-12 23:28:10 +00:00
}
Ok ( replace )
}
fn check_source_illegal_keywords ( source :& String ) ->bool {
source . find ( " getfenv " ) . is_some ( ) | | source . find ( " require " ) . is_some ( )
}
2023-09-14 20:54:08 +00:00
fn find_first_child_class < ' a > ( dom :& ' a rbx_dom_weak ::WeakDom , instance :& ' a rbx_dom_weak ::Instance , name :& ' a str , class :& ' a str ) -> Option < & ' a rbx_dom_weak ::Instance > {
for & referent in instance . children ( ) {
if let Some ( c ) = dom . get_by_ref ( referent ) {
if c . name = = name & & class_is_a ( c . class . as_str ( ) , class ) {
return Some ( c ) ;
}
}
}
None
}
fn get_mapinfo ( dom :& rbx_dom_weak ::WeakDom ) -> BoxResult < ( String , String , String ) > {
let workspace_children = dom . root ( ) . children ( ) ;
if workspace_children . len ( ) ! = 1 {
return Err ( Error ::new ( " there can only be one model " ) ) ;
}
if let Some ( model_instance ) = dom . get_by_ref ( workspace_children [ 0 ] ) {
if let ( Some ( creator ) , Some ( displayname ) ) = ( find_first_child_class ( dom , model_instance , " Creator " , " StringValue " ) , find_first_child_class ( dom , model_instance , " DisplayName " , " StringValue " ) ) {
if let (
Some ( rbx_dom_weak ::types ::Variant ::String ( creator_string ) ) ,
Some ( rbx_dom_weak ::types ::Variant ::String ( displayname_string ) )
) = (
creator . properties . get ( " Value " ) ,
displayname . properties . get ( " Value " )
) {
return Ok ( ( model_instance . name . clone ( ) , creator_string . clone ( ) , displayname_string . clone ( ) ) ) ;
}
}
}
return Err ( Error ::new ( " no stuff in map " ) ) ;
}
2023-09-14 04:03:17 +00:00
fn download ( map_list : Vec < u64 > ) -> BoxResult < ( ) > {
2023-09-12 00:42:03 +00:00
let header = format! ( " Cookie: .ROBLOSECURITY= {} " , std ::env ::var ( " RBXCOOKIE " ) ? ) ;
let shared_args = & [
" -q " ,
" --header " ,
header . as_str ( ) ,
" -O " ,
] ;
for map_id in map_list . iter ( ) {
std ::process ::Command ::new ( " wget " )
. args ( shared_args )
2023-09-14 19:06:02 +00:00
. arg ( format! ( " maps/unprocessed/ {} .rbxm " , map_id ) )
2023-09-12 00:42:03 +00:00
. arg ( format! ( " https://assetdelivery.roblox.com/v1/asset/?ID= {} " , map_id ) )
. spawn ( ) ? ;
}
Ok ( ( ) )
2023-09-13 01:16:25 +00:00
}
2023-09-12 02:18:55 +00:00
enum Scan {
Passed ,
Blocked ,
2023-09-12 02:18:38 +00:00
Flagged ,
2023-09-12 02:18:55 +00:00
}
2023-09-13 14:13:23 +00:00
2023-09-14 04:03:17 +00:00
fn scan ( ) -> BoxResult < ( ) > {
2023-09-12 23:28:10 +00:00
let mut id = get_id ( ) ? ;
2023-09-05 00:16:02 +00:00
//Construct allowed scripts
2023-09-12 23:28:10 +00:00
let allowed_set = get_allowed_set ( ) ? ;
let mut blocked = get_blocked ( ) ? ;
2023-09-05 00:16:02 +00:00
2023-09-13 01:16:25 +00:00
for entry in std ::fs ::read_dir ( " maps/unprocessed " ) ? {
let file_thing = entry ? ;
let input = std ::io ::BufReader ::new ( std ::fs ::File ::open ( file_thing . path ( ) ) ? ) ;
2023-09-05 00:16:02 +00:00
2023-09-13 01:16:25 +00:00
let dom = rbx_binary ::from_reader ( input ) ? ;
2023-09-13 01:16:45 +00:00
2023-09-13 01:30:34 +00:00
let script_refs = get_script_refs ( & dom ) ;
2023-09-13 01:16:45 +00:00
//check scribb
2023-09-12 02:18:55 +00:00
let mut fail_count = 0 ;
let mut fail_type = Scan ::Passed ;
2023-09-13 01:30:34 +00:00
for & script_ref in script_refs . iter ( ) {
if let Some ( script ) = dom . get_by_ref ( script_ref ) {
if let Some ( rbx_dom_weak ::types ::Variant ::String ( s ) ) = script . properties . get ( " Source " ) {
//flag keywords and instantly fail
if check_source_illegal_keywords ( s ) {
println! ( " {:?} - flagged. " , file_thing . file_name ( ) ) ;
fail_type = Scan ::Flagged ;
break ;
}
if allowed_set . contains ( s ) {
continue ;
} else {
fail_type = Scan ::Blocked ; //no need to check for Flagged, it breaks the loop.
fail_count + = 1 ;
if ! blocked . contains ( s ) {
blocked . insert ( s . clone ( ) ) ; //all fixed! just clone!
std ::fs ::write ( format! ( " scripts/blocked/ {} .lua " , id ) , s ) ? ;
id + = 1 ;
}
2023-09-13 01:16:25 +00:00
}
2023-09-13 01:30:34 +00:00
} else {
panic! ( " FATAL: failed to get source for {:?} " , file_thing . file_name ( ) ) ;
2023-09-05 00:34:31 +00:00
}
} else {
2023-09-13 01:30:34 +00:00
panic! ( " FATAL: failed to get_by_ref {:?} " , script_ref ) ;
2023-09-05 00:34:31 +00:00
}
2023-09-13 01:16:25 +00:00
}
2023-09-12 02:18:55 +00:00
let mut dest = match fail_type {
Scan ::Passed = > std ::path ::PathBuf ::from ( " maps/processed " ) ,
Scan ::Blocked = > {
println! ( " {:?} - {} {} not allowed. " , file_thing . file_name ( ) , fail_count , if fail_count = = 1 { " script " } else { " scripts " } ) ;
2023-09-12 23:41:24 +00:00
std ::path ::PathBuf ::from ( " maps/blocked " )
2023-09-12 02:18:55 +00:00
}
2023-09-12 02:18:38 +00:00
Scan ::Flagged = > std ::path ::PathBuf ::from ( " maps/flagged " )
2023-09-12 02:18:55 +00:00
} ;
dest . push ( file_thing . file_name ( ) ) ;
std ::fs ::rename ( file_thing . path ( ) , dest ) ? ;
2023-09-05 00:16:02 +00:00
}
2023-09-13 01:16:25 +00:00
std ::fs ::write ( " id " , id . to_string ( ) ) ? ;
Ok ( ( ) )
}
2023-09-14 04:03:17 +00:00
fn extract ( file_id :u64 ) -> BoxResult < ( ) > {
2023-09-13 00:52:45 +00:00
let mut id = 0 ;
//Construct allowed scripts
let mut script_set = std ::collections ::HashSet ::< String > ::new ( ) ;
let file_id_string = file_id . to_string ( ) ;
for entry in std ::fs ::read_dir ( " maps/unprocessed " ) ? {
let file_thing = entry ? ;
if file_thing . file_name ( ) . to_str ( ) . unwrap ( ) . find ( & file_id_string ) . is_none ( ) {
continue ;
}
let input = std ::io ::BufReader ::new ( std ::fs ::File ::open ( file_thing . path ( ) ) ? ) ;
let dom = rbx_binary ::from_reader ( input ) ? ;
2023-09-13 01:30:34 +00:00
let script_refs = get_script_refs ( & dom ) ;
2023-09-13 00:52:45 +00:00
//extract scribb
2023-09-13 01:30:34 +00:00
for & script_ref in script_refs . iter ( ) {
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 script_set . contains ( s ) {
continue ;
} else {
script_set . insert ( s . clone ( ) ) ;
std ::fs ::write ( format! ( " scripts/extracted/ {:?} _ {} _ {} .lua " , file_thing . file_name ( ) , id , script . name ) , s ) ? ;
id + = 1 ;
}
2023-09-13 00:52:45 +00:00
} else {
2023-09-13 01:30:34 +00:00
panic! ( " FATAL: failed to get source for {:?} " , file_thing . file_name ( ) ) ;
2023-09-13 00:52:45 +00:00
}
} else {
2023-09-13 01:30:34 +00:00
panic! ( " FATAL: failed to get_by_ref {:?} " , script_ref ) ;
2023-09-13 00:52:45 +00:00
}
}
}
println! ( " extracted {} {} " , id , if id = = 1 { " script " } else { " scripts " } ) ;
Ok ( ( ) )
}
2023-09-14 04:03:17 +00:00
fn replace ( ) -> BoxResult < ( ) > {
2023-09-12 23:28:10 +00:00
let allowed_map = get_allowed_map ( ) ? ;
let replace_map = get_replace_map ( ) ? ;
2023-09-13 01:16:25 +00:00
2023-09-12 23:41:24 +00:00
for entry in std ::fs ::read_dir ( " maps/blocked " ) ? {
2023-09-13 01:16:25 +00:00
let file_thing = entry ? ;
2023-09-13 00:25:01 +00:00
let input = std ::io ::BufReader ::new ( std ::fs ::File ::open ( file_thing . path ( ) ) ? ) ;
2023-09-13 01:30:34 +00:00
let mut dom = rbx_binary ::from_reader ( input ) ? ;
2023-09-13 01:16:25 +00:00
2023-09-13 01:30:34 +00:00
let script_refs = get_script_refs ( & dom ) ;
2023-09-13 01:16:25 +00:00
//check scribb
let mut any_failed = false ;
2023-09-13 01:30:34 +00:00
for & script_ref in script_refs . iter ( ) {
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 ( replace_id ) , Some ( replace_script ) ) = ( replace_map . get ( source ) , dom . get_by_ref_mut ( script . referent ( ) ) ) {
println! ( " replace {} " , replace_id ) ;
//replace the source
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 ( ) ) ) ;
} else {
println! ( " failed to get replacement source {} " , replace_id ) ;
any_failed = true ;
}
2023-09-13 01:16:25 +00:00
} else {
2023-09-13 01:30:34 +00:00
println! ( " failed to failed to get replace_id and replace_script " ) ;
2023-09-13 01:16:25 +00:00
any_failed = true ;
}
2023-09-12 02:53:42 +00:00
} else {
2023-09-13 01:30:34 +00:00
panic! ( " FATAL: failed to get source for {:?} " , file_thing . file_name ( ) ) ;
2023-09-13 01:16:25 +00:00
}
2023-09-12 02:53:42 +00:00
} else {
2023-09-13 01:30:34 +00:00
panic! ( " FATAL: failed to get_by_ref {:?} " , script_ref ) ;
2023-09-13 01:16:25 +00:00
}
}
if any_failed {
println! ( " One or more scripts failed to replace. " ) ;
} else {
let mut dest = std ::path ::PathBuf ::from ( " maps/unprocessed " ) ;
dest . set_file_name ( file_thing . file_name ( ) ) ;
let output = std ::io ::BufWriter ::new ( std ::fs ::File ::open ( dest ) ? ) ;
2023-09-13 01:30:34 +00:00
rbx_binary ::to_writer ( output , & dom , & [ dom . root_ref ( ) ] ) ? ;
2023-09-13 01:16:25 +00:00
}
}
Ok ( ( ) )
}
2023-09-14 04:03:17 +00:00
fn upload ( ) -> BoxResult < ( ) > {
2023-09-12 02:18:44 +00:00
//interactive prompt per upload:
2023-09-14 20:54:08 +00:00
for entry in std ::fs ::read_dir ( " maps/passed " ) ? {
let file_thing = entry ? ;
let input = std ::io ::BufReader ::new ( std ::fs ::File ::open ( file_thing . path ( ) ) ? ) ;
let dom = rbx_binary ::from_reader ( input ) ? ;
let ( modelname , creator , displayname ) = get_mapinfo ( & dom ) ? ;
//Creator: [auto fill creator]
//DisplayName: [auto fill DisplayName]
//id: ["New" for blank because of my double enter key]
print! ( " Model name: {} \n Creator: {} \n DisplayName: {} \n Asset Id: " , modelname , creator , displayname ) ;
std ::io ::Write ::flush ( & mut std ::io ::stdout ( ) ) ? ;
let asset_id ;
loop {
let mut asset_id_string = String ::new ( ) ;
std ::io ::stdin ( ) . read_line ( & mut asset_id_string ) ? ;
asset_id_string . pop ( ) ; //drop newline
if let Ok ( parsed_asset_id ) = asset_id_string . parse ::< u64 > ( ) {
asset_id = parsed_asset_id ;
break ;
} else {
print! ( " Asset Id: " ) ;
std ::io ::Write ::flush ( & mut std ::io ::stdout ( ) ) ? ;
}
}
std ::process ::Command ::new ( " ../rbxcompiler-linux-amd64 " )
. arg ( " --compile=false " )
. arg ( " --group=6980477 " )
. arg ( format! ( " --asset= {} " , asset_id ) )
. arg ( format! ( " --input= {} " , file_thing . path ( ) . into_os_string ( ) . into_string ( ) . unwrap ( ) ) )
. spawn ( ) ? ;
}
Ok ( ( ) )
2023-09-13 01:16:25 +00:00
}
2023-09-12 23:41:24 +00:00
enum Interactive {
Passed ,
Blocked ,
Flagged ,
}
enum ScriptAction {
Pass ,
Replace ( u32 ) ,
Flag ,
Block ,
2023-09-13 02:28:13 +00:00
Delete ,
2023-09-12 23:41:24 +00:00
}
enum ScriptActionParseResult {
Pass ,
Block ,
2023-09-13 02:28:13 +00:00
Exit ,
Delete ,
2023-09-12 23:41:24 +00:00
}
struct ParseScriptActionErr ;
impl std ::str ::FromStr for ScriptActionParseResult {
type Err = ParseScriptActionErr ;
2023-09-14 04:03:17 +00:00
fn from_str ( s : & str ) -> Result < Self , Self ::Err > {
2023-09-13 01:48:07 +00:00
if s = = " pass \n " | | s = = " 1 \n " {
2023-09-12 23:41:24 +00:00
Ok ( Self ::Pass )
2023-09-13 01:48:07 +00:00
} else if s = = " block \n " {
2023-09-12 23:41:24 +00:00
Ok ( Self ::Block )
2023-09-13 02:28:13 +00:00
} else if s = = " exit \n " {
Ok ( Self ::Exit )
} else if s = = " delete \n " {
Ok ( Self ::Delete )
2023-09-12 23:41:24 +00:00
} else {
Err ( ParseScriptActionErr )
}
}
}
2023-09-14 04:03:17 +00:00
fn interactive ( ) -> BoxResult < ( ) > {
2023-09-12 23:41:24 +00:00
let mut id = get_id ( ) ? ;
//Construct allowed scripts
let mut allowed_set = get_allowed_set ( ) ? ;
let mut allowed_map = get_allowed_map ( ) ? ;
let mut replace_map = get_replace_map ( ) ? ;
2023-09-12 23:56:07 +00:00
let mut blocked = get_blocked ( ) ? ;
2023-09-12 23:41:24 +00:00
2023-09-13 02:28:13 +00:00
' map_loop : for entry in std ::fs ::read_dir ( " maps/unprocessed " ) ? {
2023-09-12 23:41:24 +00:00
let file_thing = entry ? ;
println! ( " processing map= {:?} " , file_thing . file_name ( ) ) ;
let input = std ::io ::BufReader ::new ( std ::fs ::File ::open ( file_thing . path ( ) ) ? ) ;
2023-09-13 01:30:34 +00:00
let mut dom = rbx_binary ::from_reader ( input ) ? ;
2023-09-12 23:41:24 +00:00
2023-09-13 01:30:34 +00:00
let script_refs = get_script_refs ( & dom ) ;
2023-09-12 23:41:24 +00:00
//check scribb
2023-09-12 23:56:43 +00:00
let mut script_count = 0 ;
2023-09-13 00:34:43 +00:00
let mut replace_count = 0 ;
2023-09-12 23:56:43 +00:00
let mut block_count = 0 ;
2023-09-12 23:41:24 +00:00
let mut fail_type = Interactive ::Passed ;
2023-09-13 01:30:34 +00:00
for & script_ref in script_refs . iter ( ) {
if let Some ( script ) = dom . get_by_ref ( script_ref ) {
if let Some ( rbx_dom_weak ::types ::Variant ::String ( source ) ) = script . properties . get ( " Source " ) {
script_count + = 1 ;
let source_action = if check_source_illegal_keywords ( source ) {
ScriptAction ::Flag //script triggers flagging -> Flag
} else if blocked . contains ( source ) {
ScriptAction ::Block //script is blocked -> Block
} else if allowed_set . contains ( source ) {
ScriptAction ::Pass //script is allowed -> Pass
} else if let Some ( replace_id ) = replace_map . get ( source ) {
ScriptAction ::Replace ( * replace_id )
} else {
//interactive logic goes here
2023-09-13 01:47:57 +00:00
print! ( " unresolved source location= {} \n action: " , get_full_name ( & dom , script ) ) ;
std ::io ::Write ::flush ( & mut std ::io ::stdout ( ) ) ? ;
2023-09-13 01:30:34 +00:00
//load source into current.lua
std ::fs ::write ( " current.lua " , source ) ? ;
//prompt action in terminal
//wait for input
let script_action ;
loop {
let mut action_string = String ::new ( ) ;
std ::io ::stdin ( ) . read_line ( & mut action_string ) ? ;
if let Ok ( parsed_script_action ) = action_string . parse ::< ScriptActionParseResult > ( ) {
script_action = parsed_script_action ;
break ;
} else {
2023-09-13 04:36:38 +00:00
print! ( " action: " ) ;
std ::io ::Write ::flush ( & mut std ::io ::stdout ( ) ) ? ;
2023-09-13 01:30:34 +00:00
}
2023-09-12 23:41:24 +00:00
}
2023-09-13 01:30:34 +00:00
//update allowed/replace/blocked
match script_action {
ScriptActionParseResult ::Pass = > {
//if current.lua was updated, create an allowed and replace file and set script_action to replace(new_id)
let modified_source = std ::fs ::read_to_string ( " current.lua " ) ? ;
if & modified_source = = source {
//it's always new.
//insert allowed_set
allowed_set . insert ( modified_source . clone ( ) ) ;
//insert allowed_map
allowed_map . insert ( id , modified_source . clone ( ) ) ;
//write allowed/id.lua
std ::fs ::write ( format! ( " scripts/allowed/ {} .lua " , id ) , modified_source ) ? ;
id + = 1 ;
ScriptAction ::Pass
} else {
//insert allowed_set
allowed_set . insert ( modified_source . clone ( ) ) ;
//insert allowed_map
allowed_map . insert ( id , modified_source . clone ( ) ) ;
//insert replace_map
replace_map . insert ( source . clone ( ) , id ) ; //this cannot be reached if it already exists
//write allowed/id.lua
std ::fs ::write ( format! ( " scripts/allowed/ {} .lua " , id ) , modified_source ) ? ;
//write replace/id.lua
std ::fs ::write ( format! ( " scripts/replace/ {} .lua " , id ) , source ) ? ;
let ret = ScriptAction ::Replace ( id ) ;
id + = 1 ;
ret
}
} ,
ScriptActionParseResult ::Block = > {
blocked . insert ( source . clone ( ) ) ;
std ::fs ::write ( format! ( " scripts/blocked/ {} .lua " , id ) , source ) ? ;
2023-09-12 23:41:24 +00:00
id + = 1 ;
2023-09-13 01:30:34 +00:00
ScriptAction ::Block
} ,
2023-09-13 02:28:13 +00:00
ScriptActionParseResult ::Exit = > break 'map_loop ,
ScriptActionParseResult ::Delete = > ScriptAction ::Delete ,
2023-09-13 01:30:34 +00:00
}
} ;
2023-09-13 02:29:43 +00:00
let location = get_full_name ( & dom , script ) ;
2023-09-13 01:30:34 +00:00
match source_action {
2023-09-13 02:29:43 +00:00
ScriptAction ::Pass = > println! ( " passed source location= {} " , location ) ,
2023-09-13 01:30:34 +00:00
ScriptAction ::Replace ( replace_id ) = > {
//replace the source
if let ( Some ( replace_source ) , Some ( replace_script ) ) = ( allowed_map . get ( & replace_id ) , dom . get_by_ref_mut ( script . referent ( ) ) ) {
replace_count + = 1 ;
println! ( " replaced source id= {} location= {} " , replace_id , location ) ;
replace_script . properties . insert ( " Source " . to_string ( ) , rbx_dom_weak ::types ::Variant ::String ( replace_source . clone ( ) ) ) ;
2023-09-12 23:41:24 +00:00
} else {
2023-09-13 01:30:34 +00:00
panic! ( " failed to get replacement source id= {} location= {} " , replace_id , location ) ;
2023-09-12 23:41:24 +00:00
}
2023-09-13 02:28:13 +00:00
} ,
ScriptAction ::Delete = > {
2023-09-13 02:29:43 +00:00
println! ( " deleted source location= {} " , location ) ;
2023-09-14 04:22:28 +00:00
replace_count + = 1 ; //trigger a new file generation
2023-09-13 02:28:13 +00:00
dom . destroy ( script . referent ( ) ) ;
} ,
2023-09-13 01:30:34 +00:00
ScriptAction ::Flag = > {
2023-09-13 02:29:43 +00:00
println! ( " flagged source location= {} " , location ) ;
2023-09-13 01:30:34 +00:00
fail_type = Interactive ::Flagged ;
2023-09-12 23:41:24 +00:00
} ,
2023-09-13 01:30:34 +00:00
ScriptAction ::Block = > {
block_count + = 1 ;
2023-09-13 02:29:43 +00:00
println! ( " blocked source location= {} " , location ) ;
2023-09-13 01:30:34 +00:00
match fail_type {
Interactive ::Passed = > fail_type = Interactive ::Blocked ,
_ = > ( ) ,
}
2023-09-12 23:56:07 +00:00
} ,
2023-09-12 23:41:24 +00:00
}
2023-09-13 01:30:34 +00:00
} else {
panic! ( " FATAL: failed to get source for {:?} " , file_thing . file_name ( ) ) ;
2023-09-12 23:41:24 +00:00
}
2023-09-13 00:02:05 +00:00
} else {
2023-09-13 01:30:34 +00:00
panic! ( " FATAL: failed to get_by_ref {:?} " , script_ref ) ;
2023-09-12 23:41:24 +00:00
}
}
let mut dest = match fail_type {
2023-09-12 23:56:43 +00:00
Interactive ::Passed = > {
println! ( " map= {:?} passed with {} {} " , file_thing . file_name ( ) , script_count , if script_count = = 1 { " script " } else { " scripts " } ) ;
2023-09-13 00:34:43 +00:00
if replace_count = = 0 {
std ::path ::PathBuf ::from ( " maps/passed " )
} else {
//create new file
println! ( " {} {} replaced - generating new file... " , replace_count , if replace_count = = 1 { " script was " } else { " scripts were " } ) ;
let mut dest = std ::path ::PathBuf ::from ( " maps/passed " ) ;
dest . push ( file_thing . file_name ( ) ) ;
let output = std ::io ::BufWriter ::new ( std ::fs ::File ::create ( dest ) ? ) ;
2023-09-14 20:53:52 +00:00
//write workspace:GetChildren()[1]
let workspace_children = dom . root ( ) . children ( ) ;
if workspace_children . len ( ) ! = 1 {
return Err ( Error ::new ( " there can only be one model " ) ) ;
}
rbx_binary ::to_writer ( output , & dom , & [ workspace_children [ 0 ] ] ) ? ;
2023-09-13 00:34:43 +00:00
//move original to processed folder
std ::path ::PathBuf ::from ( " maps/unaltered " )
}
2023-09-12 23:56:43 +00:00
} , //write map into maps/processed
Interactive ::Blocked = > {
println! ( " map= {:?} blocked with {} / {} {} blocked " , file_thing . file_name ( ) , block_count , script_count , if script_count = = 1 { " script " } else { " scripts " } ) ;
std ::path ::PathBuf ::from ( " maps/blocked " )
} , //write map into maps/blocked
Interactive ::Flagged = > {
println! ( " map= {:?} flagged " , file_thing . file_name ( ) ) ;
std ::path ::PathBuf ::from ( " maps/flagged " )
} , //write map into maps/flagged
2023-09-12 23:41:24 +00:00
} ;
dest . push ( file_thing . file_name ( ) ) ;
std ::fs ::rename ( file_thing . path ( ) , dest ) ? ;
}
std ::fs ::write ( " id " , id . to_string ( ) ) ? ;
Ok ( ( ) )
2023-09-12 02:37:37 +00:00
}
2023-09-14 04:03:17 +00:00
fn main ( ) -> BoxResult < ( ) > {
2023-09-13 01:16:25 +00:00
let cli = Cli ::parse ( ) ;
match cli . command {
Commands ::Download ( map_list ) = > download ( map_list . maps ) ,
2023-09-12 02:37:37 +00:00
Commands ::Upload = > upload ( ) ,
2023-09-13 01:16:25 +00:00
Commands ::Scan = > scan ( ) ,
Commands ::Replace = > replace ( ) ,
2023-09-12 02:37:37 +00:00
Commands ::Interactive = > interactive ( ) ,
2023-09-13 00:52:45 +00:00
Commands ::Extract ( map ) = > extract ( map . id ) ,
2023-09-13 01:16:25 +00:00
}
2023-09-04 19:24:00 +00:00
}