From bb8e131464d85ffe798af41aafa79a36fc006680 Mon Sep 17 00:00:00 2001 From: Quaternions <krakow20@gmail.com> Date: Thu, 17 Apr 2025 18:05:33 -0700 Subject: [PATCH] roblox_emulator: use extended instances --- .../src/runner/instance/instance.rs | 73 ++++++------------- lib/roblox_emulator/src/runner/runner.rs | 17 ++--- 2 files changed, 27 insertions(+), 63 deletions(-) diff --git a/lib/roblox_emulator/src/runner/instance/instance.rs b/lib/roblox_emulator/src/runner/instance/instance.rs index 5e4d836..2bb131c 100644 --- a/lib/roblox_emulator/src/runner/instance/instance.rs +++ b/lib/roblox_emulator/src/runner/instance/instance.rs @@ -15,7 +15,6 @@ fn static_ustr(s:&'static str)->rbx_dom_weak::Ustr{ 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 table=lua.create_table()?; @@ -329,16 +328,13 @@ impl mlua::UserData for Instance{ } //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) - } - })?{ + let instance=this.get_mut(dom)?; + if let Some(value)=get_or_create_userdata(instance,lua,index_str)?{ return value.into_lua(lua); } + // drop mutable borrow //find a child with a matching name + let instance=this.get(dom)?; find_first_child(dom,instance,index_str) .map(|instance|Instance::new_unchecked(instance.referent())) .into_lua(lua) @@ -585,8 +581,6 @@ fn find_virtual_property( } // 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<mlua::AnyUserData>; type LUD=phf::Map<&'static str,// Class name phf::Map<&'static str,// Value name @@ -616,47 +610,22 @@ static LAZY_USER_DATA:LUD=phf::phf_map!{ "DescendantRemoved"=>create_script_signal, }, }; -#[derive(Default)] -pub struct InstanceValueStore{ - values:HashMap<Ref, - HashMap<&'static str, - mlua::AnyUserData - > - >, -} -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<InstanceValues>{ - 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()), - } - ) +fn get_or_create_userdata(instance:&mut rbx_dom_weak::Instance,lua:&mlua::Lua,index:&str)->mlua::Result<Option<mlua::AnyUserData>>{ + use std::collections::hash_map::Entry; + let db=rbx_reflection_database::get(); + let Some(class)=db.classes.get(instance.class.as_str())else{ + return Ok(None) + }; + if let Some((&static_str,create_userdata))=db.superclasses_iter(class).find_map(|superclass| + // find pair (class,index) + LAZY_USER_DATA.get(&superclass.name) + .and_then(|map|map.get_entry(index)) + ){ + let index_ustr=static_ustr(static_str); + return Ok(Some(match instance.userdata.entry(index_ustr){ + Entry::Occupied(entry)=>entry.get().clone(), + Entry::Vacant(entry)=>entry.insert(create_userdata(lua)?).clone(), + })); } -} -impl InstanceValues<'_>{ - pub fn get_or_create_value(&mut self,lua:&mlua::Lua,index:&str)->mlua::Result<Option<mlua::AnyUserData>>{ - 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<T>(lua:&mlua::Lua,mut f:impl FnMut(&mut InstanceValueStore)->mlua::Result<T>)->mlua::Result<T>{ - let mut cf=lua.app_data_mut::<InstanceValueStore>().ok_or_else(||mlua::Error::runtime("InstanceValueStore missing"))?; - f(&mut *cf) + Ok(None) } diff --git a/lib/roblox_emulator/src/runner/runner.rs b/lib/roblox_emulator/src/runner/runner.rs index 817bc6d..8220fe6 100644 --- a/lib/roblox_emulator/src/runner/runner.rs +++ b/lib/roblox_emulator/src/runner/runner.rs @@ -123,20 +123,15 @@ impl Runnable<'_>{ } #[cfg(feature="run-service")] pub fn run_service_step(&self)->Result<(),mlua::Error>{ - let render_stepped=super::instance::instance::dom_mut(&self.lua,|dom|{ + let render_stepped_signal=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")?; - //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) + Ok(match run_service.userdata.get(&rbx_dom_weak::ustr("RenderStepped")){ + Some(render_stepped)=>Some(render_stepped.borrow::<super::script_signal::ScriptSignal>()?.clone()), + None=>None }) })?; - if let Some(render_stepped)=render_stepped{ - let signal:&super::script_signal::ScriptSignal=&*render_stepped.borrow()?; - signal.fire(&mlua::MultiValue::new()); + if let Some(render_stepped_signal)=render_stepped_signal{ + render_stepped_signal.fire(&mlua::MultiValue::new()); } Ok(()) }