122 lines
3.9 KiB
Rust
122 lines
3.9 KiB
Rust
use crate::util::static_ustr;
|
|
use rbx_dom_weak::{types::Ref,InstanceBuilder,WeakDom};
|
|
|
|
#[derive(Debug)]
|
|
pub enum ServicesError{
|
|
WorkspaceNotFound,
|
|
}
|
|
impl std::fmt::Display for ServicesError{
|
|
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
|
write!(f,"{self:?}")
|
|
}
|
|
}
|
|
impl std::error::Error for ServicesError{}
|
|
|
|
pub struct Services{
|
|
pub(crate) game:Ref,
|
|
pub(crate) workspace:Ref,
|
|
}
|
|
|
|
impl Services{
|
|
fn find_services(dom:&WeakDom)->Result<Services,ServicesError>{
|
|
Ok(Services{
|
|
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(),
|
|
})
|
|
}
|
|
}
|
|
|
|
pub type LuaAppData=&'static mut WeakDom;
|
|
pub struct Context{
|
|
pub(crate)dom:WeakDom,
|
|
pub(crate)services:Services,
|
|
}
|
|
|
|
impl Context{
|
|
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){
|
|
let script=InstanceBuilder::new("Script")
|
|
.with_property("Source",rbx_types::Variant::String(source));
|
|
let script_ref=script.referent();
|
|
let dom=WeakDom::new(
|
|
InstanceBuilder::new("DataModel")
|
|
.with_child(script)
|
|
);
|
|
let context=Self::from_model(dom);
|
|
(context,crate::runner::instance::Instance::new_unchecked(script_ref))
|
|
}
|
|
/// Creates an iterator over all items of a particular class.
|
|
pub fn superclass_iter<'a>(&'a self,superclass:&'a str)->impl Iterator<Item=Ref>+'a{
|
|
let db=rbx_reflection_database::get();
|
|
let Some(superclass)=db.classes.get(superclass)else{
|
|
panic!("Invalid class");
|
|
};
|
|
self.dom.descendants().filter_map(|instance|{
|
|
let class=db.classes.get(instance.class.as_str())?;
|
|
db.has_superclass(class,superclass).then(||instance.referent())
|
|
})
|
|
}
|
|
pub fn scripts(&self)->Vec<crate::runner::instance::Instance>{
|
|
self.superclass_iter("Script")
|
|
.filter_map(|script_ref|{
|
|
let script=self.dom.get_by_ref(script_ref)?;
|
|
if let None|Some(rbx_dom_weak::types::Variant::Bool(false))=script.properties.get(&static_ustr("Disabled")){
|
|
return Some(crate::runner::instance::Instance::new_unchecked(script_ref));
|
|
}
|
|
None
|
|
})
|
|
.collect()
|
|
}
|
|
|
|
pub fn from_model(mut dom:WeakDom)->Context{
|
|
//snapshot root instances
|
|
let children=dom.root().children().to_owned();
|
|
|
|
//insert services
|
|
let game=dom.root_ref();
|
|
let terrain_bldr=InstanceBuilder::new("Terrain")
|
|
.with_properties([
|
|
("CFrame",rbx_dom_weak::types::Variant::CFrame(rbx_dom_weak::types::CFrame::new(rbx_dom_weak::types::Vector3::new(0.0,0.0,0.0),rbx_dom_weak::types::Matrix3::identity()))),
|
|
("Size",rbx_dom_weak::types::Variant::Vector3(rbx_dom_weak::types::Vector3::new(1.0,1.0,1.0))),
|
|
("Velocity",rbx_dom_weak::types::Variant::Vector3(rbx_dom_weak::types::Vector3::new(0.0,0.0,0.0))),
|
|
("Transparency",rbx_dom_weak::types::Variant::Float32(0.0)),
|
|
("Color",rbx_dom_weak::types::Variant::Color3uint8(rbx_dom_weak::types::Color3uint8::new(255,255,255))),
|
|
("CanCollide",rbx_dom_weak::types::Variant::Bool(true)),
|
|
]);
|
|
let workspace=dom.insert(game,
|
|
InstanceBuilder::new("Workspace")
|
|
//Set Workspace.Terrain property equal to Terrain
|
|
.with_property("Terrain",terrain_bldr.referent())
|
|
.with_child(terrain_bldr)
|
|
);
|
|
|
|
//transfer original root instances into workspace
|
|
for instance in children{
|
|
dom.transfer_within(instance,workspace);
|
|
}
|
|
|
|
{
|
|
//Lowercase and upper case workspace property!
|
|
let game=dom.root_mut();
|
|
// TODO: DELETE THIS!
|
|
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"));
|
|
|
|
let services=Services{game,workspace};
|
|
Self{dom,services}
|
|
}
|
|
}
|
|
|
|
impl AsRef<WeakDom> for Context{
|
|
fn as_ref(&self)->&WeakDom{
|
|
&self.dom
|
|
}
|
|
}
|