From 4eb6c7c057e74b7fc97d01badedcee5ad42e3cc0 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Mon, 16 Sep 2024 18:54:04 -0700 Subject: [PATCH 001/129] Initial commit --- .gitignore | 1 + Cargo.lock | 480 +++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 9 + src/context.rs | 33 +++ src/lib.rs | 9 + src/runner/mod.rs | 3 + src/runner/runner.rs | 19 ++ src/script.rs | 28 +++ src/tests.rs | 0 9 files changed, 582 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/context.rs create mode 100644 src/lib.rs create mode 100644 src/runner/mod.rs create mode 100644 src/runner/runner.rs create mode 100644 src/script.rs create mode 100644 src/tests.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..57cc3ab --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,480 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "blake3" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", +] + +[[package]] +name = "bstr" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cc" +version = "1.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d74707dde2ba56f86ae90effb3b43ddd369504387e718014de010cec7959800" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.158" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" + +[[package]] +name = "libloading" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +dependencies = [ + "cfg-if", + "windows-targets", +] + +[[package]] +name = "luau0-src" +version = "0.10.3+luau640" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f39d12b514a676c943990cfbe6200fedcb9c293c8c9219d29be512a6969be92" +dependencies = [ + "cc", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "mlua" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d111deb18a9c9bd33e1541309f4742523bfab01d276bfa9a27519f6de9c11dc7" +dependencies = [ + "bstr", + "libloading", + "mlua-sys", + "num-traits", + "once_cell", + "rustc-hash", +] + +[[package]] +name = "mlua-sys" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe026d6bd1583a9cf9080e189030ddaea7e6f5f0deb366a8e26f8a26c4135b8" +dependencies = [ + "cc", + "cfg-if", + "luau0-src", + "pkg-config", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rbx_dom_weak" +version = "2.9.0" +source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/" +checksum = "2a6b916687c98aaea36f9c03e80906bfafab057bebee248628c8c04def807f43" +dependencies = [ + "rbx_types", + "serde", +] + +[[package]] +name = "rbx_reflection" +version = "4.7.0" +source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/" +checksum = "c1b43fe592a4ce6fe54eb215fb82735efbb516d2cc045a94e3dc0234ff293620" +dependencies = [ + "rbx_types", + "serde", + "thiserror", +] + +[[package]] +name = "rbx_reflection_database" +version = "0.2.12+roblox-638" +source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/" +checksum = "2e772bb9e1bc0ebe65d338f876d1bb1ea22e15a8f9a82e8245028010c2fea3c9" +dependencies = [ + "lazy_static", + "rbx_reflection", + "rmp-serde", + "serde", +] + +[[package]] +name = "rbx_types" +version = "1.10.0" +source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/" +checksum = "d7a390c44034fa448c53bd0983dfc2d70d8d6b2f65be4f164d4bec8b6a2a2d09" +dependencies = [ + "base64", + "bitflags", + "blake3", + "lazy_static", + "rand", + "serde", + "thiserror", +] + +[[package]] +name = "rmp" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" +dependencies = [ + "byteorder", + "num-traits", + "paste", +] + +[[package]] +name = "rmp-serde" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db" +dependencies = [ + "byteorder", + "rmp", + "serde", +] + +[[package]] +name = "roblox_emulator" +version = "0.1.0" +dependencies = [ + "mlua", + "rbx_dom_weak", + "rbx_reflection_database", +] + +[[package]] +name = "rustc-hash" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" + +[[package]] +name = "serde" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "syn" +version = "2.0.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..884596f --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "roblox_emulator" +version = "0.1.0" +edition = "2021" + +[dependencies] +mlua = { version = "0.9.9", features = ["luau"] } +rbx_dom_weak = { version = "2.7.0", registry = "strafesnet" } +rbx_reflection_database = { version = "0.2.10", registry = "strafesnet" } diff --git a/src/context.rs b/src/context.rs new file mode 100644 index 0000000..cd85038 --- /dev/null +++ b/src/context.rs @@ -0,0 +1,33 @@ +use rbx_dom_weak::{types::Ref,WeakDom}; + +pub fn class_is_a(class:&str,superclass:&str)->bool{ + class==superclass + ||rbx_reflection_database::get().classes.get(class) + .is_some_and(|descriptor| + descriptor.superclass.as_ref().is_some_and(|class_super| + class_is_a(class_super,superclass) + ) + ) +} + +pub struct Context{ + pub(crate)dom:WeakDom, +} + +impl Context{ + pub const fn new(dom:WeakDom)->Self{ + Self{dom} + } + pub fn into_inner(self)->WeakDom{ + self.dom + } + /// Creates an iterator over all items of a particular class. + pub fn superclass_iter<'a>(&'a self,superclass:&'a str)->impl Iterator+'a{ + self.dom.descendants().filter(|&instance| + class_is_a(instance.class.as_ref(),superclass) + ).map(|instance|instance.referent()) + } + pub fn scripts(&self)->Vec{ + self.superclass_iter("LuaSourceContainer").map(crate::script::Script::new).collect() + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..fb0dd5f --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,9 @@ +pub mod script; +pub mod context; + +mod runner; + +pub type Result=core::result::Result; + +#[cfg(test)] +mod tests; diff --git a/src/runner/mod.rs b/src/runner/mod.rs new file mode 100644 index 0000000..5cf589b --- /dev/null +++ b/src/runner/mod.rs @@ -0,0 +1,3 @@ +mod runner; + +pub use runner::{Runner,Error}; diff --git a/src/runner/runner.rs b/src/runner/runner.rs new file mode 100644 index 0000000..b8194c2 --- /dev/null +++ b/src/runner/runner.rs @@ -0,0 +1,19 @@ +pub enum Error{ + Lua(mlua::Error), +} + +pub struct Runner{ + source:String, +} + +impl Runner{ + pub const fn new(source:String)->Self{ + Self{source} + } + pub fn run(self,context:&mut crate::context::Context)->Result<(),Error>{ + let lua=mlua::Lua::new(); + lua.sandbox(true).map_err(Error::Lua)?; + lua.load(self.source).exec().map_err(Error::Lua)?; + Ok(()) + } +} diff --git a/src/script.rs b/src/script.rs new file mode 100644 index 0000000..3027c7c --- /dev/null +++ b/src/script.rs @@ -0,0 +1,28 @@ +use rbx_dom_weak::types::Ref; + +pub enum Error{ + Runner(crate::runner::Error), + NoScript, + NoSource, +} + +pub struct Script{ + script:Ref, +} +impl Script{ + pub const fn new(script:Ref)->Self{ + Self{script} + } + pub fn run(&self,context:&mut crate::context::Context)->Result<(),Error>{ + // grab source + let source={ + let instance=context.dom.get_by_ref(self.script).ok_or(Error::NoScript)?; + match instance.properties.get("Source").ok_or(Error::NoSource)?{ + rbx_dom_weak::types::Variant::String(s)=>s.clone(), + _=>Err(Error::NoSource)?, + } + }; + // run it lole + crate::runner::Runner::new(source).run(context).map_err(Error::Runner) + } +} diff --git a/src/tests.rs b/src/tests.rs new file mode 100644 index 0000000..e69de29 From 2ccc5bb17df0c41d5630aeaba16c5d294095336f Mon Sep 17 00:00:00 2001 From: Quaternions Date: Mon, 16 Sep 2024 19:01:16 -0700 Subject: [PATCH 002/129] runner: no object --- src/runner/mod.rs | 2 +- src/runner/runner.rs | 19 +++++-------------- src/script.rs | 2 +- 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/src/runner/mod.rs b/src/runner/mod.rs index 5cf589b..e525f41 100644 --- a/src/runner/mod.rs +++ b/src/runner/mod.rs @@ -1,3 +1,3 @@ mod runner; -pub use runner::{Runner,Error}; +pub use runner::{run,Error}; diff --git a/src/runner/runner.rs b/src/runner/runner.rs index b8194c2..f670fbf 100644 --- a/src/runner/runner.rs +++ b/src/runner/runner.rs @@ -2,18 +2,9 @@ pub enum Error{ Lua(mlua::Error), } -pub struct Runner{ - source:String, -} - -impl Runner{ - pub const fn new(source:String)->Self{ - Self{source} - } - pub fn run(self,context:&mut crate::context::Context)->Result<(),Error>{ - let lua=mlua::Lua::new(); - lua.sandbox(true).map_err(Error::Lua)?; - lua.load(self.source).exec().map_err(Error::Lua)?; - Ok(()) - } +pub fn run(source:String,context:&mut crate::context::Context)->Result<(),Error>{ + let lua=mlua::Lua::new(); + lua.sandbox(true).map_err(Error::Lua)?; + lua.load(source).exec().map_err(Error::Lua)?; + Ok(()) } diff --git a/src/script.rs b/src/script.rs index 3027c7c..b893afd 100644 --- a/src/script.rs +++ b/src/script.rs @@ -23,6 +23,6 @@ impl Script{ } }; // run it lole - crate::runner::Runner::new(source).run(context).map_err(Error::Runner) + crate::runner::run(source,context).map_err(Error::Runner) } } From 362b5709ff63827d616c285a2f077aaabb5a9fd1 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Tue, 17 Sep 2024 17:16:57 -0700 Subject: [PATCH 003/129] change api again --- src/runner/mod.rs | 2 +- src/runner/runner.rs | 26 ++++++++++++++++++++------ src/script.rs | 6 ++++-- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/runner/mod.rs b/src/runner/mod.rs index e525f41..9b6e5d2 100644 --- a/src/runner/mod.rs +++ b/src/runner/mod.rs @@ -1,3 +1,3 @@ mod runner; -pub use runner::{run,Error}; +pub use runner::Runner; diff --git a/src/runner/runner.rs b/src/runner/runner.rs index f670fbf..c03c38e 100644 --- a/src/runner/runner.rs +++ b/src/runner/runner.rs @@ -1,10 +1,24 @@ -pub enum Error{ - Lua(mlua::Error), +pub struct Runner{ + lua:mlua::Lua, } -pub fn run(source:String,context:&mut crate::context::Context)->Result<(),Error>{ - let lua=mlua::Lua::new(); - lua.sandbox(true).map_err(Error::Lua)?; - lua.load(source).exec().map_err(Error::Lua)?; +fn init(lua:&mlua::Lua)->mlua::Result<()>{ Ok(()) } + +impl Runner{ + pub fn new()->mlua::Result{ + let runner=Self{ + lua:mlua::Lua::new(), + }; + init(&runner.lua)?; + Ok(runner) + } + pub fn set_script(&self,script:rbx_dom_weak::types::Ref)->mlua::Result<()>{ + Ok(()) + } + pub fn run(&self,source:String,context:&mut crate::context::Context)->mlua::Result<()>{ + //Set up dom access here? + self.lua.load(source).exec() + } +} diff --git a/src/script.rs b/src/script.rs index b893afd..a17b7ab 100644 --- a/src/script.rs +++ b/src/script.rs @@ -1,7 +1,7 @@ use rbx_dom_weak::types::Ref; pub enum Error{ - Runner(crate::runner::Error), + Runner(mlua::Error), NoScript, NoSource, } @@ -23,6 +23,8 @@ impl Script{ } }; // run it lole - crate::runner::run(source,context).map_err(Error::Runner) + let runner=crate::runner::Runner::new().map_err(Error::Runner)?; + runner.set_script(self.script).map_err(Error::Runner)?; + runner.run(source,context).map_err(Error::Runner) } } From 1a0bb8f8c45a6f06398583c57cb2ed5c61aa790e Mon Sep 17 00:00:00 2001 From: Quaternions Date: Tue, 17 Sep 2024 17:17:12 -0700 Subject: [PATCH 004/129] paste old code --- Cargo.lock | 7 ++++++ Cargo.toml | 1 + src/runner/cframe.rs | 51 +++++++++++++++++++++++++++++++++++++++++++ src/runner/mod.rs | 3 +++ src/runner/runner.rs | 48 ++++++++++++++++++++++++++++++++++++++++ src/runner/vector3.rs | 51 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 161 insertions(+) create mode 100644 src/runner/cframe.rs create mode 100644 src/runner/vector3.rs diff --git a/Cargo.lock b/Cargo.lock index 57cc3ab..be2a2a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -93,6 +93,12 @@ dependencies = [ "wasi", ] +[[package]] +name = "glam" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "779ae4bf7e8421cf91c0b3b64e7e8b40b862fba4d393f59150042de7c4965a94" + [[package]] name = "lazy_static" version = "1.5.0" @@ -314,6 +320,7 @@ dependencies = [ name = "roblox_emulator" version = "0.1.0" dependencies = [ + "glam", "mlua", "rbx_dom_weak", "rbx_reflection_database", diff --git a/Cargo.toml b/Cargo.toml index 884596f..749bc87 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] +glam = "0.28.0" mlua = { version = "0.9.9", features = ["luau"] } rbx_dom_weak = { version = "2.7.0", registry = "strafesnet" } rbx_reflection_database = { version = "0.2.10", registry = "strafesnet" } diff --git a/src/runner/cframe.rs b/src/runner/cframe.rs new file mode 100644 index 0000000..690aeb3 --- /dev/null +++ b/src/runner/cframe.rs @@ -0,0 +1,51 @@ +use super::vector3::Vector3; + +#[derive(Clone,Copy)] +pub struct CFrame(pub(crate)glam::Affine3A); + +impl CFrame{ + pub fn new(x:f32,y:f32,z:f32)->Self{ + Self(glam::Affine3A::from_translation(glam::vec3(x,y,z))) + } + pub fn angles(x:f32,y:f32,z:f32)->Self{ + Self(glam::Affine3A::from_mat3(glam::Mat3::from_euler(glam::EulerRot::YXZ,y,x,z))) + } +} + +impl mlua::UserData for CFrame{ + fn add_fields<'lua,F:mlua::UserDataFields<'lua,Self>>(fields:&mut F){ + //CFrame.p + fields.add_field_method_get("p",|_,this|Ok(Vector3(this.0.translation))); + } + + fn add_methods<'lua,M:mlua::UserDataMethods<'lua,Self>>(methods:&mut M){ + //methods.add_method("area",|_,this,()|Ok(this.length*this.width)); + + //methods.add_meta_method(mlua::MetaMethod::Mul,|_,this,val:&Vector3|Ok(Vector3(this.0.matrix3*val.0+this.0.translation))); + methods.add_meta_function(mlua::MetaMethod::Mul,|_,(this,val):(Self,Self)|Ok(Self(this.0*val.0))); + methods.add_meta_function(mlua::MetaMethod::ToString,|_,this:Self| + Ok(format!("CFrame.new({},{},{},{},{},{},{},{},{},{},{},{})", + this.0.translation.x, + this.0.translation.y, + this.0.translation.z, + this.0.matrix3.x_axis.x, + this.0.matrix3.y_axis.x, + this.0.matrix3.z_axis.x, + this.0.matrix3.x_axis.y, + this.0.matrix3.y_axis.y, + this.0.matrix3.z_axis.y, + this.0.matrix3.x_axis.z, + this.0.matrix3.y_axis.z, + this.0.matrix3.z_axis.z, + )) + ); + } +} +impl<'lua> mlua::FromLua<'lua> for CFrame{ + fn from_lua(value:mlua::prelude::LuaValue<'lua>,_lua:&'lua mlua::prelude::Lua)->mlua::prelude::LuaResult{ + match value { + mlua::Value::UserData(ud) => Ok(*ud.borrow::()?), + _ => unreachable!(), + } + } +} diff --git a/src/runner/mod.rs b/src/runner/mod.rs index 9b6e5d2..905b778 100644 --- a/src/runner/mod.rs +++ b/src/runner/mod.rs @@ -1,3 +1,6 @@ mod runner; +mod cframe; +mod vector3; + pub use runner::Runner; diff --git a/src/runner/runner.rs b/src/runner/runner.rs index c03c38e..cfec65a 100644 --- a/src/runner/runner.rs +++ b/src/runner/runner.rs @@ -1,8 +1,51 @@ +use super::vector3::Vector3; +use super::cframe::CFrame; + pub struct Runner{ lua:mlua::Lua, } fn init(lua:&mlua::Lua)->mlua::Result<()>{ + lua.sandbox(true)?; + + //global environment + let globals=lua.globals(); + + //Vector3 + { + let vector3_table=lua.create_table()?; + + //Vector3.new + vector3_table.raw_set("new", + lua.create_function(|ctx,(x,y,z):(f32,f32,f32)| + Ok(ctx.create_userdata(Vector3::new(x,y,z))) + )? + )?; + + globals.set("Vector3",vector3_table)?; + } + + //CFrame + { + let cframe_table=lua.create_table()?; + + //CFrame.new + cframe_table.raw_set("new", + lua.create_function(|ctx,(x,y,z):(f32,f32,f32)| + Ok(ctx.create_userdata(CFrame::new(x,y,z))) + )? + )?; + + //CFrame.Angles + cframe_table.raw_set("Angles", + lua.create_function(|ctx,(x,y,z):(f32,f32,f32)| + Ok(ctx.create_userdata(CFrame::angles(x,y,z))) + )? + )?; + + globals.set("CFrame",cframe_table)?; + } + Ok(()) } @@ -15,6 +58,11 @@ impl Runner{ Ok(runner) } pub fn set_script(&self,script:rbx_dom_weak::types::Ref)->mlua::Result<()>{ + //TODO: Instance type + let script_table=self.lua.create_table()?; + //script.Name + script_table.raw_set("Name","Placeholder")?; + self.lua.globals().set("script",script_table)?; Ok(()) } pub fn run(&self,source:String,context:&mut crate::context::Context)->mlua::Result<()>{ diff --git a/src/runner/vector3.rs b/src/runner/vector3.rs new file mode 100644 index 0000000..8c8cb9a --- /dev/null +++ b/src/runner/vector3.rs @@ -0,0 +1,51 @@ +#[derive(Clone,Copy)] +pub struct Vector3(pub(crate)glam::Vec3A); + +impl Vector3{ + pub const fn new(x:f32,y:f32,z:f32)->Self{ + Self(glam::vec3a(x,y,z)) + } +} + +impl mlua::UserData for Vector3{ + fn add_fields<'lua,F: mlua::UserDataFields<'lua,Self>>(fields: &mut F) { + fields.add_field_method_get("magnitude",|_,this| Ok(this.0.length())); + fields.add_field_method_get("x",|_,this| Ok(this.0.x)); + fields.add_field_method_set("x",|_,this,val| { + this.0.x = val; + Ok(()) + }); + fields.add_field_method_get("y",|_,this| Ok(this.0.y)); + fields.add_field_method_set("y",|_,this,val| { + this.0.y = val; + Ok(()) + }); + fields.add_field_method_get("z",|_,this| Ok(this.0.z)); + fields.add_field_method_set("z",|_,this,val| { + this.0.z = val; + Ok(()) + }); + } + + fn add_methods<'lua,M: mlua::UserDataMethods<'lua,Self>>(methods:&mut M){ + //methods.add_method("area",|_,this,()| Ok(this.length * this.width)); + + methods.add_meta_function(mlua::MetaMethod::Add,|_,(this,val):(Self,Self)|Ok(Self(this.0+val.0))); + methods.add_meta_function(mlua::MetaMethod::ToString,|_,this:Self| + Ok(format!("Vector3.new({},{},{})", + this.0.x, + this.0.y, + this.0.z, + )) + ); + } +} + +impl<'lua> mlua::FromLua<'lua> for Vector3{ + fn from_lua(value:mlua::prelude::LuaValue<'lua>,_lua:&'lua mlua::prelude::Lua)->mlua::prelude::LuaResult{ + match value { + mlua::Value::UserData(ud) => Ok(*ud.borrow::()?), + _ => unreachable!(), + } + } +} From a4e2ed7e2fb002b2ba7bf1e036704636a30badf3 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Tue, 17 Sep 2024 18:00:17 -0700 Subject: [PATCH 005/129] error printing function --- src/script.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/script.rs b/src/script.rs index a17b7ab..360f4d6 100644 --- a/src/script.rs +++ b/src/script.rs @@ -1,10 +1,21 @@ use rbx_dom_weak::types::Ref; +#[derive(Debug)] pub enum Error{ Runner(mlua::Error), NoScript, NoSource, } +impl Error{ + pub fn print(self){ + match self{ + Self::Runner(mlua::Error::RuntimeError(s))=>{ + println!("lua error: {s:?}"); + }, + other=>println!("{:?}",other), + } + } +} pub struct Script{ script:Ref, From 1585e2f32178faaaa5f2d15b54a68415b28142b7 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Tue, 17 Sep 2024 18:26:30 -0700 Subject: [PATCH 006/129] fix the problem --- src/script.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/script.rs b/src/script.rs index 360f4d6..5453eae 100644 --- a/src/script.rs +++ b/src/script.rs @@ -10,7 +10,7 @@ impl Error{ pub fn print(self){ match self{ Self::Runner(mlua::Error::RuntimeError(s))=>{ - println!("lua error: {s:?}"); + println!("lua error: {s}"); }, other=>println!("{:?}",other), } From c7c17243fb22d059801b94b695bbbba8065e6396 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Tue, 17 Sep 2024 18:26:58 -0700 Subject: [PATCH 007/129] set script full name --- src/runner/runner.rs | 10 +++++++--- src/script.rs | 20 ++++++++++++++++---- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/runner/runner.rs b/src/runner/runner.rs index cfec65a..4297b71 100644 --- a/src/runner/runner.rs +++ b/src/runner/runner.rs @@ -57,16 +57,20 @@ impl Runner{ init(&runner.lua)?; Ok(runner) } - pub fn set_script(&self,script:rbx_dom_weak::types::Ref)->mlua::Result<()>{ + pub fn set_script(&self,script:rbx_dom_weak::types::Ref,name:String)->mlua::Result<()>{ //TODO: Instance type let script_table=self.lua.create_table()?; //script.Name - script_table.raw_set("Name","Placeholder")?; + script_table.raw_set("Name",name)?; self.lua.globals().set("script",script_table)?; Ok(()) } pub fn run(&self,source:String,context:&mut crate::context::Context)->mlua::Result<()>{ //Set up dom access here? - self.lua.load(source).exec() + let script:mlua::Table<'_>=self.lua.globals().raw_get("script")?; + let name:String=script.raw_get("Name")?; + self.lua.load(source) + .set_name(name) + .exec() } } diff --git a/src/script.rs b/src/script.rs index 5453eae..f2cb1a7 100644 --- a/src/script.rs +++ b/src/script.rs @@ -17,6 +17,17 @@ impl Error{ } } +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.as_str()); + pref=parent.parent(); + } + full_name +} + pub struct Script{ script:Ref, } @@ -26,16 +37,17 @@ impl Script{ } pub fn run(&self,context:&mut crate::context::Context)->Result<(),Error>{ // grab source - let source={ + let (source,full_name)={ let instance=context.dom.get_by_ref(self.script).ok_or(Error::NoScript)?; - match instance.properties.get("Source").ok_or(Error::NoSource)?{ + let source=match instance.properties.get("Source").ok_or(Error::NoSource)?{ rbx_dom_weak::types::Variant::String(s)=>s.clone(), _=>Err(Error::NoSource)?, - } + }; + (source,get_full_name(&context.dom,instance)) }; // run it lole let runner=crate::runner::Runner::new().map_err(Error::Runner)?; - runner.set_script(self.script).map_err(Error::Runner)?; + runner.set_script(self.script,full_name).map_err(Error::Runner)?; runner.run(source,context).map_err(Error::Runner) } } From f84bd5651e50c8abf58aa2266be4c8f857894f53 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Wed, 18 Sep 2024 15:30:28 -0700 Subject: [PATCH 008/129] context take a &mut WeakDom to simplify external business --- src/context.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/context.rs b/src/context.rs index cd85038..47957bc 100644 --- a/src/context.rs +++ b/src/context.rs @@ -10,16 +10,13 @@ pub fn class_is_a(class:&str,superclass:&str)->bool{ ) } -pub struct Context{ - pub(crate)dom:WeakDom, +pub struct Context<'a>{ + pub(crate)dom:&'a mut WeakDom, } -impl Context{ - pub const fn new(dom:WeakDom)->Self{ - Self{dom} - } - pub fn into_inner(self)->WeakDom{ - self.dom +impl Context<'_>{ + pub fn new(dom:&mut WeakDom)->Context<'_>{ + Context{dom} } /// Creates an iterator over all items of a particular class. pub fn superclass_iter<'a>(&'a self,superclass:&'a str)->impl Iterator+'a{ From d5854f7e92caf4044a1b34a80961d95f65150d65 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Wed, 18 Sep 2024 18:46:38 -0700 Subject: [PATCH 009/129] add deps --- Cargo.lock | 2 ++ Cargo.toml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index be2a2a2..76099f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -323,7 +323,9 @@ dependencies = [ "glam", "mlua", "rbx_dom_weak", + "rbx_reflection", "rbx_reflection_database", + "rbx_types", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 749bc87..b4991a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,4 +7,6 @@ edition = "2021" glam = "0.28.0" mlua = { version = "0.9.9", features = ["luau"] } rbx_dom_weak = { version = "2.7.0", registry = "strafesnet" } +rbx_reflection = { version = "4.7.0", registry = "strafesnet" } rbx_reflection_database = { version = "0.2.10", registry = "strafesnet" } +rbx_types = { version = "1.10.0", registry = "strafesnet" } From cef0ce4c09e14a00c1e8349e44b314f96a388a68 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Wed, 18 Sep 2024 18:47:55 -0700 Subject: [PATCH 010/129] impl Into for Vector3 --- src/runner/vector3.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/runner/vector3.rs b/src/runner/vector3.rs index 8c8cb9a..7fd6753 100644 --- a/src/runner/vector3.rs +++ b/src/runner/vector3.rs @@ -7,6 +7,12 @@ impl Vector3{ } } +impl Into for Vector3{ + fn into(self)->rbx_types::Vector3{ + rbx_types::Vector3::new(self.0.x,self.0.y,self.0.z) + } +} + impl mlua::UserData for Vector3{ fn add_fields<'lua,F: mlua::UserDataFields<'lua,Self>>(fields: &mut F) { fields.add_field_method_get("magnitude",|_,this| Ok(this.0.length())); From 129998e6286168ce69392b22a6dcc3b6fc19b8a0 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Wed, 18 Sep 2024 18:48:07 -0700 Subject: [PATCH 011/129] tweak Vector3 FromLua --- src/runner/vector3.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/runner/vector3.rs b/src/runner/vector3.rs index 7fd6753..36aee3e 100644 --- a/src/runner/vector3.rs +++ b/src/runner/vector3.rs @@ -49,9 +49,9 @@ impl mlua::UserData for Vector3{ impl<'lua> mlua::FromLua<'lua> for Vector3{ fn from_lua(value:mlua::prelude::LuaValue<'lua>,_lua:&'lua mlua::prelude::Lua)->mlua::prelude::LuaResult{ - match value { - mlua::Value::UserData(ud) => Ok(*ud.borrow::()?), - _ => unreachable!(), + match value{ + mlua::Value::UserData(ud)=>ud.take(), + other=>Err(mlua::Error::runtime(format!("Expected Vector3 got {:?}",other))), } } } From 2dddda685a34775ebafc34c50b8fdaf1055afabb Mon Sep 17 00:00:00 2001 From: Quaternions Date: Wed, 18 Sep 2024 18:47:38 -0700 Subject: [PATCH 012/129] must own (rework api) --- src/context.rs | 11 +++--- src/lib.rs | 2 +- src/runner/instance.rs | 79 ++++++++++++++++++++++++++++++++++++++++++ src/runner/mod.rs | 1 + src/runner/runner.rs | 48 +++++++++++++++++-------- src/script.rs | 34 +++++------------- 6 files changed, 130 insertions(+), 45 deletions(-) create mode 100644 src/runner/instance.rs diff --git a/src/context.rs b/src/context.rs index 47957bc..cc5f4e0 100644 --- a/src/context.rs +++ b/src/context.rs @@ -10,14 +10,17 @@ pub fn class_is_a(class:&str,superclass:&str)->bool{ ) } -pub struct Context<'a>{ - pub(crate)dom:&'a mut WeakDom, +pub struct Context{ + pub(crate)dom:WeakDom, } -impl Context<'_>{ - pub fn new(dom:&mut WeakDom)->Context<'_>{ +impl Context{ + pub fn new(dom:WeakDom)->Context{ Context{dom} } + pub fn into_inner(self)->WeakDom{ + self.dom + } /// Creates an iterator over all items of a particular class. pub fn superclass_iter<'a>(&'a self,superclass:&'a str)->impl Iterator+'a{ self.dom.descendants().filter(|&instance| diff --git a/src/lib.rs b/src/lib.rs index fb0dd5f..8c34547 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ pub mod script; pub mod context; -mod runner; +pub mod runner; pub type Result=core::result::Result; diff --git a/src/runner/instance.rs b/src/runner/instance.rs new file mode 100644 index 0000000..f8103a4 --- /dev/null +++ b/src/runner/instance.rs @@ -0,0 +1,79 @@ +use rbx_dom_weak::WeakDom; + +use super::vector3::Vector3; + +pub struct Instance{ + referent:rbx_types::Ref, +} + +impl From for Instance{ + fn from(value:crate::script::Script)->Self{ + Self{referent:value.script} + } +} + +impl Instance{ + pub const fn new(referent:rbx_types::Ref)->Self{ + Self{referent} + } + pub fn get<'a>(&'a self,dom:&'a WeakDom)->mlua::Result<&'a rbx_dom_weak::Instance>{ + dom.get_by_ref(self.referent).ok_or(mlua::Error::runtime("Instance missing")) + } + pub fn get_mut<'a>(&'a self,dom:&'a mut WeakDom)->mlua::Result<&'a mut rbx_dom_weak::Instance>{ + dom.get_by_ref_mut(self.referent).ok_or(mlua::Error::runtime("Instance missing")) + } +} + +// LMAO look at this function! +fn dom(lua:&mlua::Lua,mut f:impl FnMut(&mut WeakDom)->mlua::Result)->mlua::Result{ + f(&mut *lua.app_data_mut::().ok_or(mlua::Error::runtime("DataModel missing"))?) +} + +impl mlua::UserData for Instance{ + fn add_fields<'lua,F:mlua::UserDataFields<'lua,Self>>(fields:&mut F){ + fields.add_field_method_get("Parent",|lua,this|{ + dom(lua,|dom|{ + let instance=this.get(dom)?; + Ok(Instance::new(instance.parent())) + }) + }); + fields.add_field_method_set("Parent",|lua,this,val:Self|{ + dom(lua,|dom|{ + dom.transfer_within(this.referent,val.referent); + Ok(()) + }) + }); + } + + fn add_methods<'lua,M:mlua::UserDataMethods<'lua,Self>>(methods:&mut M){ + methods.add_meta_function(mlua::MetaMethod::NewIndex,|lua,(this,index,value):(Self,mlua::String,mlua::Value)| + dom(lua,|dom|{ + let instance=this.get_mut(dom)?; + let index_str=index.to_str()?; + let class=rbx_reflection_database::get().classes.get(instance.class.as_str()).ok_or(mlua::Error::runtime("Class missing"))?; + let property=class.default_properties.get(index_str).ok_or(mlua::Error::runtime(format!("Property '{index_str}' missing on class '{}'",class.name)))?; + match property{ + rbx_types::Variant::Vector3(_)=>{ + let typed_value:Vector3=value.as_userdata().ok_or(mlua::Error::runtime("Expected Userdata"))?.take()?; + instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Vector3(typed_value.into())); + }, + rbx_types::Variant::Float64(_)=>{ + let typed_value:f64=value.as_f64().ok_or(mlua::Error::runtime("Expected f64"))?; + instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Float64(typed_value)); + }, + _=>unimplemented!(), + } + Ok(()) + }) + ); + } +} + +impl<'lua> mlua::FromLua<'lua> for Instance{ + fn from_lua(value:mlua::prelude::LuaValue<'lua>,_lua:&'lua mlua::prelude::Lua)->mlua::prelude::LuaResult{ + match value{ + mlua::Value::UserData(ud)=>ud.take(), + other=>Err(mlua::Error::runtime(format!("Expected Instance got {:?}",other))), + } + } +} diff --git a/src/runner/mod.rs b/src/runner/mod.rs index 905b778..a00b1cf 100644 --- a/src/runner/mod.rs +++ b/src/runner/mod.rs @@ -2,5 +2,6 @@ mod runner; mod cframe; mod vector3; +mod instance; pub use runner::Runner; diff --git a/src/runner/runner.rs b/src/runner/runner.rs index 4297b71..0d68d5e 100644 --- a/src/runner/runner.rs +++ b/src/runner/runner.rs @@ -1,9 +1,28 @@ +use crate::context::Context; + use super::vector3::Vector3; use super::cframe::CFrame; pub struct Runner{ lua:mlua::Lua, } +#[derive(Debug)] +pub enum Error{ + Lua(mlua::Error), + Script(crate::script::Error), + /// If the lua.remove_app_data function fails + RemoveAppData, +} +impl Error{ + pub fn print(self){ + match self{ + Self::Lua(mlua::Error::RuntimeError(s))=>{ + println!("lua error: {s}"); + }, + other=>println!("{:?}",other), + } + } +} fn init(lua:&mlua::Lua)->mlua::Result<()>{ lua.sandbox(true)?; @@ -57,20 +76,19 @@ impl Runner{ init(&runner.lua)?; Ok(runner) } - pub fn set_script(&self,script:rbx_dom_weak::types::Ref,name:String)->mlua::Result<()>{ - //TODO: Instance type - let script_table=self.lua.create_table()?; - //script.Name - script_table.raw_set("Name",name)?; - self.lua.globals().set("script",script_table)?; - Ok(()) - } - pub fn run(&self,source:String,context:&mut crate::context::Context)->mlua::Result<()>{ - //Set up dom access here? - let script:mlua::Table<'_>=self.lua.globals().raw_get("script")?; - let name:String=script.raw_get("Name")?; - self.lua.load(source) - .set_name(name) - .exec() + pub fn run_script(&self,script:crate::script::Script,context:Context)->(Context,Result<(),Error>){ + let yoink=script.name_source(&context); + self.lua.set_app_data(context.dom); + let r=(||{ + let (name,source)=yoink.map_err(Error::Script)?; + self.lua.globals().set("script",super::instance::Instance::from(script)).map_err(Error::Lua)?; + self.lua.load(source) + .set_name(name) + .exec().map_err(Error::Lua)?; + Ok(()) + })(); + let dom=self.lua.remove_app_data() + .expect("Fatal: Lua lost the dom"); + (Context::new(dom),r) } } diff --git a/src/script.rs b/src/script.rs index f2cb1a7..8a81941 100644 --- a/src/script.rs +++ b/src/script.rs @@ -1,21 +1,12 @@ use rbx_dom_weak::types::Ref; +use crate::context::Context; + #[derive(Debug)] pub enum Error{ - Runner(mlua::Error), NoScript, NoSource, } -impl Error{ - pub fn print(self){ - match self{ - Self::Runner(mlua::Error::RuntimeError(s))=>{ - println!("lua error: {s}"); - }, - other=>println!("{:?}",other), - } - } -} fn get_full_name(dom:&rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance)->String{ let mut full_name=instance.name.clone(); @@ -29,25 +20,18 @@ fn get_full_name(dom:&rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance)->S } pub struct Script{ - script:Ref, + pub(crate)script:Ref, } impl Script{ pub const fn new(script:Ref)->Self{ Self{script} } - pub fn run(&self,context:&mut crate::context::Context)->Result<(),Error>{ - // grab source - let (source,full_name)={ - let instance=context.dom.get_by_ref(self.script).ok_or(Error::NoScript)?; - let source=match instance.properties.get("Source").ok_or(Error::NoSource)?{ - rbx_dom_weak::types::Variant::String(s)=>s.clone(), - _=>Err(Error::NoSource)?, - }; - (source,get_full_name(&context.dom,instance)) + pub fn name_source(&self,context:&Context)->Result<(String,String),Error>{ + let instance=context.dom.get_by_ref(self.script).ok_or(Error::NoScript)?; + let source=match instance.properties.get("Source").ok_or(Error::NoSource)?{ + rbx_dom_weak::types::Variant::String(s)=>s.clone(), + _=>Err(Error::NoSource)?, }; - // run it lole - let runner=crate::runner::Runner::new().map_err(Error::Runner)?; - runner.set_script(self.script,full_name).map_err(Error::Runner)?; - runner.run(source,context).map_err(Error::Runner) + Ok((get_full_name(&context.dom,instance),source)) } } From a394778a8e89a8be45c87a40a1145eeb7e4b85bf Mon Sep 17 00:00:00 2001 From: Quaternions Date: Wed, 18 Sep 2024 20:16:14 -0700 Subject: [PATCH 013/129] make boosters work --- src/runner/instance.rs | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index f8103a4..448adc2 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -29,6 +29,14 @@ fn dom(lua:&mlua::Lua,mut f:impl FnMut(&mut WeakDom)->mlua::Result)->mlua: f(&mut *lua.app_data_mut::().ok_or(mlua::Error::runtime("DataModel missing"))?) } +fn coerce_float(value:&mlua::Value)->Option{ + match value{ + &mlua::Value::Integer(i)=>Some(i as f32), + &mlua::Value::Number(f)=>Some(f as f32), + _=>None, + } +} + impl mlua::UserData for Instance{ fn add_fields<'lua,F:mlua::UserDataFields<'lua,Self>>(fields:&mut F){ fields.add_field_method_get("Parent",|lua,this|{ @@ -46,6 +54,24 @@ impl mlua::UserData for Instance{ } fn add_methods<'lua,M:mlua::UserDataMethods<'lua,Self>>(methods:&mut M){ + methods.add_method("GetChildren",|lua,this,_:()| + dom(lua,|dom|{ + let instance=this.get(dom)?; + let children:Vec<_>=instance + .children() + .iter() + .copied() + .map(Instance::new) + .collect(); + Ok(children) + }) + ); + methods.add_method("IsA",|lua,this,classname:mlua::String| + dom(lua,|dom|{ + let instance=this.get(dom)?; + Ok(crate::context::class_is_a(instance.class.as_str(),classname.to_str()?)) + }) + ); methods.add_meta_function(mlua::MetaMethod::NewIndex,|lua,(this,index,value):(Self,mlua::String,mlua::Value)| dom(lua,|dom|{ let instance=this.get_mut(dom)?; @@ -57,11 +83,11 @@ impl mlua::UserData for Instance{ let typed_value:Vector3=value.as_userdata().ok_or(mlua::Error::runtime("Expected Userdata"))?.take()?; instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Vector3(typed_value.into())); }, - rbx_types::Variant::Float64(_)=>{ - let typed_value:f64=value.as_f64().ok_or(mlua::Error::runtime("Expected f64"))?; - instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Float64(typed_value)); + rbx_types::Variant::Float32(_)=>{ + let typed_value:f32=coerce_float(&value).ok_or(mlua::Error::runtime("Expected f32"))?; + instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Float32(typed_value)); }, - _=>unimplemented!(), + other=>println!("Unimplemented property type: {other:?}"), } Ok(()) }) From 261e0a474efefe7d8e76ce25fa9c5abfcf01ff43 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Wed, 18 Sep 2024 20:16:28 -0700 Subject: [PATCH 014/129] GetDescendants --- src/runner/instance.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 448adc2..5ef7b6a 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -66,6 +66,17 @@ impl mlua::UserData for Instance{ Ok(children) }) ); + methods.add_method("GetDescendants",|lua,this,_:()| + dom(lua,|dom|{ + let children:Vec<_>=dom + .descendants_of(this.referent) + .map(|instance| + Instance::new(instance.referent()) + ) + .collect(); + Ok(children) + }) + ); methods.add_method("IsA",|lua,this,classname:mlua::String| dom(lua,|dom|{ let instance=this.get(dom)?; From acfdc1bd5e3f3bcc5c581e2169de0d9901af3411 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 20 Sep 2024 11:41:13 -0700 Subject: [PATCH 015/129] v0.1.0 open source --- Cargo.toml | 4 ++ LICENSE-APACHE | 176 +++++++++++++++++++++++++++++++++++++++++++++++++ LICENSE-MIT | 23 +++++++ README.md | 19 ++++++ 4 files changed, 222 insertions(+) create mode 100644 LICENSE-APACHE create mode 100644 LICENSE-MIT create mode 100644 README.md diff --git a/Cargo.toml b/Cargo.toml index b4991a7..6854b70 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,10 @@ name = "roblox_emulator" version = "0.1.0" edition = "2021" +repository = "https://git.itzana.me/StrafesNET/roblox_emulator" +license = "MIT OR Apache-2.0" +description = "Run embedded Luau scripts which manipulate the DOM." +authors = ["Rhys Lloyd "] [dependencies] glam = "0.28.0" diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 0000000..a7e77cb --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..468cd79 --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..f488cb1 --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +Roblox Emulator +=============== + +## Run embedded Lua scripts which manipulate the DOM + +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + From aa0bee9f69822b4b781c300e35458d25f2c8a884 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 20 Sep 2024 13:51:17 -0700 Subject: [PATCH 016/129] the "transmute lifetimes" solution --- src/context.rs | 7 ++++--- src/runner/instance.rs | 3 ++- src/runner/runner.rs | 25 +++++++++++-------------- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/context.rs b/src/context.rs index cc5f4e0..4ca6f66 100644 --- a/src/context.rs +++ b/src/context.rs @@ -10,16 +10,17 @@ pub fn class_is_a(class:&str,superclass:&str)->bool{ ) } +#[repr(transparent)] pub struct Context{ pub(crate)dom:WeakDom, } impl Context{ - pub fn new(dom:WeakDom)->Context{ + pub const fn new(dom:WeakDom)->Context{ Context{dom} } - pub fn into_inner(self)->WeakDom{ - self.dom + pub fn from_mut(dom:&mut WeakDom)->&mut Context{ + unsafe{&mut *(dom as *mut WeakDom as *mut Context)} } /// Creates an iterator over all items of a particular class. pub fn superclass_iter<'a>(&'a self,superclass:&'a str)->impl Iterator+'a{ diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 5ef7b6a..1289826 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -26,7 +26,8 @@ impl Instance{ // LMAO look at this function! fn dom(lua:&mlua::Lua,mut f:impl FnMut(&mut WeakDom)->mlua::Result)->mlua::Result{ - f(&mut *lua.app_data_mut::().ok_or(mlua::Error::runtime("DataModel missing"))?) + let mut dom=lua.app_data_mut::<&'static mut WeakDom>().ok_or(mlua::Error::runtime("DataModel missing"))?; + f(&mut *dom) } fn coerce_float(value:&mlua::Value)->Option{ diff --git a/src/runner/runner.rs b/src/runner/runner.rs index 0d68d5e..fc0fbb6 100644 --- a/src/runner/runner.rs +++ b/src/runner/runner.rs @@ -76,19 +76,16 @@ impl Runner{ init(&runner.lua)?; Ok(runner) } - pub fn run_script(&self,script:crate::script::Script,context:Context)->(Context,Result<(),Error>){ - let yoink=script.name_source(&context); - self.lua.set_app_data(context.dom); - let r=(||{ - let (name,source)=yoink.map_err(Error::Script)?; - self.lua.globals().set("script",super::instance::Instance::from(script)).map_err(Error::Lua)?; - self.lua.load(source) - .set_name(name) - .exec().map_err(Error::Lua)?; - Ok(()) - })(); - let dom=self.lua.remove_app_data() - .expect("Fatal: Lua lost the dom"); - (Context::new(dom),r) + pub fn run_script(&self,script:crate::script::Script,context:&mut Context)->Result<(),Error>{ + let yoink=script.name_source(context); + //this makes set_app_data shut up about the lifetime + self.lua.set_app_data::<&'static mut rbx_dom_weak::WeakDom>(unsafe{core::mem::transmute(&mut context.dom)}); + let (name,source)=yoink.map_err(Error::Script)?; + self.lua.globals().set("script",super::instance::Instance::from(script)).map_err(Error::Lua)?; + self.lua.load(source) + .set_name(name) + .exec().map_err(Error::Lua)?; + self.lua.remove_app_data::<&'static mut rbx_dom_weak::WeakDom>(); + Ok(()) } } From 930ac1c331246b7c9aede5fd2bcdfb20936dc5ee Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 20 Sep 2024 17:53:55 -0700 Subject: [PATCH 017/129] cframe: fixup FromLua --- src/runner/cframe.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/runner/cframe.rs b/src/runner/cframe.rs index 690aeb3..8536204 100644 --- a/src/runner/cframe.rs +++ b/src/runner/cframe.rs @@ -43,9 +43,9 @@ impl mlua::UserData for CFrame{ } impl<'lua> mlua::FromLua<'lua> for CFrame{ fn from_lua(value:mlua::prelude::LuaValue<'lua>,_lua:&'lua mlua::prelude::Lua)->mlua::prelude::LuaResult{ - match value { - mlua::Value::UserData(ud) => Ok(*ud.borrow::()?), - _ => unreachable!(), + match value{ + mlua::Value::UserData(ud)=>ud.take()?, + other=>Err(mlua::Error::runtime(format!("Expected CFrame got {:?}",other))), } } } From 701897b00d25057e92e0c335ab6251a089a3c47f Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 20 Sep 2024 17:54:16 -0700 Subject: [PATCH 018/129] coerce_float32 --- src/runner/instance.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 1289826..b0719be 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -30,7 +30,7 @@ fn dom(lua:&mlua::Lua,mut f:impl FnMut(&mut WeakDom)->mlua::Result)->mlua: f(&mut *dom) } -fn coerce_float(value:&mlua::Value)->Option{ +fn coerce_float32(value:&mlua::Value)->Option{ match value{ &mlua::Value::Integer(i)=>Some(i as f32), &mlua::Value::Number(f)=>Some(f as f32), @@ -96,7 +96,7 @@ impl mlua::UserData for Instance{ instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Vector3(typed_value.into())); }, rbx_types::Variant::Float32(_)=>{ - let typed_value:f32=coerce_float(&value).ok_or(mlua::Error::runtime("Expected f32"))?; + let typed_value:f32=coerce_float32(&value).ok_or(mlua::Error::runtime("Expected f32"))?; instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Float32(typed_value)); }, other=>println!("Unimplemented property type: {other:?}"), From e2c74b8dfe272e3b87282bd8d9d9492f4feaff1a Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 20 Sep 2024 17:54:43 -0700 Subject: [PATCH 019/129] use find_default_property --- src/runner/instance.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index b0719be..551c6ff 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -88,8 +88,9 @@ impl mlua::UserData for Instance{ dom(lua,|dom|{ let instance=this.get_mut(dom)?; let index_str=index.to_str()?; - let class=rbx_reflection_database::get().classes.get(instance.class.as_str()).ok_or(mlua::Error::runtime("Class missing"))?; - let property=class.default_properties.get(index_str).ok_or(mlua::Error::runtime(format!("Property '{index_str}' missing on class '{}'",class.name)))?; + let db=rbx_reflection_database::get(); + let class=db.classes.get(instance.class.as_str()).ok_or(mlua::Error::runtime("Class missing"))?; + let property=db.find_default_property(class,index_str).ok_or(mlua::Error::runtime(format!("Property '{index_str}' missing on class '{}'",class.name)))?; match property{ rbx_types::Variant::Vector3(_)=>{ let typed_value:Vector3=value.as_userdata().ok_or(mlua::Error::runtime("Expected Userdata"))?.take()?; From ededfd9e55a798c70e7071ff7c92d4c7218aaed7 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 20 Sep 2024 18:01:25 -0700 Subject: [PATCH 020/129] include source in error --- src/runner/runner.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/runner/runner.rs b/src/runner/runner.rs index fc0fbb6..8475486 100644 --- a/src/runner/runner.rs +++ b/src/runner/runner.rs @@ -8,7 +8,10 @@ pub struct Runner{ } #[derive(Debug)] pub enum Error{ - Lua(mlua::Error), + Lua{ + source:String, + error:mlua::Error + }, Script(crate::script::Error), /// If the lua.remove_app_data function fails RemoveAppData, @@ -16,8 +19,8 @@ pub enum Error{ impl Error{ pub fn print(self){ match self{ - Self::Lua(mlua::Error::RuntimeError(s))=>{ - println!("lua error: {s}"); + Self::Lua{source,error:mlua::Error::RuntimeError(s)}=>{ + println!("lua error: {s}\nsource:{source}"); }, other=>println!("{:?}",other), } @@ -81,11 +84,12 @@ impl Runner{ //this makes set_app_data shut up about the lifetime self.lua.set_app_data::<&'static mut rbx_dom_weak::WeakDom>(unsafe{core::mem::transmute(&mut context.dom)}); let (name,source)=yoink.map_err(Error::Script)?; - self.lua.globals().set("script",super::instance::Instance::from(script)).map_err(Error::Lua)?; - self.lua.load(source) + self.lua.globals().set("script",super::instance::Instance::from(script)).map_err(|error|Error::Lua{source:source.clone(),error})?; + let r=self.lua.load(source.as_str()) .set_name(name) - .exec().map_err(Error::Lua)?; + .exec().map_err(|error|Error::Lua{source,error}); self.lua.remove_app_data::<&'static mut rbx_dom_weak::WeakDom>(); + r?; Ok(()) } } From ff76f3c865cdc55dccc5ad9439f160ea6d712a4d Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 20 Sep 2024 18:01:33 -0700 Subject: [PATCH 021/129] Instance: name --- src/runner/instance.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 551c6ff..09bc459 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -52,6 +52,20 @@ impl mlua::UserData for Instance{ Ok(()) }) }); + fields.add_field_method_get("Name",|lua,this|{ + dom(lua,|dom|{ + let instance=this.get(dom)?; + Ok(instance.name.clone()) + }) + }); + fields.add_field_method_set("Name",|lua,this,val:String|{ + dom(lua,move|dom|{ + let instance=this.get_mut(dom)?; + //Why does this need to be cloned? + instance.name=val.clone(); + Ok(()) + }) + }); } fn add_methods<'lua,M:mlua::UserDataMethods<'lua,Self>>(methods:&mut M){ From 90609f4ad4b864f77c5cbb9ed61c8fffd1a8609f Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 20 Sep 2024 18:21:00 -0700 Subject: [PATCH 022/129] the composition paradigm --- src/runner/instance.rs | 119 +++++++++++++++++++++++++++++++---------- 1 file changed, 91 insertions(+), 28 deletions(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 09bc459..45484d7 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -1,29 +1,8 @@ +use rbx_types::Ref; use rbx_dom_weak::WeakDom; use super::vector3::Vector3; -pub struct Instance{ - referent:rbx_types::Ref, -} - -impl From for Instance{ - fn from(value:crate::script::Script)->Self{ - Self{referent:value.script} - } -} - -impl Instance{ - pub const fn new(referent:rbx_types::Ref)->Self{ - Self{referent} - } - pub fn get<'a>(&'a self,dom:&'a WeakDom)->mlua::Result<&'a rbx_dom_weak::Instance>{ - dom.get_by_ref(self.referent).ok_or(mlua::Error::runtime("Instance missing")) - } - pub fn get_mut<'a>(&'a self,dom:&'a mut WeakDom)->mlua::Result<&'a mut rbx_dom_weak::Instance>{ - dom.get_by_ref_mut(self.referent).ok_or(mlua::Error::runtime("Instance missing")) - } -} - // LMAO look at this function! fn dom(lua:&mlua::Lua,mut f:impl FnMut(&mut WeakDom)->mlua::Result)->mlua::Result{ let mut dom=lua.app_data_mut::<&'static mut WeakDom>().ok_or(mlua::Error::runtime("DataModel missing"))?; @@ -38,8 +17,36 @@ fn coerce_float32(value:&mlua::Value)->Option{ } } -impl mlua::UserData for Instance{ - fn add_fields<'lua,F:mlua::UserDataFields<'lua,Self>>(fields:&mut F){ +trait Referent{ + fn referent(&self)->Ref; + fn get<'a>(&self,dom:&'a WeakDom)->mlua::Result<&'a rbx_dom_weak::Instance>{ + dom.get_by_ref(self.referent()).ok_or(mlua::Error::runtime("Instance missing")) + } + fn get_mut<'a>(&self,dom:&'a mut WeakDom)->mlua::Result<&'a mut rbx_dom_weak::Instance>{ + dom.get_by_ref_mut(self.referent()).ok_or(mlua::Error::runtime("Instance missing")) + } +} + +pub struct Instance{ + referent:Ref, +} +impl Referent for Instance{ + fn referent(&self)->Ref{ + self.referent + } +} + +impl From for Instance{ + fn from(value:crate::script::Script)->Self{ + Self{referent:value.script} + } +} + +impl Instance{ + pub const fn new(referent:Ref)->Self{ + Self{referent} + } + fn add_fields<'lua,T:Referent,F:mlua::UserDataFields<'lua,T>>(fields:&mut F){ fields.add_field_method_get("Parent",|lua,this|{ dom(lua,|dom|{ let instance=this.get(dom)?; @@ -48,7 +55,7 @@ impl mlua::UserData for Instance{ }); fields.add_field_method_set("Parent",|lua,this,val:Self|{ dom(lua,|dom|{ - dom.transfer_within(this.referent,val.referent); + dom.transfer_within(this.referent(),val.referent); Ok(()) }) }); @@ -68,7 +75,7 @@ impl mlua::UserData for Instance{ }); } - fn add_methods<'lua,M:mlua::UserDataMethods<'lua,Self>>(methods:&mut M){ + fn add_methods<'lua,T:Referent,M:mlua::UserDataMethods<'lua,T>>(methods:&mut M){ methods.add_method("GetChildren",|lua,this,_:()| dom(lua,|dom|{ let instance=this.get(dom)?; @@ -84,7 +91,7 @@ impl mlua::UserData for Instance{ methods.add_method("GetDescendants",|lua,this,_:()| dom(lua,|dom|{ let children:Vec<_>=dom - .descendants_of(this.referent) + .descendants_of(this.referent()) .map(|instance| Instance::new(instance.referent()) ) @@ -100,6 +107,7 @@ impl mlua::UserData for Instance{ ); methods.add_meta_function(mlua::MetaMethod::NewIndex,|lua,(this,index,value):(Self,mlua::String,mlua::Value)| dom(lua,|dom|{ + //println!("__newindex t={this:?} i={index:?} v={value:?}"); let instance=this.get_mut(dom)?; let index_str=index.to_str()?; let db=rbx_reflection_database::get(); @@ -121,7 +129,14 @@ impl mlua::UserData for Instance{ ); } } - +impl mlua::UserData for Instance{ + fn add_fields<'lua,F:mlua::UserDataFields<'lua,Self>>(fields:&mut F){ + Instance::add_fields(fields); + } + fn add_methods<'lua,M:mlua::UserDataMethods<'lua,Self>>(methods:&mut M){ + Instance::add_methods(methods); + } +} impl<'lua> mlua::FromLua<'lua> for Instance{ fn from_lua(value:mlua::prelude::LuaValue<'lua>,_lua:&'lua mlua::prelude::Lua)->mlua::prelude::LuaResult{ match value{ @@ -130,3 +145,51 @@ impl<'lua> mlua::FromLua<'lua> for Instance{ } } } + +pub struct DataModel{ + referent:Ref, +} +impl Referent for DataModel{ + fn referent(&self)->Ref{ + self.referent + } +} +impl DataModel{ + fn add_methods<'lua,T,M:mlua::UserDataMethods<'lua,T>>(methods:&mut M){ + methods.add_method("GetService",|lua,this,service:String| + dom(lua,|dom|{ + match service.as_str(){ + //"Lighting"=>Ok(Lighting::new()), + other=>Err::<(),_>(mlua::Error::runtime("Service '{other}' not supported")), + } + }) + ); + } +} +impl mlua::UserData for DataModel{ + fn add_fields<'lua,F:mlua::UserDataFields<'lua,Self>>(fields:&mut F){ + Instance::add_fields(fields); + //DataModel::add_fields(fields); + } + fn add_methods<'lua,M:mlua::UserDataMethods<'lua,Self>>(methods:&mut M){ + Instance::add_methods(methods); + DataModel::add_methods(methods); + } +} + +pub struct Lighting{ + referent:Ref, +} +impl Referent for Lighting{ + fn referent(&self)->Ref{ + self.referent + } +} +impl mlua::UserData for Lighting{ + fn add_fields<'lua,F:mlua::UserDataFields<'lua,Self>>(fields:&mut F){ + Instance::add_fields(fields); + } + fn add_methods<'lua,M:mlua::UserDataMethods<'lua,Self>>(methods:&mut M){ + Instance::add_methods(methods); + } +} From 4f65c3540764502b41585b40076cb7a915d61314 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sat, 21 Sep 2024 12:39:31 -0700 Subject: [PATCH 023/129] v0.2.0 change api to &mut self --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 76099f3..c55d86c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -318,7 +318,7 @@ dependencies = [ [[package]] name = "roblox_emulator" -version = "0.1.0" +version = "0.2.0" dependencies = [ "glam", "mlua", diff --git a/Cargo.toml b/Cargo.toml index 6854b70..7ae1f9e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "roblox_emulator" -version = "0.1.0" +version = "0.2.0" edition = "2021" repository = "https://git.itzana.me/StrafesNET/roblox_emulator" license = "MIT OR Apache-2.0" From b765f4cb219710bfa6bc56fcacec6932e292624f Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sat, 21 Sep 2024 12:53:03 -0700 Subject: [PATCH 024/129] why are these early returns in between app data --- src/runner/runner.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/runner/runner.rs b/src/runner/runner.rs index 8475486..62a7928 100644 --- a/src/runner/runner.rs +++ b/src/runner/runner.rs @@ -80,11 +80,10 @@ impl Runner{ Ok(runner) } pub fn run_script(&self,script:crate::script::Script,context:&mut Context)->Result<(),Error>{ - let yoink=script.name_source(context); + let (name,source)=script.name_source(context).map_err(Error::Script)?; + self.lua.globals().set("script",super::instance::Instance::from(script)).map_err(|error|Error::Lua{source:source.clone(),error})?; //this makes set_app_data shut up about the lifetime self.lua.set_app_data::<&'static mut rbx_dom_weak::WeakDom>(unsafe{core::mem::transmute(&mut context.dom)}); - let (name,source)=yoink.map_err(Error::Script)?; - self.lua.globals().set("script",super::instance::Instance::from(script)).map_err(|error|Error::Lua{source:source.clone(),error})?; let r=self.lua.load(source.as_str()) .set_name(name) .exec().map_err(|error|Error::Lua{source,error}); From 66d9279445fbb0015d824e01ed792c8c6e8aa169 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sat, 21 Sep 2024 13:26:20 -0700 Subject: [PATCH 025/129] macro-ify classes + bring script into instances --- src/context.rs | 4 +- src/lib.rs | 4 -- src/runner/instance.rs | 143 ++++++++++++++++++++++------------------- src/runner/mod.rs | 2 +- src/runner/runner.rs | 8 +-- src/script.rs | 37 ----------- 6 files changed, 85 insertions(+), 113 deletions(-) delete mode 100644 src/script.rs diff --git a/src/context.rs b/src/context.rs index 4ca6f66..6f8c8f0 100644 --- a/src/context.rs +++ b/src/context.rs @@ -28,7 +28,7 @@ impl Context{ class_is_a(instance.class.as_ref(),superclass) ).map(|instance|instance.referent()) } - pub fn scripts(&self)->Vec{ - self.superclass_iter("LuaSourceContainer").map(crate::script::Script::new).collect() + pub fn scripts(&self)->Vec{ + self.superclass_iter("LuaSourceContainer").map(crate::runner::instance::Script::new).collect() } } diff --git a/src/lib.rs b/src/lib.rs index 8c34547..f93d8c1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,5 @@ -pub mod script; pub mod context; - pub mod runner; -pub type Result=core::result::Result; - #[cfg(test)] mod tests; diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 45484d7..ac5aa6d 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -17,6 +17,17 @@ fn coerce_float32(value:&mlua::Value)->Option{ } } +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.as_str()); + pref=parent.parent(); + } + full_name +} + trait Referent{ fn referent(&self)->Ref; fn get<'a>(&self,dom:&'a WeakDom)->mlua::Result<&'a rbx_dom_weak::Instance>{ @@ -27,26 +38,54 @@ trait Referent{ } } -pub struct Instance{ - referent:Ref, +macro_rules! class{ + ($class:ident)=>{ + pub struct $class{ + referent:Ref, + } + impl $class{ + pub const fn new(referent:Ref)->Self{ + Self{referent} + } + } + impl Referent for $class{ + fn referent(&self)->Ref{ + self.referent + } + } + impl<'lua> mlua::FromLua<'lua> for $class{ + fn from_lua(value:mlua::Value<'lua>,_lua:&'lua mlua::Lua)->mlua::Result{ + match value{ + mlua::Value::UserData(ud)=>ud.take(), + other=>Err(mlua::Error::runtime(format!("Expected {} got {:?}",stringify!($class),other))), + } + } + } + }; } -impl Referent for Instance{ - fn referent(&self)->Ref{ - self.referent - } +macro_rules! class_composition{ + ($class:ident,($($superclass:ident),*))=>{ + impl mlua::UserData for $class{ + fn add_fields<'lua,F:mlua::UserDataFields<'lua,Self>>(fields:&mut F){ + $( + $superclass::composition_add_fields(fields); + )* + } + fn add_methods<'lua,M:mlua::UserDataMethods<'lua,Self>>(methods:&mut M){ + $( + $superclass::composition_add_methods(methods); + )* + } + } + }; } -impl From for Instance{ - fn from(value:crate::script::Script)->Self{ - Self{referent:value.script} - } -} + +class!(Instance); +class_composition!(Instance,(Instance)); impl Instance{ - pub const fn new(referent:Ref)->Self{ - Self{referent} - } - fn add_fields<'lua,T:Referent,F:mlua::UserDataFields<'lua,T>>(fields:&mut F){ + fn composition_add_fields<'lua,T:Referent,F:mlua::UserDataFields<'lua,T>>(fields:&mut F){ fields.add_field_method_get("Parent",|lua,this|{ dom(lua,|dom|{ let instance=this.get(dom)?; @@ -74,8 +113,7 @@ impl Instance{ }) }); } - - fn add_methods<'lua,T:Referent,M:mlua::UserDataMethods<'lua,T>>(methods:&mut M){ + fn composition_add_methods<'lua,T:Referent,M:mlua::UserDataMethods<'lua,T>>(methods:&mut M){ methods.add_method("GetChildren",|lua,this,_:()| dom(lua,|dom|{ let instance=this.get(dom)?; @@ -129,33 +167,13 @@ impl Instance{ ); } } -impl mlua::UserData for Instance{ - fn add_fields<'lua,F:mlua::UserDataFields<'lua,Self>>(fields:&mut F){ - Instance::add_fields(fields); - } - fn add_methods<'lua,M:mlua::UserDataMethods<'lua,Self>>(methods:&mut M){ - Instance::add_methods(methods); - } -} -impl<'lua> mlua::FromLua<'lua> for Instance{ - fn from_lua(value:mlua::prelude::LuaValue<'lua>,_lua:&'lua mlua::prelude::Lua)->mlua::prelude::LuaResult{ - match value{ - mlua::Value::UserData(ud)=>ud.take(), - other=>Err(mlua::Error::runtime(format!("Expected Instance got {:?}",other))), - } - } -} -pub struct DataModel{ - referent:Ref, -} -impl Referent for DataModel{ - fn referent(&self)->Ref{ - self.referent - } -} +class!(DataModel); +class_composition!(DataModel,(Instance,DataModel)); impl DataModel{ - fn add_methods<'lua,T,M:mlua::UserDataMethods<'lua,T>>(methods:&mut M){ + fn composition_add_fields<'lua,T:Referent,F:mlua::UserDataFields<'lua,T>>(fields:&mut F){ + } + fn composition_add_methods<'lua,T,M:mlua::UserDataMethods<'lua,T>>(methods:&mut M){ methods.add_method("GetService",|lua,this,service:String| dom(lua,|dom|{ match service.as_str(){ @@ -166,30 +184,25 @@ impl DataModel{ ); } } -impl mlua::UserData for DataModel{ - fn add_fields<'lua,F:mlua::UserDataFields<'lua,Self>>(fields:&mut F){ - Instance::add_fields(fields); - //DataModel::add_fields(fields); - } - fn add_methods<'lua,M:mlua::UserDataMethods<'lua,Self>>(methods:&mut M){ - Instance::add_methods(methods); - DataModel::add_methods(methods); - } + +class!(Lighting); +class_composition!(Lighting,(Instance)); + +#[derive(Debug)] +pub enum GetScriptError{ + NoScript, + NoSource, } -pub struct Lighting{ - referent:Ref, -} -impl Referent for Lighting{ - fn referent(&self)->Ref{ - self.referent - } -} -impl mlua::UserData for Lighting{ - fn add_fields<'lua,F:mlua::UserDataFields<'lua,Self>>(fields:&mut F){ - Instance::add_fields(fields); - } - fn add_methods<'lua,M:mlua::UserDataMethods<'lua,Self>>(methods:&mut M){ - Instance::add_methods(methods); +class!(Script); +class_composition!(Script,(Instance)); +impl Script{ + pub fn get_name_source(&self,context:&crate::context::Context)->Result<(String,String),GetScriptError>{ + let instance=context.dom.get_by_ref(self.referent).ok_or(GetScriptError::NoScript)?; + let source=match instance.properties.get("Source").ok_or(GetScriptError::NoSource)?{ + rbx_dom_weak::types::Variant::String(s)=>s.clone(), + _=>Err(GetScriptError::NoSource)?, + }; + Ok((get_full_name(&context.dom,instance),source)) } } diff --git a/src/runner/mod.rs b/src/runner/mod.rs index a00b1cf..f27d117 100644 --- a/src/runner/mod.rs +++ b/src/runner/mod.rs @@ -2,6 +2,6 @@ mod runner; mod cframe; mod vector3; -mod instance; +pub mod instance; pub use runner::Runner; diff --git a/src/runner/runner.rs b/src/runner/runner.rs index 62a7928..d10c4ab 100644 --- a/src/runner/runner.rs +++ b/src/runner/runner.rs @@ -12,7 +12,7 @@ pub enum Error{ source:String, error:mlua::Error }, - Script(crate::script::Error), + Script(super::instance::GetScriptError), /// If the lua.remove_app_data function fails RemoveAppData, } @@ -79,9 +79,9 @@ impl Runner{ init(&runner.lua)?; Ok(runner) } - pub fn run_script(&self,script:crate::script::Script,context:&mut Context)->Result<(),Error>{ - let (name,source)=script.name_source(context).map_err(Error::Script)?; - self.lua.globals().set("script",super::instance::Instance::from(script)).map_err(|error|Error::Lua{source:source.clone(),error})?; + pub fn run_script(&self,script:super::instance::Script,context:&mut Context)->Result<(),Error>{ + let (name,source)=script.get_name_source(context).map_err(Error::Script)?; + self.lua.globals().set("script",script).map_err(|error|Error::Lua{source:source.clone(),error})?; //this makes set_app_data shut up about the lifetime self.lua.set_app_data::<&'static mut rbx_dom_weak::WeakDom>(unsafe{core::mem::transmute(&mut context.dom)}); let r=self.lua.load(source.as_str()) diff --git a/src/script.rs b/src/script.rs deleted file mode 100644 index 8a81941..0000000 --- a/src/script.rs +++ /dev/null @@ -1,37 +0,0 @@ -use rbx_dom_weak::types::Ref; - -use crate::context::Context; - -#[derive(Debug)] -pub enum Error{ - NoScript, - NoSource, -} - -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.as_str()); - pref=parent.parent(); - } - full_name -} - -pub struct Script{ - pub(crate)script:Ref, -} -impl Script{ - pub const fn new(script:Ref)->Self{ - Self{script} - } - pub fn name_source(&self,context:&Context)->Result<(String,String),Error>{ - let instance=context.dom.get_by_ref(self.script).ok_or(Error::NoScript)?; - let source=match instance.properties.get("Source").ok_or(Error::NoSource)?{ - rbx_dom_weak::types::Variant::String(s)=>s.clone(), - _=>Err(Error::NoSource)?, - }; - Ok((get_full_name(&context.dom,instance),source)) - } -} From b0df1fb3bdbbf8c7226050289ea12693dfdb4e5c Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sat, 21 Sep 2024 14:21:23 -0700 Subject: [PATCH 026/129] clone once instead of twice --- src/runner/instance.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index ac5aa6d..d17d86e 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -104,11 +104,11 @@ impl Instance{ Ok(instance.name.clone()) }) }); - fields.add_field_method_set("Name",|lua,this,val:String|{ - dom(lua,move|dom|{ + fields.add_field_method_set("Name",|lua,this,val:mlua::String|{ + dom(lua,|dom|{ let instance=this.get_mut(dom)?; //Why does this need to be cloned? - instance.name=val.clone(); + instance.name=val.to_str()?.to_owned(); Ok(()) }) }); From 0ea85517814f45b68bace5437d98f22fa5723448 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sat, 21 Sep 2024 14:25:56 -0700 Subject: [PATCH 027/129] throw lua error rather than silently failing --- src/runner/instance.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index d17d86e..88eec38 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -160,7 +160,7 @@ impl Instance{ let typed_value:f32=coerce_float32(&value).ok_or(mlua::Error::runtime("Expected f32"))?; instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Float32(typed_value)); }, - other=>println!("Unimplemented property type: {other:?}"), + other=>return Err(mlua::Error::runtime(format!("Unimplemented property type: {other:?}"))), } Ok(()) }) From a1626b464e5257b490a782b88d8c8dbec311c57c Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sat, 21 Sep 2024 15:03:27 -0700 Subject: [PATCH 028/129] redo error stuff --- src/runner/runner.rs | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/runner/runner.rs b/src/runner/runner.rs index d10c4ab..74910ed 100644 --- a/src/runner/runner.rs +++ b/src/runner/runner.rs @@ -12,17 +12,15 @@ pub enum Error{ source:String, error:mlua::Error }, + RustLua(mlua::Error), Script(super::instance::GetScriptError), - /// If the lua.remove_app_data function fails - RemoveAppData, } -impl Error{ - pub fn print(self){ +impl std::fmt::Display for Error{ + fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{ match self{ - Self::Lua{source,error:mlua::Error::RuntimeError(s)}=>{ - println!("lua error: {s}\nsource:{source}"); - }, - other=>println!("{:?}",other), + Self::Lua{source,error:mlua::Error::RuntimeError(s)}=>write!(f,"lua error: {s}\nsource:{source}"), + Self::RustLua(mlua::Error::RuntimeError(s))=>write!(f,"rust-side lua error: {s}"), + other=>write!(f,"{other:?}"), } } } @@ -72,16 +70,16 @@ fn init(lua:&mlua::Lua)->mlua::Result<()>{ } impl Runner{ - pub fn new()->mlua::Result{ + pub fn new()->Result{ let runner=Self{ lua:mlua::Lua::new(), }; - init(&runner.lua)?; + init(&runner.lua).map_err(Error::RustLua)?; Ok(runner) } pub fn run_script(&self,script:super::instance::Script,context:&mut Context)->Result<(),Error>{ let (name,source)=script.get_name_source(context).map_err(Error::Script)?; - self.lua.globals().set("script",script).map_err(|error|Error::Lua{source:source.clone(),error})?; + self.lua.globals().set("script",script).map_err(Error::RustLua)?; //this makes set_app_data shut up about the lifetime self.lua.set_app_data::<&'static mut rbx_dom_weak::WeakDom>(unsafe{core::mem::transmute(&mut context.dom)}); let r=self.lua.load(source.as_str()) From 8aa5aa2c5adae26302ebd1fe5639b89a97e63c19 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sat, 21 Sep 2024 15:08:29 -0700 Subject: [PATCH 029/129] v0.2.1 slightly different errors --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c55d86c..681c27a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -318,7 +318,7 @@ dependencies = [ [[package]] name = "roblox_emulator" -version = "0.2.0" +version = "0.2.1" dependencies = [ "glam", "mlua", diff --git a/Cargo.toml b/Cargo.toml index 7ae1f9e..045c836 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "roblox_emulator" -version = "0.2.0" +version = "0.2.1" edition = "2021" repository = "https://git.itzana.me/StrafesNET/roblox_emulator" license = "MIT OR Apache-2.0" From 0e4ea2e722615cfd3b06cbbdb93cab22479f4ac6 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sat, 28 Sep 2024 12:31:27 -0700 Subject: [PATCH 030/129] expose runner Error --- src/runner/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runner/mod.rs b/src/runner/mod.rs index f27d117..f832a6a 100644 --- a/src/runner/mod.rs +++ b/src/runner/mod.rs @@ -4,4 +4,4 @@ mod cframe; mod vector3; pub mod instance; -pub use runner::Runner; +pub use runner::{Runner,Error}; From 7780e1a3f1532bf10b8d0371e6d6cd3b3866bd2a Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sat, 28 Sep 2024 12:31:41 -0700 Subject: [PATCH 031/129] Vector3 __div --- src/runner/vector3.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/runner/vector3.rs b/src/runner/vector3.rs index 36aee3e..2e1942d 100644 --- a/src/runner/vector3.rs +++ b/src/runner/vector3.rs @@ -37,6 +37,17 @@ impl mlua::UserData for Vector3{ //methods.add_method("area",|_,this,()| Ok(this.length * this.width)); methods.add_meta_function(mlua::MetaMethod::Add,|_,(this,val):(Self,Self)|Ok(Self(this.0+val.0))); + methods.add_meta_function(mlua::MetaMethod::Div,|_,(this,val):(Self,mlua::Value)|{ + match val{ + mlua::Value::Integer(n)=>Ok(Self(this.0/(n as f32))), + mlua::Value::Number(n)=>Ok(Self(this.0/(n as f32))), + mlua::Value::UserData(ud)=>{ + let rhs:Vector3=ud.take()?; + Ok(Self(this.0/rhs.0)) + }, + other=>Err(mlua::Error::runtime(format!("Attempt to divide Vector3 by {other:?}"))), + } + }); methods.add_meta_function(mlua::MetaMethod::ToString,|_,this:Self| Ok(format!("Vector3.new({},{},{})", this.0.x, From 72874d450fb834536e1cac8f50545d5170bf3fa3 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sat, 28 Sep 2024 12:31:52 -0700 Subject: [PATCH 032/129] CFrame :components() --- src/runner/cframe.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/runner/cframe.rs b/src/runner/cframe.rs index 8536204..d3c0890 100644 --- a/src/runner/cframe.rs +++ b/src/runner/cframe.rs @@ -19,7 +19,20 @@ impl mlua::UserData for CFrame{ } fn add_methods<'lua,M:mlua::UserDataMethods<'lua,Self>>(methods:&mut M){ - //methods.add_method("area",|_,this,()|Ok(this.length*this.width)); + methods.add_method("components",|_,this,()|Ok(( + this.0.translation.x, + this.0.translation.y, + this.0.translation.z, + this.0.matrix3.x_axis.x, + this.0.matrix3.y_axis.x, + this.0.matrix3.z_axis.x, + this.0.matrix3.x_axis.y, + this.0.matrix3.y_axis.y, + this.0.matrix3.z_axis.y, + this.0.matrix3.x_axis.z, + this.0.matrix3.y_axis.z, + this.0.matrix3.z_axis.z, + ))); //methods.add_meta_method(mlua::MetaMethod::Mul,|_,this,val:&Vector3|Ok(Vector3(this.0.matrix3*val.0+this.0.translation))); methods.add_meta_function(mlua::MetaMethod::Mul,|_,(this,val):(Self,Self)|Ok(Self(this.0*val.0))); From 4a939e74d1656cc183abf81d45cf23036dce3ec8 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sat, 28 Sep 2024 12:32:19 -0700 Subject: [PATCH 033/129] Context::script_singleton constructor for running a single script from cli --- src/context.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/context.rs b/src/context.rs index 6f8c8f0..1d9017b 100644 --- a/src/context.rs +++ b/src/context.rs @@ -19,6 +19,14 @@ impl Context{ pub const fn new(dom:WeakDom)->Context{ Context{dom} } + pub fn script_singleton(source:String)->(Context,crate::runner::instance::Script){ + let dom=WeakDom::new( + rbx_dom_weak::InstanceBuilder::new("Script") + .with_property("Source",rbx_types::Variant::String(source)) + ); + let script=crate::runner::instance::Script::new(dom.root_ref()); + (Context{dom},script) + } pub fn from_mut(dom:&mut WeakDom)->&mut Context{ unsafe{&mut *(dom as *mut WeakDom as *mut Context)} } From 6a3f0ca9aa426cd77c7a9f53473ae9597d626a90 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sat, 28 Sep 2024 12:34:02 -0700 Subject: [PATCH 034/129] v0.2.2 run single script from cli --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 681c27a..e4b19c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -318,7 +318,7 @@ dependencies = [ [[package]] name = "roblox_emulator" -version = "0.2.1" +version = "0.2.2" dependencies = [ "glam", "mlua", diff --git a/Cargo.toml b/Cargo.toml index 045c836..c50d9bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "roblox_emulator" -version = "0.2.1" +version = "0.2.2" edition = "2021" repository = "https://git.itzana.me/StrafesNET/roblox_emulator" license = "MIT OR Apache-2.0" From 9d56773343dcb94ed3721976f88b21785418ab26 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Tue, 1 Oct 2024 16:42:33 -0700 Subject: [PATCH 035/129] update deps --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e4b19c7..a1cff33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -95,9 +95,9 @@ dependencies = [ [[package]] name = "glam" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "779ae4bf7e8421cf91c0b3b64e7e8b40b862fba4d393f59150042de7c4965a94" +checksum = "c28091a37a5d09b555cb6628fd954da299b536433834f5b8e59eba78e0cbbf8a" [[package]] name = "lazy_static" diff --git a/Cargo.toml b/Cargo.toml index c50d9bf..25f9965 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ description = "Run embedded Luau scripts which manipulate the DOM." authors = ["Rhys Lloyd "] [dependencies] -glam = "0.28.0" +glam = "0.29.0" mlua = { version = "0.9.9", features = ["luau"] } rbx_dom_weak = { version = "2.7.0", registry = "strafesnet" } rbx_reflection = { version = "4.7.0", registry = "strafesnet" } From 3bb496f87b287909f2e5e0a4310d366eacb680a3 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Tue, 1 Oct 2024 16:42:53 -0700 Subject: [PATCH 036/129] v0.2.3 update deps --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a1cff33..3edd97e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -318,7 +318,7 @@ dependencies = [ [[package]] name = "roblox_emulator" -version = "0.2.2" +version = "0.2.3" dependencies = [ "glam", "mlua", diff --git a/Cargo.toml b/Cargo.toml index 25f9965..be22d01 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "roblox_emulator" -version = "0.2.2" +version = "0.2.3" edition = "2021" repository = "https://git.itzana.me/StrafesNET/roblox_emulator" license = "MIT OR Apache-2.0" From a4e2137463b09741c6d364b7f5937c5a1d602683 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Thu, 3 Oct 2024 16:26:23 -0700 Subject: [PATCH 037/129] move globals init into their respective files --- src/runner/cframe.rs | 22 ++++++++++++++++++++++ src/runner/runner.rs | 39 ++------------------------------------- src/runner/vector3.rs | 15 +++++++++++++++ 3 files changed, 39 insertions(+), 37 deletions(-) diff --git a/src/runner/cframe.rs b/src/runner/cframe.rs index d3c0890..3c66cef 100644 --- a/src/runner/cframe.rs +++ b/src/runner/cframe.rs @@ -12,6 +12,28 @@ impl CFrame{ } } +pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table<'_>)->Result<(),mlua::Error>{ + let cframe_table=lua.create_table()?; + + //CFrame.new + cframe_table.raw_set("new", + lua.create_function(|ctx,(x,y,z):(f32,f32,f32)| + Ok(ctx.create_userdata(CFrame::new(x,y,z))) + )? + )?; + + //CFrame.Angles + cframe_table.raw_set("Angles", + lua.create_function(|ctx,(x,y,z):(f32,f32,f32)| + Ok(ctx.create_userdata(CFrame::angles(x,y,z))) + )? + )?; + + globals.set("CFrame",cframe_table)?; + + Ok(()) +} + impl mlua::UserData for CFrame{ fn add_fields<'lua,F:mlua::UserDataFields<'lua,Self>>(fields:&mut F){ //CFrame.p diff --git a/src/runner/runner.rs b/src/runner/runner.rs index 74910ed..aaa4547 100644 --- a/src/runner/runner.rs +++ b/src/runner/runner.rs @@ -1,8 +1,5 @@ use crate::context::Context; -use super::vector3::Vector3; -use super::cframe::CFrame; - pub struct Runner{ lua:mlua::Lua, } @@ -31,40 +28,8 @@ fn init(lua:&mlua::Lua)->mlua::Result<()>{ //global environment let globals=lua.globals(); - //Vector3 - { - let vector3_table=lua.create_table()?; - - //Vector3.new - vector3_table.raw_set("new", - lua.create_function(|ctx,(x,y,z):(f32,f32,f32)| - Ok(ctx.create_userdata(Vector3::new(x,y,z))) - )? - )?; - - globals.set("Vector3",vector3_table)?; - } - - //CFrame - { - let cframe_table=lua.create_table()?; - - //CFrame.new - cframe_table.raw_set("new", - lua.create_function(|ctx,(x,y,z):(f32,f32,f32)| - Ok(ctx.create_userdata(CFrame::new(x,y,z))) - )? - )?; - - //CFrame.Angles - cframe_table.raw_set("Angles", - lua.create_function(|ctx,(x,y,z):(f32,f32,f32)| - Ok(ctx.create_userdata(CFrame::angles(x,y,z))) - )? - )?; - - globals.set("CFrame",cframe_table)?; - } + super::vector3::set_globals(lua,&globals)?; + super::cframe::set_globals(lua,&globals)?; Ok(()) } diff --git a/src/runner/vector3.rs b/src/runner/vector3.rs index 2e1942d..78244e5 100644 --- a/src/runner/vector3.rs +++ b/src/runner/vector3.rs @@ -7,6 +7,21 @@ impl Vector3{ } } +pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table<'_>)->Result<(),mlua::Error>{ + let vector3_table=lua.create_table()?; + + //Vector3.new + vector3_table.raw_set("new", + lua.create_function(|ctx,(x,y,z):(f32,f32,f32)| + Ok(ctx.create_userdata(Vector3::new(x,y,z))) + )? + )?; + + globals.set("Vector3",vector3_table)?; + + Ok(()) +} + impl Into for Vector3{ fn into(self)->rbx_types::Vector3{ rbx_types::Vector3::new(self.0.x,self.0.y,self.0.z) From 6b66009c44685faeab2b24e72c82ebcd518b05f5 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Thu, 3 Oct 2024 16:26:54 -0700 Subject: [PATCH 038/129] self --- src/context.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/context.rs b/src/context.rs index 1d9017b..91f3a69 100644 --- a/src/context.rs +++ b/src/context.rs @@ -16,8 +16,8 @@ pub struct Context{ } impl Context{ - pub const fn new(dom:WeakDom)->Context{ - Context{dom} + pub const fn new(dom:WeakDom)->Self{ + Self{dom} } pub fn script_singleton(source:String)->(Context,crate::runner::instance::Script){ let dom=WeakDom::new( From f5e9287798fa0015d139e74138b8d117a9a4095a Mon Sep 17 00:00:00 2001 From: Quaternions Date: Thu, 3 Oct 2024 17:20:31 -0700 Subject: [PATCH 039/129] weave the thread of fate lifetime annotations hold &mut Context while scripts are runnable --- src/runner/runner.rs | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/src/runner/runner.rs b/src/runner/runner.rs index aaa4547..2d44869 100644 --- a/src/runner/runner.rs +++ b/src/runner/runner.rs @@ -11,6 +11,7 @@ pub enum Error{ }, RustLua(mlua::Error), Script(super::instance::GetScriptError), + NoContext, } impl std::fmt::Display for Error{ fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{ @@ -42,16 +43,37 @@ impl Runner{ init(&runner.lua).map_err(Error::RustLua)?; Ok(runner) } - pub fn run_script(&self,script:super::instance::Script,context:&mut Context)->Result<(),Error>{ - let (name,source)=script.get_name_source(context).map_err(Error::Script)?; - self.lua.globals().set("script",script).map_err(Error::RustLua)?; + pub fn runnable_context<'a>(self,context:&'a mut Context,services:crate::place::Services)->Result,Error>{ //this makes set_app_data shut up about the lifetime self.lua.set_app_data::<&'static mut rbx_dom_weak::WeakDom>(unsafe{core::mem::transmute(&mut context.dom)}); - let r=self.lua.load(source.as_str()) - .set_name(name) - .exec().map_err(|error|Error::Lua{source,error}); - self.lua.remove_app_data::<&'static mut rbx_dom_weak::WeakDom>(); - r?; - Ok(()) + Ok(Runnable{ + lua:self.lua, + _lifetime:&std::marker::PhantomData + }) + } +} + +//Runnable is the same thing but has context set, which it holds the lifetime for. +pub struct Runnable<'a>{ + lua:mlua::Lua, + _lifetime:&'a std::marker::PhantomData<()> +} +impl Runnable<'_>{ + pub fn drop_context(self)->Runner{ + self.lua.remove_app_data::<&'static mut rbx_dom_weak::WeakDom>(); + Runner{ + lua:self.lua, + } + } + pub fn run_script(&self,script:super::instance::Script)->Result<(),Error>{ + let (name,source)={ + let dom=&mut *self.lua.app_data_mut::<&'static mut rbx_dom_weak::WeakDom>().ok_or(Error::NoContext)?; + let (name,source)=script.get_name_source(Context::from_mut(dom)).map_err(Error::Script)?; + self.lua.globals().set("script",script).map_err(Error::RustLua)?; + (name,source) + }; + self.lua.load(source.as_str()) + .set_name(name) + .exec().map_err(|error|Error::Lua{source,error}) } } From fb38f1076dcf0ff641e0c91622f8092bbeb925ad Mon Sep 17 00:00:00 2001 From: Quaternions Date: Thu, 3 Oct 2024 17:19:47 -0700 Subject: [PATCH 040/129] place with services --- src/context.rs | 18 +++++++++++------- src/lib.rs | 3 ++- src/place.rs | 37 +++++++++++++++++++++++++++++++++++++ src/runner/instance.rs | 3 +++ src/runner/runner.rs | 5 +++++ 5 files changed, 58 insertions(+), 8 deletions(-) create mode 100644 src/place.rs diff --git a/src/context.rs b/src/context.rs index 91f3a69..9e0b05c 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,4 +1,4 @@ -use rbx_dom_weak::{types::Ref,WeakDom}; +use rbx_dom_weak::{types::Ref,InstanceBuilder,WeakDom}; pub fn class_is_a(class:&str,superclass:&str)->bool{ class==superclass @@ -19,13 +19,17 @@ impl Context{ pub const fn new(dom:WeakDom)->Self{ Self{dom} } - pub fn script_singleton(source:String)->(Context,crate::runner::instance::Script){ - let dom=WeakDom::new( - rbx_dom_weak::InstanceBuilder::new("Script") - .with_property("Source",rbx_types::Variant::String(source)) + pub fn script_singleton(source:String)->(Context,crate::runner::instance::Script,crate::place::Services){ + let script=InstanceBuilder::new("Script") + .with_property("Source",rbx_types::Variant::String(source)); + let script_ref=script.referent(); + let (dom,services)=crate::place::new_place_with_instances_in_workspace( + WeakDom::new( + InstanceBuilder::new("DataModel") + .with_child(script) + ) ); - let script=crate::runner::instance::Script::new(dom.root_ref()); - (Context{dom},script) + (Context{dom},crate::runner::instance::Script::new(script_ref),services) } pub fn from_mut(dom:&mut WeakDom)->&mut Context{ unsafe{&mut *(dom as *mut WeakDom as *mut Context)} diff --git a/src/lib.rs b/src/lib.rs index f93d8c1..70c62b9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ -pub mod context; +pub mod place; pub mod runner; +pub mod context; #[cfg(test)] mod tests; diff --git a/src/place.rs b/src/place.rs new file mode 100644 index 0000000..1fa0979 --- /dev/null +++ b/src/place.rs @@ -0,0 +1,37 @@ +use rbx_dom_weak::{InstanceBuilder,WeakDom}; +use rbx_types::Ref; + +pub struct Services{ + pub game:Ref, + pub workspace:Ref, +} + +pub fn new_place_with_instances_in_workspace(mut instance_dom:WeakDom)->(WeakDom,Services){ + //workspace + let workspace_bldr=InstanceBuilder::new("Workspace") + .with_child(InstanceBuilder::new("Terrain")); + let workspace=workspace_bldr.referent(); + + //game + let game_bldr= + InstanceBuilder::new("DataModel") + .with_child(workspace_bldr) + .with_child(InstanceBuilder::new("Lighting")); + let game=game_bldr.referent(); + + let mut dom=WeakDom::new(game_bldr); + + //put instances in workspace + let children=instance_dom.root().children().to_owned(); + for instance in children{ + instance_dom.transfer(instance,&mut dom,workspace); + } + + ( + dom, + Services{ + game, + workspace + } + ) +} diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 88eec38..6face0b 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -185,6 +185,9 @@ impl DataModel{ } } +class!(Workspace); +class_composition!(Workspace,(Instance)); + class!(Lighting); class_composition!(Lighting,(Instance)); diff --git a/src/runner/runner.rs b/src/runner/runner.rs index 2d44869..df3c237 100644 --- a/src/runner/runner.rs +++ b/src/runner/runner.rs @@ -44,6 +44,11 @@ impl Runner{ Ok(runner) } pub fn runnable_context<'a>(self,context:&'a mut Context,services:crate::place::Services)->Result,Error>{ + { + let globals=self.lua.globals(); + globals.set("game",super::instance::DataModel::new(services.game)).map_err(Error::RustLua)?; + globals.set("workspace",super::instance::Workspace::new(services.workspace)).map_err(Error::RustLua)?; + } //this makes set_app_data shut up about the lifetime self.lua.set_app_data::<&'static mut rbx_dom_weak::WeakDom>(unsafe{core::mem::transmute(&mut context.dom)}); Ok(Runnable{ From c06ba656624727c190cd562ec7dc5ad3e8ff1aaf Mon Sep 17 00:00:00 2001 From: Quaternions Date: Thu, 3 Oct 2024 18:05:39 -0700 Subject: [PATCH 041/129] Color3 --- src/runner/color3.rs | 50 ++++++++++++++++++++++++++++++++++++++++++ src/runner/instance.rs | 4 ++++ src/runner/mod.rs | 1 + src/runner/runner.rs | 1 + 4 files changed, 56 insertions(+) create mode 100644 src/runner/color3.rs diff --git a/src/runner/color3.rs b/src/runner/color3.rs new file mode 100644 index 0000000..f6a162d --- /dev/null +++ b/src/runner/color3.rs @@ -0,0 +1,50 @@ +#[derive(Clone,Copy)] +pub struct Color3{ + r:f32, + g:f32, + b:f32, +} +impl Color3{ + pub const fn new(r:f32,g:f32,b:f32)->Self{ + Self{r,g,b} + } +} +impl Into for Color3{ + fn into(self)->rbx_types::Color3{ + rbx_types::Color3::new(self.r,self.g,self.b) + } +} + +pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table<'_>)->Result<(),mlua::Error>{ + let color3_table=lua.create_table()?; + + color3_table.raw_set("new", + lua.create_function(|ctx,(r,g,b):(f32,f32,f32)| + Ok(ctx.create_userdata(Color3::new(r,g,b))) + )? + )?; + color3_table.raw_set("fromRGB", + lua.create_function(|ctx,(r,g,b):(u8,u8,u8)| + Ok(ctx.create_userdata(Color3::new(r as f32/255.0,g as f32/255.0,b as f32/255.0))) + )? + )?; + + globals.set("Color3",color3_table)?; + + Ok(()) +} + +impl mlua::UserData for Color3{ + fn add_fields<'lua,F:mlua::UserDataFields<'lua,Self>>(fields:&mut F){ + } + fn add_methods<'lua,M:mlua::UserDataMethods<'lua,Self>>(methods:&mut M){ + } +} +impl<'lua> mlua::FromLua<'lua> for Color3{ + fn from_lua(value:mlua::prelude::LuaValue<'lua>,_lua:&'lua mlua::prelude::Lua)->mlua::prelude::LuaResult{ + match value{ + mlua::Value::UserData(ud)=>ud.take()?, + other=>Err(mlua::Error::runtime(format!("Expected Color3 got {:?}",other))), + } + } +} diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 6face0b..b26e42d 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -160,6 +160,10 @@ impl Instance{ let typed_value:f32=coerce_float32(&value).ok_or(mlua::Error::runtime("Expected f32"))?; instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Float32(typed_value)); }, + rbx_types::Variant::Color3(_)=>{ + let typed_value:super::color3::Color3=value.as_userdata().ok_or(mlua::Error::runtime("Expected Userdata"))?.take()?; + instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Color3(typed_value.into())); + }, other=>return Err(mlua::Error::runtime(format!("Unimplemented property type: {other:?}"))), } Ok(()) diff --git a/src/runner/mod.rs b/src/runner/mod.rs index f832a6a..0b364fd 100644 --- a/src/runner/mod.rs +++ b/src/runner/mod.rs @@ -1,5 +1,6 @@ mod runner; +mod color3; mod cframe; mod vector3; pub mod instance; diff --git a/src/runner/runner.rs b/src/runner/runner.rs index df3c237..658da3f 100644 --- a/src/runner/runner.rs +++ b/src/runner/runner.rs @@ -29,6 +29,7 @@ fn init(lua:&mlua::Lua)->mlua::Result<()>{ //global environment let globals=lua.globals(); + super::color3::set_globals(lua,&globals)?; super::vector3::set_globals(lua,&globals)?; super::cframe::set_globals(lua,&globals)?; From 7403888348fa4d929f04d12b6b98aab7ddf66f21 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Thu, 3 Oct 2024 18:05:44 -0700 Subject: [PATCH 042/129] Enum --- src/runner/enum.rs | 86 ++++++++++++++++++++++++++++++++++++++++++ src/runner/instance.rs | 4 ++ src/runner/mod.rs | 1 + src/runner/runner.rs | 1 + 4 files changed, 92 insertions(+) create mode 100644 src/runner/enum.rs diff --git a/src/runner/enum.rs b/src/runner/enum.rs new file mode 100644 index 0000000..0fcda7a --- /dev/null +++ b/src/runner/enum.rs @@ -0,0 +1,86 @@ +use mlua::IntoLua; + +#[derive(Clone,Copy)] +pub struct Enum(u32); +pub struct EnumItems; +pub struct EnumItem{ + name:String +} + +impl Into for Enum{ + fn into(self)->rbx_types::Enum{ + rbx_types::Enum::from_u32(self.0) + } +} + +impl EnumItem{ + const fn new(name:String)->Self{ + Self{name} + } +} + +pub fn set_globals(_lua:&mlua::Lua,globals:&mlua::Table<'_>)->Result<(),mlua::Error>{ + globals.set("Enum",EnumItems) +} + +impl mlua::UserData for EnumItem{ + fn add_fields<'lua,F:mlua::UserDataFields<'lua,Self>>(_fields:&mut F){ + } + fn add_methods<'lua,M:mlua::UserDataMethods<'lua,Self>>(methods:&mut M){ + methods.add_meta_function(mlua::MetaMethod::Index,|lua,(this,val):(Self,String)|{ + let db=rbx_reflection_database::get(); + match db.enums.get(this.name.as_str()){ + Some(e)=>match e.items.get(val.as_str()){ + Some(&id)=>Enum(id).into_lua(lua), + None=>mlua::Value::Nil.into_lua(lua), + }, + None=>mlua::Value::Nil.into_lua(lua), + } + }); + } +} +impl<'lua> mlua::FromLua<'lua> for EnumItem{ + fn from_lua(value:mlua::prelude::LuaValue<'lua>,_lua:&'lua mlua::prelude::Lua)->mlua::prelude::LuaResult{ + match value{ + mlua::Value::UserData(ud)=>ud.take()?, + other=>Err(mlua::Error::runtime(format!("Expected Enum got {:?}",other))), + } + } +} + +impl mlua::UserData for EnumItems{ + fn add_fields<'lua,F:mlua::UserDataFields<'lua,Self>>(_fields:&mut F){ + } + fn add_methods<'lua,M:mlua::UserDataMethods<'lua,Self>>(methods:&mut M){ + methods.add_meta_function(mlua::MetaMethod::Index,|lua,(_,val):(Self,String)|{ + let db=rbx_reflection_database::get(); + match db.enums.get(val.as_str()){ + Some(_)=>EnumItem::new(val).into_lua(lua), + None=>mlua::Value::Nil.into_lua(lua), + } + }); + } +} +impl<'lua> mlua::FromLua<'lua> for EnumItems{ + fn from_lua(value:mlua::prelude::LuaValue<'lua>,_lua:&'lua mlua::prelude::Lua)->mlua::prelude::LuaResult{ + match value{ + mlua::Value::UserData(ud)=>ud.take()?, + other=>Err(mlua::Error::runtime(format!("Expected Enum got {:?}",other))), + } + } +} + +impl mlua::UserData for Enum{ + fn add_fields<'lua,F:mlua::UserDataFields<'lua,Self>>(_fields:&mut F){ + } + fn add_methods<'lua,M:mlua::UserDataMethods<'lua,Self>>(_methods:&mut M){ + } +} +impl<'lua> mlua::FromLua<'lua> for Enum{ + fn from_lua(value:mlua::prelude::LuaValue<'lua>,_lua:&'lua mlua::prelude::Lua)->mlua::prelude::LuaResult{ + match value{ + mlua::Value::UserData(ud)=>ud.take()?, + other=>Err(mlua::Error::runtime(format!("Expected Enum got {:?}",other))), + } + } +} diff --git a/src/runner/instance.rs b/src/runner/instance.rs index b26e42d..2464224 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -160,6 +160,10 @@ impl Instance{ let typed_value:f32=coerce_float32(&value).ok_or(mlua::Error::runtime("Expected f32"))?; instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Float32(typed_value)); }, + rbx_types::Variant::Enum(_)=>{ + let typed_value:super::r#enum::Enum=value.as_userdata().ok_or(mlua::Error::runtime("Expected Userdata"))?.take()?; + instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Enum(typed_value.into())); + }, rbx_types::Variant::Color3(_)=>{ let typed_value:super::color3::Color3=value.as_userdata().ok_or(mlua::Error::runtime("Expected Userdata"))?.take()?; instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Color3(typed_value.into())); diff --git a/src/runner/mod.rs b/src/runner/mod.rs index 0b364fd..abec22e 100644 --- a/src/runner/mod.rs +++ b/src/runner/mod.rs @@ -1,5 +1,6 @@ mod runner; +mod r#enum; mod color3; mod cframe; mod vector3; diff --git a/src/runner/runner.rs b/src/runner/runner.rs index 658da3f..130702a 100644 --- a/src/runner/runner.rs +++ b/src/runner/runner.rs @@ -29,6 +29,7 @@ fn init(lua:&mlua::Lua)->mlua::Result<()>{ //global environment let globals=lua.globals(); + super::r#enum::set_globals(lua,&globals)?; super::color3::set_globals(lua,&globals)?; super::vector3::set_globals(lua,&globals)?; super::cframe::set_globals(lua,&globals)?; From 748f544a4b94f85a417218fe057af5ab96b0b455 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Thu, 3 Oct 2024 18:03:42 -0700 Subject: [PATCH 043/129] ClassName --- src/runner/instance.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 2464224..720b7a3 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -112,6 +112,12 @@ impl Instance{ Ok(()) }) }); + fields.add_field_method_get("ClassName",|lua,this|{ + dom(lua,|dom|{ + let instance=this.get(dom)?; + Ok(instance.class.clone()) + }) + }); } fn composition_add_methods<'lua,T:Referent,M:mlua::UserDataMethods<'lua,T>>(methods:&mut M){ methods.add_method("GetChildren",|lua,this,_:()| From 6ec0d61b3def806fd27e1d09b154a9ea264ca9d9 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Thu, 3 Oct 2024 18:04:41 -0700 Subject: [PATCH 044/129] game:GetService("Lighting") + game.PlaceId --- src/runner/instance.rs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 720b7a3..b48db73 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -1,5 +1,6 @@ +use mlua::IntoLua; use rbx_types::Ref; -use rbx_dom_weak::WeakDom; +use rbx_dom_weak::{InstanceBuilder,WeakDom}; use super::vector3::Vector3; @@ -186,13 +187,27 @@ class!(DataModel); class_composition!(DataModel,(Instance,DataModel)); impl DataModel{ fn composition_add_fields<'lua,T:Referent,F:mlua::UserDataFields<'lua,T>>(fields:&mut F){ + fields.add_field_method_get("PlaceId",|lua,this|{ + Ok(mlua::Value::Integer(0)) + }); } fn composition_add_methods<'lua,T,M:mlua::UserDataMethods<'lua,T>>(methods:&mut M){ methods.add_method("GetService",|lua,this,service:String| dom(lua,|dom|{ match service.as_str(){ - //"Lighting"=>Ok(Lighting::new()), - other=>Err::<(),_>(mlua::Error::runtime("Service '{other}' not supported")), + "Lighting"=>{ + let referent=dom.root() + .children() + .iter() + .find(|&&c| + dom.get_by_ref(c).is_some_and(|c|c.class=="Lighting") + ).map(|r|*r) + .unwrap_or_else(|| + dom.insert(dom.root_ref(),InstanceBuilder::new("Lighting")) + ); + Lighting::new(referent).into_lua(lua) + }, + other=>Err::(mlua::Error::runtime(format!("Service '{other}' not supported"))), } }) ); From 9d219004f452e81ffab56b679cbeccd0bd032753 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Thu, 3 Oct 2024 18:04:52 -0700 Subject: [PATCH 045/129] Terrain --- src/runner/instance.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index b48db73..c81d874 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -238,3 +238,15 @@ impl Script{ Ok((get_full_name(&context.dom,instance),source)) } } + +class!(Terrain); +class_composition!(Terrain,(Instance,Terrain)); +impl Terrain{ + fn composition_add_fields<'lua,T:Referent,F:mlua::UserDataFields<'lua,T>>(fields:&mut F){ + } + fn composition_add_methods<'lua,T,M:mlua::UserDataMethods<'lua,T>>(methods:&mut M){ + methods.add_method("FillBlock",|lua,this,_:(super::cframe::CFrame,Vector3,super::r#enum::Enum)| + Ok(())//Ok(mlua::Value::Nil) + ) + } +} From 5a1df16bd9abe961fd75328b4fccd75201e92901 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Thu, 3 Oct 2024 18:53:17 -0700 Subject: [PATCH 046/129] from_lua macro --- src/runner/cframe.rs | 10 ++-------- src/runner/color3.rs | 9 +-------- src/runner/enum.rs | 27 +++------------------------ src/runner/instance.rs | 9 +-------- src/runner/macros.rs | 12 ++++++++++++ src/runner/mod.rs | 2 ++ src/runner/vector3.rs | 9 +-------- 7 files changed, 22 insertions(+), 56 deletions(-) create mode 100644 src/runner/macros.rs diff --git a/src/runner/cframe.rs b/src/runner/cframe.rs index 3c66cef..8942578 100644 --- a/src/runner/cframe.rs +++ b/src/runner/cframe.rs @@ -76,11 +76,5 @@ impl mlua::UserData for CFrame{ ); } } -impl<'lua> mlua::FromLua<'lua> for CFrame{ - fn from_lua(value:mlua::prelude::LuaValue<'lua>,_lua:&'lua mlua::prelude::Lua)->mlua::prelude::LuaResult{ - match value{ - mlua::Value::UserData(ud)=>ud.take()?, - other=>Err(mlua::Error::runtime(format!("Expected CFrame got {:?}",other))), - } - } -} + +type_from_lua_userdata!(CFrame); diff --git a/src/runner/color3.rs b/src/runner/color3.rs index f6a162d..71899e8 100644 --- a/src/runner/color3.rs +++ b/src/runner/color3.rs @@ -40,11 +40,4 @@ impl mlua::UserData for Color3{ fn add_methods<'lua,M:mlua::UserDataMethods<'lua,Self>>(methods:&mut M){ } } -impl<'lua> mlua::FromLua<'lua> for Color3{ - fn from_lua(value:mlua::prelude::LuaValue<'lua>,_lua:&'lua mlua::prelude::Lua)->mlua::prelude::LuaResult{ - match value{ - mlua::Value::UserData(ud)=>ud.take()?, - other=>Err(mlua::Error::runtime(format!("Expected Color3 got {:?}",other))), - } - } -} +type_from_lua_userdata!(Color3); diff --git a/src/runner/enum.rs b/src/runner/enum.rs index 0fcda7a..b508f7e 100644 --- a/src/runner/enum.rs +++ b/src/runner/enum.rs @@ -39,14 +39,7 @@ impl mlua::UserData for EnumItem{ }); } } -impl<'lua> mlua::FromLua<'lua> for EnumItem{ - fn from_lua(value:mlua::prelude::LuaValue<'lua>,_lua:&'lua mlua::prelude::Lua)->mlua::prelude::LuaResult{ - match value{ - mlua::Value::UserData(ud)=>ud.take()?, - other=>Err(mlua::Error::runtime(format!("Expected Enum got {:?}",other))), - } - } -} +type_from_lua_userdata!(EnumItem); impl mlua::UserData for EnumItems{ fn add_fields<'lua,F:mlua::UserDataFields<'lua,Self>>(_fields:&mut F){ @@ -61,14 +54,7 @@ impl mlua::UserData for EnumItems{ }); } } -impl<'lua> mlua::FromLua<'lua> for EnumItems{ - fn from_lua(value:mlua::prelude::LuaValue<'lua>,_lua:&'lua mlua::prelude::Lua)->mlua::prelude::LuaResult{ - match value{ - mlua::Value::UserData(ud)=>ud.take()?, - other=>Err(mlua::Error::runtime(format!("Expected Enum got {:?}",other))), - } - } -} +type_from_lua_userdata!(EnumItems); impl mlua::UserData for Enum{ fn add_fields<'lua,F:mlua::UserDataFields<'lua,Self>>(_fields:&mut F){ @@ -76,11 +62,4 @@ impl mlua::UserData for Enum{ fn add_methods<'lua,M:mlua::UserDataMethods<'lua,Self>>(_methods:&mut M){ } } -impl<'lua> mlua::FromLua<'lua> for Enum{ - fn from_lua(value:mlua::prelude::LuaValue<'lua>,_lua:&'lua mlua::prelude::Lua)->mlua::prelude::LuaResult{ - match value{ - mlua::Value::UserData(ud)=>ud.take()?, - other=>Err(mlua::Error::runtime(format!("Expected Enum got {:?}",other))), - } - } -} +type_from_lua_userdata!(Enum); diff --git a/src/runner/instance.rs b/src/runner/instance.rs index c81d874..666a8db 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -54,14 +54,7 @@ macro_rules! class{ self.referent } } - impl<'lua> mlua::FromLua<'lua> for $class{ - fn from_lua(value:mlua::Value<'lua>,_lua:&'lua mlua::Lua)->mlua::Result{ - match value{ - mlua::Value::UserData(ud)=>ud.take(), - other=>Err(mlua::Error::runtime(format!("Expected {} got {:?}",stringify!($class),other))), - } - } - } + type_from_lua_userdata!($class); }; } macro_rules! class_composition{ diff --git a/src/runner/macros.rs b/src/runner/macros.rs new file mode 100644 index 0000000..b935225 --- /dev/null +++ b/src/runner/macros.rs @@ -0,0 +1,12 @@ +macro_rules! type_from_lua_userdata{ + ($asd:ident)=>{ + impl<'lua> mlua::FromLua<'lua> for $asd{ + fn from_lua(value:mlua::Value<'lua>,_lua:&'lua mlua::Lua)->Result{ + match value{ + mlua::Value::UserData(ud)=>ud.take(), + other=>Err(mlua::Error::runtime(format!("Expected {} got {:?}",stringify!($asd),other))), + } + } + } + }; +} diff --git a/src/runner/mod.rs b/src/runner/mod.rs index abec22e..de4859f 100644 --- a/src/runner/mod.rs +++ b/src/runner/mod.rs @@ -1,3 +1,5 @@ +#[macro_use] +mod macros; mod runner; mod r#enum; diff --git a/src/runner/vector3.rs b/src/runner/vector3.rs index 78244e5..bff57a6 100644 --- a/src/runner/vector3.rs +++ b/src/runner/vector3.rs @@ -73,11 +73,4 @@ impl mlua::UserData for Vector3{ } } -impl<'lua> mlua::FromLua<'lua> for Vector3{ - fn from_lua(value:mlua::prelude::LuaValue<'lua>,_lua:&'lua mlua::prelude::Lua)->mlua::prelude::LuaResult{ - match value{ - mlua::Value::UserData(ud)=>ud.take(), - other=>Err(mlua::Error::runtime(format!("Expected Vector3 got {:?}",other))), - } - } -} +type_from_lua_userdata!(Vector3); From 6c12bc2bf6cb19a99bc594c0f3d8fc1373a5768f Mon Sep 17 00:00:00 2001 From: Quaternions Date: Thu, 3 Oct 2024 18:54:37 -0700 Subject: [PATCH 047/129] print errors better --- src/runner/runner.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runner/runner.rs b/src/runner/runner.rs index 130702a..3bc3dfc 100644 --- a/src/runner/runner.rs +++ b/src/runner/runner.rs @@ -16,8 +16,8 @@ pub enum Error{ impl std::fmt::Display for Error{ fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{ match self{ - Self::Lua{source,error:mlua::Error::RuntimeError(s)}=>write!(f,"lua error: {s}\nsource:{source}"), - Self::RustLua(mlua::Error::RuntimeError(s))=>write!(f,"rust-side lua error: {s}"), + Self::Lua{source,error}=>write!(f,"lua error: source:\n{source}\n{error}"), + Self::RustLua(error)=>write!(f,"rust-side lua error: {error}"), other=>write!(f,"{other:?}"), } } From 40655cdf449259999468d83923b290470ed8ff17 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Thu, 3 Oct 2024 18:55:50 -0700 Subject: [PATCH 048/129] get referent from any class --- src/runner/instance.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 666a8db..0dad951 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -29,6 +29,11 @@ fn get_full_name(dom:&rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance)->S full_name } +//workaround until I have an enum of classes +struct Dereferent(Ref); +impl mlua::UserData for Dereferent{} +type_from_lua_userdata!(Dereferent); + trait Referent{ fn referent(&self)->Ref; fn get<'a>(&self,dom:&'a WeakDom)->mlua::Result<&'a rbx_dom_weak::Instance>{ @@ -61,6 +66,9 @@ macro_rules! class_composition{ ($class:ident,($($superclass:ident),*))=>{ impl mlua::UserData for $class{ fn add_fields<'lua,F:mlua::UserDataFields<'lua,Self>>(fields:&mut F){ + fields.add_field_method_get("Referent",|_,this|{ + Ok(Dereferent(this.referent())) + }); $( $superclass::composition_add_fields(fields); )* @@ -86,9 +94,10 @@ impl Instance{ Ok(Instance::new(instance.parent())) }) }); - fields.add_field_method_set("Parent",|lua,this,val:Self|{ + fields.add_field_method_set("Parent",|lua,this,val:mlua::AnyUserData|{ + let Dereferent(referent)=mlua::AnyUserDataExt::get(&val,"Referent")?; dom(lua,|dom|{ - dom.transfer_within(this.referent(),val.referent); + dom.transfer_within(this.referent(),referent); Ok(()) }) }); From e67f0f08892da1e543a15a4843ec7ea5266a7f8a Mon Sep 17 00:00:00 2001 From: Quaternions Date: Thu, 3 Oct 2024 19:09:02 -0700 Subject: [PATCH 049/129] implement Instance.__index --- src/runner/instance.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 0dad951..ffb950c 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -152,6 +152,23 @@ impl Instance{ Ok(crate::context::class_is_a(instance.class.as_str(),classname.to_str()?)) }) ); + methods.add_meta_function(mlua::MetaMethod::Index,|lua,(this,index):(Self,mlua::String)|{ + let index_str=index.to_str()?; + dom(lua,|dom|{ + let instance=this.get(dom)?; + //find a child with a matching name + let maybe_child=instance.children() + .iter() + .find(|&&r| + dom.get_by_ref(r) + .is_some_and(|instance|instance.name==index_str) + ); + match maybe_child{ + Some(&referent)=>Instance::new(referent).into_lua(lua), + None=>mlua::Value::Nil.into_lua(lua), + } + }) + }); methods.add_meta_function(mlua::MetaMethod::NewIndex,|lua,(this,index,value):(Self,mlua::String,mlua::Value)| dom(lua,|dom|{ //println!("__newindex t={this:?} i={index:?} v={value:?}"); From d272ac242bf996a920c7921fd6806de99fe6150d Mon Sep 17 00:00:00 2001 From: Quaternions Date: Thu, 3 Oct 2024 19:14:58 -0700 Subject: [PATCH 050/129] sneak past type issues --- src/runner/instance.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index ffb950c..cef224f 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -33,6 +33,11 @@ fn get_full_name(dom:&rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance)->S struct Dereferent(Ref); impl mlua::UserData for Dereferent{} type_from_lua_userdata!(Dereferent); +impl Referent for Dereferent{ + fn referent(&self)->Ref{ + self.0 + } +} trait Referent{ fn referent(&self)->Ref; @@ -152,10 +157,11 @@ impl Instance{ Ok(crate::context::class_is_a(instance.class.as_str(),classname.to_str()?)) }) ); - methods.add_meta_function(mlua::MetaMethod::Index,|lua,(this,index):(Self,mlua::String)|{ + methods.add_meta_function(mlua::MetaMethod::Index,|lua,(this,index):(mlua::AnyUserData,mlua::String)|{ let index_str=index.to_str()?; + let dereferent:Dereferent=mlua::AnyUserDataExt::get(&this,"Referent")?; dom(lua,|dom|{ - let instance=this.get(dom)?; + let instance=dereferent.get(dom)?; //find a child with a matching name let maybe_child=instance.children() .iter() @@ -169,10 +175,11 @@ impl Instance{ } }) }); - methods.add_meta_function(mlua::MetaMethod::NewIndex,|lua,(this,index,value):(Self,mlua::String,mlua::Value)| + methods.add_meta_function(mlua::MetaMethod::NewIndex,|lua,(this,index,value):(mlua::AnyUserData,mlua::String,mlua::Value)|{ + let dereferent:Dereferent=mlua::AnyUserDataExt::get(&this,"Referent")?; dom(lua,|dom|{ - //println!("__newindex t={this:?} i={index:?} v={value:?}"); - let instance=this.get_mut(dom)?; + let instance=dereferent.get_mut(dom)?; + //println!("__newindex t={} i={index:?} v={value:?}",instance.name); let index_str=index.to_str()?; let db=rbx_reflection_database::get(); let class=db.classes.get(instance.class.as_str()).ok_or(mlua::Error::runtime("Class missing"))?; @@ -198,7 +205,7 @@ impl Instance{ } Ok(()) }) - ); + }); } } From 00a5d71b2bb4d9f813b5db80403e055b3e052a05 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Thu, 3 Oct 2024 19:30:17 -0700 Subject: [PATCH 051/129] v0.3.0 thread of fate --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3edd97e..dc3fe6e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -318,7 +318,7 @@ dependencies = [ [[package]] name = "roblox_emulator" -version = "0.2.3" +version = "0.3.0" dependencies = [ "glam", "mlua", diff --git a/Cargo.toml b/Cargo.toml index be22d01..24080bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "roblox_emulator" -version = "0.2.3" +version = "0.3.0" edition = "2021" repository = "https://git.itzana.me/StrafesNET/roblox_emulator" license = "MIT OR Apache-2.0" From c12ad7df0f6d9dbd0c15ebac90a2b09a9169bc9f Mon Sep 17 00:00:00 2001 From: Quaternions Date: Thu, 3 Oct 2024 20:23:23 -0700 Subject: [PATCH 052/129] v0.3.1 services reference --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/runner/runner.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dc3fe6e..5d35bcd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -318,7 +318,7 @@ dependencies = [ [[package]] name = "roblox_emulator" -version = "0.3.0" +version = "0.3.1" dependencies = [ "glam", "mlua", diff --git a/Cargo.toml b/Cargo.toml index 24080bb..6345b70 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "roblox_emulator" -version = "0.3.0" +version = "0.3.1" edition = "2021" repository = "https://git.itzana.me/StrafesNET/roblox_emulator" license = "MIT OR Apache-2.0" diff --git a/src/runner/runner.rs b/src/runner/runner.rs index 3bc3dfc..e952dc9 100644 --- a/src/runner/runner.rs +++ b/src/runner/runner.rs @@ -45,7 +45,7 @@ impl Runner{ init(&runner.lua).map_err(Error::RustLua)?; Ok(runner) } - pub fn runnable_context<'a>(self,context:&'a mut Context,services:crate::place::Services)->Result,Error>{ + pub fn runnable_context<'a>(self,context:&'a mut Context,services:&crate::place::Services)->Result,Error>{ { let globals=self.lua.globals(); globals.set("game",super::instance::DataModel::new(services.game)).map_err(Error::RustLua)?; From 317400548d756c5ffe1fb676c3045d4817ac0b45 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Thu, 3 Oct 2024 21:22:43 -0700 Subject: [PATCH 053/129] error trait --- src/runner/runner.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/runner/runner.rs b/src/runner/runner.rs index e952dc9..bf5def1 100644 --- a/src/runner/runner.rs +++ b/src/runner/runner.rs @@ -22,6 +22,7 @@ impl std::fmt::Display for Error{ } } } +impl std::error::Error for Error{} fn init(lua:&mlua::Lua)->mlua::Result<()>{ lua.sandbox(true)?; From a88debe9f160c79fc15e3355440f3950752d26ed Mon Sep 17 00:00:00 2001 From: Quaternions Date: Thu, 3 Oct 2024 21:35:00 -0700 Subject: [PATCH 054/129] Services::find_in --- src/place.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/place.rs b/src/place.rs index 1fa0979..6961609 100644 --- a/src/place.rs +++ b/src/place.rs @@ -5,6 +5,16 @@ pub struct Services{ pub game:Ref, pub workspace:Ref, } +impl Services{ + pub fn find_in(dom:&WeakDom)->Option{ + Some(Services{ + workspace:*dom.root().children().iter().find(|&&r| + dom.get_by_ref(r).is_some_and(|instance|instance.class=="Workspace") + )?, + game:dom.root_ref(), + }) + } +} pub fn new_place_with_instances_in_workspace(mut instance_dom:WeakDom)->(WeakDom,Services){ //workspace From db8e22c34d6718b83fa906a520de141d285777e5 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Thu, 3 Oct 2024 21:39:24 -0700 Subject: [PATCH 055/129] v0.3.2 error trait + Services constructor --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5d35bcd..c70964a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -318,7 +318,7 @@ dependencies = [ [[package]] name = "roblox_emulator" -version = "0.3.1" +version = "0.3.2" dependencies = [ "glam", "mlua", diff --git a/Cargo.toml b/Cargo.toml index 6345b70..3c931b3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "roblox_emulator" -version = "0.3.1" +version = "0.3.2" edition = "2021" repository = "https://git.itzana.me/StrafesNET/roblox_emulator" license = "MIT OR Apache-2.0" From 7d67e762b14811f37d2b11658319f88f865acbc3 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 4 Oct 2024 16:32:49 -0700 Subject: [PATCH 056/129] Context::from_ref --- src/context.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/context.rs b/src/context.rs index 9e0b05c..44458b9 100644 --- a/src/context.rs +++ b/src/context.rs @@ -31,6 +31,9 @@ impl Context{ ); (Context{dom},crate::runner::instance::Script::new(script_ref),services) } + pub fn from_ref(dom:&WeakDom)->&Context{ + unsafe{&*(dom as *const WeakDom as *const Context)} + } pub fn from_mut(dom:&mut WeakDom)->&mut Context{ unsafe{&mut *(dom as *mut WeakDom as *mut Context)} } From 3fabb6dbaed0ab662c012c04d73e5eae4c7076c9 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 4 Oct 2024 16:47:53 -0700 Subject: [PATCH 057/129] fix print --- src/runner/instance.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index cef224f..b3e12ba 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -194,11 +194,11 @@ impl Instance{ instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Float32(typed_value)); }, rbx_types::Variant::Enum(_)=>{ - let typed_value:super::r#enum::Enum=value.as_userdata().ok_or(mlua::Error::runtime("Expected Userdata"))?.take()?; + let typed_value:super::r#enum::Enum=value.as_userdata().ok_or(mlua::Error::runtime("Expected Enum"))?.take()?; instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Enum(typed_value.into())); }, rbx_types::Variant::Color3(_)=>{ - let typed_value:super::color3::Color3=value.as_userdata().ok_or(mlua::Error::runtime("Expected Userdata"))?.take()?; + let typed_value:super::color3::Color3=value.as_userdata().ok_or(mlua::Error::runtime("Expected Color3"))?.take()?; instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Color3(typed_value.into())); }, other=>return Err(mlua::Error::runtime(format!("Unimplemented property type: {other:?}"))), From 7774fe9eb47537486053457830bd9ac87e1cf277 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 4 Oct 2024 16:48:19 -0700 Subject: [PATCH 058/129] Instance.__newindex=bool --- src/runner/instance.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index b3e12ba..c3152d5 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -201,6 +201,10 @@ impl Instance{ let typed_value:super::color3::Color3=value.as_userdata().ok_or(mlua::Error::runtime("Expected Color3"))?.take()?; instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Color3(typed_value.into())); }, + rbx_types::Variant::Bool(_)=>{ + let typed_value=value.as_boolean().ok_or(mlua::Error::runtime("Expected boolean"))?; + instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Bool(typed_value)); + }, other=>return Err(mlua::Error::runtime(format!("Unimplemented property type: {other:?}"))), } Ok(()) From c0323d12dff90b3ea8492e2543d681a3a1943d12 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 4 Oct 2024 16:14:03 -0700 Subject: [PATCH 059/129] delete place.rs --- src/context.rs | 51 ++++++++++++++++++++++++++++++++++++++++++-------- src/lib.rs | 1 - src/place.rs | 47 ---------------------------------------------- 3 files changed, 43 insertions(+), 56 deletions(-) delete mode 100644 src/place.rs diff --git a/src/context.rs b/src/context.rs index 44458b9..91562bd 100644 --- a/src/context.rs +++ b/src/context.rs @@ -19,17 +19,16 @@ impl Context{ pub const fn new(dom:WeakDom)->Self{ Self{dom} } - pub fn script_singleton(source:String)->(Context,crate::runner::instance::Script,crate::place::Services){ + pub fn script_singleton(source:String)->(Context,crate::runner::instance::Script,Services){ let script=InstanceBuilder::new("Script") .with_property("Source",rbx_types::Variant::String(source)); let script_ref=script.referent(); - let (dom,services)=crate::place::new_place_with_instances_in_workspace( - WeakDom::new( - InstanceBuilder::new("DataModel") - .with_child(script) - ) - ); - (Context{dom},crate::runner::instance::Script::new(script_ref),services) + let mut context=Self::new(WeakDom::new( + InstanceBuilder::new("DataModel") + .with_child(script) + )); + let services=context.convert_into_place(); + (context,crate::runner::instance::Script::new(script_ref),services) } pub fn from_ref(dom:&WeakDom)->&Context{ unsafe{&*(dom as *const WeakDom as *const Context)} @@ -46,4 +45,40 @@ impl Context{ pub fn scripts(&self)->Vec{ self.superclass_iter("LuaSourceContainer").map(crate::runner::instance::Script::new).collect() } + + pub fn find_services(&self)->Option{ + Some(Services{ + workspace:*self.dom.root().children().iter().find(|&&r| + self.dom.get_by_ref(r).is_some_and(|instance|instance.class=="Workspace") + )?, + game:self.dom.root_ref(), + }) + } + pub fn convert_into_place(&mut self)->Services{ + //snapshot root instances + let children=self.dom.root().children().to_owned(); + + //insert services + let game=self.dom.root_ref(); + let workspace=self.dom.insert(game, + InstanceBuilder::new("Workspace") + .with_child(InstanceBuilder::new("Terrain")) + ); + self.dom.insert(game,InstanceBuilder::new("Lighting")); + + //transfer original root instances into workspace + for instance in children{ + self.dom.transfer_within(instance,workspace); + } + + Services{ + game, + workspace, + } + } +} + +pub struct Services{ + pub game:Ref, + pub workspace:Ref, } diff --git a/src/lib.rs b/src/lib.rs index 70c62b9..b97eda2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,3 @@ -pub mod place; pub mod runner; pub mod context; diff --git a/src/place.rs b/src/place.rs deleted file mode 100644 index 6961609..0000000 --- a/src/place.rs +++ /dev/null @@ -1,47 +0,0 @@ -use rbx_dom_weak::{InstanceBuilder,WeakDom}; -use rbx_types::Ref; - -pub struct Services{ - pub game:Ref, - pub workspace:Ref, -} -impl Services{ - pub fn find_in(dom:&WeakDom)->Option{ - Some(Services{ - workspace:*dom.root().children().iter().find(|&&r| - dom.get_by_ref(r).is_some_and(|instance|instance.class=="Workspace") - )?, - game:dom.root_ref(), - }) - } -} - -pub fn new_place_with_instances_in_workspace(mut instance_dom:WeakDom)->(WeakDom,Services){ - //workspace - let workspace_bldr=InstanceBuilder::new("Workspace") - .with_child(InstanceBuilder::new("Terrain")); - let workspace=workspace_bldr.referent(); - - //game - let game_bldr= - InstanceBuilder::new("DataModel") - .with_child(workspace_bldr) - .with_child(InstanceBuilder::new("Lighting")); - let game=game_bldr.referent(); - - let mut dom=WeakDom::new(game_bldr); - - //put instances in workspace - let children=instance_dom.root().children().to_owned(); - for instance in children{ - instance_dom.transfer(instance,&mut dom,workspace); - } - - ( - dom, - Services{ - game, - workspace - } - ) -} From e1103653252c7ded3e715e1c2d6beb2015a2fe14 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 4 Oct 2024 16:48:25 -0700 Subject: [PATCH 060/129] more api --- src/runner/runner.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/runner/runner.rs b/src/runner/runner.rs index bf5def1..5d7180d 100644 --- a/src/runner/runner.rs +++ b/src/runner/runner.rs @@ -12,6 +12,7 @@ pub enum Error{ RustLua(mlua::Error), Script(super::instance::GetScriptError), NoContext, + NoServices, } impl std::fmt::Display for Error{ fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{ @@ -46,7 +47,11 @@ impl Runner{ init(&runner.lua).map_err(Error::RustLua)?; Ok(runner) } - pub fn runnable_context<'a>(self,context:&'a mut Context,services:&crate::place::Services)->Result,Error>{ + pub fn runnable_context<'a>(self,context:&'a mut Context)->Result,Error>{ + let services=context.find_services().ok_or(Error::NoServices)?; + self.runnable_context_with_services(context,&services) + } + pub fn runnable_context_with_services<'a>(self,context:&'a mut Context,services:&crate::context::Services)->Result,Error>{ { let globals=self.lua.globals(); globals.set("game",super::instance::DataModel::new(services.game)).map_err(Error::RustLua)?; From d496a2dac5e9abd243b6a00f59722421823c922d Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 4 Oct 2024 16:56:16 -0700 Subject: [PATCH 061/129] v0.4.0 less cringe into_place api --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c70964a..e9b68e9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -318,7 +318,7 @@ dependencies = [ [[package]] name = "roblox_emulator" -version = "0.3.2" +version = "0.4.0" dependencies = [ "glam", "mlua", diff --git a/Cargo.toml b/Cargo.toml index 3c931b3..b22ea8f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "roblox_emulator" -version = "0.3.2" +version = "0.4.0" edition = "2021" repository = "https://git.itzana.me/StrafesNET/roblox_emulator" license = "MIT OR Apache-2.0" From 9b077d6db7b6ecad83e5018babd60c72ca0b1052 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 4 Oct 2024 17:33:59 -0700 Subject: [PATCH 062/129] no double enum database access --- src/runner/enum.rs | 30 +++++++++++++----------------- src/runner/macros.rs | 12 ++++++++++++ 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/src/runner/enum.rs b/src/runner/enum.rs index b508f7e..27f2df0 100644 --- a/src/runner/enum.rs +++ b/src/runner/enum.rs @@ -3,8 +3,8 @@ use mlua::IntoLua; #[derive(Clone,Copy)] pub struct Enum(u32); pub struct EnumItems; -pub struct EnumItem{ - name:String +pub struct EnumItem<'a>{ + ed:&'a rbx_reflection::EnumDescriptor<'a>, } impl Into for Enum{ @@ -13,9 +13,9 @@ impl Into for Enum{ } } -impl EnumItem{ - const fn new(name:String)->Self{ - Self{name} +impl<'a> EnumItem<'a>{ + const fn new(ed:&'a rbx_reflection::EnumDescriptor)->Self{ + Self{ed} } } @@ -23,32 +23,28 @@ pub fn set_globals(_lua:&mlua::Lua,globals:&mlua::Table<'_>)->Result<(),mlua::Er globals.set("Enum",EnumItems) } -impl mlua::UserData for EnumItem{ +impl mlua::UserData for EnumItem<'_>{ fn add_fields<'lua,F:mlua::UserDataFields<'lua,Self>>(_fields:&mut F){ } fn add_methods<'lua,M:mlua::UserDataMethods<'lua,Self>>(methods:&mut M){ - methods.add_meta_function(mlua::MetaMethod::Index,|lua,(this,val):(Self,String)|{ - let db=rbx_reflection_database::get(); - match db.enums.get(this.name.as_str()){ - Some(e)=>match e.items.get(val.as_str()){ - Some(&id)=>Enum(id).into_lua(lua), - None=>mlua::Value::Nil.into_lua(lua), - }, + methods.add_meta_function(mlua::MetaMethod::Index,|lua,(this,val):(EnumItem<'lua>,mlua::String)|{ + match this.ed.items.get(val.to_str()?){ + Some(&id)=>Enum(id).into_lua(lua), None=>mlua::Value::Nil.into_lua(lua), } }); } } -type_from_lua_userdata!(EnumItem); +type_from_lua_userdata_lua_lifetime!(EnumItem); impl mlua::UserData for EnumItems{ fn add_fields<'lua,F:mlua::UserDataFields<'lua,Self>>(_fields:&mut F){ } fn add_methods<'lua,M:mlua::UserDataMethods<'lua,Self>>(methods:&mut M){ - methods.add_meta_function(mlua::MetaMethod::Index,|lua,(_,val):(Self,String)|{ + methods.add_meta_function(mlua::MetaMethod::Index,|lua,(_,val):(Self,mlua::String)|{ let db=rbx_reflection_database::get(); - match db.enums.get(val.as_str()){ - Some(_)=>EnumItem::new(val).into_lua(lua), + match db.enums.get(val.to_str()?){ + Some(ed)=>EnumItem::new(ed).into_lua(lua), None=>mlua::Value::Nil.into_lua(lua), } }); diff --git a/src/runner/macros.rs b/src/runner/macros.rs index b935225..8121af8 100644 --- a/src/runner/macros.rs +++ b/src/runner/macros.rs @@ -10,3 +10,15 @@ macro_rules! type_from_lua_userdata{ } }; } +macro_rules! type_from_lua_userdata_lua_lifetime{ + ($asd:ident)=>{ + impl<'lua> mlua::FromLua<'lua> for $asd<'lua>{ + fn from_lua(value:mlua::Value<'lua>,_lua:&'lua mlua::Lua)->Result{ + match value{ + mlua::Value::UserData(ud)=>ud.take(), + other=>Err(mlua::Error::runtime(format!("Expected {} got {:?}",stringify!($asd),other))), + } + } + } + }; +} From e4114ab2cca5dacfbffe97f1ce9b1af4ff81f7a9 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 4 Oct 2024 17:51:56 -0700 Subject: [PATCH 063/129] simplify run_script logic --- src/runner/instance.rs | 22 +++++++++------------- src/runner/runner.rs | 10 ++-------- 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index c3152d5..213aa91 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -250,22 +250,18 @@ class_composition!(Workspace,(Instance)); class!(Lighting); class_composition!(Lighting,(Instance)); -#[derive(Debug)] -pub enum GetScriptError{ - NoScript, - NoSource, -} - class!(Script); class_composition!(Script,(Instance)); impl Script{ - pub fn get_name_source(&self,context:&crate::context::Context)->Result<(String,String),GetScriptError>{ - let instance=context.dom.get_by_ref(self.referent).ok_or(GetScriptError::NoScript)?; - let source=match instance.properties.get("Source").ok_or(GetScriptError::NoSource)?{ - rbx_dom_weak::types::Variant::String(s)=>s.clone(), - _=>Err(GetScriptError::NoSource)?, - }; - Ok((get_full_name(&context.dom,instance),source)) + pub fn get_name_source(&self,lua:&mlua::Lua)->Result<(String,String),mlua::Error>{ + dom(lua,|dom|{ + let instance=self.get(dom)?; + let source=match instance.properties.get("Source"){ + Some(rbx_dom_weak::types::Variant::String(s))=>s.clone(), + _=>Err(mlua::Error::external("Missing script.Source"))?, + }; + Ok((get_full_name(dom,instance),source)) + }) } } diff --git a/src/runner/runner.rs b/src/runner/runner.rs index 5d7180d..a6935cb 100644 --- a/src/runner/runner.rs +++ b/src/runner/runner.rs @@ -10,8 +10,6 @@ pub enum Error{ error:mlua::Error }, RustLua(mlua::Error), - Script(super::instance::GetScriptError), - NoContext, NoServices, } impl std::fmt::Display for Error{ @@ -79,12 +77,8 @@ impl Runnable<'_>{ } } pub fn run_script(&self,script:super::instance::Script)->Result<(),Error>{ - let (name,source)={ - let dom=&mut *self.lua.app_data_mut::<&'static mut rbx_dom_weak::WeakDom>().ok_or(Error::NoContext)?; - let (name,source)=script.get_name_source(Context::from_mut(dom)).map_err(Error::Script)?; - self.lua.globals().set("script",script).map_err(Error::RustLua)?; - (name,source) - }; + let (name,source)=script.get_name_source(&self.lua).map_err(Error::RustLua)?; + self.lua.globals().set("script",script).map_err(Error::RustLua)?; self.lua.load(source.as_str()) .set_name(name) .exec().map_err(|error|Error::Lua{source,error}) From cb5b842276f9f147d24d4c4bde16e2e3e71d2e15 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 4 Oct 2024 18:43:11 -0700 Subject: [PATCH 064/129] fix Instance.__newindex + implement String --- src/runner/instance.rs | 56 +++++++++++++++++++++++++++++++++++------- 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 213aa91..3e79efd 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -87,6 +87,24 @@ macro_rules! class_composition{ }; } +//TODO: update rbx_reflection and use dom.superclasses_iter +pub struct SuperClassIter<'a> { + database: &'a rbx_reflection::ReflectionDatabase<'a>, + descriptor: Option<&'a rbx_reflection::ClassDescriptor<'a>>, +} +impl<'a> SuperClassIter<'a> { + fn next_descriptor(&self) -> Option<&'a rbx_reflection::ClassDescriptor<'a>> { + let superclass = self.descriptor?.superclass.as_ref()?; + self.database.classes.get(superclass) + } +} +impl<'a> Iterator for SuperClassIter<'a> { + type Item = &'a rbx_reflection::ClassDescriptor<'a>; + fn next(&mut self) -> Option { + let next_descriptor = self.next_descriptor(); + std::mem::replace(&mut self.descriptor, next_descriptor) + } +} class!(Instance); class_composition!(Instance,(Instance)); @@ -183,28 +201,48 @@ impl Instance{ let index_str=index.to_str()?; let db=rbx_reflection_database::get(); let class=db.classes.get(instance.class.as_str()).ok_or(mlua::Error::runtime("Class missing"))?; - let property=db.find_default_property(class,index_str).ok_or(mlua::Error::runtime(format!("Property '{index_str}' missing on class '{}'",class.name)))?; - match property{ - rbx_types::Variant::Vector3(_)=>{ + let mut iter=SuperClassIter{ + database:db, + descriptor:Some(class), + }; + let property=iter.find_map(|cls|cls.properties.get(index_str)).ok_or(mlua::Error::runtime(format!("Property '{index_str}' missing on class '{}'",class.name)))?; + match &property.data_type{ + rbx_reflection::DataType::Value(rbx_types::VariantType::Vector3)=>{ let typed_value:Vector3=value.as_userdata().ok_or(mlua::Error::runtime("Expected Userdata"))?.take()?; instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Vector3(typed_value.into())); }, - rbx_types::Variant::Float32(_)=>{ + rbx_reflection::DataType::Value(rbx_types::VariantType::Float32)=>{ let typed_value:f32=coerce_float32(&value).ok_or(mlua::Error::runtime("Expected f32"))?; instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Float32(typed_value)); }, - rbx_types::Variant::Enum(_)=>{ - let typed_value:super::r#enum::Enum=value.as_userdata().ok_or(mlua::Error::runtime("Expected Enum"))?.take()?; - instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Enum(typed_value.into())); + rbx_reflection::DataType::Enum(enum_name)=>{ + let typed_value=match &value{ + &mlua::Value::Integer(int)=>Ok(rbx_types::Enum::from_u32(int as u32)), + &mlua::Value::Number(num)=>Ok(rbx_types::Enum::from_u32(num as u32)), + mlua::Value::String(s)=>{ + let e=db.enums.get(enum_name).ok_or(mlua::Error::runtime("Database DataType Enum name does not exist"))?; + Ok(rbx_types::Enum::from_u32(*e.items.get(s.to_str()?).ok_or(mlua::Error::runtime("Invalid enum item"))?)) + }, + mlua::Value::UserData(any_user_data)=>{ + let e:super::r#enum::Enum=any_user_data.take()?; + Ok(e.into()) + }, + _=>Err(mlua::Error::runtime("Expected Enum")), + }?; + instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Enum(typed_value)); }, - rbx_types::Variant::Color3(_)=>{ + rbx_reflection::DataType::Value(rbx_types::VariantType::Color3)=>{ let typed_value:super::color3::Color3=value.as_userdata().ok_or(mlua::Error::runtime("Expected Color3"))?.take()?; instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Color3(typed_value.into())); }, - rbx_types::Variant::Bool(_)=>{ + rbx_reflection::DataType::Value(rbx_types::VariantType::Bool)=>{ let typed_value=value.as_boolean().ok_or(mlua::Error::runtime("Expected boolean"))?; instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Bool(typed_value)); }, + rbx_reflection::DataType::Value(rbx_types::VariantType::String)=>{ + let typed_value=value.as_str().ok_or(mlua::Error::runtime("Expected boolean"))?; + instance.properties.insert(index_str.to_owned(),rbx_types::Variant::String(typed_value.to_owned())); + }, other=>return Err(mlua::Error::runtime(format!("Unimplemented property type: {other:?}"))), } Ok(()) From 0148476648fc9034b20a198deadcb3d58c3f9b2c Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 4 Oct 2024 18:43:40 -0700 Subject: [PATCH 065/129] Instance FindFirstChild + WaitForChild (no difference in implementation) --- src/runner/instance.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 3e79efd..b219885 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -158,6 +158,29 @@ impl Instance{ Ok(children) }) ); + let ffc=|lua,this:&T,(name,search_descendants):(mlua::String,mlua::Value)|{ + let name_str=name.to_str()?; + let search_descendants=match search_descendants{ + mlua::Value::Nil=>false, + mlua::Value::Boolean(b)=>b, + _=>Err(mlua::Error::runtime("Invalid argument #3 bool expected"))?, + }; + dom(lua,|dom|{ + let instance=this.get(dom)?; + let child=match search_descendants{ + true=>dom.descendants_of(this.referent()).find(|inst|inst.name==name_str), + false=>instance.children().iter().filter_map(|&r| + dom.get_by_ref(r) + ).find(|inst|inst.name==name_str), + }; + match child{ + Some(instance)=>Instance::new(instance.referent()).into_lua(lua), + None=>mlua::Value::Nil.into_lua(lua), + } + }) + }; + methods.add_method("FindFirstChild",ffc); + methods.add_method("WaitForChild",ffc); methods.add_method("GetDescendants",|lua,this,_:()| dom(lua,|dom|{ let children:Vec<_>=dom From 67223efa265dcc291ce9dcd8e113ae96a0f467f2 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 4 Oct 2024 19:05:10 -0700 Subject: [PATCH 066/129] find_first_child_of_class --- src/runner/instance.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index b219885..9fbc645 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -29,6 +29,10 @@ fn get_full_name(dom:&rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance)->S full_name } +pub fn find_first_child_of_class<'a>(dom:&'a rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance,class:&str)->Option<&'a rbx_dom_weak::Instance>{ + instance.children().iter().filter_map(|&r|dom.get_by_ref(r)).find(|inst|inst.class==class) +} + //workaround until I have an enum of classes struct Dereferent(Ref); impl mlua::UserData for Dereferent{} @@ -181,6 +185,22 @@ impl Instance{ }; methods.add_method("FindFirstChild",ffc); methods.add_method("WaitForChild",ffc); + methods.add_method("FindFirstChildOfClass",|lua,this,(class,search_descendants):(mlua::String,mlua::Value)|{ + let class_str=class.to_str()?; + let search_descendants=match search_descendants{ + mlua::Value::Nil=>false, + mlua::Value::Boolean(b)=>b, + _=>Err(mlua::Error::runtime("Invalid argument #3 bool expected"))?, + }; + if search_descendants==true{ + return Err(mlua::Error::runtime("FFC of class searching descendants not supported get rekt")); + } + dom(lua,|dom|{ + Ok(find_first_child_of_class(dom,this.get(dom)?,class_str) + .map(|inst|(Instance::new(inst.referent()))) + ) + }) + }); methods.add_method("GetDescendants",|lua,this,_:()| dom(lua,|dom|{ let children:Vec<_>=dom From 96c8b1035a0791921809e8d549eacce132f9563e Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 4 Oct 2024 19:04:54 -0700 Subject: [PATCH 067/129] game.workspace --- src/runner/instance.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 9fbc645..792010c 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -298,6 +298,13 @@ class!(DataModel); class_composition!(DataModel,(Instance,DataModel)); impl DataModel{ fn composition_add_fields<'lua,T:Referent,F:mlua::UserDataFields<'lua,T>>(fields:&mut F){ + fields.add_field_method_get("workspace",|lua,this|{ + dom(lua,|dom|{ + Ok(find_first_child_of_class(dom,this.get(dom)?,"Workspace") + .map(|inst|Workspace::new(inst.referent())) + ) + }) + }); fields.add_field_method_get("PlaceId",|lua,this|{ Ok(mlua::Value::Integer(0)) }); From acbb1c8478a0f40e845dfd12aab05e6be996eb66 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 4 Oct 2024 19:05:05 -0700 Subject: [PATCH 068/129] workspace.Terrain --- src/runner/instance.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 792010c..5a229b0 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -333,8 +333,20 @@ impl DataModel{ } class!(Workspace); -class_composition!(Workspace,(Instance)); - +class_composition!(Workspace,(Instance,Workspace)); +impl Workspace{ + fn composition_add_fields<'lua,T:Referent,F:mlua::UserDataFields<'lua,T>>(fields:&mut F){ + fields.add_field_method_get("Terrain",|lua,this|{ + dom(lua,|dom|{ + Ok(find_first_child_of_class(dom,this.get(dom)?,"Terrain") + .map(|inst|Terrain::new(inst.referent())) + ) + }) + }); + } + fn composition_add_methods<'lua,T,M:mlua::UserDataMethods<'lua,T>>(_methods:&mut M){ + } +} class!(Lighting); class_composition!(Lighting,(Instance)); From ba9918f2d557c42dfdfea248a12f8f5ff9f51bd3 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 4 Oct 2024 19:05:21 -0700 Subject: [PATCH 069/129] None maps to Nil ezpz --- src/runner/instance.rs | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 5a229b0..ed695ad 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -171,16 +171,17 @@ impl Instance{ }; dom(lua,|dom|{ let instance=this.get(dom)?; - let child=match search_descendants{ - true=>dom.descendants_of(this.referent()).find(|inst|inst.name==name_str), - false=>instance.children().iter().filter_map(|&r| - dom.get_by_ref(r) - ).find(|inst|inst.name==name_str), - }; - match child{ - Some(instance)=>Instance::new(instance.referent()).into_lua(lua), - None=>mlua::Value::Nil.into_lua(lua), - } + Ok( + match search_descendants{ + true=>dom.descendants_of(this.referent()).find(|inst|inst.name==name_str), + false=>instance.children().iter().filter_map(|&r| + dom.get_by_ref(r) + ).find(|inst|inst.name==name_str), + } + .map(|instance| + Instance::new(instance.referent()) + ) + ) }) }; methods.add_method("FindFirstChild",ffc); @@ -224,16 +225,15 @@ impl Instance{ dom(lua,|dom|{ let instance=dereferent.get(dom)?; //find a child with a matching name - let maybe_child=instance.children() - .iter() - .find(|&&r| - dom.get_by_ref(r) - .is_some_and(|instance|instance.name==index_str) - ); - match maybe_child{ - Some(&referent)=>Instance::new(referent).into_lua(lua), - None=>mlua::Value::Nil.into_lua(lua), - } + Ok( + instance.children() + .iter() + .find(|&&r| + dom.get_by_ref(r) + .is_some_and(|instance|instance.name==index_str) + ) + .map(|&referent|Instance::new(referent)) + ) }) }); methods.add_meta_function(mlua::MetaMethod::NewIndex,|lua,(this,index,value):(mlua::AnyUserData,mlua::String,mlua::Value)|{ From 9030646f39f997684a1cc90892dc6a5d06b7f677 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 4 Oct 2024 19:28:32 -0700 Subject: [PATCH 070/129] begin Instance.__index properties implementation --- src/runner/cframe.rs | 51 ++++++++++++++++++++++++++++++++++++++++-- src/runner/instance.rs | 8 ++++++- src/runner/vector3.rs | 6 +++++ 3 files changed, 62 insertions(+), 3 deletions(-) diff --git a/src/runner/cframe.rs b/src/runner/cframe.rs index 8942578..8dfcbd9 100644 --- a/src/runner/cframe.rs +++ b/src/runner/cframe.rs @@ -4,7 +4,22 @@ use super::vector3::Vector3; pub struct CFrame(pub(crate)glam::Affine3A); impl CFrame{ - pub fn new(x:f32,y:f32,z:f32)->Self{ + pub fn new( + x:f32,y:f32,z:f32, + xx:f32,yx:f32,zx:f32, + xy:f32,yy:f32,zy:f32, + xz:f32,yz:f32,zz:f32, + )->Self{ + Self(glam::Affine3A::from_mat3_translation( + glam::mat3( + glam::vec3(xx,yx,zx), + glam::vec3(xy,yy,zy), + glam::vec3(xz,yz,zz) + ), + glam::vec3(x,y,z) + )) + } + pub fn point(x:f32,y:f32,z:f32)->Self{ Self(glam::Affine3A::from_translation(glam::vec3(x,y,z))) } pub fn angles(x:f32,y:f32,z:f32)->Self{ @@ -12,13 +27,45 @@ impl CFrame{ } } +fn vec3_to_glam(v:glam::Vec3A)->rbx_types::Vector3{ + rbx_types::Vector3::new(v.x,v.y,v.z) +} +fn vec3_from_glam(v:rbx_types::Vector3)->glam::Vec3A{ + glam::vec3a(v.x,v.y,v.z) +} + +impl Into for CFrame{ + fn into(self)->rbx_types::CFrame{ + rbx_types::CFrame::new( + vec3_to_glam(self.0.translation), + rbx_types::Matrix3::new( + vec3_to_glam(self.0.matrix3.x_axis), + vec3_to_glam(self.0.matrix3.y_axis), + vec3_to_glam(self.0.matrix3.z_axis), + ) + ) + } +} +impl From for CFrame{ + fn from(value:rbx_types::CFrame)->Self{ + CFrame(glam::Affine3A{ + matrix3:glam::mat3a( + vec3_from_glam(value.orientation.x), + vec3_from_glam(value.orientation.y), + vec3_from_glam(value.orientation.z), + ), + translation:vec3_from_glam(value.position) + }) + } +} + pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table<'_>)->Result<(),mlua::Error>{ let cframe_table=lua.create_table()?; //CFrame.new cframe_table.raw_set("new", lua.create_function(|ctx,(x,y,z):(f32,f32,f32)| - Ok(ctx.create_userdata(CFrame::new(x,y,z))) + Ok(ctx.create_userdata(CFrame::point(x,y,z))) )? )?; diff --git a/src/runner/instance.rs b/src/runner/instance.rs index ed695ad..49714e0 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -224,6 +224,12 @@ impl Instance{ let dereferent:Dereferent=mlua::AnyUserDataExt::get(&this,"Referent")?; dom(lua,|dom|{ let instance=dereferent.get(dom)?; + match instance.properties.get(index_str){ + Some(&rbx_types::Variant::CFrame(cf))=>return Ok(Into::::into(cf).into_lua(lua)), + Some(&rbx_types::Variant::Vector3(v))=>return Ok(Into::::into(v).into_lua(lua)), + //None=>get_default_value + _=>(), + } //find a child with a matching name Ok( instance.children() @@ -232,7 +238,7 @@ impl Instance{ dom.get_by_ref(r) .is_some_and(|instance|instance.name==index_str) ) - .map(|&referent|Instance::new(referent)) + .map(|&referent|Instance::new(referent)).into_lua(lua) ) }) }); diff --git a/src/runner/vector3.rs b/src/runner/vector3.rs index bff57a6..e6c09cd 100644 --- a/src/runner/vector3.rs +++ b/src/runner/vector3.rs @@ -28,6 +28,12 @@ impl Into for Vector3{ } } +impl From for Vector3{ + fn from(value:rbx_types::Vector3)->Vector3{ + Vector3::new(value.x,value.y,value.z) + } +} + impl mlua::UserData for Vector3{ fn add_fields<'lua,F: mlua::UserDataFields<'lua,Self>>(fields: &mut F) { fields.add_field_method_get("magnitude",|_,this| Ok(this.0.length())); From f4dc80713f2dd5ba418d55555f5af3a0284275ea Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 4 Oct 2024 19:32:30 -0700 Subject: [PATCH 071/129] Instance.Destroy --- src/runner/instance.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 49714e0..093897c 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -219,6 +219,12 @@ impl Instance{ Ok(crate::context::class_is_a(instance.class.as_str(),classname.to_str()?)) }) ); + methods.add_method("Destroy",|lua,this,()| + dom(lua,|dom|{ + dom.destroy(this.referent()); + Ok(()) + }) + ); methods.add_meta_function(mlua::MetaMethod::Index,|lua,(this,index):(mlua::AnyUserData,mlua::String)|{ let index_str=index.to_str()?; let dereferent:Dereferent=mlua::AnyUserDataExt::get(&this,"Referent")?; From ef7877870871a3128fe756d97a8352adddd56245 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 4 Oct 2024 19:39:09 -0700 Subject: [PATCH 072/129] v0.4.1 additional implementations --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e9b68e9..afdf635 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -318,7 +318,7 @@ dependencies = [ [[package]] name = "roblox_emulator" -version = "0.4.0" +version = "0.4.1" dependencies = [ "glam", "mlua", diff --git a/Cargo.toml b/Cargo.toml index b22ea8f..5d28835 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "roblox_emulator" -version = "0.4.0" +version = "0.4.1" edition = "2021" repository = "https://git.itzana.me/StrafesNET/roblox_emulator" license = "MIT OR Apache-2.0" From 3a716373db85fb4a5b703a5561213b430701847b Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 4 Oct 2024 20:48:47 -0700 Subject: [PATCH 073/129] FromLua type stuff + find_first_descendant_of_class --- src/runner/instance.rs | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 093897c..e52caf2 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -32,6 +32,9 @@ fn get_full_name(dom:&rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance)->S pub fn find_first_child_of_class<'a>(dom:&'a rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance,class:&str)->Option<&'a rbx_dom_weak::Instance>{ instance.children().iter().filter_map(|&r|dom.get_by_ref(r)).find(|inst|inst.class==class) } +pub fn find_first_descendant_of_class<'a>(dom:&'a rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance,class:&str)->Option<&'a rbx_dom_weak::Instance>{ + dom.descendants_of(instance.referent()).find(|&inst|inst.class==class) +} //workaround until I have an enum of classes struct Dereferent(Ref); @@ -162,17 +165,12 @@ impl Instance{ Ok(children) }) ); - let ffc=|lua,this:&T,(name,search_descendants):(mlua::String,mlua::Value)|{ + let ffc=|lua,this:&T,(name,search_descendants):(mlua::String,Option)|{ let name_str=name.to_str()?; - let search_descendants=match search_descendants{ - mlua::Value::Nil=>false, - mlua::Value::Boolean(b)=>b, - _=>Err(mlua::Error::runtime("Invalid argument #3 bool expected"))?, - }; dom(lua,|dom|{ let instance=this.get(dom)?; Ok( - match search_descendants{ + match search_descendants.unwrap_or(false){ true=>dom.descendants_of(this.referent()).find(|inst|inst.name==name_str), false=>instance.children().iter().filter_map(|&r| dom.get_by_ref(r) @@ -186,19 +184,15 @@ impl Instance{ }; methods.add_method("FindFirstChild",ffc); methods.add_method("WaitForChild",ffc); - methods.add_method("FindFirstChildOfClass",|lua,this,(class,search_descendants):(mlua::String,mlua::Value)|{ + methods.add_method("FindFirstChildOfClass",|lua,this,(class,search_descendants):(mlua::String,Option)|{ let class_str=class.to_str()?; - let search_descendants=match search_descendants{ - mlua::Value::Nil=>false, - mlua::Value::Boolean(b)=>b, - _=>Err(mlua::Error::runtime("Invalid argument #3 bool expected"))?, - }; - if search_descendants==true{ - return Err(mlua::Error::runtime("FFC of class searching descendants not supported get rekt")); - } dom(lua,|dom|{ - Ok(find_first_child_of_class(dom,this.get(dom)?,class_str) - .map(|inst|(Instance::new(inst.referent()))) + Ok( + match search_descendants.unwrap_or(false){ + true=>find_first_descendant_of_class(dom,this.get(dom)?,class_str), + false=>find_first_child_of_class(dom,this.get(dom)?,class_str), + } + .map(|inst|(Instance::new(inst.referent()))) ) }) }); From 7b8f091ab3937c4828be403605e6d4c7af9c888d Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 4 Oct 2024 21:08:28 -0700 Subject: [PATCH 074/129] deduplicate more find code --- src/runner/instance.rs | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index e52caf2..a850ac1 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -29,6 +29,13 @@ fn get_full_name(dom:&rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance)->S full_name } +pub fn find_first_child<'a>(dom:&'a rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance,name:&str)->Option<&'a rbx_dom_weak::Instance>{ + instance.children().iter().filter_map(|&r|dom.get_by_ref(r)).find(|inst|inst.name==name) +} +pub fn find_first_descendant<'a>(dom:&'a rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance,name:&str)->Option<&'a rbx_dom_weak::Instance>{ + dom.descendants_of(instance.referent()).find(|&inst|inst.name==name) +} + pub fn find_first_child_of_class<'a>(dom:&'a rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance,class:&str)->Option<&'a rbx_dom_weak::Instance>{ instance.children().iter().filter_map(|&r|dom.get_by_ref(r)).find(|inst|inst.class==class) } @@ -171,10 +178,8 @@ impl Instance{ let instance=this.get(dom)?; Ok( match search_descendants.unwrap_or(false){ - true=>dom.descendants_of(this.referent()).find(|inst|inst.name==name_str), - false=>instance.children().iter().filter_map(|&r| - dom.get_by_ref(r) - ).find(|inst|inst.name==name_str), + true=>find_first_descendant(dom,instance,name_str), + false=>find_first_child(dom,instance,name_str), } .map(|instance| Instance::new(instance.referent()) @@ -192,7 +197,9 @@ impl Instance{ true=>find_first_descendant_of_class(dom,this.get(dom)?,class_str), false=>find_first_child_of_class(dom,this.get(dom)?,class_str), } - .map(|inst|(Instance::new(inst.referent()))) + .map(|instance| + Instance::new(instance.referent()) + ) ) }) }); @@ -232,13 +239,9 @@ impl Instance{ } //find a child with a matching name Ok( - instance.children() - .iter() - .find(|&&r| - dom.get_by_ref(r) - .is_some_and(|instance|instance.name==index_str) - ) - .map(|&referent|Instance::new(referent)).into_lua(lua) + find_first_child(dom,instance,index_str) + .map(|instance|Instance::new(instance.referent())) + .into_lua(lua) ) }) }); @@ -320,15 +323,11 @@ impl DataModel{ dom(lua,|dom|{ match service.as_str(){ "Lighting"=>{ - let referent=dom.root() - .children() - .iter() - .find(|&&c| - dom.get_by_ref(c).is_some_and(|c|c.class=="Lighting") - ).map(|r|*r) - .unwrap_or_else(|| - dom.insert(dom.root_ref(),InstanceBuilder::new("Lighting")) - ); + let referent=find_first_child_of_class(dom,dom.root(),"Lighting") + .map(|instance|instance.referent()) + .unwrap_or_else(|| + dom.insert(dom.root_ref(),InstanceBuilder::new("Lighting")) + ); Lighting::new(referent).into_lua(lua) }, other=>Err::(mlua::Error::runtime(format!("Service '{other}' not supported"))), From 136b3605909d2a3669ab3854996663c2acb63cb2 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sat, 5 Oct 2024 11:45:10 -0700 Subject: [PATCH 075/129] rename dom function to avoid confusion with dom variable --- src/runner/instance.rs | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index a850ac1..3489a3f 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -5,7 +5,7 @@ use rbx_dom_weak::{InstanceBuilder,WeakDom}; use super::vector3::Vector3; // LMAO look at this function! -fn dom(lua:&mlua::Lua,mut f:impl FnMut(&mut WeakDom)->mlua::Result)->mlua::Result{ +fn dom_mut(lua:&mlua::Lua,mut f:impl FnMut(&mut WeakDom)->mlua::Result)->mlua::Result{ let mut dom=lua.app_data_mut::<&'static mut WeakDom>().ok_or(mlua::Error::runtime("DataModel missing"))?; f(&mut *dom) } @@ -126,26 +126,26 @@ class_composition!(Instance,(Instance)); impl Instance{ fn composition_add_fields<'lua,T:Referent,F:mlua::UserDataFields<'lua,T>>(fields:&mut F){ fields.add_field_method_get("Parent",|lua,this|{ - dom(lua,|dom|{ + dom_mut(lua,|dom|{ let instance=this.get(dom)?; Ok(Instance::new(instance.parent())) }) }); fields.add_field_method_set("Parent",|lua,this,val:mlua::AnyUserData|{ let Dereferent(referent)=mlua::AnyUserDataExt::get(&val,"Referent")?; - dom(lua,|dom|{ + dom_mut(lua,|dom|{ dom.transfer_within(this.referent(),referent); Ok(()) }) }); fields.add_field_method_get("Name",|lua,this|{ - dom(lua,|dom|{ + dom_mut(lua,|dom|{ let instance=this.get(dom)?; Ok(instance.name.clone()) }) }); fields.add_field_method_set("Name",|lua,this,val:mlua::String|{ - dom(lua,|dom|{ + dom_mut(lua,|dom|{ let instance=this.get_mut(dom)?; //Why does this need to be cloned? instance.name=val.to_str()?.to_owned(); @@ -153,7 +153,7 @@ impl Instance{ }) }); fields.add_field_method_get("ClassName",|lua,this|{ - dom(lua,|dom|{ + dom_mut(lua,|dom|{ let instance=this.get(dom)?; Ok(instance.class.clone()) }) @@ -161,7 +161,7 @@ impl Instance{ } fn composition_add_methods<'lua,T:Referent,M:mlua::UserDataMethods<'lua,T>>(methods:&mut M){ methods.add_method("GetChildren",|lua,this,_:()| - dom(lua,|dom|{ + dom_mut(lua,|dom|{ let instance=this.get(dom)?; let children:Vec<_>=instance .children() @@ -174,7 +174,7 @@ impl Instance{ ); let ffc=|lua,this:&T,(name,search_descendants):(mlua::String,Option)|{ let name_str=name.to_str()?; - dom(lua,|dom|{ + dom_mut(lua,|dom|{ let instance=this.get(dom)?; Ok( match search_descendants.unwrap_or(false){ @@ -191,7 +191,7 @@ impl Instance{ methods.add_method("WaitForChild",ffc); methods.add_method("FindFirstChildOfClass",|lua,this,(class,search_descendants):(mlua::String,Option)|{ let class_str=class.to_str()?; - dom(lua,|dom|{ + dom_mut(lua,|dom|{ Ok( match search_descendants.unwrap_or(false){ true=>find_first_descendant_of_class(dom,this.get(dom)?,class_str), @@ -204,7 +204,7 @@ impl Instance{ }) }); methods.add_method("GetDescendants",|lua,this,_:()| - dom(lua,|dom|{ + dom_mut(lua,|dom|{ let children:Vec<_>=dom .descendants_of(this.referent()) .map(|instance| @@ -215,13 +215,13 @@ impl Instance{ }) ); methods.add_method("IsA",|lua,this,classname:mlua::String| - dom(lua,|dom|{ + dom_mut(lua,|dom|{ let instance=this.get(dom)?; Ok(crate::context::class_is_a(instance.class.as_str(),classname.to_str()?)) }) ); methods.add_method("Destroy",|lua,this,()| - dom(lua,|dom|{ + dom_mut(lua,|dom|{ dom.destroy(this.referent()); Ok(()) }) @@ -229,7 +229,7 @@ impl Instance{ methods.add_meta_function(mlua::MetaMethod::Index,|lua,(this,index):(mlua::AnyUserData,mlua::String)|{ let index_str=index.to_str()?; let dereferent:Dereferent=mlua::AnyUserDataExt::get(&this,"Referent")?; - dom(lua,|dom|{ + dom_mut(lua,|dom|{ let instance=dereferent.get(dom)?; match instance.properties.get(index_str){ Some(&rbx_types::Variant::CFrame(cf))=>return Ok(Into::::into(cf).into_lua(lua)), @@ -247,7 +247,7 @@ impl Instance{ }); methods.add_meta_function(mlua::MetaMethod::NewIndex,|lua,(this,index,value):(mlua::AnyUserData,mlua::String,mlua::Value)|{ let dereferent:Dereferent=mlua::AnyUserDataExt::get(&this,"Referent")?; - dom(lua,|dom|{ + dom_mut(lua,|dom|{ let instance=dereferent.get_mut(dom)?; //println!("__newindex t={} i={index:?} v={value:?}",instance.name); let index_str=index.to_str()?; @@ -308,7 +308,7 @@ class_composition!(DataModel,(Instance,DataModel)); impl DataModel{ fn composition_add_fields<'lua,T:Referent,F:mlua::UserDataFields<'lua,T>>(fields:&mut F){ fields.add_field_method_get("workspace",|lua,this|{ - dom(lua,|dom|{ + dom_mut(lua,|dom|{ Ok(find_first_child_of_class(dom,this.get(dom)?,"Workspace") .map(|inst|Workspace::new(inst.referent())) ) @@ -320,7 +320,7 @@ impl DataModel{ } fn composition_add_methods<'lua,T,M:mlua::UserDataMethods<'lua,T>>(methods:&mut M){ methods.add_method("GetService",|lua,this,service:String| - dom(lua,|dom|{ + dom_mut(lua,|dom|{ match service.as_str(){ "Lighting"=>{ let referent=find_first_child_of_class(dom,dom.root(),"Lighting") @@ -342,7 +342,7 @@ class_composition!(Workspace,(Instance,Workspace)); impl Workspace{ fn composition_add_fields<'lua,T:Referent,F:mlua::UserDataFields<'lua,T>>(fields:&mut F){ fields.add_field_method_get("Terrain",|lua,this|{ - dom(lua,|dom|{ + dom_mut(lua,|dom|{ Ok(find_first_child_of_class(dom,this.get(dom)?,"Terrain") .map(|inst|Terrain::new(inst.referent())) ) @@ -359,7 +359,7 @@ class!(Script); class_composition!(Script,(Instance)); impl Script{ pub fn get_name_source(&self,lua:&mlua::Lua)->Result<(String,String),mlua::Error>{ - dom(lua,|dom|{ + dom_mut(lua,|dom|{ let instance=self.get(dom)?; let source=match instance.properties.get("Source"){ Some(rbx_dom_weak::types::Variant::String(s))=>s.clone(), From ed3f9f9b3040f6a55b8c672327a4d835d1a50197 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sat, 5 Oct 2024 11:52:18 -0700 Subject: [PATCH 076/129] reduce globals code --- src/runner/cframe.rs | 8 ++++---- src/runner/color3.rs | 8 ++++---- src/runner/vector3.rs | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/runner/cframe.rs b/src/runner/cframe.rs index 8dfcbd9..9bea84f 100644 --- a/src/runner/cframe.rs +++ b/src/runner/cframe.rs @@ -64,15 +64,15 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table<'_>)->Result<(),mlua::Err //CFrame.new cframe_table.raw_set("new", - lua.create_function(|ctx,(x,y,z):(f32,f32,f32)| - Ok(ctx.create_userdata(CFrame::point(x,y,z))) + lua.create_function(|_,(x,y,z):(f32,f32,f32)| + Ok(CFrame::point(x,y,z)) )? )?; //CFrame.Angles cframe_table.raw_set("Angles", - lua.create_function(|ctx,(x,y,z):(f32,f32,f32)| - Ok(ctx.create_userdata(CFrame::angles(x,y,z))) + lua.create_function(|_,(x,y,z):(f32,f32,f32)| + Ok(CFrame::angles(x,y,z)) )? )?; diff --git a/src/runner/color3.rs b/src/runner/color3.rs index 71899e8..fb155b8 100644 --- a/src/runner/color3.rs +++ b/src/runner/color3.rs @@ -19,13 +19,13 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table<'_>)->Result<(),mlua::Err let color3_table=lua.create_table()?; color3_table.raw_set("new", - lua.create_function(|ctx,(r,g,b):(f32,f32,f32)| - Ok(ctx.create_userdata(Color3::new(r,g,b))) + lua.create_function(|_,(r,g,b):(f32,f32,f32)| + Ok(Color3::new(r,g,b)) )? )?; color3_table.raw_set("fromRGB", - lua.create_function(|ctx,(r,g,b):(u8,u8,u8)| - Ok(ctx.create_userdata(Color3::new(r as f32/255.0,g as f32/255.0,b as f32/255.0))) + lua.create_function(|_,(r,g,b):(u8,u8,u8)| + Ok(Color3::new(r as f32/255.0,g as f32/255.0,b as f32/255.0)) )? )?; diff --git a/src/runner/vector3.rs b/src/runner/vector3.rs index e6c09cd..ef47f2f 100644 --- a/src/runner/vector3.rs +++ b/src/runner/vector3.rs @@ -12,8 +12,8 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table<'_>)->Result<(),mlua::Err //Vector3.new vector3_table.raw_set("new", - lua.create_function(|ctx,(x,y,z):(f32,f32,f32)| - Ok(ctx.create_userdata(Vector3::new(x,y,z))) + lua.create_function(|_,(x,y,z):(f32,f32,f32)| + Ok(Vector3::new(x,y,z)) )? )?; From b457da64a11685eec05863ea3af95ab81688001c Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sat, 5 Oct 2024 12:02:15 -0700 Subject: [PATCH 077/129] Instance globals --- src/runner/instance.rs | 20 ++++++++++++++++++++ src/runner/runner.rs | 1 + 2 files changed, 21 insertions(+) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 3489a3f..a54f826 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -4,6 +4,26 @@ use rbx_dom_weak::{InstanceBuilder,WeakDom}; use super::vector3::Vector3; +pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table<'_>)->Result<(),mlua::Error>{ + let instance_table=lua.create_table()?; + + //Instance.new + instance_table.raw_set("new", + lua.create_function(|lua,(class_name,parent):(mlua::String,Instance)|{ + let class_name_str=class_name.to_str()?; + dom_mut(lua,|dom|{ + //TODO: Nil instances, accept optional parent:Option + //let parent_ref=parent.map_or(NIL_INSTANCES,|instance|instance.referent); + Ok(Instance::new(dom.insert(parent.referent,InstanceBuilder::new(class_name_str)))) + }) + })? + )?; + + globals.set("Instance",instance_table)?; + + Ok(()) +} + // LMAO look at this function! fn dom_mut(lua:&mlua::Lua,mut f:impl FnMut(&mut WeakDom)->mlua::Result)->mlua::Result{ let mut dom=lua.app_data_mut::<&'static mut WeakDom>().ok_or(mlua::Error::runtime("DataModel missing"))?; diff --git a/src/runner/runner.rs b/src/runner/runner.rs index a6935cb..b603aa0 100644 --- a/src/runner/runner.rs +++ b/src/runner/runner.rs @@ -33,6 +33,7 @@ fn init(lua:&mlua::Lua)->mlua::Result<()>{ super::color3::set_globals(lua,&globals)?; super::vector3::set_globals(lua,&globals)?; super::cframe::set_globals(lua,&globals)?; + super::instance::set_globals(lua,&globals)?; Ok(()) } From eccf7243c466f572227914ce4f7bf2a0f408fbab Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sat, 5 Oct 2024 12:09:57 -0700 Subject: [PATCH 078/129] fake out nil parent --- src/runner/instance.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index a54f826..7a3a5af 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -9,11 +9,11 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table<'_>)->Result<(),mlua::Err //Instance.new instance_table.raw_set("new", - lua.create_function(|lua,(class_name,parent):(mlua::String,Instance)|{ + lua.create_function(|lua,(class_name,parent):(mlua::String,Option)|{ let class_name_str=class_name.to_str()?; + let parent=parent.ok_or(mlua::Error::runtime("Nil Parent not yet supported"))?; dom_mut(lua,|dom|{ - //TODO: Nil instances, accept optional parent:Option - //let parent_ref=parent.map_or(NIL_INSTANCES,|instance|instance.referent); + //TODO: Nil instances Ok(Instance::new(dom.insert(parent.referent,InstanceBuilder::new(class_name_str)))) }) })? From ff9c122470acc8a03a28c3fa02c30ee331d01522 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sat, 5 Oct 2024 12:19:55 -0700 Subject: [PATCH 079/129] add some Color3 methods --- src/runner/color3.rs | 25 +++++++++++++++++++++++++ src/runner/vector3.rs | 22 +++++++++++----------- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/runner/color3.rs b/src/runner/color3.rs index fb155b8..7952a89 100644 --- a/src/runner/color3.rs +++ b/src/runner/color3.rs @@ -33,11 +33,36 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table<'_>)->Result<(),mlua::Err Ok(()) } +fn lerp(lhs:f32,rhs:f32,t:f32)->f32{ + lhs+(rhs-lhs)*t +} impl mlua::UserData for Color3{ fn add_fields<'lua,F:mlua::UserDataFields<'lua,Self>>(fields:&mut F){ + fields.add_field_method_get("r",|_,this|Ok(this.r)); + fields.add_field_method_set("r",|_,this,val|{ + this.r=val; + Ok(()) + }); + fields.add_field_method_get("g",|_,this|Ok(this.g)); + fields.add_field_method_set("g",|_,this,val|{ + this.g=val; + Ok(()) + }); + fields.add_field_method_get("b",|_,this|Ok(this.b)); + fields.add_field_method_set("b",|_,this,val|{ + this.b=val; + Ok(()) + }); } fn add_methods<'lua,M:mlua::UserDataMethods<'lua,Self>>(methods:&mut M){ + methods.add_method("Lerp",|_,this,(other,t):(Self,f32)| + Ok(Color3::new( + lerp(this.r,other.r,t), + lerp(this.g,other.g,t), + lerp(this.b,other.b,t), + )) + ) } } type_from_lua_userdata!(Color3); diff --git a/src/runner/vector3.rs b/src/runner/vector3.rs index ef47f2f..7b33eec 100644 --- a/src/runner/vector3.rs +++ b/src/runner/vector3.rs @@ -35,21 +35,21 @@ impl From for Vector3{ } impl mlua::UserData for Vector3{ - fn add_fields<'lua,F: mlua::UserDataFields<'lua,Self>>(fields: &mut F) { - fields.add_field_method_get("magnitude",|_,this| Ok(this.0.length())); - fields.add_field_method_get("x",|_,this| Ok(this.0.x)); - fields.add_field_method_set("x",|_,this,val| { - this.0.x = val; + fn add_fields<'lua,F: mlua::UserDataFields<'lua,Self>>(fields: &mut F){ + fields.add_field_method_get("magnitude",|_,this|Ok(this.0.length())); + fields.add_field_method_get("x",|_,this|Ok(this.0.x)); + fields.add_field_method_set("x",|_,this,val|{ + this.0.x=val; Ok(()) }); - fields.add_field_method_get("y",|_,this| Ok(this.0.y)); - fields.add_field_method_set("y",|_,this,val| { - this.0.y = val; + fields.add_field_method_get("y",|_,this|Ok(this.0.y)); + fields.add_field_method_set("y",|_,this,val|{ + this.0.y=val; Ok(()) }); - fields.add_field_method_get("z",|_,this| Ok(this.0.z)); - fields.add_field_method_set("z",|_,this,val| { - this.0.z = val; + fields.add_field_method_get("z",|_,this|Ok(this.0.z)); + fields.add_field_method_set("z",|_,this,val|{ + this.0.z=val; Ok(()) }); } From 4988eeed6512d1605ec361bbfcd38823550a6c40 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sat, 5 Oct 2024 12:34:30 -0700 Subject: [PATCH 080/129] CFrame.new --- src/runner/cframe.rs | 50 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/src/runner/cframe.rs b/src/runner/cframe.rs index 9bea84f..c1f60fa 100644 --- a/src/runner/cframe.rs +++ b/src/runner/cframe.rs @@ -64,9 +64,53 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table<'_>)->Result<(),mlua::Err //CFrame.new cframe_table.raw_set("new", - lua.create_function(|_,(x,y,z):(f32,f32,f32)| - Ok(CFrame::point(x,y,z)) - )? + lua.create_function(|_,tuple:( + mlua::Value,mlua::Value,Option, + Option,Option,Option, + Option,Option,Option, + Option,Option,Option, + )|match tuple{ + //CFrame.new(pos) + ( + mlua::Value::UserData(pos),mlua::Value::Nil,None, + None,None,None, + None,None,None, + None,None,None, + )=>{ + let pos:Vector3=pos.take()?; + Ok(CFrame::point(pos.0.x,pos.0.y,pos.0.z)) + }, + //TODO: CFrame.new(pos,look) + ( + mlua::Value::UserData(pos),mlua::Value::UserData(look),None, + None,None,None, + None,None,None, + None,None,None, + )=>{ + let _pos:Vector3=pos.take()?; + let _look:Vector3=look.take()?; + Err(mlua::Error::runtime("Not yet implemented")) + }, + //CFrame.new(x,y,z) + ( + mlua::Value::Number(x),mlua::Value::Number(y),Some(z), + None,None,None, + None,None,None, + None,None,None, + )=>Ok(CFrame::point(x as f32,y as f32,z)), + //CFrame.new(x,y,z,xx,yx,zx,xy,yy,zy,xz,yz,zz) + ( + mlua::Value::Number(x),mlua::Value::Number(y),Some(z), + Some(xx),Some(yx),Some(zx), + Some(xy),Some(yy),Some(zy), + Some(xz),Some(yz),Some(zz), + )=>Ok(CFrame::new(x as f32,y as f32,z, + xx,yx,zx, + xy,yy,zy, + xz,yz,zz, + )), + _=>Err(mlua::Error::runtime("Invalid arguments")) + })? )?; //CFrame.Angles From a9a4ed2c46135e476ced62bdc8fbe28752753d03 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sat, 5 Oct 2024 13:10:57 -0700 Subject: [PATCH 081/129] default properties --- src/runner/instance.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 7a3a5af..06355f9 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -251,10 +251,18 @@ impl Instance{ let dereferent:Dereferent=mlua::AnyUserDataExt::get(&this,"Referent")?; dom_mut(lua,|dom|{ let instance=dereferent.get(dom)?; - match instance.properties.get(index_str){ + //Find existing property + match instance.properties.get(index_str) + //Find default value + .or_else(||{ + let db=rbx_reflection_database::get(); + db.classes.get(instance.class.as_str()).and_then(|cd| + db.find_default_property(cd,index_str) + ) + }) + { Some(&rbx_types::Variant::CFrame(cf))=>return Ok(Into::::into(cf).into_lua(lua)), Some(&rbx_types::Variant::Vector3(v))=>return Ok(Into::::into(v).into_lua(lua)), - //None=>get_default_value _=>(), } //find a child with a matching name From b2beef472693c3cce7f3e55f17c1013b657f2bd2 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sat, 5 Oct 2024 16:36:01 -0700 Subject: [PATCH 082/129] v0.4.2 additional implementations --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index afdf635..bfee02f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -318,7 +318,7 @@ dependencies = [ [[package]] name = "roblox_emulator" -version = "0.4.1" +version = "0.4.2" dependencies = [ "glam", "mlua", diff --git a/Cargo.toml b/Cargo.toml index 5d28835..107b70a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "roblox_emulator" -version = "0.4.1" +version = "0.4.2" edition = "2021" repository = "https://git.itzana.me/StrafesNET/roblox_emulator" license = "MIT OR Apache-2.0" From 69d43d8beada8c292e1f766357a0f98c7df9e9a5 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sat, 5 Oct 2024 12:35:38 -0700 Subject: [PATCH 083/129] class function database + update mlua to beta version to avoid unsafe --- Cargo.lock | 117 ++++++++++++++- Cargo.toml | 3 +- src/context.rs | 8 +- src/runner/cframe.rs | 6 +- src/runner/color3.rs | 6 +- src/runner/enum.rs | 22 +-- src/runner/instance.rs | 326 ++++++++++++++++++++++------------------- src/runner/macros.rs | 12 +- src/runner/runner.rs | 8 +- src/runner/vector3.rs | 6 +- 10 files changed, 321 insertions(+), 193 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bfee02f..260d89e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,6 +32,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + [[package]] name = "blake3" version = "1.5.4" @@ -121,6 +127,16 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "luau0-src" version = "0.10.3+luau640" @@ -138,15 +154,15 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "mlua" -version = "0.9.9" +version = "0.10.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d111deb18a9c9bd33e1541309f4742523bfab01d276bfa9a27519f6de9c11dc7" +checksum = "200dd4c8e5f81416d43a023b9921c3cbf01d828094b23a90b26826c3840ba4f3" dependencies = [ "bstr", "libloading", "mlua-sys", "num-traits", - "once_cell", + "parking_lot", "rustc-hash", ] @@ -172,10 +188,27 @@ dependencies = [ ] [[package]] -name = "once_cell" -version = "1.19.0" +name = "parking_lot" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] [[package]] name = "paste" @@ -183,6 +216,48 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_macros", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + [[package]] name = "pkg-config" version = "0.3.30" @@ -286,7 +361,7 @@ source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/" checksum = "d7a390c44034fa448c53bd0983dfc2d70d8d6b2f65be4f164d4bec8b6a2a2d09" dependencies = [ "base64", - "bitflags", + "bitflags 1.3.2", "blake3", "lazy_static", "rand", @@ -294,6 +369,15 @@ dependencies = [ "thiserror", ] +[[package]] +name = "redox_syscall" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +dependencies = [ + "bitflags 2.6.0", +] + [[package]] name = "rmp" version = "0.8.14" @@ -322,6 +406,7 @@ version = "0.4.2" dependencies = [ "glam", "mlua", + "phf", "rbx_dom_weak", "rbx_reflection", "rbx_reflection_database", @@ -334,6 +419,12 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "serde" version = "1.0.210" @@ -360,6 +451,18 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + [[package]] name = "syn" version = "2.0.77" diff --git a/Cargo.toml b/Cargo.toml index 107b70a..0172374 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,8 @@ authors = ["Rhys Lloyd "] [dependencies] glam = "0.29.0" -mlua = { version = "0.9.9", features = ["luau"] } +mlua = { version = "0.10.0-beta", features = ["luau"] } +phf = { version = "0.11.2", features = ["macros"] } rbx_dom_weak = { version = "2.7.0", registry = "strafesnet" } rbx_reflection = { version = "4.7.0", registry = "strafesnet" } rbx_reflection_database = { version = "0.2.10", registry = "strafesnet" } diff --git a/src/context.rs b/src/context.rs index 91562bd..c86320c 100644 --- a/src/context.rs +++ b/src/context.rs @@ -19,7 +19,7 @@ impl Context{ pub const fn new(dom:WeakDom)->Self{ Self{dom} } - pub fn script_singleton(source:String)->(Context,crate::runner::instance::Script,Services){ + pub fn script_singleton(source:String)->(Context,crate::runner::instance::Instance,Services){ let script=InstanceBuilder::new("Script") .with_property("Source",rbx_types::Variant::String(source)); let script_ref=script.referent(); @@ -28,7 +28,7 @@ impl Context{ .with_child(script) )); let services=context.convert_into_place(); - (context,crate::runner::instance::Script::new(script_ref),services) + (context,crate::runner::instance::Instance::new(script_ref),services) } pub fn from_ref(dom:&WeakDom)->&Context{ unsafe{&*(dom as *const WeakDom as *const Context)} @@ -42,8 +42,8 @@ impl Context{ class_is_a(instance.class.as_ref(),superclass) ).map(|instance|instance.referent()) } - pub fn scripts(&self)->Vec{ - self.superclass_iter("LuaSourceContainer").map(crate::runner::instance::Script::new).collect() + pub fn scripts(&self)->Vec{ + self.superclass_iter("LuaSourceContainer").map(crate::runner::instance::Instance::new).collect() } pub fn find_services(&self)->Option{ diff --git a/src/runner/cframe.rs b/src/runner/cframe.rs index c1f60fa..e9f77c2 100644 --- a/src/runner/cframe.rs +++ b/src/runner/cframe.rs @@ -59,7 +59,7 @@ impl From for CFrame{ } } -pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table<'_>)->Result<(),mlua::Error>{ +pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{ let cframe_table=lua.create_table()?; //CFrame.new @@ -126,12 +126,12 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table<'_>)->Result<(),mlua::Err } impl mlua::UserData for CFrame{ - fn add_fields<'lua,F:mlua::UserDataFields<'lua,Self>>(fields:&mut F){ + fn add_fields>(fields:&mut F){ //CFrame.p fields.add_field_method_get("p",|_,this|Ok(Vector3(this.0.translation))); } - fn add_methods<'lua,M:mlua::UserDataMethods<'lua,Self>>(methods:&mut M){ + fn add_methods>(methods:&mut M){ methods.add_method("components",|_,this,()|Ok(( this.0.translation.x, this.0.translation.y, diff --git a/src/runner/color3.rs b/src/runner/color3.rs index 7952a89..93b8c68 100644 --- a/src/runner/color3.rs +++ b/src/runner/color3.rs @@ -15,7 +15,7 @@ impl Into for Color3{ } } -pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table<'_>)->Result<(),mlua::Error>{ +pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{ let color3_table=lua.create_table()?; color3_table.raw_set("new", @@ -38,7 +38,7 @@ fn lerp(lhs:f32,rhs:f32,t:f32)->f32{ } impl mlua::UserData for Color3{ - fn add_fields<'lua,F:mlua::UserDataFields<'lua,Self>>(fields:&mut F){ + fn add_fields>(fields:&mut F){ fields.add_field_method_get("r",|_,this|Ok(this.r)); fields.add_field_method_set("r",|_,this,val|{ this.r=val; @@ -55,7 +55,7 @@ impl mlua::UserData for Color3{ Ok(()) }); } - fn add_methods<'lua,M:mlua::UserDataMethods<'lua,Self>>(methods:&mut M){ + fn add_methods>(methods:&mut M){ methods.add_method("Lerp",|_,this,(other,t):(Self,f32)| Ok(Color3::new( lerp(this.r,other.r,t), diff --git a/src/runner/enum.rs b/src/runner/enum.rs index 27f2df0..0b6bd47 100644 --- a/src/runner/enum.rs +++ b/src/runner/enum.rs @@ -2,7 +2,9 @@ use mlua::IntoLua; #[derive(Clone,Copy)] pub struct Enum(u32); +#[derive(Clone,Copy)] pub struct EnumItems; +#[derive(Clone,Copy)] pub struct EnumItem<'a>{ ed:&'a rbx_reflection::EnumDescriptor<'a>, } @@ -19,16 +21,16 @@ impl<'a> EnumItem<'a>{ } } -pub fn set_globals(_lua:&mlua::Lua,globals:&mlua::Table<'_>)->Result<(),mlua::Error>{ +pub fn set_globals(_lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{ globals.set("Enum",EnumItems) } impl mlua::UserData for EnumItem<'_>{ - fn add_fields<'lua,F:mlua::UserDataFields<'lua,Self>>(_fields:&mut F){ + fn add_fields>(_fields:&mut F){ } - fn add_methods<'lua,M:mlua::UserDataMethods<'lua,Self>>(methods:&mut M){ - methods.add_meta_function(mlua::MetaMethod::Index,|lua,(this,val):(EnumItem<'lua>,mlua::String)|{ - match this.ed.items.get(val.to_str()?){ + fn add_methods>(methods:&mut M){ + methods.add_meta_function(mlua::MetaMethod::Index,|lua,(this,val):(EnumItem<'_>,mlua::String)|{ + match this.ed.items.get(&*val.to_str()?){ Some(&id)=>Enum(id).into_lua(lua), None=>mlua::Value::Nil.into_lua(lua), } @@ -38,12 +40,12 @@ impl mlua::UserData for EnumItem<'_>{ type_from_lua_userdata_lua_lifetime!(EnumItem); impl mlua::UserData for EnumItems{ - fn add_fields<'lua,F:mlua::UserDataFields<'lua,Self>>(_fields:&mut F){ + fn add_fields>(_fields:&mut F){ } - fn add_methods<'lua,M:mlua::UserDataMethods<'lua,Self>>(methods:&mut M){ + fn add_methods>(methods:&mut M){ methods.add_meta_function(mlua::MetaMethod::Index,|lua,(_,val):(Self,mlua::String)|{ let db=rbx_reflection_database::get(); - match db.enums.get(val.to_str()?){ + match db.enums.get(&*val.to_str()?){ Some(ed)=>EnumItem::new(ed).into_lua(lua), None=>mlua::Value::Nil.into_lua(lua), } @@ -53,9 +55,9 @@ impl mlua::UserData for EnumItems{ type_from_lua_userdata!(EnumItems); impl mlua::UserData for Enum{ - fn add_fields<'lua,F:mlua::UserDataFields<'lua,Self>>(_fields:&mut F){ + fn add_fields>(_fields:&mut F){ } - fn add_methods<'lua,M:mlua::UserDataMethods<'lua,Self>>(_methods:&mut M){ + fn add_methods>(_methods:&mut M){ } } type_from_lua_userdata!(Enum); diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 06355f9..0668e38 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -1,16 +1,21 @@ -use mlua::IntoLua; +use std::collections::{hash_map::Entry,HashMap}; + +use mlua::{FromLuaMulti,IntoLua,IntoLuaMulti}; use rbx_types::Ref; use rbx_dom_weak::{InstanceBuilder,WeakDom}; use super::vector3::Vector3; -pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table<'_>)->Result<(),mlua::Error>{ +pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{ + //class functions store + lua.set_app_data(ClassFunctions::default()); + let instance_table=lua.create_table()?; //Instance.new instance_table.raw_set("new", lua.create_function(|lua,(class_name,parent):(mlua::String,Option)|{ - let class_name_str=class_name.to_str()?; + let class_name_str=&*class_name.to_str()?; let parent=parent.ok_or(mlua::Error::runtime("Nil Parent not yet supported"))?; dom_mut(lua,|dom|{ //TODO: Nil instances @@ -29,6 +34,10 @@ fn dom_mut(lua:&mlua::Lua,mut f:impl FnMut(&mut WeakDom)->mlua::Result)->m let mut dom=lua.app_data_mut::<&'static mut WeakDom>().ok_or(mlua::Error::runtime("DataModel missing"))?; f(&mut *dom) } +fn class_functions_mut(lua:&mlua::Lua,mut f:impl FnMut(&mut ClassFunctions)->mlua::Result)->mlua::Result{ + let mut cf=lua.app_data_mut::().ok_or(mlua::Error::runtime("ClassFunctions missing"))?; + f(&mut *cf) +} fn coerce_float32(value:&mlua::Value)->Option{ match value{ @@ -48,6 +57,17 @@ fn get_full_name(dom:&rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance)->S } full_name } +//helper function for script +pub fn get_name_source(lua:&mlua::Lua,script:Instance)->Result<(String,String),mlua::Error>{ + dom_mut(lua,|dom|{ + let instance=script.get(dom)?; + let source=match instance.properties.get("Source"){ + Some(rbx_dom_weak::types::Variant::String(s))=>s.clone(), + _=>Err(mlua::Error::external("Missing script.Source"))?, + }; + Ok((get_full_name(dom,instance),source)) + }) +} pub fn find_first_child<'a>(dom:&'a rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance,name:&str)->Option<&'a rbx_dom_weak::Instance>{ instance.children().iter().filter_map(|&r|dom.get_by_ref(r)).find(|inst|inst.name==name) @@ -63,63 +83,22 @@ pub fn find_first_descendant_of_class<'a>(dom:&'a rbx_dom_weak::WeakDom,instance dom.descendants_of(instance.referent()).find(|&inst|inst.class==class) } -//workaround until I have an enum of classes -struct Dereferent(Ref); -impl mlua::UserData for Dereferent{} -type_from_lua_userdata!(Dereferent); -impl Referent for Dereferent{ - fn referent(&self)->Ref{ - self.0 +#[derive(Clone,Copy)] +pub struct Instance{ + referent:Ref, +} +impl Instance{ + pub const fn new(referent:Ref)->Self{ + Self{referent} + } + pub fn get<'a>(&self,dom:&'a WeakDom)->mlua::Result<&'a rbx_dom_weak::Instance>{ + dom.get_by_ref(self.referent).ok_or(mlua::Error::runtime("Instance missing")) + } + pub fn get_mut<'a>(&self,dom:&'a mut WeakDom)->mlua::Result<&'a mut rbx_dom_weak::Instance>{ + dom.get_by_ref_mut(self.referent).ok_or(mlua::Error::runtime("Instance missing")) } } - -trait Referent{ - fn referent(&self)->Ref; - fn get<'a>(&self,dom:&'a WeakDom)->mlua::Result<&'a rbx_dom_weak::Instance>{ - dom.get_by_ref(self.referent()).ok_or(mlua::Error::runtime("Instance missing")) - } - fn get_mut<'a>(&self,dom:&'a mut WeakDom)->mlua::Result<&'a mut rbx_dom_weak::Instance>{ - dom.get_by_ref_mut(self.referent()).ok_or(mlua::Error::runtime("Instance missing")) - } -} - -macro_rules! class{ - ($class:ident)=>{ - pub struct $class{ - referent:Ref, - } - impl $class{ - pub const fn new(referent:Ref)->Self{ - Self{referent} - } - } - impl Referent for $class{ - fn referent(&self)->Ref{ - self.referent - } - } - type_from_lua_userdata!($class); - }; -} -macro_rules! class_composition{ - ($class:ident,($($superclass:ident),*))=>{ - impl mlua::UserData for $class{ - fn add_fields<'lua,F:mlua::UserDataFields<'lua,Self>>(fields:&mut F){ - fields.add_field_method_get("Referent",|_,this|{ - Ok(Dereferent(this.referent())) - }); - $( - $superclass::composition_add_fields(fields); - )* - } - fn add_methods<'lua,M:mlua::UserDataMethods<'lua,Self>>(methods:&mut M){ - $( - $superclass::composition_add_methods(methods); - )* - } - } - }; -} +type_from_lua_userdata!(Instance); //TODO: update rbx_reflection and use dom.superclasses_iter pub struct SuperClassIter<'a> { @@ -140,21 +119,18 @@ impl<'a> Iterator for SuperClassIter<'a> { } } -class!(Instance); -class_composition!(Instance,(Instance)); - -impl Instance{ - fn composition_add_fields<'lua,T:Referent,F:mlua::UserDataFields<'lua,T>>(fields:&mut F){ +impl mlua::UserData for Instance{ + fn add_fields>(fields:&mut F){ fields.add_field_method_get("Parent",|lua,this|{ dom_mut(lua,|dom|{ let instance=this.get(dom)?; Ok(Instance::new(instance.parent())) }) }); - fields.add_field_method_set("Parent",|lua,this,val:mlua::AnyUserData|{ - let Dereferent(referent)=mlua::AnyUserDataExt::get(&val,"Referent")?; + fields.add_field_method_set("Parent",|lua,this,val:Option|{ + let parent=val.ok_or(mlua::Error::runtime("Nil Parent not yet supported"))?; dom_mut(lua,|dom|{ - dom.transfer_within(this.referent(),referent); + dom.transfer_within(this.referent,parent.referent); Ok(()) }) }); @@ -179,7 +155,7 @@ impl Instance{ }) }); } - fn composition_add_methods<'lua,T:Referent,M:mlua::UserDataMethods<'lua,T>>(methods:&mut M){ + fn add_methods>(methods:&mut M){ methods.add_method("GetChildren",|lua,this,_:()| dom_mut(lua,|dom|{ let instance=this.get(dom)?; @@ -192,8 +168,8 @@ impl Instance{ Ok(children) }) ); - let ffc=|lua,this:&T,(name,search_descendants):(mlua::String,Option)|{ - let name_str=name.to_str()?; + fn ffc(lua:&mlua::Lua,this:&Instance,(name,search_descendants):(mlua::String,Option))->mlua::Result>{ + let name_str=&*name.to_str()?; dom_mut(lua,|dom|{ let instance=this.get(dom)?; Ok( @@ -206,11 +182,11 @@ impl Instance{ ) ) }) - }; + } methods.add_method("FindFirstChild",ffc); methods.add_method("WaitForChild",ffc); methods.add_method("FindFirstChildOfClass",|lua,this,(class,search_descendants):(mlua::String,Option)|{ - let class_str=class.to_str()?; + let class_str=&*class.to_str()?; dom_mut(lua,|dom|{ Ok( match search_descendants.unwrap_or(false){ @@ -226,7 +202,7 @@ impl Instance{ methods.add_method("GetDescendants",|lua,this,_:()| dom_mut(lua,|dom|{ let children:Vec<_>=dom - .descendants_of(this.referent()) + .descendants_of(this.referent) .map(|instance| Instance::new(instance.referent()) ) @@ -237,33 +213,58 @@ impl Instance{ methods.add_method("IsA",|lua,this,classname:mlua::String| dom_mut(lua,|dom|{ let instance=this.get(dom)?; - Ok(crate::context::class_is_a(instance.class.as_str(),classname.to_str()?)) + Ok(crate::context::class_is_a(instance.class.as_str(),&*classname.to_str()?)) }) ); methods.add_method("Destroy",|lua,this,()| dom_mut(lua,|dom|{ - dom.destroy(this.referent()); + dom.destroy(this.referent); Ok(()) }) ); - methods.add_meta_function(mlua::MetaMethod::Index,|lua,(this,index):(mlua::AnyUserData,mlua::String)|{ - let index_str=index.to_str()?; - let dereferent:Dereferent=mlua::AnyUserDataExt::get(&this,"Referent")?; + methods.add_meta_function(mlua::MetaMethod::ToString,|lua,this:Instance|{ dom_mut(lua,|dom|{ - let instance=dereferent.get(dom)?; + let instance=this.get(dom)?; + Ok(instance.name.clone()) + }) + }); + methods.add_meta_function(mlua::MetaMethod::Index,|lua,(this,index):(Instance,mlua::String)|{ + let index_str=&*index.to_str()?; + dom_mut(lua,|dom|{ + let instance=this.get(dom)?; + //println!("__index t={} i={index:?}",instance.name); + let db=rbx_reflection_database::get(); + let class=db.classes.get(instance.class.as_str()).ok_or(mlua::Error::runtime("Class missing"))?; //Find existing property match instance.properties.get(index_str) //Find default value - .or_else(||{ - let db=rbx_reflection_database::get(); - db.classes.get(instance.class.as_str()).and_then(|cd| - db.find_default_property(cd,index_str) - ) - }) + .or_else(||db.find_default_property(class,index_str)) { + Some(&rbx_types::Variant::Int32(val))=>return Ok(val.into_lua(lua)), + Some(&rbx_types::Variant::Int64(val))=>return Ok(val.into_lua(lua)), + Some(&rbx_types::Variant::Float32(val))=>return Ok(val.into_lua(lua)), + Some(&rbx_types::Variant::Float64(val))=>return Ok(val.into_lua(lua)), Some(&rbx_types::Variant::CFrame(cf))=>return Ok(Into::::into(cf).into_lua(lua)), Some(&rbx_types::Variant::Vector3(v))=>return Ok(Into::::into(v).into_lua(lua)), - _=>(), + other=>println!("instance.properties.get(i)={other:?}"), + } + //find a function with a matching name + if let Some(function)=class_functions_mut(lua,|cf|{ + let mut iter=SuperClassIter{ + database:db, + descriptor:Some(class), + }; + Ok(loop{ + match iter.next(){ + Some(class)=>match cf.get_or_create_class_function(lua,&class.name,index_str)?{ + Some(function)=>break Some(function), + None=>(), + }, + None=>break None, + } + }) + })?{ + return Ok(function.into_lua(lua)); } //find a child with a matching name Ok( @@ -273,12 +274,11 @@ impl Instance{ ) }) }); - methods.add_meta_function(mlua::MetaMethod::NewIndex,|lua,(this,index,value):(mlua::AnyUserData,mlua::String,mlua::Value)|{ - let dereferent:Dereferent=mlua::AnyUserDataExt::get(&this,"Referent")?; + methods.add_meta_function(mlua::MetaMethod::NewIndex,|lua,(this,index,value):(Instance,mlua::String,mlua::Value)|{ dom_mut(lua,|dom|{ - let instance=dereferent.get_mut(dom)?; + let instance=this.get_mut(dom)?; //println!("__newindex t={} i={index:?} v={value:?}",instance.name); - let index_str=index.to_str()?; + let index_str=&*index.to_str()?; let db=rbx_reflection_database::get(); let class=db.classes.get(instance.class.as_str()).ok_or(mlua::Error::runtime("Class missing"))?; let mut iter=SuperClassIter{ @@ -301,7 +301,7 @@ impl Instance{ &mlua::Value::Number(num)=>Ok(rbx_types::Enum::from_u32(num as u32)), mlua::Value::String(s)=>{ let e=db.enums.get(enum_name).ok_or(mlua::Error::runtime("Database DataType Enum name does not exist"))?; - Ok(rbx_types::Enum::from_u32(*e.items.get(s.to_str()?).ok_or(mlua::Error::runtime("Invalid enum item"))?)) + Ok(rbx_types::Enum::from_u32(*e.items.get(&*s.to_str()?).ok_or(mlua::Error::runtime("Invalid enum item"))?)) }, mlua::Value::UserData(any_user_data)=>{ let e:super::r#enum::Enum=any_user_data.take()?; @@ -331,81 +331,103 @@ impl Instance{ } } -class!(DataModel); -class_composition!(DataModel,(Instance,DataModel)); -impl DataModel{ - fn composition_add_fields<'lua,T:Referent,F:mlua::UserDataFields<'lua,T>>(fields:&mut F){ - fields.add_field_method_get("workspace",|lua,this|{ +/// A class function definition shorthand. +macro_rules! cf{ + ($f:expr)=>{ + |lua,this|$f(lua,FromLuaMulti::from_lua_multi(this,lua)?)?.into_lua_multi(lua) + }; +} +type FPointer=fn(&mlua::Lua,mlua::MultiValue)->mlua::Result; +/// A double hash map of function pointers. +/// The class tree is walked by the Instance.__index metamethod to find available class methods. +static CLASS_FUNCTION_DATABASE:phf::Map<&str,phf::Map<&str,FPointer>>=phf::phf_map!{ + "DataModel"=>phf::phf_map!{ + "GetService"=>cf!(|lua,(_this,service):(Instance,mlua::String)|{ dom_mut(lua,|dom|{ - Ok(find_first_child_of_class(dom,this.get(dom)?,"Workspace") - .map(|inst|Workspace::new(inst.referent())) - ) - }) - }); - fields.add_field_method_get("PlaceId",|lua,this|{ - Ok(mlua::Value::Integer(0)) - }); - } - fn composition_add_methods<'lua,T,M:mlua::UserDataMethods<'lua,T>>(methods:&mut M){ - methods.add_method("GetService",|lua,this,service:String| - dom_mut(lua,|dom|{ - match service.as_str(){ + //dom.root_ref()==this.referent ? + match &*service.to_str()?{ "Lighting"=>{ let referent=find_first_child_of_class(dom,dom.root(),"Lighting") .map(|instance|instance.referent()) .unwrap_or_else(|| dom.insert(dom.root_ref(),InstanceBuilder::new("Lighting")) ); - Lighting::new(referent).into_lua(lua) + Ok(Instance::new(referent)) }, - other=>Err::(mlua::Error::runtime(format!("Service '{other}' not supported"))), + other=>Err::(mlua::Error::runtime(format!("Service '{other}' not supported"))), } }) - ); - } -} - -class!(Workspace); -class_composition!(Workspace,(Instance,Workspace)); -impl Workspace{ - fn composition_add_fields<'lua,T:Referent,F:mlua::UserDataFields<'lua,T>>(fields:&mut F){ - fields.add_field_method_get("Terrain",|lua,this|{ + }), + "workspace"=>cf!(|lua,this:Instance|{ dom_mut(lua,|dom|{ - Ok(find_first_child_of_class(dom,this.get(dom)?,"Terrain") - .map(|inst|Terrain::new(inst.referent())) + Ok(find_first_child_of_class(dom,this.get(dom)?,"Workspace") + .map(|inst|Instance::new(inst.referent())) ) }) - }); - } - fn composition_add_methods<'lua,T,M:mlua::UserDataMethods<'lua,T>>(_methods:&mut M){ - } -} -class!(Lighting); -class_composition!(Lighting,(Instance)); + }), + }, + "Workspace"=>phf::phf_map!{ + "Terrain"=>cf!(|lua,this:Instance|{ + dom_mut(lua,|dom|{ + Ok(find_first_child_of_class(dom,this.get(dom)?,"Terrain") + .map(|inst|Instance::new(inst.referent())) + ) + }) + }), + }, + "Terrain"=>phf::phf_map!{ + "FillBlock"=>cf!(|_lua,_:(Instance,super::cframe::CFrame,Vector3,super::r#enum::Enum)|mlua::Result::Ok(())) + }, +}; -class!(Script); -class_composition!(Script,(Instance)); -impl Script{ - pub fn get_name_source(&self,lua:&mlua::Lua)->Result<(String,String),mlua::Error>{ - dom_mut(lua,|dom|{ - let instance=self.get(dom)?; - let source=match instance.properties.get("Source"){ - Some(rbx_dom_weak::types::Variant::String(s))=>s.clone(), - _=>Err(mlua::Error::external("Missing script.Source"))?, - }; - Ok((get_full_name(dom,instance),source)) - }) - } -} - -class!(Terrain); -class_composition!(Terrain,(Instance,Terrain)); -impl Terrain{ - fn composition_add_fields<'lua,T:Referent,F:mlua::UserDataFields<'lua,T>>(fields:&mut F){ - } - fn composition_add_methods<'lua,T,M:mlua::UserDataMethods<'lua,T>>(methods:&mut M){ - methods.add_method("FillBlock",|lua,this,_:(super::cframe::CFrame,Vector3,super::r#enum::Enum)| - Ok(())//Ok(mlua::Value::Nil) - ) +/// A store of created functions for each Roblox class. +/// Functions are created the first time they are accessed and stored in this data structure. +#[derive(Default)] +struct ClassFunctions{ + classes:HashMap<&'static str,//ClassName + HashMap<&'static str,//Function name + mlua::Function + > + > +} +impl ClassFunctions{ + /// Someone please rewrite this, all it's supposed to do is + /// return self.classes[class][index] or create the function in the hashmap and then return it + fn get_or_create_class_function(&mut self,lua:&mlua::Lua,class:&str,index:&str)->mlua::Result>{ + // Use get_entry to get the &'static str key of the database + // and use it as a key for the classes hashmap + let f=match CLASS_FUNCTION_DATABASE.get_entry(class){ + Some((&static_class_str,class_functions))=>{ + match self.classes.entry(static_class_str){ + Entry::Occupied(mut occupied_entry)=>{ + match class_functions.get_entry(index){ + Some((&static_index_str,function_pointer))=>{ + match occupied_entry.get_mut().entry(static_index_str){ + Entry::Occupied(occupied_entry)=>{ + Some(occupied_entry.get().clone()) + }, + Entry::Vacant(vacant_entry)=>{ + Some(vacant_entry.insert(lua.create_function(function_pointer)?).clone()) + }, + } + }, + None=>None, + } + }, + Entry::Vacant(vacant_entry)=>{ + match class_functions.get_entry(index){ + Some((&static_index_str,function_pointer))=>{ + let mut h=HashMap::new(); + h.entry(static_index_str).or_insert(lua.create_function(function_pointer)?); + vacant_entry.insert(h).get(static_index_str).map(|f|f.clone()) + }, + None=>None, + } + }, + } + }, + None=>None, + }; + Ok(f) } } diff --git a/src/runner/macros.rs b/src/runner/macros.rs index 8121af8..180c020 100644 --- a/src/runner/macros.rs +++ b/src/runner/macros.rs @@ -1,9 +1,9 @@ macro_rules! type_from_lua_userdata{ ($asd:ident)=>{ - impl<'lua> mlua::FromLua<'lua> for $asd{ - fn from_lua(value:mlua::Value<'lua>,_lua:&'lua mlua::Lua)->Result{ + impl mlua::FromLua for $asd{ + fn from_lua(value:mlua::Value,_lua:&mlua::Lua)->Result{ match value{ - mlua::Value::UserData(ud)=>ud.take(), + mlua::Value::UserData(ud)=>Ok(*ud.borrow::()?), other=>Err(mlua::Error::runtime(format!("Expected {} got {:?}",stringify!($asd),other))), } } @@ -12,10 +12,10 @@ macro_rules! type_from_lua_userdata{ } macro_rules! type_from_lua_userdata_lua_lifetime{ ($asd:ident)=>{ - impl<'lua> mlua::FromLua<'lua> for $asd<'lua>{ - fn from_lua(value:mlua::Value<'lua>,_lua:&'lua mlua::Lua)->Result{ + impl mlua::FromLua for $asd<'static>{ + fn from_lua(value:mlua::Value,_lua:&mlua::Lua)->Result{ match value{ - mlua::Value::UserData(ud)=>ud.take(), + mlua::Value::UserData(ud)=>Ok(*ud.borrow::()?), other=>Err(mlua::Error::runtime(format!("Expected {} got {:?}",stringify!($asd),other))), } } diff --git a/src/runner/runner.rs b/src/runner/runner.rs index b603aa0..48dee06 100644 --- a/src/runner/runner.rs +++ b/src/runner/runner.rs @@ -53,8 +53,8 @@ impl Runner{ pub fn runnable_context_with_services<'a>(self,context:&'a mut Context,services:&crate::context::Services)->Result,Error>{ { let globals=self.lua.globals(); - globals.set("game",super::instance::DataModel::new(services.game)).map_err(Error::RustLua)?; - globals.set("workspace",super::instance::Workspace::new(services.workspace)).map_err(Error::RustLua)?; + globals.set("game",super::instance::Instance::new(services.game)).map_err(Error::RustLua)?; + globals.set("workspace",super::instance::Instance::new(services.workspace)).map_err(Error::RustLua)?; } //this makes set_app_data shut up about the lifetime self.lua.set_app_data::<&'static mut rbx_dom_weak::WeakDom>(unsafe{core::mem::transmute(&mut context.dom)}); @@ -77,8 +77,8 @@ impl Runnable<'_>{ lua:self.lua, } } - pub fn run_script(&self,script:super::instance::Script)->Result<(),Error>{ - let (name,source)=script.get_name_source(&self.lua).map_err(Error::RustLua)?; + pub fn run_script(&self,script:super::instance::Instance)->Result<(),Error>{ + let (name,source)=super::instance::get_name_source(&self.lua,script).map_err(Error::RustLua)?; self.lua.globals().set("script",script).map_err(Error::RustLua)?; self.lua.load(source.as_str()) .set_name(name) diff --git a/src/runner/vector3.rs b/src/runner/vector3.rs index 7b33eec..2e543de 100644 --- a/src/runner/vector3.rs +++ b/src/runner/vector3.rs @@ -7,7 +7,7 @@ impl Vector3{ } } -pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table<'_>)->Result<(),mlua::Error>{ +pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{ let vector3_table=lua.create_table()?; //Vector3.new @@ -35,7 +35,7 @@ impl From for Vector3{ } impl mlua::UserData for Vector3{ - fn add_fields<'lua,F: mlua::UserDataFields<'lua,Self>>(fields: &mut F){ + fn add_fields>(fields:&mut F){ fields.add_field_method_get("magnitude",|_,this|Ok(this.0.length())); fields.add_field_method_get("x",|_,this|Ok(this.0.x)); fields.add_field_method_set("x",|_,this,val|{ @@ -54,7 +54,7 @@ impl mlua::UserData for Vector3{ }); } - fn add_methods<'lua,M: mlua::UserDataMethods<'lua,Self>>(methods:&mut M){ + fn add_methods>(methods:&mut M){ //methods.add_method("area",|_,this,()| Ok(this.length * this.width)); methods.add_meta_function(mlua::MetaMethod::Add,|_,(this,val):(Self,Self)|Ok(Self(this.0+val.0))); From 35d60cde16aa03b704579367793834449b856976 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sat, 5 Oct 2024 21:31:53 -0700 Subject: [PATCH 084/129] todo: use macros for class function database --- src/runner/instance.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 0668e38..2e748ca 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -338,6 +338,7 @@ macro_rules! cf{ }; } type FPointer=fn(&mlua::Lua,mlua::MultiValue)->mlua::Result; +// TODO: use macros to define these with better organization /// A double hash map of function pointers. /// The class tree is walked by the Instance.__index metamethod to find available class methods. static CLASS_FUNCTION_DATABASE:phf::Map<&str,phf::Map<&str,FPointer>>=phf::phf_map!{ From d8aacb9ed252e773c2aa7aae24ed1b72264988da Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sat, 5 Oct 2024 21:46:09 -0700 Subject: [PATCH 085/129] class function database can only return functions, not values --- src/context.rs | 11 ++++++++++- src/runner/instance.rs | 16 ---------------- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/src/context.rs b/src/context.rs index c86320c..92b1424 100644 --- a/src/context.rs +++ b/src/context.rs @@ -60,10 +60,19 @@ impl Context{ //insert services let game=self.dom.root_ref(); + let terrain_bldr=InstanceBuilder::new("Terrain"); let workspace=self.dom.insert(game, InstanceBuilder::new("Workspace") - .with_child(InstanceBuilder::new("Terrain")) + //Set Workspace.Terrain property equal to Terrain + .with_property("Terrain",terrain_bldr.referent()) + .with_child(terrain_bldr) ); + { + //Lowercase and upper case workspace property! + let game=self.dom.root_mut(); + game.properties.insert("workspace".to_owned(),rbx_types::Variant::Ref(workspace)); + game.properties.insert("Workspace".to_owned(),rbx_types::Variant::Ref(workspace)); + } self.dom.insert(game,InstanceBuilder::new("Lighting")); //transfer original root instances into workspace diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 2e748ca..3d9e257 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -359,22 +359,6 @@ static CLASS_FUNCTION_DATABASE:phf::Map<&str,phf::Map<&str,FPointer>>=phf::phf_m } }) }), - "workspace"=>cf!(|lua,this:Instance|{ - dom_mut(lua,|dom|{ - Ok(find_first_child_of_class(dom,this.get(dom)?,"Workspace") - .map(|inst|Instance::new(inst.referent())) - ) - }) - }), - }, - "Workspace"=>phf::phf_map!{ - "Terrain"=>cf!(|lua,this:Instance|{ - dom_mut(lua,|dom|{ - Ok(find_first_child_of_class(dom,this.get(dom)?,"Terrain") - .map(|inst|Instance::new(inst.referent())) - ) - }) - }), }, "Terrain"=>phf::phf_map!{ "FillBlock"=>cf!(|_lua,_:(Instance,super::cframe::CFrame,Vector3,super::r#enum::Enum)|mlua::Result::Ok(())) From 58edaf329143bd7351ddeb717fd7963506079a79 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sat, 5 Oct 2024 21:52:12 -0700 Subject: [PATCH 086/129] Instance.__index whole thing was wrong --- src/runner/instance.rs | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 3d9e257..c38e7e4 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -240,12 +240,12 @@ impl mlua::UserData for Instance{ //Find default value .or_else(||db.find_default_property(class,index_str)) { - Some(&rbx_types::Variant::Int32(val))=>return Ok(val.into_lua(lua)), - Some(&rbx_types::Variant::Int64(val))=>return Ok(val.into_lua(lua)), - Some(&rbx_types::Variant::Float32(val))=>return Ok(val.into_lua(lua)), - Some(&rbx_types::Variant::Float64(val))=>return Ok(val.into_lua(lua)), - Some(&rbx_types::Variant::CFrame(cf))=>return Ok(Into::::into(cf).into_lua(lua)), - Some(&rbx_types::Variant::Vector3(v))=>return Ok(Into::::into(v).into_lua(lua)), + Some(&rbx_types::Variant::Int32(val))=>return val.into_lua(lua), + Some(&rbx_types::Variant::Int64(val))=>return val.into_lua(lua), + Some(&rbx_types::Variant::Float32(val))=>return val.into_lua(lua), + Some(&rbx_types::Variant::Float64(val))=>return val.into_lua(lua), + Some(&rbx_types::Variant::CFrame(cf))=>return Into::::into(cf).into_lua(lua), + Some(&rbx_types::Variant::Vector3(v))=>return Into::::into(v).into_lua(lua), other=>println!("instance.properties.get(i)={other:?}"), } //find a function with a matching name @@ -264,14 +264,12 @@ impl mlua::UserData for Instance{ } }) })?{ - return Ok(function.into_lua(lua)); + return function.into_lua(lua); } //find a child with a matching name - Ok( - find_first_child(dom,instance,index_str) - .map(|instance|Instance::new(instance.referent())) - .into_lua(lua) - ) + find_first_child(dom,instance,index_str) + .map(|instance|Instance::new(instance.referent())) + .into_lua(lua) }) }); methods.add_meta_function(mlua::MetaMethod::NewIndex,|lua,(this,index,value):(Instance,mlua::String,mlua::Value)|{ From a23e8fc36f7501b64f9cece59559a1d8d8e56277 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sat, 5 Oct 2024 21:52:41 -0700 Subject: [PATCH 087/129] return Instance from Instance.__Index --- src/runner/instance.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index c38e7e4..d0d1a77 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -244,6 +244,7 @@ impl mlua::UserData for Instance{ Some(&rbx_types::Variant::Int64(val))=>return val.into_lua(lua), Some(&rbx_types::Variant::Float32(val))=>return val.into_lua(lua), Some(&rbx_types::Variant::Float64(val))=>return val.into_lua(lua), + Some(&rbx_types::Variant::Ref(val))=>return Instance::new(val).into_lua(lua), Some(&rbx_types::Variant::CFrame(cf))=>return Into::::into(cf).into_lua(lua), Some(&rbx_types::Variant::Vector3(v))=>return Into::::into(v).into_lua(lua), other=>println!("instance.properties.get(i)={other:?}"), From fac1f318d7e4f50b85a17e0309f11a1d23890124 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sat, 5 Oct 2024 21:54:01 -0700 Subject: [PATCH 088/129] v0.4.3 rewrite Instances to be a single UserData type using a class function database --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 260d89e..24a3606 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -402,7 +402,7 @@ dependencies = [ [[package]] name = "roblox_emulator" -version = "0.4.2" +version = "0.4.3" dependencies = [ "glam", "mlua", diff --git a/Cargo.toml b/Cargo.toml index 0172374..610718c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "roblox_emulator" -version = "0.4.2" +version = "0.4.3" edition = "2021" repository = "https://git.itzana.me/StrafesNET/roblox_emulator" license = "MIT OR Apache-2.0" From 849b0813b9ff6057fd9b1fcb501dea3c562ff2f5 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sat, 5 Oct 2024 22:03:51 -0700 Subject: [PATCH 089/129] change cf macro to include Instance as the first argument --- src/runner/instance.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index d0d1a77..2129f7c 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -333,16 +333,20 @@ impl mlua::UserData for Instance{ /// A class function definition shorthand. macro_rules! cf{ ($f:expr)=>{ - |lua,this|$f(lua,FromLuaMulti::from_lua_multi(this,lua)?)?.into_lua_multi(lua) + |lua,args|{ + //TODO: make this not suck. two fully general conversions? really? + let (this,args):(Instance,mlua::MultiValue)=FromLuaMulti::from_lua_multi(args,lua)?; + $f(lua,this,FromLuaMulti::from_lua_multi(args,lua)?)?.into_lua_multi(lua) + } }; } -type FPointer=fn(&mlua::Lua,mlua::MultiValue)->mlua::Result; +type ClassFunctionPointer=fn(&mlua::Lua,mlua::MultiValue)->mlua::Result; // TODO: use macros to define these with better organization /// A double hash map of function pointers. /// The class tree is walked by the Instance.__index metamethod to find available class methods. -static CLASS_FUNCTION_DATABASE:phf::Map<&str,phf::Map<&str,FPointer>>=phf::phf_map!{ +static CLASS_FUNCTION_DATABASE:phf::Map<&str,phf::Map<&str,ClassFunctionPointer>>=phf::phf_map!{ "DataModel"=>phf::phf_map!{ - "GetService"=>cf!(|lua,(_this,service):(Instance,mlua::String)|{ + "GetService"=>cf!(|lua,_this,service:mlua::String|{ dom_mut(lua,|dom|{ //dom.root_ref()==this.referent ? match &*service.to_str()?{ @@ -360,7 +364,7 @@ static CLASS_FUNCTION_DATABASE:phf::Map<&str,phf::Map<&str,FPointer>>=phf::phf_m }), }, "Terrain"=>phf::phf_map!{ - "FillBlock"=>cf!(|_lua,_:(Instance,super::cframe::CFrame,Vector3,super::r#enum::Enum)|mlua::Result::Ok(())) + "FillBlock"=>cf!(|_lua,_,_:(super::cframe::CFrame,Vector3,super::r#enum::Enum)|mlua::Result::Ok(())) }, }; From de363bc271e7cd8486abef31113bbd4bb194fb84 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sat, 5 Oct 2024 22:17:56 -0700 Subject: [PATCH 090/129] no print when none --- src/runner/instance.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 2129f7c..b088f38 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -247,6 +247,7 @@ impl mlua::UserData for Instance{ Some(&rbx_types::Variant::Ref(val))=>return Instance::new(val).into_lua(lua), Some(&rbx_types::Variant::CFrame(cf))=>return Into::::into(cf).into_lua(lua), Some(&rbx_types::Variant::Vector3(v))=>return Into::::into(v).into_lua(lua), + None=>(), other=>println!("instance.properties.get(i)={other:?}"), } //find a function with a matching name From 97e2010826b6658b2f7e19722530b9345b128e93 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sat, 5 Oct 2024 22:30:17 -0700 Subject: [PATCH 091/129] split type onto multiple lines --- src/runner/instance.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index b088f38..2da9a52 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -345,7 +345,12 @@ type ClassFunctionPointer=fn(&mlua::Lua,mlua::MultiValue)->mlua::Result>=phf::phf_map!{ +type CFD=phf::Map<&'static str,// Class name + phf::Map<&'static str,// Method name + ClassFunctionPointer + > +>; +static CLASS_FUNCTION_DATABASE:CFD=phf::phf_map!{ "DataModel"=>phf::phf_map!{ "GetService"=>cf!(|lua,_this,service:mlua::String|{ dom_mut(lua,|dom|{ @@ -374,7 +379,7 @@ static CLASS_FUNCTION_DATABASE:phf::Map<&str,phf::Map<&str,ClassFunctionPointer> #[derive(Default)] struct ClassFunctions{ classes:HashMap<&'static str,//ClassName - HashMap<&'static str,//Function name + HashMap<&'static str,//Method name mlua::Function > > From bf0c4f74c374927edff332f8d00f2aac88c8c322 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sat, 5 Oct 2024 22:31:48 -0700 Subject: [PATCH 092/129] error instead of print, expanded message --- src/runner/instance.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 2da9a52..3059157 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -248,7 +248,7 @@ impl mlua::UserData for Instance{ Some(&rbx_types::Variant::CFrame(cf))=>return Into::::into(cf).into_lua(lua), Some(&rbx_types::Variant::Vector3(v))=>return Into::::into(v).into_lua(lua), None=>(), - other=>println!("instance.properties.get(i)={other:?}"), + other=>return Err(mlua::Error::runtime(format!("Instance.__index Unsupported property type instance={} index={index_str} value={other:?}",instance.name))), } //find a function with a matching name if let Some(function)=class_functions_mut(lua,|cf|{ From 082de122b11b3b17c3a80e48e49239aced428dfd Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sun, 6 Oct 2024 10:26:58 -0700 Subject: [PATCH 093/129] fix double convert --- src/runner/instance.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 3059157..2286f4c 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -1,6 +1,6 @@ use std::collections::{hash_map::Entry,HashMap}; -use mlua::{FromLuaMulti,IntoLua,IntoLuaMulti}; +use mlua::{FromLua,FromLuaMulti,IntoLua,IntoLuaMulti}; use rbx_types::Ref; use rbx_dom_weak::{InstanceBuilder,WeakDom}; @@ -334,9 +334,8 @@ impl mlua::UserData for Instance{ /// A class function definition shorthand. macro_rules! cf{ ($f:expr)=>{ - |lua,args|{ - //TODO: make this not suck. two fully general conversions? really? - let (this,args):(Instance,mlua::MultiValue)=FromLuaMulti::from_lua_multi(args,lua)?; + |lua,mut args|{ + let this=Instance::from_lua(args.pop_front().unwrap_or(mlua::Value::Nil),lua)?; $f(lua,this,FromLuaMulti::from_lua_multi(args,lua)?)?.into_lua_multi(lua) } }; From 726ffeca213902285ee8a0320e9eba9e13c269e0 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sun, 6 Oct 2024 10:41:42 -0700 Subject: [PATCH 094/129] ClassFunction exceptional simplification --- src/runner/instance.rs | 50 ++++++++++++------------------------------ 1 file changed, 14 insertions(+), 36 deletions(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 2286f4c..80dedd5 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -1,4 +1,4 @@ -use std::collections::{hash_map::Entry,HashMap}; +use std::collections::HashMap; use mlua::{FromLua,FromLuaMulti,IntoLua,IntoLuaMulti}; use rbx_types::Ref; @@ -384,43 +384,21 @@ struct ClassFunctions{ > } impl ClassFunctions{ - /// Someone please rewrite this, all it's supposed to do is /// return self.classes[class][index] or create the function in the hashmap and then return it fn get_or_create_class_function(&mut self,lua:&mlua::Lua,class:&str,index:&str)->mlua::Result>{ - // Use get_entry to get the &'static str key of the database + // Use get_entry to get the &'static str keys of the database // and use it as a key for the classes hashmap - let f=match CLASS_FUNCTION_DATABASE.get_entry(class){ - Some((&static_class_str,class_functions))=>{ - match self.classes.entry(static_class_str){ - Entry::Occupied(mut occupied_entry)=>{ - match class_functions.get_entry(index){ - Some((&static_index_str,function_pointer))=>{ - match occupied_entry.get_mut().entry(static_index_str){ - Entry::Occupied(occupied_entry)=>{ - Some(occupied_entry.get().clone()) - }, - Entry::Vacant(vacant_entry)=>{ - Some(vacant_entry.insert(lua.create_function(function_pointer)?).clone()) - }, - } - }, - None=>None, - } - }, - Entry::Vacant(vacant_entry)=>{ - match class_functions.get_entry(index){ - Some((&static_index_str,function_pointer))=>{ - let mut h=HashMap::new(); - h.entry(static_index_str).or_insert(lua.create_function(function_pointer)?); - vacant_entry.insert(h).get(static_index_str).map(|f|f.clone()) - }, - None=>None, - } - }, - } - }, - None=>None, - }; - Ok(f) + if let Some((&static_class_str,class_functions))=CLASS_FUNCTION_DATABASE.get_entry(class){ + if let Some((&static_index_str,function_pointer))=class_functions.get_entry(index){ + return Ok(Some( + self.classes.entry(static_class_str) + .or_insert_with(||HashMap::new()) + .entry(static_index_str) + .or_insert(lua.create_function(function_pointer)?) + .clone() + )) + } + } + return Ok(None) } } From 09dd44294850e2b2e9ad88490d6f7a712aca2168 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sun, 6 Oct 2024 10:49:41 -0700 Subject: [PATCH 095/129] class tree walk can be idiomized with find_map and transpose --- src/runner/instance.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 80dedd5..ed94bac 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -256,15 +256,9 @@ impl mlua::UserData for Instance{ database:db, descriptor:Some(class), }; - Ok(loop{ - match iter.next(){ - Some(class)=>match cf.get_or_create_class_function(lua,&class.name,index_str)?{ - Some(function)=>break Some(function), - None=>(), - }, - None=>break None, - } - }) + iter.find_map(|class| + cf.get_or_create_class_function(lua,&class.name,index_str).transpose() + ).transpose() })?{ return function.into_lua(lua); } From 5e45e952d97844ff00ee3ef1290bd74af6cec585 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sun, 6 Oct 2024 11:26:18 -0700 Subject: [PATCH 096/129] v0.4.4 less terrible all around --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 24a3606..8702c15 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -402,7 +402,7 @@ dependencies = [ [[package]] name = "roblox_emulator" -version = "0.4.3" +version = "0.4.4" dependencies = [ "glam", "mlua", diff --git a/Cargo.toml b/Cargo.toml index 610718c..779726b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "roblox_emulator" -version = "0.4.3" +version = "0.4.4" edition = "2021" repository = "https://git.itzana.me/StrafesNET/roblox_emulator" license = "MIT OR Apache-2.0" From 692697f82b3c05141cbc9b63acad9575194979b0 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sun, 6 Oct 2024 11:41:52 -0700 Subject: [PATCH 097/129] split get_or_create_class_function into two parts in case you want to get multiple functions from the same class --- src/runner/instance.rs | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index ed94bac..2d96e06 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -257,7 +257,10 @@ impl mlua::UserData for Instance{ descriptor:Some(class), }; iter.find_map(|class| - cf.get_or_create_class_function(lua,&class.name,index_str).transpose() + cf.get_or_create_class_methods(&class.name) + .and_then(|mut class_methods| + class_methods.get_or_create_function(lua,index_str).transpose() + ) ).transpose() })?{ return function.into_lua(lua); @@ -378,20 +381,33 @@ struct ClassFunctions{ > } impl ClassFunctions{ - /// return self.classes[class][index] or create the function in the hashmap and then return it - fn get_or_create_class_function(&mut self,lua:&mlua::Lua,class:&str,index:&str)->mlua::Result>{ + /// return self.classes[class] or create the ClassMethods and then return it + fn get_or_create_class_methods(&mut self,class:&str)->Option{ // Use get_entry to get the &'static str keys of the database // and use it as a key for the classes hashmap - if let Some((&static_class_str,class_functions))=CLASS_FUNCTION_DATABASE.get_entry(class){ - if let Some((&static_index_str,function_pointer))=class_functions.get_entry(index){ - return Ok(Some( - self.classes.entry(static_class_str) - .or_insert_with(||HashMap::new()) - .entry(static_index_str) - .or_insert(lua.create_function(function_pointer)?) - .clone() - )) - } + CLASS_FUNCTION_DATABASE.get_entry(class) + .map(|(&static_class_str,method_pointers)| + ClassMethods{ + method_pointers, + methods:self.classes.entry(static_class_str) + .or_insert_with(||HashMap::new()), + } + ) + } +} +struct ClassMethods<'a>{ + method_pointers:&'static phf::Map<&'static str,ClassFunctionPointer>, + methods:&'a mut HashMap<&'static str,mlua::Function>, +} +impl ClassMethods<'_>{ + /// return self.methods[index] or create the function in the hashmap and then return it + fn get_or_create_function(&mut self,lua:&mlua::Lua,index:&str)->mlua::Result>{ + if let Some((&static_index_str,function_pointer))=self.method_pointers.get_entry(index){ + return Ok(Some( + self.methods.entry(static_index_str) + .or_insert(lua.create_function(function_pointer)?) + .clone() + )) } return Ok(None) } From aa1db9551e90cd878efabca0c9382fb438a074a3 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sun, 6 Oct 2024 13:45:44 -0700 Subject: [PATCH 098/129] match has better line width balance --- src/runner/instance.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 2d96e06..396752b 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -402,13 +402,13 @@ struct ClassMethods<'a>{ impl ClassMethods<'_>{ /// return self.methods[index] or create the function in the hashmap and then return it fn get_or_create_function(&mut self,lua:&mlua::Lua,index:&str)->mlua::Result>{ - if let Some((&static_index_str,function_pointer))=self.method_pointers.get_entry(index){ - return Ok(Some( + Ok(match self.method_pointers.get_entry(index){ + Some((&static_index_str,function_pointer))=>Some( self.methods.entry(static_index_str) .or_insert(lua.create_function(function_pointer)?) .clone() - )) - } - return Ok(None) + ), + None=>None, + }) } } From 9a03ac199a29a8f7cb910b5ddfc0c670c3972856 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sun, 6 Oct 2024 13:53:41 -0700 Subject: [PATCH 099/129] deref function pointer, not sure if this does anything --- src/runner/instance.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 396752b..d2b5d8e 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -403,7 +403,7 @@ impl ClassMethods<'_>{ /// return self.methods[index] or create the function in the hashmap and then return it fn get_or_create_function(&mut self,lua:&mlua::Lua,index:&str)->mlua::Result>{ Ok(match self.method_pointers.get_entry(index){ - Some((&static_index_str,function_pointer))=>Some( + Some((&static_index_str,&function_pointer))=>Some( self.methods.entry(static_index_str) .or_insert(lua.create_function(function_pointer)?) .clone() From 3ad9d45452f3e9cba68da23dca502ce8beb737bc Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sun, 6 Oct 2024 16:00:14 -0700 Subject: [PATCH 100/129] don't create and drop a new function every call --- src/runner/instance.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index d2b5d8e..8ce90b8 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::{hash_map::Entry,HashMap}; use mlua::{FromLua,FromLuaMulti,IntoLua,IntoLuaMulti}; use rbx_types::Ref; @@ -404,9 +404,12 @@ impl ClassMethods<'_>{ fn get_or_create_function(&mut self,lua:&mlua::Lua,index:&str)->mlua::Result>{ Ok(match self.method_pointers.get_entry(index){ Some((&static_index_str,&function_pointer))=>Some( - self.methods.entry(static_index_str) - .or_insert(lua.create_function(function_pointer)?) - .clone() + match self.methods.entry(static_index_str){ + Entry::Occupied(entry)=>entry.get().clone(), + Entry::Vacant(entry)=>entry.insert( + lua.create_function(function_pointer)? + ).clone(), + } ), None=>None, }) From 6dfa46bc6783a19659bfaa90d76eea3bee63e98d Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sun, 6 Oct 2024 17:14:46 -0700 Subject: [PATCH 101/129] VIRTUAL_PROPERTY_DATABASE (another goddamn superclass walk) --- src/runner/instance.rs | 75 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 67 insertions(+), 8 deletions(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 8ce90b8..222201a 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -237,16 +237,27 @@ impl mlua::UserData for Instance{ let class=db.classes.get(instance.class.as_str()).ok_or(mlua::Error::runtime("Class missing"))?; //Find existing property match instance.properties.get(index_str) + .cloned() //Find default value - .or_else(||db.find_default_property(class,index_str)) + .or_else(||db.find_default_property(class,index_str).cloned()) + //Find virtual property + .or_else(||{ + SuperClassIter{ + database:db, + descriptor:Some(class), + } + .find_map(|class| + find_virtual_property(&instance.properties,class,index_str) + ) + }) { - Some(&rbx_types::Variant::Int32(val))=>return val.into_lua(lua), - Some(&rbx_types::Variant::Int64(val))=>return val.into_lua(lua), - Some(&rbx_types::Variant::Float32(val))=>return val.into_lua(lua), - Some(&rbx_types::Variant::Float64(val))=>return val.into_lua(lua), - Some(&rbx_types::Variant::Ref(val))=>return Instance::new(val).into_lua(lua), - Some(&rbx_types::Variant::CFrame(cf))=>return Into::::into(cf).into_lua(lua), - Some(&rbx_types::Variant::Vector3(v))=>return Into::::into(v).into_lua(lua), + Some(rbx_types::Variant::Int32(val))=>return val.into_lua(lua), + Some(rbx_types::Variant::Int64(val))=>return val.into_lua(lua), + Some(rbx_types::Variant::Float32(val))=>return val.into_lua(lua), + Some(rbx_types::Variant::Float64(val))=>return val.into_lua(lua), + Some(rbx_types::Variant::Ref(val))=>return Instance::new(val).into_lua(lua), + Some(rbx_types::Variant::CFrame(cf))=>return Into::::into(cf).into_lua(lua), + Some(rbx_types::Variant::Vector3(v))=>return Into::::into(v).into_lua(lua), None=>(), other=>return Err(mlua::Error::runtime(format!("Instance.__index Unsupported property type instance={} index={index_str} value={other:?}",instance.name))), } @@ -415,3 +426,51 @@ impl ClassMethods<'_>{ }) } } + +/// A virtual property pointer definition shorthand. +type VirtualPropertyFunctionPointer=fn(&rbx_types::Variant)->Option; +const fn vpp( + property:&'static str, + pointer:VirtualPropertyFunctionPointer, +)->VirtualProperty{ + VirtualProperty{ + property, + pointer, + } +} +struct VirtualProperty{ + property:&'static str,// Source property name + pointer:VirtualPropertyFunctionPointer, +} +type VPD=phf::Map<&'static str,// Class name + phf::Map<&'static str,// Virtual property name + VirtualProperty + > +>; +static VIRTUAL_PROPERTY_DATABASE:VPD=phf::phf_map!{ + "BasePart"=>phf::phf_map!{ + "Position"=>vpp("CFrame",|c:&rbx_types::Variant|{ + let c=match c{ + rbx_types::Variant::CFrame(c)=>c, + _=>return None,//fail silently and ungracefully + }; + Some(rbx_types::Variant::Vector3(c.position)) + }), + }, +}; + +fn find_virtual_property( + properties:&HashMap, + class:&rbx_reflection::ClassDescriptor, + index:&str +)->Option{ + //Find virtual property + let class_virtual_properties=VIRTUAL_PROPERTY_DATABASE.get(&class.name)?; + let virtual_property=class_virtual_properties.get(index)?; + + //Get source property + let variant=properties.get(virtual_property.property)?; + + //Transform Source property with provided function + (virtual_property.pointer)(variant) +} From fe91de5668e9edb5c95897d82cfbd1c8a19b1b54 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sun, 6 Oct 2024 18:20:53 -0700 Subject: [PATCH 102/129] remove and_then --- src/runner/instance.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 222201a..0b9bb64 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -267,12 +267,11 @@ impl mlua::UserData for Instance{ database:db, descriptor:Some(class), }; - iter.find_map(|class| - cf.get_or_create_class_methods(&class.name) - .and_then(|mut class_methods| - class_methods.get_or_create_function(lua,index_str).transpose() - ) - ).transpose() + iter.find_map(|class|{ + let mut class_methods=cf.get_or_create_class_methods(&class.name)?; + class_methods.get_or_create_function(lua,index_str) + .transpose() + }).transpose() })?{ return function.into_lua(lua); } From 25577211b2791a6b5cacca247967efdb905a0f08 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sun, 6 Oct 2024 18:44:50 -0700 Subject: [PATCH 103/129] cursed userdata take --- src/runner/instance.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 0b9bb64..3f79386 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -295,7 +295,7 @@ impl mlua::UserData for Instance{ let property=iter.find_map(|cls|cls.properties.get(index_str)).ok_or(mlua::Error::runtime(format!("Property '{index_str}' missing on class '{}'",class.name)))?; match &property.data_type{ rbx_reflection::DataType::Value(rbx_types::VariantType::Vector3)=>{ - let typed_value:Vector3=value.as_userdata().ok_or(mlua::Error::runtime("Expected Userdata"))?.take()?; + let typed_value:Vector3=*value.as_userdata().ok_or(mlua::Error::runtime("Expected Userdata"))?.borrow()?; instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Vector3(typed_value.into())); }, rbx_reflection::DataType::Value(rbx_types::VariantType::Float32)=>{ @@ -311,7 +311,7 @@ impl mlua::UserData for Instance{ Ok(rbx_types::Enum::from_u32(*e.items.get(&*s.to_str()?).ok_or(mlua::Error::runtime("Invalid enum item"))?)) }, mlua::Value::UserData(any_user_data)=>{ - let e:super::r#enum::Enum=any_user_data.take()?; + let e:super::r#enum::Enum=*any_user_data.borrow()?; Ok(e.into()) }, _=>Err(mlua::Error::runtime("Expected Enum")), @@ -319,7 +319,7 @@ impl mlua::UserData for Instance{ instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Enum(typed_value)); }, rbx_reflection::DataType::Value(rbx_types::VariantType::Color3)=>{ - let typed_value:super::color3::Color3=value.as_userdata().ok_or(mlua::Error::runtime("Expected Color3"))?.take()?; + let typed_value:super::color3::Color3=*value.as_userdata().ok_or(mlua::Error::runtime("Expected Color3"))?.borrow()?; instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Color3(typed_value.into())); }, rbx_reflection::DataType::Value(rbx_types::VariantType::Bool)=>{ From b672c1360d769964f309b4065afb4dcdde9eba72 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sun, 6 Oct 2024 18:58:58 -0700 Subject: [PATCH 104/129] v0.4.5 virtual property database + fixes --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8702c15..2cb490e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -402,7 +402,7 @@ dependencies = [ [[package]] name = "roblox_emulator" -version = "0.4.4" +version = "0.4.5" dependencies = [ "glam", "mlua", diff --git a/Cargo.toml b/Cargo.toml index 779726b..486ed4c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "roblox_emulator" -version = "0.4.4" +version = "0.4.5" edition = "2021" repository = "https://git.itzana.me/StrafesNET/roblox_emulator" license = "MIT OR Apache-2.0" From 4ce6fb215594fef08c2295ea76e73caacc5d32f5 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sun, 6 Oct 2024 18:45:25 -0700 Subject: [PATCH 105/129] non-functional NumberSequence skeleton --- src/runner/instance.rs | 4 ++++ src/runner/mod.rs | 1 + src/runner/number_sequence.rs | 31 +++++++++++++++++++++++++++++++ src/runner/runner.rs | 1 + 4 files changed, 37 insertions(+) create mode 100644 src/runner/number_sequence.rs diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 3f79386..edccffd 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -330,6 +330,10 @@ impl mlua::UserData for Instance{ let typed_value=value.as_str().ok_or(mlua::Error::runtime("Expected boolean"))?; instance.properties.insert(index_str.to_owned(),rbx_types::Variant::String(typed_value.to_owned())); }, + rbx_reflection::DataType::Value(rbx_types::VariantType::NumberSequence)=>{ + let typed_value:super::number_sequence::NumberSequence=*value.as_userdata().ok_or(mlua::Error::runtime("Expected NumberSequence"))?.borrow()?; + instance.properties.insert(index_str.to_owned(),rbx_types::Variant::NumberSequence(typed_value.into())); + }, other=>return Err(mlua::Error::runtime(format!("Unimplemented property type: {other:?}"))), } Ok(()) diff --git a/src/runner/mod.rs b/src/runner/mod.rs index de4859f..ec90f9a 100644 --- a/src/runner/mod.rs +++ b/src/runner/mod.rs @@ -7,5 +7,6 @@ mod color3; mod cframe; mod vector3; pub mod instance; +mod number_sequence; pub use runner::{Runner,Error}; diff --git a/src/runner/number_sequence.rs b/src/runner/number_sequence.rs new file mode 100644 index 0000000..bfa25bb --- /dev/null +++ b/src/runner/number_sequence.rs @@ -0,0 +1,31 @@ +#[derive(Clone,Copy)] +pub struct NumberSequence{} +impl NumberSequence{ + pub const fn new()->Self{ + Self{} + } +} +impl Into for NumberSequence{ + fn into(self)->rbx_types::NumberSequence{ + rbx_types::NumberSequence{ + keypoints:Vec::new() + } + } +} + +pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{ + let number_sequence_table=lua.create_table()?; + + number_sequence_table.raw_set("new", + lua.create_function(|_,_:mlua::MultiValue| + Ok(NumberSequence::new()) + )? + )?; + + globals.set("NumberSequence",number_sequence_table)?; + + Ok(()) +} + +impl mlua::UserData for NumberSequence{} +type_from_lua_userdata!(NumberSequence); diff --git a/src/runner/runner.rs b/src/runner/runner.rs index 48dee06..b58de5f 100644 --- a/src/runner/runner.rs +++ b/src/runner/runner.rs @@ -34,6 +34,7 @@ fn init(lua:&mlua::Lua)->mlua::Result<()>{ super::vector3::set_globals(lua,&globals)?; super::cframe::set_globals(lua,&globals)?; super::instance::set_globals(lua,&globals)?; + super::number_sequence::set_globals(lua,&globals)?; Ok(()) } From 9898c53de88f6384b62f1a4895897215dbccfb07 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Sun, 6 Oct 2024 18:48:14 -0700 Subject: [PATCH 106/129] non-functional ColorSequence skeleton --- src/runner/color_sequence.rs | 31 +++++++++++++++++++++++++++++++ src/runner/instance.rs | 4 ++++ src/runner/mod.rs | 1 + src/runner/runner.rs | 1 + 4 files changed, 37 insertions(+) create mode 100644 src/runner/color_sequence.rs diff --git a/src/runner/color_sequence.rs b/src/runner/color_sequence.rs new file mode 100644 index 0000000..819fa2e --- /dev/null +++ b/src/runner/color_sequence.rs @@ -0,0 +1,31 @@ +#[derive(Clone,Copy)] +pub struct ColorSequence{} +impl ColorSequence{ + pub const fn new()->Self{ + Self{} + } +} +impl Into for ColorSequence{ + fn into(self)->rbx_types::ColorSequence{ + rbx_types::ColorSequence{ + keypoints:Vec::new() + } + } +} + +pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{ + let number_sequence_table=lua.create_table()?; + + number_sequence_table.raw_set("new", + lua.create_function(|_,_:mlua::MultiValue| + Ok(ColorSequence::new()) + )? + )?; + + globals.set("ColorSequence",number_sequence_table)?; + + Ok(()) +} + +impl mlua::UserData for ColorSequence{} +type_from_lua_userdata!(ColorSequence); diff --git a/src/runner/instance.rs b/src/runner/instance.rs index edccffd..88ebc7b 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -334,6 +334,10 @@ impl mlua::UserData for Instance{ let typed_value:super::number_sequence::NumberSequence=*value.as_userdata().ok_or(mlua::Error::runtime("Expected NumberSequence"))?.borrow()?; instance.properties.insert(index_str.to_owned(),rbx_types::Variant::NumberSequence(typed_value.into())); }, + rbx_reflection::DataType::Value(rbx_types::VariantType::ColorSequence)=>{ + let typed_value:super::color_sequence::ColorSequence=*value.as_userdata().ok_or(mlua::Error::runtime("Expected ColorSequence"))?.borrow()?; + instance.properties.insert(index_str.to_owned(),rbx_types::Variant::ColorSequence(typed_value.into())); + }, other=>return Err(mlua::Error::runtime(format!("Unimplemented property type: {other:?}"))), } Ok(()) diff --git a/src/runner/mod.rs b/src/runner/mod.rs index ec90f9a..c21caac 100644 --- a/src/runner/mod.rs +++ b/src/runner/mod.rs @@ -8,5 +8,6 @@ mod cframe; mod vector3; pub mod instance; mod number_sequence; +mod color_sequence; pub use runner::{Runner,Error}; diff --git a/src/runner/runner.rs b/src/runner/runner.rs index b58de5f..f84e8b1 100644 --- a/src/runner/runner.rs +++ b/src/runner/runner.rs @@ -35,6 +35,7 @@ fn init(lua:&mlua::Lua)->mlua::Result<()>{ super::cframe::set_globals(lua,&globals)?; super::instance::set_globals(lua,&globals)?; super::number_sequence::set_globals(lua,&globals)?; + super::color_sequence::set_globals(lua,&globals)?; Ok(()) } From 752ad6bd95dfa0e344a57e194601d686a54a197b Mon Sep 17 00:00:00 2001 From: Quaternions Date: Wed, 16 Oct 2024 19:53:58 -0700 Subject: [PATCH 107/129] scheduler --- src/lib.rs | 1 + src/runner/runner.rs | 2 ++ src/scheduler.rs | 58 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 src/scheduler.rs diff --git a/src/lib.rs b/src/lib.rs index b97eda2..669c126 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ pub mod runner; pub mod context; +pub(crate) mod scheduler; #[cfg(test)] mod tests; diff --git a/src/runner/runner.rs b/src/runner/runner.rs index f84e8b1..e70fb37 100644 --- a/src/runner/runner.rs +++ b/src/runner/runner.rs @@ -60,6 +60,7 @@ impl Runner{ } //this makes set_app_data shut up about the lifetime self.lua.set_app_data::<&'static mut rbx_dom_weak::WeakDom>(unsafe{core::mem::transmute(&mut context.dom)}); + self.lua.set_app_data::(crate::scheduler::Scheduler::default()); Ok(Runnable{ lua:self.lua, _lifetime:&std::marker::PhantomData @@ -75,6 +76,7 @@ pub struct Runnable<'a>{ impl Runnable<'_>{ pub fn drop_context(self)->Runner{ self.lua.remove_app_data::<&'static mut rbx_dom_weak::WeakDom>(); + self.lua.remove_app_data::(); Runner{ lua:self.lua, } diff --git a/src/scheduler.rs b/src/scheduler.rs new file mode 100644 index 0000000..f99a5c8 --- /dev/null +++ b/src/scheduler.rs @@ -0,0 +1,58 @@ +pub use tick::Tick; +mod tick{ + #[derive(Clone,Copy,Default,Hash,PartialEq,Eq,PartialOrd,Ord)] + pub struct Tick(u64); + impl Tick{ + pub const fn new(value:u64)->Self{ + Self(value) + } + pub const fn get(&self)->u64{ + self.0 + } + } + impl std::ops::Add for Tick{ + type Output=Self; + fn add(self,rhs:u64)->Self::Output{ + Self(self.0+rhs) + } + } + impl std::ops::Sub for Tick{ + type Output=Self; + fn sub(self,rhs:u64)->Self::Output{ + Self(self.0-rhs) + } + } + impl std::ops::AddAssign for Tick{ + fn add_assign(&mut self,rhs:u64){ + self.0+=rhs; + } + } + impl std::ops::SubAssign for Tick{ + fn sub_assign(&mut self,rhs:u64){ + self.0-=rhs; + } + } +} +#[derive(Default)] +pub struct Scheduler{ + tick:Tick, + schedule:std::collections::HashMap>, +} + +impl Scheduler{ + pub const fn tick(&self)->Tick{ + self.tick + } + pub fn has_scheduled_threads(&self)->bool{ + !self.schedule.is_empty() + } + pub fn schedule_thread(&mut self,delay:u64,thread:mlua::Thread){ + self.schedule.entry(self.tick+delay.max(1)) + .or_insert(Vec::new()) + .push(thread); + } + pub fn tick_threads(&mut self)->Option>{ + self.tick+=1; + self.schedule.remove(&self.tick) + } +} From 9c1807ec76864d7c658195fb942d97f64928fb9f Mon Sep 17 00:00:00 2001 From: Quaternions Date: Wed, 16 Oct 2024 17:45:41 -0700 Subject: [PATCH 108/129] wait --- src/runner/runner.rs | 2 ++ src/scheduler.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/src/runner/runner.rs b/src/runner/runner.rs index e70fb37..80efe97 100644 --- a/src/runner/runner.rs +++ b/src/runner/runner.rs @@ -1,4 +1,5 @@ use crate::context::Context; +use crate::scheduler::scheduler_mut; pub struct Runner{ lua:mlua::Lua, @@ -29,6 +30,7 @@ fn init(lua:&mlua::Lua)->mlua::Result<()>{ //global environment let globals=lua.globals(); + crate::scheduler::set_globals(lua,&globals)?; super::r#enum::set_globals(lua,&globals)?; super::color3::set_globals(lua,&globals)?; super::vector3::set_globals(lua,&globals)?; diff --git a/src/scheduler.rs b/src/scheduler.rs index f99a5c8..05b4d8a 100644 --- a/src/scheduler.rs +++ b/src/scheduler.rs @@ -56,3 +56,44 @@ impl Scheduler{ self.schedule.remove(&self.tick) } } + +fn coerce_float64(value:&mlua::Value)->Option{ + match value{ + &mlua::Value::Integer(i)=>Some(i as f64), + &mlua::Value::Number(f)=>Some(f), + _=>None, + } +} +pub fn scheduler_mut(lua:&mlua::Lua,mut f:impl FnMut(&mut crate::scheduler::Scheduler)->mlua::Result)->mlua::Result{ + let mut scheduler=lua.app_data_mut::().ok_or(mlua::Error::runtime("Scheduler missing"))?; + f(&mut *scheduler) +} +pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{ + let schedule_thread=lua.create_function(move|lua,dt:mlua::Value|{ + let delay=coerce_float64(&dt).ok_or(mlua::Error::runtime("Expected float"))?.max(0.0)*60.0; + if delay("coroutine")?)?; + wait_env.raw_set("schedule_thread",schedule_thread)?; + let wait=lua.load(" + local coroutine_yield=coroutine.yield + local schedule_thread=schedule_thread + return function(dt) + schedule_thread(dt) + return coroutine_yield() + end + ") + .set_name("wait") + .set_environment(wait_env) + .call::(())?; + globals.raw_set("wait",wait)?; + + Ok(()) +} From 8950bcbf020c1b78738e6cb809352fdce49ac1d2 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Wed, 16 Oct 2024 19:50:40 -0700 Subject: [PATCH 109/129] game ticks api --- src/runner/runner.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/runner/runner.rs b/src/runner/runner.rs index 80efe97..04611e6 100644 --- a/src/runner/runner.rs +++ b/src/runner/runner.rs @@ -90,4 +90,23 @@ impl Runnable<'_>{ .set_name(name) .exec().map_err(|error|Error::Lua{source,error}) } + pub fn has_scheduled_threads(&self)->Result{ + scheduler_mut(&self.lua,|scheduler| + Ok(scheduler.has_scheduled_threads()) + ) + } + pub fn game_tick(&self)->Result<(),mlua::Error>{ + if let Some(threads)=scheduler_mut(&self.lua,|scheduler|Ok(scheduler.tick_threads()))?{ + for thread in threads{ + //TODO: return dt and total run time + let result=thread.resume::((1.0/30.0,0.0)) + .map_err(|error|Error::Lua{source:"source unavailable".to_owned(),error}); + match result{ + Ok(_)=>(), + Err(e)=>println!("game_tick Error: {e}"), + } + } + } + Ok(()) + } } From 5ddb3dacfd97944ed8fe922c35001a4b25b344c1 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Wed, 16 Oct 2024 19:54:10 -0700 Subject: [PATCH 110/129] run script as a thread --- src/runner/runner.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/runner/runner.rs b/src/runner/runner.rs index 04611e6..571a978 100644 --- a/src/runner/runner.rs +++ b/src/runner/runner.rs @@ -85,10 +85,15 @@ impl Runnable<'_>{ } pub fn run_script(&self,script:super::instance::Instance)->Result<(),Error>{ let (name,source)=super::instance::get_name_source(&self.lua,script).map_err(Error::RustLua)?; - self.lua.globals().set("script",script).map_err(Error::RustLua)?; - self.lua.load(source.as_str()) - .set_name(name) - .exec().map_err(|error|Error::Lua{source,error}) + self.lua.globals().raw_set("script",script).map_err(Error::RustLua)?; + let f=self.lua.load(source.as_str()) + .set_name(name).into_function().map_err(Error::RustLua)?; + // TODO: set_environment without losing the ability to print from Lua + let thread=self.lua.create_thread(f).map_err(Error::RustLua)?; + thread.resume::(()).map_err(|error|Error::Lua{source,error})?; + // wait() is called from inside Lua and goes to a rust function that schedules the thread and then yields + // No need to schedule the thread here + Ok(()) } pub fn has_scheduled_threads(&self)->Result{ scheduler_mut(&self.lua,|scheduler| From 03e9d989f84dafda9b9ce7aa4227db076ef2f479 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Wed, 16 Oct 2024 20:26:59 -0700 Subject: [PATCH 111/129] make scheduler into a crate feature --- Cargo.toml | 4 ++++ src/lib.rs | 1 + src/runner/runner.rs | 6 ++++++ 3 files changed, 11 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 486ed4c..fde6cc8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,10 @@ license = "MIT OR Apache-2.0" description = "Run embedded Luau scripts which manipulate the DOM." authors = ["Rhys Lloyd "] +[features] +default=["run-service"] +run-service=[] + [dependencies] glam = "0.29.0" mlua = { version = "0.10.0-beta", features = ["luau"] } diff --git a/src/lib.rs b/src/lib.rs index 669c126..fd38760 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ pub mod runner; pub mod context; +#[cfg(feature="run-service")] pub(crate) mod scheduler; #[cfg(test)] diff --git a/src/runner/runner.rs b/src/runner/runner.rs index 571a978..39fa25a 100644 --- a/src/runner/runner.rs +++ b/src/runner/runner.rs @@ -1,4 +1,5 @@ use crate::context::Context; +#[cfg(feature="run-service")] use crate::scheduler::scheduler_mut; pub struct Runner{ @@ -30,6 +31,7 @@ fn init(lua:&mlua::Lua)->mlua::Result<()>{ //global environment let globals=lua.globals(); + #[cfg(feature="run-service")] crate::scheduler::set_globals(lua,&globals)?; super::r#enum::set_globals(lua,&globals)?; super::color3::set_globals(lua,&globals)?; @@ -62,6 +64,7 @@ impl Runner{ } //this makes set_app_data shut up about the lifetime self.lua.set_app_data::<&'static mut rbx_dom_weak::WeakDom>(unsafe{core::mem::transmute(&mut context.dom)}); + #[cfg(feature="run-service")] self.lua.set_app_data::(crate::scheduler::Scheduler::default()); Ok(Runnable{ lua:self.lua, @@ -78,6 +81,7 @@ pub struct Runnable<'a>{ impl Runnable<'_>{ pub fn drop_context(self)->Runner{ self.lua.remove_app_data::<&'static mut rbx_dom_weak::WeakDom>(); + #[cfg(feature="run-service")] self.lua.remove_app_data::(); Runner{ lua:self.lua, @@ -95,11 +99,13 @@ impl Runnable<'_>{ // No need to schedule the thread here Ok(()) } + #[cfg(feature="run-service")] pub fn has_scheduled_threads(&self)->Result{ scheduler_mut(&self.lua,|scheduler| Ok(scheduler.has_scheduled_threads()) ) } + #[cfg(feature="run-service")] pub fn game_tick(&self)->Result<(),mlua::Error>{ if let Some(threads)=scheduler_mut(&self.lua,|scheduler|Ok(scheduler.tick_threads()))?{ for thread in threads{ From 13621022e1a791d6fc1775efea103dd18787b7a0 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Wed, 16 Oct 2024 21:21:56 -0700 Subject: [PATCH 112/129] export Runnable type --- src/runner/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runner/mod.rs b/src/runner/mod.rs index c21caac..7d716eb 100644 --- a/src/runner/mod.rs +++ b/src/runner/mod.rs @@ -10,4 +10,4 @@ pub mod instance; mod number_sequence; mod color_sequence; -pub use runner::{Runner,Error}; +pub use runner::{Runner,Runnable,Error}; From 368ce7da9eea4dd6a6406671222fbed7e44fb6e7 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Wed, 16 Oct 2024 20:58:26 -0700 Subject: [PATCH 113/129] v0.4.6 thread scheduler --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2cb490e..5119b54 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -402,7 +402,7 @@ dependencies = [ [[package]] name = "roblox_emulator" -version = "0.4.5" +version = "0.4.6" dependencies = [ "glam", "mlua", diff --git a/Cargo.toml b/Cargo.toml index fde6cc8..1fa8d5c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "roblox_emulator" -version = "0.4.5" +version = "0.4.6" edition = "2021" repository = "https://git.itzana.me/StrafesNET/roblox_emulator" license = "MIT OR Apache-2.0" From 135103364db3de7fd3253f805dd169c0525f72d4 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Wed, 16 Oct 2024 21:22:45 -0700 Subject: [PATCH 114/129] remove this when rbx-dom updates --- .cargo/config.toml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .cargo/config.toml diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..8b662bc --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[registries.strafesnet] +index = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/" \ No newline at end of file From f8f659e8cefd6ee5cf6a94d59b5d19c9cb41f068 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Wed, 16 Oct 2024 23:07:32 -0700 Subject: [PATCH 115/129] specialize coerce f64 code --- src/scheduler.rs | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/src/scheduler.rs b/src/scheduler.rs index 05b4d8a..81611f2 100644 --- a/src/scheduler.rs +++ b/src/scheduler.rs @@ -57,27 +57,33 @@ impl Scheduler{ } } -fn coerce_float64(value:&mlua::Value)->Option{ - match value{ - &mlua::Value::Integer(i)=>Some(i as f64), - &mlua::Value::Number(f)=>Some(f), - _=>None, - } -} pub fn scheduler_mut(lua:&mlua::Lua,mut f:impl FnMut(&mut crate::scheduler::Scheduler)->mlua::Result)->mlua::Result{ let mut scheduler=lua.app_data_mut::().ok_or(mlua::Error::runtime("Scheduler missing"))?; f(&mut *scheduler) } pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{ - let schedule_thread=lua.create_function(move|lua,dt:mlua::Value|{ - let delay=coerce_float64(&dt).ok_or(mlua::Error::runtime("Expected float"))?.max(0.0)*60.0; - if delayi.max(0) as u64*60, + mlua::Value::Number(f)=>{ + let delay=f.max(0.0)*60.0; + match delay.classify(){ + std::num::FpCategory::Nan=>Err(mlua::Error::runtime("NaN"))?, + std::num::FpCategory::Infinite=>return Ok(()), + std::num::FpCategory::Normal=>if (u64::MAX as f64)(), + } + delay as u64 + }, + mlua::Value::Nil=>0, + _=>Err(mlua::Error::runtime("Expected float"))?, + }; + scheduler_mut(lua,|scheduler|{ + scheduler.schedule_thread(delay.max(2),lua.current_thread()); + Ok(()) + }) })?; let wait_env=lua.create_table()?; wait_env.raw_set("coroutine",globals.get::("coroutine")?)?; From bffc5bb8f1c3d3adaf9a9b90f358777c49dd7480 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Thu, 17 Oct 2024 11:32:40 -0700 Subject: [PATCH 116/129] comment --- src/scheduler.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/scheduler.rs b/src/scheduler.rs index 81611f2..c5b890c 100644 --- a/src/scheduler.rs +++ b/src/scheduler.rs @@ -69,6 +69,7 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{ let delay=f.max(0.0)*60.0; match delay.classify(){ std::num::FpCategory::Nan=>Err(mlua::Error::runtime("NaN"))?, + // cases where the number is too large to schedule std::num::FpCategory::Infinite=>return Ok(()), std::num::FpCategory::Normal=>if (u64::MAX as f64) Date: Thu, 17 Oct 2024 16:52:55 -0700 Subject: [PATCH 117/129] scheduler code cleanup --- src/scheduler.rs | 77 +++++++++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 33 deletions(-) diff --git a/src/scheduler.rs b/src/scheduler.rs index c5b890c..53170d1 100644 --- a/src/scheduler.rs +++ b/src/scheduler.rs @@ -61,45 +61,56 @@ pub fn scheduler_mut(lua:&mlua::Lua,mut f:impl FnMut(&mut crate::scheduler::S let mut scheduler=lua.app_data_mut::().ok_or(mlua::Error::runtime("Scheduler missing"))?; f(&mut *scheduler) } + +fn schedule_thread(lua:&mlua::Lua,dt:mlua::Value)->Result<(),mlua::Error>{ + let delay=match dt{ + mlua::Value::Integer(i)=>i.max(0) as u64*60, + mlua::Value::Number(f)=>{ + let delay=f.max(0.0)*60.0; + match delay.classify(){ + std::num::FpCategory::Nan=>Err(mlua::Error::runtime("NaN"))?, + // cases where the number is too large to schedule + std::num::FpCategory::Infinite=>return Ok(()), + std::num::FpCategory::Normal=>if (u64::MAX as f64)(), + } + delay as u64 + }, + mlua::Value::Nil=>0, + _=>Err(mlua::Error::runtime("Expected float"))?, + }; + scheduler_mut(lua,|scheduler|{ + scheduler.schedule_thread(delay.max(2),lua.current_thread()); + Ok(()) + }) +} + +// This is used to avoid calling coroutine.yield from the rust side. +const LUA_WAIT:&str= +"local coroutine_yield=coroutine.yield +local schedule_thread=schedule_thread +return function(dt) + schedule_thread(dt) + return coroutine_yield() +end"; + pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{ - let schedule_thread=lua.create_function(|lua,dt:mlua::Value|{ - let delay=match dt{ - mlua::Value::Integer(i)=>i.max(0) as u64*60, - mlua::Value::Number(f)=>{ - let delay=f.max(0.0)*60.0; - match delay.classify(){ - std::num::FpCategory::Nan=>Err(mlua::Error::runtime("NaN"))?, - // cases where the number is too large to schedule - std::num::FpCategory::Infinite=>return Ok(()), - std::num::FpCategory::Normal=>if (u64::MAX as f64)(), - } - delay as u64 - }, - mlua::Value::Nil=>0, - _=>Err(mlua::Error::runtime("Expected float"))?, - }; - scheduler_mut(lua,|scheduler|{ - scheduler.schedule_thread(delay.max(2),lua.current_thread()); - Ok(()) - }) - })?; + let coroutine_table=globals.get::("coroutine")?; + let schedule_thread=lua.create_function(schedule_thread)?; + + //create wait function environment let wait_env=lua.create_table()?; - wait_env.raw_set("coroutine",globals.get::("coroutine")?)?; + wait_env.raw_set("coroutine",coroutine_table)?; wait_env.raw_set("schedule_thread",schedule_thread)?; - let wait=lua.load(" - local coroutine_yield=coroutine.yield - local schedule_thread=schedule_thread - return function(dt) - schedule_thread(dt) - return coroutine_yield() - end - ") + + //construct wait function from Lua code + let wait=lua.load(LUA_WAIT) .set_name("wait") .set_environment(wait_env) .call::(())?; + globals.raw_set("wait",wait)?; Ok(()) From 210832c73742b9ec17f32935a5b898b761f14bcf Mon Sep 17 00:00:00 2001 From: Quaternions Date: Thu, 17 Oct 2024 12:50:13 -0700 Subject: [PATCH 118/129] RBXScriptSignal --- src/runner/mod.rs | 3 +- src/runner/script_signal.rs | 79 +++++++++++++++++++++++++++++++++++++ src/scheduler.rs | 11 ------ 3 files changed, 81 insertions(+), 12 deletions(-) create mode 100644 src/runner/script_signal.rs diff --git a/src/runner/mod.rs b/src/runner/mod.rs index 7d716eb..a208868 100644 --- a/src/runner/mod.rs +++ b/src/runner/mod.rs @@ -7,7 +7,8 @@ mod color3; mod cframe; mod vector3; pub mod instance; -mod number_sequence; +mod script_signal; mod color_sequence; +mod number_sequence; pub use runner::{Runner,Runnable,Error}; diff --git a/src/runner/script_signal.rs b/src/runner/script_signal.rs new file mode 100644 index 0000000..992ab95 --- /dev/null +++ b/src/runner/script_signal.rs @@ -0,0 +1,79 @@ +use std::{cell::RefCell,rc::Rc}; + +#[derive(Clone)] +pub struct ScriptSignal{ + // Emulate the garbage roblox api. + // ScriptConnection should not exist. + // :Disconnect should be a method on ScriptSignal, and this would be avoided entirely. + callbacks:Rc>>, +} +pub struct ScriptConnection{ + signal:ScriptSignal, + function:mlua::Function, +} +impl ScriptSignal{ + pub fn new()->Self{ + Self{ + callbacks:Rc::new(RefCell::new(Vec::new())), + } + } + // This eats the Lua error + pub fn fire(&self,args:mlua::MultiValue){ + // Make a copy of the list in case Lua attempts to modify it during the loop + let functions=self.callbacks.borrow().clone(); + for function in functions{ + //wee let's allocate for our function calls + if let Err(e)=function.call::(args.clone()){ + println!("Script Signal Error: {e}"); + } + } + } + pub fn connect(&self,function:mlua::Function)->ScriptConnection{ + self.callbacks.borrow_mut().push(function.clone()); + ScriptConnection{ + signal:self.clone(), + function, + } + } +} +impl ScriptConnection{ + pub fn position(&self)->Option{ + self.signal.callbacks.borrow().iter().position(|function|function==&self.function) + } +} + +impl mlua::UserData for ScriptSignal{ + fn add_methods>(methods:&mut M){ + methods.add_method("Connect",|_lua,this,f:mlua::Function| + Ok(this.connect(f)) + ); + // Fire is not allowed to be called from Lua + // methods.add_method("Fire",|_lua,this,args:mlua::MultiValue| + // Ok(this.fire(args)) + // ); + } +} +impl mlua::FromLua for ScriptSignal{ + fn from_lua(value:mlua::Value,_lua:&mlua::Lua)->Result{ + match value{ + mlua::Value::UserData(ud)=>Ok(ud.borrow::()?.clone()), + other=>Err(mlua::Error::runtime(format!("Expected {} got {:?}",stringify!(ScriptSignal),other))), + } + } +} + +impl mlua::UserData for ScriptConnection{ + fn add_fields>(fields:&mut F){ + fields.add_field_method_get("Connected",|_,this|{ + Ok(this.position().is_some()) + }); + } + fn add_methods>(methods:&mut M){ + methods.add_method("Disconnect",|_,this,_:()|{ + if let Some(index)=this.position(){ + this.signal.callbacks.borrow_mut().remove(index); + } + Ok(()) + }); + } +} diff --git a/src/scheduler.rs b/src/scheduler.rs index 53170d1..b767aa1 100644 --- a/src/scheduler.rs +++ b/src/scheduler.rs @@ -2,14 +2,6 @@ pub use tick::Tick; mod tick{ #[derive(Clone,Copy,Default,Hash,PartialEq,Eq,PartialOrd,Ord)] pub struct Tick(u64); - impl Tick{ - pub const fn new(value:u64)->Self{ - Self(value) - } - pub const fn get(&self)->u64{ - self.0 - } - } impl std::ops::Add for Tick{ type Output=Self; fn add(self,rhs:u64)->Self::Output{ @@ -40,9 +32,6 @@ pub struct Scheduler{ } impl Scheduler{ - pub const fn tick(&self)->Tick{ - self.tick - } pub fn has_scheduled_threads(&self)->bool{ !self.schedule.is_empty() } From a6eb5e184c7a501eabc1b5ff3f139883f4ebc74c Mon Sep 17 00:00:00 2001 From: Quaternions Date: Thu, 17 Oct 2024 14:14:42 -0700 Subject: [PATCH 119/129] rename ClassFunctions -> ClassMethodsStore --- src/runner/instance.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 88ebc7b..688b7cc 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -8,7 +8,7 @@ use super::vector3::Vector3; pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{ //class functions store - lua.set_app_data(ClassFunctions::default()); + lua.set_app_data(ClassMethodsStore::default()); let instance_table=lua.create_table()?; @@ -34,10 +34,6 @@ fn dom_mut(lua:&mlua::Lua,mut f:impl FnMut(&mut WeakDom)->mlua::Result)->m let mut dom=lua.app_data_mut::<&'static mut WeakDom>().ok_or(mlua::Error::runtime("DataModel missing"))?; f(&mut *dom) } -fn class_functions_mut(lua:&mlua::Lua,mut f:impl FnMut(&mut ClassFunctions)->mlua::Result)->mlua::Result{ - let mut cf=lua.app_data_mut::().ok_or(mlua::Error::runtime("ClassFunctions missing"))?; - f(&mut *cf) -} fn coerce_float32(value:&mlua::Value)->Option{ match value{ @@ -262,7 +258,7 @@ impl mlua::UserData for Instance{ other=>return Err(mlua::Error::runtime(format!("Instance.__index Unsupported property type instance={} index={index_str} value={other:?}",instance.name))), } //find a function with a matching name - if let Some(function)=class_functions_mut(lua,|cf|{ + if let Some(function)=class_methods_store_mut(lua,|cf|{ let mut iter=SuperClassIter{ database:db, descriptor:Some(class), @@ -391,14 +387,14 @@ static CLASS_FUNCTION_DATABASE:CFD=phf::phf_map!{ /// A store of created functions for each Roblox class. /// Functions are created the first time they are accessed and stored in this data structure. #[derive(Default)] -struct ClassFunctions{ +struct ClassMethodsStore{ classes:HashMap<&'static str,//ClassName HashMap<&'static str,//Method name mlua::Function > > } -impl ClassFunctions{ +impl ClassMethodsStore{ /// return self.classes[class] or create the ClassMethods and then return it fn get_or_create_class_methods(&mut self,class:&str)->Option{ // Use get_entry to get the &'static str keys of the database @@ -433,6 +429,10 @@ impl ClassMethods<'_>{ }) } } +fn class_methods_store_mut(lua:&mlua::Lua,mut f:impl FnMut(&mut ClassMethodsStore)->mlua::Result)->mlua::Result{ + let mut cf=lua.app_data_mut::().ok_or(mlua::Error::runtime("ClassMethodsStore missing"))?; + f(&mut *cf) +} /// A virtual property pointer definition shorthand. type VirtualPropertyFunctionPointer=fn(&rbx_types::Variant)->Option; From 6f0749f8278e3c9470d06148d07166c4a99d4cf4 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 18 Oct 2024 10:33:07 -0700 Subject: [PATCH 120/129] associated values store (dumb) --- src/runner/instance.rs | 70 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index 688b7cc..d055567 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -9,6 +9,7 @@ use super::vector3::Vector3; pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{ //class functions store lua.set_app_data(ClassMethodsStore::default()); + lua.set_app_data(InstanceValueStore::default()); let instance_table=lua.create_table()?; @@ -30,7 +31,7 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{ } // LMAO look at this function! -fn dom_mut(lua:&mlua::Lua,mut f:impl FnMut(&mut WeakDom)->mlua::Result)->mlua::Result{ +pub fn dom_mut(lua:&mlua::Lua,mut f:impl FnMut(&mut WeakDom)->mlua::Result)->mlua::Result{ let mut dom=lua.app_data_mut::<&'static mut WeakDom>().ok_or(mlua::Error::runtime("DataModel missing"))?; f(&mut *dom) } @@ -271,6 +272,17 @@ impl mlua::UserData for Instance{ })?{ return function.into_lua(lua); } + + //find or create an associated userdata object + if let Some(value)=instance_value_store_mut(lua,|ivs|{ + //TODO: walk class tree somehow + match ivs.get_or_create_instance_values(&instance){ + Some(mut instance_values)=>instance_values.get_or_create_value(lua,index_str), + None=>Ok(None) + } + })?{ + return value.into_lua(lua); + } //find a child with a matching name find_first_child(dom,instance,index_str) .map(|instance|Instance::new(instance.referent())) @@ -481,3 +493,59 @@ fn find_virtual_property( //Transform Source property with provided function (virtual_property.pointer)(variant) } + +// lazy-loaded per-instance userdata values +// This whole thing is a bad idea and a garbage collection nightmare. +// TODO: recreate rbx_dom_weak with my own instance type that owns this data. +type CreateUserData=fn(&mlua::Lua)->mlua::Result; +type LUD=phf::Map<&'static str,// Class name + phf::Map<&'static str,// Value name + CreateUserData + > +>; +static LAZY_USER_DATA:LUD=phf::phf_map!{ +}; +#[derive(Default)] +pub struct InstanceValueStore{ + values:HashMap + >, +} +pub struct InstanceValues<'a>{ + named_values:&'static phf::Map<&'static str,CreateUserData>, + values:&'a mut HashMap<&'static str,mlua::AnyUserData>, +} +impl InstanceValueStore{ + pub fn get_or_create_instance_values(&mut self,instance:&rbx_dom_weak::Instance)->Option{ + LAZY_USER_DATA.get(instance.class.as_str()) + .map(|named_values| + InstanceValues{ + named_values, + values:self.values.entry(instance.referent()) + .or_insert_with(||HashMap::new()), + } + ) + } +} +impl InstanceValues<'_>{ + pub fn get_or_create_value(&mut self,lua:&mlua::Lua,index:&str)->mlua::Result>{ + Ok(match self.named_values.get_entry(index){ + Some((&static_index_str,&function_pointer))=>Some( + match self.values.entry(static_index_str){ + Entry::Occupied(entry)=>entry.get().clone(), + Entry::Vacant(entry)=>entry.insert( + function_pointer(lua)? + ).clone(), + } + ), + None=>None, + }) + } +} + +pub fn instance_value_store_mut(lua:&mlua::Lua,mut f:impl FnMut(&mut InstanceValueStore)->mlua::Result)->mlua::Result{ + let mut cf=lua.app_data_mut::().ok_or(mlua::Error::runtime("InstanceValueStore missing"))?; + f(&mut *cf) +} From bd38c6f1e485728024f09cdb805b4aefd6c5021d Mon Sep 17 00:00:00 2001 From: Quaternions Date: Thu, 17 Oct 2024 11:33:20 -0700 Subject: [PATCH 121/129] runservice --- src/runner/instance.rs | 14 ++++++++++---- src/runner/runner.rs | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/runner/instance.rs b/src/runner/instance.rs index d055567..62e52f3 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance.rs @@ -377,12 +377,13 @@ static CLASS_FUNCTION_DATABASE:CFD=phf::phf_map!{ "GetService"=>cf!(|lua,_this,service:mlua::String|{ dom_mut(lua,|dom|{ //dom.root_ref()==this.referent ? - match &*service.to_str()?{ - "Lighting"=>{ - let referent=find_first_child_of_class(dom,dom.root(),"Lighting") + let service=&*service.to_str()?; + match service{ + "Lighting"|"RunService"=>{ + let referent=find_first_child_of_class(dom,dom.root(),service) .map(|instance|instance.referent()) .unwrap_or_else(|| - dom.insert(dom.root_ref(),InstanceBuilder::new("Lighting")) + dom.insert(dom.root_ref(),InstanceBuilder::new(service)) ); Ok(Instance::new(referent)) }, @@ -504,6 +505,11 @@ type LUD=phf::Map<&'static str,// Class name > >; static LAZY_USER_DATA:LUD=phf::phf_map!{ + "RunService"=>phf::phf_map!{ + "RenderStepped"=>|lua|{ + lua.create_any_userdata(super::script_signal::ScriptSignal::new()) + }, + }, }; #[derive(Default)] pub struct InstanceValueStore{ diff --git a/src/runner/runner.rs b/src/runner/runner.rs index 39fa25a..debd1e1 100644 --- a/src/runner/runner.rs +++ b/src/runner/runner.rs @@ -120,4 +120,23 @@ impl Runnable<'_>{ } Ok(()) } + #[cfg(feature="run-service")] + pub fn run_service_step(&self)->Result<(),mlua::Error>{ + let render_stepped=super::instance::dom_mut(&self.lua,|dom|{ + let run_service=super::instance::find_first_child_of_class(dom,dom.root(),"RunService").ok_or_else(||mlua::Error::runtime("RunService missing"))?; + super::instance::instance_value_store_mut(&self.lua,|instance_value_store|{ + //unwrap because I trust my find_first_child_of_class function to + let mut instance_values=instance_value_store.get_or_create_instance_values(run_service).ok_or_else(||mlua::Error::runtime("RunService InstanceValues missing"))?; + let render_stepped=instance_values.get_or_create_value(&self.lua,"RenderStepped")?; + //let stepped=instance_values.get_or_create_value(&self.lua,"Stepped")?; + //let heartbeat=instance_values.get_or_create_value(&self.lua,"Heartbeat")?; + Ok(render_stepped) + }) + })?; + if let Some(render_stepped)=render_stepped{ + let signal:&super::script_signal::ScriptSignal=&*render_stepped.borrow()?; + signal.fire(mlua::MultiValue::new()); + } + Ok(()) + } } From d7d24cc64c9829f46134589496d955b6ce67a685 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 18 Oct 2024 10:22:13 -0700 Subject: [PATCH 122/129] move instance into module to further break it down --- src/runner/{ => instance}/instance.rs | 18 +++++++++--------- src/runner/instance/mod.rs | 2 ++ src/runner/runner.rs | 10 +++++----- 3 files changed, 16 insertions(+), 14 deletions(-) rename src/runner/{ => instance}/instance.rs (95%) create mode 100644 src/runner/instance/mod.rs diff --git a/src/runner/instance.rs b/src/runner/instance/instance.rs similarity index 95% rename from src/runner/instance.rs rename to src/runner/instance/instance.rs index 62e52f3..5c7f66c 100644 --- a/src/runner/instance.rs +++ b/src/runner/instance/instance.rs @@ -4,7 +4,7 @@ use mlua::{FromLua,FromLuaMulti,IntoLua,IntoLuaMulti}; use rbx_types::Ref; use rbx_dom_weak::{InstanceBuilder,WeakDom}; -use super::vector3::Vector3; +use crate::runner::vector3::Vector3; pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{ //class functions store @@ -253,8 +253,8 @@ impl mlua::UserData for Instance{ Some(rbx_types::Variant::Float32(val))=>return val.into_lua(lua), Some(rbx_types::Variant::Float64(val))=>return val.into_lua(lua), Some(rbx_types::Variant::Ref(val))=>return Instance::new(val).into_lua(lua), - Some(rbx_types::Variant::CFrame(cf))=>return Into::::into(cf).into_lua(lua), - Some(rbx_types::Variant::Vector3(v))=>return Into::::into(v).into_lua(lua), + Some(rbx_types::Variant::CFrame(cf))=>return Into::::into(cf).into_lua(lua), + Some(rbx_types::Variant::Vector3(v))=>return Into::::into(v).into_lua(lua), None=>(), other=>return Err(mlua::Error::runtime(format!("Instance.__index Unsupported property type instance={} index={index_str} value={other:?}",instance.name))), } @@ -319,7 +319,7 @@ impl mlua::UserData for Instance{ Ok(rbx_types::Enum::from_u32(*e.items.get(&*s.to_str()?).ok_or(mlua::Error::runtime("Invalid enum item"))?)) }, mlua::Value::UserData(any_user_data)=>{ - let e:super::r#enum::Enum=*any_user_data.borrow()?; + let e:crate::runner::r#enum::Enum=*any_user_data.borrow()?; Ok(e.into()) }, _=>Err(mlua::Error::runtime("Expected Enum")), @@ -327,7 +327,7 @@ impl mlua::UserData for Instance{ instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Enum(typed_value)); }, rbx_reflection::DataType::Value(rbx_types::VariantType::Color3)=>{ - let typed_value:super::color3::Color3=*value.as_userdata().ok_or(mlua::Error::runtime("Expected Color3"))?.borrow()?; + let typed_value:crate::runner::color3::Color3=*value.as_userdata().ok_or(mlua::Error::runtime("Expected Color3"))?.borrow()?; instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Color3(typed_value.into())); }, rbx_reflection::DataType::Value(rbx_types::VariantType::Bool)=>{ @@ -339,11 +339,11 @@ impl mlua::UserData for Instance{ instance.properties.insert(index_str.to_owned(),rbx_types::Variant::String(typed_value.to_owned())); }, rbx_reflection::DataType::Value(rbx_types::VariantType::NumberSequence)=>{ - let typed_value:super::number_sequence::NumberSequence=*value.as_userdata().ok_or(mlua::Error::runtime("Expected NumberSequence"))?.borrow()?; + let typed_value:crate::runner::number_sequence::NumberSequence=*value.as_userdata().ok_or(mlua::Error::runtime("Expected NumberSequence"))?.borrow()?; instance.properties.insert(index_str.to_owned(),rbx_types::Variant::NumberSequence(typed_value.into())); }, rbx_reflection::DataType::Value(rbx_types::VariantType::ColorSequence)=>{ - let typed_value:super::color_sequence::ColorSequence=*value.as_userdata().ok_or(mlua::Error::runtime("Expected ColorSequence"))?.borrow()?; + let typed_value:crate::runner::color_sequence::ColorSequence=*value.as_userdata().ok_or(mlua::Error::runtime("Expected ColorSequence"))?.borrow()?; instance.properties.insert(index_str.to_owned(),rbx_types::Variant::ColorSequence(typed_value.into())); }, other=>return Err(mlua::Error::runtime(format!("Unimplemented property type: {other:?}"))), @@ -393,7 +393,7 @@ static CLASS_FUNCTION_DATABASE:CFD=phf::phf_map!{ }), }, "Terrain"=>phf::phf_map!{ - "FillBlock"=>cf!(|_lua,_,_:(super::cframe::CFrame,Vector3,super::r#enum::Enum)|mlua::Result::Ok(())) + "FillBlock"=>cf!(|_lua,_,_:(crate::runner::cframe::CFrame,Vector3,crate::runner::r#enum::Enum)|mlua::Result::Ok(())) }, }; @@ -507,7 +507,7 @@ type LUD=phf::Map<&'static str,// Class name static LAZY_USER_DATA:LUD=phf::phf_map!{ "RunService"=>phf::phf_map!{ "RenderStepped"=>|lua|{ - lua.create_any_userdata(super::script_signal::ScriptSignal::new()) + lua.create_any_userdata(crate::runner::script_signal::ScriptSignal::new()) }, }, }; diff --git a/src/runner/instance/mod.rs b/src/runner/instance/mod.rs new file mode 100644 index 0000000..234af3d --- /dev/null +++ b/src/runner/instance/mod.rs @@ -0,0 +1,2 @@ +pub mod instance; +pub use instance::Instance; diff --git a/src/runner/runner.rs b/src/runner/runner.rs index debd1e1..7137229 100644 --- a/src/runner/runner.rs +++ b/src/runner/runner.rs @@ -37,7 +37,7 @@ fn init(lua:&mlua::Lua)->mlua::Result<()>{ super::color3::set_globals(lua,&globals)?; super::vector3::set_globals(lua,&globals)?; super::cframe::set_globals(lua,&globals)?; - super::instance::set_globals(lua,&globals)?; + super::instance::instance::set_globals(lua,&globals)?; super::number_sequence::set_globals(lua,&globals)?; super::color_sequence::set_globals(lua,&globals)?; @@ -88,7 +88,7 @@ impl Runnable<'_>{ } } pub fn run_script(&self,script:super::instance::Instance)->Result<(),Error>{ - let (name,source)=super::instance::get_name_source(&self.lua,script).map_err(Error::RustLua)?; + let (name,source)=super::instance::instance::get_name_source(&self.lua,script).map_err(Error::RustLua)?; self.lua.globals().raw_set("script",script).map_err(Error::RustLua)?; let f=self.lua.load(source.as_str()) .set_name(name).into_function().map_err(Error::RustLua)?; @@ -122,9 +122,9 @@ impl Runnable<'_>{ } #[cfg(feature="run-service")] pub fn run_service_step(&self)->Result<(),mlua::Error>{ - let render_stepped=super::instance::dom_mut(&self.lua,|dom|{ - let run_service=super::instance::find_first_child_of_class(dom,dom.root(),"RunService").ok_or_else(||mlua::Error::runtime("RunService missing"))?; - super::instance::instance_value_store_mut(&self.lua,|instance_value_store|{ + let render_stepped=super::instance::instance::dom_mut(&self.lua,|dom|{ + let run_service=super::instance::instance::find_first_child_of_class(dom,dom.root(),"RunService").ok_or_else(||mlua::Error::runtime("RunService missing"))?; + super::instance::instance::instance_value_store_mut(&self.lua,|instance_value_store|{ //unwrap because I trust my find_first_child_of_class function to let mut instance_values=instance_value_store.get_or_create_instance_values(run_service).ok_or_else(||mlua::Error::runtime("RunService InstanceValues missing"))?; let render_stepped=instance_values.get_or_create_value(&self.lua,"RenderStepped")?; From 24701dc5fe3dd930287e439ef2529b4032b23e65 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 18 Oct 2024 10:31:01 -0700 Subject: [PATCH 123/129] do not allocate strings for unused errors --- src/runner/instance/instance.rs | 38 ++++++++++++++++----------------- src/scheduler.rs | 2 +- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/runner/instance/instance.rs b/src/runner/instance/instance.rs index 5c7f66c..7dc1f46 100644 --- a/src/runner/instance/instance.rs +++ b/src/runner/instance/instance.rs @@ -17,7 +17,7 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{ instance_table.raw_set("new", lua.create_function(|lua,(class_name,parent):(mlua::String,Option)|{ let class_name_str=&*class_name.to_str()?; - let parent=parent.ok_or(mlua::Error::runtime("Nil Parent not yet supported"))?; + let parent=parent.ok_or_else(||mlua::Error::runtime("Nil Parent not yet supported"))?; dom_mut(lua,|dom|{ //TODO: Nil instances Ok(Instance::new(dom.insert(parent.referent,InstanceBuilder::new(class_name_str)))) @@ -32,7 +32,7 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{ // LMAO look at this function! pub fn dom_mut(lua:&mlua::Lua,mut f:impl FnMut(&mut WeakDom)->mlua::Result)->mlua::Result{ - let mut dom=lua.app_data_mut::<&'static mut WeakDom>().ok_or(mlua::Error::runtime("DataModel missing"))?; + let mut dom=lua.app_data_mut::<&'static mut WeakDom>().ok_or_else(||mlua::Error::runtime("DataModel missing"))?; f(&mut *dom) } @@ -89,10 +89,10 @@ impl Instance{ Self{referent} } pub fn get<'a>(&self,dom:&'a WeakDom)->mlua::Result<&'a rbx_dom_weak::Instance>{ - dom.get_by_ref(self.referent).ok_or(mlua::Error::runtime("Instance missing")) + dom.get_by_ref(self.referent).ok_or_else(||mlua::Error::runtime("Instance missing")) } pub fn get_mut<'a>(&self,dom:&'a mut WeakDom)->mlua::Result<&'a mut rbx_dom_weak::Instance>{ - dom.get_by_ref_mut(self.referent).ok_or(mlua::Error::runtime("Instance missing")) + dom.get_by_ref_mut(self.referent).ok_or_else(||mlua::Error::runtime("Instance missing")) } } type_from_lua_userdata!(Instance); @@ -125,7 +125,7 @@ impl mlua::UserData for Instance{ }) }); fields.add_field_method_set("Parent",|lua,this,val:Option|{ - let parent=val.ok_or(mlua::Error::runtime("Nil Parent not yet supported"))?; + let parent=val.ok_or_else(||mlua::Error::runtime("Nil Parent not yet supported"))?; dom_mut(lua,|dom|{ dom.transfer_within(this.referent,parent.referent); Ok(()) @@ -231,7 +231,7 @@ impl mlua::UserData for Instance{ let instance=this.get(dom)?; //println!("__index t={} i={index:?}",instance.name); let db=rbx_reflection_database::get(); - let class=db.classes.get(instance.class.as_str()).ok_or(mlua::Error::runtime("Class missing"))?; + let class=db.classes.get(instance.class.as_str()).ok_or_else(||mlua::Error::runtime("Class missing"))?; //Find existing property match instance.properties.get(index_str) .cloned() @@ -295,19 +295,19 @@ impl mlua::UserData for Instance{ //println!("__newindex t={} i={index:?} v={value:?}",instance.name); let index_str=&*index.to_str()?; let db=rbx_reflection_database::get(); - let class=db.classes.get(instance.class.as_str()).ok_or(mlua::Error::runtime("Class missing"))?; + let class=db.classes.get(instance.class.as_str()).ok_or_else(||mlua::Error::runtime("Class missing"))?; let mut iter=SuperClassIter{ database:db, descriptor:Some(class), }; - let property=iter.find_map(|cls|cls.properties.get(index_str)).ok_or(mlua::Error::runtime(format!("Property '{index_str}' missing on class '{}'",class.name)))?; + let property=iter.find_map(|cls|cls.properties.get(index_str)).ok_or_else(||mlua::Error::runtime(format!("Property '{index_str}' missing on class '{}'",class.name)))?; match &property.data_type{ rbx_reflection::DataType::Value(rbx_types::VariantType::Vector3)=>{ - let typed_value:Vector3=*value.as_userdata().ok_or(mlua::Error::runtime("Expected Userdata"))?.borrow()?; + let typed_value:Vector3=*value.as_userdata().ok_or_else(||mlua::Error::runtime("Expected Userdata"))?.borrow()?; instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Vector3(typed_value.into())); }, rbx_reflection::DataType::Value(rbx_types::VariantType::Float32)=>{ - let typed_value:f32=coerce_float32(&value).ok_or(mlua::Error::runtime("Expected f32"))?; + let typed_value:f32=coerce_float32(&value).ok_or_else(||mlua::Error::runtime("Expected f32"))?; instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Float32(typed_value)); }, rbx_reflection::DataType::Enum(enum_name)=>{ @@ -315,8 +315,8 @@ impl mlua::UserData for Instance{ &mlua::Value::Integer(int)=>Ok(rbx_types::Enum::from_u32(int as u32)), &mlua::Value::Number(num)=>Ok(rbx_types::Enum::from_u32(num as u32)), mlua::Value::String(s)=>{ - let e=db.enums.get(enum_name).ok_or(mlua::Error::runtime("Database DataType Enum name does not exist"))?; - Ok(rbx_types::Enum::from_u32(*e.items.get(&*s.to_str()?).ok_or(mlua::Error::runtime("Invalid enum item"))?)) + let e=db.enums.get(enum_name).ok_or_else(||mlua::Error::runtime("Database DataType Enum name does not exist"))?; + Ok(rbx_types::Enum::from_u32(*e.items.get(&*s.to_str()?).ok_or_else(||mlua::Error::runtime("Invalid enum item"))?)) }, mlua::Value::UserData(any_user_data)=>{ let e:crate::runner::r#enum::Enum=*any_user_data.borrow()?; @@ -327,23 +327,23 @@ impl mlua::UserData for Instance{ instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Enum(typed_value)); }, rbx_reflection::DataType::Value(rbx_types::VariantType::Color3)=>{ - let typed_value:crate::runner::color3::Color3=*value.as_userdata().ok_or(mlua::Error::runtime("Expected Color3"))?.borrow()?; + let typed_value:crate::runner::color3::Color3=*value.as_userdata().ok_or_else(||mlua::Error::runtime("Expected Color3"))?.borrow()?; instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Color3(typed_value.into())); }, rbx_reflection::DataType::Value(rbx_types::VariantType::Bool)=>{ - let typed_value=value.as_boolean().ok_or(mlua::Error::runtime("Expected boolean"))?; + let typed_value=value.as_boolean().ok_or_else(||mlua::Error::runtime("Expected boolean"))?; instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Bool(typed_value)); }, rbx_reflection::DataType::Value(rbx_types::VariantType::String)=>{ - let typed_value=value.as_str().ok_or(mlua::Error::runtime("Expected boolean"))?; + let typed_value=value.as_str().ok_or_else(||mlua::Error::runtime("Expected boolean"))?; instance.properties.insert(index_str.to_owned(),rbx_types::Variant::String(typed_value.to_owned())); }, rbx_reflection::DataType::Value(rbx_types::VariantType::NumberSequence)=>{ - let typed_value:crate::runner::number_sequence::NumberSequence=*value.as_userdata().ok_or(mlua::Error::runtime("Expected NumberSequence"))?.borrow()?; + let typed_value:crate::runner::number_sequence::NumberSequence=*value.as_userdata().ok_or_else(||mlua::Error::runtime("Expected NumberSequence"))?.borrow()?; instance.properties.insert(index_str.to_owned(),rbx_types::Variant::NumberSequence(typed_value.into())); }, rbx_reflection::DataType::Value(rbx_types::VariantType::ColorSequence)=>{ - let typed_value:crate::runner::color_sequence::ColorSequence=*value.as_userdata().ok_or(mlua::Error::runtime("Expected ColorSequence"))?.borrow()?; + let typed_value:crate::runner::color_sequence::ColorSequence=*value.as_userdata().ok_or_else(||mlua::Error::runtime("Expected ColorSequence"))?.borrow()?; instance.properties.insert(index_str.to_owned(),rbx_types::Variant::ColorSequence(typed_value.into())); }, other=>return Err(mlua::Error::runtime(format!("Unimplemented property type: {other:?}"))), @@ -443,7 +443,7 @@ impl ClassMethods<'_>{ } } fn class_methods_store_mut(lua:&mlua::Lua,mut f:impl FnMut(&mut ClassMethodsStore)->mlua::Result)->mlua::Result{ - let mut cf=lua.app_data_mut::().ok_or(mlua::Error::runtime("ClassMethodsStore missing"))?; + let mut cf=lua.app_data_mut::().ok_or_else(||mlua::Error::runtime("ClassMethodsStore missing"))?; f(&mut *cf) } @@ -552,6 +552,6 @@ impl InstanceValues<'_>{ } pub fn instance_value_store_mut(lua:&mlua::Lua,mut f:impl FnMut(&mut InstanceValueStore)->mlua::Result)->mlua::Result{ - let mut cf=lua.app_data_mut::().ok_or(mlua::Error::runtime("InstanceValueStore missing"))?; + let mut cf=lua.app_data_mut::().ok_or_else(||mlua::Error::runtime("InstanceValueStore missing"))?; f(&mut *cf) } diff --git a/src/scheduler.rs b/src/scheduler.rs index b767aa1..f665e9d 100644 --- a/src/scheduler.rs +++ b/src/scheduler.rs @@ -47,7 +47,7 @@ impl Scheduler{ } pub fn scheduler_mut(lua:&mlua::Lua,mut f:impl FnMut(&mut crate::scheduler::Scheduler)->mlua::Result)->mlua::Result{ - let mut scheduler=lua.app_data_mut::().ok_or(mlua::Error::runtime("Scheduler missing"))?; + let mut scheduler=lua.app_data_mut::().ok_or_else(||mlua::Error::runtime("Scheduler missing"))?; f(&mut *scheduler) } From fd2aa199498f5c4b7a8d851c380e4668cabddcf6 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 18 Oct 2024 11:09:00 -0700 Subject: [PATCH 124/129] rewrite ScriptSignal with more features --- src/runner/runner.rs | 3 +- src/runner/script_signal.rs | 128 +++++++++++++++++++++++++++++++----- 2 files changed, 112 insertions(+), 19 deletions(-) diff --git a/src/runner/runner.rs b/src/runner/runner.rs index 7137229..4b25bd6 100644 --- a/src/runner/runner.rs +++ b/src/runner/runner.rs @@ -33,6 +33,7 @@ fn init(lua:&mlua::Lua)->mlua::Result<()>{ #[cfg(feature="run-service")] crate::scheduler::set_globals(lua,&globals)?; + super::script_signal::set_globals(lua,&globals)?; super::r#enum::set_globals(lua,&globals)?; super::color3::set_globals(lua,&globals)?; super::vector3::set_globals(lua,&globals)?; @@ -135,7 +136,7 @@ impl Runnable<'_>{ })?; if let Some(render_stepped)=render_stepped{ let signal:&super::script_signal::ScriptSignal=&*render_stepped.borrow()?; - signal.fire(mlua::MultiValue::new()); + signal.fire(&mlua::MultiValue::new()); } Ok(()) } diff --git a/src/runner/script_signal.rs b/src/runner/script_signal.rs index 992ab95..45eab8e 100644 --- a/src/runner/script_signal.rs +++ b/src/runner/script_signal.rs @@ -1,44 +1,98 @@ use std::{cell::RefCell,rc::Rc}; +use mlua::UserDataFields; + #[derive(Clone)] -pub struct ScriptSignal{ - // Emulate the garbage roblox api. - // ScriptConnection should not exist. - // :Disconnect should be a method on ScriptSignal, and this would be avoided entirely. - callbacks:Rc>>, +struct FunctionList{ + functions:Vec, } -pub struct ScriptConnection{ - signal:ScriptSignal, - function:mlua::Function, -} -impl ScriptSignal{ +impl FunctionList{ pub fn new()->Self{ Self{ - callbacks:Rc::new(RefCell::new(Vec::new())), + functions:Vec::new(), } } // This eats the Lua error - pub fn fire(&self,args:mlua::MultiValue){ + pub fn fire(self,args:&mlua::MultiValue){ // Make a copy of the list in case Lua attempts to modify it during the loop - let functions=self.callbacks.borrow().clone(); - for function in functions{ + for function in self.functions{ //wee let's allocate for our function calls if let Err(e)=function.call::(args.clone()){ println!("Script Signal Error: {e}"); } } } +} +#[derive(Clone)] +struct RcFunctionList{ + functions:Rc>, +} +impl RcFunctionList{ + pub fn new()->Self{ + Self{ + functions:Rc::new(RefCell::new(FunctionList::new())), + } + } + pub fn fire(&self,args:&mlua::MultiValue){ + // Make a copy of the list in case Lua attempts to modify it during the loop + self.functions.borrow().clone().fire(args) + } +} +#[derive(Clone)] +pub struct ScriptSignal{ + // Emulate the garbage roblox api. + // ScriptConnection should not exist. + // :Disconnect should be a method on ScriptSignal, and this would be avoided entirely. + connections:RcFunctionList, + once:RcFunctionList, + wait:Rc>>, +} +pub struct ScriptConnection{ + connection:RcFunctionList, + function:mlua::Function, +} +impl ScriptSignal{ + pub fn new()->Self{ + Self{ + connections:RcFunctionList::new(), + once:RcFunctionList::new(), + wait:Rc::new(RefCell::new(Vec::new())), + } + } + pub fn fire(&self,args:&mlua::MultiValue){ + self.connections.fire(args); + //Replace the FunctionList with an empty one and drop the borrow + let once=std::mem::replace(&mut *self.once.functions.borrow_mut(),FunctionList::new()); + once.fire(args); + //resume threads waiting for this signal + let threads=std::mem::replace(&mut *self.wait.borrow_mut(),Vec::new()); + for thread in threads{ + if let Err(e)=thread.resume::(args.clone()){ + println!("Script Signal thread resume Error: {e}"); + } + } + } pub fn connect(&self,function:mlua::Function)->ScriptConnection{ - self.callbacks.borrow_mut().push(function.clone()); + self.connections.functions.borrow_mut().functions.push(function.clone()); ScriptConnection{ - signal:self.clone(), + connection:self.connections.clone(), function, } } + pub fn once(&self,function:mlua::Function)->ScriptConnection{ + self.once.functions.borrow_mut().functions.push(function.clone()); + ScriptConnection{ + connection:self.once.clone(), + function, + } + } + pub fn wait(&self,thread:mlua::Thread){ + self.wait.borrow_mut().push(thread); + } } impl ScriptConnection{ pub fn position(&self)->Option{ - self.signal.callbacks.borrow().iter().position(|function|function==&self.function) + self.connection.functions.borrow().functions.iter().position(|function|function==&self.function) } } @@ -47,6 +101,9 @@ impl mlua::UserData for ScriptSignal{ methods.add_method("Connect",|_lua,this,f:mlua::Function| Ok(this.connect(f)) ); + methods.add_method("Once",|_lua,this,f:mlua::Function| + Ok(this.once(f)) + ); // Fire is not allowed to be called from Lua // methods.add_method("Fire",|_lua,this,args:mlua::MultiValue| // Ok(this.fire(args)) @@ -71,9 +128,44 @@ impl mlua::UserData for ScriptConnection{ fn add_methods>(methods:&mut M){ methods.add_method("Disconnect",|_,this,_:()|{ if let Some(index)=this.position(){ - this.signal.callbacks.borrow_mut().remove(index); + this.connection.functions.borrow_mut().functions.remove(index); } Ok(()) }); } } + +fn wait_thread(lua:&mlua::Lua,this:ScriptSignal)->Result<(),mlua::Error>{ + Ok(this.wait(lua.current_thread())) +} + +// This is used to avoid calling coroutine.yield from the rust side. +const LUA_WAIT:&str= +"local coroutine_yield=coroutine.yield +local wait_thread=wait_thread +return function(signal) + wait_thread(signal) + return coroutine_yield() +end"; + +pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{ + let coroutine_table=globals.get::("coroutine")?; + let wait_thread=lua.create_function(wait_thread)?; + + //create wait function environment + let wait_env=lua.create_table()?; + wait_env.raw_set("coroutine",coroutine_table)?; + wait_env.raw_set("wait_thread",wait_thread)?; + + //construct wait function from Lua code + let wait=lua.load(LUA_WAIT) + .set_name("wait") + .set_environment(wait_env) + .call::(())?; + + lua.register_userdata_type::(|reg|{ + reg.add_field("Wait",wait); + })?; + + Ok(()) +} From 1e7814488e33d0c38dc78a90bcf30491a2b3d368 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Thu, 17 Oct 2024 18:51:02 -0700 Subject: [PATCH 125/129] register ScriptSignal UserData type because it's not initialized for some reason --- src/runner/script_signal.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/runner/script_signal.rs b/src/runner/script_signal.rs index 45eab8e..877f2b6 100644 --- a/src/runner/script_signal.rs +++ b/src/runner/script_signal.rs @@ -165,6 +165,7 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{ lua.register_userdata_type::(|reg|{ reg.add_field("Wait",wait); + mlua::UserData::register(reg); })?; Ok(()) From 3797d226e48833e6aecdd1c73258147be43e1f42 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Tue, 22 Oct 2024 16:25:39 -0700 Subject: [PATCH 126/129] v0.4.7 RBXScriptSignal + RunService --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5119b54..529ccb2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -402,7 +402,7 @@ dependencies = [ [[package]] name = "roblox_emulator" -version = "0.4.6" +version = "0.4.7" dependencies = [ "glam", "mlua", diff --git a/Cargo.toml b/Cargo.toml index 1fa8d5c..cdb42e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "roblox_emulator" -version = "0.4.6" +version = "0.4.7" edition = "2021" repository = "https://git.itzana.me/StrafesNET/roblox_emulator" license = "MIT OR Apache-2.0" From f51c5544925b66e2f721bff07efe8acd6e9f58fd Mon Sep 17 00:00:00 2001 From: Quaternions Date: Wed, 27 Nov 2024 14:45:42 -0800 Subject: [PATCH 127/129] update deps --- Cargo.lock | 75 +++++++++++++++++++++++++++++------------------------- Cargo.toml | 2 +- 2 files changed, 42 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 529ccb2..21f7633 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16,9 +16,9 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "base64" @@ -40,9 +40,9 @@ checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "blake3" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" +checksum = "b8ee0c1824c4dea5b5f81736aff91bae041d2c07ee1192bec91054e10e3e601e" dependencies = [ "arrayref", "arrayvec", @@ -53,9 +53,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" +checksum = "1a68f1f47cdf0ec8ee4b941b2eee2a80cb796db73118c0dd09ac63fbe405be22" dependencies = [ "memchr", "serde", @@ -69,9 +69,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.1.19" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d74707dde2ba56f86ae90effb3b43ddd369504387e718014de010cec7959800" +checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" dependencies = [ "shlex", ] @@ -88,6 +88,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + [[package]] name = "getrandom" version = "0.2.15" @@ -101,9 +107,9 @@ dependencies = [ [[package]] name = "glam" -version = "0.29.0" +version = "0.29.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28091a37a5d09b555cb6628fd954da299b536433834f5b8e59eba78e0cbbf8a" +checksum = "dc46dd3ec48fdd8e693a98d2b8bafae273a2d54c1de02a2a7e3d57d501f39677" [[package]] name = "lazy_static" @@ -113,9 +119,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.158" +version = "0.2.166" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "c2ccc108bbc0b1331bd061864e7cd823c0cab660bbe6970e66e2c0614decde36" [[package]] name = "libloading" @@ -139,9 +145,9 @@ dependencies = [ [[package]] name = "luau0-src" -version = "0.10.3+luau640" +version = "0.11.2+luau653" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f39d12b514a676c943990cfbe6200fedcb9c293c8c9219d29be512a6969be92" +checksum = "02313a53daf1fae25e82f7e7ca56180b72d1f08c514426672877cd957298201c" dependencies = [ "cc", ] @@ -154,11 +160,12 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "mlua" -version = "0.10.0-beta.2" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200dd4c8e5f81416d43a023b9921c3cbf01d828094b23a90b26826c3840ba4f3" +checksum = "0ae9546e4a268c309804e8bbb7526e31cbfdedca7cd60ac1b987d0b212e0d876" dependencies = [ "bstr", + "either", "libloading", "mlua-sys", "num-traits", @@ -168,9 +175,9 @@ dependencies = [ [[package]] name = "mlua-sys" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebe026d6bd1583a9cf9080e189030ddaea7e6f5f0deb366a8e26f8a26c4135b8" +checksum = "efa6bf1a64f06848749b7e7727417f4ec2121599e2a10ef0a8a3888b0e9a5a0d" dependencies = [ "cc", "cfg-if", @@ -260,9 +267,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "ppv-lite86" @@ -275,9 +282,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -427,18 +434,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.210" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", @@ -465,9 +472,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "syn" -version = "2.0.77" +version = "2.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" dependencies = [ "proc-macro2", "quote", @@ -476,18 +483,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", @@ -496,9 +503,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "wasi" diff --git a/Cargo.toml b/Cargo.toml index cdb42e4..3521348 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ run-service=[] [dependencies] glam = "0.29.0" -mlua = { version = "0.10.0-beta", features = ["luau"] } +mlua = { version = "0.10.1", features = ["luau"] } phf = { version = "0.11.2", features = ["macros"] } rbx_dom_weak = { version = "2.7.0", registry = "strafesnet" } rbx_reflection = { version = "4.7.0", registry = "strafesnet" } From ef4e6995980a41fee9691fd9c038bcbf42d610e7 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Tue, 31 Dec 2024 23:42:43 -0800 Subject: [PATCH 128/129] implement VectorToWorldSpace --- src/runner/cframe.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/runner/cframe.rs b/src/runner/cframe.rs index e9f77c2..bab3c3e 100644 --- a/src/runner/cframe.rs +++ b/src/runner/cframe.rs @@ -146,6 +146,9 @@ impl mlua::UserData for CFrame{ this.0.matrix3.y_axis.z, this.0.matrix3.z_axis.z, ))); + methods.add_method("VectorToWorldSpace",|_,this,v:Vector3| + Ok(Vector3(this.0.transform_vector3a(v.0))) + ); //methods.add_meta_method(mlua::MetaMethod::Mul,|_,this,val:&Vector3|Ok(Vector3(this.0.matrix3*val.0+this.0.translation))); methods.add_meta_function(mlua::MetaMethod::Mul,|_,(this,val):(Self,Self)|Ok(Self(this.0*val.0))); From 002ebbb52ef273a09a52e01ce5d3c97d7efbca2b Mon Sep 17 00:00:00 2001 From: Quaternions Date: Thu, 2 Jan 2025 19:50:11 -0800 Subject: [PATCH 129/129] roblox_emulator: move into folder --- .gitignore => lib/roblox_emulator/.gitignore | 0 Cargo.lock => lib/roblox_emulator/Cargo.lock | 0 Cargo.toml => lib/roblox_emulator/Cargo.toml | 0 LICENSE-APACHE => lib/roblox_emulator/LICENSE-APACHE | 0 LICENSE-MIT => lib/roblox_emulator/LICENSE-MIT | 0 README.md => lib/roblox_emulator/README.md | 0 {src => lib/roblox_emulator/src}/context.rs | 0 {src => lib/roblox_emulator/src}/lib.rs | 0 {src => lib/roblox_emulator/src}/runner/cframe.rs | 0 {src => lib/roblox_emulator/src}/runner/color3.rs | 0 {src => lib/roblox_emulator/src}/runner/color_sequence.rs | 0 {src => lib/roblox_emulator/src}/runner/enum.rs | 0 {src => lib/roblox_emulator/src}/runner/instance/instance.rs | 0 {src => lib/roblox_emulator/src}/runner/instance/mod.rs | 0 {src => lib/roblox_emulator/src}/runner/macros.rs | 0 {src => lib/roblox_emulator/src}/runner/mod.rs | 0 {src => lib/roblox_emulator/src}/runner/number_sequence.rs | 0 {src => lib/roblox_emulator/src}/runner/runner.rs | 0 {src => lib/roblox_emulator/src}/runner/script_signal.rs | 0 {src => lib/roblox_emulator/src}/runner/vector3.rs | 0 {src => lib/roblox_emulator/src}/scheduler.rs | 0 {src => lib/roblox_emulator/src}/tests.rs | 0 22 files changed, 0 insertions(+), 0 deletions(-) rename .gitignore => lib/roblox_emulator/.gitignore (100%) rename Cargo.lock => lib/roblox_emulator/Cargo.lock (100%) rename Cargo.toml => lib/roblox_emulator/Cargo.toml (100%) rename LICENSE-APACHE => lib/roblox_emulator/LICENSE-APACHE (100%) rename LICENSE-MIT => lib/roblox_emulator/LICENSE-MIT (100%) rename README.md => lib/roblox_emulator/README.md (100%) rename {src => lib/roblox_emulator/src}/context.rs (100%) rename {src => lib/roblox_emulator/src}/lib.rs (100%) rename {src => lib/roblox_emulator/src}/runner/cframe.rs (100%) rename {src => lib/roblox_emulator/src}/runner/color3.rs (100%) rename {src => lib/roblox_emulator/src}/runner/color_sequence.rs (100%) rename {src => lib/roblox_emulator/src}/runner/enum.rs (100%) rename {src => lib/roblox_emulator/src}/runner/instance/instance.rs (100%) rename {src => lib/roblox_emulator/src}/runner/instance/mod.rs (100%) rename {src => lib/roblox_emulator/src}/runner/macros.rs (100%) rename {src => lib/roblox_emulator/src}/runner/mod.rs (100%) rename {src => lib/roblox_emulator/src}/runner/number_sequence.rs (100%) rename {src => lib/roblox_emulator/src}/runner/runner.rs (100%) rename {src => lib/roblox_emulator/src}/runner/script_signal.rs (100%) rename {src => lib/roblox_emulator/src}/runner/vector3.rs (100%) rename {src => lib/roblox_emulator/src}/scheduler.rs (100%) rename {src => lib/roblox_emulator/src}/tests.rs (100%) diff --git a/.gitignore b/lib/roblox_emulator/.gitignore similarity index 100% rename from .gitignore rename to lib/roblox_emulator/.gitignore diff --git a/Cargo.lock b/lib/roblox_emulator/Cargo.lock similarity index 100% rename from Cargo.lock rename to lib/roblox_emulator/Cargo.lock diff --git a/Cargo.toml b/lib/roblox_emulator/Cargo.toml similarity index 100% rename from Cargo.toml rename to lib/roblox_emulator/Cargo.toml diff --git a/LICENSE-APACHE b/lib/roblox_emulator/LICENSE-APACHE similarity index 100% rename from LICENSE-APACHE rename to lib/roblox_emulator/LICENSE-APACHE diff --git a/LICENSE-MIT b/lib/roblox_emulator/LICENSE-MIT similarity index 100% rename from LICENSE-MIT rename to lib/roblox_emulator/LICENSE-MIT diff --git a/README.md b/lib/roblox_emulator/README.md similarity index 100% rename from README.md rename to lib/roblox_emulator/README.md diff --git a/src/context.rs b/lib/roblox_emulator/src/context.rs similarity index 100% rename from src/context.rs rename to lib/roblox_emulator/src/context.rs diff --git a/src/lib.rs b/lib/roblox_emulator/src/lib.rs similarity index 100% rename from src/lib.rs rename to lib/roblox_emulator/src/lib.rs diff --git a/src/runner/cframe.rs b/lib/roblox_emulator/src/runner/cframe.rs similarity index 100% rename from src/runner/cframe.rs rename to lib/roblox_emulator/src/runner/cframe.rs diff --git a/src/runner/color3.rs b/lib/roblox_emulator/src/runner/color3.rs similarity index 100% rename from src/runner/color3.rs rename to lib/roblox_emulator/src/runner/color3.rs diff --git a/src/runner/color_sequence.rs b/lib/roblox_emulator/src/runner/color_sequence.rs similarity index 100% rename from src/runner/color_sequence.rs rename to lib/roblox_emulator/src/runner/color_sequence.rs diff --git a/src/runner/enum.rs b/lib/roblox_emulator/src/runner/enum.rs similarity index 100% rename from src/runner/enum.rs rename to lib/roblox_emulator/src/runner/enum.rs diff --git a/src/runner/instance/instance.rs b/lib/roblox_emulator/src/runner/instance/instance.rs similarity index 100% rename from src/runner/instance/instance.rs rename to lib/roblox_emulator/src/runner/instance/instance.rs diff --git a/src/runner/instance/mod.rs b/lib/roblox_emulator/src/runner/instance/mod.rs similarity index 100% rename from src/runner/instance/mod.rs rename to lib/roblox_emulator/src/runner/instance/mod.rs diff --git a/src/runner/macros.rs b/lib/roblox_emulator/src/runner/macros.rs similarity index 100% rename from src/runner/macros.rs rename to lib/roblox_emulator/src/runner/macros.rs diff --git a/src/runner/mod.rs b/lib/roblox_emulator/src/runner/mod.rs similarity index 100% rename from src/runner/mod.rs rename to lib/roblox_emulator/src/runner/mod.rs diff --git a/src/runner/number_sequence.rs b/lib/roblox_emulator/src/runner/number_sequence.rs similarity index 100% rename from src/runner/number_sequence.rs rename to lib/roblox_emulator/src/runner/number_sequence.rs diff --git a/src/runner/runner.rs b/lib/roblox_emulator/src/runner/runner.rs similarity index 100% rename from src/runner/runner.rs rename to lib/roblox_emulator/src/runner/runner.rs diff --git a/src/runner/script_signal.rs b/lib/roblox_emulator/src/runner/script_signal.rs similarity index 100% rename from src/runner/script_signal.rs rename to lib/roblox_emulator/src/runner/script_signal.rs diff --git a/src/runner/vector3.rs b/lib/roblox_emulator/src/runner/vector3.rs similarity index 100% rename from src/runner/vector3.rs rename to lib/roblox_emulator/src/runner/vector3.rs diff --git a/src/scheduler.rs b/lib/roblox_emulator/src/scheduler.rs similarity index 100% rename from src/scheduler.rs rename to lib/roblox_emulator/src/scheduler.rs diff --git a/src/tests.rs b/lib/roblox_emulator/src/tests.rs similarity index 100% rename from src/tests.rs rename to lib/roblox_emulator/src/tests.rs