rbx_loader: stronger Place & Model types

This commit is contained in:
2025-04-22 14:35:17 -07:00
parent 08d47b0f63
commit 615372aad5
5 changed files with 58 additions and 46 deletions

View File

@@ -1,5 +1,6 @@
use std::io::Read;
use rbx_dom_weak::WeakDom;
use roblox_emulator::context::Context;
use strafesnet_deferred_loader::deferred_loader::{LoadFailureMode,MeshDeferredLoader,RenderConfigDeferredLoader};
mod rbx;
@@ -27,12 +28,6 @@ impl Model{
fn new(dom:WeakDom)->Self{
Self{dom}
}
pub fn into_place(self)->Place{
let Self{mut dom}=self;
let context=roblox_emulator::context::Context::from_mut(&mut dom);
let services=context.convert_into_place();
Place{dom,services}
}
pub fn to_snf(&self,failure_mode:LoadFailureMode)->Result<strafesnet_common::map::CompleteMap,LoadError>{
to_snf(self,failure_mode)
}
@@ -44,21 +39,20 @@ impl AsRef<WeakDom> for Model{
}
pub struct Place{
dom:WeakDom,
context:Context,
services:roblox_emulator::context::Services,
}
impl Place{
pub fn new(dom:WeakDom)->Option<Self>{
let context=roblox_emulator::context::Context::from_ref(&dom);
Some(Self{
services:context.find_services()?,
dom,
pub fn new(dom:WeakDom)->Result<Self,roblox_emulator::context::ServicesError>{
let (context,services)=Context::from_place(dom)?;
Ok(Self{
context,
services,
})
}
pub fn run_scripts(&mut self){
let Place{dom,services}=self;
let Place{context,services}=self;
let runner=roblox_emulator::runner::Runner::new().unwrap();
let context=roblox_emulator::context::Context::from_mut(dom);
let scripts=context.scripts();
let runnable=runner.runnable_context_with_services(context,services).unwrap();
for script in scripts{
@@ -73,7 +67,16 @@ impl Place{
}
impl AsRef<WeakDom> for Place{
fn as_ref(&self)->&WeakDom{
&self.dom
self.context.as_ref()
}
}
impl From<Model> for Place{
fn from(model:Model)->Self{
let (context,services)=Context::from_model(model.dom);
Self{
context,
services,
}
}
}

View File

@@ -5,32 +5,34 @@ fn static_ustr(s:&'static str)->rbx_dom_weak::Ustr{
rbx_dom_weak::ustr(s)
}
#[derive(Debug)]
pub enum ServicesError{
Workspace,
}
#[repr(transparent)]
pub struct Context{
pub(crate)dom:WeakDom,
}
impl Context{
pub const fn new(dom:WeakDom)->Self{
Self{dom}
pub fn from_place(dom:WeakDom)->Result<(Context,Services),ServicesError>{
// TODO: create nil instances
let context=Self{dom};
let services=context.find_services()?;
Ok((context,services))
}
pub fn script_singleton(source:String)->(Context,crate::runner::instance::Instance,Services){
let script=InstanceBuilder::new("Script")
.with_property("Source",rbx_types::Variant::String(source));
let script_ref=script.referent();
let mut context=Self::new(WeakDom::new(
let dom=WeakDom::new(
InstanceBuilder::new("DataModel")
.with_child(script)
));
let services=context.convert_into_place();
);
let (context,services)=Self::from_model(dom);
(context,crate::runner::instance::Instance::new(script_ref),services)
}
pub fn from_ref(dom:&WeakDom)->&Context{
unsafe{&*(dom as *const WeakDom as *const Context)}
}
pub fn from_mut(dom:&mut WeakDom)->&mut Context{
unsafe{&mut *(dom as *mut WeakDom as *mut Context)}
}
/// 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();
@@ -46,22 +48,22 @@ impl Context{
self.superclass_iter("LuaSourceContainer").map(crate::runner::instance::Instance::new).collect()
}
pub fn find_services(&self)->Option<Services>{
Some(Services{
pub fn find_services(&self)->Result<Services,ServicesError>{
Ok(Services{
workspace:*self.dom.root().children().iter().find(|&&r|
self.dom.get_by_ref(r).is_some_and(|instance|instance.class=="Workspace")
)?,
).ok_or(ServicesError::Workspace)?,
game:self.dom.root_ref(),
})
}
pub fn convert_into_place(&mut self)->Services{
pub fn from_model(mut dom:WeakDom)->(Context,Services){
//snapshot root instances
let children=self.dom.root().children().to_owned();
let children=dom.root().children().to_owned();
//insert services
let game=self.dom.root_ref();
let game=dom.root_ref();
let terrain_bldr=InstanceBuilder::new("Terrain");
let workspace=self.dom.insert(game,
let workspace=dom.insert(game,
InstanceBuilder::new("Workspace")
//Set Workspace.Terrain property equal to Terrain
.with_property("Terrain",terrain_bldr.referent())
@@ -69,25 +71,32 @@ impl Context{
);
{
//Lowercase and upper case workspace property!
let game=self.dom.root_mut();
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));
}
self.dom.insert(game,InstanceBuilder::new("Lighting"));
dom.insert(game,InstanceBuilder::new("Lighting"));
//transfer original root instances into workspace
for instance in children{
self.dom.transfer_within(instance,workspace);
dom.transfer_within(instance,workspace);
}
Services{
game,
workspace,
(
Self{dom},
Services{game,workspace},
)
}
}
impl AsRef<WeakDom> for Context{
fn as_ref(&self)->&WeakDom{
&self.dom
}
}
pub struct Services{
pub game:Ref,
pub workspace:Ref,
pub(crate) game:Ref,
pub(crate) workspace:Ref,
}

View File

@@ -12,7 +12,7 @@ pub enum Error{
error:mlua::Error
},
RustLua(mlua::Error),
NoServices,
Services(crate::context::ServicesError),
}
impl std::fmt::Display for Error{
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
@@ -54,7 +54,7 @@ impl Runner{
Ok(runner)
}
pub fn runnable_context<'a>(self,context:&'a mut Context)->Result<Runnable<'a>,Error>{
let services=context.find_services().ok_or(Error::NoServices)?;
let services=context.find_services().map_err(Error::Services)?;
self.runnable_context_with_services(context,&services)
}
pub fn runnable_context_with_services<'a>(self,context:&'a mut Context,services:&crate::context::Services)->Result<Runnable<'a>,Error>{

View File

@@ -423,7 +423,7 @@ async fn convert_to_snf(path:&Path,output_folder:PathBuf)->AResult<()>{
std::io::Cursor::new(entire_file)
).map_err(ConvertError::RobloxRead)?;
let mut place=model.into_place();
let mut place=strafesnet_rbx_loader::Place::from(model);
place.run_scripts();
let map=place.to_snf(LoadFailureMode::DefaultToNone).map_err(ConvertError::RobloxLoad)?;

View File

@@ -97,7 +97,7 @@ pub fn load<P:AsRef<std::path::Path>>(path:P)->Result<LoadFormat,LoadError>{
ReadFormat::SNFM(map)=>Ok(LoadFormat::Map(map)),
#[cfg(feature="roblox")]
ReadFormat::Roblox(model)=>{
let mut place=model.into_place();
let mut place=strafesnet_rbx_loader::Place::from(model);
place.run_scripts();
Ok(LoadFormat::Map(
place.to_snf(LoadFailureMode::DefaultToNone).map_err(LoadError::LoadRoblox)?