Compare commits

...

2 Commits
master ... nil

Author SHA1 Message Date
0aed94568e Context::get_or_create_service 2024-10-14 12:15:39 -07:00
cfa24c98a6 hack together nil instances 2024-10-14 11:55:17 -07:00
2 changed files with 45 additions and 14 deletions

View File

@ -46,11 +46,21 @@ impl Context{
self.superclass_iter("LuaSourceContainer").map(crate::runner::instance::Instance::new).collect()
}
fn get_service(&self,service:&str)->Option<Ref>{
self.dom.root().children().iter().find(|&&r|
self.dom.get_by_ref(r).is_some_and(|instance|instance.class==service)
).copied()
}
fn get_or_create_service(&mut self,service:&str,mut create:impl FnMut(&mut Context)->Ref)->Ref{
match self.get_service(service){
Some(referent)=>referent,
None=>create(self),
}
}
pub fn find_services(&self)->Option<Services>{
Some(Services{
workspace:*self.dom.root().children().iter().find(|&&r|
self.dom.get_by_ref(r).is_some_and(|instance|instance.class=="Workspace")
)?,
workspace:self.get_service("Workspace")?,
nil:self.get_service("Nil")?,
game:self.dom.root_ref(),
})
}
@ -60,13 +70,15 @@ impl Context{
//insert services
let game=self.dom.root_ref();
let workspace=self.get_or_create_service("Workspace",|context|{
let terrain_bldr=InstanceBuilder::new("Terrain");
let workspace=self.dom.insert(game,
context.dom.insert(game,
InstanceBuilder::new("Workspace")
//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();
@ -74,6 +86,17 @@ impl Context{
game.properties.insert("Workspace".to_owned(),rbx_types::Variant::Ref(workspace));
}
self.dom.insert(game,InstanceBuilder::new("Lighting"));
// Special nonexistent class that holds instances parented to nil,
// which can still be referenced by scripts.
// Using a sentinel value as a ref because global variables are hard.
let nil=self.get_or_create_service("Nil",|context|
context.dom.insert(
game,InstanceBuilder::new("Nil")
.with_referent(
<Ref as std::str::FromStr>::from_str("ffffffffffffffffffffffffffffffff").unwrap()
)
)
);
//transfer original root instances into workspace
for instance in children{
@ -83,6 +106,7 @@ impl Context{
Services{
game,
workspace,
nil,
}
}
}
@ -90,4 +114,5 @@ impl Context{
pub struct Services{
pub game:Ref,
pub workspace:Ref,
pub nil:Ref,
}

View File

@ -16,9 +16,8 @@ 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<Instance>)|{
let class_name_str=&*class_name.to_str()?;
let parent=parent.ok_or(mlua::Error::runtime("Nil Parent not yet supported"))?;
let parent=parent.unwrap_or(Instance::nil());
dom_mut(lua,|dom|{
//TODO: Nil instances
Ok(Instance::new(dom.insert(parent.referent,InstanceBuilder::new(class_name_str))))
})
})?
@ -91,6 +90,12 @@ impl Instance{
pub const fn new(referent:Ref)->Self{
Self{referent}
}
// Using a sentinel value as a ref for nil instances because global variables are hard.
pub fn nil()->Self{
Self{
referent:<Ref as std::str::FromStr>::from_str("ffffffffffffffffffffffffffffffff").unwrap()
}
}
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"))
}
@ -124,11 +129,12 @@ impl mlua::UserData for Instance{
fields.add_field_method_get("Parent",|lua,this|{
dom_mut(lua,|dom|{
let instance=this.get(dom)?;
//TODO: return nil when parent is Nil instances
Ok(Instance::new(instance.parent()))
})
});
fields.add_field_method_set("Parent",|lua,this,val:Option<Instance>|{
let parent=val.ok_or(mlua::Error::runtime("Nil Parent not yet supported"))?;
let parent=val.unwrap_or(Instance::nil());
dom_mut(lua,|dom|{
dom.transfer_within(this.referent,parent.referent);
Ok(())
@ -218,7 +224,7 @@ impl mlua::UserData for Instance{
);
methods.add_method("Destroy",|lua,this,()|
dom_mut(lua,|dom|{
dom.destroy(this.referent);
dom.transfer_within(this.referent,Instance::nil().referent);
Ok(())
})
);