Compare commits
1 Commits
nil
...
virtual-pr
| Author | SHA1 | Date | |
|---|---|---|---|
| e799f6a094 |
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -402,7 +402,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "roblox_emulator"
|
||||
version = "0.4.5"
|
||||
version = "0.4.4"
|
||||
dependencies = [
|
||||
"glam",
|
||||
"mlua",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "roblox_emulator"
|
||||
version = "0.4.5"
|
||||
version = "0.4.4"
|
||||
edition = "2021"
|
||||
repository = "https://git.itzana.me/StrafesNET/roblox_emulator"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
@@ -46,21 +46,11 @@ 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.get_service("Workspace")?,
|
||||
nil:self.get_service("Nil")?,
|
||||
workspace:*self.dom.root().children().iter().find(|&&r|
|
||||
self.dom.get_by_ref(r).is_some_and(|instance|instance.class=="Workspace")
|
||||
)?,
|
||||
game:self.dom.root_ref(),
|
||||
})
|
||||
}
|
||||
@@ -70,15 +60,13 @@ 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");
|
||||
context.dom.insert(game,
|
||||
InstanceBuilder::new("Workspace")
|
||||
//Set Workspace.Terrain property equal to Terrain
|
||||
.with_property("Terrain",terrain_bldr.referent())
|
||||
.with_child(terrain_bldr)
|
||||
)
|
||||
});
|
||||
let terrain_bldr=InstanceBuilder::new("Terrain");
|
||||
let workspace=self.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();
|
||||
@@ -86,17 +74,6 @@ 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{
|
||||
@@ -106,7 +83,6 @@ impl Context{
|
||||
Services{
|
||||
game,
|
||||
workspace,
|
||||
nil,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -114,5 +90,4 @@ impl Context{
|
||||
pub struct Services{
|
||||
pub game:Ref,
|
||||
pub workspace:Ref,
|
||||
pub nil:Ref,
|
||||
}
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
#[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,8 +16,9 @@ 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.unwrap_or(Instance::nil());
|
||||
let parent=parent.ok_or(mlua::Error::runtime("Nil Parent not yet supported"))?;
|
||||
dom_mut(lua,|dom|{
|
||||
//TODO: Nil instances
|
||||
Ok(Instance::new(dom.insert(parent.referent,InstanceBuilder::new(class_name_str))))
|
||||
})
|
||||
})?
|
||||
@@ -90,12 +91,6 @@ 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"))
|
||||
}
|
||||
@@ -129,12 +124,11 @@ 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.unwrap_or(Instance::nil());
|
||||
let parent=val.ok_or(mlua::Error::runtime("Nil Parent not yet supported"))?;
|
||||
dom_mut(lua,|dom|{
|
||||
dom.transfer_within(this.referent,parent.referent);
|
||||
Ok(())
|
||||
@@ -224,7 +218,7 @@ impl mlua::UserData for Instance{
|
||||
);
|
||||
methods.add_method("Destroy",|lua,this,()|
|
||||
dom_mut(lua,|dom|{
|
||||
dom.transfer_within(this.referent,Instance::nil().referent);
|
||||
dom.destroy(this.referent);
|
||||
Ok(())
|
||||
})
|
||||
);
|
||||
@@ -273,11 +267,12 @@ impl mlua::UserData for Instance{
|
||||
database:db,
|
||||
descriptor:Some(class),
|
||||
};
|
||||
iter.find_map(|class|{
|
||||
let mut class_methods=cf.get_or_create_class_methods(&class.name)?;
|
||||
class_methods.get_or_create_function(lua,index_str)
|
||||
.transpose()
|
||||
}).transpose()
|
||||
iter.find_map(|class|
|
||||
cf.get_or_create_class_methods(&class.name)
|
||||
.and_then(|mut class_methods|
|
||||
class_methods.get_or_create_function(lua,index_str).transpose()
|
||||
)
|
||||
).transpose()
|
||||
})?{
|
||||
return function.into_lua(lua);
|
||||
}
|
||||
@@ -301,7 +296,7 @@ impl mlua::UserData for Instance{
|
||||
let property=iter.find_map(|cls|cls.properties.get(index_str)).ok_or(mlua::Error::runtime(format!("Property '{index_str}' missing on class '{}'",class.name)))?;
|
||||
match &property.data_type{
|
||||
rbx_reflection::DataType::Value(rbx_types::VariantType::Vector3)=>{
|
||||
let typed_value:Vector3=*value.as_userdata().ok_or(mlua::Error::runtime("Expected Userdata"))?.borrow()?;
|
||||
let typed_value:Vector3=value.as_userdata().ok_or(mlua::Error::runtime("Expected Userdata"))?.take()?;
|
||||
instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Vector3(typed_value.into()));
|
||||
},
|
||||
rbx_reflection::DataType::Value(rbx_types::VariantType::Float32)=>{
|
||||
@@ -317,7 +312,7 @@ impl mlua::UserData for Instance{
|
||||
Ok(rbx_types::Enum::from_u32(*e.items.get(&*s.to_str()?).ok_or(mlua::Error::runtime("Invalid enum item"))?))
|
||||
},
|
||||
mlua::Value::UserData(any_user_data)=>{
|
||||
let e:super::r#enum::Enum=*any_user_data.borrow()?;
|
||||
let e:super::r#enum::Enum=any_user_data.take()?;
|
||||
Ok(e.into())
|
||||
},
|
||||
_=>Err(mlua::Error::runtime("Expected Enum")),
|
||||
@@ -325,7 +320,7 @@ impl mlua::UserData for Instance{
|
||||
instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Enum(typed_value));
|
||||
},
|
||||
rbx_reflection::DataType::Value(rbx_types::VariantType::Color3)=>{
|
||||
let typed_value:super::color3::Color3=*value.as_userdata().ok_or(mlua::Error::runtime("Expected Color3"))?.borrow()?;
|
||||
let typed_value:super::color3::Color3=value.as_userdata().ok_or(mlua::Error::runtime("Expected Color3"))?.take()?;
|
||||
instance.properties.insert(index_str.to_owned(),rbx_types::Variant::Color3(typed_value.into()));
|
||||
},
|
||||
rbx_reflection::DataType::Value(rbx_types::VariantType::Bool)=>{
|
||||
@@ -336,14 +331,6 @@ impl mlua::UserData for Instance{
|
||||
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()));
|
||||
},
|
||||
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:?}"))),
|
||||
}
|
||||
Ok(())
|
||||
@@ -442,18 +429,22 @@ impl ClassMethods<'_>{
|
||||
|
||||
/// A virtual property pointer definition shorthand.
|
||||
type VirtualPropertyFunctionPointer=fn(&rbx_types::Variant)->Option<rbx_types::Variant>;
|
||||
type VirtualPropertyFunctionPointerMut=fn(&mut rbx_types::Variant,rbx_types::Variant)->Option<()>;
|
||||
const fn vpp(
|
||||
property:&'static str,
|
||||
pointer:VirtualPropertyFunctionPointer,
|
||||
access:VirtualPropertyFunctionPointer,
|
||||
access_mut:VirtualPropertyFunctionPointerMut,
|
||||
)->VirtualProperty{
|
||||
VirtualProperty{
|
||||
property,
|
||||
pointer,
|
||||
access,
|
||||
access_mut,
|
||||
}
|
||||
}
|
||||
struct VirtualProperty{
|
||||
property:&'static str,// Source property name
|
||||
pointer:VirtualPropertyFunctionPointer,
|
||||
access:VirtualPropertyFunctionPointer,
|
||||
access_mut:VirtualPropertyFunctionPointerMut,
|
||||
}
|
||||
type VPD=phf::Map<&'static str,// Class name
|
||||
phf::Map<&'static str,// Virtual property name
|
||||
@@ -462,13 +453,26 @@ type VPD=phf::Map<&'static str,// Class name
|
||||
>;
|
||||
static VIRTUAL_PROPERTY_DATABASE:VPD=phf::phf_map!{
|
||||
"BasePart"=>phf::phf_map!{
|
||||
"Position"=>vpp("CFrame",|c:&rbx_types::Variant|{
|
||||
let c=match c{
|
||||
rbx_types::Variant::CFrame(c)=>c,
|
||||
_=>return None,//fail silently and ungracefully
|
||||
};
|
||||
Some(rbx_types::Variant::Vector3(c.position))
|
||||
}),
|
||||
"Position"=>vpp(
|
||||
"CFrame",
|
||||
//Get
|
||||
|c|{
|
||||
let c=match c{
|
||||
rbx_types::Variant::CFrame(c)=>c,
|
||||
_=>return None,//fail silently and ungracefully
|
||||
};
|
||||
Some(rbx_types::Variant::Vector3(c.position))
|
||||
},
|
||||
//Set
|
||||
|c,p|{
|
||||
let (c,p)=match (c,p){
|
||||
(rbx_types::Variant::CFrame(c),rbx_types::Variant::Vector3(p))=>(c,p),
|
||||
_=>return None,//fail silently and ungracefully
|
||||
};
|
||||
c.position=p;
|
||||
Some(())
|
||||
}
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -485,5 +489,5 @@ fn find_virtual_property(
|
||||
let variant=properties.get(virtual_property.property)?;
|
||||
|
||||
//Transform Source property with provided function
|
||||
(virtual_property.pointer)(variant)
|
||||
(virtual_property.access)(variant)
|
||||
}
|
||||
|
||||
@@ -7,7 +7,5 @@ mod color3;
|
||||
mod cframe;
|
||||
mod vector3;
|
||||
pub mod instance;
|
||||
mod number_sequence;
|
||||
mod color_sequence;
|
||||
|
||||
pub use runner::{Runner,Error};
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
#[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,8 +34,6 @@ fn init(lua:&mlua::Lua)->mlua::Result<()>{
|
||||
super::vector3::set_globals(lua,&globals)?;
|
||||
super::cframe::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(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user