roblox_emulator: replace coerce_float32 with a special Number type

This commit is contained in:
Quaternions 2025-04-23 00:36:35 -07:00
parent 877964be1f
commit f48d86fe56
Signed by: Quaternions
GPG Key ID: D0DF5964F79AC131
14 changed files with 134 additions and 87 deletions

@ -9,15 +9,15 @@ impl BrickColor{
}
pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
let brickcolor_table=lua.create_table()?;
let table=lua.create_table()?;
brickcolor_table.raw_set("new",
table.raw_set("new",
lua.create_function(|_,name:mlua::String|
Ok(BrickColor::from_name(&*name.to_str()?))
)?
)?;
globals.set("BrickColor",brickcolor_table)?;
globals.set("BrickColor",table)?;
Ok(())
}

@ -1,4 +1,6 @@
use super::util::coerce_float32;
use mlua::FromLua;
use super::number::Number;
use super::vector3::Vector3;
#[derive(Clone,Copy)]
@ -61,15 +63,15 @@ impl From<rbx_types::CFrame> for CFrame{
}
pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
let cframe_table=lua.create_table()?;
let table=lua.create_table()?;
//CFrame.new
cframe_table.raw_set("new",
lua.create_function(|_,tuple:(
mlua::Value,mlua::Value,Option<f32>,
Option<f32>,Option<f32>,Option<f32>,
Option<f32>,Option<f32>,Option<f32>,
Option<f32>,Option<f32>,Option<f32>,
table.raw_set("new",
lua.create_function(|lua,tuple:(
mlua::Value,mlua::Value,Option<Number>,
Option<Number>,Option<Number>,Option<Number>,
Option<Number>,Option<Number>,Option<Number>,
Option<Number>,Option<Number>,Option<Number>,
)|match tuple{
//CFrame.new(pos)
(
@ -98,30 +100,30 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
None,None,None,
None,None,None,
None,None,None,
)=>Ok(CFrame::point(coerce_float32(&x)?,coerce_float32(&y)?,z)),
)=>Ok(CFrame::point(Number::from_lua(x,lua)?.into(),Number::from_lua(y,lua)?.into(),z.into())),
//CFrame.new(x,y,z,xx,yx,zx,xy,yy,zy,xz,yz,zz)
(
mlua::Value::Number(x),mlua::Value::Number(y),Some(z),
x,y,Some(z),
Some(xx),Some(yx),Some(zx),
Some(xy),Some(yy),Some(zy),
Some(xz),Some(yz),Some(zz),
)=>Ok(CFrame::new(x as f32,y as f32,z,
xx,yx,zx,
xy,yy,zy,
xz,yz,zz,
)=>Ok(CFrame::new(Number::from_lua(x,lua)?.into(),Number::from_lua(y,lua)?.into(),z.into(),
xx.into(),yx.into(),zx.into(),
xy.into(),yy.into(),zy.into(),
xz.into(),yz.into(),zz.into(),
)),
_=>Err(mlua::Error::runtime("Invalid arguments"))
})?
)?;
//CFrame.Angles
cframe_table.raw_set("Angles",
lua.create_function(|_,(x,y,z):(f32,f32,f32)|
Ok(CFrame::angles(x,y,z))
table.raw_set("Angles",
lua.create_function(|_,(x,y,z):(Number,Number,Number)|
Ok(CFrame::angles(x.into(),y.into(),z.into()))
)?
)?;
globals.set("CFrame",cframe_table)?;
globals.set("CFrame",table)?;
Ok(())
}

@ -1,3 +1,5 @@
use super::number::Number;
#[derive(Clone,Copy)]
pub struct Color3{
r:f32,
@ -24,20 +26,20 @@ impl From<Color3> for rbx_types::Color3{
}
pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
let color3_table=lua.create_table()?;
let table=lua.create_table()?;
color3_table.raw_set("new",
lua.create_function(|_,(r,g,b):(f32,f32,f32)|
Ok(Color3::new(r,g,b))
table.raw_set("new",
lua.create_function(|_,(r,g,b):(Number,Number,Number)|
Ok(Color3::new(r.into(),g.into(),b.into()))
)?
)?;
color3_table.raw_set("fromRGB",
table.raw_set("fromRGB",
lua.create_function(|_,(r,g,b):(u8,u8,u8)|
Ok(Color3::from_rgb(r,g,b))
)?
)?;
globals.set("Color3",color3_table)?;
globals.set("Color3",table)?;
Ok(())
}

@ -1,31 +1,30 @@
#[derive(Clone,Copy)]
pub struct ColorSequence{}
#[derive(Clone)]
pub struct ColorSequence(rbx_types::ColorSequence);
impl ColorSequence{
pub const fn new()->Self{
Self{}
pub const fn new(keypoints:Vec<rbx_types::ColorSequenceKeypoint>)->Self{
Self(rbx_types::ColorSequence{keypoints})
}
}
impl Into<rbx_types::ColorSequence> for ColorSequence{
fn into(self)->rbx_types::ColorSequence{
rbx_types::ColorSequence{
keypoints:Vec::new()
}
impl From<ColorSequence> for rbx_types::ColorSequence{
fn from(value:ColorSequence)->rbx_types::ColorSequence{
let ColorSequence(sequence)=value;
sequence
}
}
pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
let number_sequence_table=lua.create_table()?;
let table=lua.create_table()?;
number_sequence_table.raw_set("new",
table.raw_set("new",
lua.create_function(|_,_:mlua::MultiValue|
Ok(ColorSequence::new())
Ok(ColorSequence::new(Vec::new()))
)?
)?;
globals.set("ColorSequence",number_sequence_table)?;
globals.set("ColorSequence",table)?;
Ok(())
}
impl mlua::UserData for ColorSequence{}
type_from_lua_userdata!(ColorSequence);
type_from_lua_userdata_clone!(ColorSequence);

@ -5,7 +5,7 @@ use rbx_types::Ref;
use rbx_dom_weak::{Ustr,InstanceBuilder,WeakDom};
use crate::runner::vector3::Vector3;
use crate::runner::util::coerce_float32;
use crate::runner::number::Number;
// disallow non-static lifetimes
fn static_ustr(s:&'static str)->rbx_dom_weak::Ustr{
@ -17,10 +17,10 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
lua.set_app_data(ClassMethodsStore::default());
lua.set_app_data(InstanceValueStore::default());
let instance_table=lua.create_table()?;
let table=lua.create_table()?;
//Instance.new
instance_table.raw_set("new",
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());
@ -30,7 +30,7 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
})?
)?;
globals.set("Instance",instance_table)?;
globals.set("Instance",table)?;
Ok(())
}
@ -360,7 +360,7 @@ impl mlua::UserData for Instance{
rbx_types::Variant::Vector3(typed_value.into())
},
rbx_reflection::DataType::Value(rbx_types::VariantType::Float32)=>{
let typed_value:f32=coerce_float32(&value)?;
let typed_value=Number::from_lua(value.clone(),lua)?.to_f32();
rbx_types::Variant::Float32(typed_value)
},
rbx_reflection::DataType::Enum(enum_name)=>{
@ -368,7 +368,7 @@ impl mlua::UserData for Instance{
&mlua::Value::Integer(int)=>Ok(rbx_types::Enum::from_u32(int as u32)),
&mlua::Value::Number(num)=>Ok(rbx_types::Enum::from_u32(num as u32)),
mlua::Value::String(s)=>{
let e=db.enums.get(enum_name).ok_or_else(||mlua::Error::runtime("Database DataType Enum name does not exist"))?;
let e=db.enums.get(enum_name).ok_or_else(||mlua::Error::runtime("Database DataType Enum name does not exist"))?;
Ok(rbx_types::Enum::from_u32(*e.items.get(&*s.to_str()?).ok_or_else(||mlua::Error::runtime("Invalid enum item"))?))
},
mlua::Value::UserData(any_user_data)=>{
@ -404,8 +404,8 @@ impl mlua::UserData for Instance{
rbx_types::Variant::NumberSequence(typed_value.clone().into())
},
rbx_reflection::DataType::Value(rbx_types::VariantType::ColorSequence)=>{
let typed_value:crate::runner::color_sequence::ColorSequence=*value.as_userdata().ok_or_else(||mlua::Error::runtime("Expected ColorSequence"))?.borrow()?;
rbx_types::Variant::ColorSequence(typed_value.into())
let typed_value:&crate::runner::color_sequence::ColorSequence=&*value.as_userdata().ok_or_else(||mlua::Error::runtime("Expected ColorSequence"))?.borrow()?;
rbx_types::Variant::ColorSequence(typed_value.clone().into())
},
rbx_reflection::DataType::Value(rbx_types::VariantType::ContentId)=>{
let typed_value=value.as_str().ok_or_else(||mlua::Error::runtime("Expected string"))?.to_owned();

@ -10,6 +10,18 @@ macro_rules! type_from_lua_userdata{
}
};
}
macro_rules! type_from_lua_userdata_clone{
($ty:ident)=>{
impl mlua::FromLua for $ty{
fn from_lua(value:mlua::Value,_lua:&mlua::Lua)->Result<Self,mlua::Error>{
match value{
mlua::Value::UserData(ud)=>Ok(ud.borrow::<Self>()?.clone()),
other=>Err(mlua::Error::runtime(format!("Expected {} got {:?}",stringify!($ty),other))),
}
}
}
};
}
macro_rules! type_from_lua_userdata_lua_lifetime{
($ty:ident)=>{
impl mlua::FromLua for $ty<'static>{

@ -1,13 +1,13 @@
#[macro_use]
mod macros;
mod runner;
mod util;
mod r#enum;
mod udim;
mod udim2;
mod color3;
mod cframe;
mod number;
mod vector3;
mod brickcolor;
pub mod instance;

@ -0,0 +1,43 @@
// the goal of this module is to provide an intermediate type
// that is guaranteed to be some kind of number, and provide
// methods to coerce it into various more specific types.
#[derive(Clone,Copy)]
pub enum Number{
Integer(i32),
Number(f64),
}
macro_rules! impl_ty{
($ident:ident,$ty:ty)=>{
impl Number{
#[inline]
pub fn $ident(self)->$ty{
match self{
Self::Integer(int)=>int as $ty,
Self::Number(num)=>num as $ty,
}
}
}
impl From<Number> for $ty{
fn from(value:Number)->$ty{
value.$ident()
}
}
};
}
impl_ty!(to_u32,u32);
impl_ty!(to_i32,i32);
impl_ty!(to_f32,f32);
impl_ty!(to_u64,u64);
impl_ty!(to_i64,i64);
impl_ty!(to_f64,f64);
impl mlua::FromLua for Number{
fn from_lua(value:mlua::Value,_lua:&mlua::Lua)->Result<Self,mlua::Error>{
match value{
mlua::Value::Integer(int)=>Ok(Number::Integer(int)),
mlua::Value::Number(num)=>Ok(Number::Number(num)),
other=>Err(mlua::Error::runtime(format!("Expected {} got {:?}",stringify!(Number),other))),
}
}
}

@ -1,4 +1,4 @@
use super::util::coerce_float32;
use super::number::Number;
#[derive(Clone)]
pub struct NumberRange(rbx_types::NumberRange);
@ -18,14 +18,11 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
let table=lua.create_table()?;
table.raw_set("new",
lua.create_function(|_,(min,max):(mlua::Value,mlua::Value)|{
let min=coerce_float32(&min)?;
if max.is_nil(){
Ok(NumberRange::new(min,min))
}else{
let max=coerce_float32(&max)?;
Ok(NumberRange::new(min,max))
}
lua.create_function(|_,(min,max):(Number,Option<Number>)|{
Ok(match max{
Some(max)=>NumberRange::new(min.into(),max.into()),
None=>NumberRange::new(min.into(),min.into()),
})
})?
)?;
@ -35,11 +32,4 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
}
impl mlua::UserData for NumberRange{}
impl mlua::FromLua for NumberRange{
fn from_lua(value:mlua::Value,_lua:&mlua::Lua)->Result<Self,mlua::Error>{
match value{
mlua::Value::UserData(ud)=>Ok(ud.borrow::<Self>()?.clone()),
other=>Err(mlua::Error::runtime(format!("Expected {} got {:?}",stringify!(NumberRange),other))),
}
}
}
type_from_lua_userdata_clone!(NumberRange);

@ -13,15 +13,15 @@ impl From<NumberSequence> for rbx_types::NumberSequence{
}
pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
let number_sequence_table=lua.create_table()?;
let table=lua.create_table()?;
number_sequence_table.raw_set("new",
table.raw_set("new",
lua.create_function(|_,_:mlua::MultiValue|
Ok(NumberSequence::new(Vec::new()))
)?
)?;
globals.set("NumberSequence",number_sequence_table)?;
globals.set("NumberSequence",table)?;
Ok(())
}

@ -1,3 +1,5 @@
use super::number::Number;
#[derive(Clone,Copy)]
pub struct UDim(rbx_types::UDim);
impl UDim{
@ -15,8 +17,8 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
let table=lua.create_table()?;
table.raw_set("new",
lua.create_function(|_,(scale,offset):(f32,i32)|
Ok(UDim::new(scale,offset))
lua.create_function(|_,(scale,offset):(Number,i32)|
Ok(UDim::new(scale.into(),offset))
)?
)?;

@ -1,4 +1,5 @@
use super::udim::UDim;
use super::number::Number;
#[derive(Clone,Copy)]
pub struct UDim2(rbx_types::UDim2);
@ -15,8 +16,8 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
let table=lua.create_table()?;
table.raw_set("new",
lua.create_function(|_,(sx,ox,sy,oy):(f32,i32,f32,i32)|
Ok(UDim2::new(sx,ox,sy,oy))
lua.create_function(|_,(sx,ox,sy,oy):(Number,i32,Number,i32)|
Ok(UDim2::new(sx.into(),ox,sy.into(),oy))
)?
)?;

@ -1,7 +0,0 @@
pub fn coerce_float32(value:&mlua::Value)->mlua::Result<f32>{
match value{
&mlua::Value::Integer(i)=>Ok(i as f32),
&mlua::Value::Number(f)=>Ok(f as f32),
_=>Err(mlua::Error::runtime("Expected f32")),
}
}

@ -1,3 +1,5 @@
use super::number::Number;
#[derive(Clone,Copy)]
pub struct Vector3(pub(crate)glam::Vec3A);
@ -8,23 +10,24 @@ impl Vector3{
}
pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
let vector3_table=lua.create_table()?;
let table=lua.create_table()?;
//Vector3.new
vector3_table.raw_set("new",
lua.create_function(|_,(x,y,z):(f32,f32,f32)|
Ok(Vector3::new(x,y,z))
table.raw_set("new",
lua.create_function(|_,(x,y,z):(Number,Number,Number)|
Ok(Vector3::new(x.into(),y.into(),z.into()))
)?
)?;
globals.set("Vector3",vector3_table)?;
globals.set("Vector3",table)?;
Ok(())
}
impl Into<rbx_types::Vector3> for Vector3{
fn into(self)->rbx_types::Vector3{
rbx_types::Vector3::new(self.0.x,self.0.y,self.0.z)
let Vector3(v)=self;
rbx_types::Vector3::new(v.x,v.y,v.z)
}
}