roblox_emulator: refactor nil instances

This commit is contained in:
Quaternions 2025-04-22 19:59:11 -07:00
parent 8bfc201d1f
commit 3d399635d7
Signed by: Quaternions
GPG Key ID: D0DF5964F79AC131
2 changed files with 15 additions and 40 deletions
lib/roblox_emulator/src
context.rs
runner/instance

@ -13,24 +13,15 @@ pub enum ServicesError{
pub struct Services{
pub(crate) game:Ref,
pub(crate) workspace:Ref,
pub(crate) nil:Ref,
}
impl Services{
fn get_or_create_services(dom:&mut WeakDom)->Result<Services,ServicesError>{
let game=dom.root_ref();
// error if workspace does not exist
let workspace=*dom.root().children().iter().find(|&&r|
dom.get_by_ref(r).is_some_and(|instance|instance.class=="Workspace")
).ok_or(ServicesError::WorkspaceNotFound)?;
// the root nil instance does not have a parent
let nil=dom.insert(Ref::none(),InstanceBuilder::new("Nil")
.with_referent(<Ref as std::str::FromStr>::from_str("ffffffffffffffffffffffffffffffff").unwrap())
);
fn find_services(dom:&WeakDom)->Result<Services,ServicesError>{
Ok(Services{
game,
workspace,
nil,
workspace:*dom.root().children().iter().find(|&&r|
dom.get_by_ref(r).is_some_and(|instance|instance.class=="Workspace")
).ok_or(ServicesError::WorkspaceNotFound)?,
game:dom.root_ref(),
})
}
}
@ -42,8 +33,8 @@ pub struct Context{
}
impl Context{
pub fn from_place(mut dom:WeakDom)->Result<Context,ServicesError>{
let services=Services::get_or_create_services(&mut dom)?;
pub fn from_place(dom:WeakDom)->Result<Context,ServicesError>{
let services=Services::find_services(&dom)?;
Ok(Self{dom,services})
}
pub fn script_singleton(source:String)->(Context,crate::runner::instance::Instance){
@ -106,15 +97,9 @@ impl Context{
game.properties.insert(static_ustr("workspace"),rbx_types::Variant::Ref(workspace));
game.properties.insert(static_ustr("Workspace"),rbx_types::Variant::Ref(workspace));
}
dom.insert(game,InstanceBuilder::new("Lighting"));
// the root nil instance does not have a parent
let nil=dom.insert(Ref::none(),InstanceBuilder::new("Nil")
.with_referent(<Ref as std::str::FromStr>::from_str("ffffffffffffffffffffffffffffffff").unwrap())
);
let services=Services{game,workspace,nil};
let services=Services{game,workspace};
Self{dom,services}
}
}

@ -22,9 +22,9 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
table.raw_set("new",
lua.create_function(|lua,(class_name,parent):(mlua::String,Option<Instance>)|{
let class_name_str=&*class_name.to_str()?;
let parent=parent.unwrap_or(Instance::nil());
let parent_ref=parent.map_or(Ref::none(),|instance|instance.referent);
dom_mut(lua,|dom|{
Ok(Instance::new_unchecked(dom.insert(parent.referent,InstanceBuilder::new(class_name_str))))
Ok(Instance::new_unchecked(dom.insert(parent_ref,InstanceBuilder::new(class_name_str))))
})
})?
)?;
@ -107,16 +107,7 @@ impl Instance{
Self{referent}
}
pub fn new(referent:Ref)->Option<Self>{
match referent=="ffffffffffffffffffffffffffffffff".parse().unwrap(){
true=>None,
false=>Some(Self{referent})
}
}
// Using a sentinel value as a ref for nil instances because global variables are hard.
pub fn nil()->Self{
Self{
referent:"ffffffffffffffffffffffffffffffff".parse().unwrap()
}
referent.is_some().then_some(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_else(||mlua::Error::runtime("Instance missing"))
@ -137,10 +128,10 @@ impl mlua::UserData for Instance{
}
fields.add_field_method_get("parent",get_parent);
fields.add_field_method_get("Parent",get_parent);
fn set_parent(lua:&mlua::Lua,this:&mut Instance,val:Option<Instance>)->mlua::Result<()>{
let parent=val.unwrap_or(Instance::nil());
fn set_parent(lua:&mlua::Lua,this:&mut Instance,new_parent:Option<Instance>)->mlua::Result<()>{
let parent_ref=new_parent.map_or(Ref::none(),|instance|instance.referent);
dom_mut(lua,|dom|{
dom.transfer_within(this.referent,parent.referent);
dom.transfer_within(this.referent,parent_ref);
Ok(())
})
}
@ -171,7 +162,6 @@ impl mlua::UserData for Instance{
fn clone(lua:&mlua::Lua,this:&Instance,_:())->mlua::Result<Instance>{
dom_mut(lua,|dom|{
let instance_ref=dom.clone_within(this.referent);
dom.transfer_within(instance_ref,Instance::nil().referent);
Ok(Instance::new_unchecked(instance_ref))
})
}
@ -271,7 +261,7 @@ impl mlua::UserData for Instance{
methods.add_method("IsA",is_a);
methods.add_method("Destroy",|lua,this,()|
dom_mut(lua,|dom|{
dom.transfer_within(this.referent,Instance::nil().referent);
dom.transfer_within(this.referent,Ref::none());
Ok(())
})
);