diff --git a/Cargo.lock b/Cargo.lock index 29a691b..fe3a485 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -234,6 +234,12 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + [[package]] name = "luau0-src" version = "0.10.3+luau640" @@ -243,6 +249,25 @@ dependencies = [ "cc", ] +[[package]] +name = "lz4" +version = "1.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d1febb2b4a79ddd1980eede06a8f7902197960aa0383ffcfdd62fe723036725" +dependencies = [ + "lz4-sys", +] + +[[package]] +name = "lz4-sys" +version = "1.11.1+lz4-1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bd8c0d6c6ed0cd30b3652886bb8711dc4bb01d637a68105a3d5158039b418e6" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "memchr" version = "2.7.4" @@ -320,6 +345,25 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "profiling" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d84d1d7a6ac92673717f9f6d1518374ef257669c24ebc5ac25d5033828be58" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8021cf59c8ec9c432cfc2526ac6b8aa508ecaf29cd415f271b8406c1b851c3fd" +dependencies = [ + "quote", + "syn", +] + [[package]] name = "quote" version = "1.0.37" @@ -359,6 +403,21 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rbx_binary" +version = "0.7.4" +source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/" +checksum = "18b401155b93f7151217bf51e36bdfa7bddcaf5f0d26b563c9ac3b08a3701c27" +dependencies = [ + "log", + "lz4", + "profiling", + "rbx_dom_weak", + "rbx_reflection", + "rbx_reflection_database", + "thiserror", +] + [[package]] name = "rbx_dom_weak" version = "2.9.0" @@ -407,6 +466,20 @@ dependencies = [ "thiserror", ] +[[package]] +name = "rbx_xml" +version = "0.13.3" +source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/" +checksum = "d6d1a15f58a1e4b4f578abe6eb5e1461cb16eea82fb4a147d5995c9b79f08d1f" +dependencies = [ + "base64", + "log", + "rbx_dom_weak", + "rbx_reflection", + "rbx_reflection_database", + "xml-rs", +] + [[package]] name = "rmp" version = "0.8.14" @@ -431,9 +504,9 @@ dependencies = [ [[package]] name = "roblox_emulator" -version = "0.3.1" +version = "0.3.2" source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/" -checksum = "b58d7bb42d458984e629a012757474710fd0e429c2c824a2529574be5e7c2fd6" +checksum = "f73c50802f947550642aaeb3da2993751c0e37024ac922dec99313068596321e" dependencies = [ "glam", "mlua", @@ -449,6 +522,9 @@ version = "0.1.1" dependencies = [ "anyhow", "clap", + "rbx_binary", + "rbx_dom_weak", + "rbx_xml", "roblox_emulator", ] @@ -612,6 +688,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "xml-rs" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af4e2e2f7cba5a093896c1e150fbfe177d1883e7448200efb81d40b9d339ef26" + [[package]] name = "zerocopy" version = "0.7.35" diff --git a/Cargo.toml b/Cargo.toml index 4959320..570869a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,4 +10,7 @@ authors = ["Rhys Lloyd "] [dependencies] anyhow = "1.0.89" clap = { version = "4.5.18", features = ["derive"] } -roblox_emulator = { version = "0.3.1", registry = "strafesnet" } +roblox_emulator = { version = "0.3.2", registry = "strafesnet" } +rbx_binary = { version = "0.7.4", registry = "strafesnet" } +rbx_dom_weak = { version = "2.9.0", registry = "strafesnet" } +rbx_xml = { version = "0.13.3", registry = "strafesnet" } diff --git a/src/main.rs b/src/main.rs index 07e2993..98d5d78 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,6 +13,8 @@ struct Cli{ #[derive(Subcommand)] enum Commands{ RunScript(RunScriptSubcommand), + RunModel(RunModelSubcommand), + RunPlace(RunPlaceSubcommand), } #[derive(Args)] @@ -20,11 +22,23 @@ struct RunScriptSubcommand{ #[arg()] input_file:PathBuf, } +#[derive(Args)] +struct RunModelSubcommand{ + #[arg()] + input_file:PathBuf, +} +#[derive(Args)] +struct RunPlaceSubcommand{ + #[arg()] + input_file:PathBuf, +} fn main()->anyhow::Result<()>{ let cli=Cli::parse(); match cli.command{ Commands::RunScript(command)=>run_script(command.input_file), + Commands::RunModel(command)=>run_model(command.input_file), + Commands::RunPlace(command)=>run_place(command.input_file), } } @@ -40,3 +54,55 @@ fn run_script(input_file:PathBuf)->anyhow::Result<()>{ runnable.run_script(script)?; Ok(()) } + +#[derive(Debug)] +pub enum ReadError{ + RbxBinary(rbx_binary::DecodeError), + RbxXml(rbx_xml::DecodeError), + Io(std::io::Error), + UnknownFileFormat, +} +impl std::fmt::Display for ReadError{ + fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{ + write!(f,"{self:?}") + } +} +impl std::error::Error for ReadError{} + +pub fn read(input:R)->Result{ + let mut buf=std::io::BufReader::new(input); + let peek=std::io::BufRead::fill_buf(&mut buf).map_err(ReadError::Io)?; + match &peek[0..8]{ + b"rbx_binary::from_reader(buf).map_err(ReadError::RbxBinary), + b"rbx_xml::from_reader_default(buf).map_err(ReadError::RbxXml), + _=>Err(ReadError::UnknownFileFormat), + } +} + +fn run_model(input_file:PathBuf)->anyhow::Result<()>{ + let file=std::fs::File::open(input_file)?; + let dom=read(file)?; + let (dom,services)=roblox_emulator::place::new_place_with_instances_in_workspace(dom); + let mut context=roblox_emulator::context::Context::new(dom); + let scripts=context.scripts(); + let runner=roblox_emulator::runner::Runner::new()?; + let runnable=runner.runnable_context(&mut context,&services)?; + for script in scripts{ + runnable.run_script(script)?; + } + Ok(()) +} + +fn run_place(input_file:PathBuf)->anyhow::Result<()>{ + let file=std::fs::File::open(input_file)?; + let dom=read(file)?; + let services=roblox_emulator::place::Services::find_in(&dom).ok_or(anyhow::Error::msg("Could not find Workspace"))?; + let mut context=roblox_emulator::context::Context::new(dom); + let scripts=context.scripts(); + let runner=roblox_emulator::runner::Runner::new()?; + let runnable=runner.runnable_context(&mut context,&services)?; + for script in scripts{ + runnable.run_script(script)?; + } + Ok(()) +}