Compare commits

..

7 Commits

Author SHA1 Message Date
8d99c788ef RBXScriptSignal 2024-10-17 13:11:16 -07:00
43ab764b18 wip runservice 2024-10-17 11:33:20 -07:00
bffc5bb8f1 comment 2024-10-17 11:32:40 -07:00
f8f659e8ce specialize coerce f64 code 2024-10-16 23:07:32 -07:00
135103364d remove this when rbx-dom updates 2024-10-16 21:22:45 -07:00
368ce7da9e v0.4.6 thread scheduler 2024-10-16 21:22:01 -07:00
13621022e1 export Runnable type 2024-10-16 21:22:01 -07:00
7 changed files with 107 additions and 24 deletions

2
.cargo/config.toml Normal file
View File

@ -0,0 +1,2 @@
[registries.strafesnet]
index = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/"

2
Cargo.lock generated
View File

@ -402,7 +402,7 @@ dependencies = [
[[package]] [[package]]
name = "roblox_emulator" name = "roblox_emulator"
version = "0.4.5" version = "0.4.6"
dependencies = [ dependencies = [
"glam", "glam",
"mlua", "mlua",

View File

@ -1,6 +1,6 @@
[package] [package]
name = "roblox_emulator" name = "roblox_emulator"
version = "0.4.5" version = "0.4.6"
edition = "2021" edition = "2021"
repository = "https://git.itzana.me/StrafesNET/roblox_emulator" repository = "https://git.itzana.me/StrafesNET/roblox_emulator"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"

View File

@ -369,12 +369,13 @@ static CLASS_FUNCTION_DATABASE:CFD=phf::phf_map!{
"GetService"=>cf!(|lua,_this,service:mlua::String|{ "GetService"=>cf!(|lua,_this,service:mlua::String|{
dom_mut(lua,|dom|{ dom_mut(lua,|dom|{
//dom.root_ref()==this.referent ? //dom.root_ref()==this.referent ?
match &*service.to_str()?{ let service=&*service.to_str()?;
"Lighting"=>{ match service{
let referent=find_first_child_of_class(dom,dom.root(),"Lighting") "Lighting"|"RunService"=>{
let referent=find_first_child_of_class(dom,dom.root(),service)
.map(|instance|instance.referent()) .map(|instance|instance.referent())
.unwrap_or_else(|| .unwrap_or_else(||
dom.insert(dom.root_ref(),InstanceBuilder::new("Lighting")) dom.insert(dom.root_ref(),InstanceBuilder::new(service))
); );
Ok(Instance::new(referent)) Ok(Instance::new(referent))
}, },

View File

@ -7,7 +7,8 @@ mod color3;
mod cframe; mod cframe;
mod vector3; mod vector3;
pub mod instance; pub mod instance;
mod number_sequence; mod script_signal;
mod color_sequence; mod color_sequence;
mod number_sequence;
pub use runner::{Runner,Error}; pub use runner::{Runner,Runnable,Error};

View File

@ -0,0 +1,72 @@
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<RefCell<Vec<mlua::Function>>>,
}
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 allocate_twice=self.callbacks.borrow().clone();
for function in allocate_twice{
//wee let's allocate for our function calls
if let Err(e)=function.call::<mlua::MultiValue>(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<usize>{
self.signal.callbacks.borrow().iter().position(|function|function==&self.function)
}
}
impl mlua::UserData for ScriptSignal{
fn add_methods<M:mlua::UserDataMethods<Self>>(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))
// );
}
}
//type_from_lua_userdata!(ScriptSignal);
impl mlua::UserData for ScriptConnection{
fn add_fields<F:mlua::UserDataFields<Self>>(fields:&mut F){
fields.add_field_method_get("Connected",|_,this|{
Ok(this.position().is_some())
});
}
fn add_methods<M:mlua::UserDataMethods<Self>>(methods:&mut M){
methods.add_method("Disconnect",|_,this,_:()|{
if let Some(index)=this.position(){
this.signal.callbacks.borrow_mut().remove(index);
}
Ok(())
});
}
}

View File

@ -57,27 +57,34 @@ impl Scheduler{
} }
} }
fn coerce_float64(value:&mlua::Value)->Option<f64>{
match value{
&mlua::Value::Integer(i)=>Some(i as f64),
&mlua::Value::Number(f)=>Some(f),
_=>None,
}
}
pub fn scheduler_mut<T>(lua:&mlua::Lua,mut f:impl FnMut(&mut crate::scheduler::Scheduler)->mlua::Result<T>)->mlua::Result<T>{ pub fn scheduler_mut<T>(lua:&mlua::Lua,mut f:impl FnMut(&mut crate::scheduler::Scheduler)->mlua::Result<T>)->mlua::Result<T>{
let mut scheduler=lua.app_data_mut::<crate::scheduler::Scheduler>().ok_or(mlua::Error::runtime("Scheduler missing"))?; let mut scheduler=lua.app_data_mut::<crate::scheduler::Scheduler>().ok_or(mlua::Error::runtime("Scheduler missing"))?;
f(&mut *scheduler) f(&mut *scheduler)
} }
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 schedule_thread=lua.create_function(move|lua,dt:mlua::Value|{ let schedule_thread=lua.create_function(|lua,dt:mlua::Value|{
let delay=coerce_float64(&dt).ok_or(mlua::Error::runtime("Expected float"))?.max(0.0)*60.0; let delay=match dt{
if delay<u64::MAX as f64{ mlua::Value::Integer(i)=>i.max(0) as u64*60,
scheduler_mut(lua,|scheduler|{ mlua::Value::Number(f)=>{
scheduler.schedule_thread((delay as u64).max(2),lua.current_thread()); let delay=f.max(0.0)*60.0;
Ok(()) match delay.classify(){
}).unwrap(); 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{
return Ok(());
},
_=>(),
} }
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(()) Ok(())
})
})?; })?;
let wait_env=lua.create_table()?; let wait_env=lua.create_table()?;
wait_env.raw_set("coroutine",globals.get::<mlua::Table>("coroutine")?)?; wait_env.raw_set("coroutine",globals.get::<mlua::Table>("coroutine")?)?;