Compare commits
5 Commits
bf6e169126
...
0aed94568e
Author | SHA1 | Date | |
---|---|---|---|
0aed94568e | |||
cfa24c98a6 | |||
9898c53de8 | |||
4ce6fb2155 | |||
b672c1360d |
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -402,7 +402,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "roblox_emulator"
|
name = "roblox_emulator"
|
||||||
version = "0.4.4"
|
version = "0.4.5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"glam",
|
"glam",
|
||||||
"mlua",
|
"mlua",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "roblox_emulator"
|
name = "roblox_emulator"
|
||||||
version = "0.4.4"
|
version = "0.4.5"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
repository = "https://git.itzana.me/StrafesNET/roblox_emulator"
|
repository = "https://git.itzana.me/StrafesNET/roblox_emulator"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
@ -46,11 +46,21 @@ impl Context{
|
|||||||
self.superclass_iter("LuaSourceContainer").map(crate::runner::instance::Instance::new).collect()
|
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>{
|
pub fn find_services(&self)->Option<Services>{
|
||||||
Some(Services{
|
Some(Services{
|
||||||
workspace:*self.dom.root().children().iter().find(|&&r|
|
workspace:self.get_service("Workspace")?,
|
||||||
self.dom.get_by_ref(r).is_some_and(|instance|instance.class=="Workspace")
|
nil:self.get_service("Nil")?,
|
||||||
)?,
|
|
||||||
game:self.dom.root_ref(),
|
game:self.dom.root_ref(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -60,13 +70,15 @@ impl Context{
|
|||||||
|
|
||||||
//insert services
|
//insert services
|
||||||
let game=self.dom.root_ref();
|
let game=self.dom.root_ref();
|
||||||
let terrain_bldr=InstanceBuilder::new("Terrain");
|
let workspace=self.get_or_create_service("Workspace",|context|{
|
||||||
let workspace=self.dom.insert(game,
|
let terrain_bldr=InstanceBuilder::new("Terrain");
|
||||||
InstanceBuilder::new("Workspace")
|
context.dom.insert(game,
|
||||||
//Set Workspace.Terrain property equal to Terrain
|
InstanceBuilder::new("Workspace")
|
||||||
.with_property("Terrain",terrain_bldr.referent())
|
//Set Workspace.Terrain property equal to Terrain
|
||||||
.with_child(terrain_bldr)
|
.with_property("Terrain",terrain_bldr.referent())
|
||||||
);
|
.with_child(terrain_bldr)
|
||||||
|
)
|
||||||
|
});
|
||||||
{
|
{
|
||||||
//Lowercase and upper case workspace property!
|
//Lowercase and upper case workspace property!
|
||||||
let game=self.dom.root_mut();
|
let game=self.dom.root_mut();
|
||||||
@ -74,6 +86,17 @@ impl Context{
|
|||||||
game.properties.insert("Workspace".to_owned(),rbx_types::Variant::Ref(workspace));
|
game.properties.insert("Workspace".to_owned(),rbx_types::Variant::Ref(workspace));
|
||||||
}
|
}
|
||||||
self.dom.insert(game,InstanceBuilder::new("Lighting"));
|
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
|
//transfer original root instances into workspace
|
||||||
for instance in children{
|
for instance in children{
|
||||||
@ -83,6 +106,7 @@ impl Context{
|
|||||||
Services{
|
Services{
|
||||||
game,
|
game,
|
||||||
workspace,
|
workspace,
|
||||||
|
nil,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,4 +114,5 @@ impl Context{
|
|||||||
pub struct Services{
|
pub struct Services{
|
||||||
pub game:Ref,
|
pub game:Ref,
|
||||||
pub workspace:Ref,
|
pub workspace:Ref,
|
||||||
|
pub nil:Ref,
|
||||||
}
|
}
|
||||||
|
31
src/runner/color_sequence.rs
Normal file
31
src/runner/color_sequence.rs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#[derive(Clone,Copy)]
|
||||||
|
pub struct ColorSequence{}
|
||||||
|
impl ColorSequence{
|
||||||
|
pub const fn new()->Self{
|
||||||
|
Self{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Into<rbx_types::ColorSequence> for ColorSequence{
|
||||||
|
fn into(self)->rbx_types::ColorSequence{
|
||||||
|
rbx_types::ColorSequence{
|
||||||
|
keypoints:Vec::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
|
||||||
|
let number_sequence_table=lua.create_table()?;
|
||||||
|
|
||||||
|
number_sequence_table.raw_set("new",
|
||||||
|
lua.create_function(|_,_:mlua::MultiValue|
|
||||||
|
Ok(ColorSequence::new())
|
||||||
|
)?
|
||||||
|
)?;
|
||||||
|
|
||||||
|
globals.set("ColorSequence",number_sequence_table)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
impl mlua::UserData for ColorSequence{}
|
||||||
|
type_from_lua_userdata!(ColorSequence);
|
@ -16,9 +16,8 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
|
|||||||
instance_table.raw_set("new",
|
instance_table.raw_set("new",
|
||||||
lua.create_function(|lua,(class_name,parent):(mlua::String,Option<Instance>)|{
|
lua.create_function(|lua,(class_name,parent):(mlua::String,Option<Instance>)|{
|
||||||
let class_name_str=&*class_name.to_str()?;
|
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|{
|
dom_mut(lua,|dom|{
|
||||||
//TODO: Nil instances
|
|
||||||
Ok(Instance::new(dom.insert(parent.referent,InstanceBuilder::new(class_name_str))))
|
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{
|
pub const fn new(referent:Ref)->Self{
|
||||||
Self{referent}
|
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>{
|
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"))
|
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|{
|
fields.add_field_method_get("Parent",|lua,this|{
|
||||||
dom_mut(lua,|dom|{
|
dom_mut(lua,|dom|{
|
||||||
let instance=this.get(dom)?;
|
let instance=this.get(dom)?;
|
||||||
|
//TODO: return nil when parent is Nil instances
|
||||||
Ok(Instance::new(instance.parent()))
|
Ok(Instance::new(instance.parent()))
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
fields.add_field_method_set("Parent",|lua,this,val:Option<Instance>|{
|
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_mut(lua,|dom|{
|
||||||
dom.transfer_within(this.referent,parent.referent);
|
dom.transfer_within(this.referent,parent.referent);
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -218,7 +224,7 @@ impl mlua::UserData for Instance{
|
|||||||
);
|
);
|
||||||
methods.add_method("Destroy",|lua,this,()|
|
methods.add_method("Destroy",|lua,this,()|
|
||||||
dom_mut(lua,|dom|{
|
dom_mut(lua,|dom|{
|
||||||
dom.destroy(this.referent);
|
dom.transfer_within(this.referent,Instance::nil().referent);
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -330,6 +336,14 @@ impl mlua::UserData for Instance{
|
|||||||
let typed_value=value.as_str().ok_or(mlua::Error::runtime("Expected boolean"))?;
|
let typed_value=value.as_str().ok_or(mlua::Error::runtime("Expected boolean"))?;
|
||||||
instance.properties.insert(index_str.to_owned(),rbx_types::Variant::String(typed_value.to_owned()));
|
instance.properties.insert(index_str.to_owned(),rbx_types::Variant::String(typed_value.to_owned()));
|
||||||
},
|
},
|
||||||
|
rbx_reflection::DataType::Value(rbx_types::VariantType::NumberSequence)=>{
|
||||||
|
let typed_value:super::number_sequence::NumberSequence=*value.as_userdata().ok_or(mlua::Error::runtime("Expected NumberSequence"))?.borrow()?;
|
||||||
|
instance.properties.insert(index_str.to_owned(),rbx_types::Variant::NumberSequence(typed_value.into()));
|
||||||
|
},
|
||||||
|
rbx_reflection::DataType::Value(rbx_types::VariantType::ColorSequence)=>{
|
||||||
|
let typed_value:super::color_sequence::ColorSequence=*value.as_userdata().ok_or(mlua::Error::runtime("Expected ColorSequence"))?.borrow()?;
|
||||||
|
instance.properties.insert(index_str.to_owned(),rbx_types::Variant::ColorSequence(typed_value.into()));
|
||||||
|
},
|
||||||
other=>return Err(mlua::Error::runtime(format!("Unimplemented property type: {other:?}"))),
|
other=>return Err(mlua::Error::runtime(format!("Unimplemented property type: {other:?}"))),
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -7,5 +7,7 @@ mod color3;
|
|||||||
mod cframe;
|
mod cframe;
|
||||||
mod vector3;
|
mod vector3;
|
||||||
pub mod instance;
|
pub mod instance;
|
||||||
|
mod number_sequence;
|
||||||
|
mod color_sequence;
|
||||||
|
|
||||||
pub use runner::{Runner,Error};
|
pub use runner::{Runner,Error};
|
||||||
|
31
src/runner/number_sequence.rs
Normal file
31
src/runner/number_sequence.rs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#[derive(Clone,Copy)]
|
||||||
|
pub struct NumberSequence{}
|
||||||
|
impl NumberSequence{
|
||||||
|
pub const fn new()->Self{
|
||||||
|
Self{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Into<rbx_types::NumberSequence> for NumberSequence{
|
||||||
|
fn into(self)->rbx_types::NumberSequence{
|
||||||
|
rbx_types::NumberSequence{
|
||||||
|
keypoints:Vec::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
|
||||||
|
let number_sequence_table=lua.create_table()?;
|
||||||
|
|
||||||
|
number_sequence_table.raw_set("new",
|
||||||
|
lua.create_function(|_,_:mlua::MultiValue|
|
||||||
|
Ok(NumberSequence::new())
|
||||||
|
)?
|
||||||
|
)?;
|
||||||
|
|
||||||
|
globals.set("NumberSequence",number_sequence_table)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
impl mlua::UserData for NumberSequence{}
|
||||||
|
type_from_lua_userdata!(NumberSequence);
|
@ -34,6 +34,8 @@ fn init(lua:&mlua::Lua)->mlua::Result<()>{
|
|||||||
super::vector3::set_globals(lua,&globals)?;
|
super::vector3::set_globals(lua,&globals)?;
|
||||||
super::cframe::set_globals(lua,&globals)?;
|
super::cframe::set_globals(lua,&globals)?;
|
||||||
super::instance::set_globals(lua,&globals)?;
|
super::instance::set_globals(lua,&globals)?;
|
||||||
|
super::number_sequence::set_globals(lua,&globals)?;
|
||||||
|
super::color_sequence::set_globals(lua,&globals)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user